Downgrade Clipper to 5.1.5

This commit is contained in:
Alessandro Ranellucci 2013-08-26 15:57:54 +02:00
parent 0933a2cf6b
commit b6005327d6
5 changed files with 189 additions and 321 deletions

View File

@ -21,9 +21,9 @@ my $build = Module::Build::WithXSpp->new(
Module::Build 0.38
Module::Build::WithXSpp 0.13
)},
# _GLIBCXX_USE_C99 : to get the long long type for g++
# HAS_BOOL : stops Perl/lib/CORE/handy.h from doing "# define bool char" for MSVC
extra_compiler_flags => [qw(-DHAS_BOOL)],
extra_compiler_flags => [qw(-D_GLIBCXX_USE_C99 -DHAS_BOOL)],
# Provides extra C typemaps that are auto-merged
extra_typemap_modules => {

View File

@ -144,7 +144,7 @@ offset_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float de
void
offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
// read input
ClipperLib::Polygons* input = new ClipperLib::Polygons();
@ -168,7 +168,7 @@ offset2(Slic3r::Polygons &polygons, ClipperLib::Polygons &retval, const float de
void
offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
@ -181,7 +181,7 @@ offset2(Slic3r::Polygons &polygons, Slic3r::Polygons &retval, const float delta1
void
offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float delta1,
const float delta2, double scale, ClipperLib::JoinType joinType, double miterLimit)
const float delta2, const double scale, const ClipperLib::JoinType joinType, const double miterLimit)
{
// perform offset
ClipperLib::Polygons* output = new ClipperLib::Polygons();
@ -193,8 +193,8 @@ offset2_ex(Slic3r::Polygons &polygons, Slic3r::ExPolygons &retval, const float d
}
template <class T>
void _clipper_do(ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
Slic3r::Polygons &clip, T &retval, bool safety_offset)
void _clipper_do(const ClipperLib::ClipType clipType, Slic3r::Polygons &subject,
Slic3r::Polygons &clip, T &retval, const bool safety_offset)
{
// read input
ClipperLib::Polygons* input_subject = new ClipperLib::Polygons();

View File

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 5.1.6 *
* Date : 23 May 2013 *
* Version : 5.1.5 *
* Date : 4 May 2013 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 *
* *
@ -59,8 +59,6 @@ enum Direction { dRightToLeft, dLeftToRight };
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
const char coords_range_error[] = "Coordinate exceeds range bounds.";
inline long64 Abs(long64 val)
{
return val < 0 ? -val : val;
@ -356,7 +354,7 @@ bool FullRangeNeeded(const Polygon &pts)
for (Polygon::size_type i = 0; i < pts.size(); ++i)
{
if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange)
throw coords_range_error;
throw "Coordinate exceeds range bounds.";
else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
result = true;
}
@ -456,17 +454,17 @@ bool PointOnLineSegment(const IntPoint pt,
}
//------------------------------------------------------------------------------
bool PointOnPolygon(const IntPoint pt, OutPt *pp, bool UseFullInt64Range)
bool PointOnPolygon(const IntPoint pt,
OutPt *pp, bool UseFullInt64Range)
{
OutPt *pp2 = pp;
while (true)
for (;;)
{
if (PointOnLineSegment(pt, pp2->pt, pp2->next->pt, UseFullInt64Range))
return true;
pp2 = pp2->next;
if (pp2 == pp) break;
if (pp2 == pp) return false;
}
return false;
}
//------------------------------------------------------------------------------
@ -503,7 +501,7 @@ bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
}
//------------------------------------------------------------------------------
bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
{
if (UseFullInt64Range)
return Int128Mul(e1.deltaY, e2.deltaX) == Int128Mul(e1.deltaX, e2.deltaY);
@ -669,7 +667,8 @@ void DisposeOutPts(OutPt*& pp)
void InitEdge(TEdge *e, TEdge *eNext,
TEdge *ePrev, const IntPoint &pt, PolyType polyType)
{
std::memset(e, 0, sizeof(TEdge));
std::memset( e, 0, sizeof( TEdge ));
e->next = eNext;
e->prev = ePrev;
e->xcurr = pt.X;
@ -861,39 +860,27 @@ ClipperBase::~ClipperBase() //destructor
}
//------------------------------------------------------------------------------
void RangeTest(const IntPoint& pt, long64& maxrange)
{
if (Abs(pt.X) > maxrange)
{
if (Abs(pt.X) > hiRange)
throw coords_range_error;
else maxrange = hiRange;
}
if (Abs(pt.Y) > maxrange)
{
if (Abs(pt.Y) > hiRange)
throw coords_range_error;
else maxrange = hiRange;
}
}
//------------------------------------------------------------------------------
bool ClipperBase::AddPolygon(const Polygon &pg, PolyType polyType)
bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
{
int len = (int)pg.size();
if (len < 3) return false;
long64 maxVal;
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
RangeTest(pg[0], maxVal);
Polygon p(len);
p[0] = pg[0];
int j = 0;
long64 maxVal;
if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
for (int i = 0; i < len; ++i)
{
RangeTest(pg[i], maxVal);
if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
{
if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange)
throw "Coordinate exceeds range bounds";
maxVal = hiRange;
m_UseFullRange = true;
}
if (i == 0 || PointsEqual(p[j], pg[i])) continue;
else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
@ -1203,6 +1190,7 @@ void Clipper::Reset()
while (lm)
{
InsertScanbeam(lm->Y);
InsertScanbeam(lm->leftBound->ytop);
lm = lm->next;
}
}
@ -1272,7 +1260,7 @@ bool Clipper::ExecuteInternal()
if (!succeeded) break;
ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
} while(m_Scanbeam || m_CurrentLM);
} while( m_Scanbeam );
}
catch(...) {
succeeded = false;
@ -1470,7 +1458,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default:
return (edge.windCnt2 < 0);
}
break;
case ctUnion:
switch(pft2)
{
@ -1482,7 +1469,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default:
return (edge.windCnt2 >= 0);
}
break;
case ctDifference:
if (edge.polyType == ptSubject)
switch(pft2)
@ -1506,7 +1492,6 @@ bool Clipper::IsContributing(const TEdge& edge) const
default:
return (edge.windCnt2 < 0);
}
break;
default:
return true;
}
@ -2070,12 +2055,12 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
{
OutRec *outRec = CreateOutRec();
e->outIdx = outRec->idx;
OutPt* newOp = new OutPt;
outRec->pts = newOp;
newOp->pt = pt;
newOp->idx = outRec->idx;
newOp->next = newOp;
newOp->prev = newOp;
OutPt* op = new OutPt;
outRec->pts = op;
op->pt = pt;
op->idx = outRec->idx;
op->next = op;
op->prev = op;
SetHoleState(e, outRec);
} else
{
@ -2084,14 +2069,14 @@ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
if ((ToFront && PointsEqual(pt, op->pt)) ||
(!ToFront && PointsEqual(pt, op->prev->pt))) return;
OutPt* newOp = new OutPt;
newOp->pt = pt;
newOp->idx = outRec->idx;
newOp->next = op;
newOp->prev = op->prev;
newOp->prev->next = newOp;
op->prev = newOp;
if (ToFront) outRec->pts = newOp;
OutPt* op2 = new OutPt;
op2->pt = pt;
op2->idx = outRec->idx;
op2->next = op;
op2->prev = op->prev;
op2->prev->next = op2;
op->prev = op2;
if (ToFront) outRec->pts = op2;
}
}
//------------------------------------------------------------------------------
@ -2413,8 +2398,8 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
}
//bubblesort ...
bool isModified;
do
bool isModified = true;
while( isModified && m_SortedEdges )
{
isModified = false;
e = m_SortedEdges;
@ -2431,7 +2416,7 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
pt.Y = botY;
pt.X = TopX(*e, pt.Y);
}
InsertIntersectNode( e, eNext, pt );
AddIntersectNode( e, eNext, pt );
SwapPositionsInSEL(e, eNext);
isModified = true;
}
@ -2441,12 +2426,11 @@ void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
else break;
}
while ( isModified );
m_SortedEdges = 0; //important
m_SortedEdges = 0;
}
//------------------------------------------------------------------------------
void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
{
IntersectNode* newNode = new IntersectNode;
newNode->edge1 = e1;
@ -2463,7 +2447,7 @@ void Clipper::InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
{
IntersectNode* iNode = m_IntersectNodes;
while(iNode->next && newNode->pt.Y <= iNode->next->pt.Y)
iNode = iNode->next;
iNode = iNode->next;
newNode->next = iNode->next;
iNode->next = newNode;
}
@ -2766,7 +2750,7 @@ bool Clipper::FixupIntersectionOrder()
}
//------------------------------------------------------------------------------
inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
{
if (e2.xcurr == e1.xcurr)
{
@ -3172,151 +3156,134 @@ DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
class OffsetBuilder
class PolyOffsetBuilder
{
private:
const Polygons& m_p;
Polygons m_p;
Polygon* m_curr_poly;
std::vector<DoublePoint> normals;
double m_delta, m_rmin, m_r;
double m_delta, m_RMin, m_R;
size_t m_i, m_j, m_k;
static const int buffLength = 128;
JoinType m_jointype;
public:
OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
bool isPolygon, double delta, JoinType jointype, EndType endtype, double limit): m_p(in_polys)
PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
double delta, JoinType jointype, double limit, bool autoFix)
{
//precondition: &out_polys != &in_polys
//nb precondition - out_polys != ptsin_polys
if (NEAR_ZERO(delta))
{
out_polys = in_polys;
return;
}
if (NEAR_ZERO(delta)) {out_polys = in_polys; return;}
m_rmin = 0.5;
m_delta = delta;
if (jointype == jtMiter)
this->m_p = in_polys;
this->m_delta = delta;
this->m_jointype = jointype;
//ChecksInput - fixes polygon orientation if necessary and removes
//duplicate vertices. Can be set false when you're sure that polygon
//orientation is correct and that there are no duplicate vertices.
if (autoFix)
{
if (limit > 2) m_rmin = 2.0 / (limit * limit);
limit = 0.25; //just in case endtype == etRound
size_t Len = m_p.size(), botI = 0;
while (botI < Len && m_p[botI].empty()) botI++;
if (botI == Len) return;
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
//This point (on m_p[botI]) must be on an outer polygon ring and if
//its orientation is false (counterclockwise) then assume all polygons
//need reversing ...
IntPoint botPt = m_p[botI][0];
for (size_t i = botI; i < Len; ++i)
{
if (m_p[i].size() < 3) continue;
if (UpdateBotPt(m_p[i][0], botPt)) botI = i;
Polygon::iterator it = m_p[i].begin() +1;
while (it != m_p[i].end())
{
if (PointsEqual(*it, *(it -1)))
it = m_p[i].erase(it);
else
{
if (UpdateBotPt(*it, botPt)) botI = i;
++it;
}
}
}
if (!Orientation(m_p[botI]))
ReversePolygons(m_p);
}
else
switch (jointype)
{
if (limit <= 0) limit = 0.25;
else if (limit > std::fabs(delta)) limit = std::fabs(delta);
case jtRound:
if (limit <= 0) limit = 0.25;
else if (limit > std::fabs(delta)) limit = std::fabs(delta);
break;
case jtMiter:
if (limit < 2) limit = 2;
break;
default: //unused
limit = 1;
}
m_RMin = 2.0/(limit*limit);
double deltaSq = delta*delta;
out_polys.clear();
out_polys.resize(m_p.size());
for (m_i = 0; m_i < m_p.size(); m_i++)
{
m_curr_poly = &out_polys[m_i];
size_t len = m_p[m_i].size();
if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X &&
m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--;
//when 'shrinking' polygons - to minimize artefacts
//strip those polygons that have an area < pi * delta^2 ...
double a1 = Area(m_p[m_i]);
if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; }
else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area
if (len == 0 || (len < 3 && delta <= 0))
continue;
continue;
else if (len == 1)
{
out_polys[m_i] = BuildArc(m_p[m_i][0], 0, 2*pi, delta, limit);
Polygon arc;
arc = BuildArc(m_p[m_i][len-1], 0, 2 * pi, delta, limit);
out_polys[m_i] = arc;
continue;
}
bool forceClose = PointsEqual(m_p[m_i][0], m_p[m_i][len -1]);
if (forceClose) len--;
//build normals ...
normals.clear();
normals.resize(len);
normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]);
for (m_j = 0; m_j < len -1; ++m_j)
normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j +1]);
if (isPolygon || forceClose)
normals[len-1] = GetUnitNormal(m_p[m_i][len-1], m_p[m_i][0]);
else //is open polyline
normals[len-1] = normals[len-2];
normals[m_j] = GetUnitNormal(m_p[m_i][m_j], m_p[m_i][m_j+1]);
m_curr_poly = &out_polys[m_i];
m_curr_poly->reserve(len);
if (isPolygon || forceClose)
m_k = len -1;
for (m_j = 0; m_j < len; ++m_j)
{
m_k = len -1;
for (m_j = 0; m_j < len; ++m_j)
OffsetPoint(jointype, limit);
if (!isPolygon)
switch (jointype)
{
size_t j = out_polys.size();
out_polys.resize(j+1);
m_curr_poly = &out_polys[j];
m_curr_poly->reserve(len);
m_delta = -m_delta;
m_k = len -1;
for (m_j = 0; m_j < len; ++m_j)
OffsetPoint(jointype, limit);
m_delta = -m_delta;
ReversePolygon(*m_curr_poly);
}
}
else //is open polyline
{
//offset the polyline going forward ...
m_k = 0;
for (m_j = 1; m_j < len -1; ++m_j)
OffsetPoint(jointype, limit);
//handle the end (butt, round or square) ...
IntPoint pt1;
if (endtype == etButt)
{
m_j = len - 1;
pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
AddPoint(pt1);
pt1 = IntPoint(Round(m_p[m_i][m_j].X - normals[m_j].X * m_delta),
Round(m_p[m_i][m_j].Y - normals[m_j].Y * m_delta));
AddPoint(pt1);
}
else
{
m_j = len - 1;
m_k = len - 2;
normals[m_j].X = -normals[m_j].X;
normals[m_j].Y = -normals[m_j].Y;
if (endtype == etSquare) DoSquare();
else DoRound(limit);
}
//re-build Normals ...
for (int j = len - 1; j > 0; --j)
{
normals[j].X = -normals[j - 1].X;
normals[j].Y = -normals[j - 1].Y;
}
normals[0].X = -normals[1].X;
normals[0].Y = -normals[1].Y;
//offset the polyline going backward ...
m_k = len -1;
for (m_j = m_k - 1; m_j > 0; --m_j)
OffsetPoint(jointype, limit);
//finally handle the start (butt, round or square) ...
if (endtype == etButt)
{
pt1 = IntPoint(Round(m_p[m_i][0].X - normals[0].X * m_delta),
Round(m_p[m_i][0].Y - normals[0].Y * m_delta));
AddPoint(pt1);
pt1 = IntPoint(Round(m_p[m_i][0].X + normals[0].X * m_delta),
Round(m_p[m_i][0].Y + normals[0].Y * m_delta));
AddPoint(pt1);
} else
{
m_k = 1;
if (endtype == etSquare) DoSquare();
else DoRound(limit);
case jtMiter:
{
m_R = 1 + (normals[m_j].X*normals[m_k].X +
normals[m_j].Y*normals[m_k].Y);
if (m_R >= m_RMin) DoMiter(); else DoSquare(limit);
break;
}
case jtSquare: DoSquare(1.0); break;
case jtRound: DoRound(limit); break;
}
m_k = m_j;
}
}
//and clean up untidy corners using Clipper ...
//finally, clean up untidy corners using Clipper ...
Clipper clpr;
clpr.AddPolygons(out_polys, ptSubject);
if (delta > 0)
@ -3334,10 +3301,12 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
outer[3] = IntPoint(r.left - 10, r.top - 10);
clpr.AddPolygon(outer, ptSubject);
clpr.ReverseSolution(true);
if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative))
{
out_polys.erase(out_polys.begin());
else
ReversePolygons(out_polys);
} else
out_polys.clear();
}
}
@ -3345,24 +3314,6 @@ OffsetBuilder(const Polygons& in_polys, Polygons& out_polys,
private:
void OffsetPoint(JoinType jointype, double limit)
{
switch (jointype)
{
case jtMiter:
{
m_r = 1 + (normals[m_j].X*normals[m_k].X +
normals[m_j].Y*normals[m_k].Y);
if (m_r >= m_rmin) DoMiter(); else DoSquare();
break;
}
case jtSquare: DoSquare(); break;
case jtRound: DoRound(limit); break;
}
m_k = m_j;
}
//------------------------------------------------------------------------------
void AddPoint(const IntPoint& pt)
{
if (m_curr_poly->size() == m_curr_poly->capacity())
@ -3371,22 +3322,24 @@ void AddPoint(const IntPoint& pt)
}
//------------------------------------------------------------------------------
void DoSquare()
void DoSquare(double mul)
{
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
{
double a1 = std::atan2(normals[m_k].Y, normals[m_k].X);
double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X);
a1 = std::fabs(a2 - a1);
if (a1 > pi) a1 = pi * 2 - a1;
double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta);
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), (long64)(pt1.Y + normals[m_k].X * dx));
double dx = std::tan((pi - a1) / 4) * std::fabs(m_delta * mul);
pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx),
(long64)(pt1.Y + normals[m_k].X * dx));
AddPoint(pt1);
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), (long64)(pt2.Y -normals[m_j].X * dx));
pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx),
(long64)(pt2.Y -normals[m_j].X * dx));
AddPoint(pt2);
}
else
@ -3402,16 +3355,17 @@ void DoMiter()
{
if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0)
{
double q = m_delta / m_r;
AddPoint(IntPoint(Round(m_p[m_i][m_j].X + (normals[m_k].X + normals[m_j].X) * q),
Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
double q = m_delta / m_R;
AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X +
(normals[m_k].X + normals[m_j].X) * q),
(long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q)));
}
else
{
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X *
m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X *
m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
AddPoint(pt1);
AddPoint(m_p[m_i][m_j]);
AddPoint(pt2);
@ -3421,10 +3375,10 @@ void DoMiter()
void DoRound(double limit)
{
IntPoint pt1 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint(Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta),
(long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta));
IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta),
(long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta));
AddPoint(pt1);
//round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg).
if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0)
@ -3446,11 +3400,6 @@ void DoRound(double limit)
}
//--------------------------------------------------------------------------
}; //end PolyOffsetBuilder
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
{
if (pt.Y > botPt.Y || (pt.Y == botPt.Y && pt.X < botPt.X))
@ -3462,93 +3411,20 @@ bool UpdateBotPt(const IntPoint &pt, IntPoint &botPt)
}
//--------------------------------------------------------------------------
}; //end PolyOffsetBuilder
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype, double limit, bool autoFix)
{
if (!autoFix && &in_polys != &out_polys)
if (&out_polys == &in_polys)
{
OffsetBuilder(in_polys, out_polys, true, delta, jointype, etClosed, limit);
return;
Polygons poly2(in_polys);
PolyOffsetBuilder(poly2, out_polys, delta, jointype, limit, autoFix);
}
Polygons inPolys = Polygons(in_polys);
out_polys.clear();
//ChecksInput - fixes polygon orientation if necessary and removes
//duplicate vertices. Can be set false when you're sure that polygon
//orientation is correct and that there are no duplicate vertices.
if (autoFix)
{
size_t polyCount = inPolys.size(), botPoly = 0;
while (botPoly < polyCount && inPolys[botPoly].empty()) botPoly++;
if (botPoly == polyCount) return;
//botPt: used to find the lowermost (in inverted Y-axis) & leftmost point
//This point (on m_p[botPoly]) must be on an outer polygon ring and if
//its orientation is false (counterclockwise) then assume all polygons
//need reversing ...
IntPoint botPt = inPolys[botPoly][0];
for (size_t i = botPoly; i < polyCount; ++i)
{
if (inPolys[i].size() < 3) { inPolys[i].clear(); continue; }
if (UpdateBotPt(inPolys[i][0], botPt)) botPoly = i;
Polygon::iterator it = inPolys[i].begin() +1;
while (it != inPolys[i].end())
{
if (PointsEqual(*it, *(it -1)))
it = inPolys[i].erase(it);
else
{
if (UpdateBotPt(*it, botPt)) botPoly = i;
++it;
}
}
}
if (!Orientation(inPolys[botPoly]))
ReversePolygons(inPolys);
}
OffsetBuilder(inPolys, out_polys, true, delta, jointype, etClosed, limit);
}
//------------------------------------------------------------------------------
void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines,
double delta, JoinType jointype, EndType endtype,
double limit, bool autoFix)
{
if (!autoFix && endtype != etClosed && &in_lines != &out_lines)
{
OffsetBuilder(in_lines, out_lines, false, delta, jointype, endtype, limit);
return;
}
Polygons inLines = Polygons(in_lines);
if (autoFix)
for (size_t i = 0; i < inLines.size(); ++i)
{
if (inLines[i].size() < 2) { inLines[i].clear(); continue; }
Polygon::iterator it = inLines[i].begin() +1;
while (it != inLines[i].end())
{
if (PointsEqual(*it, *(it -1)))
it = inLines[i].erase(it);
else
++it;
}
}
if (endtype == etClosed)
{
size_t sz = inLines.size();
inLines.resize(sz * 2);
for (size_t i = 0; i < sz; ++i)
{
inLines[sz+i] = inLines[i];
ReversePolygon(inLines[sz+i]);
}
OffsetBuilder(inLines, out_lines, true, delta, jointype, endtype, limit);
}
else
OffsetBuilder(inLines, out_lines, false, delta, jointype, endtype, limit);
else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, limit, autoFix);
}
//------------------------------------------------------------------------------
@ -3616,7 +3492,7 @@ bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
}
//------------------------------------------------------------------------------
void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
void CleanPolygon(Polygon& in_poly, Polygon& out_poly, double distance)
{
//distance = proximity in units/pixels below which vertices
//will be stripped. Default ~= sqrt(2).
@ -3625,17 +3501,15 @@ void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
while (highI > 0 && PointsAreClose(in_poly[highI], in_poly[0], distSqrd)) highI--;
if (highI < 2) { out_poly.clear(); return; }
if (&in_poly != &out_poly)
out_poly.resize(highI + 1);
out_poly.resize(highI + 1);
IntPoint pt = in_poly[highI];
int i = 0, k = 0;
for (;;)
{
while (i < highI && PointsAreClose(pt, in_poly[i+1], distSqrd)) i+=2;
while (i <= highI && PointsAreClose(pt, in_poly[i+1], distSqrd)) i+=2;
int i2 = i;
while (i < highI && (PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) ||
SlopesNearColinear(pt, in_poly[i], in_poly[i+1], distSqrd))) i++;
while (i <= highI && PointsAreClose(in_poly[i], in_poly[i+1], distSqrd) ||
SlopesNearColinear(pt, in_poly[i], in_poly[+1], distSqrd)) i++;
if (i >= highI) break;
else if (i != i2) continue;
pt = in_poly[i++];
@ -3648,14 +3522,14 @@ void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance)
}
//------------------------------------------------------------------------------
void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance)
void CleanPolygons(Polygons& in_polys, Polygons& out_polys, double distance)
{
for (Polygons::size_type i = 0; i < in_polys.size(); ++i)
CleanPolygon(in_polys[i], out_polys[i], distance);
}
//------------------------------------------------------------------------------
void AddPolyNodeToPolygons(const PolyNode& polynode, Polygons& polygons)
void AddPolyNodeToPolygons(PolyNode& polynode, Polygons& polygons)
{
if (!polynode.Contour.empty())
polygons.push_back(polynode.Contour);
@ -3664,7 +3538,7 @@ void AddPolyNodeToPolygons(const PolyNode& polynode, Polygons& polygons)
}
//------------------------------------------------------------------------------
void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons)
void PolyTreeToPolygons(PolyTree& polytree, Polygons& polygons)
{
polygons.resize(0);
polygons.reserve(polytree.Total());

View File

@ -1,8 +1,8 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 5.1.6 *
* Date : 23 May 2013 *
* Version : 5.1.5 *
* Date : 4 May 2013 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2013 *
* *
@ -101,7 +101,6 @@ private:
};
enum JoinType { jtSquare, jtRound, jtMiter };
enum EndType { etClosed, etButt, etSquare, etRound};
bool Orientation(const Polygon &poly);
double Area(const Polygon &poly);
@ -109,17 +108,14 @@ double Area(const Polygon &poly);
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype = jtSquare, double limit = 0, bool autoFix = true);
void OffsetPolyLines(const Polygons &in_lines, Polygons &out_lines,
double delta, JoinType jointype = jtSquare, EndType endtype = etSquare, double limit = 0, bool autoFix = true);
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
void CleanPolygon(const Polygon& in_poly, Polygon& out_poly, double distance = 1.415);
void CleanPolygons(const Polygons& in_polys, Polygons& out_polys, double distance = 1.415);
void CleanPolygon(Polygon& in_poly, Polygon& out_poly, double distance = 1.415);
void CleanPolygons(Polygons& in_polys, Polygons& out_polys, double distance = 1.415);
void PolyTreeToPolygons(const PolyTree& polytree, Polygons& polygons);
void PolyTreeToPolygons(PolyTree& polytree, Polygons& polygons);
void ReversePolygon(Polygon& p);
void ReversePolygons(Polygons& p);
@ -127,8 +123,6 @@ void ReversePolygons(Polygons& p);
//used internally ...
enum EdgeSide { esLeft = 1, esRight = 2};
enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
//inline IntersectProtects operator|(IntersectProtects a, IntersectProtects b)
//{return static_cast<IntersectProtects>(static_cast<int>(a) | static_cast<int>(b));}
struct TEdge {
long64 xbot;
@ -304,7 +298,7 @@ private:
void DisposeAllPolyPts();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const long64 botY, const long64 topY);
void InsertIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
void BuildIntersectList(const long64 botY, const long64 topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const long64 topY);

View File

@ -62,7 +62,7 @@ my $expolygon = Slic3r::ExPolygon->new($square, $hole_in_square);
[15000000, 15000000],
[15000000, 5000000],
]);
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon2 ], +49900, -49900);
my $result = Slic3r::Geometry::Clipper::offset2_ex([ @$expolygon2 ], -1, +1);
is_deeply $result->[0]->pp, $expolygon2->pp, 'offset2_ex';
}