Coverage Report

Created: 2025-08-28 06:38

/src/assimp/contrib/clipper/clipper.cpp
Line
Count
Source (jump to first uncovered line)
1
/*******************************************************************************
2
*                                                                              *
3
* Author    :  Angus Johnson                                                   *
4
* Version   :  6.4.2                                                           *
5
* Date      :  27 February 2017                                                *
6
* Website   :  http://www.angusj.com                                           *
7
* Copyright :  Angus Johnson 2010-2017                                         *
8
*                                                                              *
9
* License:                                                                     *
10
* Use, modification & distribution is subject to Boost Software License Ver 1. *
11
* http://www.boost.org/LICENSE_1_0.txt                                         *
12
*                                                                              *
13
* Attributions:                                                                *
14
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
15
* "A generic solution to polygon clipping"                                     *
16
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63.             *
17
* http://portal.acm.org/citation.cfm?id=129906                                 *
18
*                                                                              *
19
* Computer graphics and geometric modeling: implementation and algorithms      *
20
* By Max K. Agoston                                                            *
21
* Springer; 1 edition (January 4, 2005)                                        *
22
* http://books.google.com/books?q=vatti+clipping+agoston                       *
23
*                                                                              *
24
* See also:                                                                    *
25
* "Polygon Offsetting by Computing Winding Numbers"                            *
26
* Paper no. DETC2005-85513 pp. 565-575                                         *
27
* ASME 2005 International Design Engineering Technical Conferences             *
28
* and Computers and Information in Engineering Conference (IDETC/CIE2005)      *
29
* September 24-28, 2005 , Long Beach, California, USA                          *
30
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf              *
31
*                                                                              *
32
*******************************************************************************/
33
34
/*******************************************************************************
35
*                                                                              *
36
* This is a translation of the Delphi Clipper library and the naming style     *
37
* used has retained a Delphi flavour.                                          *
38
*                                                                              *
39
*******************************************************************************/
40
41
#include "clipper.hpp"
42
#include <cmath>
43
#include <vector>
44
#include <algorithm>
45
#include <stdexcept>
46
#include <cstring>
47
#include <cstdlib>
48
#include <ostream>
49
#include <functional>
50
51
namespace ClipperLib {
52
53
static double const pi = 3.141592653589793238;
54
static double const two_pi = pi *2;
55
static double const def_arc_tolerance = 0.25;
56
57
enum Direction { dRightToLeft, dLeftToRight };
58
59
static int const Unassigned = -1;  //edge not currently 'owning' a solution
60
static int const Skip = -2;        //edge that would otherwise close a path
61
62
0
#define HORIZONTAL (-1.0E+40)
63
0
#define TOLERANCE (1.0e-20)
64
0
#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
65
66
struct TEdge {
67
  IntPoint Bot;
68
  IntPoint Curr; //current (updated for every new scanbeam)
69
  IntPoint Top;
70
  double Dx;
71
  PolyType PolyTyp;
72
  EdgeSide Side; //side only refers to current side of solution poly
73
  int WindDelta; //1 or -1 depending on winding direction
74
  int WindCnt;
75
  int WindCnt2; //winding count of the opposite polytype
76
  int OutIdx;
77
  TEdge *Next;
78
  TEdge *Prev;
79
  TEdge *NextInLML;
80
  TEdge *NextInAEL;
81
  TEdge *PrevInAEL;
82
  TEdge *NextInSEL;
83
  TEdge *PrevInSEL;
84
};
85
86
struct IntersectNode {
87
  TEdge          *Edge1;
88
  TEdge          *Edge2;
89
  IntPoint        Pt;
90
};
91
92
struct LocalMinimum {
93
  cInt          Y;
94
  TEdge        *LeftBound;
95
  TEdge        *RightBound;
96
};
97
98
struct OutPt;
99
100
//OutRec: contains a path in the clipping solution. Edges in the AEL will
101
//carry a pointer to an OutRec when they are part of the clipping solution.
102
struct OutRec {
103
  int       Idx;
104
  bool      IsHole;
105
  bool      IsOpen;
106
  OutRec   *FirstLeft;  //see comments in clipper.pas
107
  PolyNode *PolyNd;
108
  OutPt    *Pts;
109
  OutPt    *BottomPt;
110
};
111
112
struct OutPt {
113
  int       Idx;
114
  IntPoint  Pt;
115
  OutPt    *Next;
116
  OutPt    *Prev;
117
};
118
119
struct Join {
120
  OutPt    *OutPt1;
121
  OutPt    *OutPt2;
122
  IntPoint  OffPt;
123
};
124
125
struct LocMinSorter
126
{
127
  inline bool operator()(const LocalMinimum& locMin1, const LocalMinimum& locMin2)
128
0
  {
129
0
    return locMin2.Y < locMin1.Y;
130
0
  }
131
};
132
133
//------------------------------------------------------------------------------
134
//------------------------------------------------------------------------------
135
136
inline cInt Round(double val)
137
0
{
138
0
  if ((val < 0)) return static_cast<cInt>(val - 0.5);
139
0
  else return static_cast<cInt>(val + 0.5);
140
0
}
141
//------------------------------------------------------------------------------
142
143
inline cInt Abs(cInt val)
144
0
{
145
0
  return val < 0 ? -val : val;
146
0
}
147
148
//------------------------------------------------------------------------------
149
// PolyTree methods ...
150
//------------------------------------------------------------------------------
151
152
void PolyTree::Clear()
153
0
{
154
0
    for (PolyNodes::size_type i = 0; i < AllNodes.size(); ++i)
155
0
      delete AllNodes[i];
156
0
    AllNodes.resize(0);
157
0
    Childs.resize(0);
158
0
}
159
//------------------------------------------------------------------------------
160
161
PolyNode* PolyTree::GetFirst() const
162
0
{
163
0
  if (!Childs.empty())
164
0
      return Childs[0];
165
0
  else
166
0
      return 0;
167
0
}
168
//------------------------------------------------------------------------------
169
170
int PolyTree::Total() const
171
0
{
172
0
  int result = (int)AllNodes.size();
173
  //with negative offsets, ignore the hidden outer polygon ...
174
0
  if (result > 0 && Childs[0] != AllNodes[0]) result--;
175
0
  return result;
176
0
}
177
178
//------------------------------------------------------------------------------
179
// PolyNode methods ...
180
//------------------------------------------------------------------------------
181
182
0
PolyNode::PolyNode(): Parent(0), Index(0), m_IsOpen(false)
183
0
{
184
0
}
185
//------------------------------------------------------------------------------
186
187
int PolyNode::ChildCount() const
188
0
{
189
0
  return (int)Childs.size();
190
0
}
191
//------------------------------------------------------------------------------
192
193
void PolyNode::AddChild(PolyNode& child)
194
0
{
195
0
  unsigned cnt = (unsigned)Childs.size();
196
0
  Childs.push_back(&child);
197
0
  child.Parent = this;
198
0
  child.Index = cnt;
199
0
}
200
//------------------------------------------------------------------------------
201
202
PolyNode* PolyNode::GetNext() const
203
0
{
204
0
  if (!Childs.empty())
205
0
      return Childs[0];
206
0
  else
207
0
      return GetNextSiblingUp();
208
0
}
209
//------------------------------------------------------------------------------
210
211
PolyNode* PolyNode::GetNextSiblingUp() const
212
0
{
213
0
  if (!Parent) //protects against PolyTree.GetNextSiblingUp()
214
0
      return 0;
215
0
  else if (Index == Parent->Childs.size() - 1)
216
0
      return Parent->GetNextSiblingUp();
217
0
  else
218
0
      return Parent->Childs[Index + 1];
219
0
}
220
//------------------------------------------------------------------------------
221
222
bool PolyNode::IsHole() const
223
0
{
224
0
  bool result = true;
225
0
  PolyNode* node = Parent;
226
0
  while (node)
227
0
  {
228
0
      result = !result;
229
0
      node = node->Parent;
230
0
  }
231
0
  return result;
232
0
}
233
//------------------------------------------------------------------------------
234
235
bool PolyNode::IsOpen() const
236
0
{
237
0
  return m_IsOpen;
238
0
}
239
//------------------------------------------------------------------------------
240
241
#ifndef use_int32
242
243
//------------------------------------------------------------------------------
244
// Int128 class (enables safe math on signed 64bit integers)
245
// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1
246
//    Int128 val2((long64)9223372036854775807);
247
//    Int128 val3 = val1 * val2;
248
//    val3.AsString => "85070591730234615847396907784232501249" (8.5e+37)
249
//------------------------------------------------------------------------------
250
251
class Int128
252
{
253
  public:
254
    ulong64 lo;
255
    long64 hi;
256
257
    Int128(long64 _lo = 0)
258
0
    {
259
0
      lo = (ulong64)_lo;
260
0
      if (_lo < 0)  hi = -1; else hi = 0;
261
0
    }
262
263
264
0
    Int128(const Int128 &val): lo(val.lo), hi(val.hi){}
265
266
0
    Int128(const long64& _hi, const ulong64& _lo): lo(_lo), hi(_hi){}
267
268
  Int128& operator = (const Int128 &val)
269
0
    {
270
0
      lo = val.lo;
271
0
      hi = val.hi;
272
0
      return *this;
273
0
    }
274
275
    Int128& operator = (const long64 &val)
276
0
    {
277
0
      lo = (ulong64)val;
278
0
      if (val < 0) hi = -1; else hi = 0;
279
0
      return *this;
280
0
    }
281
282
    bool operator == (const Int128 &val) const
283
0
      {return (hi == val.hi && lo == val.lo);}
284
285
    bool operator != (const Int128 &val) const
286
0
      { return !(*this == val);}
287
288
    bool operator > (const Int128 &val) const
289
0
    {
290
0
      if (hi != val.hi)
291
0
        return hi > val.hi;
292
0
      else
293
0
        return lo > val.lo;
294
0
    }
295
296
    bool operator < (const Int128 &val) const
297
0
    {
298
0
      if (hi != val.hi)
299
0
        return hi < val.hi;
300
0
      else
301
0
        return lo < val.lo;
302
0
    }
303
304
    bool operator >= (const Int128 &val) const
305
0
      { return !(*this < val);}
306
307
    bool operator <= (const Int128 &val) const
308
0
      { return !(*this > val);}
309
310
    Int128& operator += (const Int128 &rhs)
311
0
    {
312
0
      hi += rhs.hi;
313
0
      lo += rhs.lo;
314
0
      if (lo < rhs.lo) hi++;
315
0
      return *this;
316
0
    }
317
318
    Int128 operator + (const Int128 &rhs) const
319
0
    {
320
0
      Int128 result(*this);
321
0
      result+= rhs;
322
0
      return result;
323
0
    }
324
325
    Int128& operator -= (const Int128 &rhs)
326
0
    {
327
0
      *this += -rhs;
328
0
      return *this;
329
0
    }
330
331
    Int128 operator - (const Int128 &rhs) const
332
0
    {
333
0
      Int128 result(*this);
334
0
      result -= rhs;
335
0
      return result;
336
0
    }
337
338
    Int128 operator-() const //unary negation
339
0
    {
340
0
      if (lo == 0)
341
0
        return Int128(-hi, 0);
342
0
      else
343
0
        return Int128(~hi, ~lo + 1);
344
0
    }
345
346
    operator double() const
347
0
    {
348
0
      const double shift64 = 18446744073709551616.0; //2^64
349
0
      if (hi < 0)
350
0
      {
351
0
        if (lo == 0) return (double)hi * shift64;
352
0
        else return -(double)(~lo + ~hi * shift64);
353
0
      }
354
0
      else
355
0
        return (double)(lo + hi * shift64);
356
0
    }
357
358
};
359
//------------------------------------------------------------------------------
360
361
Int128 Int128Mul (long64 lhs, long64 rhs)
362
0
{
363
0
  bool negate = (lhs < 0) != (rhs < 0);
364
365
0
  if (lhs < 0) lhs = -lhs;
366
0
  ulong64 int1Hi = ulong64(lhs) >> 32;
367
0
  ulong64 int1Lo = ulong64(lhs & 0xFFFFFFFF);
368
369
0
  if (rhs < 0) rhs = -rhs;
370
0
  ulong64 int2Hi = ulong64(rhs) >> 32;
371
0
  ulong64 int2Lo = ulong64(rhs & 0xFFFFFFFF);
372
373
  //nb: see comments in clipper.pas
374
0
  ulong64 a = int1Hi * int2Hi;
375
0
  ulong64 b = int1Lo * int2Lo;
376
0
  ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
377
378
0
  Int128 tmp;
379
0
  tmp.hi = long64(a + (c >> 32));
380
0
  tmp.lo = long64(c << 32);
381
0
  tmp.lo += long64(b);
382
0
  if (tmp.lo < b) tmp.hi++;
383
0
  if (negate) tmp = -tmp;
384
0
  return tmp;
385
0
};
386
#endif
387
388
//------------------------------------------------------------------------------
389
// Miscellaneous global functions
390
//------------------------------------------------------------------------------
391
392
bool Orientation(const Path &poly)
393
0
{
394
0
    return Area(poly) >= 0;
395
0
}
396
//------------------------------------------------------------------------------
397
398
double Area(const Path &poly)
399
0
{
400
0
  int size = (int)poly.size();
401
0
  if (size < 3) return 0;
402
403
0
  double a = 0;
404
0
  for (int i = 0, j = size -1; i < size; ++i)
405
0
  {
406
0
    a += ((double)poly[j].X + poly[i].X) * ((double)poly[j].Y - poly[i].Y);
407
0
    j = i;
408
0
  }
409
0
  return -a * 0.5;
410
0
}
411
//------------------------------------------------------------------------------
412
413
double Area(const OutPt *op)
414
0
{
415
0
  const OutPt *startOp = op;
416
0
  if (!op) return 0;
417
0
  double a = 0;
418
0
  do {
419
0
    a +=  (double)(op->Prev->Pt.X + op->Pt.X) * (double)(op->Prev->Pt.Y - op->Pt.Y);
420
0
    op = op->Next;
421
0
  } while (op != startOp);
422
0
  return a * 0.5;
423
0
}
424
//------------------------------------------------------------------------------
425
426
double Area(const OutRec &outRec)
427
0
{
428
0
  return Area(outRec.Pts);
429
0
}
430
//------------------------------------------------------------------------------
431
432
bool PointIsVertex(const IntPoint &Pt, OutPt *pp)
433
0
{
434
0
  OutPt *pp2 = pp;
435
0
  do
436
0
  {
437
0
    if (pp2->Pt == Pt) return true;
438
0
    pp2 = pp2->Next;
439
0
  }
440
0
  while (pp2 != pp);
441
0
  return false;
442
0
}
443
//------------------------------------------------------------------------------
444
445
//See "The Point in Polygon Problem for Arbitrary Polygons" by Hormann & Agathos
446
//http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88.5498&rep=rep1&type=pdf
447
int PointInPolygon(const IntPoint &pt, const Path &path)
448
0
{
449
  //returns 0 if false, +1 if true, -1 if pt ON polygon boundary
450
0
  int result = 0;
451
0
  size_t cnt = path.size();
452
0
  if (cnt < 3) return 0;
453
0
  IntPoint ip = path[0];
454
0
  for(size_t i = 1; i <= cnt; ++i)
455
0
  {
456
0
    IntPoint ipNext = (i == cnt ? path[0] : path[i]);
457
0
    if (ipNext.Y == pt.Y)
458
0
    {
459
0
        if ((ipNext.X == pt.X) || (ip.Y == pt.Y &&
460
0
          ((ipNext.X > pt.X) == (ip.X < pt.X)))) return -1;
461
0
    }
462
0
    if ((ip.Y < pt.Y) != (ipNext.Y < pt.Y))
463
0
    {
464
0
      if (ip.X >= pt.X)
465
0
      {
466
0
        if (ipNext.X > pt.X) result = 1 - result;
467
0
        else
468
0
        {
469
0
          double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
470
0
            (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
471
0
          if (!d) return -1;
472
0
          if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
473
0
        }
474
0
      } else
475
0
      {
476
0
        if (ipNext.X > pt.X)
477
0
        {
478
0
          double d = (double)(ip.X - pt.X) * (ipNext.Y - pt.Y) -
479
0
            (double)(ipNext.X - pt.X) * (ip.Y - pt.Y);
480
0
          if (!d) return -1;
481
0
          if ((d > 0) == (ipNext.Y > ip.Y)) result = 1 - result;
482
0
        }
483
0
      }
484
0
    }
485
0
    ip = ipNext;
486
0
  }
487
0
  return result;
488
0
}
489
//------------------------------------------------------------------------------
490
491
int PointInPolygon (const IntPoint &pt, OutPt *op)
492
0
{
493
  //returns 0 if false, +1 if true, -1 if pt ON polygon boundary
494
0
  int result = 0;
495
0
  OutPt* startOp = op;
496
0
  for(;;)
497
0
  {
498
0
    if (op->Next->Pt.Y == pt.Y)
499
0
    {
500
0
        if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y &&
501
0
          ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X)))) return -1;
502
0
    }
503
0
    if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y))
504
0
    {
505
0
      if (op->Pt.X >= pt.X)
506
0
      {
507
0
        if (op->Next->Pt.X > pt.X) result = 1 - result;
508
0
        else
509
0
        {
510
0
          double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
511
0
            (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
512
0
          if (!d) return -1;
513
0
          if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
514
0
        }
515
0
      } else
516
0
      {
517
0
        if (op->Next->Pt.X > pt.X)
518
0
        {
519
0
          double d = (double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
520
0
            (double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
521
0
          if (!d) return -1;
522
0
          if ((d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
523
0
        }
524
0
      }
525
0
    }
526
0
    op = op->Next;
527
0
    if (startOp == op) break;
528
0
  }
529
0
  return result;
530
0
}
531
//------------------------------------------------------------------------------
532
533
bool Poly2ContainsPoly1(OutPt *OutPt1, OutPt *OutPt2)
534
0
{
535
0
  OutPt* op = OutPt1;
536
0
  do
537
0
  {
538
    //nb: PointInPolygon returns 0 if false, +1 if true, -1 if pt on polygon
539
0
    int res = PointInPolygon(op->Pt, OutPt2);
540
0
    if (res >= 0) return res > 0;
541
0
    op = op->Next;
542
0
  }
543
0
  while (op != OutPt1);
544
0
  return true;
545
0
}
546
//----------------------------------------------------------------------
547
548
bool SlopesEqual(const TEdge &e1, const TEdge &e2, bool UseFullInt64Range)
549
0
{
550
0
#ifndef use_int32
551
0
  if (UseFullInt64Range)
552
0
    return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
553
0
    Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
554
0
  else
555
0
#endif
556
0
    return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
557
0
    (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
558
0
}
559
//------------------------------------------------------------------------------
560
561
bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
562
  const IntPoint pt3, bool UseFullInt64Range)
563
0
{
564
0
#ifndef use_int32
565
0
  if (UseFullInt64Range)
566
0
    return Int128Mul(pt1.Y-pt2.Y, pt2.X-pt3.X) == Int128Mul(pt1.X-pt2.X, pt2.Y-pt3.Y);
567
0
  else
568
0
#endif
569
0
    return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
570
0
}
571
//------------------------------------------------------------------------------
572
573
bool SlopesEqual(const IntPoint pt1, const IntPoint pt2,
574
  const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range)
575
0
{
576
0
#ifndef use_int32
577
0
  if (UseFullInt64Range)
578
0
    return Int128Mul(pt1.Y-pt2.Y, pt3.X-pt4.X) == Int128Mul(pt1.X-pt2.X, pt3.Y-pt4.Y);
579
0
  else
580
0
#endif
581
0
    return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y);
582
0
}
583
//------------------------------------------------------------------------------
584
585
inline bool IsHorizontal(TEdge &e)
586
0
{
587
0
  return e.Dx == HORIZONTAL;
588
0
}
589
//------------------------------------------------------------------------------
590
591
inline double GetDx(const IntPoint pt1, const IntPoint pt2)
592
0
{
593
0
  return (pt1.Y == pt2.Y) ?
594
0
    HORIZONTAL : (double)(pt2.X - pt1.X) / (pt2.Y - pt1.Y);
595
0
}
596
//---------------------------------------------------------------------------
597
598
inline void SetDx(TEdge &e)
599
0
{
600
0
  cInt dy  = (e.Top.Y - e.Bot.Y);
601
0
  if (dy == 0) e.Dx = HORIZONTAL;
602
0
  else e.Dx = (double)(e.Top.X - e.Bot.X) / dy;
603
0
}
604
//---------------------------------------------------------------------------
605
606
inline void SwapSides(TEdge &Edge1, TEdge &Edge2)
607
0
{
608
0
  EdgeSide Side =  Edge1.Side;
609
0
  Edge1.Side = Edge2.Side;
610
0
  Edge2.Side = Side;
611
0
}
612
//------------------------------------------------------------------------------
613
614
inline void SwapPolyIndexes(TEdge &Edge1, TEdge &Edge2)
615
0
{
616
0
  int OutIdx =  Edge1.OutIdx;
617
0
  Edge1.OutIdx = Edge2.OutIdx;
618
0
  Edge2.OutIdx = OutIdx;
619
0
}
620
//------------------------------------------------------------------------------
621
622
inline cInt TopX(TEdge &edge, const cInt currentY)
623
0
{
624
0
  return ( currentY == edge.Top.Y ) ?
625
0
    edge.Top.X : edge.Bot.X + Round(edge.Dx *(currentY - edge.Bot.Y));
626
0
}
627
//------------------------------------------------------------------------------
628
629
void IntersectPoint(TEdge &Edge1, TEdge &Edge2, IntPoint &ip)
630
0
{
631
#ifdef use_xyz
632
  ip.Z = 0;
633
#endif
634
635
0
  double b1, b2;
636
0
  if (Edge1.Dx == Edge2.Dx)
637
0
  {
638
0
    ip.Y = Edge1.Curr.Y;
639
0
    ip.X = TopX(Edge1, ip.Y);
640
0
    return;
641
0
  }
642
0
  else if (Edge1.Dx == 0)
643
0
  {
644
0
    ip.X = Edge1.Bot.X;
645
0
    if (IsHorizontal(Edge2))
646
0
      ip.Y = Edge2.Bot.Y;
647
0
    else
648
0
    {
649
0
      b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx);
650
0
      ip.Y = Round(ip.X / Edge2.Dx + b2);
651
0
    }
652
0
  }
653
0
  else if (Edge2.Dx == 0)
654
0
  {
655
0
    ip.X = Edge2.Bot.X;
656
0
    if (IsHorizontal(Edge1))
657
0
      ip.Y = Edge1.Bot.Y;
658
0
    else
659
0
    {
660
0
      b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx);
661
0
      ip.Y = Round(ip.X / Edge1.Dx + b1);
662
0
    }
663
0
  }
664
0
  else
665
0
  {
666
0
    b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
667
0
    b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
668
0
    double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
669
0
    ip.Y = Round(q);
670
0
    if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
671
0
      ip.X = Round(Edge1.Dx * q + b1);
672
0
    else
673
0
      ip.X = Round(Edge2.Dx * q + b2);
674
0
  }
675
676
0
  if (ip.Y < Edge1.Top.Y || ip.Y < Edge2.Top.Y)
677
0
  {
678
0
    if (Edge1.Top.Y > Edge2.Top.Y)
679
0
      ip.Y = Edge1.Top.Y;
680
0
    else
681
0
      ip.Y = Edge2.Top.Y;
682
0
    if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
683
0
      ip.X = TopX(Edge1, ip.Y);
684
0
    else
685
0
      ip.X = TopX(Edge2, ip.Y);
686
0
  }
687
  //finally, don't allow 'ip' to be BELOW curr.Y (ie bottom of scanbeam) ...
688
0
  if (ip.Y > Edge1.Curr.Y)
689
0
  {
690
0
    ip.Y = Edge1.Curr.Y;
691
    //use the more vertical edge to derive X ...
692
0
    if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
693
0
      ip.X = TopX(Edge2, ip.Y); else
694
0
      ip.X = TopX(Edge1, ip.Y);
695
0
  }
696
0
}
697
//------------------------------------------------------------------------------
698
699
void ReversePolyPtLinks(OutPt *pp)
700
0
{
701
0
  if (!pp) return;
702
0
  OutPt *pp1, *pp2;
703
0
  pp1 = pp;
704
0
  do {
705
0
  pp2 = pp1->Next;
706
0
  pp1->Next = pp1->Prev;
707
0
  pp1->Prev = pp2;
708
0
  pp1 = pp2;
709
0
  } while( pp1 != pp );
710
0
}
711
//------------------------------------------------------------------------------
712
713
void DisposeOutPts(OutPt*& pp)
714
0
{
715
0
  if (pp == 0) return;
716
0
    pp->Prev->Next = 0;
717
0
  while( pp )
718
0
  {
719
0
    OutPt *tmpPp = pp;
720
0
    pp = pp->Next;
721
0
    delete tmpPp;
722
0
  }
723
0
}
724
//------------------------------------------------------------------------------
725
726
inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev, const IntPoint& Pt)
727
0
{
728
0
  *e = {};
729
  //std::memset(e, 0, sizeof(TEdge));
730
0
  e->Next = eNext;
731
0
  e->Prev = ePrev;
732
0
  e->Curr = Pt;
733
0
  e->OutIdx = Unassigned;
734
0
}
735
//------------------------------------------------------------------------------
736
737
void InitEdge2(TEdge& e, PolyType Pt)
738
0
{
739
0
  if (e.Curr.Y >= e.Next->Curr.Y)
740
0
  {
741
0
    e.Bot = e.Curr;
742
0
    e.Top = e.Next->Curr;
743
0
  } else
744
0
  {
745
0
    e.Top = e.Curr;
746
0
    e.Bot = e.Next->Curr;
747
0
  }
748
0
  SetDx(e);
749
0
  e.PolyTyp = Pt;
750
0
}
751
//------------------------------------------------------------------------------
752
753
TEdge* RemoveEdge(TEdge* e)
754
0
{
755
  //removes e from double_linked_list (but without removing from memory)
756
0
  e->Prev->Next = e->Next;
757
0
  e->Next->Prev = e->Prev;
758
0
  TEdge* result = e->Next;
759
0
  e->Prev = 0; //flag as removed (see ClipperBase.Clear)
760
0
  return result;
761
0
}
762
//------------------------------------------------------------------------------
763
764
inline void ReverseHorizontal(TEdge &e)
765
0
{
766
  //swap horizontal edges' Top and Bottom x's so they follow the natural
767
  //progression of the bounds - ie so their xbots will align with the
768
  //adjoining lower edge. [Helpful in the ProcessHorizontal() method.]
769
0
  std::swap(e.Top.X, e.Bot.X);
770
#ifdef use_xyz
771
  std::swap(e.Top.Z, e.Bot.Z);
772
#endif
773
0
}
774
//------------------------------------------------------------------------------
775
776
void SwapPoints(IntPoint &pt1, IntPoint &pt2)
777
0
{
778
0
  IntPoint tmp = pt1;
779
0
  pt1 = pt2;
780
0
  pt2 = tmp;
781
0
}
782
//------------------------------------------------------------------------------
783
784
bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a,
785
  IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
786
0
{
787
  //precondition: segments are Collinear.
788
0
  if (Abs(pt1a.X - pt1b.X) > Abs(pt1a.Y - pt1b.Y))
789
0
  {
790
0
    if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b);
791
0
    if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b);
792
0
    if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a;
793
0
    if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b;
794
0
    return pt1.X < pt2.X;
795
0
  } else
796
0
  {
797
0
    if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b);
798
0
    if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b);
799
0
    if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a;
800
0
    if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b;
801
0
    return pt1.Y > pt2.Y;
802
0
  }
803
0
}
804
//------------------------------------------------------------------------------
805
806
bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2)
807
0
{
808
0
  OutPt *p = btmPt1->Prev;
809
0
  while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev;
810
0
  double dx1p = std::fabs(GetDx(btmPt1->Pt, p->Pt));
811
0
  p = btmPt1->Next;
812
0
  while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next;
813
0
  double dx1n = std::fabs(GetDx(btmPt1->Pt, p->Pt));
814
815
0
  p = btmPt2->Prev;
816
0
  while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev;
817
0
  double dx2p = std::fabs(GetDx(btmPt2->Pt, p->Pt));
818
0
  p = btmPt2->Next;
819
0
  while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next;
820
0
  double dx2n = std::fabs(GetDx(btmPt2->Pt, p->Pt));
821
822
0
  if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
823
0
    std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
824
0
      return Area(btmPt1) > 0; //if otherwise identical use orientation
825
0
  else
826
0
    return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
827
0
}
828
//------------------------------------------------------------------------------
829
830
OutPt* GetBottomPt(OutPt *pp)
831
0
{
832
0
  OutPt* dups = 0;
833
0
  OutPt* p = pp->Next;
834
0
  while (p != pp)
835
0
  {
836
0
    if (p->Pt.Y > pp->Pt.Y)
837
0
    {
838
0
      pp = p;
839
0
      dups = 0;
840
0
    }
841
0
    else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X)
842
0
    {
843
0
      if (p->Pt.X < pp->Pt.X)
844
0
      {
845
0
        dups = 0;
846
0
        pp = p;
847
0
      } else
848
0
      {
849
0
        if (p->Next != pp && p->Prev != pp) dups = p;
850
0
      }
851
0
    }
852
0
    p = p->Next;
853
0
  }
854
0
  if (dups)
855
0
  {
856
    //there appears to be at least 2 vertices at BottomPt so ...
857
0
    while (dups != p)
858
0
    {
859
0
      if (!FirstIsBottomPt(p, dups)) pp = dups;
860
0
      dups = dups->Next;
861
0
      while (dups->Pt != pp->Pt) dups = dups->Next;
862
0
    }
863
0
  }
864
0
  return pp;
865
0
}
866
//------------------------------------------------------------------------------
867
868
bool Pt2IsBetweenPt1AndPt3(const IntPoint pt1,
869
  const IntPoint pt2, const IntPoint pt3)
870
0
{
871
0
  if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2))
872
0
    return false;
873
0
  else if (pt1.X != pt3.X)
874
0
    return (pt2.X > pt1.X) == (pt2.X < pt3.X);
875
0
  else
876
0
    return (pt2.Y > pt1.Y) == (pt2.Y < pt3.Y);
877
0
}
878
//------------------------------------------------------------------------------
879
880
bool HorzSegmentsOverlap(cInt seg1a, cInt seg1b, cInt seg2a, cInt seg2b)
881
0
{
882
0
  if (seg1a > seg1b) std::swap(seg1a, seg1b);
883
0
  if (seg2a > seg2b) std::swap(seg2a, seg2b);
884
0
  return (seg1a < seg2b) && (seg2a < seg1b);
885
0
}
886
887
//------------------------------------------------------------------------------
888
// ClipperBase class methods ...
889
//------------------------------------------------------------------------------
890
891
ClipperBase::ClipperBase() //constructor
892
0
{
893
0
  m_CurrentLM = m_MinimaList.begin(); //begin() == end() here
894
0
  m_UseFullRange = false;
895
0
}
896
//------------------------------------------------------------------------------
897
898
ClipperBase::~ClipperBase() //destructor
899
0
{
900
0
  Clear();
901
0
}
902
//------------------------------------------------------------------------------
903
904
void RangeTest(const IntPoint& Pt, bool& useFullRange)
905
0
{
906
0
  if (useFullRange)
907
0
  {
908
0
    if (Pt.X > hiRange || Pt.Y > hiRange || -Pt.X > hiRange || -Pt.Y > hiRange)
909
0
      throw clipperException("Coordinate outside allowed range");
910
0
  }
911
0
  else if (Pt.X > loRange|| Pt.Y > loRange || -Pt.X > loRange || -Pt.Y > loRange)
912
0
  {
913
0
    useFullRange = true;
914
0
    RangeTest(Pt, useFullRange);
915
0
  }
916
0
}
917
//------------------------------------------------------------------------------
918
919
TEdge* FindNextLocMin(TEdge* E)
920
0
{
921
0
  for (;;)
922
0
  {
923
0
    while (E->Bot != E->Prev->Bot || E->Curr == E->Top) E = E->Next;
924
0
    if (!IsHorizontal(*E) && !IsHorizontal(*E->Prev)) break;
925
0
    while (IsHorizontal(*E->Prev)) E = E->Prev;
926
0
    TEdge* E2 = E;
927
0
    while (IsHorizontal(*E)) E = E->Next;
928
0
    if (E->Top.Y == E->Prev->Bot.Y) continue; //ie just an intermediate horz.
929
0
    if (E2->Prev->Bot.X < E->Bot.X) E = E2;
930
0
    break;
931
0
  }
932
0
  return E;
933
0
}
934
//------------------------------------------------------------------------------
935
936
TEdge* ClipperBase::ProcessBound(TEdge* E, bool NextIsForward)
937
0
{
938
0
  TEdge *Result = E;
939
0
  TEdge *Horz = 0;
940
941
0
  if (E->OutIdx == Skip)
942
0
  {
943
    //if edges still remain in the current bound beyond the skip edge then
944
    //create another LocMin and call ProcessBound once more
945
0
    if (NextIsForward)
946
0
    {
947
0
      while (E->Top.Y == E->Next->Bot.Y) E = E->Next;
948
      //don't include top horizontals when parsing a bound a second time,
949
      //they will be contained in the opposite bound ...
950
0
      while (E != Result && IsHorizontal(*E)) E = E->Prev;
951
0
    }
952
0
    else
953
0
    {
954
0
      while (E->Top.Y == E->Prev->Bot.Y) E = E->Prev;
955
0
      while (E != Result && IsHorizontal(*E)) E = E->Next;
956
0
    }
957
958
0
    if (E == Result)
959
0
    {
960
0
      if (NextIsForward) Result = E->Next;
961
0
      else Result = E->Prev;
962
0
    }
963
0
    else
964
0
    {
965
      //there are more edges in the bound beyond result starting with E
966
0
      if (NextIsForward)
967
0
        E = Result->Next;
968
0
      else
969
0
        E = Result->Prev;
970
0
      MinimaList::value_type locMin;
971
0
      locMin.Y = E->Bot.Y;
972
0
      locMin.LeftBound = 0;
973
0
      locMin.RightBound = E;
974
0
      E->WindDelta = 0;
975
0
      Result = ProcessBound(E, NextIsForward);
976
0
      m_MinimaList.push_back(locMin);
977
0
    }
978
0
    return Result;
979
0
  }
980
981
0
  TEdge *EStart;
982
983
0
  if (IsHorizontal(*E))
984
0
  {
985
    //We need to be careful with open paths because this may not be a
986
    //true local minima (ie E may be following a skip edge).
987
    //Also, consecutive horz. edges may start heading left before going right.
988
0
    if (NextIsForward)
989
0
      EStart = E->Prev;
990
0
    else
991
0
      EStart = E->Next;
992
0
    if (IsHorizontal(*EStart)) //ie an adjoining horizontal skip edge
993
0
      {
994
0
        if (EStart->Bot.X != E->Bot.X && EStart->Top.X != E->Bot.X)
995
0
          ReverseHorizontal(*E);
996
0
      }
997
0
      else if (EStart->Bot.X != E->Bot.X)
998
0
        ReverseHorizontal(*E);
999
0
  }
1000
1001
0
  EStart = E;
1002
0
  if (NextIsForward)
1003
0
  {
1004
0
    while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx != Skip)
1005
0
      Result = Result->Next;
1006
0
    if (IsHorizontal(*Result) && Result->Next->OutIdx != Skip)
1007
0
    {
1008
      //nb: at the top of a bound, horizontals are added to the bound
1009
      //only when the preceding edge attaches to the horizontal's left vertex
1010
      //unless a Skip edge is encountered when that becomes the top divide
1011
0
      Horz = Result;
1012
0
      while (IsHorizontal(*Horz->Prev)) Horz = Horz->Prev;
1013
0
      if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
1014
0
    }
1015
0
    while (E != Result)
1016
0
    {
1017
0
      E->NextInLML = E->Next;
1018
0
      if (IsHorizontal(*E) && E != EStart &&
1019
0
        E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
1020
0
      E = E->Next;
1021
0
    }
1022
0
    if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Prev->Top.X)
1023
0
      ReverseHorizontal(*E);
1024
0
    Result = Result->Next; //move to the edge just beyond current bound
1025
0
  } else
1026
0
  {
1027
0
    while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx != Skip)
1028
0
      Result = Result->Prev;
1029
0
    if (IsHorizontal(*Result) && Result->Prev->OutIdx != Skip)
1030
0
    {
1031
0
      Horz = Result;
1032
0
      while (IsHorizontal(*Horz->Next)) Horz = Horz->Next;
1033
0
      if (Horz->Next->Top.X == Result->Prev->Top.X ||
1034
0
          Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
1035
0
    }
1036
1037
0
    while (E != Result)
1038
0
    {
1039
0
      E->NextInLML = E->Prev;
1040
0
      if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
1041
0
        ReverseHorizontal(*E);
1042
0
      E = E->Prev;
1043
0
    }
1044
0
    if (IsHorizontal(*E) && E != EStart && E->Bot.X != E->Next->Top.X)
1045
0
      ReverseHorizontal(*E);
1046
0
    Result = Result->Prev; //move to the edge just beyond current bound
1047
0
  }
1048
1049
0
  return Result;
1050
0
}
1051
//------------------------------------------------------------------------------
1052
1053
bool ClipperBase::AddPath(const Path &pg, PolyType PolyTyp, bool Closed)
1054
0
{
1055
0
#ifdef use_lines
1056
0
  if (!Closed && PolyTyp == ptClip)
1057
0
    throw clipperException("AddPath: Open paths must be subject.");
1058
#else
1059
  if (!Closed)
1060
    throw clipperException("AddPath: Open paths have been disabled.");
1061
#endif
1062
1063
0
  int highI = (int)pg.size() -1;
1064
0
  if (Closed) while (highI > 0 && (pg[highI] == pg[0])) --highI;
1065
0
  while (highI > 0 && (pg[highI] == pg[highI -1])) --highI;
1066
0
  if ((Closed && highI < 2) || (!Closed && highI < 1)) return false;
1067
1068
  //create a new edge array ...
1069
0
  TEdge *edges = new TEdge [highI +1];
1070
1071
0
  bool IsFlat = true;
1072
  //1. Basic (first) edge initialization ...
1073
0
  try
1074
0
  {
1075
0
    edges[1].Curr = pg[1];
1076
0
    RangeTest(pg[0], m_UseFullRange);
1077
0
    RangeTest(pg[highI], m_UseFullRange);
1078
0
    InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
1079
0
    InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
1080
0
    for (int i = highI - 1; i >= 1; --i)
1081
0
    {
1082
0
      RangeTest(pg[i], m_UseFullRange);
1083
0
      InitEdge(&edges[i], &edges[i+1], &edges[i-1], pg[i]);
1084
0
    }
1085
0
  }
1086
0
  catch(...)
1087
0
  {
1088
0
    delete [] edges;
1089
0
    throw; //range test fails
1090
0
  }
1091
0
  TEdge *eStart = &edges[0];
1092
1093
  //2. Remove duplicate vertices, and (when closed) collinear edges ...
1094
0
  TEdge *E = eStart, *eLoopStop = eStart;
1095
0
  for (;;)
1096
0
  {
1097
    //nb: allows matching start and end points when not Closed ...
1098
0
    if (E->Curr == E->Next->Curr && (Closed || E->Next != eStart))
1099
0
    {
1100
0
      if (E == E->Next) break;
1101
0
      if (E == eStart) eStart = E->Next;
1102
0
      E = RemoveEdge(E);
1103
0
      eLoopStop = E;
1104
0
      continue;
1105
0
    }
1106
0
    if (E->Prev == E->Next)
1107
0
      break; //only two vertices
1108
0
    else if (Closed &&
1109
0
      SlopesEqual(E->Prev->Curr, E->Curr, E->Next->Curr, m_UseFullRange) &&
1110
0
      (!m_PreserveCollinear ||
1111
0
      !Pt2IsBetweenPt1AndPt3(E->Prev->Curr, E->Curr, E->Next->Curr)))
1112
0
    {
1113
      //Collinear edges are allowed for open paths but in closed paths
1114
      //the default is to merge adjacent collinear edges into a single edge.
1115
      //However, if the PreserveCollinear property is enabled, only overlapping
1116
      //collinear edges (ie spikes) will be removed from closed paths.
1117
0
      if (E == eStart) eStart = E->Next;
1118
0
      E = RemoveEdge(E);
1119
0
      E = E->Prev;
1120
0
      eLoopStop = E;
1121
0
      continue;
1122
0
    }
1123
0
    E = E->Next;
1124
0
    if ((E == eLoopStop) || (!Closed && E->Next == eStart)) break;
1125
0
  }
1126
1127
0
  if ((!Closed && (E == E->Next)) || (Closed && (E->Prev == E->Next)))
1128
0
  {
1129
0
    delete [] edges;
1130
0
    return false;
1131
0
  }
1132
1133
0
  if (!Closed)
1134
0
  {
1135
0
    m_HasOpenPaths = true;
1136
0
    eStart->Prev->OutIdx = Skip;
1137
0
  }
1138
1139
  //3. Do second stage of edge initialization ...
1140
0
  E = eStart;
1141
0
  do
1142
0
  {
1143
0
    InitEdge2(*E, PolyTyp);
1144
0
    E = E->Next;
1145
0
    if (IsFlat && E->Curr.Y != eStart->Curr.Y) IsFlat = false;
1146
0
  }
1147
0
  while (E != eStart);
1148
1149
  //4. Finally, add edge bounds to LocalMinima list ...
1150
1151
  //Totally flat paths must be handled differently when adding them
1152
  //to LocalMinima list to avoid endless loops etc ...
1153
0
  if (IsFlat)
1154
0
  {
1155
0
    if (Closed)
1156
0
    {
1157
0
      delete [] edges;
1158
0
      return false;
1159
0
    }
1160
0
    E->Prev->OutIdx = Skip;
1161
0
    MinimaList::value_type locMin;
1162
0
    locMin.Y = E->Bot.Y;
1163
0
    locMin.LeftBound = 0;
1164
0
    locMin.RightBound = E;
1165
0
    locMin.RightBound->Side = esRight;
1166
0
    locMin.RightBound->WindDelta = 0;
1167
0
    for (;;)
1168
0
    {
1169
0
      if (E->Bot.X != E->Prev->Top.X) ReverseHorizontal(*E);
1170
0
      if (E->Next->OutIdx == Skip) break;
1171
0
      E->NextInLML = E->Next;
1172
0
      E = E->Next;
1173
0
    }
1174
0
    m_MinimaList.push_back(locMin);
1175
0
    m_edges.push_back(edges);
1176
0
    return true;
1177
0
  }
1178
1179
0
  m_edges.push_back(edges);
1180
0
  bool leftBoundIsForward;
1181
0
  TEdge* EMin = 0;
1182
1183
  //workaround to avoid an endless loop in the while loop below when
1184
  //open paths have matching start and end points ...
1185
0
  if (E->Prev->Bot == E->Prev->Top) E = E->Next;
1186
1187
0
  for (;;)
1188
0
  {
1189
0
    E = FindNextLocMin(E);
1190
0
    if (E == EMin) break;
1191
0
    else if (!EMin) EMin = E;
1192
1193
    //E and E.Prev now share a local minima (left aligned if horizontal).
1194
    //Compare their slopes to find which starts which bound ...
1195
0
    MinimaList::value_type locMin;
1196
0
    locMin.Y = E->Bot.Y;
1197
0
    if (E->Dx < E->Prev->Dx)
1198
0
    {
1199
0
      locMin.LeftBound = E->Prev;
1200
0
      locMin.RightBound = E;
1201
0
      leftBoundIsForward = false; //Q.nextInLML = Q.prev
1202
0
    } else
1203
0
    {
1204
0
      locMin.LeftBound = E;
1205
0
      locMin.RightBound = E->Prev;
1206
0
      leftBoundIsForward = true; //Q.nextInLML = Q.next
1207
0
    }
1208
1209
0
    if (!Closed) locMin.LeftBound->WindDelta = 0;
1210
0
    else if (locMin.LeftBound->Next == locMin.RightBound)
1211
0
      locMin.LeftBound->WindDelta = -1;
1212
0
    else locMin.LeftBound->WindDelta = 1;
1213
0
    locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
1214
1215
0
    E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
1216
0
    if (E->OutIdx == Skip) E = ProcessBound(E, leftBoundIsForward);
1217
1218
0
    TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
1219
0
    if (E2->OutIdx == Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
1220
1221
0
    if (locMin.LeftBound->OutIdx == Skip)
1222
0
      locMin.LeftBound = 0;
1223
0
    else if (locMin.RightBound->OutIdx == Skip)
1224
0
      locMin.RightBound = 0;
1225
0
    m_MinimaList.push_back(locMin);
1226
0
    if (!leftBoundIsForward) E = E2;
1227
0
  }
1228
0
  return true;
1229
0
}
1230
//------------------------------------------------------------------------------
1231
1232
bool ClipperBase::AddPaths(const Paths &ppg, PolyType PolyTyp, bool Closed)
1233
0
{
1234
0
  bool result = false;
1235
0
  for (Paths::size_type i = 0; i < ppg.size(); ++i)
1236
0
    if (AddPath(ppg[i], PolyTyp, Closed)) result = true;
1237
0
  return result;
1238
0
}
1239
//------------------------------------------------------------------------------
1240
1241
void ClipperBase::Clear()
1242
0
{
1243
0
  DisposeLocalMinimaList();
1244
0
  for (EdgeList::size_type i = 0; i < m_edges.size(); ++i)
1245
0
  {
1246
0
    TEdge* edges = m_edges[i];
1247
0
    delete [] edges;
1248
0
  }
1249
0
  m_edges.clear();
1250
0
  m_UseFullRange = false;
1251
0
  m_HasOpenPaths = false;
1252
0
}
1253
//------------------------------------------------------------------------------
1254
1255
void ClipperBase::Reset()
1256
0
{
1257
0
  m_CurrentLM = m_MinimaList.begin();
1258
0
  if (m_CurrentLM == m_MinimaList.end()) return; //ie nothing to process
1259
0
  std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
1260
1261
0
  m_Scanbeam = ScanbeamList(); //clears/resets priority_queue
1262
  //reset all edges ...
1263
0
  for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
1264
0
  {
1265
0
    InsertScanbeam(lm->Y);
1266
0
    TEdge* e = lm->LeftBound;
1267
0
    if (e)
1268
0
    {
1269
0
      e->Curr = e->Bot;
1270
0
      e->Side = esLeft;
1271
0
      e->OutIdx = Unassigned;
1272
0
    }
1273
1274
0
    e = lm->RightBound;
1275
0
    if (e)
1276
0
    {
1277
0
      e->Curr = e->Bot;
1278
0
      e->Side = esRight;
1279
0
      e->OutIdx = Unassigned;
1280
0
    }
1281
0
  }
1282
0
  m_ActiveEdges = 0;
1283
0
  m_CurrentLM = m_MinimaList.begin();
1284
0
}
1285
//------------------------------------------------------------------------------
1286
1287
void ClipperBase::DisposeLocalMinimaList()
1288
0
{
1289
0
  m_MinimaList.clear();
1290
0
  m_CurrentLM = m_MinimaList.begin();
1291
0
}
1292
//------------------------------------------------------------------------------
1293
1294
bool ClipperBase::PopLocalMinima(cInt Y, const LocalMinimum *&locMin)
1295
0
{
1296
0
  if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y) return false;
1297
0
  locMin = &(*m_CurrentLM);
1298
0
  ++m_CurrentLM;
1299
0
  return true;
1300
0
}
1301
//------------------------------------------------------------------------------
1302
1303
IntRect ClipperBase::GetBounds()
1304
0
{
1305
0
  IntRect result;
1306
0
  MinimaList::iterator lm = m_MinimaList.begin();
1307
0
  if (lm == m_MinimaList.end())
1308
0
  {
1309
0
    result.left = result.top = result.right = result.bottom = 0;
1310
0
    return result;
1311
0
  }
1312
0
  result.left = lm->LeftBound->Bot.X;
1313
0
  result.top = lm->LeftBound->Bot.Y;
1314
0
  result.right = lm->LeftBound->Bot.X;
1315
0
  result.bottom = lm->LeftBound->Bot.Y;
1316
0
  while (lm != m_MinimaList.end())
1317
0
  {
1318
    //todo - needs fixing for open paths
1319
0
    result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
1320
0
    TEdge* e = lm->LeftBound;
1321
0
    for (;;) {
1322
0
      TEdge* bottomE = e;
1323
0
      while (e->NextInLML)
1324
0
      {
1325
0
        if (e->Bot.X < result.left) result.left = e->Bot.X;
1326
0
        if (e->Bot.X > result.right) result.right = e->Bot.X;
1327
0
        e = e->NextInLML;
1328
0
      }
1329
0
      result.left = std::min(result.left, e->Bot.X);
1330
0
      result.right = std::max(result.right, e->Bot.X);
1331
0
      result.left = std::min(result.left, e->Top.X);
1332
0
      result.right = std::max(result.right, e->Top.X);
1333
0
      result.top = std::min(result.top, e->Top.Y);
1334
0
      if (bottomE == lm->LeftBound) e = lm->RightBound;
1335
0
      else break;
1336
0
    }
1337
0
    ++lm;
1338
0
  }
1339
0
  return result;
1340
0
}
1341
//------------------------------------------------------------------------------
1342
1343
void ClipperBase::InsertScanbeam(const cInt Y)
1344
0
{
1345
0
  m_Scanbeam.push(Y);
1346
0
}
1347
//------------------------------------------------------------------------------
1348
1349
bool ClipperBase::PopScanbeam(cInt &Y)
1350
0
{
1351
0
  if (m_Scanbeam.empty()) return false;
1352
0
  Y = m_Scanbeam.top();
1353
0
  m_Scanbeam.pop();
1354
0
  while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); } // Pop duplicates.
1355
0
  return true;
1356
0
}
1357
//------------------------------------------------------------------------------
1358
1359
0
void ClipperBase::DisposeAllOutRecs(){
1360
0
  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
1361
0
    DisposeOutRec(i);
1362
0
  m_PolyOuts.clear();
1363
0
}
1364
//------------------------------------------------------------------------------
1365
1366
void ClipperBase::DisposeOutRec(PolyOutList::size_type index)
1367
0
{
1368
0
  OutRec *outRec = m_PolyOuts[index];
1369
0
  if (outRec->Pts) DisposeOutPts(outRec->Pts);
1370
0
  delete outRec;
1371
0
  m_PolyOuts[index] = 0;
1372
0
}
1373
//------------------------------------------------------------------------------
1374
1375
void ClipperBase::DeleteFromAEL(TEdge *e)
1376
0
{
1377
0
  TEdge* AelPrev = e->PrevInAEL;
1378
0
  TEdge* AelNext = e->NextInAEL;
1379
0
  if (!AelPrev &&  !AelNext && (e != m_ActiveEdges)) return; //already deleted
1380
0
  if (AelPrev) AelPrev->NextInAEL = AelNext;
1381
0
  else m_ActiveEdges = AelNext;
1382
0
  if (AelNext) AelNext->PrevInAEL = AelPrev;
1383
0
  e->NextInAEL = 0;
1384
0
  e->PrevInAEL = 0;
1385
0
}
1386
//------------------------------------------------------------------------------
1387
1388
OutRec* ClipperBase::CreateOutRec()
1389
0
{
1390
0
  OutRec* result = new OutRec;
1391
0
  result->IsHole = false;
1392
0
  result->IsOpen = false;
1393
0
  result->FirstLeft = 0;
1394
0
  result->Pts = 0;
1395
0
  result->BottomPt = 0;
1396
0
  result->PolyNd = 0;
1397
0
  m_PolyOuts.push_back(result);
1398
0
  result->Idx = (int)m_PolyOuts.size() - 1;
1399
0
  return result;
1400
0
}
1401
//------------------------------------------------------------------------------
1402
1403
void ClipperBase::SwapPositionsInAEL(TEdge *Edge1, TEdge *Edge2)
1404
0
{
1405
  //check that one or other edge hasn't already been removed from AEL ...
1406
0
  if (Edge1->NextInAEL == Edge1->PrevInAEL ||
1407
0
    Edge2->NextInAEL == Edge2->PrevInAEL) return;
1408
1409
0
  if (Edge1->NextInAEL == Edge2)
1410
0
  {
1411
0
    TEdge* Next = Edge2->NextInAEL;
1412
0
    if (Next) Next->PrevInAEL = Edge1;
1413
0
    TEdge* Prev = Edge1->PrevInAEL;
1414
0
    if (Prev) Prev->NextInAEL = Edge2;
1415
0
    Edge2->PrevInAEL = Prev;
1416
0
    Edge2->NextInAEL = Edge1;
1417
0
    Edge1->PrevInAEL = Edge2;
1418
0
    Edge1->NextInAEL = Next;
1419
0
  }
1420
0
  else if (Edge2->NextInAEL == Edge1)
1421
0
  {
1422
0
    TEdge* Next = Edge1->NextInAEL;
1423
0
    if (Next) Next->PrevInAEL = Edge2;
1424
0
    TEdge* Prev = Edge2->PrevInAEL;
1425
0
    if (Prev) Prev->NextInAEL = Edge1;
1426
0
    Edge1->PrevInAEL = Prev;
1427
0
    Edge1->NextInAEL = Edge2;
1428
0
    Edge2->PrevInAEL = Edge1;
1429
0
    Edge2->NextInAEL = Next;
1430
0
  }
1431
0
  else
1432
0
  {
1433
0
    TEdge* Next = Edge1->NextInAEL;
1434
0
    TEdge* Prev = Edge1->PrevInAEL;
1435
0
    Edge1->NextInAEL = Edge2->NextInAEL;
1436
0
    if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1;
1437
0
    Edge1->PrevInAEL = Edge2->PrevInAEL;
1438
0
    if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1;
1439
0
    Edge2->NextInAEL = Next;
1440
0
    if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2;
1441
0
    Edge2->PrevInAEL = Prev;
1442
0
    if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2;
1443
0
  }
1444
1445
0
  if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1;
1446
0
  else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2;
1447
0
}
1448
//------------------------------------------------------------------------------
1449
1450
void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e)
1451
0
{
1452
0
  if (!e->NextInLML)
1453
0
    throw clipperException("UpdateEdgeIntoAEL: invalid call");
1454
1455
0
  e->NextInLML->OutIdx = e->OutIdx;
1456
0
  TEdge* AelPrev = e->PrevInAEL;
1457
0
  TEdge* AelNext = e->NextInAEL;
1458
0
  if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
1459
0
  else m_ActiveEdges = e->NextInLML;
1460
0
  if (AelNext) AelNext->PrevInAEL = e->NextInLML;
1461
0
  e->NextInLML->Side = e->Side;
1462
0
  e->NextInLML->WindDelta = e->WindDelta;
1463
0
  e->NextInLML->WindCnt = e->WindCnt;
1464
0
  e->NextInLML->WindCnt2 = e->WindCnt2;
1465
0
  e = e->NextInLML;
1466
0
  e->Curr = e->Bot;
1467
0
  e->PrevInAEL = AelPrev;
1468
0
  e->NextInAEL = AelNext;
1469
0
  if (!IsHorizontal(*e)) InsertScanbeam(e->Top.Y);
1470
0
}
1471
//------------------------------------------------------------------------------
1472
1473
bool ClipperBase::LocalMinimaPending()
1474
0
{
1475
0
  return (m_CurrentLM != m_MinimaList.end());
1476
0
}
1477
1478
//------------------------------------------------------------------------------
1479
// TClipper methods ...
1480
//------------------------------------------------------------------------------
1481
1482
0
Clipper::Clipper(int initOptions) : ClipperBase() //constructor
1483
0
{
1484
0
  m_ExecuteLocked = false;
1485
0
  m_UseFullRange = false;
1486
0
  m_ReverseOutput = ((initOptions & ioReverseSolution) != 0);
1487
0
  m_StrictSimple = ((initOptions & ioStrictlySimple) != 0);
1488
0
  m_PreserveCollinear = ((initOptions & ioPreserveCollinear) != 0);
1489
0
  m_HasOpenPaths = false;
1490
#ifdef use_xyz
1491
  m_ZFill = 0;
1492
#endif
1493
0
}
Unexecuted instantiation: ClipperLib::Clipper::Clipper(int)
Unexecuted instantiation: ClipperLib::Clipper::Clipper(int)
1494
//------------------------------------------------------------------------------
1495
1496
#ifdef use_xyz
1497
void Clipper::ZFillFunction(ZFillCallback zFillFunc)
1498
{
1499
  m_ZFill = zFillFunc;
1500
}
1501
//------------------------------------------------------------------------------
1502
#endif
1503
1504
bool Clipper::Execute(ClipType clipType, Paths &solution, PolyFillType fillType)
1505
0
{
1506
0
    return Execute(clipType, solution, fillType, fillType);
1507
0
}
1508
//------------------------------------------------------------------------------
1509
1510
bool Clipper::Execute(ClipType clipType, PolyTree &polytree, PolyFillType fillType)
1511
0
{
1512
0
    return Execute(clipType, polytree, fillType, fillType);
1513
0
}
1514
//------------------------------------------------------------------------------
1515
1516
bool Clipper::Execute(ClipType clipType, Paths &solution,
1517
    PolyFillType subjFillType, PolyFillType clipFillType)
1518
0
{
1519
0
  if( m_ExecuteLocked ) return false;
1520
0
  if (m_HasOpenPaths)
1521
0
    throw clipperException("Error: PolyTree struct is needed for open path clipping.");
1522
0
  m_ExecuteLocked = true;
1523
0
  solution.resize(0);
1524
0
  m_SubjFillType = subjFillType;
1525
0
  m_ClipFillType = clipFillType;
1526
0
  m_ClipType = clipType;
1527
0
  m_UsingPolyTree = false;
1528
0
  bool succeeded = ExecuteInternal();
1529
0
  if (succeeded) BuildResult(solution);
1530
0
  DisposeAllOutRecs();
1531
0
  m_ExecuteLocked = false;
1532
0
  return succeeded;
1533
0
}
1534
//------------------------------------------------------------------------------
1535
1536
bool Clipper::Execute(ClipType clipType, PolyTree& polytree,
1537
    PolyFillType subjFillType, PolyFillType clipFillType)
1538
0
{
1539
0
  if( m_ExecuteLocked ) return false;
1540
0
  m_ExecuteLocked = true;
1541
0
  m_SubjFillType = subjFillType;
1542
0
  m_ClipFillType = clipFillType;
1543
0
  m_ClipType = clipType;
1544
0
  m_UsingPolyTree = true;
1545
0
  bool succeeded = ExecuteInternal();
1546
0
  if (succeeded) BuildResult2(polytree);
1547
0
  DisposeAllOutRecs();
1548
0
  m_ExecuteLocked = false;
1549
0
  return succeeded;
1550
0
}
1551
//------------------------------------------------------------------------------
1552
1553
void Clipper::FixHoleLinkage(OutRec &outrec)
1554
0
{
1555
  //skip OutRecs that (a) contain outermost polygons or
1556
  //(b) already have the correct owner/child linkage ...
1557
0
  if (!outrec.FirstLeft ||
1558
0
      (outrec.IsHole != outrec.FirstLeft->IsHole &&
1559
0
      outrec.FirstLeft->Pts)) return;
1560
1561
0
  OutRec* orfl = outrec.FirstLeft;
1562
0
  while (orfl && ((orfl->IsHole == outrec.IsHole) || !orfl->Pts))
1563
0
      orfl = orfl->FirstLeft;
1564
0
  outrec.FirstLeft = orfl;
1565
0
}
1566
//------------------------------------------------------------------------------
1567
1568
bool Clipper::ExecuteInternal()
1569
0
{
1570
0
  bool succeeded = true;
1571
0
  try {
1572
0
    Reset();
1573
0
    m_Maxima = MaximaList();
1574
0
    m_SortedEdges = 0;
1575
1576
0
    succeeded = true;
1577
0
    cInt botY = 0, topY = 0;
1578
0
    if (!PopScanbeam(botY)) return false;
1579
0
    InsertLocalMinimaIntoAEL(botY);
1580
0
    while (PopScanbeam(topY) || LocalMinimaPending())
1581
0
    {
1582
0
      ProcessHorizontals();
1583
0
      ClearGhostJoins();
1584
0
      if (!ProcessIntersections(topY))
1585
0
      {
1586
0
        succeeded = false;
1587
0
        break;
1588
0
      }
1589
0
      ProcessEdgesAtTopOfScanbeam(topY);
1590
0
      botY = topY;
1591
0
      InsertLocalMinimaIntoAEL(botY);
1592
0
    }
1593
0
  }
1594
0
  catch(...)
1595
0
  {
1596
0
    succeeded = false;
1597
0
  }
1598
1599
0
  if (succeeded)
1600
0
  {
1601
    //fix orientations ...
1602
0
    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
1603
0
    {
1604
0
      OutRec *outRec = m_PolyOuts[i];
1605
0
      if (!outRec->Pts || outRec->IsOpen) continue;
1606
0
      if ((outRec->IsHole ^ m_ReverseOutput) == (Area(*outRec) > 0))
1607
0
        ReversePolyPtLinks(outRec->Pts);
1608
0
    }
1609
1610
0
    if (!m_Joins.empty()) JoinCommonEdges();
1611
1612
    //unfortunately FixupOutPolygon() must be done after JoinCommonEdges()
1613
0
    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
1614
0
    {
1615
0
      OutRec *outRec = m_PolyOuts[i];
1616
0
      if (!outRec->Pts) continue;
1617
0
      if (outRec->IsOpen)
1618
0
        FixupOutPolyline(*outRec);
1619
0
      else
1620
0
        FixupOutPolygon(*outRec);
1621
0
    }
1622
1623
0
    if (m_StrictSimple) DoSimplePolygons();
1624
0
  }
1625
1626
0
  ClearJoins();
1627
0
  ClearGhostJoins();
1628
0
  return succeeded;
1629
0
}
1630
//------------------------------------------------------------------------------
1631
1632
void Clipper::SetWindingCount(TEdge &edge)
1633
0
{
1634
0
  TEdge *e = edge.PrevInAEL;
1635
  //find the edge of the same polytype that immediately preceeds 'edge' in AEL
1636
0
  while (e  && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
1637
0
  if (!e)
1638
0
  {
1639
0
    if (edge.WindDelta == 0)
1640
0
    {
1641
0
      PolyFillType pft = (edge.PolyTyp == ptSubject ? m_SubjFillType : m_ClipFillType);
1642
0
      edge.WindCnt = (pft == pftNegative ? -1 : 1);
1643
0
    }
1644
0
    else
1645
0
      edge.WindCnt = edge.WindDelta;
1646
0
    edge.WindCnt2 = 0;
1647
0
    e = m_ActiveEdges; //ie get ready to calc WindCnt2
1648
0
  }
1649
0
  else if (edge.WindDelta == 0 && m_ClipType != ctUnion)
1650
0
  {
1651
0
    edge.WindCnt = 1;
1652
0
    edge.WindCnt2 = e->WindCnt2;
1653
0
    e = e->NextInAEL; //ie get ready to calc WindCnt2
1654
0
  }
1655
0
  else if (IsEvenOddFillType(edge))
1656
0
  {
1657
    //EvenOdd filling ...
1658
0
    if (edge.WindDelta == 0)
1659
0
    {
1660
      //are we inside a subj polygon ...
1661
0
      bool Inside = true;
1662
0
      TEdge *e2 = e->PrevInAEL;
1663
0
      while (e2)
1664
0
      {
1665
0
        if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0)
1666
0
          Inside = !Inside;
1667
0
        e2 = e2->PrevInAEL;
1668
0
      }
1669
0
      edge.WindCnt = (Inside ? 0 : 1);
1670
0
    }
1671
0
    else
1672
0
    {
1673
0
      edge.WindCnt = edge.WindDelta;
1674
0
    }
1675
0
    edge.WindCnt2 = e->WindCnt2;
1676
0
    e = e->NextInAEL; //ie get ready to calc WindCnt2
1677
0
  }
1678
0
  else
1679
0
  {
1680
    //nonZero, Positive or Negative filling ...
1681
0
    if (e->WindCnt * e->WindDelta < 0)
1682
0
    {
1683
      //prev edge is 'decreasing' WindCount (WC) toward zero
1684
      //so we're outside the previous polygon ...
1685
0
      if (Abs(e->WindCnt) > 1)
1686
0
      {
1687
        //outside prev poly but still inside another.
1688
        //when reversing direction of prev poly use the same WC
1689
0
        if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1690
        //otherwise continue to 'decrease' WC ...
1691
0
        else edge.WindCnt = e->WindCnt + edge.WindDelta;
1692
0
      }
1693
0
      else
1694
        //now outside all polys of same polytype so set own WC ...
1695
0
        edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
1696
0
    } else
1697
0
    {
1698
      //prev edge is 'increasing' WindCount (WC) away from zero
1699
      //so we're inside the previous polygon ...
1700
0
      if (edge.WindDelta == 0)
1701
0
        edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1);
1702
      //if wind direction is reversing prev then use same WC
1703
0
      else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1704
      //otherwise add to WC ...
1705
0
      else edge.WindCnt = e->WindCnt + edge.WindDelta;
1706
0
    }
1707
0
    edge.WindCnt2 = e->WindCnt2;
1708
0
    e = e->NextInAEL; //ie get ready to calc WindCnt2
1709
0
  }
1710
1711
  //update WindCnt2 ...
1712
0
  if (IsEvenOddAltFillType(edge))
1713
0
  {
1714
    //EvenOdd filling ...
1715
0
    while (e != &edge)
1716
0
    {
1717
0
      if (e->WindDelta != 0)
1718
0
        edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
1719
0
      e = e->NextInAEL;
1720
0
    }
1721
0
  } else
1722
0
  {
1723
    //nonZero, Positive or Negative filling ...
1724
0
    while ( e != &edge )
1725
0
    {
1726
0
      edge.WindCnt2 += e->WindDelta;
1727
0
      e = e->NextInAEL;
1728
0
    }
1729
0
  }
1730
0
}
1731
//------------------------------------------------------------------------------
1732
1733
bool Clipper::IsEvenOddFillType(const TEdge& edge) const
1734
0
{
1735
0
  if (edge.PolyTyp == ptSubject)
1736
0
    return m_SubjFillType == pftEvenOdd; else
1737
0
    return m_ClipFillType == pftEvenOdd;
1738
0
}
1739
//------------------------------------------------------------------------------
1740
1741
bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const
1742
0
{
1743
0
  if (edge.PolyTyp == ptSubject)
1744
0
    return m_ClipFillType == pftEvenOdd; else
1745
0
    return m_SubjFillType == pftEvenOdd;
1746
0
}
1747
//------------------------------------------------------------------------------
1748
1749
bool Clipper::IsContributing(const TEdge& edge) const
1750
0
{
1751
0
  PolyFillType pft, pft2;
1752
0
  if (edge.PolyTyp == ptSubject)
1753
0
  {
1754
0
    pft = m_SubjFillType;
1755
0
    pft2 = m_ClipFillType;
1756
0
  } else
1757
0
  {
1758
0
    pft = m_ClipFillType;
1759
0
    pft2 = m_SubjFillType;
1760
0
  }
1761
1762
0
  switch(pft)
1763
0
  {
1764
0
    case pftEvenOdd:
1765
      //return false if a subj line has been flagged as inside a subj polygon
1766
0
      if (edge.WindDelta == 0 && edge.WindCnt != 1) return false;
1767
0
      break;
1768
0
    case pftNonZero:
1769
0
      if (Abs(edge.WindCnt) != 1) return false;
1770
0
      break;
1771
0
    case pftPositive:
1772
0
      if (edge.WindCnt != 1) return false;
1773
0
      break;
1774
0
    default: //pftNegative
1775
0
      if (edge.WindCnt != -1) return false;
1776
0
  }
1777
1778
0
  switch(m_ClipType)
1779
0
  {
1780
0
    case ctIntersection:
1781
0
      switch(pft2)
1782
0
      {
1783
0
        case pftEvenOdd:
1784
0
        case pftNonZero:
1785
0
          return (edge.WindCnt2 != 0);
1786
0
        case pftPositive:
1787
0
          return (edge.WindCnt2 > 0);
1788
0
        default:
1789
0
          return (edge.WindCnt2 < 0);
1790
0
      }
1791
0
      break;
1792
0
    case ctUnion:
1793
0
      switch(pft2)
1794
0
      {
1795
0
        case pftEvenOdd:
1796
0
        case pftNonZero:
1797
0
          return (edge.WindCnt2 == 0);
1798
0
        case pftPositive:
1799
0
          return (edge.WindCnt2 <= 0);
1800
0
        default:
1801
0
          return (edge.WindCnt2 >= 0);
1802
0
      }
1803
0
      break;
1804
0
    case ctDifference:
1805
0
      if (edge.PolyTyp == ptSubject)
1806
0
        switch(pft2)
1807
0
        {
1808
0
          case pftEvenOdd:
1809
0
          case pftNonZero:
1810
0
            return (edge.WindCnt2 == 0);
1811
0
          case pftPositive:
1812
0
            return (edge.WindCnt2 <= 0);
1813
0
          default:
1814
0
            return (edge.WindCnt2 >= 0);
1815
0
        }
1816
0
      else
1817
0
        switch(pft2)
1818
0
        {
1819
0
          case pftEvenOdd:
1820
0
          case pftNonZero:
1821
0
            return (edge.WindCnt2 != 0);
1822
0
          case pftPositive:
1823
0
            return (edge.WindCnt2 > 0);
1824
0
          default:
1825
0
            return (edge.WindCnt2 < 0);
1826
0
        }
1827
0
      break;
1828
0
    case ctXor:
1829
0
      if (edge.WindDelta == 0) //XOr always contributing unless open
1830
0
        switch(pft2)
1831
0
        {
1832
0
          case pftEvenOdd:
1833
0
          case pftNonZero:
1834
0
            return (edge.WindCnt2 == 0);
1835
0
          case pftPositive:
1836
0
            return (edge.WindCnt2 <= 0);
1837
0
          default:
1838
0
            return (edge.WindCnt2 >= 0);
1839
0
        }
1840
0
      else
1841
0
        return true;
1842
0
      break;
1843
0
    default:
1844
0
      return true;
1845
0
  }
1846
0
}
1847
//------------------------------------------------------------------------------
1848
1849
OutPt* Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
1850
0
{
1851
0
  OutPt* result;
1852
0
  TEdge *e, *prevE;
1853
0
  if (IsHorizontal(*e2) || ( e1->Dx > e2->Dx ))
1854
0
  {
1855
0
    result = AddOutPt(e1, Pt);
1856
0
    e2->OutIdx = e1->OutIdx;
1857
0
    e1->Side = esLeft;
1858
0
    e2->Side = esRight;
1859
0
    e = e1;
1860
0
    if (e->PrevInAEL == e2)
1861
0
      prevE = e2->PrevInAEL;
1862
0
    else
1863
0
      prevE = e->PrevInAEL;
1864
0
  } else
1865
0
  {
1866
0
    result = AddOutPt(e2, Pt);
1867
0
    e1->OutIdx = e2->OutIdx;
1868
0
    e1->Side = esRight;
1869
0
    e2->Side = esLeft;
1870
0
    e = e2;
1871
0
    if (e->PrevInAEL == e1)
1872
0
        prevE = e1->PrevInAEL;
1873
0
    else
1874
0
        prevE = e->PrevInAEL;
1875
0
  }
1876
1877
0
  if (prevE && prevE->OutIdx >= 0 && prevE->Top.Y < Pt.Y && e->Top.Y < Pt.Y)
1878
0
  {
1879
0
    cInt xPrev = TopX(*prevE, Pt.Y);
1880
0
    cInt xE = TopX(*e, Pt.Y);
1881
0
    if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
1882
0
      SlopesEqual(IntPoint(xPrev, Pt.Y), prevE->Top, IntPoint(xE, Pt.Y), e->Top, m_UseFullRange))
1883
0
    {
1884
0
      OutPt* outPt = AddOutPt(prevE, Pt);
1885
0
      AddJoin(result, outPt, e->Top);
1886
0
    }
1887
0
  }
1888
0
  return result;
1889
0
}
1890
//------------------------------------------------------------------------------
1891
1892
void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &Pt)
1893
0
{
1894
0
  AddOutPt( e1, Pt );
1895
0
  if (e2->WindDelta == 0) AddOutPt(e2, Pt);
1896
0
  if( e1->OutIdx == e2->OutIdx )
1897
0
  {
1898
0
    e1->OutIdx = Unassigned;
1899
0
    e2->OutIdx = Unassigned;
1900
0
  }
1901
0
  else if (e1->OutIdx < e2->OutIdx)
1902
0
    AppendPolygon(e1, e2);
1903
0
  else
1904
0
    AppendPolygon(e2, e1);
1905
0
}
1906
//------------------------------------------------------------------------------
1907
1908
void Clipper::AddEdgeToSEL(TEdge *edge)
1909
0
{
1910
  //SEL pointers in PEdge are reused to build a list of horizontal edges.
1911
  //However, we don't need to worry about order with horizontal edge processing.
1912
0
  if( !m_SortedEdges )
1913
0
  {
1914
0
    m_SortedEdges = edge;
1915
0
    edge->PrevInSEL = 0;
1916
0
    edge->NextInSEL = 0;
1917
0
  }
1918
0
  else
1919
0
  {
1920
0
    edge->NextInSEL = m_SortedEdges;
1921
0
    edge->PrevInSEL = 0;
1922
0
    m_SortedEdges->PrevInSEL = edge;
1923
0
    m_SortedEdges = edge;
1924
0
  }
1925
0
}
1926
//------------------------------------------------------------------------------
1927
1928
bool Clipper::PopEdgeFromSEL(TEdge *&edge)
1929
0
{
1930
0
  if (!m_SortedEdges) return false;
1931
0
  edge = m_SortedEdges;
1932
0
  DeleteFromSEL(m_SortedEdges);
1933
0
  return true;
1934
0
}
1935
//------------------------------------------------------------------------------
1936
1937
void Clipper::CopyAELToSEL()
1938
0
{
1939
0
  TEdge* e = m_ActiveEdges;
1940
0
  m_SortedEdges = e;
1941
0
  while ( e )
1942
0
  {
1943
0
    e->PrevInSEL = e->PrevInAEL;
1944
0
    e->NextInSEL = e->NextInAEL;
1945
0
    e = e->NextInAEL;
1946
0
  }
1947
0
}
1948
//------------------------------------------------------------------------------
1949
1950
void Clipper::AddJoin(OutPt *op1, OutPt *op2, const IntPoint OffPt)
1951
0
{
1952
0
  Join* j = new Join;
1953
0
  j->OutPt1 = op1;
1954
0
  j->OutPt2 = op2;
1955
0
  j->OffPt = OffPt;
1956
0
  m_Joins.push_back(j);
1957
0
}
1958
//------------------------------------------------------------------------------
1959
1960
void Clipper::ClearJoins()
1961
0
{
1962
0
  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
1963
0
    delete m_Joins[i];
1964
0
  m_Joins.resize(0);
1965
0
}
1966
//------------------------------------------------------------------------------
1967
1968
void Clipper::ClearGhostJoins()
1969
0
{
1970
0
  for (JoinList::size_type i = 0; i < m_GhostJoins.size(); i++)
1971
0
    delete m_GhostJoins[i];
1972
0
  m_GhostJoins.resize(0);
1973
0
}
1974
//------------------------------------------------------------------------------
1975
1976
void Clipper::AddGhostJoin(OutPt *op, const IntPoint OffPt)
1977
0
{
1978
0
  Join* j = new Join;
1979
0
  j->OutPt1 = op;
1980
0
  j->OutPt2 = 0;
1981
0
  j->OffPt = OffPt;
1982
0
  m_GhostJoins.push_back(j);
1983
0
}
1984
//------------------------------------------------------------------------------
1985
1986
void Clipper::InsertLocalMinimaIntoAEL(const cInt botY)
1987
0
{
1988
0
  const LocalMinimum *lm;
1989
0
  while (PopLocalMinima(botY, lm))
1990
0
  {
1991
0
    TEdge* lb = lm->LeftBound;
1992
0
    TEdge* rb = lm->RightBound;
1993
1994
0
    OutPt *Op1 = 0;
1995
0
    if (!lb)
1996
0
    {
1997
      //nb: don't insert LB into either AEL or SEL
1998
0
      InsertEdgeIntoAEL(rb, 0);
1999
0
      SetWindingCount(*rb);
2000
0
      if (IsContributing(*rb))
2001
0
        Op1 = AddOutPt(rb, rb->Bot);
2002
0
    }
2003
0
    else if (!rb)
2004
0
    {
2005
0
      InsertEdgeIntoAEL(lb, 0);
2006
0
      SetWindingCount(*lb);
2007
0
      if (IsContributing(*lb))
2008
0
        Op1 = AddOutPt(lb, lb->Bot);
2009
0
      InsertScanbeam(lb->Top.Y);
2010
0
    }
2011
0
    else
2012
0
    {
2013
0
      InsertEdgeIntoAEL(lb, 0);
2014
0
      InsertEdgeIntoAEL(rb, lb);
2015
0
      SetWindingCount( *lb );
2016
0
      rb->WindCnt = lb->WindCnt;
2017
0
      rb->WindCnt2 = lb->WindCnt2;
2018
0
      if (IsContributing(*lb))
2019
0
        Op1 = AddLocalMinPoly(lb, rb, lb->Bot);
2020
0
      InsertScanbeam(lb->Top.Y);
2021
0
    }
2022
2023
0
     if (rb)
2024
0
     {
2025
0
     if (IsHorizontal(*rb))
2026
0
     {
2027
0
       AddEdgeToSEL(rb);
2028
0
       if (rb->NextInLML)
2029
0
         InsertScanbeam(rb->NextInLML->Top.Y);
2030
0
     }
2031
0
     else InsertScanbeam( rb->Top.Y );
2032
0
     }
2033
2034
0
    if (!lb || !rb) continue;
2035
2036
    //if any output polygons share an edge, they'll need joining later ...
2037
0
    if (Op1 && IsHorizontal(*rb) &&
2038
0
      m_GhostJoins.size() > 0 && (rb->WindDelta != 0))
2039
0
    {
2040
0
      for (JoinList::size_type i = 0; i < m_GhostJoins.size(); ++i)
2041
0
      {
2042
0
        Join* jr = m_GhostJoins[i];
2043
        //if the horizontal Rb and a 'ghost' horizontal overlap, then convert
2044
        //the 'ghost' join to a real join ready for later ...
2045
0
        if (HorzSegmentsOverlap(jr->OutPt1->Pt.X, jr->OffPt.X, rb->Bot.X, rb->Top.X))
2046
0
          AddJoin(jr->OutPt1, Op1, jr->OffPt);
2047
0
      }
2048
0
    }
2049
2050
0
    if (lb->OutIdx >= 0 && lb->PrevInAEL &&
2051
0
      lb->PrevInAEL->Curr.X == lb->Bot.X &&
2052
0
      lb->PrevInAEL->OutIdx >= 0 &&
2053
0
      SlopesEqual(lb->PrevInAEL->Bot, lb->PrevInAEL->Top, lb->Curr, lb->Top, m_UseFullRange) &&
2054
0
      (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
2055
0
    {
2056
0
        OutPt *Op2 = AddOutPt(lb->PrevInAEL, lb->Bot);
2057
0
        AddJoin(Op1, Op2, lb->Top);
2058
0
    }
2059
2060
0
    if(lb->NextInAEL != rb)
2061
0
    {
2062
2063
0
      if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
2064
0
        SlopesEqual(rb->PrevInAEL->Curr, rb->PrevInAEL->Top, rb->Curr, rb->Top, m_UseFullRange) &&
2065
0
        (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
2066
0
      {
2067
0
          OutPt *Op2 = AddOutPt(rb->PrevInAEL, rb->Bot);
2068
0
          AddJoin(Op1, Op2, rb->Top);
2069
0
      }
2070
2071
0
      TEdge* e = lb->NextInAEL;
2072
0
      if (e)
2073
0
      {
2074
0
        while( e != rb )
2075
0
        {
2076
          //nb: For calculating winding counts etc, IntersectEdges() assumes
2077
          //that param1 will be to the Right of param2 ABOVE the intersection ...
2078
0
          IntersectEdges(rb , e , lb->Curr); //order important here
2079
0
          e = e->NextInAEL;
2080
0
        }
2081
0
      }
2082
0
    }
2083
2084
0
  }
2085
0
}
2086
//------------------------------------------------------------------------------
2087
2088
void Clipper::DeleteFromSEL(TEdge *e)
2089
0
{
2090
0
  TEdge* SelPrev = e->PrevInSEL;
2091
0
  TEdge* SelNext = e->NextInSEL;
2092
0
  if( !SelPrev &&  !SelNext && (e != m_SortedEdges) ) return; //already deleted
2093
0
  if( SelPrev ) SelPrev->NextInSEL = SelNext;
2094
0
  else m_SortedEdges = SelNext;
2095
0
  if( SelNext ) SelNext->PrevInSEL = SelPrev;
2096
0
  e->NextInSEL = 0;
2097
0
  e->PrevInSEL = 0;
2098
0
}
2099
//------------------------------------------------------------------------------
2100
2101
#ifdef use_xyz
2102
void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
2103
{
2104
  if (pt.Z != 0 || !m_ZFill) return;
2105
  else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
2106
  else if (pt == e1.Top) pt.Z = e1.Top.Z;
2107
  else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
2108
  else if (pt == e2.Top) pt.Z = e2.Top.Z;
2109
  else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
2110
}
2111
//------------------------------------------------------------------------------
2112
#endif
2113
2114
void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, IntPoint &Pt)
2115
0
{
2116
0
  bool e1Contributing = ( e1->OutIdx >= 0 );
2117
0
  bool e2Contributing = ( e2->OutIdx >= 0 );
2118
2119
#ifdef use_xyz
2120
        SetZ(Pt, *e1, *e2);
2121
#endif
2122
2123
0
#ifdef use_lines
2124
  //if either edge is on an OPEN path ...
2125
0
  if (e1->WindDelta == 0 || e2->WindDelta == 0)
2126
0
  {
2127
    //ignore subject-subject open path intersections UNLESS they
2128
    //are both open paths, AND they are both 'contributing maximas' ...
2129
0
  if (e1->WindDelta == 0 && e2->WindDelta == 0) return;
2130
2131
    //if intersecting a subj line with a subj poly ...
2132
0
    else if (e1->PolyTyp == e2->PolyTyp &&
2133
0
      e1->WindDelta != e2->WindDelta && m_ClipType == ctUnion)
2134
0
    {
2135
0
      if (e1->WindDelta == 0)
2136
0
      {
2137
0
        if (e2Contributing)
2138
0
        {
2139
0
          AddOutPt(e1, Pt);
2140
0
          if (e1Contributing) e1->OutIdx = Unassigned;
2141
0
        }
2142
0
      }
2143
0
      else
2144
0
      {
2145
0
        if (e1Contributing)
2146
0
        {
2147
0
          AddOutPt(e2, Pt);
2148
0
          if (e2Contributing) e2->OutIdx = Unassigned;
2149
0
        }
2150
0
      }
2151
0
    }
2152
0
    else if (e1->PolyTyp != e2->PolyTyp)
2153
0
    {
2154
      //toggle subj open path OutIdx on/off when Abs(clip.WndCnt) == 1 ...
2155
0
      if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 &&
2156
0
        (m_ClipType != ctUnion || e2->WindCnt2 == 0))
2157
0
      {
2158
0
        AddOutPt(e1, Pt);
2159
0
        if (e1Contributing) e1->OutIdx = Unassigned;
2160
0
      }
2161
0
      else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) &&
2162
0
        (m_ClipType != ctUnion || e1->WindCnt2 == 0))
2163
0
      {
2164
0
        AddOutPt(e2, Pt);
2165
0
        if (e2Contributing) e2->OutIdx = Unassigned;
2166
0
      }
2167
0
    }
2168
0
    return;
2169
0
  }
2170
0
#endif
2171
2172
  //update winding counts...
2173
  //assumes that e1 will be to the Right of e2 ABOVE the intersection
2174
0
  if ( e1->PolyTyp == e2->PolyTyp )
2175
0
  {
2176
0
    if ( IsEvenOddFillType( *e1) )
2177
0
    {
2178
0
      int oldE1WindCnt = e1->WindCnt;
2179
0
      e1->WindCnt = e2->WindCnt;
2180
0
      e2->WindCnt = oldE1WindCnt;
2181
0
    } else
2182
0
    {
2183
0
      if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt;
2184
0
      else e1->WindCnt += e2->WindDelta;
2185
0
      if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt;
2186
0
      else e2->WindCnt -= e1->WindDelta;
2187
0
    }
2188
0
  } else
2189
0
  {
2190
0
    if (!IsEvenOddFillType(*e2)) e1->WindCnt2 += e2->WindDelta;
2191
0
    else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0;
2192
0
    if (!IsEvenOddFillType(*e1)) e2->WindCnt2 -= e1->WindDelta;
2193
0
    else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0;
2194
0
  }
2195
2196
0
  PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
2197
0
  if (e1->PolyTyp == ptSubject)
2198
0
  {
2199
0
    e1FillType = m_SubjFillType;
2200
0
    e1FillType2 = m_ClipFillType;
2201
0
  } else
2202
0
  {
2203
0
    e1FillType = m_ClipFillType;
2204
0
    e1FillType2 = m_SubjFillType;
2205
0
  }
2206
0
  if (e2->PolyTyp == ptSubject)
2207
0
  {
2208
0
    e2FillType = m_SubjFillType;
2209
0
    e2FillType2 = m_ClipFillType;
2210
0
  } else
2211
0
  {
2212
0
    e2FillType = m_ClipFillType;
2213
0
    e2FillType2 = m_SubjFillType;
2214
0
  }
2215
2216
0
  cInt e1Wc, e2Wc;
2217
0
  switch (e1FillType)
2218
0
  {
2219
0
    case pftPositive: e1Wc = e1->WindCnt; break;
2220
0
    case pftNegative: e1Wc = -e1->WindCnt; break;
2221
0
    default: e1Wc = Abs(e1->WindCnt);
2222
0
  }
2223
0
  switch(e2FillType)
2224
0
  {
2225
0
    case pftPositive: e2Wc = e2->WindCnt; break;
2226
0
    case pftNegative: e2Wc = -e2->WindCnt; break;
2227
0
    default: e2Wc = Abs(e2->WindCnt);
2228
0
  }
2229
2230
0
  if ( e1Contributing && e2Contributing )
2231
0
  {
2232
0
    if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
2233
0
      (e1->PolyTyp != e2->PolyTyp && m_ClipType != ctXor) )
2234
0
    {
2235
0
      AddLocalMaxPoly(e1, e2, Pt);
2236
0
    }
2237
0
    else
2238
0
    {
2239
0
      AddOutPt(e1, Pt);
2240
0
      AddOutPt(e2, Pt);
2241
0
      SwapSides( *e1 , *e2 );
2242
0
      SwapPolyIndexes( *e1 , *e2 );
2243
0
    }
2244
0
  }
2245
0
  else if ( e1Contributing )
2246
0
  {
2247
0
    if (e2Wc == 0 || e2Wc == 1)
2248
0
    {
2249
0
      AddOutPt(e1, Pt);
2250
0
      SwapSides(*e1, *e2);
2251
0
      SwapPolyIndexes(*e1, *e2);
2252
0
    }
2253
0
  }
2254
0
  else if ( e2Contributing )
2255
0
  {
2256
0
    if (e1Wc == 0 || e1Wc == 1)
2257
0
    {
2258
0
      AddOutPt(e2, Pt);
2259
0
      SwapSides(*e1, *e2);
2260
0
      SwapPolyIndexes(*e1, *e2);
2261
0
    }
2262
0
  }
2263
0
  else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
2264
0
  {
2265
    //neither edge is currently contributing ...
2266
2267
0
    cInt e1Wc2, e2Wc2;
2268
0
    switch (e1FillType2)
2269
0
    {
2270
0
      case pftPositive: e1Wc2 = e1->WindCnt2; break;
2271
0
      case pftNegative : e1Wc2 = -e1->WindCnt2; break;
2272
0
      default: e1Wc2 = Abs(e1->WindCnt2);
2273
0
    }
2274
0
    switch (e2FillType2)
2275
0
    {
2276
0
      case pftPositive: e2Wc2 = e2->WindCnt2; break;
2277
0
      case pftNegative: e2Wc2 = -e2->WindCnt2; break;
2278
0
      default: e2Wc2 = Abs(e2->WindCnt2);
2279
0
    }
2280
2281
0
    if (e1->PolyTyp != e2->PolyTyp)
2282
0
    {
2283
0
      AddLocalMinPoly(e1, e2, Pt);
2284
0
    }
2285
0
    else if (e1Wc == 1 && e2Wc == 1)
2286
0
      switch( m_ClipType ) {
2287
0
        case ctIntersection:
2288
0
          if (e1Wc2 > 0 && e2Wc2 > 0)
2289
0
            AddLocalMinPoly(e1, e2, Pt);
2290
0
          break;
2291
0
        case ctUnion:
2292
0
          if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
2293
0
            AddLocalMinPoly(e1, e2, Pt);
2294
0
          break;
2295
0
        case ctDifference:
2296
0
          if (((e1->PolyTyp == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
2297
0
              ((e1->PolyTyp == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
2298
0
                AddLocalMinPoly(e1, e2, Pt);
2299
0
          break;
2300
0
        case ctXor:
2301
0
          AddLocalMinPoly(e1, e2, Pt);
2302
0
      }
2303
0
    else
2304
0
      SwapSides( *e1, *e2 );
2305
0
  }
2306
0
}
2307
//------------------------------------------------------------------------------
2308
2309
void Clipper::SetHoleState(TEdge *e, OutRec *outrec)
2310
0
{
2311
0
  TEdge *e2 = e->PrevInAEL;
2312
0
  TEdge *eTmp = 0;
2313
0
  while (e2)
2314
0
  {
2315
0
    if (e2->OutIdx >= 0 && e2->WindDelta != 0)
2316
0
    {
2317
0
      if (!eTmp) eTmp = e2;
2318
0
      else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0;
2319
0
    }
2320
0
    e2 = e2->PrevInAEL;
2321
0
  }
2322
0
  if (!eTmp)
2323
0
  {
2324
0
    outrec->FirstLeft = 0;
2325
0
    outrec->IsHole = false;
2326
0
  }
2327
0
  else
2328
0
  {
2329
0
    outrec->FirstLeft = m_PolyOuts[eTmp->OutIdx];
2330
0
    outrec->IsHole = !outrec->FirstLeft->IsHole;
2331
0
  }
2332
0
}
2333
//------------------------------------------------------------------------------
2334
2335
OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2)
2336
0
{
2337
  //work out which polygon fragment has the correct hole state ...
2338
0
  if (!outRec1->BottomPt)
2339
0
    outRec1->BottomPt = GetBottomPt(outRec1->Pts);
2340
0
  if (!outRec2->BottomPt)
2341
0
    outRec2->BottomPt = GetBottomPt(outRec2->Pts);
2342
0
  OutPt *OutPt1 = outRec1->BottomPt;
2343
0
  OutPt *OutPt2 = outRec2->BottomPt;
2344
0
  if (OutPt1->Pt.Y > OutPt2->Pt.Y) return outRec1;
2345
0
  else if (OutPt1->Pt.Y < OutPt2->Pt.Y) return outRec2;
2346
0
  else if (OutPt1->Pt.X < OutPt2->Pt.X) return outRec1;
2347
0
  else if (OutPt1->Pt.X > OutPt2->Pt.X) return outRec2;
2348
0
  else if (OutPt1->Next == OutPt1) return outRec2;
2349
0
  else if (OutPt2->Next == OutPt2) return outRec1;
2350
0
  else if (FirstIsBottomPt(OutPt1, OutPt2)) return outRec1;
2351
0
  else return outRec2;
2352
0
}
2353
//------------------------------------------------------------------------------
2354
2355
bool OutRec1RightOfOutRec2(OutRec* outRec1, OutRec* outRec2)
2356
0
{
2357
0
  do
2358
0
  {
2359
0
    outRec1 = outRec1->FirstLeft;
2360
0
    if (outRec1 == outRec2) return true;
2361
0
  } while (outRec1);
2362
0
  return false;
2363
0
}
2364
//------------------------------------------------------------------------------
2365
2366
OutRec* Clipper::GetOutRec(int Idx)
2367
0
{
2368
0
  OutRec* outrec = m_PolyOuts[Idx];
2369
0
  while (outrec != m_PolyOuts[outrec->Idx])
2370
0
    outrec = m_PolyOuts[outrec->Idx];
2371
0
  return outrec;
2372
0
}
2373
//------------------------------------------------------------------------------
2374
2375
void Clipper::AppendPolygon(TEdge *e1, TEdge *e2)
2376
0
{
2377
  //get the start and ends of both output polygons ...
2378
0
  OutRec *outRec1 = m_PolyOuts[e1->OutIdx];
2379
0
  OutRec *outRec2 = m_PolyOuts[e2->OutIdx];
2380
2381
0
  OutRec *holeStateRec;
2382
0
  if (OutRec1RightOfOutRec2(outRec1, outRec2))
2383
0
    holeStateRec = outRec2;
2384
0
  else if (OutRec1RightOfOutRec2(outRec2, outRec1))
2385
0
    holeStateRec = outRec1;
2386
0
  else
2387
0
    holeStateRec = GetLowermostRec(outRec1, outRec2);
2388
2389
  //get the start and ends of both output polygons and
2390
  //join e2 poly onto e1 poly and delete pointers to e2 ...
2391
2392
0
  OutPt* p1_lft = outRec1->Pts;
2393
0
  OutPt* p1_rt = p1_lft->Prev;
2394
0
  OutPt* p2_lft = outRec2->Pts;
2395
0
  OutPt* p2_rt = p2_lft->Prev;
2396
2397
  //join e2 poly onto e1 poly and delete pointers to e2 ...
2398
0
  if(  e1->Side == esLeft )
2399
0
  {
2400
0
    if(  e2->Side == esLeft )
2401
0
    {
2402
      //z y x a b c
2403
0
      ReversePolyPtLinks(p2_lft);
2404
0
      p2_lft->Next = p1_lft;
2405
0
      p1_lft->Prev = p2_lft;
2406
0
      p1_rt->Next = p2_rt;
2407
0
      p2_rt->Prev = p1_rt;
2408
0
      outRec1->Pts = p2_rt;
2409
0
    } else
2410
0
    {
2411
      //x y z a b c
2412
0
      p2_rt->Next = p1_lft;
2413
0
      p1_lft->Prev = p2_rt;
2414
0
      p2_lft->Prev = p1_rt;
2415
0
      p1_rt->Next = p2_lft;
2416
0
      outRec1->Pts = p2_lft;
2417
0
    }
2418
0
  } else
2419
0
  {
2420
0
    if(  e2->Side == esRight )
2421
0
    {
2422
      //a b c z y x
2423
0
      ReversePolyPtLinks(p2_lft);
2424
0
      p1_rt->Next = p2_rt;
2425
0
      p2_rt->Prev = p1_rt;
2426
0
      p2_lft->Next = p1_lft;
2427
0
      p1_lft->Prev = p2_lft;
2428
0
    } else
2429
0
    {
2430
      //a b c x y z
2431
0
      p1_rt->Next = p2_lft;
2432
0
      p2_lft->Prev = p1_rt;
2433
0
      p1_lft->Prev = p2_rt;
2434
0
      p2_rt->Next = p1_lft;
2435
0
    }
2436
0
  }
2437
2438
0
  outRec1->BottomPt = 0;
2439
0
  if (holeStateRec == outRec2)
2440
0
  {
2441
0
    if (outRec2->FirstLeft != outRec1)
2442
0
      outRec1->FirstLeft = outRec2->FirstLeft;
2443
0
    outRec1->IsHole = outRec2->IsHole;
2444
0
  }
2445
0
  outRec2->Pts = 0;
2446
0
  outRec2->BottomPt = 0;
2447
0
  outRec2->FirstLeft = outRec1;
2448
2449
0
  int OKIdx = e1->OutIdx;
2450
0
  int ObsoleteIdx = e2->OutIdx;
2451
2452
0
  e1->OutIdx = Unassigned; //nb: safe because we only get here via AddLocalMaxPoly
2453
0
  e2->OutIdx = Unassigned;
2454
2455
0
  TEdge* e = m_ActiveEdges;
2456
0
  while( e )
2457
0
  {
2458
0
    if( e->OutIdx == ObsoleteIdx )
2459
0
    {
2460
0
      e->OutIdx = OKIdx;
2461
0
      e->Side = e1->Side;
2462
0
      break;
2463
0
    }
2464
0
    e = e->NextInAEL;
2465
0
  }
2466
2467
0
  outRec2->Idx = outRec1->Idx;
2468
0
}
2469
//------------------------------------------------------------------------------
2470
2471
OutPt* Clipper::AddOutPt(TEdge *e, const IntPoint &pt)
2472
0
{
2473
0
  if(  e->OutIdx < 0 )
2474
0
  {
2475
0
    OutRec *outRec = CreateOutRec();
2476
0
    outRec->IsOpen = (e->WindDelta == 0);
2477
0
    OutPt* newOp = new OutPt;
2478
0
    outRec->Pts = newOp;
2479
0
    newOp->Idx = outRec->Idx;
2480
0
    newOp->Pt = pt;
2481
0
    newOp->Next = newOp;
2482
0
    newOp->Prev = newOp;
2483
0
    if (!outRec->IsOpen)
2484
0
      SetHoleState(e, outRec);
2485
0
    e->OutIdx = outRec->Idx;
2486
0
    return newOp;
2487
0
  } else
2488
0
  {
2489
0
    OutRec *outRec = m_PolyOuts[e->OutIdx];
2490
    //OutRec.Pts is the 'Left-most' point & OutRec.Pts.Prev is the 'Right-most'
2491
0
    OutPt* op = outRec->Pts;
2492
2493
0
  bool ToFront = (e->Side == esLeft);
2494
0
  if (ToFront && (pt == op->Pt)) return op;
2495
0
    else if (!ToFront && (pt == op->Prev->Pt)) return op->Prev;
2496
2497
0
    OutPt* newOp = new OutPt;
2498
0
    newOp->Idx = outRec->Idx;
2499
0
    newOp->Pt = pt;
2500
0
    newOp->Next = op;
2501
0
    newOp->Prev = op->Prev;
2502
0
    newOp->Prev->Next = newOp;
2503
0
    op->Prev = newOp;
2504
0
    if (ToFront) outRec->Pts = newOp;
2505
0
    return newOp;
2506
0
  }
2507
0
}
2508
//------------------------------------------------------------------------------
2509
2510
OutPt* Clipper::GetLastOutPt(TEdge *e)
2511
0
{
2512
0
  OutRec *outRec = m_PolyOuts[e->OutIdx];
2513
0
  if (e->Side == esLeft)
2514
0
    return outRec->Pts;
2515
0
  else
2516
0
    return outRec->Pts->Prev;
2517
0
}
2518
//------------------------------------------------------------------------------
2519
2520
void Clipper::ProcessHorizontals()
2521
0
{
2522
0
  TEdge* horzEdge;
2523
0
  while (PopEdgeFromSEL(horzEdge))
2524
0
    ProcessHorizontal(horzEdge);
2525
0
}
2526
//------------------------------------------------------------------------------
2527
2528
inline bool IsMinima(TEdge *e)
2529
0
{
2530
0
  return e  && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e);
2531
0
}
2532
//------------------------------------------------------------------------------
2533
2534
inline bool IsMaxima(TEdge *e, const cInt Y)
2535
0
{
2536
0
  return e && e->Top.Y == Y && !e->NextInLML;
2537
0
}
2538
//------------------------------------------------------------------------------
2539
2540
inline bool IsIntermediate(TEdge *e, const cInt Y)
2541
0
{
2542
0
  return e->Top.Y == Y && e->NextInLML;
2543
0
}
2544
//------------------------------------------------------------------------------
2545
2546
TEdge *GetMaximaPair(TEdge *e)
2547
0
{
2548
0
  if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
2549
0
    return e->Next;
2550
0
  else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
2551
0
    return e->Prev;
2552
0
  else return 0;
2553
0
}
2554
//------------------------------------------------------------------------------
2555
2556
TEdge *GetMaximaPairEx(TEdge *e)
2557
0
{
2558
  //as GetMaximaPair() but returns 0 if MaxPair isn't in AEL (unless it's horizontal)
2559
0
  TEdge* result = GetMaximaPair(e);
2560
0
  if (result && (result->OutIdx == Skip ||
2561
0
    (result->NextInAEL == result->PrevInAEL && !IsHorizontal(*result)))) return 0;
2562
0
  return result;
2563
0
}
2564
//------------------------------------------------------------------------------
2565
2566
void Clipper::SwapPositionsInSEL(TEdge *Edge1, TEdge *Edge2)
2567
0
{
2568
0
  if(  !( Edge1->NextInSEL ) &&  !( Edge1->PrevInSEL ) ) return;
2569
0
  if(  !( Edge2->NextInSEL ) &&  !( Edge2->PrevInSEL ) ) return;
2570
2571
0
  if(  Edge1->NextInSEL == Edge2 )
2572
0
  {
2573
0
    TEdge* Next = Edge2->NextInSEL;
2574
0
    if( Next ) Next->PrevInSEL = Edge1;
2575
0
    TEdge* Prev = Edge1->PrevInSEL;
2576
0
    if( Prev ) Prev->NextInSEL = Edge2;
2577
0
    Edge2->PrevInSEL = Prev;
2578
0
    Edge2->NextInSEL = Edge1;
2579
0
    Edge1->PrevInSEL = Edge2;
2580
0
    Edge1->NextInSEL = Next;
2581
0
  }
2582
0
  else if(  Edge2->NextInSEL == Edge1 )
2583
0
  {
2584
0
    TEdge* Next = Edge1->NextInSEL;
2585
0
    if( Next ) Next->PrevInSEL = Edge2;
2586
0
    TEdge* Prev = Edge2->PrevInSEL;
2587
0
    if( Prev ) Prev->NextInSEL = Edge1;
2588
0
    Edge1->PrevInSEL = Prev;
2589
0
    Edge1->NextInSEL = Edge2;
2590
0
    Edge2->PrevInSEL = Edge1;
2591
0
    Edge2->NextInSEL = Next;
2592
0
  }
2593
0
  else
2594
0
  {
2595
0
    TEdge* Next = Edge1->NextInSEL;
2596
0
    TEdge* Prev = Edge1->PrevInSEL;
2597
0
    Edge1->NextInSEL = Edge2->NextInSEL;
2598
0
    if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1;
2599
0
    Edge1->PrevInSEL = Edge2->PrevInSEL;
2600
0
    if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1;
2601
0
    Edge2->NextInSEL = Next;
2602
0
    if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2;
2603
0
    Edge2->PrevInSEL = Prev;
2604
0
    if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2;
2605
0
  }
2606
2607
0
  if( !Edge1->PrevInSEL ) m_SortedEdges = Edge1;
2608
0
  else if( !Edge2->PrevInSEL ) m_SortedEdges = Edge2;
2609
0
}
2610
//------------------------------------------------------------------------------
2611
2612
TEdge* GetNextInAEL(TEdge *e, Direction dir)
2613
0
{
2614
0
  return dir == dLeftToRight ? e->NextInAEL : e->PrevInAEL;
2615
0
}
2616
//------------------------------------------------------------------------------
2617
2618
void GetHorzDirection(TEdge& HorzEdge, Direction& Dir, cInt& Left, cInt& Right)
2619
0
{
2620
0
  if (HorzEdge.Bot.X < HorzEdge.Top.X)
2621
0
  {
2622
0
    Left = HorzEdge.Bot.X;
2623
0
    Right = HorzEdge.Top.X;
2624
0
    Dir = dLeftToRight;
2625
0
  } else
2626
0
  {
2627
0
    Left = HorzEdge.Top.X;
2628
0
    Right = HorzEdge.Bot.X;
2629
0
    Dir = dRightToLeft;
2630
0
  }
2631
0
}
2632
//------------------------------------------------------------------------
2633
2634
/*******************************************************************************
2635
* Notes: Horizontal edges (HEs) at scanline intersections (ie at the Top or    *
2636
* Bottom of a scanbeam) are processed as if layered. The order in which HEs    *
2637
* are processed doesn't matter. HEs intersect with other HE Bot.Xs only [#]    *
2638
* (or they could intersect with Top.Xs only, ie EITHER Bot.Xs OR Top.Xs),      *
2639
* and with other non-horizontal edges [*]. Once these intersections are        *
2640
* processed, intermediate HEs then 'promote' the Edge above (NextInLML) into   *
2641
* the AEL. These 'promoted' edges may in turn intersect [%] with other HEs.    *
2642
*******************************************************************************/
2643
2644
void Clipper::ProcessHorizontal(TEdge *horzEdge)
2645
0
{
2646
0
  Direction dir;
2647
0
  cInt horzLeft, horzRight;
2648
0
  bool IsOpen = (horzEdge->WindDelta == 0);
2649
2650
0
  GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
2651
2652
0
  TEdge* eLastHorz = horzEdge, *eMaxPair = 0;
2653
0
  while (eLastHorz->NextInLML && IsHorizontal(*eLastHorz->NextInLML))
2654
0
    eLastHorz = eLastHorz->NextInLML;
2655
0
  if (!eLastHorz->NextInLML)
2656
0
    eMaxPair = GetMaximaPair(eLastHorz);
2657
2658
0
  MaximaList::const_iterator maxIt;
2659
0
  MaximaList::const_reverse_iterator maxRit;
2660
0
  if (m_Maxima.size() > 0)
2661
0
  {
2662
      //get the first maxima in range (X) ...
2663
0
      if (dir == dLeftToRight)
2664
0
      {
2665
0
          maxIt = m_Maxima.begin();
2666
0
          while (maxIt != m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++;
2667
0
          if (maxIt != m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
2668
0
              maxIt = m_Maxima.end();
2669
0
      }
2670
0
      else
2671
0
      {
2672
0
          maxRit = m_Maxima.rbegin();
2673
0
          while (maxRit != m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++;
2674
0
          if (maxRit != m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
2675
0
              maxRit = m_Maxima.rend();
2676
0
      }
2677
0
  }
2678
2679
0
  OutPt* op1 = 0;
2680
2681
0
  for (;;) //loop through consec. horizontal edges
2682
0
  {
2683
2684
0
    bool IsLastHorz = (horzEdge == eLastHorz);
2685
0
    TEdge* e = GetNextInAEL(horzEdge, dir);
2686
0
    while(e)
2687
0
    {
2688
2689
        //this code block inserts extra coords into horizontal edges (in output
2690
        //polygons) whereever maxima touch these horizontal edges. This helps
2691
        //'simplifying' polygons (ie if the Simplify property is set).
2692
0
        if (m_Maxima.size() > 0)
2693
0
        {
2694
0
            if (dir == dLeftToRight)
2695
0
            {
2696
0
                while (maxIt != m_Maxima.end() && *maxIt < e->Curr.X)
2697
0
                {
2698
0
                  if (horzEdge->OutIdx >= 0 && !IsOpen)
2699
0
                    AddOutPt(horzEdge, IntPoint(*maxIt, horzEdge->Bot.Y));
2700
0
                  maxIt++;
2701
0
                }
2702
0
            }
2703
0
            else
2704
0
            {
2705
0
                while (maxRit != m_Maxima.rend() && *maxRit > e->Curr.X)
2706
0
                {
2707
0
                  if (horzEdge->OutIdx >= 0 && !IsOpen)
2708
0
                    AddOutPt(horzEdge, IntPoint(*maxRit, horzEdge->Bot.Y));
2709
0
                  maxRit++;
2710
0
                }
2711
0
            }
2712
0
        };
2713
2714
0
        if ((dir == dLeftToRight && e->Curr.X > horzRight) ||
2715
0
      (dir == dRightToLeft && e->Curr.X < horzLeft)) break;
2716
2717
    //Also break if we've got to the end of an intermediate horizontal edge ...
2718
    //nb: Smaller Dx's are to the right of larger Dx's ABOVE the horizontal.
2719
0
    if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
2720
0
      e->Dx < horzEdge->NextInLML->Dx) break;
2721
2722
0
    if (horzEdge->OutIdx >= 0 && !IsOpen)  //note: may be done multiple times
2723
0
    {
2724
#ifdef use_xyz
2725
      if (dir == dLeftToRight) SetZ(e->Curr, *horzEdge, *e);
2726
      else SetZ(e->Curr, *e, *horzEdge);
2727
#endif
2728
0
      op1 = AddOutPt(horzEdge, e->Curr);
2729
0
      TEdge* eNextHorz = m_SortedEdges;
2730
0
      while (eNextHorz)
2731
0
      {
2732
0
        if (eNextHorz->OutIdx >= 0 &&
2733
0
          HorzSegmentsOverlap(horzEdge->Bot.X,
2734
0
          horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
2735
0
        {
2736
0
                    OutPt* op2 = GetLastOutPt(eNextHorz);
2737
0
                    AddJoin(op2, op1, eNextHorz->Top);
2738
0
        }
2739
0
        eNextHorz = eNextHorz->NextInSEL;
2740
0
      }
2741
0
      AddGhostJoin(op1, horzEdge->Bot);
2742
0
    }
2743
2744
    //OK, so far we're still in range of the horizontal Edge  but make sure
2745
        //we're at the last of consec. horizontals when matching with eMaxPair
2746
0
        if(e == eMaxPair && IsLastHorz)
2747
0
        {
2748
0
          if (horzEdge->OutIdx >= 0)
2749
0
            AddLocalMaxPoly(horzEdge, eMaxPair, horzEdge->Top);
2750
0
          DeleteFromAEL(horzEdge);
2751
0
          DeleteFromAEL(eMaxPair);
2752
0
          return;
2753
0
        }
2754
2755
0
    if(dir == dLeftToRight)
2756
0
        {
2757
0
          IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
2758
0
          IntersectEdges(horzEdge, e, Pt);
2759
0
        }
2760
0
        else
2761
0
        {
2762
0
          IntPoint Pt = IntPoint(e->Curr.X, horzEdge->Curr.Y);
2763
0
          IntersectEdges( e, horzEdge, Pt);
2764
0
        }
2765
0
        TEdge* eNext = GetNextInAEL(e, dir);
2766
0
        SwapPositionsInAEL( horzEdge, e );
2767
0
        e = eNext;
2768
0
    } //end while(e)
2769
2770
  //Break out of loop if HorzEdge.NextInLML is not also horizontal ...
2771
0
  if (!horzEdge->NextInLML || !IsHorizontal(*horzEdge->NextInLML)) break;
2772
2773
0
  UpdateEdgeIntoAEL(horzEdge);
2774
0
    if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Bot);
2775
0
    GetHorzDirection(*horzEdge, dir, horzLeft, horzRight);
2776
2777
0
  } //end for (;;)
2778
2779
0
  if (horzEdge->OutIdx >= 0 && !op1)
2780
0
  {
2781
0
      op1 = GetLastOutPt(horzEdge);
2782
0
      TEdge* eNextHorz = m_SortedEdges;
2783
0
      while (eNextHorz)
2784
0
      {
2785
0
          if (eNextHorz->OutIdx >= 0 &&
2786
0
              HorzSegmentsOverlap(horzEdge->Bot.X,
2787
0
              horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
2788
0
          {
2789
0
              OutPt* op2 = GetLastOutPt(eNextHorz);
2790
0
              AddJoin(op2, op1, eNextHorz->Top);
2791
0
          }
2792
0
          eNextHorz = eNextHorz->NextInSEL;
2793
0
      }
2794
0
      AddGhostJoin(op1, horzEdge->Top);
2795
0
  }
2796
2797
0
  if (horzEdge->NextInLML)
2798
0
  {
2799
0
    if(horzEdge->OutIdx >= 0)
2800
0
    {
2801
0
      op1 = AddOutPt( horzEdge, horzEdge->Top);
2802
0
      UpdateEdgeIntoAEL(horzEdge);
2803
0
      if (horzEdge->WindDelta == 0) return;
2804
      //nb: HorzEdge is no longer horizontal here
2805
0
      TEdge* ePrev = horzEdge->PrevInAEL;
2806
0
      TEdge* eNext = horzEdge->NextInAEL;
2807
0
      if (ePrev && ePrev->Curr.X == horzEdge->Bot.X &&
2808
0
        ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 &&
2809
0
        (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
2810
0
        SlopesEqual(*horzEdge, *ePrev, m_UseFullRange)))
2811
0
      {
2812
0
        OutPt* op2 = AddOutPt(ePrev, horzEdge->Bot);
2813
0
        AddJoin(op1, op2, horzEdge->Top);
2814
0
      }
2815
0
      else if (eNext && eNext->Curr.X == horzEdge->Bot.X &&
2816
0
        eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 &&
2817
0
        eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
2818
0
        SlopesEqual(*horzEdge, *eNext, m_UseFullRange))
2819
0
      {
2820
0
        OutPt* op2 = AddOutPt(eNext, horzEdge->Bot);
2821
0
        AddJoin(op1, op2, horzEdge->Top);
2822
0
      }
2823
0
    }
2824
0
    else
2825
0
      UpdateEdgeIntoAEL(horzEdge);
2826
0
  }
2827
0
  else
2828
0
  {
2829
0
    if (horzEdge->OutIdx >= 0) AddOutPt(horzEdge, horzEdge->Top);
2830
0
    DeleteFromAEL(horzEdge);
2831
0
  }
2832
0
}
2833
//------------------------------------------------------------------------------
2834
2835
bool Clipper::ProcessIntersections(const cInt topY)
2836
0
{
2837
0
  if( !m_ActiveEdges ) return true;
2838
0
  try {
2839
0
    BuildIntersectList(topY);
2840
0
    size_t IlSize = m_IntersectList.size();
2841
0
    if (IlSize == 0) return true;
2842
0
    if (IlSize == 1 || FixupIntersectionOrder()) ProcessIntersectList();
2843
0
    else return false;
2844
0
  }
2845
0
  catch(...)
2846
0
  {
2847
0
    m_SortedEdges = 0;
2848
0
    DisposeIntersectNodes();
2849
0
    throw clipperException("ProcessIntersections error");
2850
0
  }
2851
0
  m_SortedEdges = 0;
2852
0
  return true;
2853
0
}
2854
//------------------------------------------------------------------------------
2855
2856
void Clipper::DisposeIntersectNodes()
2857
0
{
2858
0
  for (size_t i = 0; i < m_IntersectList.size(); ++i )
2859
0
    delete m_IntersectList[i];
2860
0
  m_IntersectList.clear();
2861
0
}
2862
//------------------------------------------------------------------------------
2863
2864
void Clipper::BuildIntersectList(const cInt topY)
2865
0
{
2866
0
  if ( !m_ActiveEdges ) return;
2867
2868
  //prepare for sorting ...
2869
0
  TEdge* e = m_ActiveEdges;
2870
0
  m_SortedEdges = e;
2871
0
  while( e )
2872
0
  {
2873
0
    e->PrevInSEL = e->PrevInAEL;
2874
0
    e->NextInSEL = e->NextInAEL;
2875
0
    e->Curr.X = TopX( *e, topY );
2876
0
    e = e->NextInAEL;
2877
0
  }
2878
2879
  //bubblesort ...
2880
0
  bool isModified;
2881
0
  do
2882
0
  {
2883
0
    isModified = false;
2884
0
    e = m_SortedEdges;
2885
0
    while( e->NextInSEL )
2886
0
    {
2887
0
      TEdge *eNext = e->NextInSEL;
2888
0
      IntPoint Pt;
2889
0
      if(e->Curr.X > eNext->Curr.X)
2890
0
      {
2891
0
        IntersectPoint(*e, *eNext, Pt);
2892
0
        if (Pt.Y < topY) Pt = IntPoint(TopX(*e, topY), topY);
2893
0
        IntersectNode * newNode = new IntersectNode;
2894
0
        newNode->Edge1 = e;
2895
0
        newNode->Edge2 = eNext;
2896
0
        newNode->Pt = Pt;
2897
0
        m_IntersectList.push_back(newNode);
2898
2899
0
        SwapPositionsInSEL(e, eNext);
2900
0
        isModified = true;
2901
0
      }
2902
0
      else
2903
0
        e = eNext;
2904
0
    }
2905
0
    if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0;
2906
0
    else break;
2907
0
  }
2908
0
  while ( isModified );
2909
0
  m_SortedEdges = 0; //important
2910
0
}
2911
//------------------------------------------------------------------------------
2912
2913
2914
void Clipper::ProcessIntersectList()
2915
0
{
2916
0
  for (size_t i = 0; i < m_IntersectList.size(); ++i)
2917
0
  {
2918
0
    IntersectNode* iNode = m_IntersectList[i];
2919
0
    {
2920
0
      IntersectEdges( iNode->Edge1, iNode->Edge2, iNode->Pt);
2921
0
      SwapPositionsInAEL( iNode->Edge1 , iNode->Edge2 );
2922
0
    }
2923
0
    delete iNode;
2924
0
  }
2925
0
  m_IntersectList.clear();
2926
0
}
2927
//------------------------------------------------------------------------------
2928
2929
bool IntersectListSort(IntersectNode* node1, IntersectNode* node2)
2930
0
{
2931
0
  return node2->Pt.Y < node1->Pt.Y;
2932
0
}
2933
//------------------------------------------------------------------------------
2934
2935
inline bool EdgesAdjacent(const IntersectNode &inode)
2936
0
{
2937
0
  return (inode.Edge1->NextInSEL == inode.Edge2) ||
2938
0
    (inode.Edge1->PrevInSEL == inode.Edge2);
2939
0
}
2940
//------------------------------------------------------------------------------
2941
2942
bool Clipper::FixupIntersectionOrder()
2943
0
{
2944
  //pre-condition: intersections are sorted Bottom-most first.
2945
  //Now it's crucial that intersections are made only between adjacent edges,
2946
  //so to ensure this the order of intersections may need adjusting ...
2947
0
  CopyAELToSEL();
2948
0
  std::sort(m_IntersectList.begin(), m_IntersectList.end(), IntersectListSort);
2949
0
  size_t cnt = m_IntersectList.size();
2950
0
  for (size_t i = 0; i < cnt; ++i)
2951
0
  {
2952
0
    if (!EdgesAdjacent(*m_IntersectList[i]))
2953
0
    {
2954
0
      size_t j = i + 1;
2955
0
      while (j < cnt && !EdgesAdjacent(*m_IntersectList[j])) j++;
2956
0
      if (j == cnt)  return false;
2957
0
      std::swap(m_IntersectList[i], m_IntersectList[j]);
2958
0
    }
2959
0
    SwapPositionsInSEL(m_IntersectList[i]->Edge1, m_IntersectList[i]->Edge2);
2960
0
  }
2961
0
  return true;
2962
0
}
2963
//------------------------------------------------------------------------------
2964
2965
void Clipper::DoMaxima(TEdge *e)
2966
0
{
2967
0
  TEdge* eMaxPair = GetMaximaPairEx(e);
2968
0
  if (!eMaxPair)
2969
0
  {
2970
0
    if (e->OutIdx >= 0)
2971
0
      AddOutPt(e, e->Top);
2972
0
    DeleteFromAEL(e);
2973
0
    return;
2974
0
  }
2975
2976
0
  TEdge* eNext = e->NextInAEL;
2977
0
  while(eNext && eNext != eMaxPair)
2978
0
  {
2979
0
    IntersectEdges(e, eNext, e->Top);
2980
0
    SwapPositionsInAEL(e, eNext);
2981
0
    eNext = e->NextInAEL;
2982
0
  }
2983
2984
0
  if(e->OutIdx == Unassigned && eMaxPair->OutIdx == Unassigned)
2985
0
  {
2986
0
    DeleteFromAEL(e);
2987
0
    DeleteFromAEL(eMaxPair);
2988
0
  }
2989
0
  else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
2990
0
  {
2991
0
    if (e->OutIdx >= 0) AddLocalMaxPoly(e, eMaxPair, e->Top);
2992
0
    DeleteFromAEL(e);
2993
0
    DeleteFromAEL(eMaxPair);
2994
0
  }
2995
0
#ifdef use_lines
2996
0
  else if (e->WindDelta == 0)
2997
0
  {
2998
0
    if (e->OutIdx >= 0)
2999
0
    {
3000
0
      AddOutPt(e, e->Top);
3001
0
      e->OutIdx = Unassigned;
3002
0
    }
3003
0
    DeleteFromAEL(e);
3004
3005
0
    if (eMaxPair->OutIdx >= 0)
3006
0
    {
3007
0
      AddOutPt(eMaxPair, e->Top);
3008
0
      eMaxPair->OutIdx = Unassigned;
3009
0
    }
3010
0
    DeleteFromAEL(eMaxPair);
3011
0
  }
3012
0
#endif
3013
0
  else throw clipperException("DoMaxima error");
3014
0
}
3015
//------------------------------------------------------------------------------
3016
3017
void Clipper::ProcessEdgesAtTopOfScanbeam(const cInt topY)
3018
0
{
3019
0
  TEdge* e = m_ActiveEdges;
3020
0
  while( e )
3021
0
  {
3022
    //1. process maxima, treating them as if they're 'bent' horizontal edges,
3023
    //   but exclude maxima with horizontal edges. nb: e can't be a horizontal.
3024
0
    bool IsMaximaEdge = IsMaxima(e, topY);
3025
3026
0
    if(IsMaximaEdge)
3027
0
    {
3028
0
      TEdge* eMaxPair = GetMaximaPairEx(e);
3029
0
      IsMaximaEdge = (!eMaxPair || !IsHorizontal(*eMaxPair));
3030
0
    }
3031
3032
0
    if(IsMaximaEdge)
3033
0
    {
3034
0
      if (m_StrictSimple) m_Maxima.push_back(e->Top.X);
3035
0
      TEdge* ePrev = e->PrevInAEL;
3036
0
      DoMaxima(e);
3037
0
      if( !ePrev ) e = m_ActiveEdges;
3038
0
      else e = ePrev->NextInAEL;
3039
0
    }
3040
0
    else
3041
0
    {
3042
      //2. promote horizontal edges, otherwise update Curr.X and Curr.Y ...
3043
0
      if (IsIntermediate(e, topY) && IsHorizontal(*e->NextInLML))
3044
0
      {
3045
0
        UpdateEdgeIntoAEL(e);
3046
0
        if (e->OutIdx >= 0)
3047
0
          AddOutPt(e, e->Bot);
3048
0
        AddEdgeToSEL(e);
3049
0
      }
3050
0
      else
3051
0
      {
3052
0
        e->Curr.X = TopX( *e, topY );
3053
0
        e->Curr.Y = topY;
3054
#ifdef use_xyz
3055
    e->Curr.Z = topY == e->Top.Y ? e->Top.Z : (topY == e->Bot.Y ? e->Bot.Z : 0);
3056
#endif
3057
0
    }
3058
3059
      //When StrictlySimple and 'e' is being touched by another edge, then
3060
      //make sure both edges have a vertex here ...
3061
0
      if (m_StrictSimple)
3062
0
      {
3063
0
        TEdge* ePrev = e->PrevInAEL;
3064
0
        if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
3065
0
          (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
3066
0
        {
3067
0
          IntPoint pt = e->Curr;
3068
#ifdef use_xyz
3069
          SetZ(pt, *ePrev, *e);
3070
#endif
3071
0
          OutPt* op = AddOutPt(ePrev, pt);
3072
0
          OutPt* op2 = AddOutPt(e, pt);
3073
0
          AddJoin(op, op2, pt); //StrictlySimple (type-3) join
3074
0
        }
3075
0
      }
3076
3077
0
      e = e->NextInAEL;
3078
0
    }
3079
0
  }
3080
3081
  //3. Process horizontals at the Top of the scanbeam ...
3082
0
  m_Maxima.sort();
3083
0
  ProcessHorizontals();
3084
0
  m_Maxima.clear();
3085
3086
  //4. Promote intermediate vertices ...
3087
0
  e = m_ActiveEdges;
3088
0
  while(e)
3089
0
  {
3090
0
    if(IsIntermediate(e, topY))
3091
0
    {
3092
0
      OutPt* op = 0;
3093
0
      if( e->OutIdx >= 0 )
3094
0
        op = AddOutPt(e, e->Top);
3095
0
      UpdateEdgeIntoAEL(e);
3096
3097
      //if output polygons share an edge, they'll need joining later ...
3098
0
      TEdge* ePrev = e->PrevInAEL;
3099
0
      TEdge* eNext = e->NextInAEL;
3100
0
      if (ePrev && ePrev->Curr.X == e->Bot.X &&
3101
0
        ePrev->Curr.Y == e->Bot.Y && op &&
3102
0
        ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
3103
0
        SlopesEqual(e->Curr, e->Top, ePrev->Curr, ePrev->Top, m_UseFullRange) &&
3104
0
        (e->WindDelta != 0) && (ePrev->WindDelta != 0))
3105
0
      {
3106
0
        OutPt* op2 = AddOutPt(ePrev, e->Bot);
3107
0
        AddJoin(op, op2, e->Top);
3108
0
      }
3109
0
      else if (eNext && eNext->Curr.X == e->Bot.X &&
3110
0
        eNext->Curr.Y == e->Bot.Y && op &&
3111
0
        eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
3112
0
        SlopesEqual(e->Curr, e->Top, eNext->Curr, eNext->Top, m_UseFullRange) &&
3113
0
        (e->WindDelta != 0) && (eNext->WindDelta != 0))
3114
0
      {
3115
0
        OutPt* op2 = AddOutPt(eNext, e->Bot);
3116
0
        AddJoin(op, op2, e->Top);
3117
0
      }
3118
0
    }
3119
0
    e = e->NextInAEL;
3120
0
  }
3121
0
}
3122
//------------------------------------------------------------------------------
3123
3124
void Clipper::FixupOutPolyline(OutRec &outrec)
3125
0
{
3126
0
  OutPt *pp = outrec.Pts;
3127
0
  OutPt *lastPP = pp->Prev;
3128
0
  while (pp != lastPP)
3129
0
  {
3130
0
    pp = pp->Next;
3131
0
    if (pp->Pt == pp->Prev->Pt)
3132
0
    {
3133
0
      if (pp == lastPP) lastPP = pp->Prev;
3134
0
      OutPt *tmpPP = pp->Prev;
3135
0
      tmpPP->Next = pp->Next;
3136
0
      pp->Next->Prev = tmpPP;
3137
0
      delete pp;
3138
0
      pp = tmpPP;
3139
0
    }
3140
0
  }
3141
3142
0
  if (pp == pp->Prev)
3143
0
  {
3144
0
    DisposeOutPts(pp);
3145
0
    outrec.Pts = 0;
3146
0
    return;
3147
0
  }
3148
0
}
3149
//------------------------------------------------------------------------------
3150
3151
void Clipper::FixupOutPolygon(OutRec &outrec)
3152
0
{
3153
    //FixupOutPolygon() - removes duplicate points and simplifies consecutive
3154
    //parallel edges by removing the middle vertex.
3155
0
    OutPt *lastOK = 0;
3156
0
    outrec.BottomPt = 0;
3157
0
    OutPt *pp = outrec.Pts;
3158
0
    bool preserveCol = m_PreserveCollinear || m_StrictSimple;
3159
3160
0
    for (;;)
3161
0
    {
3162
0
        if (pp->Prev == pp || pp->Prev == pp->Next)
3163
0
        {
3164
0
            DisposeOutPts(pp);
3165
0
            outrec.Pts = 0;
3166
0
            return;
3167
0
        }
3168
3169
        //test for duplicate points and collinear edges ...
3170
0
        if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
3171
0
            (SlopesEqual(pp->Prev->Pt, pp->Pt, pp->Next->Pt, m_UseFullRange) &&
3172
0
            (!preserveCol || !Pt2IsBetweenPt1AndPt3(pp->Prev->Pt, pp->Pt, pp->Next->Pt))))
3173
0
        {
3174
0
            lastOK = 0;
3175
0
            OutPt *tmp = pp;
3176
0
            pp->Prev->Next = pp->Next;
3177
0
            pp->Next->Prev = pp->Prev;
3178
0
            pp = pp->Prev;
3179
0
            delete tmp;
3180
0
        }
3181
0
        else if (pp == lastOK) break;
3182
0
        else
3183
0
        {
3184
0
            if (!lastOK) lastOK = pp;
3185
0
            pp = pp->Next;
3186
0
        }
3187
0
    }
3188
0
    outrec.Pts = pp;
3189
0
}
3190
//------------------------------------------------------------------------------
3191
3192
int PointCount(OutPt *Pts)
3193
0
{
3194
0
    if (!Pts) return 0;
3195
0
    int result = 0;
3196
0
    OutPt* p = Pts;
3197
0
    do
3198
0
    {
3199
0
        result++;
3200
0
        p = p->Next;
3201
0
    }
3202
0
    while (p != Pts);
3203
0
    return result;
3204
0
}
3205
//------------------------------------------------------------------------------
3206
3207
void Clipper::BuildResult(Paths &polys)
3208
0
{
3209
0
  polys.reserve(m_PolyOuts.size());
3210
0
  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
3211
0
  {
3212
0
    if (!m_PolyOuts[i]->Pts) continue;
3213
0
    Path pg;
3214
0
    OutPt* p = m_PolyOuts[i]->Pts->Prev;
3215
0
    int cnt = PointCount(p);
3216
0
    if (cnt < 2) continue;
3217
0
    pg.reserve(cnt);
3218
0
    for (int j = 0; j < cnt; ++j)
3219
0
    {
3220
0
      pg.push_back(p->Pt);
3221
0
      p = p->Prev;
3222
0
    }
3223
0
    polys.push_back(pg);
3224
0
  }
3225
0
}
3226
//------------------------------------------------------------------------------
3227
3228
void Clipper::BuildResult2(PolyTree& polytree)
3229
0
{
3230
0
    polytree.Clear();
3231
0
    polytree.AllNodes.reserve(m_PolyOuts.size());
3232
    //add each output polygon/contour to polytree ...
3233
0
    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++)
3234
0
    {
3235
0
        OutRec* outRec = m_PolyOuts[i];
3236
0
        int cnt = PointCount(outRec->Pts);
3237
0
        if ((outRec->IsOpen && cnt < 2) || (!outRec->IsOpen && cnt < 3)) continue;
3238
0
        FixHoleLinkage(*outRec);
3239
0
        PolyNode* pn = new PolyNode();
3240
        //nb: polytree takes ownership of all the PolyNodes
3241
0
        polytree.AllNodes.push_back(pn);
3242
0
        outRec->PolyNd = pn;
3243
0
        pn->Parent = 0;
3244
0
        pn->Index = 0;
3245
0
        pn->Contour.reserve(cnt);
3246
0
        OutPt *op = outRec->Pts->Prev;
3247
0
        for (int j = 0; j < cnt; j++)
3248
0
        {
3249
0
            pn->Contour.push_back(op->Pt);
3250
0
            op = op->Prev;
3251
0
        }
3252
0
    }
3253
3254
    //fixup PolyNode links etc ...
3255
0
    polytree.Childs.reserve(m_PolyOuts.size());
3256
0
    for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); i++)
3257
0
    {
3258
0
        OutRec* outRec = m_PolyOuts[i];
3259
0
        if (!outRec->PolyNd) continue;
3260
0
        if (outRec->IsOpen)
3261
0
        {
3262
0
          outRec->PolyNd->m_IsOpen = true;
3263
0
          polytree.AddChild(*outRec->PolyNd);
3264
0
        }
3265
0
        else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd)
3266
0
          outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd);
3267
0
        else
3268
0
          polytree.AddChild(*outRec->PolyNd);
3269
0
    }
3270
0
}
3271
//------------------------------------------------------------------------------
3272
3273
void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2)
3274
0
{
3275
  //just swap the contents (because fIntersectNodes is a single-linked-list)
3276
0
  IntersectNode inode = int1; //gets a copy of Int1
3277
0
  int1.Edge1 = int2.Edge1;
3278
0
  int1.Edge2 = int2.Edge2;
3279
0
  int1.Pt = int2.Pt;
3280
0
  int2.Edge1 = inode.Edge1;
3281
0
  int2.Edge2 = inode.Edge2;
3282
0
  int2.Pt = inode.Pt;
3283
0
}
3284
//------------------------------------------------------------------------------
3285
3286
inline bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2)
3287
0
{
3288
0
  if (e2.Curr.X == e1.Curr.X)
3289
0
  {
3290
0
    if (e2.Top.Y > e1.Top.Y)
3291
0
      return e2.Top.X < TopX(e1, e2.Top.Y);
3292
0
      else return e1.Top.X > TopX(e2, e1.Top.Y);
3293
0
  }
3294
0
  else return e2.Curr.X < e1.Curr.X;
3295
0
}
3296
//------------------------------------------------------------------------------
3297
3298
bool GetOverlap(const cInt a1, const cInt a2, const cInt b1, const cInt b2,
3299
    cInt& Left, cInt& Right)
3300
0
{
3301
0
  if (a1 < a2)
3302
0
  {
3303
0
    if (b1 < b2) {Left = std::max(a1,b1); Right = std::min(a2,b2);}
3304
0
    else {Left = std::max(a1,b2); Right = std::min(a2,b1);}
3305
0
  }
3306
0
  else
3307
0
  {
3308
0
    if (b1 < b2) {Left = std::max(a2,b1); Right = std::min(a1,b2);}
3309
0
    else {Left = std::max(a2,b2); Right = std::min(a1,b1);}
3310
0
  }
3311
0
  return Left < Right;
3312
0
}
3313
//------------------------------------------------------------------------------
3314
3315
inline void UpdateOutPtIdxs(OutRec& outrec)
3316
0
{
3317
0
  OutPt* op = outrec.Pts;
3318
0
  do
3319
0
  {
3320
0
    op->Idx = outrec.Idx;
3321
0
    op = op->Prev;
3322
0
  }
3323
0
  while(op != outrec.Pts);
3324
0
}
3325
//------------------------------------------------------------------------------
3326
3327
void Clipper::InsertEdgeIntoAEL(TEdge *edge, TEdge* startEdge)
3328
0
{
3329
0
  if(!m_ActiveEdges)
3330
0
  {
3331
0
    edge->PrevInAEL = 0;
3332
0
    edge->NextInAEL = 0;
3333
0
    m_ActiveEdges = edge;
3334
0
  }
3335
0
  else if(!startEdge && E2InsertsBeforeE1(*m_ActiveEdges, *edge))
3336
0
  {
3337
0
      edge->PrevInAEL = 0;
3338
0
      edge->NextInAEL = m_ActiveEdges;
3339
0
      m_ActiveEdges->PrevInAEL = edge;
3340
0
      m_ActiveEdges = edge;
3341
0
  }
3342
0
  else
3343
0
  {
3344
0
    if(!startEdge) startEdge = m_ActiveEdges;
3345
0
    while(startEdge->NextInAEL  &&
3346
0
      !E2InsertsBeforeE1(*startEdge->NextInAEL , *edge))
3347
0
        startEdge = startEdge->NextInAEL;
3348
0
    edge->NextInAEL = startEdge->NextInAEL;
3349
0
    if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge;
3350
0
    edge->PrevInAEL = startEdge;
3351
0
    startEdge->NextInAEL = edge;
3352
0
  }
3353
0
}
3354
//----------------------------------------------------------------------
3355
3356
OutPt* DupOutPt(OutPt* outPt, bool InsertAfter)
3357
0
{
3358
0
  OutPt* result = new OutPt;
3359
0
  result->Pt = outPt->Pt;
3360
0
  result->Idx = outPt->Idx;
3361
0
  if (InsertAfter)
3362
0
  {
3363
0
    result->Next = outPt->Next;
3364
0
    result->Prev = outPt;
3365
0
    outPt->Next->Prev = result;
3366
0
    outPt->Next = result;
3367
0
  }
3368
0
  else
3369
0
  {
3370
0
    result->Prev = outPt->Prev;
3371
0
    result->Next = outPt;
3372
0
    outPt->Prev->Next = result;
3373
0
    outPt->Prev = result;
3374
0
  }
3375
0
  return result;
3376
0
}
3377
//------------------------------------------------------------------------------
3378
3379
bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
3380
  const IntPoint Pt, bool DiscardLeft)
3381
0
{
3382
0
  Direction Dir1 = (op1->Pt.X > op1b->Pt.X ? dRightToLeft : dLeftToRight);
3383
0
  Direction Dir2 = (op2->Pt.X > op2b->Pt.X ? dRightToLeft : dLeftToRight);
3384
0
  if (Dir1 == Dir2) return false;
3385
3386
  //When DiscardLeft, we want Op1b to be on the Left of Op1, otherwise we
3387
  //want Op1b to be on the Right. (And likewise with Op2 and Op2b.)
3388
  //So, to facilitate this while inserting Op1b and Op2b ...
3389
  //when DiscardLeft, make sure we're AT or RIGHT of Pt before adding Op1b,
3390
  //otherwise make sure we're AT or LEFT of Pt. (Likewise with Op2b.)
3391
0
  if (Dir1 == dLeftToRight)
3392
0
  {
3393
0
    while (op1->Next->Pt.X <= Pt.X &&
3394
0
      op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
3395
0
        op1 = op1->Next;
3396
0
    if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
3397
0
    op1b = DupOutPt(op1, !DiscardLeft);
3398
0
    if (op1b->Pt != Pt)
3399
0
    {
3400
0
      op1 = op1b;
3401
0
      op1->Pt = Pt;
3402
0
      op1b = DupOutPt(op1, !DiscardLeft);
3403
0
    }
3404
0
  }
3405
0
  else
3406
0
  {
3407
0
    while (op1->Next->Pt.X >= Pt.X &&
3408
0
      op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
3409
0
        op1 = op1->Next;
3410
0
    if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
3411
0
    op1b = DupOutPt(op1, DiscardLeft);
3412
0
    if (op1b->Pt != Pt)
3413
0
    {
3414
0
      op1 = op1b;
3415
0
      op1->Pt = Pt;
3416
0
      op1b = DupOutPt(op1, DiscardLeft);
3417
0
    }
3418
0
  }
3419
3420
0
  if (Dir2 == dLeftToRight)
3421
0
  {
3422
0
    while (op2->Next->Pt.X <= Pt.X &&
3423
0
      op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
3424
0
        op2 = op2->Next;
3425
0
    if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
3426
0
    op2b = DupOutPt(op2, !DiscardLeft);
3427
0
    if (op2b->Pt != Pt)
3428
0
    {
3429
0
      op2 = op2b;
3430
0
      op2->Pt = Pt;
3431
0
      op2b = DupOutPt(op2, !DiscardLeft);
3432
0
    };
3433
0
  } else
3434
0
  {
3435
0
    while (op2->Next->Pt.X >= Pt.X &&
3436
0
      op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
3437
0
        op2 = op2->Next;
3438
0
    if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
3439
0
    op2b = DupOutPt(op2, DiscardLeft);
3440
0
    if (op2b->Pt != Pt)
3441
0
    {
3442
0
      op2 = op2b;
3443
0
      op2->Pt = Pt;
3444
0
      op2b = DupOutPt(op2, DiscardLeft);
3445
0
    };
3446
0
  };
3447
3448
0
  if ((Dir1 == dLeftToRight) == DiscardLeft)
3449
0
  {
3450
0
    op1->Prev = op2;
3451
0
    op2->Next = op1;
3452
0
    op1b->Next = op2b;
3453
0
    op2b->Prev = op1b;
3454
0
  }
3455
0
  else
3456
0
  {
3457
0
    op1->Next = op2;
3458
0
    op2->Prev = op1;
3459
0
    op1b->Prev = op2b;
3460
0
    op2b->Next = op1b;
3461
0
  }
3462
0
  return true;
3463
0
}
3464
//------------------------------------------------------------------------------
3465
3466
bool Clipper::JoinPoints(Join *j, OutRec* outRec1, OutRec* outRec2)
3467
0
{
3468
0
  OutPt *op1 = j->OutPt1, *op1b;
3469
0
  OutPt *op2 = j->OutPt2, *op2b;
3470
3471
  //There are 3 kinds of joins for output polygons ...
3472
  //1. Horizontal joins where Join.OutPt1 & Join.OutPt2 are vertices anywhere
3473
  //along (horizontal) collinear edges (& Join.OffPt is on the same horizontal).
3474
  //2. Non-horizontal joins where Join.OutPt1 & Join.OutPt2 are at the same
3475
  //location at the Bottom of the overlapping segment (& Join.OffPt is above).
3476
  //3. StrictSimple joins where edges touch but are not collinear and where
3477
  //Join.OutPt1, Join.OutPt2 & Join.OffPt all share the same point.
3478
0
  bool isHorizontal = (j->OutPt1->Pt.Y == j->OffPt.Y);
3479
3480
0
  if (isHorizontal  && (j->OffPt == j->OutPt1->Pt) &&
3481
0
  (j->OffPt == j->OutPt2->Pt))
3482
0
  {
3483
    //Strictly Simple join ...
3484
0
    if (outRec1 != outRec2) return false;
3485
0
    op1b = j->OutPt1->Next;
3486
0
    while (op1b != op1 && (op1b->Pt == j->OffPt))
3487
0
      op1b = op1b->Next;
3488
0
    bool reverse1 = (op1b->Pt.Y > j->OffPt.Y);
3489
0
    op2b = j->OutPt2->Next;
3490
0
    while (op2b != op2 && (op2b->Pt == j->OffPt))
3491
0
      op2b = op2b->Next;
3492
0
    bool reverse2 = (op2b->Pt.Y > j->OffPt.Y);
3493
0
    if (reverse1 == reverse2) return false;
3494
0
    if (reverse1)
3495
0
    {
3496
0
      op1b = DupOutPt(op1, false);
3497
0
      op2b = DupOutPt(op2, true);
3498
0
      op1->Prev = op2;
3499
0
      op2->Next = op1;
3500
0
      op1b->Next = op2b;
3501
0
      op2b->Prev = op1b;
3502
0
      j->OutPt1 = op1;
3503
0
      j->OutPt2 = op1b;
3504
0
      return true;
3505
0
    } else
3506
0
    {
3507
0
      op1b = DupOutPt(op1, true);
3508
0
      op2b = DupOutPt(op2, false);
3509
0
      op1->Next = op2;
3510
0
      op2->Prev = op1;
3511
0
      op1b->Prev = op2b;
3512
0
      op2b->Next = op1b;
3513
0
      j->OutPt1 = op1;
3514
0
      j->OutPt2 = op1b;
3515
0
      return true;
3516
0
    }
3517
0
  }
3518
0
  else if (isHorizontal)
3519
0
  {
3520
    //treat horizontal joins differently to non-horizontal joins since with
3521
    //them we're not yet sure where the overlapping is. OutPt1.Pt & OutPt2.Pt
3522
    //may be anywhere along the horizontal edge.
3523
0
    op1b = op1;
3524
0
    while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2)
3525
0
      op1 = op1->Prev;
3526
0
    while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2)
3527
0
      op1b = op1b->Next;
3528
0
    if (op1b->Next == op1 || op1b->Next == op2) return false; //a flat 'polygon'
3529
3530
0
    op2b = op2;
3531
0
    while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b)
3532
0
      op2 = op2->Prev;
3533
0
    while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1)
3534
0
      op2b = op2b->Next;
3535
0
    if (op2b->Next == op2 || op2b->Next == op1) return false; //a flat 'polygon'
3536
3537
0
    cInt Left, Right;
3538
    //Op1 --> Op1b & Op2 --> Op2b are the extremites of the horizontal edges
3539
0
    if (!GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right))
3540
0
      return false;
3541
3542
    //DiscardLeftSide: when overlapping edges are joined, a spike will created
3543
    //which needs to be cleaned up. However, we don't want Op1 or Op2 caught up
3544
    //on the discard Side as either may still be needed for other joins ...
3545
0
    IntPoint Pt;
3546
0
    bool DiscardLeftSide;
3547
0
    if (op1->Pt.X >= Left && op1->Pt.X <= Right)
3548
0
    {
3549
0
      Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X);
3550
0
    }
3551
0
    else if (op2->Pt.X >= Left&& op2->Pt.X <= Right)
3552
0
    {
3553
0
      Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X);
3554
0
    }
3555
0
    else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right)
3556
0
    {
3557
0
      Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X;
3558
0
    }
3559
0
    else
3560
0
    {
3561
0
      Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X);
3562
0
    }
3563
0
    j->OutPt1 = op1; j->OutPt2 = op2;
3564
0
    return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
3565
0
  } else
3566
0
  {
3567
    //nb: For non-horizontal joins ...
3568
    //    1. Jr.OutPt1.Pt.Y == Jr.OutPt2.Pt.Y
3569
    //    2. Jr.OutPt1.Pt > Jr.OffPt.Y
3570
3571
    //make sure the polygons are correctly oriented ...
3572
0
    op1b = op1->Next;
3573
0
    while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next;
3574
0
    bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) ||
3575
0
      !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange));
3576
0
    if (Reverse1)
3577
0
    {
3578
0
      op1b = op1->Prev;
3579
0
      while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev;
3580
0
      if ((op1b->Pt.Y > op1->Pt.Y) ||
3581
0
        !SlopesEqual(op1->Pt, op1b->Pt, j->OffPt, m_UseFullRange)) return false;
3582
0
    };
3583
0
    op2b = op2->Next;
3584
0
    while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next;
3585
0
    bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) ||
3586
0
      !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange));
3587
0
    if (Reverse2)
3588
0
    {
3589
0
      op2b = op2->Prev;
3590
0
      while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev;
3591
0
      if ((op2b->Pt.Y > op2->Pt.Y) ||
3592
0
        !SlopesEqual(op2->Pt, op2b->Pt, j->OffPt, m_UseFullRange)) return false;
3593
0
    }
3594
3595
0
    if ((op1b == op1) || (op2b == op2) || (op1b == op2b) ||
3596
0
      ((outRec1 == outRec2) && (Reverse1 == Reverse2))) return false;
3597
3598
0
    if (Reverse1)
3599
0
    {
3600
0
      op1b = DupOutPt(op1, false);
3601
0
      op2b = DupOutPt(op2, true);
3602
0
      op1->Prev = op2;
3603
0
      op2->Next = op1;
3604
0
      op1b->Next = op2b;
3605
0
      op2b->Prev = op1b;
3606
0
      j->OutPt1 = op1;
3607
0
      j->OutPt2 = op1b;
3608
0
      return true;
3609
0
    } else
3610
0
    {
3611
0
      op1b = DupOutPt(op1, true);
3612
0
      op2b = DupOutPt(op2, false);
3613
0
      op1->Next = op2;
3614
0
      op2->Prev = op1;
3615
0
      op1b->Prev = op2b;
3616
0
      op2b->Next = op1b;
3617
0
      j->OutPt1 = op1;
3618
0
      j->OutPt2 = op1b;
3619
0
      return true;
3620
0
    }
3621
0
  }
3622
0
}
3623
//----------------------------------------------------------------------
3624
3625
static OutRec* ParseFirstLeft(OutRec* FirstLeft)
3626
0
{
3627
0
  while (FirstLeft && !FirstLeft->Pts)
3628
0
    FirstLeft = FirstLeft->FirstLeft;
3629
0
  return FirstLeft;
3630
0
}
3631
//------------------------------------------------------------------------------
3632
3633
void Clipper::FixupFirstLefts1(OutRec* OldOutRec, OutRec* NewOutRec)
3634
0
{
3635
  //tests if NewOutRec contains the polygon before reassigning FirstLeft
3636
0
  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
3637
0
  {
3638
0
    OutRec* outRec = m_PolyOuts[i];
3639
0
    OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
3640
0
    if (outRec->Pts  && firstLeft == OldOutRec)
3641
0
    {
3642
0
      if (Poly2ContainsPoly1(outRec->Pts, NewOutRec->Pts))
3643
0
        outRec->FirstLeft = NewOutRec;
3644
0
    }
3645
0
  }
3646
0
}
3647
//----------------------------------------------------------------------
3648
3649
void Clipper::FixupFirstLefts2(OutRec* InnerOutRec, OutRec* OuterOutRec)
3650
0
{
3651
  //A polygon has split into two such that one is now the inner of the other.
3652
  //It's possible that these polygons now wrap around other polygons, so check
3653
  //every polygon that's also contained by OuterOutRec's FirstLeft container
3654
  //(including 0) to see if they've become inner to the new inner polygon ...
3655
0
  OutRec* orfl = OuterOutRec->FirstLeft;
3656
0
  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
3657
0
  {
3658
0
    OutRec* outRec = m_PolyOuts[i];
3659
3660
0
    if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
3661
0
      continue;
3662
0
    OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
3663
0
    if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec)
3664
0
      continue;
3665
0
    if (Poly2ContainsPoly1(outRec->Pts, InnerOutRec->Pts))
3666
0
      outRec->FirstLeft = InnerOutRec;
3667
0
    else if (Poly2ContainsPoly1(outRec->Pts, OuterOutRec->Pts))
3668
0
      outRec->FirstLeft = OuterOutRec;
3669
0
    else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec)
3670
0
      outRec->FirstLeft = orfl;
3671
0
  }
3672
0
}
3673
//----------------------------------------------------------------------
3674
void Clipper::FixupFirstLefts3(OutRec* OldOutRec, OutRec* NewOutRec)
3675
0
{
3676
  //reassigns FirstLeft WITHOUT testing if NewOutRec contains the polygon
3677
0
  for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i)
3678
0
  {
3679
0
    OutRec* outRec = m_PolyOuts[i];
3680
0
    OutRec* firstLeft = ParseFirstLeft(outRec->FirstLeft);
3681
0
    if (outRec->Pts && firstLeft == OldOutRec)
3682
0
      outRec->FirstLeft = NewOutRec;
3683
0
  }
3684
0
}
3685
//----------------------------------------------------------------------
3686
3687
void Clipper::JoinCommonEdges()
3688
0
{
3689
0
  for (JoinList::size_type i = 0; i < m_Joins.size(); i++)
3690
0
  {
3691
0
    Join* join = m_Joins[i];
3692
3693
0
    OutRec *outRec1 = GetOutRec(join->OutPt1->Idx);
3694
0
    OutRec *outRec2 = GetOutRec(join->OutPt2->Idx);
3695
3696
0
    if (!outRec1->Pts || !outRec2->Pts) continue;
3697
0
    if (outRec1->IsOpen || outRec2->IsOpen) continue;
3698
3699
    //get the polygon fragment with the correct hole state (FirstLeft)
3700
    //before calling JoinPoints() ...
3701
0
    OutRec *holeStateRec;
3702
0
    if (outRec1 == outRec2) holeStateRec = outRec1;
3703
0
    else if (OutRec1RightOfOutRec2(outRec1, outRec2)) holeStateRec = outRec2;
3704
0
    else if (OutRec1RightOfOutRec2(outRec2, outRec1)) holeStateRec = outRec1;
3705
0
    else holeStateRec = GetLowermostRec(outRec1, outRec2);
3706
3707
0
    if (!JoinPoints(join, outRec1, outRec2)) continue;
3708
3709
0
    if (outRec1 == outRec2)
3710
0
    {
3711
      //instead of joining two polygons, we've just created a new one by
3712
      //splitting one polygon into two.
3713
0
      outRec1->Pts = join->OutPt1;
3714
0
      outRec1->BottomPt = 0;
3715
0
      outRec2 = CreateOutRec();
3716
0
      outRec2->Pts = join->OutPt2;
3717
3718
      //update all OutRec2.Pts Idx's ...
3719
0
      UpdateOutPtIdxs(*outRec2);
3720
3721
0
      if (Poly2ContainsPoly1(outRec2->Pts, outRec1->Pts))
3722
0
      {
3723
        //outRec1 contains outRec2 ...
3724
0
        outRec2->IsHole = !outRec1->IsHole;
3725
0
        outRec2->FirstLeft = outRec1;
3726
3727
0
        if (m_UsingPolyTree) FixupFirstLefts2(outRec2, outRec1);
3728
3729
0
        if ((outRec2->IsHole ^ m_ReverseOutput) == (Area(*outRec2) > 0))
3730
0
          ReversePolyPtLinks(outRec2->Pts);
3731
3732
0
      } else if (Poly2ContainsPoly1(outRec1->Pts, outRec2->Pts))
3733
0
      {
3734
        //outRec2 contains outRec1 ...
3735
0
        outRec2->IsHole = outRec1->IsHole;
3736
0
        outRec1->IsHole = !outRec2->IsHole;
3737
0
        outRec2->FirstLeft = outRec1->FirstLeft;
3738
0
        outRec1->FirstLeft = outRec2;
3739
3740
0
        if (m_UsingPolyTree) FixupFirstLefts2(outRec1, outRec2);
3741
3742
0
        if ((outRec1->IsHole ^ m_ReverseOutput) == (Area(*outRec1) > 0))
3743
0
          ReversePolyPtLinks(outRec1->Pts);
3744
0
      }
3745
0
      else
3746
0
      {
3747
        //the 2 polygons are completely separate ...
3748
0
        outRec2->IsHole = outRec1->IsHole;
3749
0
        outRec2->FirstLeft = outRec1->FirstLeft;
3750
3751
        //fixup FirstLeft pointers that may need reassigning to OutRec2
3752
0
        if (m_UsingPolyTree) FixupFirstLefts1(outRec1, outRec2);
3753
0
      }
3754
3755
0
    } else
3756
0
    {
3757
      //joined 2 polygons together ...
3758
3759
0
      outRec2->Pts = 0;
3760
0
      outRec2->BottomPt = 0;
3761
0
      outRec2->Idx = outRec1->Idx;
3762
3763
0
      outRec1->IsHole = holeStateRec->IsHole;
3764
0
      if (holeStateRec == outRec2)
3765
0
        outRec1->FirstLeft = outRec2->FirstLeft;
3766
0
      outRec2->FirstLeft = outRec1;
3767
3768
0
      if (m_UsingPolyTree) FixupFirstLefts3(outRec2, outRec1);
3769
0
    }
3770
0
  }
3771
0
}
3772
3773
//------------------------------------------------------------------------------
3774
// ClipperOffset support functions ...
3775
//------------------------------------------------------------------------------
3776
3777
DoublePoint GetUnitNormal(const IntPoint &pt1, const IntPoint &pt2)
3778
0
{
3779
0
  if(pt2.X == pt1.X && pt2.Y == pt1.Y)
3780
0
    return DoublePoint(0, 0);
3781
3782
0
  double Dx = (double)(pt2.X - pt1.X);
3783
0
  double dy = (double)(pt2.Y - pt1.Y);
3784
0
  double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy );
3785
0
  Dx *= f;
3786
0
  dy *= f;
3787
0
  return DoublePoint(dy, -Dx);
3788
0
}
3789
3790
//------------------------------------------------------------------------------
3791
// ClipperOffset class
3792
//------------------------------------------------------------------------------
3793
3794
ClipperOffset::ClipperOffset(double miterLimit, double arcTolerance)
3795
0
{
3796
0
  this->MiterLimit = miterLimit;
3797
0
  this->ArcTolerance = arcTolerance;
3798
0
  m_lowest.X = -1;
3799
0
}
3800
//------------------------------------------------------------------------------
3801
3802
ClipperOffset::~ClipperOffset()
3803
0
{
3804
0
  Clear();
3805
0
}
3806
//------------------------------------------------------------------------------
3807
3808
void ClipperOffset::Clear()
3809
0
{
3810
0
  for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3811
0
    delete m_polyNodes.Childs[i];
3812
0
  m_polyNodes.Childs.clear();
3813
0
  m_lowest.X = -1;
3814
0
}
3815
//------------------------------------------------------------------------------
3816
3817
void ClipperOffset::AddPath(const Path& path, JoinType joinType, EndType endType)
3818
0
{
3819
0
  int highI = (int)path.size() - 1;
3820
0
  if (highI < 0) return;
3821
0
  PolyNode* newNode = new PolyNode();
3822
0
  newNode->m_jointype = joinType;
3823
0
  newNode->m_endtype = endType;
3824
3825
  //strip duplicate points from path and also get index to the lowest point ...
3826
0
  if (endType == etClosedLine || endType == etClosedPolygon)
3827
0
    while (highI > 0 && path[0] == path[highI]) highI--;
3828
0
  newNode->Contour.reserve(highI + 1);
3829
0
  newNode->Contour.push_back(path[0]);
3830
0
  int j = 0, k = 0;
3831
0
  for (int i = 1; i <= highI; i++)
3832
0
    if (newNode->Contour[j] != path[i])
3833
0
    {
3834
0
      j++;
3835
0
      newNode->Contour.push_back(path[i]);
3836
0
      if (path[i].Y > newNode->Contour[k].Y ||
3837
0
        (path[i].Y == newNode->Contour[k].Y &&
3838
0
        path[i].X < newNode->Contour[k].X)) k = j;
3839
0
    }
3840
0
  if (endType == etClosedPolygon && j < 2)
3841
0
  {
3842
0
    delete newNode;
3843
0
    return;
3844
0
  }
3845
0
  m_polyNodes.AddChild(*newNode);
3846
3847
  //if this path's lowest pt is lower than all the others then update m_lowest
3848
0
  if (endType != etClosedPolygon) return;
3849
0
  if (m_lowest.X < 0)
3850
0
    m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
3851
0
  else
3852
0
  {
3853
0
    IntPoint ip = m_polyNodes.Childs[(int)m_lowest.X]->Contour[(int)m_lowest.Y];
3854
0
    if (newNode->Contour[k].Y > ip.Y ||
3855
0
      (newNode->Contour[k].Y == ip.Y &&
3856
0
      newNode->Contour[k].X < ip.X))
3857
0
      m_lowest = IntPoint(m_polyNodes.ChildCount() - 1, k);
3858
0
  }
3859
0
}
3860
//------------------------------------------------------------------------------
3861
3862
void ClipperOffset::AddPaths(const Paths& paths, JoinType joinType, EndType endType)
3863
0
{
3864
0
  for (Paths::size_type i = 0; i < paths.size(); ++i)
3865
0
    AddPath(paths[i], joinType, endType);
3866
0
}
3867
//------------------------------------------------------------------------------
3868
3869
void ClipperOffset::FixOrientations()
3870
0
{
3871
  //fixup orientations of all closed paths if the orientation of the
3872
  //closed path with the lowermost vertex is wrong ...
3873
0
  if (m_lowest.X >= 0 &&
3874
0
    !Orientation(m_polyNodes.Childs[(int)m_lowest.X]->Contour))
3875
0
  {
3876
0
    for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3877
0
    {
3878
0
      PolyNode& node = *m_polyNodes.Childs[i];
3879
0
      if (node.m_endtype == etClosedPolygon ||
3880
0
        (node.m_endtype == etClosedLine && Orientation(node.Contour)))
3881
0
          ReversePath(node.Contour);
3882
0
    }
3883
0
  } else
3884
0
  {
3885
0
    for (int i = 0; i < m_polyNodes.ChildCount(); ++i)
3886
0
    {
3887
0
      PolyNode& node = *m_polyNodes.Childs[i];
3888
0
      if (node.m_endtype == etClosedLine && !Orientation(node.Contour))
3889
0
        ReversePath(node.Contour);
3890
0
    }
3891
0
  }
3892
0
}
3893
//------------------------------------------------------------------------------
3894
3895
void ClipperOffset::Execute(Paths& solution, double delta)
3896
0
{
3897
0
  solution.clear();
3898
0
  FixOrientations();
3899
0
  DoOffset(delta);
3900
3901
  //now clean up 'corners' ...
3902
0
  Clipper clpr;
3903
0
  clpr.AddPaths(m_destPolys, ptSubject, true);
3904
0
  if (delta > 0)
3905
0
  {
3906
0
    clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
3907
0
  }
3908
0
  else
3909
0
  {
3910
0
    IntRect r = clpr.GetBounds();
3911
0
    Path outer(4);
3912
0
    outer[0] = IntPoint(r.left - 10, r.bottom + 10);
3913
0
    outer[1] = IntPoint(r.right + 10, r.bottom + 10);
3914
0
    outer[2] = IntPoint(r.right + 10, r.top - 10);
3915
0
    outer[3] = IntPoint(r.left - 10, r.top - 10);
3916
3917
0
    clpr.AddPath(outer, ptSubject, true);
3918
0
    clpr.ReverseSolution(true);
3919
0
    clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
3920
0
    if (solution.size() > 0) solution.erase(solution.begin());
3921
0
  }
3922
0
}
3923
//------------------------------------------------------------------------------
3924
3925
void ClipperOffset::Execute(PolyTree& solution, double delta)
3926
0
{
3927
0
  solution.Clear();
3928
0
  FixOrientations();
3929
0
  DoOffset(delta);
3930
3931
  //now clean up 'corners' ...
3932
0
  Clipper clpr;
3933
0
  clpr.AddPaths(m_destPolys, ptSubject, true);
3934
0
  if (delta > 0)
3935
0
  {
3936
0
    clpr.Execute(ctUnion, solution, pftPositive, pftPositive);
3937
0
  }
3938
0
  else
3939
0
  {
3940
0
    IntRect r = clpr.GetBounds();
3941
0
    Path outer(4);
3942
0
    outer[0] = IntPoint(r.left - 10, r.bottom + 10);
3943
0
    outer[1] = IntPoint(r.right + 10, r.bottom + 10);
3944
0
    outer[2] = IntPoint(r.right + 10, r.top - 10);
3945
0
    outer[3] = IntPoint(r.left - 10, r.top - 10);
3946
3947
0
    clpr.AddPath(outer, ptSubject, true);
3948
0
    clpr.ReverseSolution(true);
3949
0
    clpr.Execute(ctUnion, solution, pftNegative, pftNegative);
3950
    //remove the outer PolyNode rectangle ...
3951
0
    if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0)
3952
0
    {
3953
0
      PolyNode* outerNode = solution.Childs[0];
3954
0
      solution.Childs.reserve(outerNode->ChildCount());
3955
0
      solution.Childs[0] = outerNode->Childs[0];
3956
0
      solution.Childs[0]->Parent = outerNode->Parent;
3957
0
      for (int i = 1; i < outerNode->ChildCount(); ++i)
3958
0
        solution.AddChild(*outerNode->Childs[i]);
3959
0
    }
3960
0
    else
3961
0
      solution.Clear();
3962
0
  }
3963
0
}
3964
//------------------------------------------------------------------------------
3965
3966
void ClipperOffset::DoOffset(double delta)
3967
0
{
3968
0
  m_destPolys.clear();
3969
0
  m_delta = delta;
3970
3971
  //if Zero offset, just copy any CLOSED polygons to m_p and return ...
3972
0
  if (NEAR_ZERO(delta))
3973
0
  {
3974
0
    m_destPolys.reserve(m_polyNodes.ChildCount());
3975
0
    for (int i = 0; i < m_polyNodes.ChildCount(); i++)
3976
0
    {
3977
0
      PolyNode& node = *m_polyNodes.Childs[i];
3978
0
      if (node.m_endtype == etClosedPolygon)
3979
0
        m_destPolys.push_back(node.Contour);
3980
0
    }
3981
0
    return;
3982
0
  }
3983
3984
  //see offset_triginometry3.svg in the documentation folder ...
3985
0
  if (MiterLimit > 2) m_miterLim = 2/(MiterLimit * MiterLimit);
3986
0
  else m_miterLim = 0.5;
3987
3988
0
  double y;
3989
0
  if (ArcTolerance <= 0.0) y = def_arc_tolerance;
3990
0
  else if (ArcTolerance > std::fabs(delta) * def_arc_tolerance)
3991
0
    y = std::fabs(delta) * def_arc_tolerance;
3992
0
  else y = ArcTolerance;
3993
  //see offset_triginometry2.svg in the documentation folder ...
3994
0
  double steps = pi / std::acos(1 - y / std::fabs(delta));
3995
0
  if (steps > std::fabs(delta) * pi)
3996
0
    steps = std::fabs(delta) * pi;  //ie excessive precision check
3997
0
  m_sin = std::sin(two_pi / steps);
3998
0
  m_cos = std::cos(two_pi / steps);
3999
0
  m_StepsPerRad = steps / two_pi;
4000
0
  if (delta < 0.0) m_sin = -m_sin;
4001
4002
0
  m_destPolys.reserve(m_polyNodes.ChildCount() * 2);
4003
0
  for (int i = 0; i < m_polyNodes.ChildCount(); i++)
4004
0
  {
4005
0
    PolyNode& node = *m_polyNodes.Childs[i];
4006
0
    m_srcPoly = node.Contour;
4007
4008
0
    int len = (int)m_srcPoly.size();
4009
0
    if (len == 0 || (delta <= 0 && (len < 3 || node.m_endtype != etClosedPolygon)))
4010
0
        continue;
4011
4012
0
    m_destPoly.clear();
4013
0
    if (len == 1)
4014
0
    {
4015
0
      if (node.m_jointype == jtRound)
4016
0
      {
4017
0
        double X = 1.0, Y = 0.0;
4018
0
        for (cInt j = 1; j <= steps; j++)
4019
0
        {
4020
0
          m_destPoly.push_back(IntPoint(
4021
0
            Round(m_srcPoly[0].X + X * delta),
4022
0
            Round(m_srcPoly[0].Y + Y * delta)));
4023
0
          double X2 = X;
4024
0
          X = X * m_cos - m_sin * Y;
4025
0
          Y = X2 * m_sin + Y * m_cos;
4026
0
        }
4027
0
      }
4028
0
      else
4029
0
      {
4030
0
        double X = -1.0, Y = -1.0;
4031
0
        for (int j = 0; j < 4; ++j)
4032
0
        {
4033
0
          m_destPoly.push_back(IntPoint(
4034
0
            Round(m_srcPoly[0].X + X * delta),
4035
0
            Round(m_srcPoly[0].Y + Y * delta)));
4036
0
          if (X < 0) X = 1;
4037
0
          else if (Y < 0) Y = 1;
4038
0
          else X = -1;
4039
0
        }
4040
0
      }
4041
0
      m_destPolys.push_back(m_destPoly);
4042
0
      continue;
4043
0
    }
4044
    //build m_normals ...
4045
0
    m_normals.clear();
4046
0
    m_normals.reserve(len);
4047
0
    for (int j = 0; j < len - 1; ++j)
4048
0
      m_normals.push_back(GetUnitNormal(m_srcPoly[j], m_srcPoly[j + 1]));
4049
0
    if (node.m_endtype == etClosedLine || node.m_endtype == etClosedPolygon)
4050
0
      m_normals.push_back(GetUnitNormal(m_srcPoly[len - 1], m_srcPoly[0]));
4051
0
    else
4052
0
      m_normals.push_back(DoublePoint(m_normals[len - 2]));
4053
4054
0
    if (node.m_endtype == etClosedPolygon)
4055
0
    {
4056
0
      int k = len - 1;
4057
0
      for (int j = 0; j < len; ++j)
4058
0
        OffsetPoint(j, k, node.m_jointype);
4059
0
      m_destPolys.push_back(m_destPoly);
4060
0
    }
4061
0
    else if (node.m_endtype == etClosedLine)
4062
0
    {
4063
0
      int k = len - 1;
4064
0
      for (int j = 0; j < len; ++j)
4065
0
        OffsetPoint(j, k, node.m_jointype);
4066
0
      m_destPolys.push_back(m_destPoly);
4067
0
      m_destPoly.clear();
4068
      //re-build m_normals ...
4069
0
      DoublePoint n = m_normals[len -1];
4070
0
      for (int j = len - 1; j > 0; j--)
4071
0
        m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
4072
0
      m_normals[0] = DoublePoint(-n.X, -n.Y);
4073
0
      k = 0;
4074
0
      for (int j = len - 1; j >= 0; j--)
4075
0
        OffsetPoint(j, k, node.m_jointype);
4076
0
      m_destPolys.push_back(m_destPoly);
4077
0
    }
4078
0
    else
4079
0
    {
4080
0
      int k = 0;
4081
0
      for (int j = 1; j < len - 1; ++j)
4082
0
        OffsetPoint(j, k, node.m_jointype);
4083
4084
0
      IntPoint pt1;
4085
0
      if (node.m_endtype == etOpenButt)
4086
0
      {
4087
0
        int j = len - 1;
4088
0
        pt1 = IntPoint((cInt)Round(m_srcPoly[j].X + m_normals[j].X *
4089
0
          delta), (cInt)Round(m_srcPoly[j].Y + m_normals[j].Y * delta));
4090
0
        m_destPoly.push_back(pt1);
4091
0
        pt1 = IntPoint((cInt)Round(m_srcPoly[j].X - m_normals[j].X *
4092
0
          delta), (cInt)Round(m_srcPoly[j].Y - m_normals[j].Y * delta));
4093
0
        m_destPoly.push_back(pt1);
4094
0
      }
4095
0
      else
4096
0
      {
4097
0
        int j = len - 1;
4098
0
        k = len - 2;
4099
0
        m_sinA = 0;
4100
0
        m_normals[j] = DoublePoint(-m_normals[j].X, -m_normals[j].Y);
4101
0
        if (node.m_endtype == etOpenSquare)
4102
0
          DoSquare(j, k);
4103
0
        else
4104
0
          DoRound(j, k);
4105
0
      }
4106
4107
      //re-build m_normals ...
4108
0
      for (int j = len - 1; j > 0; j--)
4109
0
        m_normals[j] = DoublePoint(-m_normals[j - 1].X, -m_normals[j - 1].Y);
4110
0
      m_normals[0] = DoublePoint(-m_normals[1].X, -m_normals[1].Y);
4111
4112
0
      k = len - 1;
4113
0
      for (int j = k - 1; j > 0; --j) OffsetPoint(j, k, node.m_jointype);
4114
4115
0
      if (node.m_endtype == etOpenButt)
4116
0
      {
4117
0
        pt1 = IntPoint((cInt)Round(m_srcPoly[0].X - m_normals[0].X * delta),
4118
0
          (cInt)Round(m_srcPoly[0].Y - m_normals[0].Y * delta));
4119
0
        m_destPoly.push_back(pt1);
4120
0
        pt1 = IntPoint((cInt)Round(m_srcPoly[0].X + m_normals[0].X * delta),
4121
0
          (cInt)Round(m_srcPoly[0].Y + m_normals[0].Y * delta));
4122
0
        m_destPoly.push_back(pt1);
4123
0
      }
4124
0
      else
4125
0
      {
4126
0
        k = 1;
4127
0
        m_sinA = 0;
4128
0
        if (node.m_endtype == etOpenSquare)
4129
0
          DoSquare(0, 1);
4130
0
        else
4131
0
          DoRound(0, 1);
4132
0
      }
4133
0
      m_destPolys.push_back(m_destPoly);
4134
0
    }
4135
0
  }
4136
0
}
4137
//------------------------------------------------------------------------------
4138
4139
void ClipperOffset::OffsetPoint(int j, int& k, JoinType jointype)
4140
0
{
4141
  //cross product ...
4142
0
  m_sinA = (m_normals[k].X * m_normals[j].Y - m_normals[j].X * m_normals[k].Y);
4143
0
  if (std::fabs(m_sinA * m_delta) < 1.0)
4144
0
  {
4145
    //dot product ...
4146
0
    double cosA = (m_normals[k].X * m_normals[j].X + m_normals[j].Y * m_normals[k].Y );
4147
0
    if (cosA > 0) // angle => 0 degrees
4148
0
    {
4149
0
      m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
4150
0
        Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
4151
0
      return;
4152
0
    }
4153
    //else angle => 180 degrees
4154
0
  }
4155
0
  else if (m_sinA > 1.0) m_sinA = 1.0;
4156
0
  else if (m_sinA < -1.0) m_sinA = -1.0;
4157
4158
0
  if (m_sinA * m_delta < 0)
4159
0
  {
4160
0
    m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[k].X * m_delta),
4161
0
      Round(m_srcPoly[j].Y + m_normals[k].Y * m_delta)));
4162
0
    m_destPoly.push_back(m_srcPoly[j]);
4163
0
    m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
4164
0
      Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
4165
0
  }
4166
0
  else
4167
0
    switch (jointype)
4168
0
    {
4169
0
      case jtMiter:
4170
0
        {
4171
0
          double r = 1 + (m_normals[j].X * m_normals[k].X +
4172
0
            m_normals[j].Y * m_normals[k].Y);
4173
0
          if (r >= m_miterLim) DoMiter(j, k, r); else DoSquare(j, k);
4174
0
          break;
4175
0
        }
4176
0
      case jtSquare: DoSquare(j, k); break;
4177
0
      case jtRound: DoRound(j, k); break;
4178
0
    }
4179
0
  k = j;
4180
0
}
4181
//------------------------------------------------------------------------------
4182
4183
void ClipperOffset::DoSquare(int j, int k)
4184
0
{
4185
0
  double dx = std::tan(std::atan2(m_sinA,
4186
0
      m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y) / 4);
4187
0
  m_destPoly.push_back(IntPoint(
4188
0
      Round(m_srcPoly[j].X + m_delta * (m_normals[k].X - m_normals[k].Y * dx)),
4189
0
      Round(m_srcPoly[j].Y + m_delta * (m_normals[k].Y + m_normals[k].X * dx))));
4190
0
  m_destPoly.push_back(IntPoint(
4191
0
      Round(m_srcPoly[j].X + m_delta * (m_normals[j].X + m_normals[j].Y * dx)),
4192
0
      Round(m_srcPoly[j].Y + m_delta * (m_normals[j].Y - m_normals[j].X * dx))));
4193
0
}
4194
//------------------------------------------------------------------------------
4195
4196
void ClipperOffset::DoMiter(int j, int k, double r)
4197
0
{
4198
0
  double q = m_delta / r;
4199
0
  m_destPoly.push_back(IntPoint(Round(m_srcPoly[j].X + (m_normals[k].X + m_normals[j].X) * q),
4200
0
      Round(m_srcPoly[j].Y + (m_normals[k].Y + m_normals[j].Y) * q)));
4201
0
}
4202
//------------------------------------------------------------------------------
4203
4204
void ClipperOffset::DoRound(int j, int k)
4205
0
{
4206
0
  double a = std::atan2(m_sinA,
4207
0
  m_normals[k].X * m_normals[j].X + m_normals[k].Y * m_normals[j].Y);
4208
0
  int steps = std::max((int)Round(m_StepsPerRad * std::fabs(a)), 1);
4209
4210
0
  double X = m_normals[k].X, Y = m_normals[k].Y, X2;
4211
0
  for (int i = 0; i < steps; ++i)
4212
0
  {
4213
0
    m_destPoly.push_back(IntPoint(
4214
0
        Round(m_srcPoly[j].X + X * m_delta),
4215
0
        Round(m_srcPoly[j].Y + Y * m_delta)));
4216
0
    X2 = X;
4217
0
    X = X * m_cos - m_sin * Y;
4218
0
    Y = X2 * m_sin + Y * m_cos;
4219
0
  }
4220
0
  m_destPoly.push_back(IntPoint(
4221
0
  Round(m_srcPoly[j].X + m_normals[j].X * m_delta),
4222
0
  Round(m_srcPoly[j].Y + m_normals[j].Y * m_delta)));
4223
0
}
4224
4225
//------------------------------------------------------------------------------
4226
// Miscellaneous public functions
4227
//------------------------------------------------------------------------------
4228
4229
void Clipper::DoSimplePolygons()
4230
0
{
4231
0
  PolyOutList::size_type i = 0;
4232
0
  while (i < m_PolyOuts.size())
4233
0
  {
4234
0
    OutRec* outrec = m_PolyOuts[i++];
4235
0
    OutPt* op = outrec->Pts;
4236
0
    if (!op || outrec->IsOpen) continue;
4237
0
    do //for each Pt in Polygon until duplicate found do ...
4238
0
    {
4239
0
      OutPt* op2 = op->Next;
4240
0
      while (op2 != outrec->Pts)
4241
0
      {
4242
0
        if ((op->Pt == op2->Pt) && op2->Next != op && op2->Prev != op)
4243
0
        {
4244
          //split the polygon into two ...
4245
0
          OutPt* op3 = op->Prev;
4246
0
          OutPt* op4 = op2->Prev;
4247
0
          op->Prev = op4;
4248
0
          op4->Next = op;
4249
0
          op2->Prev = op3;
4250
0
          op3->Next = op2;
4251
4252
0
          outrec->Pts = op;
4253
0
          OutRec* outrec2 = CreateOutRec();
4254
0
          outrec2->Pts = op2;
4255
0
          UpdateOutPtIdxs(*outrec2);
4256
0
          if (Poly2ContainsPoly1(outrec2->Pts, outrec->Pts))
4257
0
          {
4258
            //OutRec2 is contained by OutRec1 ...
4259
0
            outrec2->IsHole = !outrec->IsHole;
4260
0
            outrec2->FirstLeft = outrec;
4261
0
            if (m_UsingPolyTree) FixupFirstLefts2(outrec2, outrec);
4262
0
          }
4263
0
          else
4264
0
            if (Poly2ContainsPoly1(outrec->Pts, outrec2->Pts))
4265
0
          {
4266
            //OutRec1 is contained by OutRec2 ...
4267
0
            outrec2->IsHole = outrec->IsHole;
4268
0
            outrec->IsHole = !outrec2->IsHole;
4269
0
            outrec2->FirstLeft = outrec->FirstLeft;
4270
0
            outrec->FirstLeft = outrec2;
4271
0
            if (m_UsingPolyTree) FixupFirstLefts2(outrec, outrec2);
4272
0
            }
4273
0
            else
4274
0
          {
4275
            //the 2 polygons are separate ...
4276
0
            outrec2->IsHole = outrec->IsHole;
4277
0
            outrec2->FirstLeft = outrec->FirstLeft;
4278
0
            if (m_UsingPolyTree) FixupFirstLefts1(outrec, outrec2);
4279
0
            }
4280
0
          op2 = op; //ie get ready for the Next iteration
4281
0
        }
4282
0
        op2 = op2->Next;
4283
0
      }
4284
0
      op = op->Next;
4285
0
    }
4286
0
    while (op != outrec->Pts);
4287
0
  }
4288
0
}
4289
//------------------------------------------------------------------------------
4290
4291
void ReversePath(Path& p)
4292
0
{
4293
0
  std::reverse(p.begin(), p.end());
4294
0
}
4295
//------------------------------------------------------------------------------
4296
4297
void ReversePaths(Paths& p)
4298
0
{
4299
0
  for (Paths::size_type i = 0; i < p.size(); ++i)
4300
0
    ReversePath(p[i]);
4301
0
}
4302
//------------------------------------------------------------------------------
4303
4304
void SimplifyPolygon(const Path &in_poly, Paths &out_polys, PolyFillType fillType)
4305
0
{
4306
0
  Clipper c;
4307
0
  c.StrictlySimple(true);
4308
0
  c.AddPath(in_poly, ptSubject, true);
4309
0
  c.Execute(ctUnion, out_polys, fillType, fillType);
4310
0
}
4311
//------------------------------------------------------------------------------
4312
4313
void SimplifyPolygons(const Paths &in_polys, Paths &out_polys, PolyFillType fillType)
4314
0
{
4315
0
  Clipper c;
4316
0
  c.StrictlySimple(true);
4317
0
  c.AddPaths(in_polys, ptSubject, true);
4318
0
  c.Execute(ctUnion, out_polys, fillType, fillType);
4319
0
}
4320
//------------------------------------------------------------------------------
4321
4322
void SimplifyPolygons(Paths &polys, PolyFillType fillType)
4323
0
{
4324
0
  SimplifyPolygons(polys, polys, fillType);
4325
0
}
4326
//------------------------------------------------------------------------------
4327
4328
inline double DistanceSqrd(const IntPoint& pt1, const IntPoint& pt2)
4329
0
{
4330
0
  double Dx = ((double)pt1.X - pt2.X);
4331
0
  double dy = ((double)pt1.Y - pt2.Y);
4332
0
  return (Dx*Dx + dy*dy);
4333
0
}
4334
//------------------------------------------------------------------------------
4335
4336
double DistanceFromLineSqrd(
4337
  const IntPoint& pt, const IntPoint& ln1, const IntPoint& ln2)
4338
0
{
4339
  //The equation of a line in general form (Ax + By + C = 0)
4340
  //given 2 points (x_1, y_1) & (x_2, y_2) is ...
4341
  //(y_1 - y_2)x + (x_2 - x_1)y - (y_1 - y_2)x_1 - (x_2 - x_1)y_1 = 0
4342
  //A = (y_1 - y_2); B = (x_2 - x_1); C = - (y_1 - y_2)x_1 - (x_2 - x_1)y_1
4343
  //perpendicular distance of point (x_0, y_0) = |Ax_0 + By_0 + C| / Sqrt(A^2 + B^2)
4344
  //see http://en.wikipedia.org/wiki/Perpendicular_distance
4345
0
  double A = double(ln1.Y - ln2.Y);
4346
0
  double B = double(ln2.X - ln1.X);
4347
0
  double C = A * ln1.X  + B * ln1.Y;
4348
0
  C = A * pt.X + B * pt.Y - C;
4349
0
  return (C * C) / (A * A + B * B);
4350
0
}
4351
//---------------------------------------------------------------------------
4352
4353
bool SlopesNearCollinear(const IntPoint& pt1,
4354
    const IntPoint& pt2, const IntPoint& pt3, double distSqrd)
4355
0
{
4356
  //this function is more accurate when the point that's geometrically
4357
  //between the other 2 points is the one that's tested for distance.
4358
  //ie makes it more likely to pick up 'spikes' ...
4359
0
  if (Abs(pt1.X - pt2.X) > Abs(pt1.Y - pt2.Y))
4360
0
  {
4361
0
    if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
4362
0
      return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
4363
0
    else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
4364
0
      return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
4365
0
    else
4366
0
      return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
4367
0
  }
4368
0
  else
4369
0
  {
4370
0
    if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
4371
0
      return DistanceFromLineSqrd(pt1, pt2, pt3) < distSqrd;
4372
0
    else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
4373
0
      return DistanceFromLineSqrd(pt2, pt1, pt3) < distSqrd;
4374
0
    else
4375
0
      return DistanceFromLineSqrd(pt3, pt1, pt2) < distSqrd;
4376
0
  }
4377
0
}
4378
//------------------------------------------------------------------------------
4379
4380
bool PointsAreClose(IntPoint pt1, IntPoint pt2, double distSqrd)
4381
0
{
4382
0
    double Dx = (double)pt1.X - pt2.X;
4383
0
    double dy = (double)pt1.Y - pt2.Y;
4384
0
    return ((Dx * Dx) + (dy * dy) <= distSqrd);
4385
0
}
4386
//------------------------------------------------------------------------------
4387
4388
OutPt* ExcludeOp(OutPt* op)
4389
0
{
4390
0
  OutPt* result = op->Prev;
4391
0
  result->Next = op->Next;
4392
0
  op->Next->Prev = result;
4393
0
  result->Idx = 0;
4394
0
  return result;
4395
0
}
4396
//------------------------------------------------------------------------------
4397
4398
void CleanPolygon(const Path& in_poly, Path& out_poly, double distance)
4399
0
{
4400
  //distance = proximity in units/pixels below which vertices
4401
  //will be stripped. Default ~= sqrt(2).
4402
4403
0
  size_t size = in_poly.size();
4404
4405
0
  if (size == 0)
4406
0
  {
4407
0
    out_poly.clear();
4408
0
    return;
4409
0
  }
4410
4411
0
  OutPt* outPts = new OutPt[size];
4412
0
  for (size_t i = 0; i < size; ++i)
4413
0
  {
4414
0
    outPts[i].Pt = in_poly[i];
4415
0
    outPts[i].Next = &outPts[(i + 1) % size];
4416
0
    outPts[i].Next->Prev = &outPts[i];
4417
0
    outPts[i].Idx = 0;
4418
0
  }
4419
4420
0
  double distSqrd = distance * distance;
4421
0
  OutPt* op = &outPts[0];
4422
0
  while (op->Idx == 0 && op->Next != op->Prev)
4423
0
  {
4424
0
    if (PointsAreClose(op->Pt, op->Prev->Pt, distSqrd))
4425
0
    {
4426
0
      op = ExcludeOp(op);
4427
0
      size--;
4428
0
    }
4429
0
    else if (PointsAreClose(op->Prev->Pt, op->Next->Pt, distSqrd))
4430
0
    {
4431
0
      ExcludeOp(op->Next);
4432
0
      op = ExcludeOp(op);
4433
0
      size -= 2;
4434
0
    }
4435
0
    else if (SlopesNearCollinear(op->Prev->Pt, op->Pt, op->Next->Pt, distSqrd))
4436
0
    {
4437
0
      op = ExcludeOp(op);
4438
0
      size--;
4439
0
    }
4440
0
    else
4441
0
    {
4442
0
      op->Idx = 1;
4443
0
      op = op->Next;
4444
0
    }
4445
0
  }
4446
4447
0
  if (size < 3) size = 0;
4448
0
  out_poly.resize(size);
4449
0
  for (size_t i = 0; i < size; ++i)
4450
0
  {
4451
0
    out_poly[i] = op->Pt;
4452
0
    op = op->Next;
4453
0
  }
4454
0
  delete [] outPts;
4455
0
}
4456
//------------------------------------------------------------------------------
4457
4458
void CleanPolygon(Path& poly, double distance)
4459
0
{
4460
0
  CleanPolygon(poly, poly, distance);
4461
0
}
4462
//------------------------------------------------------------------------------
4463
4464
void CleanPolygons(const Paths& in_polys, Paths& out_polys, double distance)
4465
0
{
4466
0
  out_polys.resize(in_polys.size());
4467
0
  for (Paths::size_type i = 0; i < in_polys.size(); ++i)
4468
0
    CleanPolygon(in_polys[i], out_polys[i], distance);
4469
0
}
4470
//------------------------------------------------------------------------------
4471
4472
void CleanPolygons(Paths& polys, double distance)
4473
0
{
4474
0
  CleanPolygons(polys, polys, distance);
4475
0
}
4476
//------------------------------------------------------------------------------
4477
4478
void Minkowski(const Path& poly, const Path& path,
4479
  Paths& solution, bool isSum, bool isClosed)
4480
0
{
4481
0
  int delta = (isClosed ? 1 : 0);
4482
0
  size_t polyCnt = poly.size();
4483
0
  size_t pathCnt = path.size();
4484
0
  Paths pp;
4485
0
  pp.reserve(pathCnt);
4486
0
  if (isSum)
4487
0
    for (size_t i = 0; i < pathCnt; ++i)
4488
0
    {
4489
0
      Path p;
4490
0
      p.reserve(polyCnt);
4491
0
      for (size_t j = 0; j < poly.size(); ++j)
4492
0
        p.push_back(IntPoint(path[i].X + poly[j].X, path[i].Y + poly[j].Y));
4493
0
      pp.push_back(p);
4494
0
    }
4495
0
  else
4496
0
    for (size_t i = 0; i < pathCnt; ++i)
4497
0
    {
4498
0
      Path p;
4499
0
      p.reserve(polyCnt);
4500
0
      for (size_t j = 0; j < poly.size(); ++j)
4501
0
        p.push_back(IntPoint(path[i].X - poly[j].X, path[i].Y - poly[j].Y));
4502
0
      pp.push_back(p);
4503
0
    }
4504
4505
0
  solution.clear();
4506
0
  solution.reserve((pathCnt + delta) * (polyCnt + 1));
4507
0
  for (size_t i = 0; i < pathCnt - 1 + delta; ++i)
4508
0
    for (size_t j = 0; j < polyCnt; ++j)
4509
0
    {
4510
0
      Path quad;
4511
0
      quad.reserve(4);
4512
0
      quad.push_back(pp[i % pathCnt][j % polyCnt]);
4513
0
      quad.push_back(pp[(i + 1) % pathCnt][j % polyCnt]);
4514
0
      quad.push_back(pp[(i + 1) % pathCnt][(j + 1) % polyCnt]);
4515
0
      quad.push_back(pp[i % pathCnt][(j + 1) % polyCnt]);
4516
0
      if (!Orientation(quad)) ReversePath(quad);
4517
0
      solution.push_back(quad);
4518
0
    }
4519
0
}
4520
//------------------------------------------------------------------------------
4521
4522
void MinkowskiSum(const Path& pattern, const Path& path, Paths& solution, bool pathIsClosed)
4523
0
{
4524
0
  Minkowski(pattern, path, solution, true, pathIsClosed);
4525
0
  Clipper c;
4526
0
  c.AddPaths(solution, ptSubject, true);
4527
0
  c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
4528
0
}
4529
//------------------------------------------------------------------------------
4530
4531
void TranslatePath(const Path& input, Path& output, const IntPoint delta)
4532
0
{
4533
  //precondition: input != output
4534
0
  output.resize(input.size());
4535
0
  for (size_t i = 0; i < input.size(); ++i)
4536
0
    output[i] = IntPoint(input[i].X + delta.X, input[i].Y + delta.Y);
4537
0
}
4538
//------------------------------------------------------------------------------
4539
4540
void MinkowskiSum(const Path& pattern, const Paths& paths, Paths& solution, bool pathIsClosed)
4541
0
{
4542
0
  Clipper c;
4543
0
  for (size_t i = 0; i < paths.size(); ++i)
4544
0
  {
4545
0
    Paths tmp;
4546
0
    Minkowski(pattern, paths[i], tmp, true, pathIsClosed);
4547
0
    c.AddPaths(tmp, ptSubject, true);
4548
0
    if (pathIsClosed)
4549
0
    {
4550
0
      Path tmp2;
4551
0
      TranslatePath(paths[i], tmp2, pattern[0]);
4552
0
      c.AddPath(tmp2, ptClip, true);
4553
0
    }
4554
0
  }
4555
0
    c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
4556
0
}
4557
//------------------------------------------------------------------------------
4558
4559
void MinkowskiDiff(const Path& poly1, const Path& poly2, Paths& solution)
4560
0
{
4561
0
  Minkowski(poly1, poly2, solution, false, true);
4562
0
  Clipper c;
4563
0
  c.AddPaths(solution, ptSubject, true);
4564
0
  c.Execute(ctUnion, solution, pftNonZero, pftNonZero);
4565
0
}
4566
//------------------------------------------------------------------------------
4567
4568
enum NodeType {ntAny, ntOpen, ntClosed};
4569
4570
void AddPolyNodeToPaths(const PolyNode& polynode, NodeType nodetype, Paths& paths)
4571
0
{
4572
0
  bool match = true;
4573
0
  if (nodetype == ntClosed) match = !polynode.IsOpen();
4574
0
  else if (nodetype == ntOpen) return;
4575
4576
0
  if (!polynode.Contour.empty() && match)
4577
0
    paths.push_back(polynode.Contour);
4578
0
  for (int i = 0; i < polynode.ChildCount(); ++i)
4579
0
    AddPolyNodeToPaths(*polynode.Childs[i], nodetype, paths);
4580
0
}
4581
//------------------------------------------------------------------------------
4582
4583
void PolyTreeToPaths(const PolyTree& polytree, Paths& paths)
4584
0
{
4585
0
  paths.resize(0);
4586
0
  paths.reserve(polytree.Total());
4587
0
  AddPolyNodeToPaths(polytree, ntAny, paths);
4588
0
}
4589
//------------------------------------------------------------------------------
4590
4591
void ClosedPathsFromPolyTree(const PolyTree& polytree, Paths& paths)
4592
0
{
4593
0
  paths.resize(0);
4594
0
  paths.reserve(polytree.Total());
4595
0
  AddPolyNodeToPaths(polytree, ntClosed, paths);
4596
0
}
4597
//------------------------------------------------------------------------------
4598
4599
void OpenPathsFromPolyTree(PolyTree& polytree, Paths& paths)
4600
0
{
4601
0
  paths.resize(0);
4602
0
  paths.reserve(polytree.Total());
4603
  //Open paths are top level only, so ...
4604
0
  for (int i = 0; i < polytree.ChildCount(); ++i)
4605
0
    if (polytree.Childs[i]->IsOpen())
4606
0
      paths.push_back(polytree.Childs[i]->Contour);
4607
0
}
4608
//------------------------------------------------------------------------------
4609
4610
std::ostream& operator <<(std::ostream &s, const IntPoint &p)
4611
0
{
4612
0
  s << "(" << p.X << "," << p.Y << ")";
4613
0
  return s;
4614
0
}
4615
//------------------------------------------------------------------------------
4616
4617
std::ostream& operator <<(std::ostream &s, const Path &p)
4618
0
{
4619
0
  if (p.empty()) return s;
4620
0
  Path::size_type last = p.size() -1;
4621
0
  for (Path::size_type i = 0; i < last; i++)
4622
0
    s << "(" << p[i].X << "," << p[i].Y << "), ";
4623
0
  s << "(" << p[last].X << "," << p[last].Y << ")\n";
4624
0
  return s;
4625
0
}
4626
//------------------------------------------------------------------------------
4627
4628
std::ostream& operator <<(std::ostream &s, const Paths &p)
4629
0
{
4630
0
  for (Paths::size_type i = 0; i < p.size(); i++)
4631
0
    s << p[i];
4632
0
  s << "\n";
4633
0
  return s;
4634
0
}
4635
//------------------------------------------------------------------------------
4636
4637
} //ClipperLib namespace