summaryrefslogtreecommitdiff
path: root/src/3rdparty
diff options
context:
space:
mode:
authorPaolo Angelelli <paolo.angelelli@qt.io>2016-12-15 18:21:19 +0100
committerPaolo Angelelli <paolo.angelelli@qt.io>2017-01-19 13:47:45 +0000
commit645e61163333002f92fc3f730043837df08cd4dd (patch)
tree74a719b84494fb4a62f272cfd4353d2d9671580e /src/3rdparty
parent09364bf515283251cf8e4a43de4d2363b16c8551 (diff)
downloadqtlocation-645e61163333002f92fc3f730043837df08cd4dd.tar.gz
Update clipper 3rd party library
This patch updates the 3rdparty clipper lib The version of clipper that this patch introduces is 6.4, with SHA1: e03b24c05a322ab91fecee8240532616bd0727ee Change-Id: I957c63249ece74b2861dd2b99879db40c0636fa1 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/3rdparty')
-rw-r--r--src/3rdparty/clipper/clipper.cpp1689
-rw-r--r--src/3rdparty/clipper/clipper.h148
2 files changed, 930 insertions, 907 deletions
diff --git a/src/3rdparty/clipper/clipper.cpp b/src/3rdparty/clipper/clipper.cpp
index 7a27bc44..d4c82344 100644
--- a/src/3rdparty/clipper/clipper.cpp
+++ b/src/3rdparty/clipper/clipper.cpp
@@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
-* Version : 6.1.3a *
-* Date : 22 January 2014 *
+* Version : 6.4.0 *
+* Date : 2 July 2015 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2014 *
+* Copyright : Angus Johnson 2010-2015 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@@ -50,15 +50,6 @@
namespace ClipperLib {
-#ifdef use_int32
- static cInt const loRange = 46340;
- static cInt const hiRange = 46340;
-#else
- static cInt const loRange = 0x3FFFFFFF;
- static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
- typedef unsigned long long ulong64;
-#endif
-
static double const pi = 3.141592653589793238;
static double const two_pi = pi *2;
static double const def_arc_tolerance = 0.25;
@@ -74,12 +65,11 @@ static int const Skip = -2; //edge that would otherwise close a path
struct TEdge {
IntPoint Bot;
- IntPoint Curr;
+ IntPoint Curr; //current (updated for every new scanbeam)
IntPoint Top;
- IntPoint Delta;
double Dx;
PolyType PolyTyp;
- EdgeSide Side;
+ EdgeSide Side; //side only refers to current side of solution poly
int WindDelta; //1 or -1 depending on winding direction
int WindCnt;
int WindCnt2; //winding count of the opposite polytype
@@ -99,15 +89,16 @@ struct IntersectNode {
IntPoint Pt;
};
-struct LocalMinima {
+struct LocalMinimum {
cInt Y;
TEdge *LeftBound;
TEdge *RightBound;
- LocalMinima *Next;
};
struct OutPt;
+//OutRec: contains a path in the clipping solution. Edges in the AEL will
+//carry a pointer to an OutRec when they are part of the clipping solution.
struct OutRec {
int Idx;
bool IsHole;
@@ -131,6 +122,14 @@ struct Join {
IntPoint OffPt;
};
+struct LocMinSorter
+{
+ inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2)
+ {
+ return locMin2.Y < locMin1.Y;
+ }
+};
+
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
@@ -170,7 +169,10 @@ PolyNode* PolyTree::GetFirst() const
int PolyTree::Total() const
{
- return (int)AllNodes.size();
+ int result = (int)AllNodes.size();
+ //with negative offsets, ignore the hidden outer polygon ...
+ if (result > 0 && Childs[0] != AllNodes[0]) result--;
+ return result;
}
//------------------------------------------------------------------------------
@@ -240,8 +242,8 @@ bool PolyNode::IsOpen() const
//------------------------------------------------------------------------------
// Int128 class (enables safe math on signed 64bit integers)
-// eg Int128 val1((cInt)9223372036854775807); //ie 2^63 -1
-// Int128 val2((cInt)9223372036854775807);
+// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
+// Int128 val2((long64)9223372036854775807);
// Int128 val3 = val1 * val2;
// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
//------------------------------------------------------------------------------
@@ -249,22 +251,21 @@ bool PolyNode::IsOpen() const
class Int128
{
public:
+ ulong64 lo;
+ long64 hi;
- cUInt lo;
- cInt hi;
-
- Int128(cInt _lo = 0)
+ Int128(long64 _lo = 0)
{
- lo = (cUInt)_lo;
+ lo = (ulong64)_lo;
if (_lo < 0) hi = -1; else hi = 0;
}
Int128(const Int128 &val): lo(val.lo), hi(val.hi){}
- Int128(const cInt& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
+ Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
- Int128& operator = (const cInt &val)
+ Int128& operator = (const long64 &val)
{
lo = (ulong64)val;
if (val < 0) hi = -1; else hi = 0;
@@ -330,81 +331,18 @@ class Int128
Int128 operator-() const //unary negation
{
if (lo == 0)
- return Int128(-hi,0);
- else
- return Int128(~hi,~lo +1);
- }
-
- Int128 operator/ (const Int128 &rhs) const
- {
- if (rhs.lo == 0 && rhs.hi == 0)
- throw "Int128 operator/: divide by zero";
-
- bool negate = (rhs.hi < 0) != (hi < 0);
- Int128 dividend = *this;
- Int128 divisor = rhs;
- if (dividend.hi < 0) dividend = -dividend;
- if (divisor.hi < 0) divisor = -divisor;
-
- if (divisor < dividend)
- {
- Int128 result = Int128(0);
- Int128 cntr = Int128(1);
- while (divisor.hi >= 0 && !(divisor > dividend))
- {
- divisor.hi <<= 1;
- if ((cInt)divisor.lo < 0) divisor.hi++;
- divisor.lo <<= 1;
-
- cntr.hi <<= 1;
- if ((cInt)cntr.lo < 0) cntr.hi++;
- cntr.lo <<= 1;
- }
- divisor.lo >>= 1;
- if ((divisor.hi & 1) == 1)
- divisor.lo |= 0x8000000000000000LL;
- divisor.hi = (ulong64)divisor.hi >> 1;
-
- cntr.lo >>= 1;
- if ((cntr.hi & 1) == 1)
- cntr.lo |= 0x8000000000000000LL;
- cntr.hi >>= 1;
-
- while (cntr.hi != 0 || cntr.lo != 0)
- {
- if (!(dividend < divisor))
- {
- dividend -= divisor;
- result.hi |= cntr.hi;
- result.lo |= cntr.lo;
- }
- divisor.lo >>= 1;
- if ((divisor.hi & 1) == 1)
- divisor.lo |= 0x8000000000000000LL;
- divisor.hi >>= 1;
-
- cntr.lo >>= 1;
- if ((cntr.hi & 1) == 1)
- cntr.lo |= 0x8000000000000000LL;
- cntr.hi >>= 1;
- }
- if (negate) result = -result;
- return result;
- }
- else if (rhs.hi == this->hi && rhs.lo == this->lo)
- return Int128(negate ? -1: 1);
+ return Int128(-hi, 0);
else
- return Int128(0);
+ return Int128(~hi, ~lo + 1);
}
- double AsDouble() const
+ operator double() const
{
const double shift64 = 18446744073709551616.0; //2^64
if (hi < 0)
{
- cUInt lo_ = ~lo + 1;
- if (lo_ == 0) return (double)hi * shift64;
- else return -(double)(lo_ + ~hi * shift64);
+ if (lo == 0) return (double)hi * shift64;
+ else return -(double)(~lo + ~hi * shift64);
}
else
return (double)(lo + hi * shift64);
@@ -413,7 +351,7 @@ class Int128
};
//------------------------------------------------------------------------------
-Int128 Int128Mul (cInt lhs, cInt rhs)
+Int128 Int128Mul (long64 lhs, long64 rhs)
{
bool negate = (lhs < 0) != (rhs < 0);
@@ -431,9 +369,9 @@ Int128 Int128Mul (cInt lhs, cInt rhs)
ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
Int128 tmp;
- tmp.hi = cInt(a + (c >> 32));
- tmp.lo = cInt(c << 32);
- tmp.lo += cInt(b);
+ tmp.hi = long64(a + (c >> 32));
+ tmp.lo = long64(c << 32);
+ tmp.lo += long64(b);
if (tmp.lo < b) tmp.hi++;
if (negate) tmp = -tmp;
return tmp;
@@ -465,19 +403,25 @@ double Area(const Path &poly)
}
//------------------------------------------------------------------------------
-double Area(const OutRec &outRec)
+double Area(const OutPt *op)
{
- OutPt *op = outRec.Pts;
+ const OutPt *startOp = op;
if (!op) return 0;
double a = 0;
do {
a += (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y);
op = op->Next;
- } while (op != outRec.Pts);
+ } while (op != startOp);
return a * 0.5;
}
//------------------------------------------------------------------------------
+double Area(const OutRec &outRec)
+{
+ return Area(outRec.Pts);
+}
+//------------------------------------------------------------------------------
+
bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
{
OutPt *pp2 = pp;
@@ -491,10 +435,11 @@ bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
}
//------------------------------------------------------------------------------
-int PointInPolygon (const IntPoint &pt, const Path &path)
+//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
+//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
+int PointInPolygon(const IntPoint &pt, const Path &path)
{
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
- //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
int result = 0;
size_t cnt = path.size();
if (cnt < 3) return 0;
@@ -539,7 +484,6 @@ int PointInPolygon (const IntPoint &pt, const Path &path)
int PointInPolygon (const IntPoint &pt, OutPt *op)
{
//returns 0 if false, +1 if true, -1 if pt ON polygon boundary
- //http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
int result = 0;
OutPt* startOp = op;
for(;;)
@@ -584,8 +528,9 @@ bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
OutPt* op = OutPt1;
do
{
+ //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
int res = PointInPolygon(op->Pt, OutPt2);
- if (res >= 0) return res != 0;
+ if (res >= 0) return res > 0;
op = op->Next;
}
while (op != OutPt1);
@@ -597,10 +542,12 @@ bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
{
#ifndef use_int32
if (UseFullInt64Range)
- return Int128Mul(e1.Delta.Y, e2.Delta.X) == Int128Mul(e1.Delta.X, e2.Delta.Y);
+ return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
+ Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
else
#endif
- return e1.Delta.Y * e2.Delta.X == e1.Delta.X * e2.Delta.Y;
+ return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
+ (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
}
//------------------------------------------------------------------------------
@@ -630,7 +577,7 @@ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
inline bool IsHorizontal(TEdge &e)
{
- return e.Delta.Y == 0;
+ return e.Dx == HORIZONTAL;
}
//------------------------------------------------------------------------------
@@ -643,11 +590,9 @@ inline double GetDx(const IntPoint pt1, const IntPoint pt2)
inline void SetDx(TEdge &e)
{
- e.Delta.X = (e.Top.X - e.Bot.X);
- e.Delta.Y = (e.Top.Y - e.Bot.Y);
-
- if (e.Delta.Y == 0) e.Dx = HORIZONTAL;
- else e.Dx = (double)(e.Delta.X) / e.Delta.Y;
+ cInt dy = (e.Top.Y - e.Bot.Y);
+ if (dy == 0) e.Dx = HORIZONTAL;
+ else e.Dx = (double)(e.Top.X - e.Bot.X) / dy;
}
//---------------------------------------------------------------------------
@@ -674,22 +619,20 @@ inline cInt TopX(TEdge &edge, const cInt currentY)
}
//------------------------------------------------------------------------------
-bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
- IntPoint &ip, bool UseFullInt64Range)
+void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
{
#ifdef use_xyz
ip.Z = 0;
#endif
+
double b1, b2;
- //nb: with very large coordinate values, it's possible for SlopesEqual() to
- //return false but for the edge.Dx value be equal due to double precision rounding.
- if (SlopesEqual(Edge1, Edge2, UseFullInt64Range) || Edge1.Dx == Edge2.Dx)
+ if (Edge1.Dx == Edge2.Dx)
{
- if (Edge2.Bot.Y > Edge1.Bot.Y) ip = Edge2.Bot;
- else ip = Edge1.Bot;
- return false;
+ ip.Y = Edge1.Curr.Y;
+ ip.X = TopX(Edge1, ip.Y);
+ return;
}
- else if (Edge1.Delta.X == 0)
+ else if (Edge1.Dx == 0)
{
ip.X = Edge1.Bot.X;
if (IsHorizontal(Edge2))
@@ -700,7 +643,7 @@ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
ip.Y = Round(ip.X / Edge2.Dx + b2);
}
}
- else if (Edge2.Delta.X == 0)
+ else if (Edge2.Dx == 0)
{
ip.X = Edge2.Bot.X;
if (IsHorizontal(Edge1))
@@ -734,7 +677,15 @@ bool IntersectPoint(TEdge &Edge1, TEdge &Edge2,
else
ip.X = TopX(Edge2, ip.Y);
}
- return true;
+ //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
+ if (ip.Y > Edge1.Curr.Y)
+ {
+ ip.Y = Edge1.Curr.Y;
+ //use the more vertical edge to derive X ...
+ if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
+ ip.X = TopX(Edge2, ip.Y); else
+ ip.X = TopX(Edge1, ip.Y);
+ }
}
//------------------------------------------------------------------------------
@@ -807,13 +758,9 @@ inline void ReverseHorizontal(TEdge &e)
//swap horizontal edges' Top and Bottom x's so they follow the natural
//progression of the bounds - ie so their xbots will align with the
//adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
- cInt tmp = e.Top.X;
- e.Top.X = e.Bot.X;
- e.Bot.X = tmp;
+ std::swap(e.Top.X, e.Bot.X);
#ifdef use_xyz
- tmp = e.Top.Z;
- e.Top.Z = e.Bot.Z;
- e.Bot.Z = tmp;
+ std::swap(e.Top.Z, e.Bot.Z);
#endif
}
//------------------------------------------------------------------------------
@@ -863,7 +810,12 @@ bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
p = btmPt2->Next;
while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next;
double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt));
- return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
+
+ if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
+ std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
+ return Area(btmPt1) > 0; //if otherwise identical use orientation
+ else
+ return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
}
//------------------------------------------------------------------------------
@@ -905,26 +857,6 @@ OutPt* GetBottomPt(OutPt *pp)
}
//------------------------------------------------------------------------------
-bool FindSegment(OutPt* &pp, bool UseFullInt64Range,
- IntPoint &pt1, IntPoint &pt2)
-{
- //OutPt1 & OutPt2 => the overlap segment (if the function returns true)
- if (!pp) return false;
- OutPt* pp2 = pp;
- IntPoint pt1a = pt1, pt2a = pt2;
- do
- {
- if (SlopesEqual(pt1a, pt2a, pp->Pt, pp->Prev->Pt, UseFullInt64Range) &&
- SlopesEqual(pt1a, pt2a, pp->Pt, UseFullInt64Range) &&
- GetOverlapSegment(pt1a, pt2a, pp->Pt, pp->Prev->Pt, pt1, pt2))
- return true;
- pp = pp->Next;
- }
- while (pp != pp2);
- return false;
-}
-//------------------------------------------------------------------------------
-
bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
const IntPoint pt2, const IntPoint pt3)
{
@@ -937,50 +869,20 @@ bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
}
//------------------------------------------------------------------------------
-OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt)
-{
- if (p1 == p2) throw "JoinError";
- OutPt* result = new OutPt;
- result->Pt = Pt;
- if (p2 == p1->Next)
- {
- p1->Next = result;
- p2->Prev = result;
- result->Next = p2;
- result->Prev = p1;
- } else
- {
- p2->Next = result;
- p1->Prev = result;
- result->Next = p1;
- result->Prev = p2;
- }
- return result;
-}
-//------------------------------------------------------------------------------
-
-bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b,
- const IntPoint& pt2a, const IntPoint& pt2b)
+bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
{
- //precondition: both segments are horizontal
- if ((pt1a.X > pt2a.X) == (pt1a.X < pt2b.X)) return true;
- else if ((pt1b.X > pt2a.X) == (pt1b.X < pt2b.X)) return true;
- else if ((pt2a.X > pt1a.X) == (pt2a.X < pt1b.X)) return true;
- else if ((pt2b.X > pt1a.X) == (pt2b.X < pt1b.X)) return true;
- else if ((pt1a.X == pt2a.X) && (pt1b.X == pt2b.X)) return true;
- else if ((pt1a.X == pt2b.X) && (pt1b.X == pt2a.X)) return true;
- else return false;
+ if (seg1a > seg1b) std::swap(seg1a, seg1b);
+ if (seg2a > seg2b) std::swap(seg2a, seg2b);
+ return (seg1a < seg2b) && (seg2a < seg1b);
}
-
//------------------------------------------------------------------------------
// ClipperBase class methods ...
//------------------------------------------------------------------------------
ClipperBase::ClipperBase() //constructor
{
- m_MinimaList = 0;
- m_CurrentLM = 0;
+ m_CurrentLM = m_MinimaList.begin(); //begin() == end() here
m_UseFullRange = false;
}
//------------------------------------------------------------------------------
@@ -996,7 +898,7 @@ void RangeTest(const IntPoint& Pt, bool& useFullRange)
if (useFullRange)
{
if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
- throw "Coordinate outside allowed range";
+ throw clipperException("Coordinate outside allowed range");
}
else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
{
@@ -1023,114 +925,119 @@ TEdge* FindNextLocMin(TEdge* E)
}
//------------------------------------------------------------------------------
-TEdge* ClipperBase::ProcessBound(TEdge* E, bool IsClockwise)
+TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
{
- TEdge *EStart = E, *Result = E;
+ TEdge *Result = E;
TEdge *Horz = 0;
- cInt StartX;
- if (IsHorizontal(*E))
- {
- //it's possible for adjacent overlapping horz edges to start heading left
- //before finishing right, so ...
- if (IsClockwise) StartX = E->Prev->Bot.X;
- else StartX = E->Next->Bot.X;
- if (E->Bot.X != StartX) ReverseHorizontal(*E);
- }
-
- if (Result->OutIdx != Skip)
- {
- if (IsClockwise)
- {
- while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
- Result = Result->Next;
- if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
- {
- //nb: at the top of a bound, horizontals are added to the bound
- //only when the preceding edge attaches to the horizontal's left vertex
- //unless a Skip edge is encountered when that becomes the top divide
- Horz = Result;
- while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
- if (Horz->Prev->Top.X == Result->Next->Top.X)
- {
- if (!IsClockwise) Result = Horz->Prev;
- }
- else if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
- }
- while (E != Result)
- {
- E->NextInLML = E->Next;
- if (IsHorizontal(*E) && E != EStart &&
- E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
- E = E->Next;
- }
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
- ReverseHorizontal(*E);
- Result = Result->Next; //move to the edge just beyond current bound
- } else
- {
- while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
- Result = Result->Prev;
- if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
- {
- Horz = Result;
- while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
- if (Horz->Next->Top.X == Result->Prev->Top.X)
- {
- if (!IsClockwise) Result = Horz->Next;
- }
- else if (Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
- }
- while (E != Result)
- {
- E->NextInLML = E->Prev;
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
- ReverseHorizontal(*E);
- E = E->Prev;
- }
- if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
- ReverseHorizontal(*E);
- Result = Result->Prev; //move to the edge just beyond current bound
- }
- }
-
- if (Result->OutIdx == Skip)
+ if (E->OutIdx == Skip)
{
//if edges still remain in the current bound beyond the skip edge then
//create another LocMin and call ProcessBound once more
- E = Result;
- if (IsClockwise)
+ if (NextIsForward)
{
while (E->Top.Y == E->Next->Bot.Y) E = E->Next;
//don't include top horizontals when parsing a bound a second time,
//they will be contained in the opposite bound ...
while (E != Result && IsHorizontal(*E)) E = E->Prev;
- } else
+ }
+ else
{
while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev;
while (E != Result && IsHorizontal(*E)) E = E->Next;
}
+
if (E == Result)
{
- if (IsClockwise) Result = E->Next;
+ if (NextIsForward) Result = E->Next;
else Result = E->Prev;
- } else
+ }
+ else
{
//there are more edges in the bound beyond result starting with E
- if (IsClockwise)
- E = Result->Next;
+ if (NextIsForward)
+ E = Result->Next;
else
E = Result->Prev;
- LocalMinima* locMin = new LocalMinima;
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
- locMin->LeftBound = 0;
- locMin->RightBound = E;
- locMin->RightBound->WindDelta = 0;
- Result = ProcessBound(locMin->RightBound, IsClockwise);
- InsertLocalMinima(locMin);
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
+ locMin.LeftBound = 0;
+ locMin.RightBound = E;
+ E->WindDelta = 0;
+ Result = ProcessBound(E, NextIsForward);
+ m_MinimaList.push_back(locMin);
}
+ return Result;
}
+
+ TEdge *EStart;
+
+ if (IsHorizontal(*E))
+ {
+ //We need to be careful with open paths because this may not be a
+ //true local minima (ie E may be following a skip edge).
+ //Also, consecutive horz. edges may start heading left before going right.
+ if (NextIsForward)
+ EStart = E->Prev;
+ else
+ EStart = E->Next;
+ if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
+ {
+ if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
+ ReverseHorizontal(*E);
+ }
+ else if (EStart->Bot.X != E->Bot.X)
+ ReverseHorizontal(*E);
+ }
+
+ EStart = E;
+ if (NextIsForward)
+ {
+ while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
+ Result = Result->Next;
+ if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
+ {
+ //nb: at the top of a bound, horizontals are added to the bound
+ //only when the preceding edge attaches to the horizontal's left vertex
+ //unless a Skip edge is encountered when that becomes the top divide
+ Horz = Result;
+ while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
+ if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
+ }
+ while (E != Result)
+ {
+ E->NextInLML = E->Next;
+ if (IsHorizontal(*E) && E != EStart &&
+ E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ E = E->Next;
+ }
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
+ ReverseHorizontal(*E);
+ Result = Result->Next; //move to the edge just beyond current bound
+ } else
+ {
+ while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
+ Result = Result->Prev;
+ if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
+ {
+ Horz = Result;
+ while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
+ if (Horz->Next->Top.X == Result->Prev->Top.X ||
+ Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
+ }
+
+ while (E != Result)
+ {
+ E->NextInLML = E->Prev;
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ ReverseHorizontal(*E);
+ E = E->Prev;
+ }
+ if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
+ ReverseHorizontal(*E);
+ Result = Result->Prev; //move to the edge just beyond current bound
+ }
+
return Result;
}
//------------------------------------------------------------------------------
@@ -1179,7 +1086,8 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
TEdge *E = eStart, *eLoopStop = eStart;
for (;;)
{
- if ((E->Curr == E->Next->Curr))
+ //nb: allows matching start and end points when not Closed ...
+ if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart))
{
if (E == E->Next) break;
if (E == eStart) eStart = E->Next;
@@ -1205,7 +1113,7 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
continue;
}
E = E->Next;
- if (E == eLoopStop) break;
+ if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break;
}
if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next)))
@@ -1242,28 +1150,32 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
return false;
}
E->Prev->OutIdx = Skip;
- if (E->Prev->Bot.X < E->Prev->Top.X) ReverseHorizontal(*E->Prev);
- LocalMinima* locMin = new LocalMinima();
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
- locMin->LeftBound = 0;
- locMin->RightBound = E;
- locMin->RightBound->Side = esRight;
- locMin->RightBound->WindDelta = 0;
- while (E->Next->OutIdx != Skip)
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
+ locMin.LeftBound = 0;
+ locMin.RightBound = E;
+ locMin.RightBound->Side = esRight;
+ locMin.RightBound->WindDelta = 0;
+ for (;;)
{
- E->NextInLML = E->Next;
if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
+ if (E->Next->OutIdx == Skip) break;
+ E->NextInLML = E->Next;
E = E->Next;
}
- InsertLocalMinima(locMin);
+ m_MinimaList.push_back(locMin);
m_edges.push_back(edges);
return true;
}
m_edges.push_back(edges);
- bool clockwise;
+ bool leftBoundIsForward;
TEdge* EMin = 0;
+
+ //workaround to avoid an endless loop in the while loop below when
+ //open paths have matching start and end points ...
+ if (E->Prev->Bot == E->Prev->Top) E = E->Next;
+
for (;;)
{
E = FindNextLocMin(E);
@@ -1272,38 +1184,38 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
//E and E.Prev now share a local minima (left aligned if horizontal).
//Compare their slopes to find which starts which bound ...
- LocalMinima* locMin = new LocalMinima;
- locMin->Next = 0;
- locMin->Y = E->Bot.Y;
+ MinimaList::value_type locMin;
+ locMin.Y = E->Bot.Y;
if (E->Dx < E->Prev->Dx)
{
- locMin->LeftBound = E->Prev;
- locMin->RightBound = E;
- clockwise = false; //Q.nextInLML = Q.prev
+ locMin.LeftBound = E->Prev;
+ locMin.RightBound = E;
+ leftBoundIsForward = false; //Q.nextInLML = Q.prev
} else
{
- locMin->LeftBound = E;
- locMin->RightBound = E->Prev;
- clockwise = true; //Q.nextInLML = Q.next
+ locMin.LeftBound = E;
+ locMin.RightBound = E->Prev;
+ leftBoundIsForward = true; //Q.nextInLML = Q.next
}
- locMin->LeftBound->Side = esLeft;
- locMin->RightBound->Side = esRight;
-
- if (!Closed) locMin->LeftBound->WindDelta = 0;
- else if (locMin->LeftBound->Next == locMin->RightBound)
- locMin->LeftBound->WindDelta = -1;
- else locMin->LeftBound->WindDelta = 1;
- locMin->RightBound->WindDelta = -locMin->LeftBound->WindDelta;
-
- E = ProcessBound(locMin->LeftBound, clockwise);
- TEdge* E2 = ProcessBound(locMin->RightBound, !clockwise);
-
- if (locMin->LeftBound->OutIdx == Skip)
- locMin->LeftBound = 0;
- else if (locMin->RightBound->OutIdx == Skip)
- locMin->RightBound = 0;
- InsertLocalMinima(locMin);
- if (!clockwise) E = E2;
+
+ if (!Closed) locMin.LeftBound->WindDelta = 0;
+ else if (locMin.LeftBound->Next == locMin.RightBound)
+ locMin.LeftBound->WindDelta = -1;
+ else locMin.LeftBound->WindDelta = 1;
+ locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
+
+ E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
+ if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
+
+ TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
+ if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
+
+ if (locMin.LeftBound->OutIdx == Skip)
+ locMin.LeftBound = 0;
+ else if (locMin.RightBound->OutIdx == Skip)
+ locMin.RightBound = 0;
+ m_MinimaList.push_back(locMin);
+ if (!leftBoundIsForward) E = E2;
}
return true;
}
@@ -1318,34 +1230,11 @@ bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
}
//------------------------------------------------------------------------------
-void ClipperBase::InsertLocalMinima(LocalMinima *newLm)
-{
- if( ! m_MinimaList )
- {
- m_MinimaList = newLm;
- }
- else if( newLm->Y >= m_MinimaList->Y )
- {
- newLm->Next = m_MinimaList;
- m_MinimaList = newLm;
- } else
- {
- LocalMinima* tmpLm = m_MinimaList;
- while( tmpLm->Next && ( newLm->Y < tmpLm->Next->Y ) )
- tmpLm = tmpLm->Next;
- newLm->Next = tmpLm->Next;
- tmpLm->Next = newLm;
- }
-}
-//------------------------------------------------------------------------------
-
void ClipperBase::Clear()
{
DisposeLocalMinimaList();
for (EdgeList::size_type i = 0; i < m_edges.size(); ++i)
{
- //for each edge array in turn, find the first used edge and
- //check for and remove any hiddenPts in each edge in the array.
TEdge* edges = m_edges[i];
delete [] edges;
}
@@ -1357,13 +1246,15 @@ void ClipperBase::Clear()
void ClipperBase::Reset()
{
- m_CurrentLM = m_MinimaList;
- if( !m_CurrentLM ) return; //ie nothing to process
+ m_CurrentLM = m_MinimaList.begin();
+ if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process
+ std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
+ m_Scanbeam = ScanbeamList(); //clears/resets priority_queue
//reset all edges ...
- LocalMinima* lm = m_MinimaList;
- while( lm )
+ for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
{
+ InsertScanbeam(lm->Y);
TEdge* e = lm->LeftBound;
if (e)
{
@@ -1379,35 +1270,33 @@ void ClipperBase::Reset()
e->Side = esRight;
e->OutIdx = Unassigned;
}
- lm = lm->Next;
}
+ m_ActiveEdges = 0;
+ m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
void ClipperBase::DisposeLocalMinimaList()
{
- while( m_MinimaList )
- {
- LocalMinima* tmpLm = m_MinimaList->Next;
- delete m_MinimaList;
- m_MinimaList = tmpLm;
- }
- m_CurrentLM = 0;
+ m_MinimaList.clear();
+ m_CurrentLM = m_MinimaList.begin();
}
//------------------------------------------------------------------------------
-void ClipperBase::PopLocalMinima()
+bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin)
{
- if( ! m_CurrentLM ) return;
- m_CurrentLM = m_CurrentLM->Next;
+ if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false;
+ locMin = &(*m_CurrentLM);
+ ++m_CurrentLM;
+ return true;
}
//------------------------------------------------------------------------------
IntRect ClipperBase::GetBounds()
{
IntRect result;
- LocalMinima* lm = m_MinimaList;
- if (!lm)
+ MinimaList::iterator lm = m_MinimaList.begin();
+ if (lm == m_MinimaList.end())
{
result.left = result.top = result.right = result.bottom = 0;
return result;
@@ -1416,10 +1305,10 @@ IntRect ClipperBase::GetBounds()
result.top = lm->LeftBound->Bot.Y;
result.right = lm->LeftBound->Bot.X;
result.bottom = lm->LeftBound->Bot.Y;
- while (lm)
+ while (lm != m_MinimaList.end())
{
- if (lm->LeftBound->Bot.Y > result.bottom)
- result.bottom = lm->LeftBound->Bot.Y;
+ //todo - needs fixing for open paths
+ result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
TEdge* e = lm->LeftBound;
for (;;) {
TEdge* bottomE = e;
@@ -1429,19 +1318,154 @@ IntRect ClipperBase::GetBounds()
if (e->Bot.X > result.right) result.right = e->Bot.X;
e = e->NextInLML;
}
- if (e->Bot.X < result.left) result.left = e->Bot.X;
- if (e->Bot.X > result.right) result.right = e->Bot.X;
- if (e->Top.X < result.left) result.left = e->Top.X;
- if (e->Top.X > result.right) result.right = e->Top.X;
- if (e->Top.Y < result.top) result.top = e->Top.Y;
-
+ result.left = std::min(result.left, e->Bot.X);
+ result.right = std::max(result.right, e->Bot.X);
+ result.left = std::min(result.left, e->Top.X);
+ result.right = std::max(result.right, e->Top.X);
+ result.top = std::min(result.top, e->Top.Y);
if (bottomE == lm->LeftBound) e = lm->RightBound;
else break;
}
- lm = lm->Next;
+ ++lm;
}
return result;
}
+//------------------------------------------------------------------------------
+
+void ClipperBase::InsertScanbeam(const cInt Y)
+{
+ m_Scanbeam.push(Y);
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::PopScanbeam(cInt &Y)
+{
+ if (m_Scanbeam.empty()) return false;
+ Y = m_Scanbeam.top();
+ m_Scanbeam.pop();
+ while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
+ return true;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DisposeAllOutRecs(){
+ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+ DisposeOutRec(i);
+ m_PolyOuts.clear();
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DisposeOutRec(PolyOutList::size_type index)
+{
+ OutRec *outRec = m_PolyOuts[index];
+ if (outRec->Pts) DisposeOutPts(outRec->Pts);
+ delete outRec;
+ m_PolyOuts[index] = 0;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::DeleteFromAEL(TEdge *e)
+{
+ TEdge* AelPrev = e->PrevInAEL;
+ TEdge* AelNext = e->NextInAEL;
+ if (!AelPrev && !AelNext && (e != m_ActiveEdges)) return; //already deleted
+ if (AelPrev) AelPrev->NextInAEL = AelNext;
+ else m_ActiveEdges = AelNext;
+ if (AelNext) AelNext->PrevInAEL = AelPrev;
+ e->NextInAEL = 0;
+ e->PrevInAEL = 0;
+}
+//------------------------------------------------------------------------------
+
+OutRec* ClipperBase::CreateOutRec()
+{
+ OutRec* result = new OutRec;
+ result->IsHole = false;
+ result->IsOpen = false;
+ result->FirstLeft = 0;
+ result->Pts = 0;
+ result->BottomPt = 0;
+ result->PolyNd = 0;
+ m_PolyOuts.push_back(result);
+ result->Idx = (int)m_PolyOuts.size() - 1;
+ return result;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
+{
+ //check that one or other edge hasn't already been removed from AEL ...
+ if (Edge1->NextInAEL == Edge1->PrevInAEL ||
+ Edge2->NextInAEL == Edge2->PrevInAEL) return;
+
+ if (Edge1->NextInAEL == Edge2)
+ {
+ TEdge* Next = Edge2->NextInAEL;
+ if (Next) Next->PrevInAEL = Edge1;
+ TEdge* Prev = Edge1->PrevInAEL;
+ if (Prev) Prev->NextInAEL = Edge2;
+ Edge2->PrevInAEL = Prev;
+ Edge2->NextInAEL = Edge1;
+ Edge1->PrevInAEL = Edge2;
+ Edge1->NextInAEL = Next;
+ }
+ else if (Edge2->NextInAEL == Edge1)
+ {
+ TEdge* Next = Edge1->NextInAEL;
+ if (Next) Next->PrevInAEL = Edge2;
+ TEdge* Prev = Edge2->PrevInAEL;
+ if (Prev) Prev->NextInAEL = Edge1;
+ Edge1->PrevInAEL = Prev;
+ Edge1->NextInAEL = Edge2;
+ Edge2->PrevInAEL = Edge1;
+ Edge2->NextInAEL = Next;
+ }
+ else
+ {
+ TEdge* Next = Edge1->NextInAEL;
+ TEdge* Prev = Edge1->PrevInAEL;
+ Edge1->NextInAEL = Edge2->NextInAEL;
+ if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1;
+ Edge1->PrevInAEL = Edge2->PrevInAEL;
+ if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1;
+ Edge2->NextInAEL = Next;
+ if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2;
+ Edge2->PrevInAEL = Prev;
+ if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2;
+ }
+
+ if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1;
+ else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2;
+}
+//------------------------------------------------------------------------------
+
+void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e)
+{
+ if (!e->NextInLML)
+ throw clipperException("UpdateEdgeIntoAEL: invalid call");
+
+ e->NextInLML->OutIdx = e->OutIdx;
+ TEdge* AelPrev = e->PrevInAEL;
+ TEdge* AelNext = e->NextInAEL;
+ if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
+ else m_ActiveEdges = e->NextInLML;
+ if (AelNext) AelNext->PrevInAEL = e->NextInLML;
+ e->NextInLML->Side = e->Side;
+ e->NextInLML->WindDelta = e->WindDelta;
+ e->NextInLML->WindCnt = e->WindCnt;
+ e->NextInLML->WindCnt2 = e->WindCnt2;
+ e = e->NextInLML;
+ e->Curr = e->Bot;
+ e->PrevInAEL = AelPrev;
+ e->NextInAEL = AelNext;
+ if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
+}
+//------------------------------------------------------------------------------
+
+bool ClipperBase::LocalMinimaPending()
+{
+ return (m_CurrentLM != m_MinimaList.end());
+}
//------------------------------------------------------------------------------
// TClipper methods ...
@@ -1449,8 +1473,6 @@ IntRect ClipperBase::GetBounds()
Clipper::Clipper(int initOptions) : ClipperBase() //constructor
{
- m_ActiveEdges = 0;
- m_SortedEdges = 0;
m_ExecuteLocked = false;
m_UseFullRange = false;
m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
@@ -1463,33 +1485,23 @@ Clipper::Clipper(int initOptions) : ClipperBase() //constructor
}
//------------------------------------------------------------------------------
-Clipper::~Clipper() //destructor
-{
- Clear();
- m_Scanbeam.clear();
-}
-//------------------------------------------------------------------------------
-
#ifdef use_xyz
-void Clipper::ZFillFunction(TZFillCallback zFillFunc)
+void Clipper::ZFillFunction(ZFillCallback zFillFunc)
{
m_ZFill = zFillFunc;
}
//------------------------------------------------------------------------------
#endif
-void Clipper::Reset()
+bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType)
{
- ClipperBase::Reset();
- m_Scanbeam.clear();
- m_ActiveEdges = 0;
- m_SortedEdges = 0;
- LocalMinima* lm = m_MinimaList;
- while (lm)
- {
- InsertScanbeam(lm->Y);
- lm = lm->Next;
- }
+ return Execute(clipType, solution, fillType, fillType);
+}
+//------------------------------------------------------------------------------
+
+bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType)
+{
+ return Execute(clipType, polytree, fillType, fillType);
}
//------------------------------------------------------------------------------
@@ -1498,7 +1510,7 @@ bool Clipper::Execute(ClipType clipType, Paths &solution,
{
if( m_ExecuteLocked ) return false;
if (m_HasOpenPaths)
- throw clipperException("Error: PolyTree struct is need for open path clipping.");
+ throw clipperException("Error: PolyTree struct is needed for open path clipping.");
m_ExecuteLocked = true;
solution.resize(0);
m_SubjFillType = subjFillType;
@@ -1550,19 +1562,26 @@ bool Clipper::ExecuteInternal()
bool succeeded = true;
try {
Reset();
- if (!m_CurrentLM) return false;
- cInt botY = PopScanbeam();
- do {
- InsertLocalMinimaIntoAEL(botY);
- ClearGhostJoins();
- ProcessHorizontals(false);
- if (m_Scanbeam.empty()) break;
- cInt topY = PopScanbeam();
- succeeded = ProcessIntersections(botY, topY);
- if (!succeeded) break;
+ m_Maxima = MaximaList();
+ m_SortedEdges = 0;
+
+ succeeded = true;
+ cInt botY, topY;
+ if (!PopScanbeam(botY)) return false;
+ InsertLocalMinimaIntoAEL(botY);
+ while (PopScanbeam(topY) || LocalMinimaPending())
+ {
+ ProcessHorizontals();
+ ClearGhostJoins();
+ if (!ProcessIntersections(topY))
+ {
+ succeeded = false;
+ break;
+ }
ProcessEdgesAtTopOfScanbeam(topY);
botY = topY;
- } while (!m_Scanbeam.empty() || m_CurrentLM);
+ InsertLocalMinimaIntoAEL(botY);
+ }
}
catch(...)
{
@@ -1586,7 +1605,10 @@ bool Clipper::ExecuteInternal()
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec *outRec = m_PolyOuts[i];
- if (outRec->Pts && !outRec->IsOpen)
+ if (!outRec->Pts) continue;
+ if (outRec->IsOpen)
+ FixupOutPolyline(*outRec);
+ else
FixupOutPolygon(*outRec);
}
@@ -1599,36 +1621,6 @@ bool Clipper::ExecuteInternal()
}
//------------------------------------------------------------------------------
-void Clipper::InsertScanbeam(const cInt Y)
-{
- m_Scanbeam.insert(Y);
-}
-//------------------------------------------------------------------------------
-
-cInt Clipper::PopScanbeam()
-{
- cInt Y = *m_Scanbeam.begin();
- m_Scanbeam.erase(m_Scanbeam.begin());
- return Y;
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeAllOutRecs(){
- for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
- DisposeOutRec(i);
- m_PolyOuts.clear();
-}
-//------------------------------------------------------------------------------
-
-void Clipper::DisposeOutRec(PolyOutList::size_type index)
-{
- OutRec *outRec = m_PolyOuts[index];
- if (outRec->Pts) DisposeOutPts(outRec->Pts);
- delete outRec;
- m_PolyOuts[index] = 0;
-}
-//------------------------------------------------------------------------------
-
void Clipper::SetWindingCount(TEdge &edge)
{
TEdge *e = edge.PrevInAEL;
@@ -1636,7 +1628,13 @@ void Clipper::SetWindingCount(TEdge &edge)
while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
if (!e)
{
- edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
+ if (edge.WindDelta == 0)
+ {
+ PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
+ edge.WindCnt = (pft == pftNegative ? -1 : 1);
+ }
+ else
+ edge.WindCnt = edge.WindDelta;
edge.WindCnt2 = 0;
e = m_ActiveEdges; //ie get ready to calc WindCnt2
}
@@ -1868,13 +1866,16 @@ OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
prevE = e->PrevInAEL;
}
- if (prevE && prevE->OutIdx >= 0 &&
- (TopX(*prevE, Pt.Y) == TopX(*e, Pt.Y)) &&
- SlopesEqual(*e, *prevE, m_UseFullRange) &&
- (e->WindDelta != 0) && (prevE->WindDelta != 0))
+ if (prevE && prevE->OutIdx >= 0)
{
- OutPt* outPt = AddOutPt(prevE, Pt);
- AddJoin(result, outPt, e->Top);
+ cInt xPrev = TopX(*prevE, Pt.Y);
+ cInt xE = TopX(*e, Pt.Y);
+ if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
+ SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange))
+ {
+ OutPt* outPt = AddOutPt(prevE, Pt);
+ AddJoin(result, outPt, e->Top);
+ }
}
return result;
}
@@ -1916,6 +1917,15 @@ void Clipper::AddEdgeToSEL(TEdge *edge)
}
//------------------------------------------------------------------------------
+bool Clipper::PopEdgeFromSEL(TEdge *&edge)
+{
+ if (!m_SortedEdges) return false;
+ edge = m_SortedEdges;
+ DeleteFromSEL(m_SortedEdges);
+ return true;
+}
+//------------------------------------------------------------------------------
+
void Clipper::CopyAELToSEL()
{
TEdge* e = m_ActiveEdges;
@@ -1967,11 +1977,12 @@ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt)
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
- while( m_CurrentLM && ( m_CurrentLM->Y == botY ) )
+ const LocalMinimum *lm;
+ while (PopLocalMinima(botY, lm))
{
- TEdge* lb = m_CurrentLM->LeftBound;
- TEdge* rb = m_CurrentLM->RightBound;
- PopLocalMinima();
+ TEdge* lb = lm->LeftBound;
+ TEdge* rb = lm->RightBound;
+
OutPt *Op1 = 0;
if (!lb)
{
@@ -2003,8 +2014,13 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (rb)
{
- if(IsHorizontal(*rb)) AddEdgeToSEL(rb);
- else InsertScanbeam( rb->Top.Y );
+ if (IsHorizontal(*rb))
+ {
+ AddEdgeToSEL(rb);
+ if (rb->NextInLML)
+ InsertScanbeam(rb->NextInLML->Top.Y);
+ }
+ else InsertScanbeam( rb->Top.Y );
}
if (!lb || !rb) continue;
@@ -2018,7 +2034,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
Join* jr = m_GhostJoins[i];
//if the horizontal Rb and a 'ghost' horizontal overlap, then convert
//the 'ghost' join to a real join ready for later ...
- if (HorzSegmentsOverlap(jr->OutPt1->Pt, jr->OffPt, rb->Bot, rb->Top))
+ if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X))
AddJoin(jr->OutPt1, Op1, jr->OffPt);
}
}
@@ -2026,7 +2042,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
if (lb->OutIdx >= 0 && lb->PrevInAEL &&
lb->PrevInAEL->Curr.X == lb->Bot.X &&
lb->PrevInAEL->OutIdx >= 0 &&
- SlopesEqual(*lb->PrevInAEL, *lb, m_UseFullRange) &&
+ SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) &&
(lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
@@ -2037,7 +2053,7 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
{
if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
- SlopesEqual(*rb->PrevInAEL, *rb, m_UseFullRange) &&
+ SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) &&
(rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
{
OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
@@ -2061,19 +2077,6 @@ void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
}
//------------------------------------------------------------------------------
-void Clipper::DeleteFromAEL(TEdge *e)
-{
- TEdge* AelPrev = e->PrevInAEL;
- TEdge* AelNext = e->NextInAEL;
- if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted
- if( AelPrev ) AelPrev->NextInAEL = AelNext;
- else m_ActiveEdges = AelNext;
- if( AelNext ) AelNext->PrevInAEL = AelPrev;
- e->NextInAEL = 0;
- e->PrevInAEL = 0;
-}
-//------------------------------------------------------------------------------
-
void Clipper::DeleteFromSEL(TEdge *e)
{
TEdge* SelPrev = e->PrevInSEL;
@@ -2088,45 +2091,34 @@ void Clipper::DeleteFromSEL(TEdge *e)
//------------------------------------------------------------------------------
#ifdef use_xyz
-
-void Clipper::SetZ(IntPoint& pt, TEdge& e)
+void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
{
- pt.Z = 0;
- if (m_ZFill)
- {
- //put the 'preferred' point as first parameter ...
- if (e.OutIdx < 0)
- (*m_ZFill)(e.Bot, e.Top, pt); //outside a path so presume entering
- else
- (*m_ZFill)(e.Top, e.Bot, pt); //inside a path so presume exiting
- }
+ if (pt.Z != 0 || !m_ZFill) return;
+ else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
+ else if (pt == e1.Top) pt.Z = e1.Top.Z;
+ else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
+ else if (pt == e2.Top) pt.Z = e2.Top.Z;
+ else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
}
//------------------------------------------------------------------------------
#endif
-void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
- const IntPoint &Pt, bool protect)
+void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
{
- //e1 will be to the Left of e2 BELOW the intersection. Therefore e1 is before
- //e2 in AEL except when e1 is being inserted at the intersection point ...
- bool e1stops = !protect && !e1->NextInLML &&
- e1->Top.X == Pt.X && e1->Top.Y == Pt.Y;
- bool e2stops = !protect && !e2->NextInLML &&
- e2->Top.X == Pt.X && e2->Top.Y == Pt.Y;
bool e1Contributing = ( e1->OutIdx >= 0 );
bool e2Contributing = ( e2->OutIdx >= 0 );
+#ifdef use_xyz
+ SetZ(Pt, *e1, *e2);
+#endif
+
#ifdef use_lines
//if either edge is on an OPEN path ...
if (e1->WindDelta == 0 || e2->WindDelta == 0)
{
//ignore subject-subject open path intersections UNLESS they
//are both open paths, AND they are both 'contributing maximas' ...
- if (e1->WindDelta == 0 && e2->WindDelta == 0)
- {
- if ((e1stops || e2stops) && e1Contributing && e2Contributing)
- AddLocalMaxPoly(e1, e2, Pt);
- }
+ if (e1->WindDelta == 0 && e2->WindDelta == 0) return;
//if intersecting a subj line with a subj poly ...
else if (e1->PolyTyp == e2->PolyTyp &&
@@ -2165,13 +2157,6 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
if (e2Contributing) e2->OutIdx = Unassigned;
}
}
-
- if (e1stops)
- if (e1->OutIdx < 0) DeleteFromAEL(e1);
- else throw clipperException("Error intersecting polylines");
- if (e2stops)
- if (e2->OutIdx < 0) DeleteFromAEL(e2);
- else throw clipperException("Error intersecting polylines");
return;
}
#endif
@@ -2236,10 +2221,11 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
if ( e1Contributing && e2Contributing )
{
- if ( e1stops || e2stops ||
- (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
+ if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
(e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
- AddLocalMaxPoly(e1, e2, Pt);
+ {
+ AddLocalMaxPoly(e1, e2, Pt);
+ }
else
{
AddOutPt(e1, Pt);
@@ -2266,8 +2252,7 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
SwapPolyIndexes(*e1, *e2);
}
}
- else if ( (e1Wc == 0 || e1Wc == 1) &&
- (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
+ else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
{
//neither edge is currently contributing ...
@@ -2286,7 +2271,9 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
}
if (e1->PolyTyp != e2->PolyTyp)
- AddLocalMinPoly(e1, e2, Pt);
+ {
+ AddLocalMinPoly(e1, e2, Pt);
+ }
else if (e1Wc == 1 && e2Wc == 1)
switch( m_ClipType ) {
case ctIntersection:
@@ -2308,35 +2295,32 @@ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
else
SwapSides( *e1, *e2 );
}
-
- if( (e1stops != e2stops) &&
- ( (e1stops && (e1->OutIdx >= 0)) || (e2stops && (e2->OutIdx >= 0)) ) )
- {
- SwapSides( *e1, *e2 );
- SwapPolyIndexes( *e1, *e2 );
- }
-
- //finally, delete any non-contributing maxima edges ...
- if( e1stops ) DeleteFromAEL( e1 );
- if( e2stops ) DeleteFromAEL( e2 );
}
//------------------------------------------------------------------------------
void Clipper::SetHoleState(TEdge *e, OutRec *outrec)
{
- bool IsHole = false;
TEdge *e2 = e->PrevInAEL;
+ TEdge *eTmp = 0;
while (e2)
{
if (e2->OutIdx >= 0 && e2->WindDelta != 0)
{
- IsHole = !IsHole;
- if (! outrec->FirstLeft)
- outrec->FirstLeft = m_PolyOuts[e2->OutIdx];
+ if (!eTmp) eTmp = e2;
+ else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0;
}
e2 = e2->PrevInAEL;
}
- if (IsHole) outrec->IsHole = true;
+ if (!eTmp)
+ {
+ outrec->FirstLeft = 0;
+ outrec->IsHole = false;
+ }
+ else
+ {
+ outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
+ outrec->IsHole = !outrec->FirstLeft->IsHole;
+ }
}
//------------------------------------------------------------------------------
@@ -2360,7 +2344,7 @@ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
}
//------------------------------------------------------------------------------
-bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2)
+bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2)
{
do
{
@@ -2387,9 +2371,9 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
OutRec *holeStateRec;
- if (Param1RightOfParam2(outRec1, outRec2))
+ if (OutRec1RightOfOutRec2(outRec1, outRec2))
holeStateRec = outRec2;
- else if (Param1RightOfParam2(outRec2, outRec1))
+ else if (OutRec1RightOfOutRec2(outRec2, outRec1))
holeStateRec = outRec1;
else
holeStateRec = GetLowermostRec(outRec1, outRec2);
@@ -2402,7 +2386,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
OutPt* p2_lft = outRec2->Pts;
OutPt* p2_rt = p2_lft->Prev;
- EdgeSide Side;
//join e2 poly onto e1 poly and delete pointers to e2 ...
if( e1->Side == esLeft )
{
@@ -2424,7 +2407,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_rt->Next = p2_lft;
outRec1->Pts = p2_lft;
}
- Side = esLeft;
} else
{
if( e2->Side == esRight )
@@ -2443,7 +2425,6 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
p1_lft->Prev = p2_rt;
p2_rt->Next = p1_lft;
}
- Side = esRight;
}
outRec1->BottomPt = 0;
@@ -2469,7 +2450,7 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
if( e->OutIdx == ObsoleteIdx )
{
e->OutIdx = OKIdx;
- e->Side = Side;
+ e->Side = e1->Side;
break;
}
e = e->NextInAEL;
@@ -2479,24 +2460,8 @@ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
}
//------------------------------------------------------------------------------
-OutRec* Clipper::CreateOutRec()
-{
- OutRec* result = new OutRec;
- result->IsHole = false;
- result->IsOpen = false;
- result->FirstLeft = 0;
- result->Pts = 0;
- result->BottomPt = 0;
- result->PolyNd = 0;
- m_PolyOuts.push_back(result);
- result->Idx = (int)m_PolyOuts.size()-1;
- return result;
-}
-//------------------------------------------------------------------------------
-
OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
{
- bool ToFront = (e->Side == esLeft);
if( e->OutIdx < 0 )
{
OutRec *outRec = CreateOutRec();
@@ -2509,12 +2474,7 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
newOp->Prev = newOp;
if (!outRec->IsOpen)
SetHoleState(e, outRec);
-#ifdef use_xyz
- if (pt == e->Bot) newOp->Pt = e->Bot;
- else if (pt == e->Top) newOp->Pt = e->Top;
- else SetZ(newOp->Pt, *e);
-#endif
- e->OutIdx = outRec->Idx; //nb: do this after SetZ !
+ e->OutIdx = outRec->Idx;
return newOp;
} else
{
@@ -2522,7 +2482,8 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
//OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
OutPt* op = outRec->Pts;
- if (ToFront && (pt == op->Pt)) return op;
+ bool ToFront = (e->Side == esLeft);
+ if (ToFront && (pt == op->Pt)) return op;
else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev;
OutPt* newOp = new OutPt;
@@ -2533,25 +2494,26 @@ OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
newOp->Prev->Next = newOp;
op->Prev = newOp;
if (ToFront) outRec->Pts = newOp;
-#ifdef use_xyz
- if (pt == e->Bot) newOp->Pt = e->Bot;
- else if (pt == e->Top) newOp->Pt = e->Top;
- else SetZ(newOp->Pt, *e);
-#endif
return newOp;
}
}
//------------------------------------------------------------------------------
-void Clipper::ProcessHorizontals(bool IsTopOfScanbeam)
+OutPt* Clipper::GetLastOutPt(TEdge *e)
{
- TEdge* horzEdge = m_SortedEdges;
- while(horzEdge)
- {
- DeleteFromSEL(horzEdge);
- ProcessHorizontal(horzEdge, IsTopOfScanbeam);
- horzEdge = m_SortedEdges;
- }
+ OutRec *outRec = m_PolyOuts[e->OutIdx];
+ if (e->Side == esLeft)
+ return outRec->Pts;
+ else
+ return outRec->Pts->Prev;
+}
+//------------------------------------------------------------------------------
+
+void Clipper::ProcessHorizontals()
+{
+ TEdge* horzEdge;
+ while (PopEdgeFromSEL(horzEdge))
+ ProcessHorizontal(horzEdge);
}
//------------------------------------------------------------------------------
@@ -2575,64 +2537,21 @@ inline bool IsIntermediate(TEdge *e, const cInt Y)
TEdge *GetMaximaPair(TEdge *e)
{
- TEdge* result = 0;
if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
- result = e->Next;
+ return e->Next;
else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
- result = e->Prev;
-
- if (result && (result->OutIdx == Skip ||
- //result is false if both NextInAEL & PrevInAEL are nil & not horizontal ...
- (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result))))
- return 0;
- return result;
+ return e->Prev;
+ else return 0;
}
//------------------------------------------------------------------------------
-void Clipper::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
+TEdge *GetMaximaPairEx(TEdge *e)
{
- //check that one or other edge hasn't already been removed from AEL ...
- if (Edge1->NextInAEL == Edge1->PrevInAEL ||
- Edge2->NextInAEL == Edge2->PrevInAEL) return;
-
- if( Edge1->NextInAEL == Edge2 )
- {
- TEdge* Next = Edge2->NextInAEL;
- if( Next ) Next->PrevInAEL = Edge1;
- TEdge* Prev = Edge1->PrevInAEL;
- if( Prev ) Prev->NextInAEL = Edge2;
- Edge2->PrevInAEL = Prev;
- Edge2->NextInAEL = Edge1;
- Edge1->PrevInAEL = Edge2;
- Edge1->NextInAEL = Next;
- }
- else if( Edge2->NextInAEL == Edge1 )
- {
- TEdge* Next = Edge1->NextInAEL;
- if( Next ) Next->PrevInAEL = Edge2;
- TEdge* Prev = Edge2->PrevInAEL;
- if( Prev ) Prev->NextInAEL = Edge1;
- Edge1->PrevInAEL = Prev;
- Edge1->NextInAEL = Edge2;
- Edge2->PrevInAEL = Edge1;
- Edge2->NextInAEL = Next;
- }
- else
- {
- TEdge* Next = Edge1->NextInAEL;
- TEdge* Prev = Edge1->PrevInAEL;
- Edge1->NextInAEL = Edge2->NextInAEL;
- if( Edge1->NextInAEL ) Edge1->NextInAEL->PrevInAEL = Edge1;
- Edge1->PrevInAEL = Edge2->PrevInAEL;
- if( Edge1->PrevInAEL ) Edge1->PrevInAEL->NextInAEL = Edge1;
- Edge2->NextInAEL = Next;
- if( Edge2->NextInAEL ) Edge2->NextInAEL->PrevInAEL = Edge2;
- Edge2->PrevInAEL = Prev;
- if( Edge2->PrevInAEL ) Edge2->PrevInAEL->NextInAEL = Edge2;
- }
-
- if( !Edge1->PrevInAEL ) m_ActiveEdges = Edge1;
- else if( !Edge2->PrevInAEL ) m_ActiveEdges = Edge2;
+ //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal)
+ TEdge* result = GetMaximaPair(e);
+ if (result && (result->OutIdx == Skip ||
+ (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0;
+ return result;
}
//------------------------------------------------------------------------------
@@ -2704,37 +2623,6 @@ void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right)
}
//------------------------------------------------------------------------
-void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
-{
- //get the last Op for this horizontal edge
- //the point may be anywhere along the horizontal ...
- OutPt* outPt = m_PolyOuts[horzEdge->OutIdx]->Pts;
- if (horzEdge->Side != esLeft) outPt = outPt->Prev;
-
- //First, match up overlapping horizontal edges (eg when one polygon's
- //intermediate horz edge overlaps an intermediate horz edge of another, or
- //when one polygon sits on top of another) ...
- //for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
- //{
- // Join* j = m_GhostJoins[i];
- // if (HorzSegmentsOverlap(j->OutPt1->Pt, j->OffPt, horzEdge->Bot, horzEdge->Top))
- // AddJoin(j->OutPt1, outPt, j->OffPt);
- //}
-
- //Also, since horizontal edges at the top of one SB are often removed from
- //the AEL before we process the horizontal edges at the bottom of the next,
- //we need to create 'ghost' Join records of 'contrubuting' horizontals that
- //we can compare with horizontals at the bottom of the next SB.
- if (isTopOfScanbeam)
- {
- if (outPt->Pt == horzEdge->Top)
- AddGhostJoin(outPt, horzEdge->Bot);
- else
- AddGhostJoin(outPt, horzEdge->Top);
- }
-}
-//------------------------------------------------------------------------------
-
/*******************************************************************************
* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or *
* Bottom of a scanbeam) are processed as if layered. The order in which HEs *
@@ -2745,10 +2633,11 @@ void Clipper::PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam)
* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs. *
*******************************************************************************/
-void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
+void Clipper::ProcessHorizontal(TEdge *horzEdge)
{
Direction dir;
cInt horzLeft, horzRight;
+ bool IsOpen = (horzEdge->WindDelta == 0);
GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
@@ -2758,69 +2647,146 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
if (!eLastHorz->NextInLML)
eMaxPair = GetMaximaPair(eLastHorz);
- for (;;)
+ MaximaList::const_iterator maxIt;
+ MaximaList::const_reverse_iterator maxRit;
+ if (m_Maxima.size() > 0)
{
+ //get the first maxima in range (X) ...
+ if (dir == dLeftToRight)
+ {
+ maxIt = m_Maxima.begin();
+ while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++;
+ if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
+ maxIt = m_Maxima.end();
+ }
+ else
+ {
+ maxRit = m_Maxima.rbegin();
+ while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++;
+ if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
+ maxRit = m_Maxima.rend();
+ }
+ }
+
+ OutPt* op1 = 0;
+
+ for (;;) //loop through consec. horizontal edges
+ {
+
bool IsLastHorz = (horzEdge == eLastHorz);
TEdge* e = GetNextInAEL(horzEdge, dir);
while(e)
{
- //Break if we've got to the end of an intermediate horizontal edge ...
- //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
- if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
- e->Dx < horzEdge->NextInLML->Dx) break;
- TEdge* eNext = GetNextInAEL(e, dir); //saves eNext for later
-
- if ((dir == dLeftToRight && e->Curr.X <= horzRight) ||
- (dir == dRightToLeft && e->Curr.X >= horzLeft))
- {
- if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
- PrepareHorzJoins(horzEdge, isTopOfScanbeam);
- //so far we're still in range of the horizontal Edge but make sure
+ //this code block inserts extra coords into horizontal edges (in output
+ //polygons) whereever maxima touch these horizontal edges. This helps
+ //'simplifying' polygons (ie if the Simplify property is set).
+ if (m_Maxima.size() > 0)
+ {
+ if (dir == dLeftToRight)
+ {
+ while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X)
+ {
+ if (horzEdge->OutIdx >= 0 && !IsOpen)
+ AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y));
+ maxIt++;
+ }
+ }
+ else
+ {
+ while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X)
+ {
+ if (horzEdge->OutIdx >= 0 && !IsOpen)
+ AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y));
+ maxRit++;
+ }
+ }
+ };
+
+ if ((dir == dLeftToRight && e->Curr.X > horzRight) ||
+ (dir == dRightToLeft && e->Curr.X < horzLeft)) break;
+
+ //Also break if we've got to the end of an intermediate horizontal edge ...
+ //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
+ if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
+ e->Dx < horzEdge->NextInLML->Dx) break;
+
+ if (horzEdge->OutIdx >= 0 && !IsOpen) //note: may be done multiple times
+ {
+ op1 = AddOutPt(horzEdge, e->Curr);
+ TEdge* eNextHorz = m_SortedEdges;
+ while (eNextHorz)
+ {
+ if (eNextHorz->OutIdx >= 0 &&
+ HorzSegmentsOverlap(horzEdge->Bot.X,
+ horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ {
+ OutPt* op2 = GetLastOutPt(eNextHorz);
+ AddJoin(op2, op1, eNextHorz->Top);
+ }
+ eNextHorz = eNextHorz->NextInSEL;
+ }
+ AddGhostJoin(op1, horzEdge->Bot);
+ }
+
+ //OK, so far we're still in range of the horizontal Edge but make sure
//we're at the last of consec. horizontals when matching with eMaxPair
if(e == eMaxPair && IsLastHorz)
{
- if (dir == dLeftToRight)
- IntersectEdges(horzEdge, e, e->Top);
- else
- IntersectEdges(e, horzEdge, e->Top);
- if (eMaxPair->OutIdx >= 0) throw clipperException("ProcessHorizontal error");
+ if (horzEdge->OutIdx >= 0)
+ AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
+ DeleteFromAEL(horzEdge);
+ DeleteFromAEL(eMaxPair);
return;
}
- else if(dir == dLeftToRight)
+
+ if(dir == dLeftToRight)
{
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
- IntersectEdges(horzEdge, e, Pt, true);
+ IntersectEdges(horzEdge, e, Pt);
}
else
{
IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
- IntersectEdges( e, horzEdge, Pt, true);
+ IntersectEdges( e, horzEdge, Pt);
}
+ TEdge* eNext = GetNextInAEL(e, dir);
SwapPositionsInAEL( horzEdge, e );
- }
- else if( (dir == dLeftToRight && e->Curr.X >= horzRight) ||
- (dir == dRightToLeft && e->Curr.X <= horzLeft) ) break;
- e = eNext;
- } //end while
+ e = eNext;
+ } //end while(e)
- if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0)
- PrepareHorzJoins(horzEdge, isTopOfScanbeam);
+ //Break out of loop if HorzEdge.NextInLML is not also horizontal ...
+ if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break;
+
+ UpdateEdgeIntoAEL(horzEdge);
+ if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
+ GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
- if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML))
- {
- UpdateEdgeIntoAEL(horzEdge);
- if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
- GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
- } else
- break;
} //end for (;;)
- if(horzEdge->NextInLML)
+ if (horzEdge->OutIdx >= 0 && !op1)
+ {
+ op1 = GetLastOutPt(horzEdge);
+ TEdge* eNextHorz = m_SortedEdges;
+ while (eNextHorz)
+ {
+ if (eNextHorz->OutIdx >= 0 &&
+ HorzSegmentsOverlap(horzEdge->Bot.X,
+ horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
+ {
+ OutPt* op2 = GetLastOutPt(eNextHorz);
+ AddJoin(op2, op1, eNextHorz->Top);
+ }
+ eNextHorz = eNextHorz->NextInSEL;
+ }
+ AddGhostJoin(op1, horzEdge->Top);
+ }
+
+ if (horzEdge->NextInLML)
{
if(horzEdge->OutIdx >= 0)
{
- OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top);
+ op1 = AddOutPt( horzEdge, horzEdge->Top);
UpdateEdgeIntoAEL(horzEdge);
if (horzEdge->WindDelta == 0) return;
//nb: HorzEdge is no longer horizontal here
@@ -2846,22 +2812,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
else
UpdateEdgeIntoAEL(horzEdge);
}
- else if (eMaxPair)
- {
- if (eMaxPair->OutIdx >= 0)
- {
- if (dir == dLeftToRight)
- IntersectEdges(horzEdge, eMaxPair, horzEdge->Top);
- else
- IntersectEdges(eMaxPair, horzEdge, horzEdge->Top);
- if (eMaxPair->OutIdx >= 0)
- throw clipperException("ProcessHorizontal error");
- } else
- {
- DeleteFromAEL(horzEdge);
- DeleteFromAEL(eMaxPair);
- }
- } else
+ else
{
if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top);
DeleteFromAEL(horzEdge);
@@ -2869,34 +2820,11 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam)
}
//------------------------------------------------------------------------------
-void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
-{
- if( !e->NextInLML ) throw
- clipperException("UpdateEdgeIntoAEL: invalid call");
-
- e->NextInLML->OutIdx = e->OutIdx;
- TEdge* AelPrev = e->PrevInAEL;
- TEdge* AelNext = e->NextInAEL;
- if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
- else m_ActiveEdges = e->NextInLML;
- if (AelNext) AelNext->PrevInAEL = e->NextInLML;
- e->NextInLML->Side = e->Side;
- e->NextInLML->WindDelta = e->WindDelta;
- e->NextInLML->WindCnt = e->WindCnt;
- e->NextInLML->WindCnt2 = e->WindCnt2;
- e = e->NextInLML;
- e->Curr = e->Bot;
- e->PrevInAEL = AelPrev;
- e->NextInAEL = AelNext;
- if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
-}
-//------------------------------------------------------------------------------
-
-bool Clipper::ProcessIntersections(const cInt botY, const cInt topY)
+bool Clipper::ProcessIntersections(const cInt topY)
{
if( !m_ActiveEdges ) return true;
try {
- BuildIntersectList(botY, topY);
+ BuildIntersectList(topY);
size_t IlSize = m_IntersectList.size();
if (IlSize == 0) return true;
if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList();
@@ -2921,7 +2849,7 @@ void Clipper::DisposeIntersectNodes()
}
//------------------------------------------------------------------------------
-void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
+void Clipper::BuildIntersectList(const cInt topY)
{
if ( !m_ActiveEdges ) return;
@@ -2948,16 +2876,8 @@ void Clipper::BuildIntersectList(const cInt botY, const cInt topY)
IntPoint Pt;
if(e->Curr.X > eNext->Curr.X)
{
- if (!IntersectPoint(*e, *eNext, Pt, m_UseFullRange) && e->Curr.X > eNext->Curr.X +1)
- throw clipperException("Intersection error");
- if (Pt.Y > botY)
- {
- Pt.Y = botY;
- if (std::fabs(e->Dx) > std::fabs(eNext->Dx))
- Pt.X = TopX(*eNext, botY); else
- Pt.X = TopX(*e, botY);
- }
-
+ IntersectPoint(*e, *eNext, Pt);
+ if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY);
IntersectNode * newNode = new IntersectNode;
newNode->Edge1 = e;
newNode->Edge2 = eNext;
@@ -2985,7 +2905,7 @@ void Clipper::ProcessIntersectList()
{
IntersectNode* iNode = m_IntersectList[i];
{
- IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt, true);
+ IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt);
SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 );
}
delete iNode;
@@ -3032,7 +2952,7 @@ bool Clipper::FixupIntersectionOrder()
void Clipper::DoMaxima(TEdge *e)
{
- TEdge* eMaxPair = GetMaximaPair(e);
+ TEdge* eMaxPair = GetMaximaPairEx(e);
if (!eMaxPair)
{
if (e->OutIdx >= 0)
@@ -3044,7 +2964,7 @@ void Clipper::DoMaxima(TEdge *e)
TEdge* eNext = e->NextInAEL;
while(eNext && eNext != eMaxPair)
{
- IntersectEdges(e, eNext, e->Top, true);
+ IntersectEdges(e, eNext, e->Top);
SwapPositionsInAEL(e, eNext);
eNext = e->NextInAEL;
}
@@ -3056,7 +2976,9 @@ void Clipper::DoMaxima(TEdge *e)
}
else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
{
- IntersectEdges( e, eMaxPair, e->Top);
+ if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top);
+ DeleteFromAEL(e);
+ DeleteFromAEL(eMaxPair);
}
#ifdef use_lines
else if (e->WindDelta == 0)
@@ -3091,12 +3013,13 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if(IsMaximaEdge)
{
- TEdge* eMaxPair = GetMaximaPair(e);
+ TEdge* eMaxPair = GetMaximaPairEx(e);
IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
}
if(IsMaximaEdge)
{
+ if (m_StrictSimple) m_Maxima.push_back(e->Top.X);
TEdge* ePrev = e->PrevInAEL;
DoMaxima(e);
if( !ePrev ) e = m_ActiveEdges;
@@ -3118,15 +3041,21 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
e->Curr.Y = topY;
}
+ //When StrictlySimple and 'e' is being touched by another edge, then
+ //make sure both edges have a vertex here ...
if (m_StrictSimple)
{
TEdge* ePrev = e->PrevInAEL;
if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
(ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
{
- OutPt* op = AddOutPt(ePrev, e->Curr);
- OutPt* op2 = AddOutPt(e, e->Curr);
- AddJoin(op, op2, e->Curr); //StrictlySimple (type-3) join
+ IntPoint pt = e->Curr;
+#ifdef use_xyz
+ SetZ(pt, *ePrev, *e);
+#endif
+ OutPt* op = AddOutPt(ePrev, pt);
+ OutPt* op2 = AddOutPt(e, pt);
+ AddJoin(op, op2, pt); //StrictlySimple (type-3) join
}
}
@@ -3135,7 +3064,9 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
//3. Process horizontals at the Top of the scanbeam ...
- ProcessHorizontals(true);
+ m_Maxima.sort();
+ ProcessHorizontals();
+ m_Maxima.clear();
//4. Promote intermediate vertices ...
e = m_ActiveEdges;
@@ -3154,7 +3085,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
if (ePrev && ePrev->Curr.X == e->Bot.X &&
ePrev->Curr.Y == e->Bot.Y && op &&
ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
- SlopesEqual(*e, *ePrev, m_UseFullRange) &&
+ SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (ePrev->WindDelta != 0))
{
OutPt* op2 = AddOutPt(ePrev, e->Bot);
@@ -3163,7 +3094,7 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
else if (eNext && eNext->Curr.X == e->Bot.X &&
eNext->Curr.Y == e->Bot.Y && op &&
eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
- SlopesEqual(*e, *eNext, m_UseFullRange) &&
+ SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) &&
(e->WindDelta != 0) && (eNext->WindDelta != 0))
{
OutPt* op2 = AddOutPt(eNext, e->Bot);
@@ -3175,44 +3106,71 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
}
//------------------------------------------------------------------------------
-void Clipper::FixupOutPolygon(OutRec &outrec)
+void Clipper::FixupOutPolyline(OutRec &outrec)
{
- //FixupOutPolygon() - removes duplicate points and simplifies consecutive
- //parallel edges by removing the middle vertex.
- OutPt *lastOK = 0;
- outrec.BottomPt = 0;
OutPt *pp = outrec.Pts;
-
- for (;;)
+ OutPt *lastPP = pp->Prev;
+ while (pp != lastPP)
{
- if (pp->Prev == pp || pp->Prev == pp->Next )
+ pp = pp->Next;
+ if (pp->Pt == pp->Prev->Pt)
{
- DisposeOutPts(pp);
- outrec.Pts = 0;
- return;
+ if (pp == lastPP) lastPP = pp->Prev;
+ OutPt *tmpPP = pp->Prev;
+ tmpPP->Next = pp->Next;
+ pp->Next->Prev = tmpPP;
+ delete pp;
+ pp = tmpPP;
}
+ }
- //test for duplicate points and collinear edges ...
- if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
- (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
- (!m_PreserveCollinear ||
- !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
- {
- lastOK = 0;
- OutPt *tmp = pp;
- pp->Prev->Next = pp->Next;
- pp->Next->Prev = pp->Prev;
- pp = pp->Prev;
- delete tmp;
- }
- else if (pp == lastOK) break;
- else
+ if (pp == pp->Prev)
+ {
+ DisposeOutPts(pp);
+ outrec.Pts = 0;
+ return;
+ }
+}
+//------------------------------------------------------------------------------
+
+void Clipper::FixupOutPolygon(OutRec &outrec)
+{
+ //FixupOutPolygon() - removes duplicate points and simplifies consecutive
+ //parallel edges by removing the middle vertex.
+ OutPt *lastOK = 0;
+ outrec.BottomPt = 0;
+ OutPt *pp = outrec.Pts;
+ bool preserveCol = m_PreserveCollinear || m_StrictSimple;
+
+ for (;;)
{
- if (!lastOK) lastOK = pp;
- pp = pp->Next;
+ if (pp->Prev == pp || pp->Prev == pp->Next)
+ {
+ DisposeOutPts(pp);
+ outrec.Pts = 0;
+ return;
+ }
+
+ //test for duplicate points and collinear edges ...
+ if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
+ (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
+ (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
+ {
+ lastOK = 0;
+ OutPt *tmp = pp;
+ pp->Prev->Next = pp->Next;
+ pp->Next->Prev = pp->Prev;
+ pp = pp->Prev;
+ delete tmp;
+ }
+ else if (pp == lastOK) break;
+ else
+ {
+ if (!lastOK) lastOK = pp;
+ pp = pp->Next;
+ }
}
- }
- outrec.Pts = pp;
+ outrec.Pts = pp;
}
//------------------------------------------------------------------------------
@@ -3496,7 +3454,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
OutPt *op2 = j->OutPt2, *op2b;
//There are 3 kinds of joins for output polygons ...
- //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are a vertices anywhere
+ //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
//along (horizontal) collinear edges (& Join.OffPt is on the same horizontal).
//2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
//location at the Bottom of the overlapping segment (& Join.OffPt is above).
@@ -3508,6 +3466,7 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
(j->OffPt == j->OutPt2->Pt))
{
//Strictly Simple join ...
+ if (outRec1 != outRec2) return false;
op1b = j->OutPt1->Next;
while (op1b != op1 && (op1b->Pt == j->OffPt))
op1b = op1b->Next;
@@ -3648,13 +3607,22 @@ bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
}
//----------------------------------------------------------------------
+static OutRec* ParseFirstLeft(OutRec* FirstLeft)
+{
+ while (FirstLeft && !FirstLeft->Pts)
+ FirstLeft = FirstLeft->FirstLeft;
+ return FirstLeft;
+}
+//------------------------------------------------------------------------------
+
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
{
-
+ //tests if NewOutRec contains the polygon before reassigning FirstLeft
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
- if (outRec->Pts && outRec->FirstLeft == OldOutRec)
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (outRec->Pts && firstLeft == OldOutRec)
{
if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
outRec->FirstLeft = NewOutRec;
@@ -3663,23 +3631,43 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
}
//----------------------------------------------------------------------
-void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec)
-{
+void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec)
+{
+ //A polygon has split into two such that one is now the inner of the other.
+ //It's possible that these polygons now wrap around other polygons, so check
+ //every polygon that's also contained by OuterOutRec's FirstLeft container
+ //(including 0) to see if they've become inner to the new inner polygon ...
+ OutRec* orfl = OuterOutRec->FirstLeft;
for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
{
OutRec* outRec = m_PolyOuts[i];
- if (outRec->FirstLeft == OldOutRec) outRec->FirstLeft = NewOutRec;
+
+ if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
+ continue;
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec)
+ continue;
+ if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts))
+ outRec->FirstLeft = InnerOutRec;
+ else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
+ outRec->FirstLeft = OuterOutRec;
+ else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec)
+ outRec->FirstLeft = orfl;
}
}
//----------------------------------------------------------------------
-
-static OutRec* ParseFirstLeft(OutRec* FirstLeft)
+void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec)
{
- while (FirstLeft && !FirstLeft->Pts)
- FirstLeft = FirstLeft->FirstLeft;
- return FirstLeft;
+ //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
+ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
+ {
+ OutRec* outRec = m_PolyOuts[i];
+ OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
+ if (outRec->Pts && outRec->FirstLeft == OldOutRec)
+ outRec->FirstLeft = NewOutRec;
+ }
}
-//------------------------------------------------------------------------------
+//----------------------------------------------------------------------
void Clipper::JoinCommonEdges()
{
@@ -3691,13 +3679,14 @@ void Clipper::JoinCommonEdges()
OutRec *outRec2 = GetOutRec(join->OutPt2->Idx);
if (!outRec1->Pts || !outRec2->Pts) continue;
+ if (outRec1->IsOpen || outRec2->IsOpen) continue;
//get the polygon fragment with the correct hole state (FirstLeft)
//before calling JoinPoints() ...
OutRec *holeStateRec;
if (outRec1 == outRec2) holeStateRec = outRec1;
- else if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2;
- else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1;
+ else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2;
+ else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1;
else holeStateRec = GetLowermostRec(outRec1, outRec2);
if (!JoinPoints(join, outRec1, outRec2)) continue;
@@ -3714,25 +3703,12 @@ void Clipper::JoinCommonEdges()
//update all OutRec2.Pts Idx's ...
UpdateOutPtIdxs(*outRec2);
- //We now need to check every OutRec.FirstLeft pointer. If it points
- //to OutRec1 it may need to point to OutRec2 instead ...
- if (m_UsingPolyTree)
- for (PolyOutList::size_type j = 0; j < m_PolyOuts.size() - 1; j++)
- {
- OutRec* oRec = m_PolyOuts[j];
- if (!oRec->Pts || ParseFirstLeft(oRec->FirstLeft) != outRec1 ||
- oRec->IsHole == outRec1->IsHole) continue;
- if (Poly2ContainsPoly1(oRec->Pts, join->OutPt2))
- oRec->FirstLeft = outRec2;
- }
-
if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
{
- //outRec2 is contained by outRec1 ...
+ //outRec1 contains outRec2 ...
outRec2->IsHole = !outRec1->IsHole;
outRec2->FirstLeft = outRec1;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
@@ -3740,13 +3716,12 @@ void Clipper::JoinCommonEdges()
} else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts))
{
- //outRec1 is contained by outRec2 ...
+ //outRec2 contains outRec1 ...
outRec2->IsHole = outRec1->IsHole;
outRec1->IsHole = !outRec2->IsHole;
outRec2->FirstLeft = outRec1->FirstLeft;
outRec1->FirstLeft = outRec2;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
@@ -3775,8 +3750,7 @@ void Clipper::JoinCommonEdges()
outRec1->FirstLeft = outRec2->FirstLeft;
outRec2->FirstLeft = outRec1;
- //fixup FirstLeft pointers that may need reassigning to OutRec1
- if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
+ if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1);
}
}
}
@@ -3848,8 +3822,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
(path[i].Y == newNode->Contour[k].Y &&
path[i].X < newNode->Contour[k].X)) k = j;
}
- if ((endType == etClosedPolygon && j < 2) ||
- (endType != etClosedPolygon && j < 0))
+ if (endType == etClosedPolygon && j < 2)
{
delete newNode;
return;
@@ -3859,7 +3832,7 @@ void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType
//if this path's lowest pt is lower than all the others then update m_lowest
if (endType != etClosedPolygon) return;
if (m_lowest.X < 0)
- m_lowest = IntPoint(0, k);
+ m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
else
{
IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
@@ -3965,6 +3938,7 @@ void ClipperOffset::Execute(PolyTree& solution, double delta)
PolyNode* outerNode = solution.Childs[0];
solution.Childs.reserve(outerNode->ChildCount());
solution.Childs[0] = outerNode->Childs[0];
+ solution.Childs[0]->Parent = outerNode->Parent;
for (int i = 1; i < outerNode->ChildCount(); ++i)
solution.AddChild(*outerNode->Childs[i]);
}
@@ -4149,8 +4123,20 @@ void ClipperOffset::DoOffset(double delta)
void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
{
+ //cross product ...
m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
- if (m_sinA < 0.00005 && m_sinA > -0.00005) return;
+ if (std::fabs(m_sinA * m_delta) < 1.0)
+ {
+ //dot product ...
+ double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
+ if (cosA > 0) // angle => 0 degrees
+ {
+ m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
+ Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
+ return;
+ }
+ //else angle => 180 degrees
+ }
else if (m_sinA > 1.0) m_sinA = 1.0;
else if (m_sinA < -1.0) m_sinA = -1.0;
@@ -4204,7 +4190,7 @@ void ClipperOffset::DoRound(int j, int k)
{
double a = std::atan2(m_sinA,
m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
- int steps = (int)Round(m_StepsPerRad * std::fabs(a));
+ int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
double X = m_normals[k].X, Y = m_normals[k].Y, X2;
for (int i = 0; i < steps; ++i)
@@ -4232,7 +4218,7 @@ void Clipper::DoSimplePolygons()
{
OutRec* outrec = m_PolyOuts[i++];
OutPt* op = outrec->Pts;
- if (!op) continue;
+ if (!op || outrec->IsOpen) continue;
do //for each Pt in Polygon until duplicate found do ...
{
OutPt* op2 = op->Next;
@@ -4257,6 +4243,7 @@ void Clipper::DoSimplePolygons()
//OutRec2 is contained by OutRec1 ...
outrec2->IsHole = !outrec->IsHole;
outrec2->FirstLeft = outrec;
+ if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
}
else
if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
@@ -4266,12 +4253,15 @@ void Clipper::DoSimplePolygons()
outrec->IsHole = !outrec2->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
outrec->FirstLeft = outrec2;
- } else
+ if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
+ }
+ else
{
//the 2 polygons are separate ...
outrec2->IsHole = outrec->IsHole;
outrec2->FirstLeft = outrec->FirstLeft;
- }
+ if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
+ }
op2 = op; //ie get ready for the Next iteration
}
op2 = op2->Next;
@@ -4331,7 +4321,12 @@ inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
double DistanceFromLineSqrd(
const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2)
{
- //see https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
+ //The equation of a line in general form (Ax + By + C = 0)
+ //given 2 points (x¹,y¹) & (x²,y²) is ...
+ //(y¹ - y²)x + (x² - x¹)y + (y² - y¹)x¹ - (x² - x¹)y¹ = 0
+ //A = (y¹ - y²); B = (x² - x¹); C = (y² - y¹)x¹ - (x² - x¹)y¹
+ //perpendicular distance of point (x³,y³) = (Ax³ + By³ + C)/Sqrt(A² + B²)
+ //see http://en.wikipedia.org/wiki/Perpendicular_distance
double A = double(ln1.Y - ln2.Y);
double B = double(ln2.X - ln1.X);
double C = A * ln1.X + B * ln1.Y;
@@ -4343,7 +4338,27 @@ double DistanceFromLineSqrd(
bool SlopesNearCollinear(const IntPoint& pt1,
const IntPoint& pt2, const IntPoint& pt3, double distSqrd)
{
- return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ //this function is more accurate when the point that's geometrically
+ //between the other 2 points is the one that's tested for distance.
+ //ie makes it more likely to pick up 'spikes' ...
+ if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y))
+ {
+ if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
+ return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
+ else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
+ return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ else
+ return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
+ }
+ else
+ {
+ if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
+ return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
+ else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
+ return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
+ else
+ return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
+ }
}
//------------------------------------------------------------------------------
@@ -4433,6 +4448,7 @@ void CleanPolygon(Path& poly, double distance)
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance)
{
+ out_polys.resize(in_polys.size());
for (Paths::size_type i = 0; i < in_polys.size(); ++i)
CleanPolygon(in_polys[i], out_polys[i], distance);
}
@@ -4471,8 +4487,8 @@ void Minkowski(const Path& poly, const Path& path,
pp.push_back(p);
}
- Paths quads;
- quads.reserve((pathCnt + delta) * (polyCnt + 1));
+ solution.clear();
+ solution.reserve((pathCnt + delta) * (polyCnt + 1));
for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
for (size_t j = 0; j < polyCnt; ++j)
{
@@ -4483,23 +4499,30 @@ void Minkowski(const Path& poly, const Path& path,
quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]);
quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]);
if (!Orientation(quad)) ReversePath(quad);
- quads.push_back(quad);
+ solution.push_back(quad);
}
+}
+//------------------------------------------------------------------------------
+void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
+{
+ Minkowski(pattern, path, solution, true, pathIsClosed);
Clipper c;
- c.AddPaths(quads, ptSubject, true);
+ c.AddPaths(solution, ptSubject, true);
c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
-void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
+void TranslatePath(const Path& input, Path& output, const IntPoint delta)
{
- Minkowski(pattern, path, solution, true, pathIsClosed);
+ //precondition: input != output
+ output.resize(input.size());
+ for (size_t i = 0; i < input.size(); ++i)
+ output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
}
//------------------------------------------------------------------------------
-void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
- PolyFillType pathFillType, bool pathIsClosed)
+void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed)
{
Clipper c;
for (size_t i = 0; i < paths.size(); ++i)
@@ -4507,21 +4530,29 @@ void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution,
Paths tmp;
Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
c.AddPaths(tmp, ptSubject, true);
+ if (pathIsClosed)
+ {
+ Path tmp2;
+ TranslatePath(paths[i], tmp2, pattern[0]);
+ c.AddPath(tmp2, ptClip, true);
+ }
}
- if (pathIsClosed) c.AddPaths(paths, ptClip, true);
- c.Execute(ctUnion, solution, pathFillType, pathFillType);
+ c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
{
Minkowski(poly1, poly2, solution, false, true);
+ Clipper c;
+ c.AddPaths(solution, ptSubject, true);
+ c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
}
//------------------------------------------------------------------------------
enum NodeType {ntAny, ntOpen, ntClosed};
-void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& paths)
+void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths)
{
bool match = true;
if (nodetype == ntClosed) match = !polynode.IsOpen();
@@ -4530,7 +4561,7 @@ void AddPolyNodeToPolygons(const PolyNode& polynode, NodeType nodetype, Paths& p
if (!polynode.Contour.empty() && match)
paths.push_back(polynode.Contour);
for (int i = 0; i < polynode.ChildCount(); ++i)
- AddPolyNodeToPolygons(*polynode.Childs[i], nodetype, paths);
+ AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths);
}
//------------------------------------------------------------------------------
@@ -4538,7 +4569,7 @@ void PolyTreeToPaths(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
- AddPolyNodeToPolygons(polytree, ntAny, paths);
+ AddPolyNodeToPaths(polytree, ntAny, paths);
}
//------------------------------------------------------------------------------
@@ -4546,7 +4577,7 @@ void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths)
{
paths.resize(0);
paths.reserve(polytree.Total());
- AddPolyNodeToPolygons(polytree, ntClosed, paths);
+ AddPolyNodeToPaths(polytree, ntClosed, paths);
}
//------------------------------------------------------------------------------
@@ -4588,18 +4619,4 @@ std::ostream& operator <<(std::ostream &s, const Paths &p)
}
//------------------------------------------------------------------------------
-#ifdef use_deprecated
-
-void OffsetPaths(const Paths &in_polys, Paths &out_polys,
- double delta, JoinType jointype, EndType_ endtype, double limit)
-{
- ClipperOffset co(limit, limit);
- co.AddPaths(in_polys, jointype, (EndType)endtype);
- co.Execute(out_polys, delta);
-}
-//------------------------------------------------------------------------------
-
-#endif
-
-
} //ClipperLib namespace
diff --git a/src/3rdparty/clipper/clipper.h b/src/3rdparty/clipper/clipper.h
index 84870141..2472ac77 100644
--- a/src/3rdparty/clipper/clipper.h
+++ b/src/3rdparty/clipper/clipper.h
@@ -1,10 +1,10 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
-* Version : 6.1.3a *
-* Date : 22 January 2014 *
+* Version : 6.4.0 *
+* Date : 2 July 2015 *
* Website : http://www.angusj.com *
-* Copyright : Angus Johnson 2010-2014 *
+* Copyright : Angus Johnson 2010-2015 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
@@ -34,7 +34,7 @@
#ifndef clipper_hpp
#define clipper_hpp
-#define CLIPPER_VERSION "6.1.3"
+#define CLIPPER_VERSION "6.2.6"
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
@@ -44,19 +44,20 @@
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
-//#define use_lines
+#define use_lines
-//use_deprecated: Enables support for the obsolete OffsetPaths() function
-//which has been replace with the ClipperOffset class.
-#define use_deprecated
+//use_deprecated: Enables temporary support for the obsolete functions
+//#define use_deprecated
#include <vector>
+#include <list>
#include <set>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
#include <functional>
+#include <queue>
namespace ClipperLib {
@@ -69,11 +70,16 @@ enum PolyType { ptSubject, ptClip };
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
#ifdef use_int32
-typedef int cInt;
-typedef unsigned int cUInt;
+ typedef int cInt;
+ static cInt const loRange = 0x7FFF;
+ static cInt const hiRange = 0x7FFF;
#else
-typedef signed long long cInt;
-typedef unsigned long long cUInt;
+ typedef signed long long cInt;
+ static cInt const loRange = 0x3FFFFFFF;
+ static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
+ typedef signed long long long64; //used by Int128 class
+ typedef unsigned long long ulong64;
+
#endif
struct IntPoint {
@@ -117,15 +123,12 @@ struct DoublePoint
//------------------------------------------------------------------------------
#ifdef use_xyz
-typedef void (*TZFillCallback)(IntPoint& z1, IntPoint& z2, IntPoint& pt);
+typedef void (*ZFillCallback)(IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
#endif
enum InitOptions {ioReverseSolution = 1, ioStrictlySimple = 2, ioPreserveCollinear = 4};
enum JoinType {jtSquare, jtRound, jtMiter};
enum EndType {etClosedPolygon, etClosedLine, etOpenButt, etOpenSquare, etOpenRound};
-#ifdef use_deprecated
- enum EndType_ {etClosed, etButt = 2, etSquare, etRound};
-#endif
class PolyNode;
typedef std::vector< PolyNode* > PolyNodes;
@@ -134,6 +137,7 @@ class PolyNode
{
public:
PolyNode();
+ virtual ~PolyNode(){};
Path Contour;
PolyNodes Childs;
PolyNode* Parent;
@@ -168,11 +172,6 @@ bool Orientation(const Path &poly);
double Area(const Path &poly);
int PointInPolygon(const IntPoint &pt, const Path &path);
-#ifdef use_deprecated
- void OffsetPaths(const Paths &in_polys, Paths &out_polys,
- double delta, JoinType jointype, EndType_ endtype, double limit = 0);
-#endif
-
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Paths &polys, PolyFillType fillType = pftEvenOdd);
@@ -183,8 +182,7 @@ void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance = 1.
void CleanPolygons(Paths& polys, double distance = 1.415);
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
-void MinkowskiSum(const Path& pattern, const Paths& paths,
- Paths& solution, PolyFillType pathFillType, bool pathIsClosed);
+void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
@@ -202,8 +200,7 @@ enum EdgeSide { esLeft = 1, esRight = 2};
//forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
-struct LocalMinima;
-struct Scanbeam;
+struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;
@@ -213,7 +210,6 @@ typedef std::vector < TEdge* > EdgeList;
typedef std::vector < Join* > JoinList;
typedef std::vector < IntersectNode* > IntersectList;
-
//------------------------------------------------------------------------------
//ClipperBase is the ancestor to the Clipper class. It should not be
@@ -224,7 +220,7 @@ class ClipperBase
public:
ClipperBase();
virtual ~ClipperBase();
- bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
+ virtual bool AddPath(const Path &pg, PolyType PolyTyp, bool Closed);
bool AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed);
virtual void Clear();
IntRect GetBounds();
@@ -233,19 +229,32 @@ public:
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e, bool IsClosed);
- void PopLocalMinima();
virtual void Reset();
TEdge* ProcessBound(TEdge* E, bool IsClockwise);
- void InsertLocalMinima(LocalMinima *newLm);
- void DoMinimaLML(TEdge* E1, TEdge* E2, bool IsClosed);
- TEdge* DescendToMin(TEdge *&E);
- void AscendToMax(TEdge *&E, bool Appending, bool IsClosed);
- LocalMinima *m_CurrentLM;
- LocalMinima *m_MinimaList;
+ void InsertScanbeam(const cInt Y);
+ bool PopScanbeam(cInt &Y);
+ bool LocalMinimaPending();
+ bool PopLocalMinima(cInt Y, const LocalMinimum *&locMin);
+ OutRec* CreateOutRec();
+ void DisposeAllOutRecs();
+ void DisposeOutRec(PolyOutList::size_type index);
+ void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
+ void DeleteFromAEL(TEdge *e);
+ void UpdateEdgeIntoAEL(TEdge *&e);
+
+ typedef std::vector<LocalMinimum> MinimaList;
+ MinimaList::iterator m_CurrentLM;
+ MinimaList m_MinimaList;
+
bool m_UseFullRange;
EdgeList m_edges;
- bool m_PreserveCollinear;
- bool m_HasOpenPaths;
+ bool m_PreserveCollinear;
+ bool m_HasOpenPaths;
+ PolyOutList m_PolyOuts;
+ TEdge *m_ActiveEdges;
+
+ typedef std::priority_queue<cInt> ScanbeamList;
+ ScanbeamList m_Scanbeam;
};
//------------------------------------------------------------------------------
@@ -253,34 +262,37 @@ class Clipper : public virtual ClipperBase
{
public:
Clipper(int initOptions = 0);
- ~Clipper();
bool Execute(ClipType clipType,
- Paths &solution,
- PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
+ Paths &solution,
+ PolyFillType fillType = pftEvenOdd);
+ bool Execute(ClipType clipType,
+ Paths &solution,
+ PolyFillType subjFillType,
+ PolyFillType clipFillType);
bool Execute(ClipType clipType,
- PolyTree &polytree,
- PolyFillType subjFillType = pftEvenOdd,
- PolyFillType clipFillType = pftEvenOdd);
- bool ReverseSolution() {return m_ReverseOutput;};
+ PolyTree &polytree,
+ PolyFillType fillType = pftEvenOdd);
+ bool Execute(ClipType clipType,
+ PolyTree &polytree,
+ PolyFillType subjFillType,
+ PolyFillType clipFillType);
+ bool ReverseSolution() { return m_ReverseOutput; };
void ReverseSolution(bool value) {m_ReverseOutput = value;};
bool StrictlySimple() {return m_StrictSimple;};
void StrictlySimple(bool value) {m_StrictSimple = value;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
- void ZFillFunction(TZFillCallback zFillFunc);
+ void ZFillFunction(ZFillCallback zFillFunc);
#endif
protected:
- void Reset();
virtual bool ExecuteInternal();
private:
- PolyOutList m_PolyOuts;
- JoinList m_Joins;
- JoinList m_GhostJoins;
- IntersectList m_IntersectList;
- ClipType m_ClipType;
- std::set< cInt, std::greater<cInt> > m_Scanbeam;
- TEdge *m_ActiveEdges;
+ JoinList m_Joins;
+ JoinList m_GhostJoins;
+ IntersectList m_IntersectList;
+ ClipType m_ClipType;
+ typedef std::list<cInt> MaximaList;
+ MaximaList m_Maxima;
TEdge *m_SortedEdges;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
@@ -289,40 +301,32 @@ private:
bool m_UsingPolyTree;
bool m_StrictSimple;
#ifdef use_xyz
- TZFillCallback m_ZFill; //custom callback
+ ZFillCallback m_ZFill; //custom callback
#endif
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
- void InsertScanbeam(const cInt Y);
- cInt PopScanbeam();
void InsertLocalMinimaIntoAEL(const cInt botY);
void InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge);
void AddEdgeToSEL(TEdge *edge);
+ bool PopEdgeFromSEL(TEdge *&edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
- void DeleteFromAEL(TEdge *e);
- void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const cInt XPos);
- void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e);
- void PrepareHorzJoins(TEdge* horzEdge, bool isTopOfScanbeam);
- void ProcessHorizontals(bool IsTopOfScanbeam);
- void ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam);
+ void ProcessHorizontals();
+ void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutPt* AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
OutRec* GetOutRec(int idx);
void AppendPolygon(TEdge *e1, TEdge *e2);
- void IntersectEdges(TEdge *e1, TEdge *e2,
- const IntPoint &pt, bool protect = false);
- OutRec* CreateOutRec();
+ void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt);
OutPt* AddOutPt(TEdge *e, const IntPoint &pt);
- void DisposeAllOutRecs();
- void DisposeOutRec(PolyOutList::size_type index);
- bool ProcessIntersections(const cInt botY, const cInt topY);
- void BuildIntersectList(const cInt botY, const cInt topY);
+ OutPt* GetLastOutPt(TEdge *e);
+ bool ProcessIntersections(const cInt topY);
+ void BuildIntersectList(const cInt topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const cInt topY);
void BuildResult(Paths& polys);
@@ -331,6 +335,7 @@ private:
void DisposeIntersectNodes();
bool FixupIntersectionOrder();
void FixupOutPolygon(OutRec &outrec);
+ void FixupOutPolyline(OutRec &outrec);
bool IsHole(TEdge *e);
bool FindOwnerFromSplitRecs(OutRec &outRec, OutRec *&currOrfl);
void FixHoleLinkage(OutRec &outrec);
@@ -342,9 +347,10 @@ private:
void JoinCommonEdges();
void DoSimplePolygons();
void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
- void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec);
+ void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
+ void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
#ifdef use_xyz
- void SetZ(IntPoint& pt, TEdge& e);
+ void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
#endif
};
//------------------------------------------------------------------------------