53 static double const pi = 3.141592653589793238;
60 static int const Skip = -2;
62 #define HORIZONTAL (-1.0E+40)
63 #define TOLERANCE (1.0e-20)
64 #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE))
86 struct IntersectNode {
129 return locMin2.
Y < locMin1.
Y;
138 if ((val < 0))
return static_cast<cInt>(val - 0.5);
139 else return static_cast<cInt>(val + 0.5);
145 return val < 0 ? -val : val;
154 for (PolyNodes::size_type
i = 0;
i <
AllNodes.size(); ++
i)
187 int PolyNode::ChildCount()
const
189 return (
int)Childs.size();
193 void PolyNode::AddChild(
PolyNode& child)
195 unsigned cnt = (unsigned)Childs.size();
196 Childs.push_back(&child);
207 return GetNextSiblingUp();
211 PolyNode* PolyNode::GetNextSiblingUp()
const
215 else if (
Index == Parent->Childs.size() - 1)
222 bool PolyNode::IsHole()
const
235 bool PolyNode::IsOpen()
const
260 if (_lo < 0) hi = -1;
else hi = 0;
266 Int128(
const long64& _hi,
const ulong64& _lo): lo(_lo), hi(_hi){}
268 Int128& operator = (
const long64 &val)
271 if (val < 0) hi = -1;
else hi = 0;
275 bool operator == (
const Int128 &val)
const
276 {
return (hi == val.
hi && lo == val.
lo);}
278 bool operator != (
const Int128 &val)
const
279 {
return !(*
this == val);}
281 bool operator > (
const Int128 &val)
const
289 bool operator < (
const Int128 &val)
const
297 bool operator >= (
const Int128 &val)
const
298 {
return !(*
this < val);}
300 bool operator <= (
const Int128 &val)
const
301 {
return !(*
this > val);}
307 if (lo < rhs.
lo) hi++;
341 const double shift64 = 18446744073709551616.0;
344 if (lo == 0)
return (
double)hi * shift64;
345 else return -(
double)(~lo + ~hi * shift64);
348 return (
double)(lo + hi * shift64);
356 bool negate = (lhs < 0) != (rhs < 0);
358 if (lhs < 0) lhs = -lhs;
362 if (rhs < 0) rhs = -rhs;
369 ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi;
376 if (negate) tmp = -tmp;
387 return Area(poly) >= 0;
393 int size = (
int)poly.size();
394 if (size < 3)
return 0;
397 for (
int i = 0,
j = size -1;
i < size; ++
i)
406 double Area(
const OutPt *op)
408 const OutPt *startOp = op;
412 a += (
double)(op->Prev->Pt.X + op->Pt.X) * (
double)(op->Prev->Pt.Y - op->Pt.Y);
414 }
while (op != startOp);
419 double Area(
const OutRec &outRec)
430 if (pp2->
Pt == Pt)
return true;
444 size_t cnt = path.size();
445 if (cnt < 3)
return 0;
447 for(
size_t i = 1;
i <= cnt; ++
i)
449 IntPoint ipNext = (
i == cnt ? path[0] : path[
i]);
450 if (ipNext.
Y == pt.Y)
452 if ((ipNext.
X == pt.X) || (ip.
Y == pt.Y &&
453 ((ipNext.
X > pt.X) == (ip.
X < pt.X))))
return -1;
455 if ((ip.
Y < pt.Y) != (ipNext.
Y < pt.Y))
459 if (ipNext.
X > pt.X) result = 1 - result;
462 double d = (
double)(ip.
X - pt.X) * (ipNext.
Y - pt.Y) -
463 (
double)(ipNext.
X - pt.X) * (ip.
Y - pt.Y);
465 if ((
d > 0) == (ipNext.
Y > ip.
Y)) result = 1 - result;
471 double d = (
double)(ip.
X - pt.X) * (ipNext.
Y - pt.Y) -
472 (
double)(ipNext.
X - pt.X) * (ip.
Y - pt.Y);
474 if ((
d > 0) == (ipNext.
Y > ip.
Y)) result = 1 - result;
491 if (op->Next->Pt.Y == pt.Y)
493 if ((op->Next->Pt.X == pt.X) || (op->Pt.Y == pt.Y &&
494 ((op->Next->Pt.X > pt.X) == (op->Pt.X < pt.X))))
return -1;
496 if ((op->Pt.Y < pt.Y) != (op->Next->Pt.Y < pt.Y))
498 if (op->Pt.X >= pt.X)
500 if (op->Next->Pt.X > pt.X) result = 1 - result;
503 double d = (
double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
504 (
double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
506 if ((
d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
510 if (op->Next->Pt.X > pt.X)
512 double d = (
double)(op->Pt.X - pt.X) * (op->Next->Pt.Y - pt.Y) -
513 (
double)(op->Next->Pt.X - pt.X) * (op->Pt.Y - pt.Y);
515 if ((
d > 0) == (op->Next->Pt.Y > op->Pt.Y)) result = 1 - result;
520 if (startOp == op)
break;
533 if (res >= 0)
return res > 0;
536 while (op != OutPt1);
541 bool SlopesEqual(
const TEdge &e1,
const TEdge &e2,
bool UseFullInt64Range)
544 if (UseFullInt64Range)
545 return Int128Mul(e1.Top.Y - e1.Bot.Y, e2.Top.X - e2.Bot.X) ==
546 Int128Mul(e1.Top.X - e1.Bot.X, e2.Top.Y - e2.Bot.Y);
549 return (e1.Top.Y - e1.Bot.Y) * (e2.Top.X - e2.Bot.X) ==
550 (e1.Top.X - e1.Bot.X) * (e2.Top.Y - e2.Bot.Y);
554 bool SlopesEqual(
const IntPoint pt1,
const IntPoint pt2,
555 const IntPoint pt3,
bool UseFullInt64Range)
558 if (UseFullInt64Range)
562 return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y);
566 bool SlopesEqual(
const IntPoint pt1,
const IntPoint pt2,
567 const IntPoint pt3,
const IntPoint pt4,
bool UseFullInt64Range)
570 if (UseFullInt64Range)
574 return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y);
584 inline double GetDx(
const IntPoint pt1,
const IntPoint pt2)
586 return (pt1.Y == pt2.Y) ?
593 cInt dy = (e.Top.Y - e.Bot.Y);
595 else e.Dx = (
double)(e.Top.X - e.Bot.X) / dy;
599 inline void SwapSides(TEdge &Edge1, TEdge &Edge2)
602 Edge1.Side = Edge2.Side;
609 int OutIdx = Edge1.OutIdx;
610 Edge1.OutIdx = Edge2.OutIdx;
611 Edge2.OutIdx = OutIdx;
617 return ( currentY == edge.Top.Y ) ?
618 edge.Top.X : edge.Bot.X +
Round(edge.Dx *(currentY - edge.Bot.Y));
629 if (Edge1.Dx == Edge2.Dx)
635 else if (Edge1.Dx == 0)
642 b2 = Edge2.Bot.Y - (Edge2.Bot.X / Edge2.Dx);
646 else if (Edge2.Dx == 0)
653 b1 = Edge1.Bot.Y - (Edge1.Bot.X / Edge1.Dx);
654 ip.
Y =
Round(ip.
X / Edge1.Dx + b1);
659 b1 = Edge1.Bot.X - Edge1.Bot.Y * Edge1.Dx;
660 b2 = Edge2.Bot.X - Edge2.Bot.Y * Edge2.Dx;
661 double q = (b2-b1) / (Edge1.Dx - Edge2.Dx);
663 if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
664 ip.
X =
Round(Edge1.Dx * q + b1);
666 ip.
X =
Round(Edge2.Dx * q + b2);
669 if (ip.
Y < Edge1.Top.Y || ip.
Y < Edge2.Top.Y)
671 if (Edge1.Top.Y > Edge2.Top.Y)
675 if (std::fabs(Edge1.Dx) < std::fabs(Edge2.Dx))
681 if (ip.
Y > Edge1.Curr.Y)
685 if (std::fabs(Edge1.Dx) > std::fabs(Edge2.Dx))
686 ip.
X =
TopX(Edge2, ip.
Y);
else
702 }
while( pp1 != pp );
719 inline void InitEdge(TEdge* e, TEdge* eNext, TEdge* ePrev,
const IntPoint& Pt)
721 std::memset(e, 0,
sizeof(TEdge));
731 if (e.Curr.Y >= e.Next->Curr.Y)
734 e.Top = e.Next->Curr;
738 e.Bot = e.Next->Curr;
748 e->Prev->Next = e->Next;
749 e->Next->Prev = e->Prev;
750 TEdge* result = e->Next;
761 std::swap(e.Top.X, e.Bot.X);
763 std::swap(e.Top.Z, e.Bot.Z);
777 IntPoint pt2b, IntPoint &pt1, IntPoint &pt2)
780 if (
Abs(pt1a.X - pt1b.X) >
Abs(pt1a.Y - pt1b.Y))
784 if (pt1a.X > pt2a.X) pt1 = pt1a;
else pt1 = pt2a;
785 if (pt1b.X < pt2b.X) pt2 = pt1b;
else pt2 = pt2b;
786 return pt1.X < pt2.X;
791 if (pt1a.Y < pt2a.Y) pt1 = pt1a;
else pt1 = pt2a;
792 if (pt1b.Y > pt2b.Y) pt2 = pt1b;
else pt2 = pt2b;
793 return pt1.Y > pt2.Y;
800 OutPt *p = btmPt1->Prev;
801 while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Prev;
802 double dx1p = std::fabs(
GetDx(btmPt1->Pt, p->Pt));
804 while ((p->Pt == btmPt1->Pt) && (p != btmPt1)) p = p->Next;
805 double dx1n = std::fabs(
GetDx(btmPt1->Pt, p->Pt));
808 while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Prev;
809 double dx2p = std::fabs(
GetDx(btmPt2->Pt, p->Pt));
811 while ((p->Pt == btmPt2->Pt) && (p != btmPt2)) p = p->Next;
812 double dx2n = std::fabs(
GetDx(btmPt2->Pt, p->Pt));
814 if (std::max(dx1p, dx1n) == std::max(dx2p, dx2n) &&
815 std::min(dx1p, dx1n) == std::min(dx2p, dx2n))
816 return Area(btmPt1) > 0;
818 return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n);
828 if (p->Pt.Y > pp->Pt.Y)
833 else if (p->Pt.Y == pp->Pt.Y && p->Pt.X <= pp->Pt.X)
835 if (p->Pt.X < pp->Pt.X)
841 if (p->Next != pp && p->Prev != pp) dups = p;
853 while (dups->Pt != pp->Pt) dups = dups->
Next;
863 if ((pt1 == pt3) || (pt1 == pt2) || (pt3 == pt2))
865 else if (pt1.
X != pt3.
X)
866 return (pt2.
X > pt1.
X) == (pt2.
X < pt3.
X);
868 return (pt2.
Y > pt1.
Y) == (pt2.
Y < pt3.
Y);
874 if (seg1a > seg1b) std::swap(seg1a, seg1b);
875 if (seg2a > seg2b) std::swap(seg2a, seg2b);
876 return (seg1a < seg2b) && (seg2a < seg1b);
883 ClipperBase::ClipperBase()
885 m_CurrentLM = m_MinimaList.begin();
886 m_UseFullRange =
false;
890 ClipperBase::~ClipperBase()
915 while (
E->Bot !=
E->Prev->Bot ||
E->Curr ==
E->Top)
E =
E->Next;
920 if (
E->Top.Y ==
E->Prev->Bot.Y)
continue;
921 if (E2->Prev->Bot.X <
E->Bot.X)
E = E2;
928 TEdge* ClipperBase::ProcessBound(
TEdge*
E,
bool NextIsForward)
933 if (
E->OutIdx ==
Skip)
939 while (
E->Top.Y ==
E->Next->Bot.Y)
E =
E->Next;
946 while (
E->Top.Y ==
E->Prev->Bot.Y)
E =
E->Prev;
952 if (NextIsForward) Result =
E->Next;
953 else Result =
E->Prev;
962 MinimaList::value_type locMin;
964 locMin.LeftBound = 0;
965 locMin.RightBound =
E;
967 Result = ProcessBound(
E, NextIsForward);
968 m_MinimaList.push_back(locMin);
986 if (EStart->Bot.X !=
E->Bot.X && EStart->Top.X !=
E->Bot.X)
989 else if (EStart->Bot.X !=
E->Bot.X)
996 while (Result->Top.Y == Result->Next->Bot.Y && Result->Next->OutIdx !=
Skip)
997 Result = Result->Next;
1005 if (Horz->Prev->Top.X > Result->Next->Top.X) Result = Horz->Prev;
1009 E->NextInLML =
E->Next;
1016 Result = Result->Next;
1019 while (Result->Top.Y == Result->Prev->Bot.Y && Result->Prev->OutIdx !=
Skip)
1020 Result = Result->Prev;
1025 if (Horz->Next->Top.X == Result->Prev->Top.X ||
1026 Horz->Next->Top.X > Result->Prev->Top.X) Result = Horz->Next;
1031 E->NextInLML =
E->Prev;
1038 Result = Result->Prev;
1045 bool ClipperBase::AddPath(
const Path &pg,
PolyType PolyTyp,
bool Closed)
1048 if (!Closed && PolyTyp ==
ptClip)
1049 throw clipperException(
"AddPath: Open paths must be subject.");
1052 throw clipperException(
"AddPath: Open paths have been disabled.");
1055 int highI = (
int)pg.size() -1;
1056 if (Closed)
while (highI > 0 && (pg[highI] == pg[0])) --highI;
1057 while (highI > 0 && (pg[highI] == pg[highI -1])) --highI;
1058 if ((Closed && highI < 2) || (!Closed && highI < 1))
return false;
1061 TEdge *edges =
new TEdge [highI +1];
1067 edges[1].Curr = pg[1];
1070 InitEdge(&edges[0], &edges[1], &edges[highI], pg[0]);
1071 InitEdge(&edges[highI], &edges[0], &edges[highI-1], pg[highI]);
1072 for (
int i = highI - 1;
i >= 1; --
i)
1083 TEdge *eStart = &edges[0];
1086 TEdge *
E = eStart, *eLoopStop = eStart;
1090 if (
E->Curr ==
E->Next->Curr && (Closed ||
E->Next != eStart))
1092 if (
E ==
E->Next)
break;
1093 if (
E == eStart) eStart =
E->Next;
1098 if (
E->Prev ==
E->Next)
1101 SlopesEqual(
E->Prev->Curr,
E->Curr,
E->Next->Curr, m_UseFullRange) &&
1102 (!m_PreserveCollinear ||
1109 if (
E == eStart) eStart =
E->Next;
1116 if ((
E == eLoopStop) || (!Closed &&
E->Next == eStart))
break;
1119 if ((!Closed && (
E ==
E->Next)) || (Closed && (
E->Prev ==
E->Next)))
1127 m_HasOpenPaths =
true;
1128 eStart->Prev->OutIdx =
Skip;
1137 if (IsFlat &&
E->Curr.Y != eStart->Curr.Y) IsFlat =
false;
1139 while (
E != eStart);
1152 E->Prev->OutIdx =
Skip;
1153 MinimaList::value_type locMin;
1154 locMin.Y =
E->Bot.Y;
1155 locMin.LeftBound = 0;
1156 locMin.RightBound =
E;
1157 locMin.RightBound->Side =
esRight;
1158 locMin.RightBound->WindDelta = 0;
1162 if (
E->Next->OutIdx ==
Skip)
break;
1163 E->NextInLML =
E->Next;
1166 m_MinimaList.push_back(locMin);
1167 m_edges.push_back(edges);
1171 m_edges.push_back(edges);
1172 bool leftBoundIsForward;
1177 if (
E->Prev->Bot ==
E->Prev->Top)
E =
E->Next;
1182 if (
E == EMin)
break;
1183 else if (!EMin) EMin =
E;
1187 MinimaList::value_type locMin;
1188 locMin.Y =
E->Bot.Y;
1189 if (
E->Dx <
E->Prev->Dx)
1191 locMin.LeftBound =
E->Prev;
1192 locMin.RightBound =
E;
1193 leftBoundIsForward =
false;
1196 locMin.LeftBound =
E;
1197 locMin.RightBound =
E->Prev;
1198 leftBoundIsForward =
true;
1201 if (!Closed) locMin.LeftBound->WindDelta = 0;
1202 else if (locMin.LeftBound->Next == locMin.RightBound)
1203 locMin.LeftBound->WindDelta = -1;
1204 else locMin.LeftBound->WindDelta = 1;
1205 locMin.RightBound->WindDelta = -locMin.LeftBound->WindDelta;
1207 E = ProcessBound(locMin.LeftBound, leftBoundIsForward);
1208 if (
E->OutIdx ==
Skip)
E = ProcessBound(
E, leftBoundIsForward);
1210 TEdge* E2 = ProcessBound(locMin.RightBound, !leftBoundIsForward);
1211 if (E2->OutIdx ==
Skip) E2 = ProcessBound(E2, !leftBoundIsForward);
1213 if (locMin.LeftBound->OutIdx ==
Skip)
1214 locMin.LeftBound = 0;
1215 else if (locMin.RightBound->OutIdx ==
Skip)
1216 locMin.RightBound = 0;
1217 m_MinimaList.push_back(locMin);
1218 if (!leftBoundIsForward)
E = E2;
1224 bool ClipperBase::AddPaths(
const Paths &ppg,
PolyType PolyTyp,
bool Closed)
1226 bool result =
false;
1227 for (Paths::size_type
i = 0;
i < ppg.size(); ++
i)
1228 if (AddPath(ppg[
i], PolyTyp, Closed)) result =
true;
1233 void ClipperBase::Clear()
1235 DisposeLocalMinimaList();
1236 for (EdgeList::size_type
i = 0;
i < m_edges.size(); ++
i)
1238 TEdge* edges = m_edges[
i];
1242 m_UseFullRange =
false;
1243 m_HasOpenPaths =
false;
1247 void ClipperBase::Reset()
1249 m_CurrentLM = m_MinimaList.begin();
1250 if (m_CurrentLM == m_MinimaList.end())
return;
1251 std::sort(m_MinimaList.begin(), m_MinimaList.end(), LocMinSorter());
1253 m_Scanbeam = ScanbeamList();
1255 for (MinimaList::iterator lm = m_MinimaList.begin(); lm != m_MinimaList.end(); ++lm)
1257 InsertScanbeam(lm->Y);
1258 TEdge* e = lm->LeftBound;
1275 m_CurrentLM = m_MinimaList.begin();
1279 void ClipperBase::DisposeLocalMinimaList()
1281 m_MinimaList.clear();
1282 m_CurrentLM = m_MinimaList.begin();
1288 if (m_CurrentLM == m_MinimaList.end() || (*m_CurrentLM).Y != Y)
return false;
1289 locMin = &(*m_CurrentLM);
1295 IntRect ClipperBase::GetBounds()
1298 MinimaList::iterator lm = m_MinimaList.begin();
1299 if (lm == m_MinimaList.end())
1301 result.left = result.top = result.right = result.bottom = 0;
1304 result.left = lm->LeftBound->Bot.X;
1305 result.top = lm->LeftBound->Bot.Y;
1306 result.right = lm->LeftBound->Bot.X;
1307 result.bottom = lm->LeftBound->Bot.Y;
1308 while (lm != m_MinimaList.end())
1311 result.bottom = std::max(result.bottom, lm->LeftBound->Bot.Y);
1312 TEdge* e = lm->LeftBound;
1315 while (e->NextInLML)
1317 if (e->Bot.X < result.left) result.left = e->Bot.X;
1318 if (e->Bot.X > result.right) result.right = e->Bot.X;
1321 result.left = std::min(result.left, e->Bot.X);
1322 result.right = std::max(result.right, e->Bot.X);
1323 result.left = std::min(result.left, e->Top.X);
1324 result.right = std::max(result.right, e->Top.X);
1325 result.top = std::min(result.top, e->Top.Y);
1326 if (bottomE == lm->LeftBound) e = lm->RightBound;
1335 void ClipperBase::InsertScanbeam(
const cInt Y)
1341 bool ClipperBase::PopScanbeam(
cInt &Y)
1343 if (m_Scanbeam.empty())
return false;
1344 Y = m_Scanbeam.top();
1346 while (!m_Scanbeam.empty() && Y == m_Scanbeam.top()) { m_Scanbeam.pop(); }
1351 void ClipperBase::DisposeAllOutRecs(){
1352 for (PolyOutList::size_type
i = 0;
i < m_PolyOuts.size(); ++
i)
1358 void ClipperBase::DisposeOutRec(PolyOutList::size_type index)
1360 OutRec *outRec = m_PolyOuts[index];
1363 m_PolyOuts[index] = 0;
1367 void ClipperBase::DeleteFromAEL(TEdge *e)
1369 TEdge* AelPrev = e->PrevInAEL;
1370 TEdge* AelNext = e->NextInAEL;
1371 if (!AelPrev && !AelNext && (e != m_ActiveEdges))
return;
1372 if (AelPrev) AelPrev->NextInAEL = AelNext;
1373 else m_ActiveEdges = AelNext;
1374 if (AelNext) AelNext->PrevInAEL = AelPrev;
1380 OutRec* ClipperBase::CreateOutRec()
1389 m_PolyOuts.push_back(result);
1390 result->
Idx = (
int)m_PolyOuts.size() - 1;
1395 void ClipperBase::SwapPositionsInAEL(
TEdge *Edge1,
TEdge *Edge2)
1398 if (Edge1->NextInAEL == Edge1->PrevInAEL ||
1399 Edge2->NextInAEL == Edge2->PrevInAEL)
return;
1401 if (Edge1->NextInAEL == Edge2)
1404 if (Next) Next->PrevInAEL = Edge1;
1405 TEdge* Prev = Edge1->PrevInAEL;
1406 if (Prev) Prev->NextInAEL = Edge2;
1407 Edge2->PrevInAEL = Prev;
1408 Edge2->NextInAEL = Edge1;
1409 Edge1->PrevInAEL = Edge2;
1410 Edge1->NextInAEL = Next;
1412 else if (Edge2->NextInAEL == Edge1)
1414 TEdge* Next = Edge1->NextInAEL;
1415 if (Next) Next->PrevInAEL = Edge2;
1417 if (Prev) Prev->NextInAEL = Edge1;
1418 Edge1->PrevInAEL = Prev;
1419 Edge1->NextInAEL = Edge2;
1420 Edge2->PrevInAEL = Edge1;
1421 Edge2->NextInAEL = Next;
1425 TEdge* Next = Edge1->NextInAEL;
1426 TEdge* Prev = Edge1->PrevInAEL;
1427 Edge1->NextInAEL = Edge2->NextInAEL;
1428 if (Edge1->NextInAEL) Edge1->NextInAEL->PrevInAEL = Edge1;
1429 Edge1->PrevInAEL = Edge2->PrevInAEL;
1430 if (Edge1->PrevInAEL) Edge1->PrevInAEL->NextInAEL = Edge1;
1431 Edge2->NextInAEL = Next;
1432 if (Edge2->NextInAEL) Edge2->NextInAEL->PrevInAEL = Edge2;
1433 Edge2->PrevInAEL = Prev;
1434 if (Edge2->PrevInAEL) Edge2->PrevInAEL->NextInAEL = Edge2;
1437 if (!Edge1->PrevInAEL) m_ActiveEdges = Edge1;
1438 else if (!Edge2->PrevInAEL) m_ActiveEdges = Edge2;
1442 void ClipperBase::UpdateEdgeIntoAEL(TEdge *&e)
1445 throw clipperException(
"UpdateEdgeIntoAEL: invalid call");
1447 e->NextInLML->OutIdx = e->OutIdx;
1448 TEdge* AelPrev = e->PrevInAEL;
1449 TEdge* AelNext = e->NextInAEL;
1450 if (AelPrev) AelPrev->NextInAEL = e->NextInLML;
1451 else m_ActiveEdges = e->NextInLML;
1452 if (AelNext) AelNext->PrevInAEL = e->NextInLML;
1453 e->NextInLML->Side = e->Side;
1454 e->NextInLML->WindDelta = e->WindDelta;
1455 e->NextInLML->WindCnt = e->WindCnt;
1456 e->NextInLML->WindCnt2 = e->WindCnt2;
1459 e->PrevInAEL = AelPrev;
1460 e->NextInAEL = AelNext;
1465 bool ClipperBase::LocalMinimaPending()
1467 return (m_CurrentLM != m_MinimaList.end());
1474 Clipper::Clipper(
int initOptions) : ClipperBase()
1476 m_ExecuteLocked =
false;
1489 void Clipper::ZFillFunction(ZFillCallback zFillFunc)
1491 m_ZFill = zFillFunc;
1498 return Execute(clipType, solution, fillType, fillType);
1504 return Execute(clipType, polytree, fillType, fillType);
1513 throw clipperException(
"Error: PolyTree struct is needed for open path clipping.");
1562 bool succeeded =
true;
1594 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
1597 if (!outRec->
Pts || outRec->
IsOpen)
continue;
1605 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
1608 if (!outRec->
Pts)
continue;
1626 TEdge *e = edge.PrevInAEL;
1628 while (e && ((e->PolyTyp != edge.PolyTyp) || (e->WindDelta == 0))) e = e->PrevInAEL;
1631 if (edge.WindDelta == 0)
1637 edge.WindCnt = edge.WindDelta;
1644 edge.WindCnt2 = e->WindCnt2;
1650 if (edge.WindDelta == 0)
1654 TEdge *e2 = e->PrevInAEL;
1657 if (e2->PolyTyp == e->PolyTyp && e2->WindDelta != 0)
1661 edge.WindCnt = (Inside ? 0 : 1);
1665 edge.WindCnt = edge.WindDelta;
1667 edge.WindCnt2 = e->WindCnt2;
1673 if (e->WindCnt * e->WindDelta < 0)
1677 if (
Abs(e->WindCnt) > 1)
1681 if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1683 else edge.WindCnt = e->WindCnt + edge.WindDelta;
1687 edge.WindCnt = (edge.WindDelta == 0 ? 1 : edge.WindDelta);
1692 if (edge.WindDelta == 0)
1693 edge.WindCnt = (e->WindCnt < 0 ? e->WindCnt - 1 : e->WindCnt + 1);
1695 else if (e->WindDelta * edge.WindDelta < 0) edge.WindCnt = e->WindCnt;
1697 else edge.WindCnt = e->WindCnt + edge.WindDelta;
1699 edge.WindCnt2 = e->WindCnt2;
1709 if (e->WindDelta != 0)
1710 edge.WindCnt2 = (edge.WindCnt2 == 0 ? 1 : 0);
1716 while ( e != &edge )
1718 edge.WindCnt2 += e->WindDelta;
1758 if (edge.WindDelta == 0 && edge.WindCnt != 1)
return false;
1761 if (
Abs(edge.WindCnt) != 1)
return false;
1764 if (edge.WindCnt != 1)
return false;
1767 if (edge.WindCnt != -1)
return false;
1777 return (edge.WindCnt2 != 0);
1779 return (edge.WindCnt2 > 0);
1781 return (edge.WindCnt2 < 0);
1789 return (edge.WindCnt2 == 0);
1791 return (edge.WindCnt2 <= 0);
1793 return (edge.WindCnt2 >= 0);
1802 return (edge.WindCnt2 == 0);
1804 return (edge.WindCnt2 <= 0);
1806 return (edge.WindCnt2 >= 0);
1813 return (edge.WindCnt2 != 0);
1815 return (edge.WindCnt2 > 0);
1817 return (edge.WindCnt2 < 0);
1821 if (edge.WindDelta == 0)
1826 return (edge.WindCnt2 == 0);
1828 return (edge.WindCnt2 <= 0);
1830 return (edge.WindCnt2 >= 0);
1848 e2->OutIdx = e1->OutIdx;
1852 if (e->PrevInAEL == e2)
1853 prevE = e2->PrevInAEL;
1855 prevE = e->PrevInAEL;
1859 e1->OutIdx = e2->OutIdx;
1863 if (e->PrevInAEL == e1)
1864 prevE = e1->PrevInAEL;
1866 prevE = e->PrevInAEL;
1869 if (prevE && prevE->OutIdx >= 0)
1873 if (xPrev == xE && (e->WindDelta != 0) && (prevE->WindDelta != 0) &&
1876 OutPt* outPt =
AddOutPt(prevE, Pt);
1887 if (e2->WindDelta == 0)
AddOutPt(e2, Pt);
1888 if( e1->OutIdx == e2->OutIdx )
1893 else if (e1->OutIdx < e2->OutIdx)
1907 edge->PrevInSEL = 0;
1908 edge->NextInSEL = 0;
1913 edge->PrevInSEL = 0;
1935 e->PrevInSEL = e->PrevInAEL;
1936 e->NextInSEL = e->NextInAEL;
1954 for (JoinList::size_type
i = 0;
i <
m_Joins.size();
i++)
2008 rb->WindCnt = lb->WindCnt;
2009 rb->WindCnt2 = lb->WindCnt2;
2026 if (!lb || !rb)
continue;
2042 if (lb->OutIdx >= 0 && lb->PrevInAEL &&
2043 lb->PrevInAEL->Curr.X == lb->Bot.X &&
2044 lb->PrevInAEL->OutIdx >= 0 &&
2046 (lb->WindDelta != 0) && (lb->PrevInAEL->WindDelta != 0))
2048 OutPt *Op2 =
AddOutPt(lb->PrevInAEL, lb->Bot);
2052 if(lb->NextInAEL != rb)
2055 if (rb->OutIdx >= 0 && rb->PrevInAEL->OutIdx >= 0 &&
2057 (rb->WindDelta != 0) && (rb->PrevInAEL->WindDelta != 0))
2059 OutPt *Op2 =
AddOutPt(rb->PrevInAEL, rb->Bot);
2063 TEdge* e = lb->NextInAEL;
2082 TEdge* SelPrev = e->PrevInSEL;
2083 TEdge* SelNext = e->NextInSEL;
2085 if( SelPrev ) SelPrev->NextInSEL = SelNext;
2087 if( SelNext ) SelNext->PrevInSEL = SelPrev;
2094 void Clipper::SetZ(IntPoint& pt, TEdge& e1, TEdge& e2)
2096 if (pt.Z != 0 || !m_ZFill)
return;
2097 else if (pt == e1.Bot) pt.Z = e1.Bot.Z;
2098 else if (pt == e1.Top) pt.Z = e1.Top.Z;
2099 else if (pt == e2.Bot) pt.Z = e2.Bot.Z;
2100 else if (pt == e2.Top) pt.Z = e2.Top.Z;
2101 else (*m_ZFill)(e1.Bot, e1.Top, e2.Bot, e2.Top, pt);
2108 bool e1Contributing = ( e1->OutIdx >= 0 );
2109 bool e2Contributing = ( e2->OutIdx >= 0 );
2117 if (e1->WindDelta == 0 || e2->WindDelta == 0)
2121 if (e1->WindDelta == 0 && e2->WindDelta == 0)
return;
2124 else if (e1->PolyTyp == e2->PolyTyp &&
2127 if (e1->WindDelta == 0)
2144 else if (e1->PolyTyp != e2->PolyTyp)
2147 if ((e1->WindDelta == 0) && abs(e2->WindCnt) == 1 &&
2153 else if ((e2->WindDelta == 0) && (abs(e1->WindCnt) == 1) &&
2166 if ( e1->PolyTyp == e2->PolyTyp )
2170 int oldE1WindCnt = e1->WindCnt;
2171 e1->WindCnt = e2->WindCnt;
2172 e2->WindCnt = oldE1WindCnt;
2175 if (e1->WindCnt + e2->WindDelta == 0 ) e1->WindCnt = -e1->WindCnt;
2176 else e1->WindCnt += e2->WindDelta;
2177 if ( e2->WindCnt - e1->WindDelta == 0 ) e2->WindCnt = -e2->WindCnt;
2178 else e2->WindCnt -= e1->WindDelta;
2183 else e1->WindCnt2 = ( e1->WindCnt2 == 0 ) ? 1 : 0;
2185 else e2->WindCnt2 = ( e2->WindCnt2 == 0 ) ? 1 : 0;
2188 PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2;
2213 default: e1Wc =
Abs(e1->WindCnt);
2219 default: e2Wc =
Abs(e2->WindCnt);
2222 if ( e1Contributing && e2Contributing )
2224 if ((e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) ||
2237 else if ( e1Contributing )
2239 if (e2Wc == 0 || e2Wc == 1)
2246 else if ( e2Contributing )
2248 if (e1Wc == 0 || e1Wc == 1)
2255 else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1))
2260 switch (e1FillType2)
2264 default: e1Wc2 =
Abs(e1->WindCnt2);
2266 switch (e2FillType2)
2270 default: e2Wc2 =
Abs(e2->WindCnt2);
2273 if (e1->PolyTyp != e2->PolyTyp)
2277 else if (e1Wc == 1 && e2Wc == 1)
2280 if (e1Wc2 > 0 && e2Wc2 > 0)
2284 if ( e1Wc2 <= 0 && e2Wc2 <= 0 )
2288 if (((e1->PolyTyp ==
ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
2289 ((e1->PolyTyp ==
ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
2303 TEdge *e2 = e->PrevInAEL;
2307 if (e2->OutIdx >= 0 && e2->WindDelta != 0)
2309 if (!eTmp) eTmp = e2;
2310 else if (eTmp->OutIdx == e2->OutIdx) eTmp = 0;
2316 outrec->FirstLeft = 0;
2317 outrec->IsHole =
false;
2321 outrec->FirstLeft =
m_PolyOuts[eTmp->OutIdx];
2322 outrec->IsHole = !outrec->FirstLeft->IsHole;
2330 if (!outRec1->BottomPt)
2332 if (!outRec2->BottomPt)
2334 OutPt *OutPt1 = outRec1->BottomPt;
2335 OutPt *OutPt2 = outRec2->BottomPt;
2336 if (OutPt1->Pt.Y > OutPt2->Pt.Y)
return outRec1;
2337 else if (OutPt1->Pt.Y < OutPt2->Pt.Y)
return outRec2;
2338 else if (OutPt1->Pt.X < OutPt2->Pt.X)
return outRec1;
2339 else if (OutPt1->Pt.X > OutPt2->Pt.X)
return outRec2;
2340 else if (OutPt1->Next == OutPt1)
return outRec2;
2341 else if (OutPt2->Next == OutPt2)
return outRec1;
2343 else return outRec2;
2352 if (outRec1 == outRec2)
return true;
2373 OutRec *holeStateRec;
2375 holeStateRec = outRec2;
2377 holeStateRec = outRec1;
2384 OutPt* p1_lft = outRec1->Pts;
2386 OutPt* p2_lft = outRec2->Pts;
2396 p2_lft->
Next = p1_lft;
2397 p1_lft->
Prev = p2_lft;
2398 p1_rt->
Next = p2_rt;
2399 p2_rt->
Prev = p1_rt;
2400 outRec1->Pts = p2_rt;
2404 p2_rt->
Next = p1_lft;
2405 p1_lft->
Prev = p2_rt;
2406 p2_lft->
Prev = p1_rt;
2407 p1_rt->
Next = p2_lft;
2408 outRec1->Pts = p2_lft;
2416 p1_rt->
Next = p2_rt;
2417 p2_rt->
Prev = p1_rt;
2418 p2_lft->
Next = p1_lft;
2419 p1_lft->
Prev = p2_lft;
2423 p1_rt->
Next = p2_lft;
2424 p2_lft->
Prev = p1_rt;
2425 p1_lft->
Prev = p2_rt;
2426 p2_rt->
Next = p1_lft;
2430 outRec1->BottomPt = 0;
2431 if (holeStateRec == outRec2)
2433 if (outRec2->FirstLeft != outRec1)
2434 outRec1->FirstLeft = outRec2->FirstLeft;
2435 outRec1->IsHole = outRec2->IsHole;
2438 outRec2->BottomPt = 0;
2439 outRec2->FirstLeft = outRec1;
2441 int OKIdx = e1->OutIdx;
2442 int ObsoleteIdx = e2->OutIdx;
2450 if( e->OutIdx == ObsoleteIdx )
2459 outRec2->Idx = outRec1->Idx;
2468 outRec->IsOpen = (e->WindDelta == 0);
2469 OutPt* newOp =
new OutPt;
2470 outRec->Pts = newOp;
2471 newOp->Idx = outRec->Idx;
2473 newOp->Next = newOp;
2474 newOp->Prev = newOp;
2475 if (!outRec->IsOpen)
2477 e->OutIdx = outRec->Idx;
2483 OutPt* op = outRec->Pts;
2485 bool ToFront = (e->Side ==
esLeft);
2486 if (ToFront && (pt == op->Pt))
return op;
2487 else if (!ToFront && (pt == op->Prev->Pt))
return op->Prev;
2489 OutPt* newOp =
new OutPt;
2490 newOp->Idx = outRec->Idx;
2493 newOp->Prev = op->Prev;
2494 newOp->Prev->Next = newOp;
2496 if (ToFront) outRec->Pts = newOp;
2522 return e && (e->Prev->NextInLML != e) && (e->Next->NextInLML != e);
2528 return e && e->Top.Y == Y && !e->NextInLML;
2534 return e->Top.Y == Y && e->NextInLML;
2540 if ((e->Next->Top == e->Top) && !e->Next->NextInLML)
2542 else if ((e->Prev->Top == e->Top) && !e->Prev->NextInLML)
2552 if (result && (result->OutIdx ==
Skip ||
2553 (result->NextInAEL == result->PrevInAEL && !
IsHorizontal(*result))))
return 0;
2560 if( !( Edge1->NextInSEL ) && !( Edge1->PrevInSEL ) )
return;
2561 if( !( Edge2->NextInSEL ) && !( Edge2->PrevInSEL ) )
return;
2563 if( Edge1->NextInSEL == Edge2 )
2565 TEdge* Next = Edge2->NextInSEL;
2566 if( Next ) Next->PrevInSEL = Edge1;
2567 TEdge* Prev = Edge1->PrevInSEL;
2568 if( Prev ) Prev->NextInSEL = Edge2;
2569 Edge2->PrevInSEL = Prev;
2570 Edge2->NextInSEL = Edge1;
2571 Edge1->PrevInSEL = Edge2;
2572 Edge1->NextInSEL = Next;
2574 else if( Edge2->NextInSEL == Edge1 )
2576 TEdge* Next = Edge1->NextInSEL;
2577 if( Next ) Next->PrevInSEL = Edge2;
2578 TEdge* Prev = Edge2->PrevInSEL;
2579 if( Prev ) Prev->NextInSEL = Edge1;
2580 Edge1->PrevInSEL = Prev;
2581 Edge1->NextInSEL = Edge2;
2582 Edge2->PrevInSEL = Edge1;
2583 Edge2->NextInSEL = Next;
2587 TEdge* Next = Edge1->NextInSEL;
2588 TEdge* Prev = Edge1->PrevInSEL;
2589 Edge1->NextInSEL = Edge2->NextInSEL;
2590 if( Edge1->NextInSEL ) Edge1->NextInSEL->PrevInSEL = Edge1;
2591 Edge1->PrevInSEL = Edge2->PrevInSEL;
2592 if( Edge1->PrevInSEL ) Edge1->PrevInSEL->NextInSEL = Edge1;
2593 Edge2->NextInSEL = Next;
2594 if( Edge2->NextInSEL ) Edge2->NextInSEL->PrevInSEL = Edge2;
2595 Edge2->PrevInSEL = Prev;
2596 if( Edge2->PrevInSEL ) Edge2->PrevInSEL->NextInSEL = Edge2;
2606 return dir ==
dLeftToRight ? e->NextInAEL : e->PrevInAEL;
2612 if (HorzEdge.Bot.X < HorzEdge.Top.X)
2614 Left = HorzEdge.Bot.X;
2615 Right = HorzEdge.Top.X;
2619 Left = HorzEdge.Top.X;
2620 Right = HorzEdge.Bot.X;
2639 cInt horzLeft, horzRight;
2640 bool IsOpen = (horzEdge->WindDelta == 0);
2644 TEdge* eLastHorz = horzEdge, *eMaxPair = 0;
2645 while (eLastHorz->NextInLML &&
IsHorizontal(*eLastHorz->NextInLML))
2646 eLastHorz = eLastHorz->NextInLML;
2647 if (!eLastHorz->NextInLML)
2650 MaximaList::const_iterator maxIt;
2651 MaximaList::const_reverse_iterator maxRit;
2658 while (maxIt !=
m_Maxima.end() && *maxIt <= horzEdge->Bot.X) maxIt++;
2659 if (maxIt !=
m_Maxima.end() && *maxIt >= eLastHorz->Top.X)
2665 while (maxRit !=
m_Maxima.rend() && *maxRit > horzEdge->Bot.X) maxRit++;
2666 if (maxRit !=
m_Maxima.rend() && *maxRit <= eLastHorz->Top.X)
2676 bool IsLastHorz = (horzEdge == eLastHorz);
2688 while (maxIt !=
m_Maxima.end() && *maxIt < e->Curr.X)
2690 if (horzEdge->OutIdx >= 0 && !IsOpen)
2697 while (maxRit !=
m_Maxima.rend() && *maxRit > e->Curr.X)
2699 if (horzEdge->OutIdx >= 0 && !IsOpen)
2711 if (e->Curr.X == horzEdge->Top.X && horzEdge->NextInLML &&
2712 e->Dx < horzEdge->NextInLML->Dx)
break;
2714 if (horzEdge->OutIdx >= 0 && !IsOpen)
2720 if (eNextHorz->OutIdx >= 0 &&
2722 horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
2725 AddJoin(op2, op1, eNextHorz->Top);
2727 eNextHorz = eNextHorz->NextInSEL;
2734 if(e == eMaxPair && IsLastHorz)
2736 if (horzEdge->OutIdx >= 0)
2759 if (!horzEdge->NextInLML || !
IsHorizontal(*horzEdge->NextInLML))
break;
2762 if (horzEdge->OutIdx >= 0)
AddOutPt(horzEdge, horzEdge->Bot);
2767 if (horzEdge->OutIdx >= 0 && !op1)
2773 if (eNextHorz->OutIdx >= 0 &&
2775 horzEdge->Top.X, eNextHorz->Bot.X, eNextHorz->Top.X))
2778 AddJoin(op2, op1, eNextHorz->Top);
2780 eNextHorz = eNextHorz->NextInSEL;
2785 if (horzEdge->NextInLML)
2787 if(horzEdge->OutIdx >= 0)
2789 op1 =
AddOutPt( horzEdge, horzEdge->Top);
2791 if (horzEdge->WindDelta == 0)
return;
2793 TEdge* ePrev = horzEdge->PrevInAEL;
2794 TEdge* eNext = horzEdge->NextInAEL;
2795 if (ePrev && ePrev->Curr.X == horzEdge->Bot.X &&
2796 ePrev->Curr.Y == horzEdge->Bot.Y && ePrev->WindDelta != 0 &&
2797 (ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
2800 OutPt* op2 =
AddOutPt(ePrev, horzEdge->Bot);
2801 AddJoin(op1, op2, horzEdge->Top);
2803 else if (eNext && eNext->Curr.X == horzEdge->Bot.X &&
2804 eNext->Curr.Y == horzEdge->Bot.Y && eNext->WindDelta != 0 &&
2805 eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
2808 OutPt* op2 =
AddOutPt(eNext, horzEdge->Bot);
2809 AddJoin(op1, op2, horzEdge->Top);
2817 if (horzEdge->OutIdx >= 0)
AddOutPt(horzEdge, horzEdge->Top);
2829 if (IlSize == 0)
return true;
2837 throw clipperException(
"ProcessIntersections error");
2861 e->PrevInSEL = e->PrevInAEL;
2862 e->NextInSEL = e->NextInAEL;
2863 e->Curr.X =
TopX( *e, topY );
2873 while( e->NextInSEL )
2875 TEdge *eNext = e->NextInSEL;
2877 if(e->Curr.X > eNext->Curr.X)
2883 newNode->Edge2 = eNext;
2893 if( e->PrevInSEL ) e->PrevInSEL->NextInSEL = 0;
2896 while ( isModified );
2919 return node2->Pt.Y < node1->Pt.Y;
2925 return (inode.Edge1->NextInSEL == inode.Edge2) ||
2926 (inode.Edge1->PrevInSEL == inode.Edge2);
2938 for (
size_t i = 0;
i < cnt; ++
i)
2944 if (
j == cnt)
return false;
2964 TEdge* eNext = e->NextInAEL;
2965 while(eNext && eNext != eMaxPair)
2969 eNext = e->NextInAEL;
2977 else if( e->OutIdx >= 0 && eMaxPair->OutIdx >= 0 )
2984 else if (e->WindDelta == 0)
2993 if (eMaxPair->OutIdx >= 0)
3001 else throw clipperException(
"DoMaxima error");
3012 bool IsMaximaEdge =
IsMaxima(e, topY);
3017 IsMaximaEdge = (!eMaxPair || !
IsHorizontal(*eMaxPair));
3023 TEdge* ePrev = e->PrevInAEL;
3026 else e = ePrev->NextInAEL;
3040 e->Curr.X =
TopX( *e, topY );
3048 TEdge* ePrev = e->PrevInAEL;
3049 if ((e->OutIdx >= 0) && (e->WindDelta != 0) && ePrev && (ePrev->OutIdx >= 0) &&
3050 (ePrev->Curr.X == e->Curr.X) && (ePrev->WindDelta != 0))
3054 SetZ(pt, *ePrev, *e);
3078 if( e->OutIdx >= 0 )
3083 TEdge* ePrev = e->PrevInAEL;
3084 TEdge* eNext = e->NextInAEL;
3085 if (ePrev && ePrev->Curr.X == e->Bot.X &&
3086 ePrev->Curr.Y == e->Bot.Y && op &&
3087 ePrev->OutIdx >= 0 && ePrev->Curr.Y > ePrev->Top.Y &&
3089 (e->WindDelta != 0) && (ePrev->WindDelta != 0))
3091 OutPt* op2 =
AddOutPt(ePrev, e->Bot);
3094 else if (eNext && eNext->Curr.X == e->Bot.X &&
3095 eNext->Curr.Y == e->Bot.Y && op &&
3096 eNext->OutIdx >= 0 && eNext->Curr.Y > eNext->Top.Y &&
3098 (e->WindDelta != 0) && (eNext->WindDelta != 0))
3100 OutPt* op2 =
AddOutPt(eNext, e->Bot);
3111 OutPt *pp = outrec.Pts;
3112 OutPt *lastPP = pp->Prev;
3113 while (pp != lastPP)
3116 if (pp->Pt == pp->Prev->Pt)
3118 if (pp == lastPP) lastPP = pp->Prev;
3119 OutPt *tmpPP = pp->Prev;
3120 tmpPP->Next = pp->Next;
3121 pp->Next->Prev = tmpPP;
3141 outrec.BottomPt = 0;
3142 OutPt *pp = outrec.Pts;
3147 if (pp->Prev == pp || pp->Prev == pp->Next)
3155 if ((pp->Pt == pp->Next->Pt) || (pp->Pt == pp->Prev->Pt) ||
3161 pp->Prev->Next = pp->Next;
3162 pp->Next->Prev = pp->Prev;
3166 else if (pp == lastOK)
break;
3169 if (!lastOK) lastOK = pp;
3195 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
3201 if (cnt < 2)
continue;
3203 for (
int i = 0;
i < cnt; ++
i)
3205 pg.push_back(p->Pt);
3208 polys.push_back(pg);
3218 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size();
i++)
3222 if ((outRec->
IsOpen && cnt < 2) || (!outRec->
IsOpen && cnt < 3))
continue;
3232 for (
int j = 0;
j < cnt;
j++)
3241 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size();
i++)
3244 if (!outRec->PolyNd)
continue;
3247 outRec->PolyNd->m_IsOpen =
true;
3248 polytree.
AddChild(*outRec->PolyNd);
3250 else if (outRec->FirstLeft && outRec->FirstLeft->PolyNd)
3251 outRec->FirstLeft->PolyNd->AddChild(*outRec->PolyNd);
3253 polytree.
AddChild(*outRec->PolyNd);
3261 IntersectNode inode = int1;
3262 int1.Edge1 = int2.Edge1;
3263 int1.Edge2 = int2.Edge2;
3265 int2.Edge1 = inode.Edge1;
3266 int2.Edge2 = inode.Edge2;
3273 if (e2.Curr.X == e1.Curr.X)
3275 if (e2.Top.Y > e1.Top.Y)
3276 return e2.Top.X <
TopX(e1, e2.Top.Y);
3277 else return e1.Top.X >
TopX(e2, e1.Top.Y);
3279 else return e2.Curr.X < e1.Curr.X;
3288 if (b1 < b2) {Left = std::max(
a1,b1); Right = std::min(
a2,b2);}
3289 else {Left = std::max(
a1,b2); Right = std::min(
a2,b1);}
3293 if (b1 < b2) {Left = std::max(
a2,b1); Right = std::min(
a1,b2);}
3294 else {Left = std::max(
a2,b2); Right = std::min(
a1,b1);}
3296 return Left < Right;
3302 OutPt* op = outrec.Pts;
3305 op->
Idx = outrec.Idx;
3308 while(op != outrec.Pts);
3316 edge->PrevInAEL = 0;
3317 edge->NextInAEL = 0;
3322 edge->PrevInAEL = 0;
3330 while(startEdge->NextInAEL &&
3332 startEdge = startEdge->NextInAEL;
3333 edge->NextInAEL = startEdge->NextInAEL;
3334 if(startEdge->NextInAEL) startEdge->NextInAEL->PrevInAEL = edge;
3335 edge->PrevInAEL = startEdge;
3336 startEdge->NextInAEL = edge;
3341 OutPt*
DupOutPt(OutPt* outPt,
bool InsertAfter)
3343 OutPt* result =
new OutPt;
3344 result->
Pt = outPt->Pt;
3345 result->Idx = outPt->Idx;
3348 result->Next = outPt->Next;
3349 result->Prev = outPt;
3350 outPt->Next->Prev = result;
3351 outPt->Next = result;
3355 result->Prev = outPt->Prev;
3356 result->Next = outPt;
3357 outPt->Prev->Next = result;
3358 outPt->Prev = result;
3364 bool JoinHorz(OutPt* op1, OutPt* op1b, OutPt* op2, OutPt* op2b,
3365 const IntPoint Pt,
bool DiscardLeft)
3369 if (Dir1 == Dir2)
return false;
3378 while (op1->Next->Pt.X <= Pt.X &&
3379 op1->Next->Pt.X >= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
3381 if (DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
3382 op1b =
DupOutPt(op1, !DiscardLeft);
3387 op1b =
DupOutPt(op1, !DiscardLeft);
3392 while (op1->Next->Pt.X >= Pt.X &&
3393 op1->Next->Pt.X <= op1->Pt.X && op1->Next->Pt.Y == Pt.Y)
3395 if (!DiscardLeft && (op1->Pt.X != Pt.X)) op1 = op1->Next;
3407 while (op2->Next->Pt.X <= Pt.X &&
3408 op2->Next->Pt.X >= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
3410 if (DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
3411 op2b =
DupOutPt(op2, !DiscardLeft);
3416 op2b =
DupOutPt(op2, !DiscardLeft);
3420 while (op2->Next->Pt.X >= Pt.X &&
3421 op2->Next->Pt.X <= op2->Pt.X && op2->Next->Pt.Y == Pt.Y)
3423 if (!DiscardLeft && (op2->Pt.X != Pt.X)) op2 = op2->Next;
3453 OutPt *op1 =
j->OutPt1, *op1b;
3454 OutPt *op2 =
j->OutPt2, *op2b;
3463 bool isHorizontal = (
j->OutPt1->Pt.Y ==
j->OffPt.Y);
3465 if (isHorizontal && (
j->OffPt ==
j->OutPt1->Pt) &&
3466 (
j->OffPt ==
j->OutPt2->Pt))
3469 if (outRec1 != outRec2)
return false;
3470 op1b =
j->OutPt1->Next;
3471 while (op1b != op1 && (op1b->Pt ==
j->OffPt))
3473 bool reverse1 = (op1b->Pt.Y >
j->OffPt.Y);
3474 op2b =
j->OutPt2->Next;
3475 while (op2b != op2 && (op2b->Pt ==
j->OffPt))
3477 bool reverse2 = (op2b->Pt.Y >
j->OffPt.Y);
3478 if (reverse1 == reverse2)
return false;
3503 else if (isHorizontal)
3509 while (op1->Prev->Pt.Y == op1->Pt.Y && op1->Prev != op1b && op1->Prev != op2)
3511 while (op1b->Next->Pt.Y == op1b->Pt.Y && op1b->Next != op1 && op1b->Next != op2)
3513 if (op1b->Next == op1 || op1b->Next == op2)
return false;
3516 while (op2->Prev->Pt.Y == op2->Pt.Y && op2->Prev != op2b && op2->Prev != op1b)
3518 while (op2b->Next->Pt.Y == op2b->Pt.Y && op2b->Next != op2 && op2b->Next != op1)
3520 if (op2b->Next == op2 || op2b->Next == op1)
return false;
3524 if (!
GetOverlap(op1->Pt.X, op1b->Pt.X, op2->Pt.X, op2b->Pt.X, Left, Right))
3531 bool DiscardLeftSide;
3532 if (op1->Pt.X >= Left && op1->Pt.X <= Right)
3534 Pt = op1->Pt; DiscardLeftSide = (op1->Pt.X > op1b->Pt.X);
3536 else if (op2->Pt.X >= Left&& op2->Pt.X <= Right)
3538 Pt = op2->Pt; DiscardLeftSide = (op2->Pt.X > op2b->Pt.X);
3540 else if (op1b->Pt.X >= Left && op1b->Pt.X <= Right)
3542 Pt = op1b->Pt; DiscardLeftSide = op1b->Pt.X > op1->Pt.X;
3546 Pt = op2b->Pt; DiscardLeftSide = (op2b->Pt.X > op2->Pt.X);
3548 j->OutPt1 = op1;
j->OutPt2 = op2;
3549 return JoinHorz(op1, op1b, op2, op2b, Pt, DiscardLeftSide);
3558 while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Next;
3559 bool Reverse1 = ((op1b->Pt.Y > op1->Pt.Y) ||
3564 while ((op1b->Pt == op1->Pt) && (op1b != op1)) op1b = op1b->Prev;
3565 if ((op1b->Pt.Y > op1->Pt.Y) ||
3569 while ((op2b->Pt == op2->Pt) && (op2b != op2))op2b = op2b->Next;
3570 bool Reverse2 = ((op2b->Pt.Y > op2->Pt.Y) ||
3575 while ((op2b->Pt == op2->Pt) && (op2b != op2)) op2b = op2b->Prev;
3576 if ((op2b->Pt.Y > op2->Pt.Y) ||
3580 if ((op1b == op1) || (op2b == op2) || (op1b == op2b) ||
3581 ((outRec1 == outRec2) && (Reverse1 == Reverse2)))
return false;
3612 while (FirstLeft && !FirstLeft->Pts)
3621 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
3625 if (outRec->Pts && firstLeft == OldOutRec)
3628 outRec->FirstLeft = NewOutRec;
3640 OutRec* orfl = OuterOutRec->FirstLeft;
3641 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
3645 if (!outRec->Pts || outRec == OuterOutRec || outRec == InnerOutRec)
3648 if (firstLeft != orfl && firstLeft != InnerOutRec && firstLeft != OuterOutRec)
3651 outRec->FirstLeft = InnerOutRec;
3653 outRec->FirstLeft = OuterOutRec;
3654 else if (outRec->FirstLeft == InnerOutRec || outRec->FirstLeft == OuterOutRec)
3655 outRec->FirstLeft = orfl;
3662 for (PolyOutList::size_type
i = 0;
i <
m_PolyOuts.size(); ++
i)
3666 if (outRec->Pts && outRec->FirstLeft == OldOutRec)
3667 outRec->FirstLeft = NewOutRec;
3674 for (JoinList::size_type
i = 0;
i <
m_Joins.size();
i++)
3681 if (!outRec1->
Pts || !outRec2->
Pts)
continue;
3687 if (outRec1 == outRec2) holeStateRec = outRec1;
3692 if (!
JoinPoints(join, outRec1, outRec2))
continue;
3694 if (outRec1 == outRec2)
3746 outRec2->
Idx = outRec1->
Idx;
3749 if (holeStateRec == outRec2)
3762 DoublePoint
GetUnitNormal(
const IntPoint &pt1,
const IntPoint &pt2)
3764 if(pt2.X == pt1.X && pt2.Y == pt1.Y)
3765 return DoublePoint(0, 0);
3767 double Dx = (
double)(pt2.X - pt1.X);
3768 double dy = (
double)(pt2.Y - pt1.Y);
3769 double f = 1 *1.0/ std::sqrt( Dx*Dx + dy*dy );
3772 return DoublePoint(dy, -Dx);
3804 int highI = (
int)path.size() - 1;
3805 if (highI < 0)
return;
3806 PolyNode* newNode =
new PolyNode();
3807 newNode->m_jointype = joinType;
3808 newNode->m_endtype = endType;
3812 while (highI > 0 && path[0] == path[highI]) highI--;
3813 newNode->Contour.reserve(highI + 1);
3814 newNode->Contour.push_back(path[0]);
3816 for (
int i = 1;
i <= highI;
i++)
3817 if (newNode->Contour[
j] != path[
i])
3820 newNode->Contour.push_back(path[
i]);
3821 if (path[
i].Y > newNode->Contour[
k].Y ||
3822 (path[
i].Y == newNode->Contour[
k].Y &&
3823 path[
i].X < newNode->Contour[
k].X))
k =
j;
3839 if (newNode->Contour[
k].Y > ip.
Y ||
3840 (newNode->Contour[
k].Y == ip.
Y &&
3841 newNode->Contour[
k].X < ip.
X))
3849 for (Paths::size_type
i = 0;
i < paths.size(); ++
i)
3850 AddPath(paths[
i], joinType, endType);
3897 outer[0] =
IntPoint(
r.left - 10,
r.bottom + 10);
3898 outer[1] =
IntPoint(
r.right + 10,
r.bottom + 10);
3899 outer[2] =
IntPoint(
r.right + 10,
r.top - 10);
3900 outer[3] =
IntPoint(
r.left - 10,
r.top - 10);
3905 if (solution.size() > 0) solution.erase(solution.begin());
3927 outer[0] =
IntPoint(
r.left - 10,
r.bottom + 10);
3928 outer[1] =
IntPoint(
r.right + 10,
r.bottom + 10);
3929 outer[2] =
IntPoint(
r.right + 10,
r.top - 10);
3930 outer[3] =
IntPoint(
r.left - 10,
r.top - 10);
3936 if (solution.ChildCount() == 1 && solution.Childs[0]->ChildCount() > 0)
3939 solution.Childs.reserve(outerNode->
ChildCount());
3940 solution.Childs[0] = outerNode->
Childs[0];
3941 solution.Childs[0]->Parent = outerNode->
Parent;
3979 double steps =
pi / std::acos(1 - y / std::fabs(
delta));
3980 if (steps > std::fabs(
delta) *
pi)
3981 steps = std::fabs(
delta) *
pi;
4002 double X = 1.0, Y = 0.0;
4003 for (
cInt j = 1;
j <= steps;
j++)
4015 double X = -1.0, Y = -1.0;
4016 for (
int j = 0;
j < 4; ++
j)
4022 else if (Y < 0) Y = 1;
4032 for (
int j = 0;
j < len - 1; ++
j)
4042 for (
int j = 0;
j < len; ++
j)
4049 for (
int j = 0;
j < len; ++
j)
4055 for (
int j = len - 1;
j > 0;
j--)
4059 for (
int j = len - 1;
j >= 0;
j--)
4066 for (
int j = 1;
j < len - 1; ++
j)
4093 for (
int j = len - 1;
j > 0;
j--)
4170 double dx = std::tan(std::atan2(
m_sinA,
4196 for (
int i = 0;
i < steps; ++
i)
4216 PolyOutList::size_type
i = 0;
4221 if (!op || outrec->
IsOpen)
continue;
4227 if ((op->
Pt == op2->
Pt) && op2->
Next != op && op2->
Prev != op)
4271 while (op != outrec->
Pts);
4278 std::reverse(p.begin(), p.end());
4284 for (Paths::size_type
i = 0;
i < p.size(); ++
i)
4292 c.StrictlySimple(
true);
4294 c.Execute(
ctUnion, out_polys, fillType, fillType);
4301 c.StrictlySimple(
true);
4303 c.Execute(
ctUnion, out_polys, fillType, fillType);
4315 double Dx = ((
double)pt1.
X - pt2.
X);
4316 double dy = ((
double)pt1.
Y - pt2.
Y);
4317 return (Dx*Dx + dy*dy);
4322 const IntPoint& pt,
const IntPoint& ln1,
const IntPoint& ln2)
4330 double A =
double(ln1.Y - ln2.Y);
4331 double B =
double(ln2.X - ln1.X);
4332 double C =
A * ln1.X + B * ln1.Y;
4333 C =
A * pt.X + B * pt.Y - C;
4334 return (C * C) / (
A *
A + B * B);
4339 const IntPoint& pt2,
const IntPoint& pt3,
double distSqrd)
4344 if (
Abs(pt1.X - pt2.X) >
Abs(pt1.Y - pt2.Y))
4346 if ((pt1.X > pt2.X) == (pt1.X < pt3.X))
4348 else if ((pt2.X > pt1.X) == (pt2.X < pt3.X))
4355 if ((pt1.Y > pt2.Y) == (pt1.Y < pt3.Y))
4357 else if ((pt2.Y > pt1.Y) == (pt2.Y < pt3.Y))
4367 double Dx = (
double)pt1.X - pt2.X;
4368 double dy = (
double)pt1.Y - pt2.Y;
4369 return ((Dx * Dx) + (dy * dy) <= distSqrd);
4388 size_t size = in_poly.size();
4396 OutPt* outPts =
new OutPt[size];
4397 for (
size_t i = 0;
i < size; ++
i)
4399 outPts[
i].Pt = in_poly[
i];
4400 outPts[
i].Next = &outPts[(
i + 1) % size];
4401 outPts[
i].Next->Prev = &outPts[
i];
4405 double distSqrd = distance * distance;
4406 OutPt* op = &outPts[0];
4407 while (op->Idx == 0 && op->Next != op->Prev)
4432 if (size < 3) size = 0;
4433 out_poly.resize(size);
4434 for (
size_t i = 0;
i < size; ++
i)
4436 out_poly[
i] = op->Pt;
4451 out_polys.resize(in_polys.size());
4452 for (Paths::size_type
i = 0;
i < in_polys.size(); ++
i)
4464 Paths& solution,
bool isSum,
bool isClosed)
4466 int delta = (isClosed ? 1 : 0);
4467 size_t polyCnt = poly.size();
4468 size_t pathCnt = path.size();
4470 pp.reserve(pathCnt);
4472 for (
size_t i = 0;
i < pathCnt; ++
i)
4476 for (
size_t j = 0;
j < poly.size(); ++
j)
4477 p.push_back(IntPoint(path[
i].X + poly[
j].X, path[
i].Y + poly[
j].Y));
4481 for (
size_t i = 0;
i < pathCnt; ++
i)
4485 for (
size_t j = 0;
j < poly.size(); ++
j)
4486 p.push_back(
IntPoint(path[
i].X - poly[
j].X, path[
i].Y - poly[
j].Y));
4491 solution.reserve((pathCnt +
delta) * (polyCnt + 1));
4492 for (
size_t i = 0;
i < pathCnt - 1 +
delta; ++
i)
4493 for (
size_t j = 0;
j < polyCnt; ++
j)
4497 quad.push_back(pp[
i % pathCnt][
j % polyCnt]);
4498 quad.push_back(pp[(
i + 1) % pathCnt][
j % polyCnt]);
4499 quad.push_back(pp[(
i + 1) % pathCnt][(
j + 1) % polyCnt]);
4500 quad.push_back(pp[
i % pathCnt][(
j + 1) % polyCnt]);
4502 solution.push_back(quad);
4509 Minkowski(pattern, path, solution,
true, pathIsClosed);
4519 output.resize(input.size());
4520 for (
size_t i = 0;
i < input.size(); ++
i)
4521 output[
i] = IntPoint(input[
i].X +
delta.X, input[
i].Y +
delta.Y);
4528 for (
size_t i = 0;
i < paths.size(); ++
i)
4531 Minkowski(pattern, paths[
i], tmp,
true, pathIsClosed);
4537 c.AddPath(tmp2,
ptClip,
true);
4546 Minkowski(poly1, poly2, solution,
false,
true);
4558 if (nodetype ==
ntClosed) match = !polynode.IsOpen();
4559 else if (nodetype ==
ntOpen)
return;
4561 if (!polynode.Contour.empty() && match)
4562 paths.push_back(polynode.Contour);
4563 for (
int i = 0;
i < polynode.ChildCount(); ++
i)
4571 paths.reserve(polytree.Total());
4579 paths.reserve(polytree.Total());
4587 paths.reserve(polytree.Total());
4589 for (
int i = 0;
i < polytree.ChildCount(); ++
i)
4590 if (polytree.Childs[
i]->IsOpen())
4591 paths.push_back(polytree.Childs[
i]->Contour);
4595 std::ostream&
operator <<(std::ostream &s,
const IntPoint &p)
4597 s <<
"(" << p.X <<
"," << p.Y <<
")";
4604 if (p.empty())
return s;
4605 Path::size_type last = p.size() -1;
4606 for (Path::size_type
i = 0;
i < last;
i++)
4607 s <<
"(" << p[
i].X <<
"," << p[
i].Y <<
"), ";
4608 s <<
"(" << p[last].X <<
"," << p[last].Y <<
")\n";
4615 for (Paths::size_type
i = 0;
i < p.size();
i++)