clipper.h 15 KB
Newer Older
Your Name's avatar
Your Name committed
1
/*******************************************************************************
liucong's avatar
liucong committed
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 *                                                                              *
 * Author    :  Angus Johnson                                                   *
 * Version   :  6.4.2                                                           *
 * Date      :  27 February 2017                                                *
 * Website   :  http://www.angusj.com                                           *
 * Copyright :  Angus Johnson 2010-2017                                         *
 *                                                                              *
 * 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              *
 *                                                                              *
 *******************************************************************************/
Your Name's avatar
Your Name committed
33
34
35
36
37
38
39
40
41
42

#pragma once

#ifndef clipper_hpp
#define clipper_hpp

#define CLIPPER_VERSION "6.4.2"

// use_int32: When enabled 32bit ints are used instead of 64bit ints. This
// improve performance but coordinate values are limited to the range +/- 46340
liucong's avatar
liucong committed
43
// #define use_int32
Your Name's avatar
Your Name committed
44
45

// use_xyz: adds a Z member to IntPoint. Adds a minor cost to perfomance.
liucong's avatar
liucong committed
46
// #define use_xyz
Your Name's avatar
Your Name committed
47
48
49
50
51

// use_lines: Enables line clipping. Adds a very minor cost to performance.
#define use_lines

// use_deprecated: Enables temporary support for the obsolete functions
liucong's avatar
liucong committed
52
// #define use_deprecated
Your Name's avatar
Your Name committed
53
54
55
56
57
58
59
60
61
62
63

#include <cstdlib>
#include <cstring>
#include <functional>
#include <list>
#include <ostream>
#include <queue>
#include <set>
#include <stdexcept>
#include <vector>

liucong's avatar
liucong committed
64
65
namespace ClipperLib
{
Your Name's avatar
Your Name committed
66

liucong's avatar
liucong committed
67
68
69
70
71
72
73
74
75
76
77
78
enum ClipType
{
    ctIntersection,
    ctUnion,
    ctDifference,
    ctXor
};
enum PolyType
{
    ptSubject,
    ptClip
};
Your Name's avatar
Your Name committed
79
80
81
82
// 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
liucong's avatar
liucong committed
83
84
85
86
87
88
89
enum PolyFillType
{
    pftEvenOdd,
    pftNonZero,
    pftPositive,
    pftNegative
};
Your Name's avatar
Your Name committed
90
91
92
93
94
95
96
97
98
99
100
101
102
103

#ifdef use_int32
typedef int cInt;
static cInt const loRange = 0x7FFF;
static cInt const hiRange = 0x7FFF;
#else
typedef signed long long cInt;
static cInt const loRange = 0x3FFFFFFF;
static cInt const hiRange = 0x3FFFFFFFFFFFFFFFLL;
typedef signed long long long64; // used by Int128 class
typedef unsigned long long ulong64;

#endif

liucong's avatar
liucong committed
104
105
106
107
struct IntPoint
{
    cInt X;
    cInt Y;
Your Name's avatar
Your Name committed
108
#ifdef use_xyz
liucong's avatar
liucong committed
109
110
    cInt Z;
    IntPoint(cInt x = 0, cInt y = 0, cInt z = 0) : X(x), Y(y), Z(z){};
Your Name's avatar
Your Name committed
111
#else
liucong's avatar
liucong committed
112
    IntPoint(cInt x = 0, cInt y = 0) : X(x), Y(y){};
Your Name's avatar
Your Name committed
113
114
#endif

liucong's avatar
liucong committed
115
116
117
118
119
120
121
122
    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;
    }
Your Name's avatar
Your Name committed
123
124
125
126
127
128
};
//------------------------------------------------------------------------------

typedef std::vector<IntPoint> Path;
typedef std::vector<Path> Paths;

liucong's avatar
liucong committed
129
130
131
132
inline Path& operator<<(Path& poly, const IntPoint& p)
{
    poly.push_back(p);
    return poly;
Your Name's avatar
Your Name committed
133
}
liucong's avatar
liucong committed
134
135
136
137
inline Paths& operator<<(Paths& polys, const Path& p)
{
    polys.push_back(p);
    return polys;
Your Name's avatar
Your Name committed
138
139
}

liucong's avatar
liucong committed
140
141
142
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);
Your Name's avatar
Your Name committed
143

liucong's avatar
liucong committed
144
145
146
147
148
149
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) {}
Your Name's avatar
Your Name committed
150
151
152
153
};
//------------------------------------------------------------------------------

#ifdef use_xyz
liucong's avatar
liucong committed
154
155
typedef void (*ZFillCallback)(
    IntPoint& e1bot, IntPoint& e1top, IntPoint& e2bot, IntPoint& e2top, IntPoint& pt);
Your Name's avatar
Your Name committed
156
157
#endif

liucong's avatar
liucong committed
158
159
160
161
162
enum InitOptions
{
    ioReverseSolution   = 1,
    ioStrictlySimple    = 2,
    ioPreserveCollinear = 4
Your Name's avatar
Your Name committed
163
};
liucong's avatar
liucong committed
164
165
166
167
168
169
170
171
172
173
174
175
176
enum JoinType
{
    jtSquare,
    jtRound,
    jtMiter
};
enum EndType
{
    etClosedPolygon,
    etClosedLine,
    etOpenButt,
    etOpenSquare,
    etOpenRound
Your Name's avatar
Your Name committed
177
178
179
};

class PolyNode;
liucong's avatar
liucong committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
typedef std::vector<PolyNode*> PolyNodes;

class PolyNode
{
    public:
    PolyNode();
    virtual ~PolyNode(){};
    Path Contour;
    PolyNodes Childs;
    PolyNode* Parent;
    PolyNode* GetNext() const;
    bool IsHole() const;
    bool IsOpen() const;
    int ChildCount() const;

    private:
    // PolyNode& operator =(PolyNode& other);
    unsigned Index; // node index in Parent.Childs
    bool m_IsOpen;
    JoinType m_jointype;
    EndType m_endtype;
    PolyNode* GetNextSiblingUp() const;
    void AddChild(PolyNode& child);
    friend class Clipper; // to access Index
    friend class ClipperOffset;
Your Name's avatar
Your Name committed
205
206
};

liucong's avatar
liucong committed
207
208
209
210
211
212
213
214
215
216
217
218
class PolyTree : public PolyNode
{
    public:
    ~PolyTree() { Clear(); };
    PolyNode* GetFirst() const;
    void Clear();
    int Total() const;

    private:
    // PolyTree& operator =(PolyTree& other);
    PolyNodes AllNodes;
    friend class Clipper; // to access AllNodes
Your Name's avatar
Your Name committed
219
220
};

liucong's avatar
liucong committed
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
bool Orientation(const Path& poly);
double Area(const Path& poly);
int PointInPolygon(const IntPoint& pt, const Path& path);

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);

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);

void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed);
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed);
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution);

void PolyTreeToPaths(const PolyTree& polytree, Paths& paths);
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;
Your Name's avatar
Your Name committed
251
252
253
};

// enums that are used internally ...
liucong's avatar
liucong committed
254
255
256
257
258
enum EdgeSide
{
    esLeft  = 1,
    esRight = 2
};
Your Name's avatar
Your Name committed
259
260
261
262
263
264
265
266
267

// forward declarations (for stuff used internally) ...
struct TEdge;
struct IntersectNode;
struct LocalMinimum;
struct OutPt;
struct OutRec;
struct Join;

liucong's avatar
liucong committed
268
269
270
271
typedef std::vector<OutRec*> PolyOutList;
typedef std::vector<TEdge*> EdgeList;
typedef std::vector<Join*> JoinList;
typedef std::vector<IntersectNode*> IntersectList;
Your Name's avatar
Your Name committed
272
273
274
275
276
277

//------------------------------------------------------------------------------

// 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.
liucong's avatar
liucong committed
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
class ClipperBase
{
    public:
    ClipperBase();
    virtual ~ClipperBase();
    virtual bool AddPath(const Path& pg, PolyType PolyTyp, bool Closed);
    bool AddPaths(const Paths& ppg, PolyType PolyTyp, bool Closed);
    virtual void Clear();
    IntRect GetBounds();
    bool PreserveCollinear() { return m_PreserveCollinear; };
    void PreserveCollinear(bool value) { m_PreserveCollinear = value; };

    protected:
    void DisposeLocalMinimaList();
    TEdge* AddBoundsToLML(TEdge* e, bool IsClosed);
    virtual void Reset();
    TEdge* ProcessBound(TEdge* E, bool IsClockwise);
    void InsertScanbeam(const cInt Y);
    bool PopScanbeam(cInt& Y);
    bool LocalMinimaPending();
    bool PopLocalMinima(cInt Y, const LocalMinimum*& locMin);
    OutRec* CreateOutRec();
    void DisposeAllOutRecs();
    void DisposeOutRec(PolyOutList::size_type index);
    void SwapPositionsInAEL(TEdge* edge1, TEdge* edge2);
    void DeleteFromAEL(TEdge* e);
    void UpdateEdgeIntoAEL(TEdge*& e);

    typedef std::vector<LocalMinimum> MinimaList;
    MinimaList::iterator m_CurrentLM;
    MinimaList m_MinimaList;

    bool m_UseFullRange;
    EdgeList m_edges;
    bool m_PreserveCollinear;
    bool m_HasOpenPaths;
    PolyOutList m_PolyOuts;
    TEdge* m_ActiveEdges;

    typedef std::priority_queue<cInt> ScanbeamList;
    ScanbeamList m_Scanbeam;
Your Name's avatar
Your Name committed
319
320
321
};
//------------------------------------------------------------------------------

liucong's avatar
liucong committed
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
class Clipper : public virtual ClipperBase
{
    public:
    Clipper(int initOptions = 0);
    bool Execute(ClipType clipType, Paths& solution, PolyFillType fillType = pftEvenOdd);
    bool Execute(ClipType clipType,
                 Paths& solution,
                 PolyFillType subjFillType,
                 PolyFillType clipFillType);
    bool Execute(ClipType clipType, PolyTree& polytree, PolyFillType fillType = pftEvenOdd);
    bool Execute(ClipType clipType,
                 PolyTree& polytree,
                 PolyFillType subjFillType,
                 PolyFillType clipFillType);
    bool ReverseSolution() { return m_ReverseOutput; };
    void ReverseSolution(bool value) { m_ReverseOutput = value; };
    bool StrictlySimple() { return m_StrictSimple; };
    void StrictlySimple(bool value) { m_StrictSimple = value; };
Your Name's avatar
Your Name committed
340
341
342
// set the callback function for z value filling on intersections (otherwise Z
// is 0)
#ifdef use_xyz
liucong's avatar
liucong committed
343
    void ZFillFunction(ZFillCallback zFillFunc);
Your Name's avatar
Your Name committed
344
#endif
liucong's avatar
liucong committed
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
    protected:
    virtual bool ExecuteInternal();

    private:
    JoinList m_Joins;
    JoinList m_GhostJoins;
    IntersectList m_IntersectList;
    ClipType m_ClipType;
    typedef std::list<cInt> MaximaList;
    MaximaList m_Maxima;
    TEdge* m_SortedEdges;
    bool m_ExecuteLocked;
    PolyFillType m_ClipFillType;
    PolyFillType m_SubjFillType;
    bool m_ReverseOutput;
    bool m_UsingPolyTree;
    bool m_StrictSimple;
Your Name's avatar
Your Name committed
362
#ifdef use_xyz
liucong's avatar
liucong committed
363
    ZFillCallback m_ZFill; // custom callback
Your Name's avatar
Your Name committed
364
#endif
liucong's avatar
liucong committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
    void SetWindingCount(TEdge& edge);
    bool IsEvenOddFillType(const TEdge& edge) const;
    bool IsEvenOddAltFillType(const TEdge& edge) const;
    void InsertLocalMinimaIntoAEL(const cInt botY);
    void InsertEdgeIntoAEL(TEdge* edge, TEdge* startEdge);
    void AddEdgeToSEL(TEdge* edge);
    bool PopEdgeFromSEL(TEdge*& edge);
    void CopyAELToSEL();
    void DeleteFromSEL(TEdge* e);
    void SwapPositionsInSEL(TEdge* edge1, TEdge* edge2);
    bool IsContributing(const TEdge& edge) const;
    bool IsTopHorz(const cInt XPos);
    void DoMaxima(TEdge* e);
    void ProcessHorizontals();
    void ProcessHorizontal(TEdge* horzEdge);
    void AddLocalMaxPoly(TEdge* e1, TEdge* e2, const IntPoint& pt);
    OutPt* AddLocalMinPoly(TEdge* e1, TEdge* e2, const IntPoint& pt);
    OutRec* GetOutRec(int idx);
    void AppendPolygon(TEdge* e1, TEdge* e2);
    void IntersectEdges(TEdge* e1, TEdge* e2, IntPoint& pt);
    OutPt* AddOutPt(TEdge* e, const IntPoint& pt);
    OutPt* GetLastOutPt(TEdge* e);
    bool ProcessIntersections(const cInt topY);
    void BuildIntersectList(const cInt topY);
    void ProcessIntersectList();
    void ProcessEdgesAtTopOfScanbeam(const cInt topY);
    void BuildResult(Paths& polys);
    void BuildResult2(PolyTree& polytree);
    void SetHoleState(TEdge* e, OutRec* outrec);
    void DisposeIntersectNodes();
    bool FixupIntersectionOrder();
    void FixupOutPolygon(OutRec& outrec);
    void FixupOutPolyline(OutRec& outrec);
    bool IsHole(TEdge* e);
    bool FindOwnerFromSplitRecs(OutRec& outRec, OutRec*& currOrfl);
    void FixHoleLinkage(OutRec& outrec);
    void AddJoin(OutPt* op1, OutPt* op2, const IntPoint offPt);
    void ClearJoins();
    void ClearGhostJoins();
    void AddGhostJoin(OutPt* op, const IntPoint offPt);
    bool JoinPoints(Join* j, OutRec* outRec1, OutRec* outRec2);
    void JoinCommonEdges();
    void DoSimplePolygons();
    void FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec);
    void FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec);
    void FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec);
Your Name's avatar
Your Name committed
411
#ifdef use_xyz
liucong's avatar
liucong committed
412
    void SetZ(IntPoint& pt, TEdge& e1, TEdge& e2);
Your Name's avatar
Your Name committed
413
414
415
416
#endif
};
//------------------------------------------------------------------------------

liucong's avatar
liucong committed
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
class ClipperOffset
{
    public:
    ClipperOffset(double miterLimit = 2.0, double roundPrecision = 0.25);
    ~ClipperOffset();
    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);
Your Name's avatar
Your Name committed
446
447
448
};
//------------------------------------------------------------------------------

liucong's avatar
liucong committed
449
450
451
452
453
454
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(); }
Your Name's avatar
Your Name committed
455

liucong's avatar
liucong committed
456
457
    private:
    std::string m_descr;
Your Name's avatar
Your Name committed
458
459
460
};
//------------------------------------------------------------------------------

liucong's avatar
liucong committed
461
} // namespace ClipperLib
Your Name's avatar
Your Name committed
462
463

#endif // clipper_hpp