diff --git a/Documentation/compiling/COMPILING.txt b/Documentation/compiling/COMPILING.txt index dbdcca25d5..618b5f9c9d 100644 --- a/Documentation/compiling/COMPILING.txt +++ b/Documentation/compiling/COMPILING.txt @@ -130,10 +130,10 @@ In order to have a working Kicad installtion, you need - documentation and translations (they are not included in sources) product branch: -bzr branch lp:kicad kicad_src +bzr branch https://code.launchpad.net/~kicad-product-committers/kicad kicad_src Stable branch: -bzr branch lp:kicad/stable kicad_src +bzr branch https://code.launchpad.net/~kicad-product-committers/kicad/stable kicad_src Components and Footprints libraries all (schematic libs, 3D shapes ...) but new footprints libraries (use Download zip tool) diff --git a/Documentation/compiling/build-config.txt b/Documentation/compiling/build-config.txt index 5d162f133f..4478aa40e4 100644 --- a/Documentation/compiling/build-config.txt +++ b/Documentation/compiling/build-config.txt @@ -14,7 +14,7 @@ boost libraries will be downloaded the first time you build Kicad. CMake ===== -KiCad uses CMake to generate the build files specific for the target platform +KiCad uses CMake (version 2.12 or later) to generate the build files specific for the target platform specified by the developer. This document attempts to define some of the more common CMake and KiCad build configuration settings. You can use CMake either by the command CMake on or the graphical version ccmake. This document only @@ -78,24 +78,6 @@ the wxWidgets library. If you wish to use a custom built wxWidgets library, set wxWidgets_ROOT_DIR to the correct path. -wxWidgets_USE_DEBUG (ON/OFF) ----------------------------- -Default: OFF - -When creating a debug build of KiCad, it is often useful to link against the -debug build of the wxWidgets. To use the debug build of wxWidgets, set -wxWidgets_USE_DEBUG to ON. - - -wxWidgets_USE_UNICODE (ON/OFF) ------------------------------- -Default: ON (wxWidgets 2.9 or later), OFF (older versions) - -If your platform supports Unicode and you wish to build KiCad with Unicode -support, set wxWidgets_USE_UNICODE to ON. Please note as of the 2.9 branch -this option is not required. - - KiCad Specific Options ====================== @@ -114,17 +96,6 @@ WARNING: The KiCad developers strongly advise you to build the bundled copy of the Boost library, as it is known to work with KiCad. Other versions may contain bugs that may result in KiCad errors. - -USE_WX_GRAPHICS_CONTEXT (ON/OFF) --------------------------------- -Default: OFF - -This option is *Experimental*. It enables advanced drawing library code using -wxGraphicsContext and should only be used for testing purposes. Under Windows, -a very recent version of mingw is needed. It also requires wxWidgets to be -built with the --enable-graphics_ctx configuration switch. - - USE_IMAGES_IN_MENUS (ON/OFF) ---------------------------- Default: OFF for OSX, ON for other platforms. @@ -147,20 +118,11 @@ to avoid download and building the dependencies multiple times. KICAD_USER_CONFIG_DIR (PATH) ---------------------------- -Default: Home directory (Unix-based systems), Application data directory (Windows) +Default: ~/.config (Unix-based systems), Application data directory (Windows) This option specifies where to store user-specific configuration information. -KICAD_KEEPCASE (ON/OFF) ------------------------ -Default: ON - -If this is OFF, component names are automatically converted to uppercase meaning -they are case insensitive. If it is ON, component names are not changed and -are therefore case sensitive. - - USE_WX_OVERLAY (ON/OFF) ----------------------- Default: ON for OSX, OFF for other platforms. @@ -192,7 +154,7 @@ KICAD_SCRIPTING_WXPYTHON (ON/OFF) Default: OFF This option enables or disables building wxPython support into the KiCad -scripting support. Currently only Pcbnew is supported. This option requires +scripting support. Currently only Pcbnew has scripting support. This option requires SWIG, Python, and wxPython to be installed on the system. diff --git a/Documentation/compiling/build-msw.txt b/Documentation/compiling/build-msw.txt index 679f4c609f..27bbf02ad4 100644 --- a/Documentation/compiling/build-msw.txt +++ b/Documentation/compiling/build-msw.txt @@ -103,16 +103,16 @@ install the wxWidgets library into MinGW then enter the following commands: #mkdir Release #cd Release -#../configure --with-opengl +#../configure --enable-monolithic=no --enable-shared=yes --with-opengl #make If you want to install wxWidgets in MinGW then enter the following commands: #mkdir Release #cd Release -#../configure --prefix=/mingw --enable-monolithic=no --disable-shared --with-opengl +#../configure --prefix=/mingw --enable-monolithic=no --enable-shared=yes --with-opengl #make && make install -wxWidgets will be statically linked to Kicad, which avoid issus with wxWidgets dlls +wxWidgets cannot be statically linked to Kicad. Download the KiCad Source Code ------------------------------ @@ -126,16 +126,19 @@ Launchpad repository has two branches for KiCad sources: near a stable state) To download the testing branch: -#bzr branch lp:kicad kicad_testing +#bzr branch https://code.launchpad.net/~kicad-product-committers/kicad kicad_testing To download the stable branch: -#bzr branch lp:kicad/stable kicad_stable +#bzr branch https://code.launchpad.net/~kicad-product-committers/kicad/stable kicad_stable -To download the component and footprint libraries -#bzr branch lp:~kicad-lib-committers/kicad/library kicad_libraries +To download the component and footprint libraries: +(This branch is a bzr/launchpad import of the Git repository +at https://github.com/KiCad/kicad-library.git. +It has schematic parts and 3D models in it.) +#bzr branch https://code.launchpad.net/~kicad-product-committers/kicad/library kicad_libraries To download the documentation and translation files: -#bzr branch lp:~kicad-developers/kicad/doc kicad_doc +#bzr branch https://code.launchpad.net/~kicad-developers/kicad/doc kicad_doc Create Makefiles with CMake --------------------------- @@ -219,7 +222,7 @@ Building the Developer Documentation ------------------------------------ To build the HTML developer documentation, run the following commands: -#cd /build/debug +#cd /build/release #make doxygen-docs The documentation will be created in the /Documentation/html diff --git a/polygon/clipper.cpp b/polygon/clipper.cpp index bb657fd993..6022853c95 100644 --- a/polygon/clipper.cpp +++ b/polygon/clipper.cpp @@ -1,8 +1,8 @@ /******************************************************************************* * * * Author : Angus Johnson * -* Version : 6.1.3a * -* Date : 22 January 2014 * +* Version : 6.2.1 * +* Date : 31 October 2014 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2014 * * * @@ -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; @@ -99,11 +90,10 @@ struct IntersectNode { IntPoint Pt; }; -struct LocalMinima { +struct LocalMinimum { cInt Y; TEdge *LeftBound; TEdge *RightBound; - LocalMinima *Next; }; struct OutPt; @@ -131,6 +121,14 @@ struct Join { IntPoint OffPt; }; +struct LocMinSorter +{ + inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2) + { + return locMin2.Y < locMin1.Y; + } +}; + //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ @@ -170,7 +168,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 +241,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 +250,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 +330,18 @@ class Int128 Int128 operator-() const //unary negation { if (lo == 0) - return Int128(-hi,0); + return Int128(-hi, 0); else - return Int128(~hi,~lo +1); + 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); - else - return Int128(0); - } - - 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 +350,7 @@ class Int128 }; //------------------------------------------------------------------------------ -Int128 Int128Mul (cInt lhs, cInt rhs) +Int128 Int128Mul (long64 lhs, long64 rhs) { bool negate = (lhs < 0) != (rhs < 0); @@ -431,9 +368,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; @@ -444,6 +381,13 @@ Int128 Int128Mul (cInt lhs, cInt rhs) // Miscellaneous global functions //------------------------------------------------------------------------------ +void Swap(cInt& val1, cInt& val2) +{ + cInt tmp = val1; + val1 = val2; + val2 = tmp; +} +//------------------------------------------------------------------------------ bool Orientation(const Path &poly) { return Area(poly) >= 0; @@ -494,6 +438,7 @@ bool PointIsVertex(const IntPoint &Pt, OutPt *pp) int PointInPolygon (const IntPoint &pt, const Path &path) { //returns 0 if false, +1 if true, -1 if pt ON polygon boundary + //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 result = 0; size_t cnt = path.size(); @@ -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); @@ -674,20 +619,18 @@ 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) { @@ -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; + Swap(e.Top.X, e.Bot.X); #ifdef use_xyz - tmp = e.Top.Z; - e.Top.Z = e.Bot.Z; - e.Bot.Z = tmp; + Swap(e.Top.Z, e.Bot.Z); #endif } //------------------------------------------------------------------------------ @@ -905,26 +852,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,41 +864,12 @@ bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1, } //------------------------------------------------------------------------------ -OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint Pt) +bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b) { - 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; + if (seg1a > seg1b) Swap(seg1a, seg1b); + if (seg2a > seg2b) Swap(seg2a, seg2b); + return (seg1a < seg2b) && (seg2a < seg1b); } -//------------------------------------------------------------------------------ - -bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b, - const IntPoint& pt2a, const IntPoint& pt2b) -{ - //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; -} - //------------------------------------------------------------------------------ // ClipperBase class methods ... @@ -979,8 +877,7 @@ bool HorzSegmentsOverlap(const IntPoint& pt1a, const IntPoint& pt1b, ClipperBase::ClipperBase() //constructor { - m_MinimaList = 0; - m_CurrentLM = 0; + m_CurrentLM = m_MinimaList.begin(); //begin() == end() here m_UseFullRange = false; } //------------------------------------------------------------------------------ @@ -1023,114 +920,129 @@ 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) + 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 (EStart->OutIdx != Skip) + { + 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) + { + if (!NextIsForward) 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 (!NextIsForward) 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 + } + return Result; } //------------------------------------------------------------------------------ @@ -1179,7 +1091,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 +1118,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))) @@ -1243,27 +1156,31 @@ bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed) } 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; + MinimaList::value_type locMin; + locMin.Y = E->Bot.Y; + locMin.LeftBound = 0; + locMin.RightBound = E; + locMin.RightBound->Side = esRight; + locMin.RightBound->WindDelta = 0; while (E->Next->OutIdx != Skip) { E->NextInLML = E->Next; if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E); 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 +1189,40 @@ 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; + 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; + 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); + E = ProcessBound(locMin.LeftBound, leftBoundIsForward); + if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward); - if (locMin->LeftBound->OutIdx == Skip) - locMin->LeftBound = 0; - else if (locMin->RightBound->OutIdx == Skip) - locMin->RightBound = 0; - InsertLocalMinima(locMin); - if (!clockwise) E = E2; + 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,27 +1237,6 @@ 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(); @@ -1357,12 +1255,12 @@ 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()); //reset all edges ... - LocalMinima* lm = m_MinimaList; - while( lm ) + for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm) { TEdge* e = lm->LeftBound; if (e) @@ -1379,35 +1277,29 @@ void ClipperBase::Reset() e->Side = esRight; e->OutIdx = Unassigned; } - lm = lm->Next; } } //------------------------------------------------------------------------------ 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() { - if( ! m_CurrentLM ) return; - m_CurrentLM = m_CurrentLM->Next; + if (m_CurrentLM == m_MinimaList.end()) return; + ++m_CurrentLM; } //------------------------------------------------------------------------------ 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 +1308,9 @@ 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; + result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y); TEdge* e = lm->LeftBound; for (;;) { TEdge* bottomE = e; @@ -1429,16 +1320,15 @@ 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; } @@ -1466,12 +1356,11 @@ 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; } @@ -1481,15 +1370,11 @@ void Clipper::ZFillFunction(TZFillCallback zFillFunc) void Clipper::Reset() { ClipperBase::Reset(); - m_Scanbeam.clear(); + m_Scanbeam = ScanbeamList(); m_ActiveEdges = 0; m_SortedEdges = 0; - LocalMinima* lm = m_MinimaList; - while (lm) - { + for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm) InsertScanbeam(lm->Y); - lm = lm->Next; - } } //------------------------------------------------------------------------------ @@ -1550,7 +1435,7 @@ bool Clipper::ExecuteInternal() bool succeeded = true; try { Reset(); - if (!m_CurrentLM) return false; + if (m_CurrentLM == m_MinimaList.end()) return true; cInt botY = PopScanbeam(); do { InsertLocalMinimaIntoAEL(botY); @@ -1558,11 +1443,11 @@ bool Clipper::ExecuteInternal() ProcessHorizontals(false); if (m_Scanbeam.empty()) break; cInt topY = PopScanbeam(); - succeeded = ProcessIntersections(botY, topY); + succeeded = ProcessIntersections(topY); if (!succeeded) break; ProcessEdgesAtTopOfScanbeam(topY); botY = topY; - } while (!m_Scanbeam.empty() || m_CurrentLM); + } while (!m_Scanbeam.empty() || m_CurrentLM != m_MinimaList.end()); } catch(...) { @@ -1601,14 +1486,16 @@ bool Clipper::ExecuteInternal() void Clipper::InsertScanbeam(const cInt Y) { - m_Scanbeam.insert(Y); + //if (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) return;// avoid duplicates. + m_Scanbeam.push(Y); } //------------------------------------------------------------------------------ cInt Clipper::PopScanbeam() { - cInt Y = *m_Scanbeam.begin(); - m_Scanbeam.erase(m_Scanbeam.begin()); + const cInt Y = m_Scanbeam.top(); + m_Scanbeam.pop(); + while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates. return Y; } //------------------------------------------------------------------------------ @@ -1967,7 +1854,7 @@ void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt) void Clipper::InsertLocalMinimaIntoAEL(const cInt botY) { - while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) + while (m_CurrentLM != m_MinimaList.end() && (m_CurrentLM->Y == botY)) { TEdge* lb = m_CurrentLM->LeftBound; TEdge* rb = m_CurrentLM->RightBound; @@ -2018,7 +1905,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); } } @@ -2088,45 +1975,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 +2041,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 +2105,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 +2136,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 +2155,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,17 +2179,6 @@ 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 ); } //------------------------------------------------------------------------------ @@ -2509,12 +2369,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 { @@ -2533,11 +2388,6 @@ 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; } } @@ -2704,37 +2554,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 * @@ -2774,28 +2593,42 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam) 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 //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) + { + OutPt* op1 = AddOutPt(horzEdge, horzEdge->Top); + 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 = AddOutPt(eNextHorz, eNextHorz->Bot); + AddJoin(op2, op1, eNextHorz->Top); + } + eNextHorz = eNextHorz->NextInSEL; + } + AddGhostJoin(op1, horzEdge->Bot); + AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top); + } + DeleteFromAEL(horzEdge); + DeleteFromAEL(eMaxPair); return; } else 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); } SwapPositionsInAEL( horzEdge, e ); } @@ -2804,9 +2637,6 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam) e = eNext; } //end while - if (horzEdge->OutIdx >= 0 && horzEdge->WindDelta != 0) - PrepareHorzJoins(horzEdge, isTopOfScanbeam); - if (horzEdge->NextInLML && IsHorizontal(*horzEdge->NextInLML)) { UpdateEdgeIntoAEL(horzEdge); @@ -2821,6 +2651,7 @@ void Clipper::ProcessHorizontal(TEdge *horzEdge, bool isTopOfScanbeam) if(horzEdge->OutIdx >= 0) { OutPt* op1 = AddOutPt( horzEdge, horzEdge->Top); + if (isTopOfScanbeam) AddGhostJoin(op1, horzEdge->Bot); UpdateEdgeIntoAEL(horzEdge); if (horzEdge->WindDelta == 0) return; //nb: HorzEdge is no longer horizontal here @@ -2846,22 +2677,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); @@ -2892,11 +2708,11 @@ void Clipper::UpdateEdgeIntoAEL(TEdge *&e) } //------------------------------------------------------------------------------ -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 +2737,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 +2764,7 @@ 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); IntersectNode * newNode = new IntersectNode; newNode->Edge1 = e; newNode->Edge2 = eNext; @@ -2985,7 +2792,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; @@ -3044,7 +2851,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 +2863,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) @@ -3124,9 +2933,13 @@ void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY) 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 } } @@ -3508,6 +3321,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 +3462,23 @@ 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) + if (!outRec->Pts || !outRec->FirstLeft) continue; + OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft); + if (firstLeft == OldOutRec) { if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts)) outRec->FirstLeft = NewOutRec; @@ -3665,6 +3489,7 @@ void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec) void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) { + //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]; @@ -3673,14 +3498,6 @@ void Clipper::FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec) } //---------------------------------------------------------------------- -static OutRec* ParseFirstLeft(OutRec* FirstLeft) -{ - while (FirstLeft && !FirstLeft->Pts) - FirstLeft = FirstLeft->FirstLeft; - return FirstLeft; -} -//------------------------------------------------------------------------------ - void Clipper::JoinCommonEdges() { for (JoinList::size_type i = 0; i < m_Joins.size(); i++) @@ -3848,8 +3665,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 +3675,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 +3781,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 +3966,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 +4033,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 +4061,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 +4086,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 +4096,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; @@ -4348,7 +4181,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; + } } //------------------------------------------------------------------------------ @@ -4476,8 +4329,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) { @@ -4488,23 +4341,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); } - - Clipper c; - c.AddPaths(quads, ptSubject, true); - c.Execute(ctUnion, solution, pftNonZero, pftNonZero); } //------------------------------------------------------------------------------ void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed) { Minkowski(pattern, path, solution, true, pathIsClosed); + Clipper c; + c.AddPaths(solution, ptSubject, true); + c.Execute(ctUnion, solution, pftNonZero, pftNonZero); } //------------------------------------------------------------------------------ -void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, - PolyFillType pathFillType, bool pathIsClosed) +void TranslatePath(const Path& input, Path& output, IntPoint delta) +{ + //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, bool pathIsClosed) { Clipper c; for (size_t i = 0; i < paths.size(); ++i) @@ -4512,21 +4372,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(); @@ -4535,7 +4403,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); } //------------------------------------------------------------------------------ @@ -4543,7 +4411,7 @@ void PolyTreeToPaths(const PolyTree& polytree, Paths& paths) { paths.resize(0); paths.reserve(polytree.Total()); - AddPolyNodeToPolygons(polytree, ntAny, paths); + AddPolyNodeToPaths(polytree, ntAny, paths); } //------------------------------------------------------------------------------ @@ -4551,7 +4419,7 @@ void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths) { paths.resize(0); paths.reserve(polytree.Total()); - AddPolyNodeToPolygons(polytree, ntClosed, paths); + AddPolyNodeToPaths(polytree, ntClosed, paths); } //------------------------------------------------------------------------------ @@ -4593,18 +4461,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/polygon/clipper.hpp b/polygon/clipper.hpp index d16fd8b693..5f3cc1c832 100644 --- a/polygon/clipper.hpp +++ b/polygon/clipper.hpp @@ -1,8 +1,8 @@ /******************************************************************************* * * * Author : Angus Johnson * -* Version : 6.1.3a * -* Date : 22 January 2014 * +* Version : 6.2.1 * +* Date : 31 October 2014 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2014 * * * @@ -34,7 +34,7 @@ #ifndef clipper_hpp #define clipper_hpp -#define CLIPPER_VERSION "6.1.3" +#define CLIPPER_VERSION "6.2.0" //use_int32: When enabled 32bit ints are used instead of 64bit ints. This //improve performance but coordinate values are limited to the range +/- 46340 @@ -46,9 +46,8 @@ //use_lines: Enables line clipping. Adds a very minor cost to performance. //#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 #include @@ -57,6 +56,7 @@ #include #include #include +#include namespace ClipperLib { @@ -69,11 +69,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 +122,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 +136,7 @@ class PolyNode { public: PolyNode(); + virtual ~PolyNode(){}; Path Contour; PolyNodes Childs; PolyNode* Parent; @@ -168,11 +171,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 +181,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,7 +199,7 @@ enum EdgeSide { esLeft = 1, esRight = 2}; //forward declarations (for stuff used internally) ... struct TEdge; struct IntersectNode; -struct LocalMinima; +struct LocalMinimum; struct Scanbeam; struct OutPt; struct OutRec; @@ -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 @@ -236,12 +232,14 @@ protected: 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; + + typedef std::vector MinimaList; + MinimaList::iterator m_CurrentLM; + MinimaList m_MinimaList; + bool m_UseFullRange; EdgeList m_edges; bool m_PreserveCollinear; @@ -268,7 +266,7 @@ public: 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(); @@ -279,7 +277,8 @@ private: JoinList m_GhostJoins; IntersectList m_IntersectList; ClipType m_ClipType; - std::set< cInt, std::greater > m_Scanbeam; + typedef std::priority_queue ScanbeamList; + ScanbeamList m_Scanbeam; TEdge *m_ActiveEdges; TEdge *m_SortedEdges; bool m_ExecuteLocked; @@ -289,7 +288,7 @@ 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; @@ -308,21 +307,19 @@ private: 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 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); + void IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &pt); OutRec* CreateOutRec(); 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); + bool ProcessIntersections(const cInt topY); + void BuildIntersectList(const cInt topY); void ProcessIntersectList(); void ProcessEdgesAtTopOfScanbeam(const cInt topY); void BuildResult(Paths& polys); @@ -344,7 +341,7 @@ private: void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec); void FixupFirstLefts2(OutRec* OldOutRec, OutRec* NewOutRec); #ifdef use_xyz - void SetZ(IntPoint& pt, TEdge& e); + void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2); #endif }; //------------------------------------------------------------------------------