From b6005327d6d49748f2c634a164d2cd417b5cc5cd Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 26 Aug 2013 15:57:54 +0200 Subject: [PATCH] Downgrade Clipper to 5.1.5 --- xs/Build.PL | 4 +- xs/src/ClipperUtils.cpp | 10 +- xs/src/clipper.cpp | 476 +++++++++++++++------------------------- xs/src/clipper.hpp | 18 +- xs/t/11_clipper.t | 2 +- 5 files changed, 189 insertions(+), 321 deletions(-) diff --git a/xs/Build.PL b/xs/Build.PL index e967aed38..81a059caf 100644 --- a/xs/Build.PL +++ b/xs/Build.PL @@ -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 => { diff --git a/xs/src/ClipperUtils.cpp b/xs/src/ClipperUtils.cpp index 672d11202..a4205991c 100644 --- a/xs/src/ClipperUtils.cpp +++ b/xs/src/ClipperUtils.cpp @@ -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 -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(); diff --git a/xs/src/clipper.cpp b/xs/src/clipper.cpp index 02a7b7085..7f4ceceb6 100755 --- a/xs/src/clipper.cpp +++ b/xs/src/clipper.cpp @@ -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 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()); diff --git a/xs/src/clipper.hpp b/xs/src/clipper.hpp index e313cfaa5..8ef36ad70 100755 --- a/xs/src/clipper.hpp +++ b/xs/src/clipper.hpp @@ -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(static_cast(a) | static_cast(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); diff --git a/xs/t/11_clipper.t b/xs/t/11_clipper.t index 496cadc3c..8b7340bc9 100644 --- a/xs/t/11_clipper.t +++ b/xs/t/11_clipper.t @@ -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'; }