Revision: 71981
          http://sourceforge.net/p/brlcad/code/71981
Author:   starseeker
Date:     2018-10-17 12:45:54 +0000 (Wed, 17 Oct 2018)
Log Message:
-----------
Clipper is like the new quickhull - actually easier to embed than try to 
maintain in src/other.  Move it to libbg for simplicity

Modified Paths:
--------------
    brlcad/trunk/doc/legal/embedded/CMakeLists.txt
    brlcad/trunk/doc/legal/other/CMakeLists.txt
    brlcad/trunk/include/bg/CMakeLists.txt
    brlcad/trunk/src/libbg/CMakeLists.txt
    brlcad/trunk/src/libged/CMakeLists.txt
    brlcad/trunk/src/libged/polyclip.cpp
    brlcad/trunk/src/other/CMakeLists.txt

Added Paths:
-----------
    brlcad/trunk/doc/legal/embedded/clipper.txt
    brlcad/trunk/include/bg/clipper.hpp
    brlcad/trunk/src/libbg/clipper.cxx

Removed Paths:
-------------
    brlcad/trunk/doc/legal/other/clipper.txt
    brlcad/trunk/src/other/clipper/
    brlcad/trunk/src/other/clipper.dist

Modified: brlcad/trunk/doc/legal/embedded/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2018-10-16 12:48:03 UTC 
(rev 71980)
+++ brlcad/trunk/doc/legal/embedded/CMakeLists.txt      2018-10-17 12:45:54 UTC 
(rev 71981)
@@ -3,6 +3,7 @@
   bullet.txt
   chull2d.txt
   chull3d.txt
+  clipper.txt
   db_faa-info.txt
   db_nist-info.txt
   dehumanize.txt

Copied: brlcad/trunk/doc/legal/embedded/clipper.txt (from rev 71980, 
brlcad/trunk/doc/legal/other/clipper.txt)
===================================================================
--- brlcad/trunk/doc/legal/embedded/clipper.txt                         (rev 0)
+++ brlcad/trunk/doc/legal/embedded/clipper.txt 2018-10-17 12:45:54 UTC (rev 
71981)
@@ -0,0 +1,31 @@
+http://www.angusj.com/delphi/clipper.php
+
+The Clipper code library, the "Software" (that includes Delphi, C++ & C#
+source code, accompanying samples and documentation), has been released
+under the following license, terms and conditions:
+
+Boost Software License - Version 1.0 - August 17th, 2003
+http://www.boost.org/LICENSE_1_0.txt
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+

Modified: brlcad/trunk/doc/legal/other/CMakeLists.txt
===================================================================
--- brlcad/trunk/doc/legal/other/CMakeLists.txt 2018-10-16 12:48:03 UTC (rev 
71980)
+++ brlcad/trunk/doc/legal/other/CMakeLists.txt 2018-10-17 12:45:54 UTC (rev 
71981)
@@ -1,5 +1,4 @@
 set(other_licenses
-  clipper.txt
   gct.txt
   gdal.txt
   incrTcl.txt

Deleted: brlcad/trunk/doc/legal/other/clipper.txt
===================================================================
--- brlcad/trunk/doc/legal/other/clipper.txt    2018-10-16 12:48:03 UTC (rev 
71980)
+++ brlcad/trunk/doc/legal/other/clipper.txt    2018-10-17 12:45:54 UTC (rev 
71981)
@@ -1,31 +0,0 @@
-http://www.angusj.com/delphi/clipper.php
-
-The Clipper code library, the "Software" (that includes Delphi, C++ & C#
-source code, accompanying samples and documentation), has been released
-under the following license, terms and conditions:
-
-Boost Software License - Version 1.0 - August 17th, 2003
-http://www.boost.org/LICENSE_1_0.txt
-
-Permission is hereby granted, free of charge, to any person or organization
-obtaining a copy of the software and accompanying documentation covered by
-this license (the "Software") to use, reproduce, display, distribute,
-execute, and transmit the Software, and to prepare derivative works of the
-Software, and to permit third-parties to whom the Software is furnished to
-do so, all subject to the following:
-
-The copyright notices in the Software and this entire statement, including
-the above license grant, this restriction and the following disclaimer,
-must be included in all copies of the Software, in whole or in part, and
-all derivative works of the Software, unless such copies or derivative
-works are solely in the form of machine-executable object code generated by
-a source language processor.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
-SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
-FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-DEALINGS IN THE SOFTWARE.
-

Modified: brlcad/trunk/include/bg/CMakeLists.txt
===================================================================
--- brlcad/trunk/include/bg/CMakeLists.txt      2018-10-16 12:48:03 UTC (rev 
71980)
+++ brlcad/trunk/include/bg/CMakeLists.txt      2018-10-17 12:45:54 UTC (rev 
71981)
@@ -1,5 +1,6 @@
 set(bg_headers
   chull.h
+  clipper.hpp
   defines.h
   obr.h
   polygon.h

Added: brlcad/trunk/include/bg/clipper.hpp
===================================================================
--- brlcad/trunk/include/bg/clipper.hpp                         (rev 0)
+++ brlcad/trunk/include/bg/clipper.hpp 2018-10-17 12:45:54 UTC (rev 71981)
@@ -0,0 +1,318 @@
+/*******************************************************************************
+ *                                                                             
 *
+ * Author    :  Angus Johnson                                                  
 *
+ * Version   :  4.6                                                            
 *
+ * Date      :  29 October 2011                                                
 *
+ * Website   :  http://www.angusj.com                                          
 *
+ * Copyright :  Angus Johnson 2010-2011                                        
 *
+ *                                                                             
 *
+ * License:                                                                    
 *
+ * Use, modification & distribution is subject to Boost Software License Ver 
1. *
+ * http://www.boost.org/LICENSE_1_0.txt                                        
 *
+ *                                                                             
 *
+ * Attributions:                                                               
 *
+ * The code in this library is an extension of Bala Vatti's clipping 
algorithm: *
+ * "A generic solution to polygon clipping"                                    
 *
+ * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.            
 *
+ * http://portal.acm.org/citation.cfm?id=129906                                
 *
+ *                                                                             
 *
+ * Computer graphics and geometric modeling: implementation and algorithms     
 *
+ * By Max K. Agoston                                                           
 *
+ * Springer; 1 edition (January 4, 2005)                                       
 *
+ * http://books.google.com/books?q=vatti+clipping+agoston                      
 *
+ *                                                                             
 *
+ * See also:                                                                   
 *
+ * "Polygon Offsetting by Computing Winding Numbers"                           
 *
+ * Paper no. DETC2005-85513 pp. 565-575                                        
 *
+ * ASME 2005 International Design Engineering Technical Conferences            
 *
+ * and Computers and Information in Engineering Conference (IDETC/CIE2005)     
 *
+ * September 24\x9628, 2005 , Long Beach, California, USA                      
    *
+ * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf             
 *
+ *                                                                             
 *
+ 
*******************************************************************************/
+
+#ifndef clipper_hpp
+#define clipper_hpp
+
+#include "common.h"
+
+extern "C" {
+#include "bg/defines.h"
+}
+
+#include <vector>
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <ostream>
+
+
+namespace ClipperLib {
+
+    enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
+    enum PolyType { ptSubject, ptClip };
+    //By far the most widely used winding rules for polygon filling are
+    //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, 
Gr32)
+    //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in 
OpenGL)
+    //see http://glprogramming.com/red/chapter11.html
+    enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
+
+    typedef signed long long long64;
+    typedef unsigned long long ulong64;
+
+    struct IntPoint {
+       public:
+           long64 X;
+           long64 Y;
+           IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {};
+           friend std::ostream& operator <<(std::ostream &s, IntPoint &p);
+    };
+
+    typedef std::vector< IntPoint > Polygon;
+    typedef std::vector< Polygon > Polygons;
+
+    std::ostream& operator <<(std::ostream &s, Polygon &p);
+    std::ostream& operator <<(std::ostream &s, Polygons &p);
+
+    struct ExPolygon {
+       Polygon  outer;
+       Polygons holes;
+    };
+    typedef std::vector< ExPolygon > ExPolygons;
+
+    enum JoinType { jtSquare, jtMiter, jtRound };
+
+    BG_EXPORT bool Orientation(const Polygon &poly);
+    BG_EXPORT double Area(const Polygon &poly);
+    BG_EXPORT void OffsetPolygons(const Polygons &in_polys,
+           Polygons &out_polys, double delta, JoinType jointype = jtSquare,
+           double MiterLimit = 2);
+
+    BG_EXPORT void ReversePoints(Polygon& p);
+    BG_EXPORT void ReversePoints(Polygons& p);
+
+    //used internally ...
+    enum EdgeSide { esLeft, esRight };
+    enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
+
+    struct TEdge {
+       long64 xbot;
+       long64 ybot;
+       long64 xcurr;
+       long64 ycurr;
+       long64 xtop;
+       long64 ytop;
+       double dx;
+       long64 tmpX;
+       PolyType polyType;
+       EdgeSide side;
+       int windDelta; //1 or -1 depending on winding direction
+       int windCnt;
+       int windCnt2; //winding count of the opposite polytype
+       int outIdx;
+       TEdge *next;
+       TEdge *prev;
+       TEdge *nextInLML;
+       TEdge *nextInAEL;
+       TEdge *prevInAEL;
+       TEdge *nextInSEL;
+       TEdge *prevInSEL;
+    };
+
+    struct IntersectNode {
+       TEdge          *edge1;
+       TEdge          *edge2;
+       IntPoint        pt;
+       IntersectNode  *next;
+    };
+
+    struct LocalMinima {
+       long64        Y;
+       TEdge        *leftBound;
+       TEdge        *rightBound;
+       LocalMinima  *next;
+    };
+
+    struct Scanbeam {
+       long64    Y;
+       Scanbeam *next;
+    };
+
+    struct OutPt; //forward declaration
+
+    struct OutRec {
+       int     idx;
+       bool    isHole;
+       OutRec *FirstLeft;
+       OutRec *AppendLink;
+       OutPt  *pts;
+       OutPt  *bottomPt;
+       TEdge  *bottomE1;
+       TEdge  *bottomE2;
+    };
+
+    struct OutPt {
+       int     idx;
+       IntPoint pt;
+       OutPt   *next;
+       OutPt   *prev;
+    };
+
+    struct JoinRec {
+       IntPoint  pt1a;
+       IntPoint  pt1b;
+       int       poly1Idx;
+       IntPoint  pt2a;
+       IntPoint  pt2b;
+       int       poly2Idx;
+    };
+
+    struct HorzJoinRec {
+       TEdge    *edge;
+       int       savedIdx;
+    };
+
+    struct IntRect { long64 left; long64 top; long64 right; long64 bottom; };
+
+    typedef std::vector < OutRec* > PolyOutList;
+    typedef std::vector < TEdge* > EdgeList;
+    typedef std::vector < JoinRec* > JoinList;
+    typedef std::vector < HorzJoinRec* > HorzJoinList;
+
+    //ClipperBase is the ancestor to the Clipper class. It should not be
+    //instantiated directly. This class simply abstracts the conversion of 
sets of
+    //polygon coordinates into edge objects that are stored in a LocalMinima 
list.
+    class BG_EXPORT ClipperBase
+    {
+       public:
+           ClipperBase();
+           virtual ~ClipperBase();
+           bool AddPolygon(const Polygon &pg, PolyType polyType);
+           bool AddPolygons( const Polygons &ppg, PolyType polyType);
+           virtual void Clear();
+           IntRect GetBounds();
+       protected:
+           void DisposeLocalMinimaList();
+           TEdge* AddBoundsToLML(TEdge *e);
+           void PopLocalMinima();
+           virtual void Reset();
+           void InsertLocalMinima(LocalMinima *newLm);
+           LocalMinima      *m_CurrentLM;
+           LocalMinima      *m_MinimaList;
+           bool              m_UseFullRange;
+           EdgeList         *m_edges;
+    };
+
+    class BG_EXPORT Clipper : public virtual ClipperBase
+    {
+       public:
+           Clipper();
+           ~Clipper();
+           bool Execute(ClipType clipType,
+                   Polygons &solution,
+                   PolyFillType subjFillType = pftEvenOdd,
+                   PolyFillType clipFillType = pftEvenOdd);
+           bool Execute(ClipType clipType,
+                   ExPolygons &solution,
+                   PolyFillType subjFillType = pftEvenOdd,
+                   PolyFillType clipFillType = pftEvenOdd);
+           void Clear();
+           bool ReverseSolution() {return m_ReverseOutput;};
+           void ReverseSolution(bool value) {m_ReverseOutput = value;}
+       protected:
+           void Reset();
+           virtual bool ExecuteInternal(bool fixHoleLinkages);
+       private:
+           PolyOutList      *m_PolyOuts;
+           JoinList         *m_Joins;
+           HorzJoinList     *m_HorizJoins;
+           ClipType          m_ClipType;
+           Scanbeam         *m_Scanbeam;
+           TEdge           *m_ActiveEdges;
+           TEdge           *m_SortedEdges;
+           IntersectNode    *m_IntersectNodes;
+           bool              m_ExecuteLocked;
+           PolyFillType      m_ClipFillType;
+           PolyFillType      m_SubjFillType;
+           bool              m_ReverseOutput;
+           void DisposeScanbeamList();
+           void SetWindingCount(TEdge& edge);
+           bool IsEvenOddFillType(const TEdge& edge) const;
+           bool IsEvenOddAltFillType(const TEdge& edge) const;
+           void InsertScanbeam(const long64 Y);
+           long64 PopScanbeam();
+           void InsertLocalMinimaIntoAEL(const long64 botY);
+           void InsertEdgeIntoAEL(TEdge *edge);
+           void AddEdgeToSEL(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 long64 XPos);
+           void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
+           void DoMaxima(TEdge *e, long64 topY);
+           void ProcessHorizontals();
+           void ProcessHorizontal(TEdge *horzEdge);
+           void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+           void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
+           void AppendPolygon(TEdge *e1, TEdge *e2);
+           void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+           void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+           void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
+           void IntersectEdges(TEdge *e1, TEdge *e2,
+                   const IntPoint &pt, IntersectProtects protects);
+           OutRec* CreateOutRec();
+           void AddOutPt(TEdge *e, TEdge *altE, const IntPoint &pt);
+           void DisposeAllPolyPts();
+           void DisposeOutRec(PolyOutList::size_type index, bool ignorePts = 
false);
+           bool ProcessIntersections(const long64 botY, const long64 topY);
+           void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
+           void BuildIntersectList(const long64 botY, const long64 topY);
+           void ProcessIntersectList();
+           void ProcessEdgesAtTopOfScanbeam(const long64 topY);
+           void BuildResult(Polygons& polys);
+           void BuildResultEx(ExPolygons& polys);
+           void SetHoleState(TEdge *e, OutRec *OutRec);
+           void DisposeIntersectNodes();
+           bool FixupIntersections();
+           void FixupOutPolygon(OutRec &outRec);
+           bool IsHole(TEdge *e);
+           void FixHoleLinkage(OutRec *outRec);
+           void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2);
+           void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2);
+           void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx 
= -1);
+           void ClearJoins();
+           void AddHorzJoin(TEdge *e, int idx);
+           void ClearHorzJoins();
+           void JoinCommonEdges(bool fixHoleLinkages);
+    };
+
+    
//------------------------------------------------------------------------------
+    
//------------------------------------------------------------------------------
+
+    class BG_EXPORT clipperException : public std::exception
+    {
+       public:
+           clipperException(const char* description) { m_descr = new 
std::string(description);}
+           virtual ~clipperException() throw() { delete m_descr; }
+           virtual const char* what() const throw() {return m_descr->c_str();}
+       private:
+           std::string *m_descr;
+    };
+    
//------------------------------------------------------------------------------
+
+} //ClipperLib namespace
+
+#endif //clipper_hpp
+
+// Local Variables:
+// tab-width: 8
+// mode: C++
+// c-basic-offset: 4
+// indent-tabs-mode: t
+// c-file-style: "stroustrup"
+// End:
+// ex: shiftwidth=4 tabstop=8
+


Property changes on: brlcad/trunk/include/bg/clipper.hpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: brlcad/trunk/src/libbg/CMakeLists.txt
===================================================================
--- brlcad/trunk/src/libbg/CMakeLists.txt       2018-10-16 12:48:03 UTC (rev 
71980)
+++ brlcad/trunk/src/libbg/CMakeLists.txt       2018-10-17 12:45:54 UTC (rev 
71981)
@@ -11,6 +11,7 @@
   chull.c
   QuickHull.cxx
   chull3d.cxx
+  clipper.cxx
   obr.c
   polygon.c
   polygon_ear_clipping.c

Added: brlcad/trunk/src/libbg/clipper.cxx
===================================================================
--- brlcad/trunk/src/libbg/clipper.cxx                          (rev 0)
+++ brlcad/trunk/src/libbg/clipper.cxx  2018-10-17 12:45:54 UTC (rev 71981)
@@ -0,0 +1,3301 @@
+/*******************************************************************************
+ *                                                                             
 *
+ * Author    :  Angus Johnson                                                  
 *
+ * Version   :  4.6                                                            
 *
+ * Date      :  29 October 2011                                                
 *
+ * Website   :  http://www.angusj.com                                          
 *
+ * Copyright :  Angus Johnson 2010-2011                                        
 *
+ *                                                                             
 *
+ * License:                                                                    
 *
+ * Use, modification & distribution is subject to Boost Software License Ver 
1. *
+ * http://www.boost.org/LICENSE_1_0.txt                                        
 *
+ *                                                                             
 *
+ * Attributions:                                                               
 *
+ * The code in this library is an extension of Bala Vatti's clipping 
algorithm: *
+ * "A generic solution to polygon clipping"                                    
 *
+ * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.            
 *
+ * http://portal.acm.org/citation.cfm?id=129906                                
 *
+ *                                                                             
 *
+ * Computer graphics and geometric modeling: implementation and algorithms     
 *
+ * By Max K. Agoston                                                           
 *
+ * Springer; 1 edition (January 4, 2005)                                       
 *
+ * http://books.google.com/books?q=vatti+clipping+agoston                      
 *
+ *                                                                             
 *
+ * See also:                                                                   
 *
+ * "Polygon Offsetting by Computing Winding Numbers"                           
 *
+ * Paper no. DETC2005-85513 pp. 565-575                                        
 *
+ * ASME 2005 International Design Engineering Technical Conferences            
 *
+ * and Computers and Information in Engineering Conference (IDETC/CIE2005)     
 *
+ * September 24\x9628, 2005 , Long Beach, California, USA                      
    *
+ * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf             
 *
+ *                                                                             
 *
+ 
*******************************************************************************/
+
+/*******************************************************************************
+ *                                                                             
 *
+ * This is a translation of the Delphi Clipper library and the naming style    
 *
+ * used has retained a Delphi flavour.                                         
 *
+ *                                                                             
 *
+ 
*******************************************************************************/
+
+#include "bg/clipper.hpp"
+#include <cmath>
+#include <iostream>
+#include <vector>
+#include <algorithm>
+#include <stdexcept>
+#include <cstring>
+#include <cstdlib>
+#include <ostream>
+
+namespace ClipperLib {
+
+    static long64 const loRange = 1518500249;            //sqrt(2^63 -1)/2
+    static long64 const hiRange = 6521908912666391106LL; //sqrt(2^127 -1)/2
+    static double const pi = 3.141592653589793238;
+    enum Direction { dRightToLeft, dLeftToRight };
+    enum RangeTest { rtLo, rtHi, rtError };
+
+#define HORIZONTAL (-1.0E+40)
+#define TOLERANCE (1.0e-20)
+#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
+#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b))
+
+    inline long64 Abs(long64 val)
+    {
+       if (val < 0) return -val; else return val;
+    }
+    
//------------------------------------------------------------------------------
+
+    
//------------------------------------------------------------------------------
+    // Int128 class (enables safe math on signed 64bit integers)
+    // eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
+    //    Int128 val2((long64)9223372036854775807);
+    //    Int128 val3 = val1 * val2;
+    //    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
+    
//------------------------------------------------------------------------------
+
+    class Int128
+    {
+       public:
+
+           Int128(long64 _lo = 0)
+           {
+               hi = 0;
+               if (_lo < 0) {
+                   lo = -_lo;
+                   Negate(*this);
+               } else
+                   lo = _lo;
+           }
+
+           Int128(const Int128 &val): hi(val.hi), lo(val.lo){}
+
+           long64 operator = (const long64 &val)
+           {
+               hi = 0;
+               lo = Abs(val);
+               if (val < 0) Negate(*this);
+               return val;
+           }
+
+           bool operator == (const Int128 &val) const
+           {return (hi == val.hi && lo == val.lo);}
+
+           bool operator != (const Int128 &val) const { return !(*this == 
val);}
+
+           bool operator > (const Int128 &val) const
+           {
+               if (hi > val.hi) return true;
+               else if (hi < val.hi) return false;
+               else return ulong64(lo) > ulong64(val.lo);
+           }
+
+           bool operator < (const Int128 &val) const
+           {
+               if (hi < val.hi) return true;
+               else if (hi > val.hi) return false;
+               else return ulong64(lo) < ulong64(val.lo);
+           }
+
+           Int128& operator += (const Int128 &rhs)
+           {
+               hi += rhs.hi;
+               lo += rhs.lo;
+               if (ulong64(lo) < ulong64(rhs.lo)) hi++;
+               return *this;
+           }
+
+           Int128 operator + (const Int128 &rhs) const
+           {
+               Int128 result(*this);
+               result+= rhs;
+               return result;
+           }
+
+           Int128& operator -= (const Int128 &rhs)
+           {
+               Int128 tmp(rhs);
+               Negate(tmp);
+               *this += tmp;
+               return *this;
+           }
+
+           Int128 operator - (const Int128 &rhs) const
+           {
+               Int128 result(*this);
+               result-= rhs;
+               return result;
+           }
+
+           Int128 operator * (const Int128 &rhs) const {
+               if ( !(hi == 0 || hi == -1) || !(rhs.hi == 0 || rhs.hi == -1))
+                   throw "Int128 operator*: overflow error";
+               bool negate = (hi < 0) != (rhs.hi < 0);
+
+               Int128 tmp(*this);
+               if (tmp.hi < 0) Negate(tmp);
+               ulong64 int1Hi = ulong64(tmp.lo) >> 32;
+               ulong64 int1Lo = ulong64(tmp.lo & 0xFFFFFFFF);
+
+               tmp = rhs;
+               if (tmp.hi < 0) Negate(tmp);
+               ulong64 int2Hi = ulong64(tmp.lo) >> 32;
+               ulong64 int2Lo = ulong64(tmp.lo & 0xFFFFFFFF);
+
+               //nb: see comments in clipper.pas
+               ulong64 a = int1Hi * int2Hi;
+               ulong64 b = int1Lo * int2Lo;
+               ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
+
+               tmp.hi = long64(a + (c >> 32));
+               tmp.lo = long64(c << 32);
+               tmp.lo += long64(b);
+               if (ulong64(tmp.lo) < b) tmp.hi++;
+               if (negate) Negate(tmp);
+               return tmp;
+           }
+
+           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 result(*this), denom(rhs);
+               if (result.hi < 0) Negate(result);
+               if (denom.hi < 0)  Negate(denom);
+               if (denom > result) return Int128(0); //result is only a 
fraction of 1
+               Negate(denom);
+
+               Int128 p(0);
+               for (int i = 0; i < 128; ++i)
+               {
+                   p.hi = p.hi << 1;
+                   if (p.lo < 0) p.hi++;
+                   p.lo = long64(p.lo) << 1;
+                   if (result.hi < 0) p.lo++;
+                   result.hi = result.hi << 1;
+                   if (result.lo < 0) result.hi++;
+                   result.lo = long64(result.lo) << 1;
+                   Int128 p2(p);
+                   p += denom;
+                   if (p.hi < 0) p = p2;
+                   else result.lo++;
+               }
+               if (negate) Negate(result);
+               return result;
+           }
+
+           double AsDouble() const
+           {
+               const double shift64 = 18446744073709551616.0; //2^64
+               const double bit64 = 9223372036854775808.0;
+               if (hi < 0)
+               {
+                   Int128 tmp(*this);
+                   Negate(tmp);
+                   if (tmp.lo < 0)
+                       return (double)tmp.lo - bit64 - tmp.hi * shift64;
+                   else
+                       return -(double)tmp.lo - tmp.hi * shift64;
+               }
+               else if (lo < 0)
+                   return -(double)lo + bit64 + hi * shift64;
+               else
+                   return (double)lo + (double)hi * shift64;
+           }
+
+           //for bug testing ...
+           std::string AsString() const
+           {
+               std::string result;
+               unsigned char r = 0;
+               Int128 tmp(0), val(*this);
+               if (hi < 0) Negate(val);
+               result.resize(50);
+               std::string::size_type i = result.size() -1;
+               while (val.hi != 0 || val.lo != 0)
+               {
+                   Div10(val, tmp, r);
+                   result[i--] = char('0' + r);
+                   val = tmp;
+               }
+               if (hi < 0) result[i--] = '-';
+               result.erase(0,i+1);
+               if (result.size() == 0) result = "0";
+               return result;
+           }
+
+       private:
+           long64 hi;
+           long64 lo;
+
+           static void Negate(Int128 &val)
+           {
+               if (val.lo == 0)
+               {
+                   if( val.hi == 0) return;
+                   val.lo = ~val.lo;
+                   val.hi = ~val.hi +1;
+               }
+               else
+               {
+                   val.lo = ~val.lo +1;
+                   val.hi = ~val.hi;
+               }
+           }
+
+           //debugging only ...
+           void Div10(const Int128 val, Int128& result, unsigned char & 
remainder) const
+           {
+               remainder = 0;
+               result = 0;
+               for (int i = 63; i >= 0; --i)
+               {
+                   if ((val.hi & ((long64)1 << i)) != 0)
+                       remainder = char((remainder * 2) + 1); else
+                           remainder *= char(2);
+                   if (remainder >= 10)
+                   {
+                       result.hi += ((long64)1 << i);
+                       remainder -= char(10);
+                   }
+               }
+               for (int i = 63; i >= 0; --i)
+               {
+                   if ((val.lo & ((long64)1 << i)) != 0)
+                       remainder = char((remainder * 2) + 1); else
+                           remainder *= char(2);
+                   if (remainder >= 10)
+                   {
+                       result.lo += ((long64)1 << i);
+                       remainder -= char(10);
+                   }
+               }
+           }
+    };
+
+    
//------------------------------------------------------------------------------
+    
//------------------------------------------------------------------------------
+
+    RangeTest TestRange(const Polygon &pts)
+    {
+       RangeTest result = rtLo;
+       for (Polygon::size_type i = 0; i <  pts.size(); ++i)
+       {
+           if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange)
+               return rtError;
+           else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange)
+               result = rtHi;
+       }
+       return result;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Orientation(const Polygon &poly)
+    {
+       int highI = (int)poly.size() -1;
+       if (highI < 2) return false;
+       bool UseFullInt64Range = false;
+
+       int j = 0, jplus, jminus;
+       for (int i = 0; i <= highI; ++i)
+       {
+           if (Abs(poly[i].X) > hiRange || Abs(poly[i].Y) > hiRange)
+               throw "Coordinate exceeds range bounds.";
+           if (Abs(poly[i].X) > loRange || Abs(poly[i].Y) > loRange)
+               UseFullInt64Range = true;
+           if (poly[i].Y < poly[j].Y) continue;
+           if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i;
+       };
+       if (j == highI) jplus = 0;
+       else jplus = j +1;
+       if (j == 0) jminus = highI;
+       else jminus = j -1;
+
+       IntPoint vec1, vec2;
+       //get cross product of vectors of the edges adjacent to highest point 
...
+       vec1.X = poly[j].X - poly[jminus].X;
+       vec1.Y = poly[j].Y - poly[jminus].Y;
+       vec2.X = poly[jplus].X - poly[j].X;
+       vec2.Y = poly[jplus].Y - poly[j].Y;
+
+       if (UseFullInt64Range)
+       {
+           Int128 cross = Int128(vec1.X) * Int128(vec2.Y) -
+               Int128(vec2.X) * Int128(vec1.Y);
+           return cross > 0;
+       }
+       else
+       {
+           return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Orientation(OutRec *outRec, bool UseFullInt64Range)
+    {
+       OutPt *opBottom = outRec->pts, *op = outRec->pts->next;
+       while (op != outRec->pts)
+       {
+           if (op->pt.Y >= opBottom->pt.Y)
+           {
+               if (op->pt.Y > opBottom->pt.Y || op->pt.X < opBottom->pt.X)
+                   opBottom = op;
+           }
+           op = op->next;
+       }
+
+       IntPoint vec1, vec2;
+       vec1.X = op->pt.X - op->prev->pt.X;
+       vec1.Y = op->pt.Y - op->prev->pt.Y;
+       vec2.X = op->next->pt.X - op->pt.X;
+       vec2.Y = op->next->pt.Y - op->pt.Y;
+
+       if (UseFullInt64Range)
+       {
+           Int128 cross = Int128(vec1.X) * Int128(vec2.Y) - Int128(vec2.X) * 
Int128(vec1.Y);
+           return cross > 0;
+       }
+       else
+       {
+           return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2)
+    {
+       return ( pt1.X == pt2.X && pt1.Y == pt2.Y );
+    }
+    
//------------------------------------------------------------------------------
+
+    double Area(const Polygon &poly)
+    {
+       int highI = (int)poly.size() -1;
+       if (highI < 2) return 0;
+       bool UseFullInt64Range;
+       RangeTest rt = TestRange(poly);
+       switch (rt) {
+           case rtLo:
+               UseFullInt64Range = false;
+               break;
+           case rtHi:
+               UseFullInt64Range = true;
+               break;
+           default:
+               throw "Coordinate exceeds range bounds.";
+       }
+
+       if (UseFullInt64Range) {
+           Int128 a(0);
+           a = (Int128(poly[highI].X) * Int128(poly[0].Y)) -
+               Int128(poly[0].X) * Int128(poly[highI].Y);
+           for (int i = 0; i < highI; ++i)
+               a += Int128(poly[i].X) * Int128(poly[i+1].Y) -
+                   Int128(poly[i+1].X) * Int128(poly[i].Y);
+           return a.AsDouble() / 2;
+       }
+       else
+       {
+           double a;
+           a = (double)poly[highI].X * poly[0].Y - (double)poly[0].X * 
poly[highI].Y;
+           for (int i = 0; i < highI; ++i)
+               a += (double)poly[i].X * poly[i+1].Y - (double)poly[i+1].X * 
poly[i].Y;
+           return a/2;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool PointIsVertex(const IntPoint &pt, OutPt *pp)
+    {
+       OutPt *pp2 = pp;
+       do
+       {
+           if (PointsEqual(pp2->pt, pt)) return true;
+           pp2 = pp2->next;
+       }
+       while (pp2 != pp);
+       return false;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range)
+    {
+       OutPt *pp2 = pp;
+       bool result = false;
+       if (UseFullInt64Range) {
+           do
+           {
+               if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
+                           ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) 
&&
+                       Int128(pt.X - pp2->pt.X) < (Int128(pp2->prev->pt.X - 
pp2->pt.X) *
+                           Int128(pt.Y - pp2->pt.Y)) / Int128(pp2->prev->pt.Y 
- pp2->pt.Y))
+                   result = !result;
+               pp2 = pp2->next;
+           }
+           while (pp2 != pp);
+       }
+       else
+       {
+           do
+           {
+               if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) ||
+                           ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) 
&&
+                       (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - 
pp2->pt.Y) /
+                        (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = 
!result;
+               pp2 = pp2->next;
+           }
+           while (pp2 != pp);
+       }
+       return result;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range)
+    {
+       if (e1.ybot == e1.ytop) return (e2.ybot == e2.ytop);
+       else if (e1.xbot == e1.xtop) return (e2.xbot == e2.xtop);
+       else if (UseFullInt64Range)
+           return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) ==
+               Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot);
+       else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) ==
+           (e1.xtop - e1.xbot)*(e2.ytop - e2.ybot);
+    }
+    
//------------------------------------------------------------------------------
+
+    bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
+           const IntPoint pt3, bool UseFullInt64Range)
+    {
+       if (pt1.Y == pt2.Y) return (pt2.Y == pt3.Y);
+       else if (pt1.X == pt2.X) return (pt2.X == pt3.X);
+       else if (UseFullInt64Range)
+           return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) ==
+               Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y);
+       else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
+    }
+    
//------------------------------------------------------------------------------
+
+    bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
+           const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range)
+    {
+       if (pt1.Y == pt2.Y) return (pt3.Y == pt4.Y);
+       else if (pt1.X == pt2.X) return (pt3.X == pt4.X);
+       else if (UseFullInt64Range)
+           return Int128(pt1.Y-pt2.Y) * Int128(pt3.X-pt4.X) ==
+               Int128(pt1.X-pt2.X) * Int128(pt3.Y-pt4.Y);
+       else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y);
+    }
+    
//------------------------------------------------------------------------------
+
+    double GetDx(const IntPoint pt1, const IntPoint pt2)
+    {
+       if (pt1.Y == pt2.Y) return HORIZONTAL;
+       else return
+           (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y);
+    }
+    
//---------------------------------------------------------------------------
+
+    void SetDx(TEdge &e)
+    {
+       if (e.ybot == e.ytop) e.dx = HORIZONTAL;
+       else e.dx =
+           (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot);
+    }
+    
//---------------------------------------------------------------------------
+
+    void SwapSides(TEdge &edge1, TEdge &edge2)
+    {
+       EdgeSide side =  edge1.side;
+       edge1.side = edge2.side;
+       edge2.side = side;
+    }
+    
//------------------------------------------------------------------------------
+
+    void SwapPolyIndexes(TEdge &edge1, TEdge &edge2)
+    {
+       int outIdx =  edge1.outIdx;
+       edge1.outIdx = edge2.outIdx;
+       edge2.outIdx = outIdx;
+    }
+    
//------------------------------------------------------------------------------
+
+    inline long64 Round(double val)
+    {
+       if ((val < 0)) return static_cast<long64>(val - 0.5);
+       else return static_cast<long64>(val + 0.5);
+    }
+    
//------------------------------------------------------------------------------
+
+    long64 TopX(TEdge &edge, const long64 currentY)
+    {
+       if( currentY == edge.ytop ) return edge.xtop;
+       return edge.xbot + Round(edge.dx *(currentY - edge.ybot));
+    }
+    
//------------------------------------------------------------------------------
+
+    long64 TopX(const IntPoint pt1, const IntPoint pt2, const long64 currentY)
+    {
+       //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y
+       if (currentY >= pt1.Y) return pt1.X;
+       else if (currentY == pt2.Y) return pt2.X;
+       else if (pt1.X == pt2.X) return pt1.X;
+       else
+       {
+           double q = (double)(pt1.X-pt2.X)/(double)(pt1.Y-pt2.Y);
+           return Round(pt1.X + (currentY - pt1.Y) *q);
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool IntersectPoint(TEdge &edge1, TEdge &edge2,
+           IntPoint &ip, bool UseFullInt64Range)
+    {
+       double b1, b2;
+       if (SlopesEqual(edge1, edge2, UseFullInt64Range)) return false;
+       else if (NEAR_ZERO(edge1.dx))
+       {
+           ip.X = edge1.xbot;
+           if (NEAR_EQUAL(edge2.dx, HORIZONTAL))
+           {
+               ip.Y = edge2.ybot;
+           } else
+           {
+               b2 = edge2.ybot - (edge2.xbot/edge2.dx);
+               ip.Y = Round(ip.X/edge2.dx + b2);
+           }
+       }
+       else if (NEAR_ZERO(edge2.dx))
+       {
+           ip.X = edge2.xbot;
+           if (NEAR_EQUAL(edge1.dx, HORIZONTAL))
+           {
+               ip.Y = edge1.ybot;
+           } else
+           {
+               b1 = edge1.ybot - (edge1.xbot/edge1.dx);
+               ip.Y = Round(ip.X/edge1.dx + b1);
+           }
+       } else
+       {
+           b1 = edge1.xbot - edge1.ybot * edge1.dx;
+           b2 = edge2.xbot - edge2.ybot * edge2.dx;
+           b2 = (b2-b1)/(edge1.dx - edge2.dx);
+           ip.Y = Round(b2);
+           ip.X = Round(edge1.dx * b2 + b1);
+       }
+
+       return
+           //can be *so close* to the top of one edge that the rounded Y 
equals one ytop ...
+           (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > 
edge2.tmpX) ||
+           (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > 
edge2.tmpX) ||
+           (ip.Y > edge1.ytop && ip.Y > edge2.ytop);
+    }
+    
//------------------------------------------------------------------------------
+
+    void ReversePolyPtLinks(OutPt &pp)
+    {
+       OutPt *pp1, *pp2;
+       pp1 = &pp;
+       do {
+           pp2 = pp1->next;
+           pp1->next = pp1->prev;
+           pp1->prev = pp2;
+           pp1 = pp2;
+       } while( pp1 != &pp );
+    }
+    
//------------------------------------------------------------------------------
+
+    void DisposeOutPts(OutPt*& pp)
+    {
+       if (pp == 0) return;
+       pp->prev->next = 0;
+       while( pp )
+       {
+           OutPt *tmpPp = pp;
+           pp = pp->next;
+           delete tmpPp ;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void InitEdge(TEdge *e, TEdge *eNext,
+           TEdge *ePrev, const IntPoint &pt, PolyType polyType)
+    {
+       std::memset( e, 0, sizeof( TEdge ));
+
+       e->next = eNext;
+       e->prev = ePrev;
+       e->xcurr = pt.X;
+       e->ycurr = pt.Y;
+       if (e->ycurr >= e->next->ycurr)
+       {
+           e->xbot = e->xcurr;
+           e->ybot = e->ycurr;
+           e->xtop = e->next->xcurr;
+           e->ytop = e->next->ycurr;
+           e->windDelta = 1;
+       } else
+       {
+           e->xtop = e->xcurr;
+           e->ytop = e->ycurr;
+           e->xbot = e->next->xcurr;
+           e->ybot = e->next->ycurr;
+           e->windDelta = -1;
+       }
+       SetDx(*e);
+       e->polyType = polyType;
+       e->outIdx = -1;
+    }
+    
//------------------------------------------------------------------------------
+
+    inline void SwapX(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.]
+       e.xcurr = e.xtop;
+       e.xtop = e.xbot;
+       e.xbot = e.xcurr;
+    }
+    
//------------------------------------------------------------------------------
+
+    void SwapPoints(IntPoint &pt1, IntPoint &pt2)
+    {
+       IntPoint tmp = pt1;
+       pt1 = pt2;
+       pt2 = tmp;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
+           IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
+    {
+       //precondition: segments are colinear.
+       if ( pt1a.Y == pt1b.Y || Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 )
+       {
+           if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b);
+           if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b);
+           if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
+           if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
+           return pt1.X < pt2.X;
+       } else
+       {
+           if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b);
+           if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b);
+           if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
+           if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
+           return pt1.Y > pt2.Y;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    OutPt* PolygonBottom(OutPt* pp)
+    {
+       OutPt* p = pp->next;
+       OutPt* result = pp;
+       while (p != pp)
+       {
+           if (p->pt.Y > result->pt.Y) result = p;
+           else if (p->pt.Y == result->pt.Y && p->pt.X < result->pt.X) result 
= p;
+           p = p->next;
+       }
+       return result;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool FindSegment(OutPt* &pp, 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, true) &&
+                   SlopesEqual(pt1a, pt2a, pp->pt, true) &&
+                   GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, 
pt2))
+               return true;
+           pp = pp->next;
+       }
+       while (pp != pp2);
+       return false;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1,
+           const IntPoint pt2, const IntPoint pt3)
+    {
+       if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true;
+       else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X);
+       else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y);
+    }
+    
//------------------------------------------------------------------------------
+
+    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;
+    }
+
+    
//------------------------------------------------------------------------------
+    // ClipperBase class methods ...
+    
//------------------------------------------------------------------------------
+
+    ClipperBase::ClipperBase() //constructor
+    {
+       m_MinimaList = 0;
+       m_CurrentLM = 0;
+       m_UseFullRange = true;
+       m_edges = new EdgeList();
+    }
+    
//------------------------------------------------------------------------------
+
+    ClipperBase::~ClipperBase() //destructor
+    {
+       Clear();
+       delete m_edges;
+       m_edges = NULL;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType)
+    {
+       int len = (int)pg.size();
+       if (len < 3) return false;
+       Polygon p(len);
+       p[0] = pg[0];
+       int j = 0;
+
+       long64 maxVal;
+       if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange;
+
+       for (int i = 0; i < len; ++i)
+       {
+           if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
+           {
+               if (m_UseFullRange)
+                   throw "Coordinate exceeds range bounds";
+               maxVal = hiRange;
+               if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal)
+                   throw "Coordinate exceeds range bounds";
+               m_UseFullRange = true;
+           }
+
+           if (i == 0 || PointsEqual(p[j], pg[i])) continue;
+           else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange))
+           {
+               if (PointsEqual(p[j-1], pg[i])) j--;
+           } else j++;
+           p[j] = pg[i];
+       }
+       if (j < 2) return false;
+
+       len = j+1;
+       for (;;)
+       {
+           //nb: test for point equality before testing slopes ...
+           if (PointsEqual(p[j], p[0])) j--;
+           else if (PointsEqual(p[0], p[1]) ||
+                   SlopesEqual(p[j], p[0], p[1], m_UseFullRange))
+               p[0] = p[j--];
+           else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--;
+           else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange))
+           {
+               for (int i = 2; i <= j; ++i) p[i-1] = p[i];
+               j--;
+           }
+           //exit loop if nothing is changed or there are too few vertices ...
+           if (j == len-1 || j < 2) break;
+           len = j +1;
+       }
+       if (len < 3) return false;
+
+       //create a new edge array ...
+       TEdge *edges = new TEdge [len];
+       m_edges->push_back(edges);
+
+       //convert vertices to a double-linked-list of edges and initialize ...
+       edges[0].xcurr = p[0].X;
+       edges[0].ycurr = p[0].Y;
+       InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType);
+       for (int i = len-2; i > 0; --i)
+           InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType);
+       InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType);
+
+       //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates
+       //increase downward so the 'highest' edge will have the smallest ytop) 
...
+       TEdge *e = &edges[0];
+       TEdge *eHighest = e;
+       do
+       {
+           e->xcurr = e->xbot;
+           e->ycurr = e->ybot;
+           if (e->ytop < eHighest->ytop) eHighest = e;
+           e = e->next;
+       }
+       while ( e != &edges[0]);
+
+       //make sure eHighest is positioned so the following loop works safely 
...
+       if (eHighest->windDelta > 0) eHighest = eHighest->next;
+       if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next;
+
+       //finally insert each local minima ...
+       e = eHighest;
+       do {
+           e = AddBoundsToLML(e);
+       }
+       while( e != eHighest );
+       return true;
+    }
+    
//------------------------------------------------------------------------------
+
+    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;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    TEdge* ClipperBase::AddBoundsToLML(TEdge *e)
+    {
+       //Starting at the top of one bound we progress to the bottom where 
there's
+       //a local minima. We then go to the top of the next bound. These two 
bounds
+       //form the left and right (or right and left) bounds of the local 
minima.
+       e->nextInLML = 0;
+       e = e->next;
+       for (;;)
+       {
+           if (NEAR_EQUAL(e->dx, HORIZONTAL))
+           {
+               //nb: proceed through horizontals when approaching from their 
right,
+               //    but break on horizontal minima if approaching from their 
left.
+               //    This ensures 'local minima' are always on the left of 
horizontals.
+               if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) 
break;
+               if (e->xtop != e->prev->xbot) SwapX(*e);
+               e->nextInLML = e->prev;
+           }
+           else if (e->ycurr == e->prev->ycurr) break;
+           else e->nextInLML = e->prev;
+           e = e->next;
+       }
+
+       //e and e.prev are now at a local minima ...
+       LocalMinima* newLm = new LocalMinima;
+       newLm->next = 0;
+       newLm->Y = e->prev->ybot;
+
+       if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a 
left bound
+       {
+           if (e->xbot != e->prev->xbot) SwapX(*e);
+           newLm->leftBound = e->prev;
+           newLm->rightBound = e;
+       } else if (e->dx < e->prev->dx)
+       {
+           newLm->leftBound = e->prev;
+           newLm->rightBound = e;
+       } else
+       {
+           newLm->leftBound = e;
+           newLm->rightBound = e->prev;
+       }
+       newLm->leftBound->side = esLeft;
+       newLm->rightBound->side = esRight;
+       InsertLocalMinima( newLm );
+
+       for (;;)
+       {
+           if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, 
HORIZONTAL) ) break;
+           e->nextInLML = e->next;
+           e = e->next;
+           if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) 
SwapX(*e);
+       }
+       return e->next;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType)
+    {
+       bool result = true;
+       for (Polygons::size_type i = 0; i < ppg.size(); ++i)
+           if (AddPolygon(ppg[i], polyType)) result = false;
+       return result;
+    }
+    
//------------------------------------------------------------------------------
+
+    void ClipperBase::Clear()
+    {
+       DisposeLocalMinimaList();
+       for (EdgeList::size_type i = 0; i < m_edges->size(); ++i) delete [] 
m_edges->at(i);
+       m_edges->clear();
+       m_UseFullRange = false;
+    }
+    
//------------------------------------------------------------------------------
+
+    void ClipperBase::Reset()
+    {
+       m_CurrentLM = m_MinimaList;
+       if( !m_CurrentLM ) return; //ie nothing to process
+
+       //reset all edges ...
+       LocalMinima* lm = m_MinimaList;
+       while( lm )
+       {
+           TEdge* e = lm->leftBound;
+           while( e )
+           {
+               e->xcurr = e->xbot;
+               e->ycurr = e->ybot;
+               e->side = esLeft;
+               e->outIdx = -1;
+               e = e->nextInLML;
+           }
+           e = lm->rightBound;
+           while( e )
+           {
+               e->xcurr = e->xbot;
+               e->ycurr = e->ybot;
+               e->side = esRight;
+               e->outIdx = -1;
+               e = e->nextInLML;
+           }
+           lm = lm->next;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void ClipperBase::DisposeLocalMinimaList()
+    {
+       while( m_MinimaList )
+       {
+           LocalMinima* tmpLm = m_MinimaList->next;
+           delete m_MinimaList;
+           m_MinimaList = tmpLm;
+       }
+       m_CurrentLM = 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    void ClipperBase::PopLocalMinima()
+    {
+       if( ! m_CurrentLM ) return;
+       m_CurrentLM = m_CurrentLM->next;
+    }
+    
//------------------------------------------------------------------------------
+
+    IntRect ClipperBase::GetBounds()
+    {
+       IntRect result;
+       LocalMinima* lm = m_MinimaList;
+       if (!lm)
+       {
+           result.left = result.top = result.right = result.bottom = 0;
+           return result;
+       }
+       result.left = lm->leftBound->xbot;
+       result.top = lm->leftBound->ybot;
+       result.right = lm->leftBound->xbot;
+       result.bottom = lm->leftBound->ybot;
+       while (lm)
+       {
+           if (lm->leftBound->ybot > result.bottom)
+               result.bottom = lm->leftBound->ybot;
+           TEdge* e = lm->leftBound;
+           for (;;) {
+               TEdge* bottomE = e;
+               while (e->nextInLML)
+               {
+                   if (e->xbot < result.left) result.left = e->xbot;
+                   if (e->xbot > result.right) result.right = e->xbot;
+                   e = e->nextInLML;
+               }
+               if (e->xbot < result.left) result.left = e->xbot;
+               if (e->xbot > result.right) result.right = e->xbot;
+               if (e->xtop < result.left) result.left = e->xtop;
+               if (e->xtop > result.right) result.right = e->xtop;
+               if (e->ytop < result.top) result.top = e->ytop;
+
+               if (bottomE == lm->leftBound) e = lm->rightBound;
+               else break;
+           }
+           lm = lm->next;
+       }
+       return result;
+    }
+
+
+    
//------------------------------------------------------------------------------
+    // TClipper methods ...
+    
//------------------------------------------------------------------------------
+
+    Clipper::Clipper() : ClipperBase() //constructor
+    {
+       m_Scanbeam = 0;
+       m_ActiveEdges = 0;
+       m_SortedEdges = 0;
+       m_IntersectNodes = 0;
+       m_ExecuteLocked = false;
+       m_UseFullRange = false;
+       m_ReverseOutput = false;
+       m_PolyOuts = new PolyOutList();
+       m_Joins = new JoinList();
+       m_HorizJoins = new HorzJoinList();
+    }
+    
//------------------------------------------------------------------------------
+
+    Clipper::~Clipper() //destructor
+    {
+       Clear();
+       DisposeScanbeamList();
+       delete m_PolyOuts;
+       delete m_Joins;
+       delete m_HorizJoins;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::Clear()
+    {
+       if (m_edges->size() == 0) return; //avoids problems with ClipperBase 
destructor
+       DisposeAllPolyPts();
+       ClipperBase::Clear();
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::DisposeScanbeamList()
+    {
+       while ( m_Scanbeam ) {
+           Scanbeam* sb2 = m_Scanbeam->next;
+           delete m_Scanbeam;
+           m_Scanbeam = sb2;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::Reset()
+    {
+       ClipperBase::Reset();
+       m_Scanbeam = 0;
+       m_ActiveEdges = 0;
+       m_SortedEdges = 0;
+       LocalMinima* lm = m_MinimaList;
+       while (lm)
+       {
+           InsertScanbeam(lm->Y);
+           InsertScanbeam(lm->leftBound->ytop);
+           lm = lm->next;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::Execute(ClipType clipType, Polygons &solution,
+           PolyFillType subjFillType, PolyFillType clipFillType)
+    {
+       if( m_ExecuteLocked ) return false;
+       m_ExecuteLocked = true;
+       solution.resize(0);
+       m_SubjFillType = subjFillType;
+       m_ClipFillType = clipFillType;
+       m_ClipType = clipType;
+       bool succeeded = ExecuteInternal(false);
+       if (succeeded) BuildResult(solution);
+       m_ExecuteLocked = false;
+       return succeeded;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::Execute(ClipType clipType, ExPolygons &solution,
+           PolyFillType subjFillType, PolyFillType clipFillType)
+    {
+       if( m_ExecuteLocked ) return false;
+       m_ExecuteLocked = true;
+       solution.resize(0);
+       m_SubjFillType = subjFillType;
+       m_ClipFillType = clipFillType;
+       m_ClipType = clipType;
+       bool succeeded = ExecuteInternal(true);
+       if (succeeded) BuildResultEx(solution);
+       m_ExecuteLocked = false;
+       return succeeded;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool PolySort(OutRec *or1, OutRec *or2)
+    {
+       if (or1 == or2) return false;
+       if (!or1->pts || !or2->pts)
+       {
+           if (or1->pts != or2->pts)
+           {
+               if (or1->pts) return true; else return false;
+           }
+           else return false;
+       }
+       int i1, i2;
+       if (or1->isHole)
+           i1 = or1->FirstLeft->idx; else
+               i1 = or1->idx;
+       if (or2->isHole)
+           i2 = or2->FirstLeft->idx; else
+               i2 = or2->idx;
+       int result = i1 - i2;
+       if (result == 0 && (or1->isHole != or2->isHole))
+       {
+           if (or1->isHole) return false;
+           else return true;
+       }
+       else return result < 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    OutRec* FindAppendLinkEnd(OutRec *outRec)
+    {
+       while (outRec->AppendLink) outRec = outRec->AppendLink;
+       return outRec;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::FixHoleLinkage(OutRec *outRec)
+    {
+       OutRec *tmp;
+       if (outRec->bottomPt)
+           tmp = m_PolyOuts->at(outRec->bottomPt->idx)->FirstLeft;
+       else
+           tmp = outRec->FirstLeft;
+       if (outRec == tmp) throw clipperException("HoleLinkage error");
+
+       if (tmp)
+       {
+           if (tmp->AppendLink) tmp = FindAppendLinkEnd(tmp);
+           if (tmp == outRec) tmp = 0;
+           else if (tmp->isHole)
+           {
+               FixHoleLinkage(tmp);
+               tmp = tmp->FirstLeft;
+           }
+       }
+       outRec->FirstLeft = tmp;
+       if (!tmp) outRec->isHole = false;
+       outRec->AppendLink = 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::ExecuteInternal(bool fixHoleLinkages)
+    {
+       bool succeeded;
+       try {
+           Reset();
+           if (!m_CurrentLM ) return true;
+           long64 botY = PopScanbeam();
+           do {
+               InsertLocalMinimaIntoAEL(botY);
+               ClearHorzJoins();
+               ProcessHorizontals();
+               long64 topY = PopScanbeam();
+               succeeded = ProcessIntersections(botY, topY);
+               if (!succeeded) break;
+               ProcessEdgesAtTopOfScanbeam(topY);
+               botY = topY;
+           } while( m_Scanbeam );
+       }
+       catch(...) {
+           succeeded = false;
+       }
+
+       if (succeeded)
+       {
+           //tidy up output polygons and fix orientations where necessary ...
+           for (PolyOutList::size_type i = 0; i < m_PolyOuts->size(); ++i)
+           {
+               OutRec *outRec = m_PolyOuts->at(i);
+               if (!outRec->pts) continue;
+               FixupOutPolygon(*outRec);
+               if (!outRec->pts) continue;
+               if (outRec->isHole && fixHoleLinkages) FixHoleLinkage(outRec);
+               if (outRec->isHole ==
+                       (m_ReverseOutput ^ Orientation(outRec, m_UseFullRange)))
+                   ReversePolyPtLinks(*outRec->pts);
+           }
+
+           JoinCommonEdges(fixHoleLinkages);
+           if (fixHoleLinkages)
+               std::sort(m_PolyOuts->begin(), m_PolyOuts->end(), PolySort);
+       }
+
+       ClearJoins();
+       ClearHorzJoins();
+       return succeeded;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::InsertScanbeam(const long64 Y)
+    {
+       if( !m_Scanbeam )
+       {
+           m_Scanbeam = new Scanbeam;
+           m_Scanbeam->next = 0;
+           m_Scanbeam->Y = Y;
+       }
+       else if(  Y > m_Scanbeam->Y )
+       {
+           Scanbeam* newSb = new Scanbeam;
+           newSb->Y = Y;
+           newSb->next = m_Scanbeam;
+           m_Scanbeam = newSb;
+       } else
+       {
+           Scanbeam* sb2 = m_Scanbeam;
+           while( sb2->next  && ( Y <= sb2->next->Y ) ) sb2 = sb2->next;
+           if(  Y == sb2->Y ) return; //ie ignores duplicates
+           Scanbeam* newSb = new Scanbeam;
+           newSb->Y = Y;
+           newSb->next = sb2->next;
+           sb2->next = newSb;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    long64 Clipper::PopScanbeam()
+    {
+       long64 Y = m_Scanbeam->Y;
+       Scanbeam* sb2 = m_Scanbeam;
+       m_Scanbeam = m_Scanbeam->next;
+       delete sb2;
+       return Y;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::DisposeAllPolyPts(){
+       for (PolyOutList::size_type i = 0; i < m_PolyOuts->size(); ++i)
+           DisposeOutRec(i);
+       m_PolyOuts->clear();
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::DisposeOutRec(PolyOutList::size_type index, bool ignorePts)
+    {
+       OutRec *outRec = m_PolyOuts->at(index);
+       if (!ignorePts && outRec->pts) DisposeOutPts(outRec->pts);
+       delete outRec;
+       m_PolyOuts->at(index) = 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::SetWindingCount(TEdge &edge)
+    {
+       TEdge *e = edge.prevInAEL;
+       //find the edge of the same polytype that immediately precedes 'edge' 
in AEL
+       while ( e  && e->polyType != edge.polyType ) e = e->prevInAEL;
+       if ( !e )
+       {
+           edge.windCnt = edge.windDelta;
+           edge.windCnt2 = 0;
+           e = m_ActiveEdges; //ie get ready to calc windCnt2
+       } else if ( IsEvenOddFillType(edge) )
+       {
+           //EvenOdd filling ...
+           edge.windCnt = 1;
+           edge.windCnt2 = e->windCnt2;
+           e = e->nextInAEL; //ie get ready to calc windCnt2
+       } else
+       {
+           //nonZero, Positive or Negative filling ...
+           if ( e->windCnt * e->windDelta < 0 )
+           {
+               if (Abs(e->windCnt) > 1)
+               {
+                   if (e->windDelta * edge.windDelta < 0) edge.windCnt = 
e->windCnt;
+                   else edge.windCnt = e->windCnt + edge.windDelta;
+               } else
+                   edge.windCnt = e->windCnt + e->windDelta + edge.windDelta;
+           } else
+           {
+               if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0)
+                   edge.windCnt = e->windCnt;
+               else if ( e->windCnt + edge.windDelta == 0 )
+                   edge.windCnt = e->windCnt;
+               else edge.windCnt = e->windCnt + edge.windDelta;
+           }
+           edge.windCnt2 = e->windCnt2;
+           e = e->nextInAEL; //ie get ready to calc windCnt2
+       }
+
+       //update windCnt2 ...
+       if ( IsEvenOddAltFillType(edge) )
+       {
+           //EvenOdd filling ...
+           while ( e != &edge )
+           {
+               edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0;
+               e = e->nextInAEL;
+           }
+       } else
+       {
+           //nonZero, Positive or Negative filling ...
+           while ( e != &edge )
+           {
+               edge.windCnt2 += e->windDelta;
+               e = e->nextInAEL;
+           }
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::IsEvenOddFillType(const TEdge& edge) const
+    {
+       if (edge.polyType == ptSubject)
+           return m_SubjFillType == pftEvenOdd; else
+               return m_ClipFillType == pftEvenOdd;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const
+    {
+       if (edge.polyType == ptSubject)
+           return m_ClipFillType == pftEvenOdd; else
+               return m_SubjFillType == pftEvenOdd;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::IsContributing(const TEdge& edge) const
+    {
+       PolyFillType pft, pft2;
+       if (edge.polyType == ptSubject)
+       {
+           pft = m_SubjFillType;
+           pft2 = m_ClipFillType;
+       } else
+       {
+           pft = m_ClipFillType;
+           pft2 = m_SubjFillType;
+       }
+
+       switch(pft)
+       {
+           case pftEvenOdd:
+           case pftNonZero:
+               if (Abs(edge.windCnt) != 1) return false;
+               break;
+           case pftPositive:
+               if (edge.windCnt != 1) return false;
+               break;
+           default: //pftNegative
+               if (edge.windCnt != -1) return false;
+       }
+
+       switch(m_ClipType)
+       {
+           case ctIntersection:
+               switch(pft2)
+               {
+                   case pftEvenOdd:
+                   case pftNonZero:
+                       return (edge.windCnt2 != 0);
+                   case pftPositive:
+                       return (edge.windCnt2 > 0);
+                   default:
+                       return (edge.windCnt2 < 0);
+               }
+           case ctUnion:
+               switch(pft2)
+               {
+                   case pftEvenOdd:
+                   case pftNonZero:
+                       return (edge.windCnt2 == 0);
+                   case pftPositive:
+                       return (edge.windCnt2 <= 0);
+                   default:
+                       return (edge.windCnt2 >= 0);
+               }
+           case ctDifference:
+               if (edge.polyType == ptSubject)
+                   switch(pft2)
+                   {
+                       case pftEvenOdd:
+                       case pftNonZero:
+                           return (edge.windCnt2 == 0);
+                       case pftPositive:
+                           return (edge.windCnt2 <= 0);
+                       default:
+                           return (edge.windCnt2 >= 0);
+                   }
+               else
+                   switch(pft2)
+                   {
+                       case pftEvenOdd:
+                       case pftNonZero:
+                           return (edge.windCnt2 != 0);
+                       case pftPositive:
+                           return (edge.windCnt2 > 0);
+                       default:
+                           return (edge.windCnt2 < 0);
+                   }
+           case ctXor:
+               std::cerr << "Unhandled ClipType ctXor\n";
+               return false;
+       }
+       return true;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
+    {
+       if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) )
+       {
+           AddOutPt( e1, e2, pt );
+           e2->outIdx = e1->outIdx;
+           e1->side = esLeft;
+           e2->side = esRight;
+       } else
+       {
+           AddOutPt( e2, e1, pt );
+           e1->outIdx = e2->outIdx;
+           e1->side = esRight;
+           e2->side = esLeft;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt)
+    {
+       AddOutPt( e1, 0, pt );
+       if( e1->outIdx == e2->outIdx )
+       {
+           e1->outIdx = -1;
+           e2->outIdx = -1;
+       }
+       else
+           AppendPolygon( e1, e2 );
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddEdgeToSEL(TEdge *edge)
+    {
+       //SEL pointers in PEdge are reused to build a list of horizontal edges.
+       //However, we don't need to worry about order with horizontal edge 
processing.
+       if( !m_SortedEdges )
+       {
+           m_SortedEdges = edge;
+           edge->prevInSEL = 0;
+           edge->nextInSEL = 0;
+       }
+       else
+       {
+           edge->nextInSEL = m_SortedEdges;
+           edge->prevInSEL = 0;
+           m_SortedEdges->prevInSEL = edge;
+           m_SortedEdges = edge;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::CopyAELToSEL()
+    {
+       TEdge* e = m_ActiveEdges;
+       m_SortedEdges = e;
+       if (!m_ActiveEdges) return;
+       m_SortedEdges->prevInSEL = 0;
+       e = e->nextInAEL;
+       while ( e )
+       {
+           e->prevInSEL = e->prevInAEL;
+           e->prevInSEL->nextInSEL = e;
+           e->nextInSEL = 0;
+           e = e->nextInAEL;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx)
+    {
+       JoinRec* jr = new JoinRec;
+       if (e1OutIdx >= 0)
+           jr->poly1Idx = e1OutIdx; else
+               jr->poly1Idx = e1->outIdx;
+       jr->pt1a = IntPoint(e1->xcurr, e1->ycurr);
+       jr->pt1b = IntPoint(e1->xtop, e1->ytop);
+       if (e2OutIdx >= 0)
+           jr->poly2Idx = e2OutIdx; else
+               jr->poly2Idx = e2->outIdx;
+       jr->pt2a = IntPoint(e2->xcurr, e2->ycurr);
+       jr->pt2b = IntPoint(e2->xtop, e2->ytop);
+       m_Joins->push_back(jr);
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ClearJoins()
+    {
+       for (JoinList::size_type i = 0; i < m_Joins->size(); i++)
+           delete m_Joins->at(i);
+       m_Joins->resize(0);
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddHorzJoin(TEdge *e, int idx)
+    {
+       HorzJoinRec* hj = new HorzJoinRec;
+       hj->edge = e;
+       hj->savedIdx = idx;
+       m_HorizJoins->push_back(hj);
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ClearHorzJoins()
+    {
+       for (HorzJoinList::size_type i = 0; i < m_HorizJoins->size(); i++)
+           delete m_HorizJoins->at(i);
+       m_HorizJoins->resize(0);
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::InsertLocalMinimaIntoAEL( const long64 botY)
+    {
+       while(  m_CurrentLM  && ( m_CurrentLM->Y == botY ) )
+       {
+           TEdge* lb = m_CurrentLM->leftBound;
+           TEdge* rb = m_CurrentLM->rightBound;
+
+           InsertEdgeIntoAEL( lb );
+           InsertScanbeam( lb->ytop );
+           InsertEdgeIntoAEL( rb );
+
+           if (IsEvenOddFillType(*lb))
+           {
+               lb->windDelta = 1;
+               rb->windDelta = 1;
+           }
+           else
+           {
+               rb->windDelta = -lb->windDelta;
+           }
+           SetWindingCount( *lb );
+           rb->windCnt = lb->windCnt;
+           rb->windCnt2 = lb->windCnt2;
+
+           if( NEAR_EQUAL(rb->dx, HORIZONTAL) )
+           {
+               //nb: only rightbounds can have a horizontal bottom edge
+               AddEdgeToSEL( rb );
+               InsertScanbeam( rb->nextInLML->ytop );
+           }
+           else
+               InsertScanbeam( rb->ytop );
+
+           if( IsContributing(*lb) )
+               AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) );
+
+           //if output polygons share an edge, they'll need joining later ...
+           if (lb->outIdx >= 0 && lb->prevInAEL &&
+                   lb->prevInAEL->outIdx >= 0 && lb->prevInAEL->xcurr == 
lb->xbot &&
+                   SlopesEqual(*lb, *lb->prevInAEL, m_UseFullRange))
+               AddJoin(lb, lb->prevInAEL);
+
+           //if any output polygons share an edge, they'll need joining later 
...
+           if (rb->outIdx >= 0)
+           {
+               if (NEAR_EQUAL(rb->dx, HORIZONTAL))
+               {
+                   for (HorzJoinList::size_type i = 0; i < 
m_HorizJoins->size(); ++i)
+                   {
+                       IntPoint pt, pt2; //returned by GetOverlapSegment() but 
unused here.
+                       HorzJoinRec* hj = m_HorizJoins->at(i);
+                       //if horizontals rb and hj.edge overlap, flag for 
joining later ...
+                       if (GetOverlapSegment(IntPoint(hj->edge->xbot, 
hj->edge->ybot),
+                                   IntPoint(hj->edge->xtop, hj->edge->ytop),
+                                   IntPoint(rb->xbot, rb->ybot),
+                                   IntPoint(rb->xtop, rb->ytop), pt, pt2))
+                           AddJoin(hj->edge, rb, hj->savedIdx);
+                   }
+               }
+           }
+
+           if( lb->nextInAEL != rb )
+           {
+               if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 &&
+                       SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange))
+                   AddJoin(rb, rb->prevInAEL);
+
+               TEdge* e = lb->nextInAEL;
+               IntPoint pt = IntPoint(lb->xcurr, lb->ycurr);
+               while( e != rb )
+               {
+                   if(!e) throw clipperException("InsertLocalMinimaIntoAEL: 
missing rightbound!");
+                   //nb: For calculating winding counts etc, IntersectEdges() 
assumes
+                   //that param1 will be to the right of param2 ABOVE the 
intersection ...
+                   IntersectEdges( rb , e , pt , ipNone); //order important 
here
+                   e = e->nextInAEL;
+               }
+           }
+           PopLocalMinima();
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    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;
+       TEdge* SelNext = e->nextInSEL;
+       if( !SelPrev &&  !SelNext && (e != m_SortedEdges) ) return; //already 
deleted
+       if( SelPrev ) SelPrev->nextInSEL = SelNext;
+       else m_SortedEdges = SelNext;
+       if( SelNext ) SelNext->prevInSEL = SelPrev;
+       e->nextInSEL = 0;
+       e->prevInSEL = 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::IntersectEdges(TEdge *e1, TEdge *e2,
+           const IntPoint &pt, IntersectProtects protects)
+    {
+       //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 = !(ipLeft & protects) &&  !e1->nextInLML &&
+           e1->xtop == pt.X && e1->ytop == pt.Y;
+       bool e2stops = !(ipRight & protects) &&  !e2->nextInLML &&
+           e2->xtop == pt.X && e2->ytop == pt.Y;
+       bool e1Contributing = ( e1->outIdx >= 0 );
+       bool e2contributing = ( e2->outIdx >= 0 );
+
+       //update winding counts...
+       //assumes that e1 will be to the right of e2 ABOVE the intersection
+       if ( e1->polyType == e2->polyType )
+       {
+           if ( IsEvenOddFillType( *e1) )
+           {
+               int oldE1WindCnt = e1->windCnt;
+               e1->windCnt = e2->windCnt;
+               e2->windCnt = oldE1WindCnt;
+           } else
+           {
+               if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = 
-e1->windCnt;
+               else e1->windCnt += e2->windDelta;
+               if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = 
-e2->windCnt;
+               else e2->windCnt -= e1->windDelta;
+           }
+       } else
+       {
+           if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta;
+           else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0;
+           if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta;
+           else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0;
+       }
+
+       PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
+       if (e1->polyType == ptSubject)
+       {
+           e1FillType = m_SubjFillType;
+           e1FillType2 = m_ClipFillType;
+       } else
+       {
+           e1FillType = m_ClipFillType;
+           e1FillType2 = m_SubjFillType;
+       }
+       if (e2->polyType == ptSubject)
+       {
+           e2FillType = m_SubjFillType;
+           e2FillType2 = m_ClipFillType;
+       } else
+       {
+           e2FillType = m_ClipFillType;
+           e2FillType2 = m_SubjFillType;
+       }
+
+       long64 e1Wc, e2Wc;
+       switch (e1FillType)
+       {
+           case pftPositive: e1Wc = e1->windCnt; break;
+           case pftNegative: e1Wc = -e1->windCnt; break;
+           default: e1Wc = Abs(e1->windCnt);
+       }
+       switch(e2FillType)
+       {
+           case pftPositive: e2Wc = e2->windCnt; break;
+           case pftNegative: e2Wc = -e2->windCnt; break;
+           default: e2Wc = Abs(e2->windCnt);
+       }
+
+       if ( e1Contributing && e2contributing )
+       {
+           if ( e1stops || e2stops ||
+                   (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
+                   (e1->polyType != e2->polyType && m_ClipType != ctXor) )
+               AddLocalMaxPoly(e1, e2, pt);
+           else
+               DoBothEdges( e1, e2, pt );
+       }
+       else if ( e1Contributing )
+       {
+           if ((e2Wc == 0 || e2Wc == 1) &&
+                   (m_ClipType != ctIntersection ||
+                    e2->polyType == ptSubject || (e2->windCnt2 != 0)))
+               DoEdge1(e1, e2, pt);
+       }
+       else if ( e2contributing )
+       {
+           if ((e1Wc == 0 || e1Wc == 1) &&
+                   (m_ClipType != ctIntersection ||
+                    e1->polyType == ptSubject || (e1->windCnt2 != 0)))
+               DoEdge2(e1, e2, pt);
+       }
+       else if ( (e1Wc == 0 || e1Wc == 1) &&
+               (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops )
+       {
+           //neither edge is currently contributing ...
+
+           long64 e1Wc2, e2Wc2;
+           switch (e1FillType2)
+           {
+               case pftPositive: e1Wc2 = e1->windCnt2; break;
+               case pftNegative : e1Wc2 = -e1->windCnt2; break;
+               default: e1Wc2 = Abs(e1->windCnt2);
+           }
+           switch (e2FillType2)
+           {
+               case pftPositive: e2Wc2 = e2->windCnt2; break;
+               case pftNegative: e2Wc2 = -e2->windCnt2; break;
+               default: e2Wc2 = Abs(e2->windCnt2);
+           }
+
+           if (e1->polyType != e2->polyType)
+               AddLocalMinPoly(e1, e2, pt);
+           else if (e1Wc == 1 && e2Wc == 1)
+               switch( m_ClipType ) {
+                   case ctIntersection:
+                       if (e1Wc2 > 0 && e2Wc2 > 0)
+                           AddLocalMinPoly(e1, e2, pt);
+                       break;
+                   case ctUnion:
+                       if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
+                           AddLocalMinPoly(e1, e2, pt);
+                       break;
+                   case ctDifference:
+                       if ((e1->polyType == ptClip && e2->polyType == ptClip &&
+                                   e1Wc2 > 0 && e2Wc2 > 0) ||
+                               (e1->polyType == ptSubject && e2->polyType == 
ptSubject &&
+                                e1Wc2 <= 0 && e2Wc2 <= 0))
+                           AddLocalMinPoly(e1, e2, pt);
+                       break;
+                   case ctXor:
+                       AddLocalMinPoly(e1, e2, pt);
+               }
+           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;
+       while (e2)
+       {
+           if (e2->outIdx >= 0)
+           {
+               isHole = !isHole;
+               if (! outRec->FirstLeft)
+                   outRec->FirstLeft = m_PolyOuts->at(e2->outIdx);
+           }
+           e2 = e2->prevInAEL;
+       }
+       if (isHole) outRec->isHole = true;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool GetNextNonDupOutPt(OutPt* pp, OutPt*& next)
+    {
+       next = pp->next;
+       while (next != pp && PointsEqual(pp->pt, next->pt))
+           next = next->next;
+       return next != pp;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool GetPrevNonDupOutPt(OutPt* pp, OutPt*& prev)
+    {
+       prev = pp->prev;
+       while (prev != pp && PointsEqual(pp->pt, prev->pt))
+           prev = prev->prev;
+       return prev != pp;
+    }
+    
//------------------------------------------------------------------------------
+
+    OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
+    {
+       //work out which polygon fragment has the correct hole state ...
+       OutPt *outPt1 = outRec1->bottomPt;
+       OutPt *outPt2 = outRec2->bottomPt;
+       if (outPt1->pt.Y > outPt2->pt.Y) return outRec1;
+       else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2;
+       else if (outPt1->pt.X < outPt2->pt.X) return outRec1;
+       else if (outPt1->pt.X > outPt2->pt.X) return outRec2;
+       else if (outRec1->bottomE2 == 0) return outRec2;
+       else if (outRec2->bottomE2 == 0) return outRec1;
+       else
+       {
+           double dx1 = std::max(outRec1->bottomE1->dx, outRec1->bottomE2->dx);
+           double dx2 = std::max(outRec2->bottomE1->dx, outRec2->bottomE2->dx);
+           if (dx2 > dx1) return outRec2; else return outRec1;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
+    {
+       //get the start and ends of both output polygons ...
+       OutRec *outRec1 = m_PolyOuts->at(e1->outIdx);
+       OutRec *outRec2 = m_PolyOuts->at(e2->outIdx);
+       OutRec *holeStateRec = GetLowermostRec(outRec1, outRec2);
+
+       //fixup hole status ...
+       if (holeStateRec == outRec2)
+           outRec1->isHole = outRec2->isHole;
+       else
+           outRec2->isHole = outRec1->isHole;
+
+       OutPt* p1_lft = outRec1->pts;
+       OutPt* p1_rt = p1_lft->prev;
+       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 )
+       {
+           if(  e2->side == esLeft )
+           {
+               //z y x a b c
+               ReversePolyPtLinks(*p2_lft);
+               p2_lft->next = p1_lft;
+               p1_lft->prev = p2_lft;
+               p1_rt->next = p2_rt;
+               p2_rt->prev = p1_rt;
+               outRec1->pts = p2_rt;
+           } else
+           {
+               //x y z a b c
+               p2_rt->next = p1_lft;
+               p1_lft->prev = p2_rt;
+               p2_lft->prev = p1_rt;
+               p1_rt->next = p2_lft;
+               outRec1->pts = p2_lft;
+           }
+           side = esLeft;
+       } else
+       {
+           if(  e2->side == esRight )
+           {
+               //a b c z y x
+               ReversePolyPtLinks( *p2_lft );
+               p1_rt->next = p2_rt;
+               p2_rt->prev = p1_rt;
+               p2_lft->next = p1_lft;
+               p1_lft->prev = p2_lft;
+           } else
+           {
+               //a b c x y z
+               p1_rt->next = p2_lft;
+               p2_lft->prev = p1_rt;
+               p1_lft->prev = p2_rt;
+               p2_rt->next = p1_lft;
+           }
+           side = esRight;
+       }
+
+       if (holeStateRec == outRec2)
+       {
+           outRec1->bottomPt = outRec2->bottomPt;
+           outRec1->bottomPt->idx = outRec1->idx;
+           outRec1->bottomE1 = outRec2->bottomE1;
+           outRec1->bottomE2 = outRec2->bottomE2;
+
+           if (outRec2->FirstLeft != outRec1)
+               outRec1->FirstLeft = outRec2->FirstLeft;
+       }
+       outRec2->pts = 0;
+       outRec2->bottomPt = 0;
+       outRec2->AppendLink = outRec1;
+       int OKIdx = e1->outIdx;
+       int ObsoleteIdx = e2->outIdx;
+
+       e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly
+       e2->outIdx = -1;
+
+       TEdge* e = m_ActiveEdges;
+       while( e )
+       {
+           if( e->outIdx == ObsoleteIdx )
+           {
+               e->outIdx = OKIdx;
+               e->side = side;
+               break;
+           }
+           e = e->nextInAEL;
+       }
+
+       for (JoinList::size_type i = 0; i < m_Joins->size(); ++i)
+       {
+           if (m_Joins->at(i)->poly1Idx == ObsoleteIdx) 
m_Joins->at(i)->poly1Idx = OKIdx;
+           if (m_Joins->at(i)->poly2Idx == ObsoleteIdx) 
m_Joins->at(i)->poly2Idx = OKIdx;
+       }
+
+       for (HorzJoinList::size_type i = 0; i < m_HorizJoins->size(); ++i)
+       {
+           if (m_HorizJoins->at(i)->savedIdx == ObsoleteIdx)
+               m_HorizJoins->at(i)->savedIdx = OKIdx;
+       }
+
+    }
+    
//------------------------------------------------------------------------------
+
+    OutRec* Clipper::CreateOutRec()
+    {
+       OutRec* result = new OutRec;
+       result->isHole = false;
+       result->FirstLeft = 0;
+       result->AppendLink = 0;
+       result->pts = 0;
+       result->bottomPt = 0;
+       return result;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddOutPt(TEdge *e, TEdge *altE, const IntPoint &pt)
+    {
+       bool ToFront = (e->side == esLeft);
+       if(  e->outIdx < 0 )
+       {
+           OutRec *outRec = CreateOutRec();
+           m_PolyOuts->push_back(outRec);
+           outRec->idx = (int)m_PolyOuts->size()-1;
+           e->outIdx = outRec->idx;
+           OutPt* op = new OutPt;
+           outRec->pts = op;
+           outRec->bottomE1 = e;
+           outRec->bottomE2 = altE;
+           outRec->bottomPt = op;
+           op->pt = pt;
+           op->idx = outRec->idx;
+           op->next = op;
+           op->prev = op;
+           SetHoleState(e, outRec);
+       } else
+       {
+           OutRec *outRec = m_PolyOuts->at(e->outIdx);
+           OutPt* op = outRec->pts;
+           if ((ToFront && PointsEqual(pt, op->pt)) ||
+                   (!ToFront && PointsEqual(pt, op->prev->pt))) return;
+           OutPt* op2 = new OutPt;
+           op2->pt = pt;
+           op2->idx = outRec->idx;
+           if (op2->pt.Y == outRec->bottomPt->pt.Y &&
+                   op2->pt.X < outRec->bottomPt->pt.X)
+           {
+               outRec->bottomPt = op2;
+               outRec->bottomE1 = e;
+               outRec->bottomE2 = altE;
+           }
+           op2->next = op;
+           op2->prev = op->prev;
+           op2->prev->next = op2;
+           op->prev = op2;
+           if (ToFront) outRec->pts = op2;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ProcessHorizontals()
+    {
+       TEdge* horzEdge = m_SortedEdges;
+       while( horzEdge )
+       {
+           DeleteFromSEL( horzEdge );
+           ProcessHorizontal( horzEdge );
+           horzEdge = m_SortedEdges;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::IsTopHorz(const long64 XPos)
+    {
+       TEdge* e = m_SortedEdges;
+       while( e )
+       {
+           if(  ( XPos >= std::min(e->xcurr, e->xtop) ) &&
+                   ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false;
+           e = e->nextInSEL;
+       }
+       return true;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool IsMinima(TEdge *e)
+    {
+       return e  && (e->prev->nextInLML != e) && (e->next->nextInLML != e);
+    }
+    
//------------------------------------------------------------------------------
+
+    bool IsMaxima(TEdge *e, const long64 Y)
+    {
+       return e && e->ytop == Y && !e->nextInLML;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool IsIntermediate(TEdge *e, const long64 Y)
+    {
+       return e->ytop == Y && e->nextInLML;
+    }
+    
//------------------------------------------------------------------------------
+
+    TEdge *GetMaximaPair(TEdge *e)
+    {
+       if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop )
+           return e->prev; else
+               return e->next;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2)
+    {
+       if(  !edge1->nextInAEL &&  !edge1->prevInAEL ) return;
+       if(  !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 Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2)
+    {
+       if(  !( edge1->nextInSEL ) &&  !( edge1->prevInSEL ) ) return;
+       if(  !( edge2->nextInSEL ) &&  !( edge2->prevInSEL ) ) return;
+
+       if(  edge1->nextInSEL == edge2 )
+       {
+           TEdge* next = edge2->nextInSEL;
+           if( next ) next->prevInSEL = edge1;
+           TEdge* prev = edge1->prevInSEL;
+           if( prev ) prev->nextInSEL = edge2;
+           edge2->prevInSEL = prev;
+           edge2->nextInSEL = edge1;
+           edge1->prevInSEL = edge2;
+           edge1->nextInSEL = next;
+       }
+       else if(  edge2->nextInSEL == edge1 )
+       {
+           TEdge* next = edge1->nextInSEL;
+           if( next ) next->prevInSEL = edge2;
+           TEdge* prev = edge2->prevInSEL;
+           if( prev ) prev->nextInSEL = edge1;
+           edge1->prevInSEL = prev;
+           edge1->nextInSEL = edge2;
+           edge2->prevInSEL = edge1;
+           edge2->nextInSEL = next;
+       }
+       else
+       {
+           TEdge* next = edge1->nextInSEL;
+           TEdge* prev = edge1->prevInSEL;
+           edge1->nextInSEL = edge2->nextInSEL;
+           if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1;
+           edge1->prevInSEL = edge2->prevInSEL;
+           if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1;
+           edge2->nextInSEL = next;
+           if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2;
+           edge2->prevInSEL = prev;
+           if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2;
+       }
+
+       if( !edge1->prevInSEL ) m_SortedEdges = edge1;
+       else if( !edge2->prevInSEL ) m_SortedEdges = edge2;
+    }
+    
//------------------------------------------------------------------------------
+
+    TEdge* GetNextInAEL(TEdge *e, Direction dir)
+    {
+       if( dir == dLeftToRight ) return e->nextInAEL;
+       else return e->prevInAEL;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ProcessHorizontal(TEdge *horzEdge)
+    {
+       Direction dir;
+       long64 horzLeft, horzRight;
+
+       if( horzEdge->xcurr < horzEdge->xtop )
+       {
+           horzLeft = horzEdge->xcurr;
+           horzRight = horzEdge->xtop;
+           dir = dLeftToRight;
+       } else
+       {
+           horzLeft = horzEdge->xtop;
+           horzRight = horzEdge->xcurr;
+           dir = dRightToLeft;
+       }
+
+       TEdge* eMaxPair;
+       if( horzEdge->nextInLML ) eMaxPair = 0;
+       else eMaxPair = GetMaximaPair(horzEdge);
+
+       TEdge* e = GetNextInAEL( horzEdge , dir );
+       while( e )
+       {
+           TEdge* eNext = GetNextInAEL( e, dir );
+
+           if (eMaxPair ||
+                   ((dir == dLeftToRight) && (e->xcurr <= horzRight)) ||
+                   ((dir == dRightToLeft) && (e->xcurr >= horzLeft)))
+           {
+               //ok, so far it looks like we're still in range of the 
horizontal edge
+               if ( e->xcurr == horzEdge->xtop && !eMaxPair )
+               {
+                   if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange))
+                   {
+                       //if output polygons share an edge, they'll need 
joining later ...
+                       if (horzEdge->outIdx >= 0 && e->outIdx >= 0)
+                           AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx);
+                       break; //we've reached the end of the horizontal line
+                   }
+                   else if (e->dx < horzEdge->nextInLML->dx)
+                       //we really have got to the end of the intermediate 
horz edge so quit.
+                       //nb: More -ve slopes follow more +ve slopes ABOVE the 
horizontal.
+                       break;
+               }
+
+               if( e == eMaxPair )
+               {
+                   //horzEdge is evidently a maxima horizontal and we've 
arrived at its end.
+                   if (dir == dLeftToRight)
+                       IntersectEdges(horzEdge, e, IntPoint(e->xcurr, 
horzEdge->ycurr), ipNone);
+                   else
+                       IntersectEdges(e, horzEdge, IntPoint(e->xcurr, 
horzEdge->ycurr), ipNone);
+                   if (eMaxPair->outIdx >= 0) throw 
clipperException("ProcessHorizontal error");
+                   return;
+               }
+               else if( NEAR_EQUAL(e->dx, HORIZONTAL) &&  !IsMinima(e) && 
!(e->xcurr > e->xtop) )
+               {
+                   //An overlapping horizontal edge. Overlapping horizontal 
edges are
+                   //processed as if layered with the current horizontal edge 
(horizEdge)
+                   //being infinitesimally lower that the next (e). Therfore, 
we
+                   //intersect with e only if e.xcurr is within the bounds of 
horzEdge ...
+                   if( dir == dLeftToRight )
+                       IntersectEdges( horzEdge , e, IntPoint(e->xcurr, 
horzEdge->ycurr),
+                               (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
+                   else
+                       IntersectEdges( e, horzEdge, IntPoint(e->xcurr, 
horzEdge->ycurr),
+                               (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
+               }
+               else if( dir == dLeftToRight )
+               {
+                   IntersectEdges( horzEdge, e, IntPoint(e->xcurr, 
horzEdge->ycurr),
+                           (IsTopHorz( e->xcurr ))? ipLeft : ipBoth );
+               }
+               else
+               {
+                   IntersectEdges( e, horzEdge, IntPoint(e->xcurr, 
horzEdge->ycurr),
+                           (IsTopHorz( e->xcurr ))? ipRight : ipBoth );
+               }
+               SwapPositionsInAEL( horzEdge, e );
+           }
+           else if( (dir == dLeftToRight && e->xcurr > horzRight  && 
m_SortedEdges) ||
+                   (dir == dRightToLeft && e->xcurr < horzLeft && 
m_SortedEdges) ) break;
+           e = eNext;
+       } //end while
+
+       if( horzEdge->nextInLML )
+       {
+           if( horzEdge->outIdx >= 0 )
+               AddOutPt( horzEdge, 0, IntPoint(horzEdge->xtop, 
horzEdge->ytop));
+           UpdateEdgeIntoAEL( horzEdge );
+       }
+       else
+       {
+           if ( horzEdge->outIdx >= 0 )
+               IntersectEdges( horzEdge, eMaxPair,
+                       IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth);
+           if (eMaxPair->outIdx >= 0) throw 
clipperException("ProcessHorizontal error");
+           DeleteFromAEL(eMaxPair);
+           DeleteFromAEL(horzEdge);
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::UpdateEdgeIntoAEL(TEdge *&e)
+    {
+       if( !e->nextInLML ) throw
+           clipperException("UpdateEdgeIntoAEL: invalid call");
+       TEdge* AelPrev = e->prevInAEL;
+       TEdge* AelNext = e->nextInAEL;
+       e->nextInLML->outIdx = e->outIdx;
+       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->prevInAEL = AelPrev;
+       e->nextInAEL = AelNext;
+       if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop );
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::ProcessIntersections(const long64 botY, const long64 topY)
+    {
+       if( !m_ActiveEdges ) return true;
+       try {
+           BuildIntersectList(botY, topY);
+           if ( !m_IntersectNodes) return true;
+           if ( FixupIntersections() ) ProcessIntersectList();
+           else return false;
+       }
+       catch(...) {
+           m_SortedEdges = 0;
+           DisposeIntersectNodes();
+           throw clipperException("ProcessIntersections error");
+       }
+       return true;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::DisposeIntersectNodes()
+    {
+       while ( m_IntersectNodes )
+       {
+           IntersectNode* iNode = m_IntersectNodes->next;
+           delete m_IntersectNodes;
+           m_IntersectNodes = iNode;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::BuildIntersectList(const long64 botY, const long64 topY)
+    {
+       if ( !m_ActiveEdges ) return;
+
+       //prepare for sorting ...
+       TEdge* e = m_ActiveEdges;
+       e->tmpX = TopX( *e, topY );
+       m_SortedEdges = e;
+       m_SortedEdges->prevInSEL = 0;
+       e = e->nextInAEL;
+       while( e )
+       {
+           e->prevInSEL = e->prevInAEL;
+           e->prevInSEL->nextInSEL = e;
+           e->nextInSEL = 0;
+           e->tmpX = TopX( *e, topY );
+           e = e->nextInAEL;
+       }
+
+       //bubblesort ...
+       bool isModified = true;
+       while( isModified && m_SortedEdges )
+       {
+           isModified = false;
+           e = m_SortedEdges;
+           while( e->nextInSEL )
+           {
+               TEdge *eNext = e->nextInSEL;
+               IntPoint pt;
+               if(e->tmpX > eNext->tmpX &&
+                       IntersectPoint(*e, *eNext, pt, m_UseFullRange))
+               {
+                   if (pt.Y > botY)
+                   {
+                       pt.Y = botY;
+                       pt.X = TopX(*e, pt.Y);
+                   }
+                   AddIntersectNode( e, eNext, pt );
+                   SwapPositionsInSEL(e, eNext);
+                   isModified = true;
+               }
+               else
+                   e = eNext;
+           }
+           if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0;
+           else break;
+       }
+       m_SortedEdges = 0;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Process1Before2(IntersectNode &node1, IntersectNode &node2)
+    {
+       bool result;
+       if (node1.pt.Y == node2.pt.Y)
+       {
+           if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1)
+           {
+               result = node2.pt.X > node1.pt.X;
+               if (node2.edge1->dx > 0) return !result; else return result;
+           }
+           else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2)
+           {
+               result = node2.pt.X > node1.pt.X;
+               if (node2.edge2->dx > 0) return !result; else return result;
+           }
+           else return node2.pt.X > node1.pt.X;
+       }
+       else return node1.pt.Y > node2.pt.Y;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt)
+    {
+       IntersectNode* newNode = new IntersectNode;
+       newNode->edge1 = e1;
+       newNode->edge2 = e2;
+       newNode->pt = pt;
+       newNode->next = 0;
+       if( !m_IntersectNodes ) m_IntersectNodes = newNode;
+       else if(  Process1Before2(*newNode, *m_IntersectNodes) )
+       {
+           newNode->next = m_IntersectNodes;
+           m_IntersectNodes = newNode;
+       }
+       else
+       {
+           IntersectNode* iNode = m_IntersectNodes;
+           while( iNode->next  && Process1Before2(*iNode->next, *newNode) )
+               iNode = iNode->next;
+           newNode->next = iNode->next;
+           iNode->next = newNode;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ProcessIntersectList()
+    {
+       while( m_IntersectNodes )
+       {
+           IntersectNode* iNode = m_IntersectNodes->next;
+           {
+               IntersectEdges( m_IntersectNodes->edge1 ,
+                       m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth 
);
+               SwapPositionsInAEL( m_IntersectNodes->edge1 , 
m_IntersectNodes->edge2 );
+           }
+           delete m_IntersectNodes;
+           m_IntersectNodes = iNode;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::DoMaxima(TEdge *e, long64 topY)
+    {
+       TEdge* eMaxPair = GetMaximaPair(e);
+       long64 X = e->xtop;
+       TEdge* eNext = e->nextInAEL;
+       while( eNext != eMaxPair )
+       {
+           if (!eNext) throw clipperException("DoMaxima error");
+           IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth );
+           eNext = eNext->nextInAEL;
+       }
+       if( e->outIdx < 0 && eMaxPair->outIdx < 0 )
+       {
+           DeleteFromAEL( e );
+           DeleteFromAEL( eMaxPair );
+       }
+       else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 )
+       {
+           IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone );
+       }
+       else throw clipperException("DoMaxima error");
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY)
+    {
+       TEdge* e = m_ActiveEdges;
+       while( e )
+       {
+           //1. process maxima, treating them as if they're 'bent' horizontal 
edges,
+           //   but exclude maxima with horizontal edges. nb: e can't be a 
horizontal.
+           if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, 
HORIZONTAL) )
+           {
+               //'e' might be removed from AEL, as may any following edges so 
...
+               TEdge* ePrior = e->prevInAEL;
+               DoMaxima(e, topY);
+               if( !ePrior ) e = m_ActiveEdges;
+               else e = ePrior->nextInAEL;
+           }
+           else
+           {
+               //2. promote horizontal edges, otherwise update xcurr and ycurr 
...
+               if(  IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, 
HORIZONTAL) )
+               {
+                   if (e->outIdx >= 0)
+                   {
+                       AddOutPt(e, 0, IntPoint(e->xtop, e->ytop));
+
+                       for (HorzJoinList::size_type i = 0; i < 
m_HorizJoins->size(); ++i)
+                       {
+                           IntPoint pt, pt2;
+                           HorzJoinRec* hj = m_HorizJoins->at(i);
+                           if (GetOverlapSegment(IntPoint(hj->edge->xbot, 
hj->edge->ybot),
+                                       IntPoint(hj->edge->xtop, 
hj->edge->ytop),
+                                       IntPoint(e->nextInLML->xbot, 
e->nextInLML->ybot),
+                                       IntPoint(e->nextInLML->xtop, 
e->nextInLML->ytop), pt, pt2))
+                               AddJoin(hj->edge, e->nextInLML, hj->savedIdx, 
e->outIdx);
+                       }
+
+                       AddHorzJoin(e->nextInLML, e->outIdx);
+                   }
+                   UpdateEdgeIntoAEL(e);
+                   AddEdgeToSEL(e);
+               } else
+               {
+                   //this just simplifies horizontal processing ...
+                   e->xcurr = TopX( *e, topY );
+                   e->ycurr = topY;
+               }
+               e = e->nextInAEL;
+           }
+       }
+
+       //3. Process horizontals at the top of the scanbeam ...
+       ProcessHorizontals();
+
+       //4. Promote intermediate vertices ...
+       e = m_ActiveEdges;
+       while( e )
+       {
+           if( IsIntermediate( e, topY ) )
+           {
+               if( e->outIdx >= 0 ) AddOutPt(e, 0, IntPoint(e->xtop,e->ytop));
+               UpdateEdgeIntoAEL(e);
+
+               //if output polygons share an edge, they'll need joining later 
...
+               if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 
&&
+                       e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr 
== e->ybot &&
+                       SlopesEqual(IntPoint(e->xbot,e->ybot), 
IntPoint(e->xtop, e->ytop),
+                           IntPoint(e->xbot,e->ybot),
+                           IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), 
m_UseFullRange))
+               {
+                   AddOutPt(e->prevInAEL, 0, IntPoint(e->xbot, e->ybot));
+                   AddJoin(e, e->prevInAEL);
+               }
+               else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx 
>= 0 &&
+                       e->nextInAEL->ycurr > e->nextInAEL->ytop &&
+                       e->nextInAEL->ycurr < e->nextInAEL->ybot &&
+                       e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr 
== e->ybot &&
+                       SlopesEqual(IntPoint(e->xbot,e->ybot), 
IntPoint(e->xtop, e->ytop),
+                           IntPoint(e->xbot,e->ybot),
+                           IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), 
m_UseFullRange))
+               {
+                   AddOutPt(e->nextInAEL, 0, IntPoint(e->xbot, e->ybot));
+                   AddJoin(e, e->nextInAEL);
+               }
+           }
+           e = e->nextInAEL;
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::FixupOutPolygon(OutRec &outRec)
+    {
+       //FixupOutPolygon() - removes duplicate points and simplifies 
consecutive
+       //parallel edges by removing the middle vertex.
+       OutPt *lastOK = 0;
+       outRec.pts = outRec.bottomPt;
+       OutPt *pp = outRec.bottomPt;
+
+       for (;;)
+       {
+           if (pp->prev == pp || pp->prev == pp->next )
+           {
+               DisposeOutPts(pp);
+               outRec.pts = 0;
+               outRec.bottomPt = 0;
+               return;
+           }
+           //test for duplicate points and for same slope (cross-product) ...
+           if ( PointsEqual(pp->pt, pp->next->pt) ||
+                   SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, 
m_UseFullRange) )
+           {
+               lastOK = 0;
+               OutPt *tmp = pp;
+               if (pp == outRec.bottomPt)
+               {
+                   if (tmp->prev->pt.Y > tmp->next->pt.Y)
+                       outRec.bottomPt = tmp->prev; else
+                           outRec.bottomPt = tmp->next;
+                   outRec.pts = outRec.bottomPt;
+                   outRec.bottomPt->idx = outRec.idx;
+               }
+               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;
+           }
+       }
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::BuildResult(Polygons &polys)
+    {
+       int k = 0;
+       polys.resize(m_PolyOuts->size());
+       for (PolyOutList::size_type i = 0; i < m_PolyOuts->size(); ++i)
+       {
+           if (m_PolyOuts->at(i)->pts)
+           {
+               Polygon* pg = &polys[k];
+               pg->clear();
+               OutPt* p = m_PolyOuts->at(i)->pts;
+               do
+               {
+                   pg->push_back(p->pt);
+                   p = p->next;
+               } while (p != m_PolyOuts->at(i)->pts);
+               //make sure each polygon has at least 3 vertices ...
+               if (pg->size() < 3) pg->clear(); else k++;
+           }
+       }
+       polys.resize(k);
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::BuildResultEx(ExPolygons &polys)
+    {
+       PolyOutList::size_type i = 0;
+       int k = 0;
+       polys.resize(0);
+       polys.reserve(m_PolyOuts->size());
+       while (i < m_PolyOuts->size() && m_PolyOuts->at(i)->pts)
+       {
+           ExPolygon epg;
+           OutPt* p = m_PolyOuts->at(i)->pts;
+           do {
+               epg.outer.push_back(p->pt);
+               p = p->next;
+           } while (p != m_PolyOuts->at(i)->pts);
+           i++;
+           //make sure polygons have at least 3 vertices ...
+           if (epg.outer.size() < 3) continue;
+           while (i < m_PolyOuts->size()
+                   && m_PolyOuts->at(i)->pts && m_PolyOuts->at(i)->isHole)
+           {
+               Polygon pg;
+               p = m_PolyOuts->at(i)->pts;
+               do {
+                   pg.push_back(p->pt);
+                   p = p->next;
+               } while (p != m_PolyOuts->at(i)->pts);
+               epg.holes.push_back(pg);
+               i++;
+           }
+           polys.push_back(epg);
+           k++;
+       }
+       polys.resize(k);
+    }
+    
//------------------------------------------------------------------------------
+
+    void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2)
+    {
+       TEdge *e1 = int1.edge1;
+       TEdge *e2 = int1.edge2;
+       IntPoint p = int1.pt;
+
+       int1.edge1 = int2.edge1;
+       int1.edge2 = int2.edge2;
+       int1.pt = int2.pt;
+
+       int2.edge1 = e1;
+       int2.edge2 = e2;
+       int2.pt = p;
+    }
+    
//------------------------------------------------------------------------------
+
+    bool Clipper::FixupIntersections()
+    {
+       if ( !m_IntersectNodes->next ) return true;
+
+       CopyAELToSEL();
+       IntersectNode *int1 = m_IntersectNodes;
+       IntersectNode *int2 = m_IntersectNodes->next;
+       while (int2)
+       {
+           TEdge *e1 = int1->edge1;
+           TEdge *e2;
+           if (e1->prevInSEL == int1->edge2) e2 = e1->prevInSEL;
+           else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL;
+           else
+           {
+               //The current intersection is out of order, so try and swap it 
with
+               //a subsequent intersection ...
+               while (int2)
+               {
+                   if (int2->edge1->nextInSEL == int2->edge2 ||
+                           int2->edge1->prevInSEL == int2->edge2) break;
+                   else int2 = int2->next;
+               }
+               if ( !int2 ) return false; //oops!!!
+
+               //found an intersect node that can be swapped ...
+               SwapIntersectNodes(*int1, *int2);
+               e1 = int1->edge1;
+               e2 = int1->edge2;
+           }
+           SwapPositionsInSEL(e1, e2);
+           int1 = int1->next;
+           int2 = int1->next;
+       }
+
+       m_SortedEdges = 0;
+
+       //finally, check the last intersection too ...
+       return (int1->edge1->prevInSEL == int1->edge2 ||
+               int1->edge1->nextInSEL == int1->edge2);
+    }
+    
//------------------------------------------------------------------------------
+
+    bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
+    {
+       if (e2.xcurr == e1.xcurr) return e2.dx > e1.dx;
+       else return e2.xcurr < e1.xcurr;
+    }
+    
//------------------------------------------------------------------------------
+
+    void Clipper::InsertEdgeIntoAEL(TEdge *edge)
+    {
+       edge->prevInAEL = 0;
+       edge->nextInAEL = 0;
+       if( !m_ActiveEdges )
+       {
+           m_ActiveEdges = edge;
+       }
+       else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) )
+       {
+           edge->nextInAEL = m_ActiveEdges;
+           m_ActiveEdges->prevInAEL = edge;
+           m_ActiveEdges = edge;
+       } else
+       {
+           TEdge* e = m_ActiveEdges;
+           while( e->nextInAEL  && !E2InsertsBeforeE1(*e->nextInAEL , *edge) )
+               e = e->nextInAEL;
+           edge->nextInAEL = e->nextInAEL;
+           if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge;
+           edge->prevInAEL = e;
+           e->nextInAEL = edge;
+       }
+    }
+    //----------------------------------------------------------------------
+
+    void Clipper::DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+    {
+       AddOutPt(edge1, edge2, pt);
+       SwapSides(*edge1, *edge2);
+       SwapPolyIndexes(*edge1, *edge2);
+    }
+    //----------------------------------------------------------------------
+
+    void Clipper::DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+    {
+       AddOutPt(edge2, edge1, pt);
+       SwapSides(*edge1, *edge2);
+       SwapPolyIndexes(*edge1, *edge2);
+    }
+    //----------------------------------------------------------------------
+
+    void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt)
+    {
+       AddOutPt(edge1, edge2, pt);
+       AddOutPt(edge2, edge1, pt);
+       SwapSides( *edge1 , *edge2 );
+       SwapPolyIndexes( *edge1 , *edge2 );
+    }
+    //----------------------------------------------------------------------
+
+    void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2)
+    {
+       //when a polygon is split into 2 polygons, make sure any holes the 
original
+       //polygon contained link to the correct polygon ...
+       for (PolyOutList::size_type i = 0; i < m_PolyOuts->size(); ++i)
+       {
+           OutRec *orec = m_PolyOuts->at(i);
+           if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 &&
+                   !PointInPolygon(orec->bottomPt->pt, outRec1->pts, 
m_UseFullRange))
+               orec->FirstLeft = outRec2;
+       }
+    }
+    //----------------------------------------------------------------------
+
+    void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2)
+    {
+       //if a hole is owned by outRec2 then make it owned by outRec1 ...
+       for (PolyOutList::size_type i = 0; i < m_PolyOuts->size(); ++i)
+           if (m_PolyOuts->at(i)->isHole && m_PolyOuts->at(i)->bottomPt &&

@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
brlcad-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to