>From an architecture perspective, having the clipper header be exported and 
>published violates encapsulation and introduces a lib dependence.  Can it move 
>to the src dir, private header?

> On Oct 17, 2018, at 8:45 AM, starseeker--- via brlcad-commits 
> <brlcad-comm...@lists.sourceforge.net> wrote:
> 
> 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-comm...@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/brlcad-commits


_______________________________________________
BRL-CAD Developer mailing list
brlcad-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-devel

Reply via email to