2013-07-16 20:09:53 +02:00
/*******************************************************************************
* *
* Author : Angus Johnson *
2015-02-22 15:13:52 +01:00
* Version : 6.2.9 *
* Date : 16 February 2015 *
2013-07-16 20:09:53 +02:00
* Website : http://www.angusj.com *
2015-02-15 16:10:04 +01:00
* Copyright : Angus Johnson 2010-2015 *
2013-07-16 20:09:53 +02:00
* *
* 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-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
2015-02-15 16:10:04 +01:00
#define CLIPPER_VERSION "6.2.6"
2013-11-20 11:35:58 +01:00
//use_int32: When enabled 32bit ints are used instead of 64bit ints. This
//improve performance but coordinate values are limited to the range +/- 46340
//#define use_int32
//use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
//#define use_xyz
//use_lines: Enables line clipping. Adds a very minor cost to performance.
2013-11-21 14:15:38 +01:00
#define use_lines
2013-11-20 11:35:58 +01:00
2014-11-08 12:05:27 +01:00
//use_deprecated: Enables temporary support for the obsolete functions
2013-11-20 15:59:19 +01:00
//#define use_deprecated
2013-11-20 11:35:58 +01:00
2013-07-16 20:09:53 +02:00
#include <vector>
2017-03-02 20:44:43 +01:00
#include <list>
#include <set>
2013-07-16 20:09:53 +02:00
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
2013-11-20 11:35:58 +01:00
#include <functional>
2014-11-08 12:05:27 +01:00
#include <queue>
2013-07-16 20:09:53 +02:00
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 };
2013-11-20 11:35:58 +01:00
#ifdef use_int32
2014-05-23 23:58:43 +02:00
typedef int cInt ;
2014-11-08 12:05:27 +01:00
static cInt const loRange = 0x7FFF ;
static cInt const hiRange = 0x7FFF ;
2013-11-20 11:35:58 +01:00
#else
2014-05-23 23:58:43 +02:00
typedef signed long long cInt ;
static cInt const loRange = 0x3FFFFFFF ;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL ;
2014-11-08 12:05:27 +01:00
typedef signed long long long64 ; //used by Int128 class
typedef unsigned long long ulong64 ;
2013-11-20 11:35:58 +01:00
#endif
2013-07-16 20:09:53 +02:00
struct IntPoint {
2013-11-20 11:35:58 +01:00
cInt X ;
cInt Y ;
#ifdef use_xyz
cInt Z ;
IntPoint ( cInt x = 0 , cInt y = 0 , cInt z = 0 ) : X ( x ), Y ( y ), Z ( z ) {};
#else
IntPoint ( cInt x = 0 , cInt y = 0 ) : X ( x ), Y ( y ) {};
#endif
friend inline bool operator == ( const IntPoint & a , const IntPoint & b )
{
return a . X == b . X && a . Y == b . Y ;
}
friend inline bool operator != ( const IntPoint & a , const IntPoint & b )
{
return a . X != b . X || a . Y != b . Y ;
}
2013-07-16 20:09:53 +02:00
};
2013-11-20 11:35:58 +01:00
//------------------------------------------------------------------------------
2013-07-16 20:09:53 +02:00
2013-11-20 11:35:58 +01:00
typedef std :: vector < IntPoint > Path ;
typedef std :: vector < Path > Paths ;
2013-07-16 20:09:53 +02:00
2013-11-20 11:35:58 +01:00
inline Path & operator << ( Path & poly , const IntPoint & p ) { poly . push_back ( p ); return poly ;}
inline Paths & operator << ( Paths & polys , const Path & p ) { polys . push_back ( p ); return polys ;}
2013-07-16 20:09:53 +02:00
2013-11-20 11:35:58 +01:00
std :: ostream & operator << ( std :: ostream & s , const IntPoint & p );
std :: ostream & operator << ( std :: ostream & s , const Path & p );
std :: ostream & operator << ( std :: ostream & s , const Paths & p );
struct DoublePoint
{
double X ;
double Y ;
DoublePoint ( double x = 0 , double y = 0 ) : X ( x ), Y ( y ) {}
DoublePoint ( IntPoint ip ) : X (( double ) ip . X ), Y (( double ) ip . Y ) {}
};
//------------------------------------------------------------------------------
#ifdef use_xyz
2014-11-08 12:05:27 +01:00
typedef void ( * ZFillCallback )( IntPoint & e1bot , IntPoint & e1top , IntPoint & e2bot , IntPoint & e2top , IntPoint & pt );
2013-11-20 11:35:58 +01:00
#endif
2013-07-16 20:09:53 +02:00
2013-12-24 12:40:46 +01:00
enum InitOptions { ioReverseSolution = 1 , ioStrictlySimple = 2 , ioPreserveCollinear = 4 };
enum JoinType { jtSquare , jtRound , jtMiter };
enum EndType { etClosedPolygon , etClosedLine , etOpenButt , etOpenSquare , etOpenRound };
2013-07-16 20:09:53 +02:00
class PolyNode ;
typedef std :: vector < PolyNode * > PolyNodes ;
class PolyNode
{
public :
2017-03-02 20:44:43 +01:00
PolyNode ();
2014-11-08 12:05:27 +01:00
virtual ~ PolyNode (){};
2013-11-20 11:35:58 +01:00
Path Contour ;
2013-07-16 20:09:53 +02:00
PolyNodes Childs ;
PolyNode * Parent ;
2017-03-02 20:44:43 +01:00
PolyNode * GetNext () const ;
2013-07-16 20:09:53 +02:00
bool IsHole () const ;
2017-03-02 20:44:43 +01:00
bool IsOpen () const ;
int ChildCount () const ;
2013-07-16 20:09:53 +02:00
private :
unsigned Index ; //node index in Parent.Childs
2013-12-24 12:40:46 +01:00
bool m_IsOpen ;
JoinType m_jointype ;
EndType m_endtype ;
2017-03-02 20:44:43 +01:00
PolyNode * GetNextSiblingUp () const ;
2013-07-16 20:09:53 +02:00
void AddChild ( PolyNode & child );
friend class Clipper ; //to access Index
2016-12-13 18:59:18 +01:00
friend class ClipperOffset ;
friend class PolyTree ; //to implement the PolyTree::move operator
2013-07-16 20:09:53 +02:00
};
class PolyTree : public PolyNode
{
public :
2016-12-13 18:59:18 +01:00
PolyTree () {}
PolyTree ( PolyTree && src ) { * this = std :: move ( src ); }
virtual ~ PolyTree (){ Clear ();};
PolyTree & operator = ( PolyTree && src ) {
AllNodes = std :: move ( src . AllNodes );
Contour = std :: move ( src . Contour );
Childs = std :: move ( src . Childs );
Parent = nullptr ;
Index = src . Index ;
m_IsOpen = src . m_IsOpen ;
m_jointype = src . m_jointype ;
m_endtype = src . m_endtype ;
for ( size_t i = 0 ; i < Childs . size (); ++ i )
Childs [ i ] -> Parent = this ;
return * this ;
}
2017-03-02 20:44:43 +01:00
PolyNode * GetFirst () const ;
void Clear ();
2013-07-16 20:09:53 +02:00
int Total () const ;
private :
2016-12-13 18:59:18 +01:00
PolyTree ( const PolyTree & src ) = delete ;
PolyTree & operator = ( const PolyTree & src ) = delete ;
2017-03-02 20:44:43 +01:00
PolyNodes AllNodes ;
2013-07-16 20:09:53 +02:00
friend class Clipper ; //to access AllNodes
};
2017-03-02 20:44:28 +01:00
bool Orientation ( const Path & poly );
2013-11-20 11:35:58 +01:00
double Area ( const Path & poly );
2014-03-23 21:40:35 +01:00
int PointInPolygon ( const IntPoint & pt , const Path & path );
2013-07-16 20:09:53 +02:00
2013-11-20 11:35:58 +01:00
void SimplifyPolygon ( const Path & in_poly , Paths & out_polys , PolyFillType fillType = pftEvenOdd );
void SimplifyPolygons ( const Paths & in_polys , Paths & out_polys , PolyFillType fillType = pftEvenOdd );
void SimplifyPolygons ( Paths & polys , PolyFillType fillType = pftEvenOdd );
2013-07-16 20:09:53 +02:00
2013-11-20 11:35:58 +01:00
void CleanPolygon ( const Path & in_poly , Path & out_poly , double distance = 1.415 );
void CleanPolygon ( Path & poly , double distance = 1.415 );
void CleanPolygons ( const Paths & in_polys , Paths & out_polys , double distance = 1.415 );
void CleanPolygons ( Paths & polys , double distance = 1.415 );
2013-07-16 20:09:53 +02:00
2014-03-23 21:40:35 +01:00
void MinkowskiSum ( const Path & pattern , const Path & path , Paths & solution , bool pathIsClosed );
2014-05-23 23:58:43 +02:00
void MinkowskiSum ( const Path & pattern , const Paths & paths , Paths & solution , bool pathIsClosed );
2014-03-23 21:40:35 +01:00
void MinkowskiDiff ( const Path & poly1 , const Path & poly2 , Paths & solution );
2013-11-20 11:35:58 +01:00
void PolyTreeToPaths ( const PolyTree & polytree , Paths & paths );
void ClosedPathsFromPolyTree ( const PolyTree & polytree , Paths & paths );
void OpenPathsFromPolyTree ( PolyTree & polytree , Paths & paths );
void ReversePath ( Path & p );
void ReversePaths ( Paths & p );
struct IntRect { cInt left ; cInt top ; cInt right ; cInt bottom ; };
//enums that are used internally ...
2013-07-16 20:09:53 +02:00
enum EdgeSide { esLeft = 1 , esRight = 2 };
2017-03-02 20:44:43 +01:00
//forward declarations (for stuff used internally) ...
struct TEdge ;
struct IntersectNode ;
struct LocalMinimum ;
struct OutPt ;
struct OutRec ;
2017-03-01 14:27:08 +01:00
struct Join {
Join ( OutPt * OutPt1 , OutPt * OutPt2 , IntPoint OffPt ) :
OutPt1 ( OutPt1 ), OutPt2 ( OutPt2 ), OffPt ( OffPt ) {}
OutPt * OutPt1 ;
OutPt * OutPt2 ;
IntPoint OffPt ;
};
2013-07-16 20:09:53 +02:00
2017-03-02 20:44:43 +01:00
typedef std :: vector < OutRec * > PolyOutList ;
typedef std :: vector < TEdge * > EdgeList ;
2017-03-01 14:27:08 +01:00
typedef std :: vector < Join > JoinList ;
2017-03-02 20:44:43 +01:00
typedef std :: vector < IntersectNode * > IntersectList ;
2013-12-24 12:40:46 +01:00
2013-11-20 11:35:58 +01:00
//------------------------------------------------------------------------------
2013-07-16 20:09:53 +02:00
//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 ClipperBase
{
public :
2017-03-02 20:44:43 +01:00
ClipperBase ();
virtual ~ ClipperBase ();
2013-11-20 11:35:58 +01:00
bool AddPath ( const Path & pg , PolyType PolyTyp , bool Closed );
bool AddPaths ( const Paths & ppg , PolyType PolyTyp , bool Closed );
2013-07-16 20:09:53 +02:00
virtual void Clear ();
IntRect GetBounds ();
2017-03-01 14:27:08 +01:00
// By default, when three or more vertices are collinear in input polygons (subject or clip), the Clipper object removes the 'inner' vertices before clipping.
// When enabled the PreserveCollinear property prevents this default behavior to allow these inner vertices to appear in the solution.
2015-07-28 02:26:01 +03:00
bool PreserveCollinear () const { return m_PreserveCollinear ;};
2013-11-20 11:35:58 +01:00
void PreserveCollinear ( bool value ) { m_PreserveCollinear = value ;};
2013-07-16 20:09:53 +02:00
protected :
2013-11-20 11:35:58 +01:00
TEdge * AddBoundsToLML ( TEdge * e , bool IsClosed );
2017-03-02 20:44:43 +01:00
void PopLocalMinima ();
2013-07-16 20:09:53 +02:00
virtual void Reset ();
2013-12-24 12:40:46 +01:00
TEdge * ProcessBound ( TEdge * E , bool IsClockwise );
2013-11-20 11:35:58 +01:00
TEdge * DescendToMin ( TEdge *& E );
void AscendToMax ( TEdge *& E , bool Appending , bool IsClosed );
2014-11-08 12:05:27 +01:00
2017-03-01 14:27:08 +01:00
// Local minima (Y, left edge, right edge) sorted by ascending Y.
std :: vector < LocalMinimum > m_MinimaList ;
2014-11-08 12:05:27 +01:00
2017-03-01 14:27:08 +01:00
// True if the input polygons have abs values higher than loRange, but lower than hiRange.
// False if the input polygons have abs values lower or equal to loRange.
2013-07-16 20:09:53 +02:00
bool m_UseFullRange ;
2017-03-01 14:27:08 +01:00
// A vector of edges per each input path.
2017-03-02 20:44:43 +01:00
EdgeList m_edges ;
2017-03-01 14:27:08 +01:00
// Don't remove intermediate vertices of a collinear sequence of points.
2013-11-20 11:35:58 +01:00
bool m_PreserveCollinear ;
2017-03-01 14:27:08 +01:00
// Is any of the paths inserted by AddPath() or AddPaths() open?
2013-11-20 11:35:58 +01:00
bool m_HasOpenPaths ;
2013-07-16 20:09:53 +02:00
};
2013-11-20 11:35:58 +01:00
//------------------------------------------------------------------------------
2013-07-16 20:09:53 +02:00
class Clipper : public virtual ClipperBase
{
public :
2013-11-20 11:35:58 +01:00
Clipper ( int initOptions = 0 );
2017-03-02 20:44:43 +01:00
~ Clipper ();
2013-07-16 20:09:53 +02:00
bool Execute ( ClipType clipType ,
2015-02-15 16:10:04 +01:00
Paths & solution ,
2017-03-02 20:44:43 +01:00
PolyFillType fillType = pftEvenOdd );
2013-07-16 20:09:53 +02:00
bool Execute ( ClipType clipType ,
2015-02-15 16:10:04 +01:00
Paths & solution ,
PolyFillType subjFillType ,
PolyFillType clipFillType );
bool Execute ( ClipType clipType ,
PolyTree & polytree ,
2017-03-02 20:44:43 +01:00
PolyFillType fillType = pftEvenOdd );
2015-02-15 16:10:04 +01:00
bool Execute ( ClipType clipType ,
PolyTree & polytree ,
PolyFillType subjFillType ,
PolyFillType clipFillType );
2015-07-28 02:26:01 +03:00
bool ReverseSolution () const { return m_ReverseOutput ; };
2013-07-16 20:09:53 +02:00
void ReverseSolution ( bool value ) { m_ReverseOutput = value ;};
2015-07-28 02:26:01 +03:00
bool StrictlySimple () const { return m_StrictSimple ;};
2013-11-20 11:35:58 +01:00
void StrictlySimple ( bool value ) { m_StrictSimple = value ;};
//set the callback function for z value filling on intersections (otherwise Z is 0)
#ifdef use_xyz
2017-03-02 20:44:43 +01:00
void ZFillFunction ( ZFillCallback zFillFunc );
2013-11-20 11:35:58 +01:00
#endif
2013-07-16 20:09:53 +02:00
protected :
void Reset ();
virtual bool ExecuteInternal ();
private :
2017-03-02 20:44:43 +01:00
PolyOutList m_PolyOuts ;
JoinList m_Joins ;
JoinList m_GhostJoins ;
IntersectList m_IntersectList ;
2015-02-15 16:10:04 +01:00
ClipType m_ClipType ;
2017-03-01 14:27:08 +01:00
// A priority queue (a binary heap) of Y coordinates.
std :: priority_queue < cInt > m_Scanbeam ;
2017-03-02 20:44:43 +01:00
typedef std :: list < cInt > MaximaList ;
MaximaList m_Maxima ;
2013-07-16 20:09:53 +02:00
TEdge * m_ActiveEdges ;
TEdge * m_SortedEdges ;
PolyFillType m_ClipFillType ;
PolyFillType m_SubjFillType ;
bool m_ReverseOutput ;
2017-03-01 14:27:08 +01:00
// Does the result go to a PolyTree or Paths?
2013-07-16 20:09:53 +02:00
bool m_UsingPolyTree ;
2013-11-20 11:35:58 +01:00
bool m_StrictSimple ;
#ifdef use_xyz
2014-11-08 12:05:27 +01:00
ZFillCallback m_ZFill ; //custom callback
2013-11-20 11:35:58 +01:00
#endif
2015-07-28 02:26:01 +03:00
void SetWindingCount ( TEdge & edge ) const ;
2017-03-02 20:44:43 +01:00
bool IsEvenOddFillType ( const TEdge & edge ) const ;
bool IsEvenOddAltFillType ( const TEdge & edge ) const ;
cInt PopScanbeam ();
2013-11-20 11:35:58 +01:00
void InsertLocalMinimaIntoAEL ( const cInt botY );
void InsertEdgeIntoAEL ( TEdge * edge , TEdge * startEdge );
2013-07-16 20:09:53 +02:00
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 ;
2013-11-20 11:35:58 +01:00
bool IsTopHorz ( const cInt XPos );
2013-07-16 20:09:53 +02:00
void SwapPositionsInAEL ( TEdge * edge1 , TEdge * edge2 );
2013-11-20 11:35:58 +01:00
void DoMaxima ( TEdge * e );
2015-02-15 16:10:04 +01:00
void ProcessHorizontals ();
void ProcessHorizontal ( TEdge * horzEdge );
2013-07-16 20:09:53 +02:00
void AddLocalMaxPoly ( TEdge * e1 , TEdge * e2 , const IntPoint & pt );
2013-11-20 11:35:58 +01:00
OutPt * AddLocalMinPoly ( TEdge * e1 , TEdge * e2 , const IntPoint & pt );
2013-07-16 20:09:53 +02:00
OutRec * GetOutRec ( int idx );
2015-07-28 02:26:01 +03:00
void AppendPolygon ( TEdge * e1 , TEdge * e2 ) const ;
2014-05-23 23:58:43 +02:00
void IntersectEdges ( TEdge * e1 , TEdge * e2 , IntPoint & pt );
2013-07-16 20:09:53 +02:00
OutRec * CreateOutRec ();
2013-11-20 11:35:58 +01:00
OutPt * AddOutPt ( TEdge * e , const IntPoint & pt );
2015-02-15 16:10:04 +01:00
OutPt * GetLastOutPt ( TEdge * e );
2013-11-20 11:35:58 +01:00
void DisposeAllOutRecs ();
2017-03-02 20:44:43 +01:00
void DisposeOutRec ( PolyOutList :: size_type index );
2014-11-08 12:05:27 +01:00
bool ProcessIntersections ( const cInt topY );
void BuildIntersectList ( const cInt topY );
2017-03-02 20:44:43 +01:00
void ProcessIntersectList ();
2013-11-20 11:35:58 +01:00
void ProcessEdgesAtTopOfScanbeam ( const cInt topY );
void BuildResult ( Paths & polys );
2013-07-16 20:09:53 +02:00
void BuildResult2 ( PolyTree & polytree );
2015-07-28 02:26:01 +03:00
void SetHoleState ( TEdge * e , OutRec * outrec ) const ;
2017-03-02 20:44:43 +01:00
void DisposeIntersectNodes ();
2013-07-16 20:09:53 +02:00
bool FixupIntersectionOrder ();
void FixupOutPolygon ( OutRec & outrec );
2015-02-15 16:10:04 +01:00
void FixupOutPolyline ( OutRec & outrec );
2013-12-24 12:40:46 +01:00
bool FindOwnerFromSplitRecs ( OutRec & outRec , OutRec *& currOrfl );
2013-07-16 20:09:53 +02:00
void FixHoleLinkage ( OutRec & outrec );
2013-12-24 12:40:46 +01:00
bool JoinPoints ( Join * j , OutRec * outRec1 , OutRec * outRec2 );
2013-07-16 20:09:53 +02:00
void JoinCommonEdges ();
void DoSimplePolygons ();
2015-07-28 02:26:01 +03:00
void FixupFirstLefts1 ( OutRec * OldOutRec , OutRec * NewOutRec ) const ;
void FixupFirstLefts2 ( OutRec * OldOutRec , OutRec * NewOutRec ) const ;
2013-11-20 11:35:58 +01:00
#ifdef use_xyz
2014-05-23 23:58:43 +02:00
void SetZ ( IntPoint & pt , TEdge & e1 , TEdge & e2 );
2013-11-20 11:35:58 +01:00
#endif
2013-07-16 20:09:53 +02:00
};
//------------------------------------------------------------------------------
2013-12-24 12:40:46 +01:00
class ClipperOffset
{
public :
ClipperOffset ( double miterLimit = 2.0 , double roundPrecision = 0.25 );
2017-03-02 20:44:43 +01:00
~ ClipperOffset ();
2013-12-24 12:40:46 +01:00
void AddPath ( const Path & path , JoinType joinType , EndType endType );
void AddPaths ( const Paths & paths , JoinType joinType , EndType endType );
void Execute ( Paths & solution , double delta );
void Execute ( PolyTree & solution , double delta );
void Clear ();
double MiterLimit ;
double ArcTolerance ;
private :
Paths m_destPolys ;
Path m_srcPoly ;
Path m_destPoly ;
std :: vector < DoublePoint > m_normals ;
double m_delta , m_sinA , m_sin , m_cos ;
double m_miterLim , m_StepsPerRad ;
IntPoint m_lowest ;
PolyNode m_polyNodes ;
void FixOrientations ();
void DoOffset ( double delta );
void OffsetPoint ( int j , int & k , JoinType jointype );
void DoSquare ( int j , int k );
void DoMiter ( int j , int k , double r );
void DoRound ( int j , int k );
};
//------------------------------------------------------------------------------
2013-07-16 20:09:53 +02:00
class clipperException : public std :: exception
{
public :
clipperException ( const char * description ) : m_descr ( description ) {}
virtual ~ clipperException () throw () {}
virtual const char * what () const throw () { return m_descr . c_str ();}
private :
std :: string m_descr ;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp