|
@@ -1,8 +1,8 @@
|
|
/*******************************************************************************
|
|
/*******************************************************************************
|
|
* Author : Angus Johnson *
|
|
* Author : Angus Johnson *
|
|
-* Date : 22 November 2023 *
|
|
|
|
|
|
+* Date : 27 April 2024 *
|
|
* Website : http://www.angusj.com *
|
|
* Website : http://www.angusj.com *
|
|
-* Copyright : Angus Johnson 2010-2023 *
|
|
|
|
|
|
+* Copyright : Angus Johnson 2010-2024 *
|
|
* Purpose : This is the main polygon clipping module *
|
|
* Purpose : This is the main polygon clipping module *
|
|
* License : http://www.boost.org/LICENSE_1_0.txt *
|
|
* License : http://www.boost.org/LICENSE_1_0.txt *
|
|
*******************************************************************************/
|
|
*******************************************************************************/
|
|
@@ -31,11 +31,11 @@ namespace Clipper2Lib {
|
|
|
|
|
|
static const Rect64 invalid_rect = Rect64(false);
|
|
static const Rect64 invalid_rect = Rect64(false);
|
|
|
|
|
|
- // Every closed path (or polygon) is made up of a series of vertices forming
|
|
|
|
- // edges that alternate between going up (relative to the Y-axis) and going
|
|
|
|
- // down. Edges consecutively going up or consecutively going down are called
|
|
|
|
- // 'bounds' (ie sides if they're simple polygons). 'Local Minima' refer to
|
|
|
|
- // vertices where descending bounds become ascending ones.
|
|
|
|
|
|
+ // Every closed path (ie polygon) is made up of a series of vertices forming edge
|
|
|
|
+ // 'bounds' that alternate between ascending bounds (containing edges going up
|
|
|
|
+ // relative to the Y-axis) and descending bounds. 'Local Minima' refers to
|
|
|
|
+ // vertices where ascending and descending bounds join at the bottom, and
|
|
|
|
+ // 'Local Maxima' are where ascending and descending bounds join at the top.
|
|
|
|
|
|
struct Scanline {
|
|
struct Scanline {
|
|
int64_t y = 0;
|
|
int64_t y = 0;
|
|
@@ -63,6 +63,7 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+
|
|
inline bool IsOdd(int val)
|
|
inline bool IsOdd(int val)
|
|
{
|
|
{
|
|
return (val & 1) ? true : false;
|
|
return (val & 1) ? true : false;
|
|
@@ -188,7 +189,7 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
|
|
|
|
//PrevPrevVertex: useful to get the (inverted Y-axis) top of the
|
|
//PrevPrevVertex: useful to get the (inverted Y-axis) top of the
|
|
- //alternate edge (ie left or right bound) during edge insertion.
|
|
|
|
|
|
+ //alternate edge (ie left or right bound) during edge insertion.
|
|
inline Vertex* PrevPrevVertex(const Active& ae)
|
|
inline Vertex* PrevPrevVertex(const Active& ae)
|
|
{
|
|
{
|
|
if (ae.wind_dx > 0)
|
|
if (ae.wind_dx > 0)
|
|
@@ -233,15 +234,15 @@ namespace Clipper2Lib {
|
|
Vertex* result = e.vertex_top;
|
|
Vertex* result = e.vertex_top;
|
|
if (e.wind_dx > 0)
|
|
if (e.wind_dx > 0)
|
|
while ((result->next->pt.y == result->pt.y) &&
|
|
while ((result->next->pt.y == result->pt.y) &&
|
|
- ((result->flags & (VertexFlags::OpenEnd |
|
|
|
|
|
|
+ ((result->flags & (VertexFlags::OpenEnd |
|
|
VertexFlags::LocalMax)) == VertexFlags::None))
|
|
VertexFlags::LocalMax)) == VertexFlags::None))
|
|
result = result->next;
|
|
result = result->next;
|
|
else
|
|
else
|
|
while (result->prev->pt.y == result->pt.y &&
|
|
while (result->prev->pt.y == result->pt.y &&
|
|
- ((result->flags & (VertexFlags::OpenEnd |
|
|
|
|
|
|
+ ((result->flags & (VertexFlags::OpenEnd |
|
|
VertexFlags::LocalMax)) == VertexFlags::None))
|
|
VertexFlags::LocalMax)) == VertexFlags::None))
|
|
result = result->prev;
|
|
result = result->prev;
|
|
- if (!IsMaxima(*result)) result = nullptr; // not a maxima
|
|
|
|
|
|
+ if (!IsMaxima(*result)) result = nullptr; // not a maxima
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -252,7 +253,7 @@ namespace Clipper2Lib {
|
|
while (result->next->pt.y == result->pt.y) result = result->next;
|
|
while (result->next->pt.y == result->pt.y) result = result->next;
|
|
else
|
|
else
|
|
while (result->prev->pt.y == result->pt.y) result = result->prev;
|
|
while (result->prev->pt.y == result->pt.y) result = result->prev;
|
|
- if (!IsMaxima(*result)) result = nullptr; // not a maxima
|
|
|
|
|
|
+ if (!IsMaxima(*result)) result = nullptr; // not a maxima
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -613,13 +614,13 @@ namespace Clipper2Lib {
|
|
list.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
|
|
list.push_back(std::make_unique <LocalMinima>(&vert, polytype, is_open));
|
|
}
|
|
}
|
|
|
|
|
|
- void AddPaths_(const Paths64& paths, PathType polytype, bool is_open,
|
|
|
|
|
|
+ void AddPaths_(const Paths64& paths, PathType polytype, bool is_open,
|
|
std::vector<Vertex*>& vertexLists, LocalMinimaList& locMinList)
|
|
std::vector<Vertex*>& vertexLists, LocalMinimaList& locMinList)
|
|
{
|
|
{
|
|
const auto total_vertex_count =
|
|
const auto total_vertex_count =
|
|
- std::accumulate(paths.begin(), paths.end(), 0,
|
|
|
|
|
|
+ std::accumulate(paths.begin(), paths.end(), size_t(0),
|
|
[](const auto& a, const Path64& path)
|
|
[](const auto& a, const Path64& path)
|
|
- {return a + static_cast<unsigned>(path.size()); });
|
|
|
|
|
|
+ {return a + path.size(); });
|
|
if (total_vertex_count == 0) return;
|
|
if (total_vertex_count == 0) return;
|
|
|
|
|
|
Vertex* vertices = new Vertex[total_vertex_count], * v = vertices;
|
|
Vertex* vertices = new Vertex[total_vertex_count], * v = vertices;
|
|
@@ -810,7 +811,7 @@ namespace Clipper2Lib {
|
|
void ClipperBase::SetZ(const Active& e1, const Active& e2, Point64& ip)
|
|
void ClipperBase::SetZ(const Active& e1, const Active& e2, Point64& ip)
|
|
{
|
|
{
|
|
if (!zCallback_) return;
|
|
if (!zCallback_) return;
|
|
- // prioritize subject over clip vertices by passing
|
|
|
|
|
|
+ // prioritize subject over clip vertices by passing
|
|
// subject vertices before clip vertices in the callback
|
|
// subject vertices before clip vertices in the callback
|
|
if (GetPolyType(e1) == PathType::Subject)
|
|
if (GetPolyType(e1) == PathType::Subject)
|
|
{
|
|
{
|
|
@@ -845,11 +846,11 @@ namespace Clipper2Lib {
|
|
if (is_open) has_open_paths_ = true;
|
|
if (is_open) has_open_paths_ = true;
|
|
minima_list_sorted_ = false;
|
|
minima_list_sorted_ = false;
|
|
AddPaths_(paths, polytype, is_open, vertex_lists_, minima_list_);
|
|
AddPaths_(paths, polytype, is_open, vertex_lists_, minima_list_);
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
|
|
- void ClipperBase::AddReuseableData(const ReuseableDataContainer64& reuseable_data)
|
|
|
|
|
|
+ void ClipperBase::AddReuseableData(const ReuseableDataContainer64& reuseable_data)
|
|
{
|
|
{
|
|
- // nb: reuseable_data will continue to own the vertices
|
|
|
|
|
|
+ // nb: reuseable_data will continue to own the vertices
|
|
// and remains responsible for their clean up.
|
|
// and remains responsible for their clean up.
|
|
succeeded_ = false;
|
|
succeeded_ = false;
|
|
minima_list_sorted_ = false;
|
|
minima_list_sorted_ = false;
|
|
@@ -1117,7 +1118,6 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
bool IsValidAelOrder(const Active& resident, const Active& newcomer)
|
|
bool IsValidAelOrder(const Active& resident, const Active& newcomer)
|
|
{
|
|
{
|
|
if (newcomer.curr_x != resident.curr_x)
|
|
if (newcomer.curr_x != resident.curr_x)
|
|
@@ -1149,8 +1149,8 @@ namespace Clipper2Lib {
|
|
//resident must also have just been inserted
|
|
//resident must also have just been inserted
|
|
else if (resident.is_left_bound != newcomerIsLeft)
|
|
else if (resident.is_left_bound != newcomerIsLeft)
|
|
return newcomerIsLeft;
|
|
return newcomerIsLeft;
|
|
- else if (CrossProduct(PrevPrevVertex(resident)->pt,
|
|
|
|
- resident.bot, resident.top) == 0) return true;
|
|
|
|
|
|
+ else if (IsCollinear(PrevPrevVertex(resident)->pt,
|
|
|
|
+ resident.bot, resident.top)) return true;
|
|
else
|
|
else
|
|
//compare turning direction of the alternate bound
|
|
//compare turning direction of the alternate bound
|
|
return (CrossProduct(PrevPrevVertex(resident)->pt,
|
|
return (CrossProduct(PrevPrevVertex(resident)->pt,
|
|
@@ -1385,7 +1385,7 @@ namespace Clipper2Lib {
|
|
{
|
|
{
|
|
if (IsJoined(e1)) Split(e1, pt);
|
|
if (IsJoined(e1)) Split(e1, pt);
|
|
if (IsJoined(e2)) Split(e2, pt);
|
|
if (IsJoined(e2)) Split(e2, pt);
|
|
-
|
|
|
|
|
|
+
|
|
if (IsFront(e1) == IsFront(e2))
|
|
if (IsFront(e1) == IsFront(e2))
|
|
{
|
|
{
|
|
if (IsOpenEnd(e1))
|
|
if (IsOpenEnd(e1))
|
|
@@ -1409,7 +1409,7 @@ namespace Clipper2Lib {
|
|
{
|
|
{
|
|
Active* e = GetPrevHotEdge(e1);
|
|
Active* e = GetPrevHotEdge(e1);
|
|
if (!e)
|
|
if (!e)
|
|
- outrec.owner = nullptr;
|
|
|
|
|
|
+ outrec.owner = nullptr;
|
|
else
|
|
else
|
|
SetOwner(&outrec, e->outrec);
|
|
SetOwner(&outrec, e->outrec);
|
|
// nb: outRec.owner here is likely NOT the real
|
|
// nb: outRec.owner here is likely NOT the real
|
|
@@ -1476,7 +1476,7 @@ namespace Clipper2Lib {
|
|
e2.outrec->pts = e1.outrec->pts;
|
|
e2.outrec->pts = e1.outrec->pts;
|
|
e1.outrec->pts = nullptr;
|
|
e1.outrec->pts = nullptr;
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+ else
|
|
SetOwner(e2.outrec, e1.outrec);
|
|
SetOwner(e2.outrec, e1.outrec);
|
|
|
|
|
|
//and e1 and e2 are maxima and are about to be dropped from the Actives list.
|
|
//and e1 and e2 are maxima and are about to be dropped from the Actives list.
|
|
@@ -1526,7 +1526,6 @@ namespace Clipper2Lib {
|
|
return new_op;
|
|
return new_op;
|
|
}
|
|
}
|
|
|
|
|
|
-
|
|
|
|
void ClipperBase::CleanCollinear(OutRec* outrec)
|
|
void ClipperBase::CleanCollinear(OutRec* outrec)
|
|
{
|
|
{
|
|
outrec = GetRealOutRec(outrec);
|
|
outrec = GetRealOutRec(outrec);
|
|
@@ -1541,7 +1540,7 @@ namespace Clipper2Lib {
|
|
for (; ; )
|
|
for (; ; )
|
|
{
|
|
{
|
|
//NB if preserveCollinear == true, then only remove 180 deg. spikes
|
|
//NB if preserveCollinear == true, then only remove 180 deg. spikes
|
|
- if ((CrossProduct(op2->prev->pt, op2->pt, op2->next->pt) == 0) &&
|
|
|
|
|
|
+ if (IsCollinear(op2->prev->pt, op2->pt, op2->next->pt) &&
|
|
(op2->pt == op2->prev->pt ||
|
|
(op2->pt == op2->prev->pt ||
|
|
op2->pt == op2->next->pt || !preserve_collinear_ ||
|
|
op2->pt == op2->next->pt || !preserve_collinear_ ||
|
|
DotProduct(op2->prev->pt, op2->pt, op2->next->pt) < 0))
|
|
DotProduct(op2->prev->pt, op2->pt, op2->next->pt) < 0))
|
|
@@ -1566,14 +1565,14 @@ namespace Clipper2Lib {
|
|
|
|
|
|
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
|
|
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
|
|
{
|
|
{
|
|
- // splitOp.prev -> splitOp &&
|
|
|
|
|
|
+ // splitOp.prev -> splitOp &&
|
|
// splitOp.next -> splitOp.next.next are intersecting
|
|
// splitOp.next -> splitOp.next.next are intersecting
|
|
OutPt* prevOp = splitOp->prev;
|
|
OutPt* prevOp = splitOp->prev;
|
|
OutPt* nextNextOp = splitOp->next->next;
|
|
OutPt* nextNextOp = splitOp->next->next;
|
|
outrec->pts = prevOp;
|
|
outrec->pts = prevOp;
|
|
|
|
|
|
Point64 ip;
|
|
Point64 ip;
|
|
- GetIntersectPoint(prevOp->pt, splitOp->pt,
|
|
|
|
|
|
+ GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
|
|
splitOp->next->pt, nextNextOp->pt, ip);
|
|
splitOp->next->pt, nextNextOp->pt, ip);
|
|
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
@@ -1617,7 +1616,7 @@ namespace Clipper2Lib {
|
|
{
|
|
{
|
|
OutRec* newOr = NewOutRec();
|
|
OutRec* newOr = NewOutRec();
|
|
newOr->owner = outrec->owner;
|
|
newOr->owner = outrec->owner;
|
|
-
|
|
|
|
|
|
+
|
|
splitOp->outrec = newOr;
|
|
splitOp->outrec = newOr;
|
|
splitOp->next->outrec = newOr;
|
|
splitOp->next->outrec = newOr;
|
|
OutPt* newOp = new OutPt(ip, newOr);
|
|
OutPt* newOp = new OutPt(ip, newOr);
|
|
@@ -1772,12 +1771,12 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
- OutPt* ClipperBase::IntersectEdges(Active& e1, Active& e2, const Point64& pt)
|
|
|
|
|
|
+ void ClipperBase::IntersectEdges(Active& e1, Active& e2, const Point64& pt)
|
|
{
|
|
{
|
|
//MANAGE OPEN PATH INTERSECTIONS SEPARATELY ...
|
|
//MANAGE OPEN PATH INTERSECTIONS SEPARATELY ...
|
|
if (has_open_paths_ && (IsOpen(e1) || IsOpen(e2)))
|
|
if (has_open_paths_ && (IsOpen(e1) || IsOpen(e2)))
|
|
{
|
|
{
|
|
- if (IsOpen(e1) && IsOpen(e2)) return nullptr;
|
|
|
|
|
|
+ if (IsOpen(e1) && IsOpen(e2)) return;
|
|
Active* edge_o, * edge_c;
|
|
Active* edge_o, * edge_c;
|
|
if (IsOpen(e1))
|
|
if (IsOpen(e1))
|
|
{
|
|
{
|
|
@@ -1791,29 +1790,40 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
if (IsJoined(*edge_c)) Split(*edge_c, pt); // needed for safety
|
|
if (IsJoined(*edge_c)) Split(*edge_c, pt); // needed for safety
|
|
|
|
|
|
- if (abs(edge_c->wind_cnt) != 1) return nullptr;
|
|
|
|
|
|
+ if (abs(edge_c->wind_cnt) != 1) return;
|
|
switch (cliptype_)
|
|
switch (cliptype_)
|
|
{
|
|
{
|
|
case ClipType::Union:
|
|
case ClipType::Union:
|
|
- if (!IsHotEdge(*edge_c)) return nullptr;
|
|
|
|
|
|
+ if (!IsHotEdge(*edge_c)) return;
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
if (edge_c->local_min->polytype == PathType::Subject)
|
|
if (edge_c->local_min->polytype == PathType::Subject)
|
|
- return nullptr;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
switch (fillrule_)
|
|
switch (fillrule_)
|
|
{
|
|
{
|
|
- case FillRule::Positive: if (edge_c->wind_cnt != 1) return nullptr; break;
|
|
|
|
- case FillRule::Negative: if (edge_c->wind_cnt != -1) return nullptr; break;
|
|
|
|
- default: if (std::abs(edge_c->wind_cnt) != 1) return nullptr; break;
|
|
|
|
|
|
+ case FillRule::Positive:
|
|
|
|
+ if (edge_c->wind_cnt != 1) return;
|
|
|
|
+ break;
|
|
|
|
+ case FillRule::Negative:
|
|
|
|
+ if (edge_c->wind_cnt != -1) return;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ if (std::abs(edge_c->wind_cnt) != 1) return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef USINGZ
|
|
OutPt* resultOp;
|
|
OutPt* resultOp;
|
|
|
|
+#endif
|
|
//toggle contribution ...
|
|
//toggle contribution ...
|
|
if (IsHotEdge(*edge_o))
|
|
if (IsHotEdge(*edge_o))
|
|
{
|
|
{
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = AddOutPt(*edge_o, pt);
|
|
resultOp = AddOutPt(*edge_o, pt);
|
|
|
|
+#else
|
|
|
|
+ AddOutPt(*edge_o, pt);
|
|
|
|
+#endif
|
|
if (IsFront(*edge_o)) edge_o->outrec->front_edge = nullptr;
|
|
if (IsFront(*edge_o)) edge_o->outrec->front_edge = nullptr;
|
|
else edge_o->outrec->back_edge = nullptr;
|
|
else edge_o->outrec->back_edge = nullptr;
|
|
edge_o->outrec = nullptr;
|
|
edge_o->outrec = nullptr;
|
|
@@ -1833,18 +1843,26 @@ namespace Clipper2Lib {
|
|
SetSides(*e3->outrec, *edge_o, *e3);
|
|
SetSides(*e3->outrec, *edge_o, *e3);
|
|
else
|
|
else
|
|
SetSides(*e3->outrec, *e3, *edge_o);
|
|
SetSides(*e3->outrec, *e3, *edge_o);
|
|
- return e3->outrec->pts;
|
|
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = StartOpenPath(*edge_o, pt);
|
|
resultOp = StartOpenPath(*edge_o, pt);
|
|
|
|
+#else
|
|
|
|
+ StartOpenPath(*edge_o, pt);
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
else
|
|
else
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = StartOpenPath(*edge_o, pt);
|
|
resultOp = StartOpenPath(*edge_o, pt);
|
|
|
|
+#else
|
|
|
|
+ StartOpenPath(*edge_o, pt);
|
|
|
|
+#endif
|
|
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
if (zCallback_) SetZ(*edge_o, *edge_c, resultOp->pt);
|
|
if (zCallback_) SetZ(*edge_o, *edge_c, resultOp->pt);
|
|
#endif
|
|
#endif
|
|
- return resultOp;
|
|
|
|
|
|
+ return;
|
|
} // end of an open path intersection
|
|
} // end of an open path intersection
|
|
|
|
|
|
//MANAGING CLOSED PATHS FROM HERE ON
|
|
//MANAGING CLOSED PATHS FROM HERE ON
|
|
@@ -1913,22 +1931,25 @@ namespace Clipper2Lib {
|
|
const bool e1_windcnt_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
|
|
const bool e1_windcnt_in_01 = old_e1_windcnt == 0 || old_e1_windcnt == 1;
|
|
const bool e2_windcnt_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
|
|
const bool e2_windcnt_in_01 = old_e2_windcnt == 0 || old_e2_windcnt == 1;
|
|
|
|
|
|
- if ((!IsHotEdge(e1) && !e1_windcnt_in_01) || (!IsHotEdge(e2) && !e2_windcnt_in_01))
|
|
|
|
- {
|
|
|
|
- return nullptr;
|
|
|
|
- }
|
|
|
|
|
|
+ if ((!IsHotEdge(e1) && !e1_windcnt_in_01) ||
|
|
|
|
+ (!IsHotEdge(e2) && !e2_windcnt_in_01))
|
|
|
|
+ return;
|
|
|
|
|
|
//NOW PROCESS THE INTERSECTION ...
|
|
//NOW PROCESS THE INTERSECTION ...
|
|
|
|
+#ifdef USINGZ
|
|
OutPt* resultOp = nullptr;
|
|
OutPt* resultOp = nullptr;
|
|
|
|
+#endif
|
|
//if both edges are 'hot' ...
|
|
//if both edges are 'hot' ...
|
|
if (IsHotEdge(e1) && IsHotEdge(e2))
|
|
if (IsHotEdge(e1) && IsHotEdge(e2))
|
|
{
|
|
{
|
|
if ((old_e1_windcnt != 0 && old_e1_windcnt != 1) || (old_e2_windcnt != 0 && old_e2_windcnt != 1) ||
|
|
if ((old_e1_windcnt != 0 && old_e1_windcnt != 1) || (old_e2_windcnt != 0 && old_e2_windcnt != 1) ||
|
|
(e1.local_min->polytype != e2.local_min->polytype && cliptype_ != ClipType::Xor))
|
|
(e1.local_min->polytype != e2.local_min->polytype && cliptype_ != ClipType::Xor))
|
|
{
|
|
{
|
|
- resultOp = AddLocalMaxPoly(e1, e2, pt);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddLocalMaxPoly(e1, e2, pt);
|
|
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMaxPoly(e1, e2, pt);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
else if (IsFront(e1) || (e1.outrec == e2.outrec))
|
|
else if (IsFront(e1) || (e1.outrec == e2.outrec))
|
|
@@ -1937,19 +1958,20 @@ namespace Clipper2Lib {
|
|
//it's sensible to split polygons that ony touch at
|
|
//it's sensible to split polygons that ony touch at
|
|
//a common vertex (not at common edges).
|
|
//a common vertex (not at common edges).
|
|
|
|
|
|
- resultOp = AddLocalMaxPoly(e1, e2, pt);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddLocalMaxPoly(e1, e2, pt);
|
|
OutPt* op2 = AddLocalMinPoly(e1, e2, pt);
|
|
OutPt* op2 = AddLocalMinPoly(e1, e2, pt);
|
|
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_) SetZ(e1, e2, op2->pt);
|
|
if (zCallback_) SetZ(e1, e2, op2->pt);
|
|
#else
|
|
#else
|
|
|
|
+ AddLocalMaxPoly(e1, e2, pt);
|
|
AddLocalMinPoly(e1, e2, pt);
|
|
AddLocalMinPoly(e1, e2, pt);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- resultOp = AddOutPt(e1, pt);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddOutPt(e1, pt);
|
|
OutPt* op2 = AddOutPt(e2, pt);
|
|
OutPt* op2 = AddOutPt(e2, pt);
|
|
if (zCallback_)
|
|
if (zCallback_)
|
|
{
|
|
{
|
|
@@ -1957,6 +1979,7 @@ namespace Clipper2Lib {
|
|
SetZ(e1, e2, op2->pt);
|
|
SetZ(e1, e2, op2->pt);
|
|
}
|
|
}
|
|
#else
|
|
#else
|
|
|
|
+ AddOutPt(e1, pt);
|
|
AddOutPt(e2, pt);
|
|
AddOutPt(e2, pt);
|
|
#endif
|
|
#endif
|
|
SwapOutrecs(e1, e2);
|
|
SwapOutrecs(e1, e2);
|
|
@@ -1964,17 +1987,21 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
else if (IsHotEdge(e1))
|
|
else if (IsHotEdge(e1))
|
|
{
|
|
{
|
|
- resultOp = AddOutPt(e1, pt);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddOutPt(e1, pt);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
|
|
+#else
|
|
|
|
+ AddOutPt(e1, pt);
|
|
#endif
|
|
#endif
|
|
SwapOutrecs(e1, e2);
|
|
SwapOutrecs(e1, e2);
|
|
}
|
|
}
|
|
else if (IsHotEdge(e2))
|
|
else if (IsHotEdge(e2))
|
|
{
|
|
{
|
|
- resultOp = AddOutPt(e2, pt);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddOutPt(e2, pt);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
|
|
+#else
|
|
|
|
+ AddOutPt(e2, pt);
|
|
#endif
|
|
#endif
|
|
SwapOutrecs(e1, e2);
|
|
SwapOutrecs(e1, e2);
|
|
}
|
|
}
|
|
@@ -2004,33 +2031,53 @@ namespace Clipper2Lib {
|
|
|
|
|
|
if (!IsSamePolyType(e1, e2))
|
|
if (!IsSamePolyType(e1, e2))
|
|
{
|
|
{
|
|
- resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
|
|
+ resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
if (zCallback_) SetZ(e1, e2, resultOp->pt);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMinPoly(e1, e2, pt, false);
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
else if (old_e1_windcnt == 1 && old_e2_windcnt == 1)
|
|
else if (old_e1_windcnt == 1 && old_e2_windcnt == 1)
|
|
{
|
|
{
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = nullptr;
|
|
resultOp = nullptr;
|
|
|
|
+#endif
|
|
switch (cliptype_)
|
|
switch (cliptype_)
|
|
{
|
|
{
|
|
case ClipType::Union:
|
|
case ClipType::Union:
|
|
if (e1Wc2 <= 0 && e2Wc2 <= 0)
|
|
if (e1Wc2 <= 0 && e2Wc2 <= 0)
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#endif
|
|
break;
|
|
break;
|
|
case ClipType::Difference:
|
|
case ClipType::Difference:
|
|
if (((GetPolyType(e1) == PathType::Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
|
|
if (((GetPolyType(e1) == PathType::Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
|
|
((GetPolyType(e1) == PathType::Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
|
|
((GetPolyType(e1) == PathType::Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
|
|
{
|
|
{
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
break;
|
|
break;
|
|
case ClipType::Xor:
|
|
case ClipType::Xor:
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#endif
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
if (e1Wc2 > 0 && e2Wc2 > 0)
|
|
if (e1Wc2 > 0 && e2Wc2 > 0)
|
|
|
|
+#ifdef USINGZ
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
resultOp = AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#else
|
|
|
|
+ AddLocalMinPoly(e1, e2, pt, false);
|
|
|
|
+#endif
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef USINGZ
|
|
#ifdef USINGZ
|
|
@@ -2038,7 +2085,6 @@ namespace Clipper2Lib {
|
|
#endif
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- return resultOp;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
inline void ClipperBase::DeleteFromAEL(Active& e)
|
|
inline void ClipperBase::DeleteFromAEL(Active& e)
|
|
@@ -2065,7 +2111,7 @@ namespace Clipper2Lib {
|
|
e->next_in_sel = e->next_in_ael;
|
|
e->next_in_sel = e->next_in_ael;
|
|
e->jump = e->next_in_sel;
|
|
e->jump = e->next_in_sel;
|
|
if (e->join_with == JoinWith::Left)
|
|
if (e->join_with == JoinWith::Left)
|
|
- e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
|
|
|
|
|
|
+ e->curr_x = e->prev_in_ael->curr_x; // also avoids complications
|
|
else
|
|
else
|
|
e->curr_x = TopX(*e, top_y);
|
|
e->curr_x = TopX(*e, top_y);
|
|
e = e->next_in_ael;
|
|
e = e->next_in_ael;
|
|
@@ -2138,7 +2184,7 @@ namespace Clipper2Lib {
|
|
if (outrecHasEdges)
|
|
if (outrecHasEdges)
|
|
{
|
|
{
|
|
OutPt* opA = outrec->pts, * opZ = opA->next;
|
|
OutPt* opA = outrec->pts, * opZ = opA->next;
|
|
- while (opP != opZ && opP->prev->pt.y == curr_y)
|
|
|
|
|
|
+ while (opP != opZ && opP->prev->pt.y == curr_y)
|
|
opP = opP->prev;
|
|
opP = opP->prev;
|
|
while (opN != opA && opN->next->pt.y == curr_y)
|
|
while (opN != opA && opN->next->pt.y == curr_y)
|
|
opN = opN->next;
|
|
opN = opN->next;
|
|
@@ -2150,7 +2196,7 @@ namespace Clipper2Lib {
|
|
while (opN->next != opP && opN->next->pt.y == curr_y)
|
|
while (opN->next != opP && opN->next->pt.y == curr_y)
|
|
opN = opN->next;
|
|
opN = opN->next;
|
|
}
|
|
}
|
|
- bool result =
|
|
|
|
|
|
+ bool result =
|
|
SetHorzSegHeadingForward(hs, opP, opN) &&
|
|
SetHorzSegHeadingForward(hs, opP, opN) &&
|
|
!hs.left_op->horz;
|
|
!hs.left_op->horz;
|
|
|
|
|
|
@@ -2160,13 +2206,14 @@ namespace Clipper2Lib {
|
|
hs.right_op = nullptr; // (for sorting)
|
|
hs.right_op = nullptr; // (for sorting)
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
void ClipperBase::ConvertHorzSegsToJoins()
|
|
void ClipperBase::ConvertHorzSegsToJoins()
|
|
{
|
|
{
|
|
- auto j = std::count_if(horz_seg_list_.begin(),
|
|
|
|
|
|
+ auto j = std::count_if(horz_seg_list_.begin(),
|
|
horz_seg_list_.end(),
|
|
horz_seg_list_.end(),
|
|
[](HorzSegment& hs) { return UpdateHorzSegment(hs); });
|
|
[](HorzSegment& hs) { return UpdateHorzSegment(hs); });
|
|
if (j < 2) return;
|
|
if (j < 2) return;
|
|
|
|
+
|
|
std::stable_sort(horz_seg_list_.begin(), horz_seg_list_.end(), HorzSegSorter());
|
|
std::stable_sort(horz_seg_list_.begin(), horz_seg_list_.end(), HorzSegSorter());
|
|
|
|
|
|
HorzSegmentList::iterator hs1 = horz_seg_list_.begin(), hs2;
|
|
HorzSegmentList::iterator hs1 = horz_seg_list_.begin(), hs2;
|
|
@@ -2207,8 +2254,8 @@ namespace Clipper2Lib {
|
|
DuplicateOp(hs1->left_op, false));
|
|
DuplicateOp(hs1->left_op, false));
|
|
horz_join_list_.push_back(join);
|
|
horz_join_list_.push_back(join);
|
|
}
|
|
}
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
|
void MoveSplits(OutRec* fromOr, OutRec* toOr)
|
|
@@ -2301,7 +2348,7 @@ namespace Clipper2Lib {
|
|
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
|
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
|
|
{
|
|
{
|
|
Point64 ip;
|
|
Point64 ip;
|
|
- if (!GetIntersectPoint(e1.bot, e1.top, e2.bot, e2.top, ip))
|
|
|
|
|
|
+ if (!GetSegmentIntersectPt(e1.bot, e1.top, e2.bot, e2.top, ip))
|
|
ip = Point64(e1.curr_x, top_y); //parallel edges
|
|
ip = Point64(e1.curr_x, top_y); //parallel edges
|
|
|
|
|
|
//rounding errors can occasionally place the calculated intersection
|
|
//rounding errors can occasionally place the calculated intersection
|
|
@@ -2321,7 +2368,7 @@ namespace Clipper2Lib {
|
|
ip = GetClosestPointOnSegment(ip, e1.bot, e1.top);
|
|
ip = GetClosestPointOnSegment(ip, e1.bot, e1.top);
|
|
else if (abs_dx2 > 100)
|
|
else if (abs_dx2 > 100)
|
|
ip = GetClosestPointOnSegment(ip, e2.bot, e2.top);
|
|
ip = GetClosestPointOnSegment(ip, e2.bot, e2.top);
|
|
- else
|
|
|
|
|
|
+ else
|
|
{
|
|
{
|
|
if (ip.y < top_y) ip.y = top_y;
|
|
if (ip.y < top_y) ip.y = top_y;
|
|
else ip.y = bot_y_;
|
|
else ip.y = bot_y_;
|
|
@@ -2453,7 +2500,7 @@ namespace Clipper2Lib {
|
|
horz_seg_list_.push_back(HorzSegment(op));
|
|
horz_seg_list_.push_back(HorzSegment(op));
|
|
}
|
|
}
|
|
|
|
|
|
- bool ClipperBase::ResetHorzDirection(const Active& horz,
|
|
|
|
|
|
+ bool ClipperBase::ResetHorzDirection(const Active& horz,
|
|
const Vertex* max_vertex, int64_t& horz_left, int64_t& horz_right)
|
|
const Vertex* max_vertex, int64_t& horz_left, int64_t& horz_right)
|
|
{
|
|
{
|
|
if (horz.bot.x == horz.top.x)
|
|
if (horz.bot.x == horz.top.x)
|
|
@@ -2536,8 +2583,8 @@ namespace Clipper2Lib {
|
|
if (IsHotEdge(horz) && IsJoined(*e))
|
|
if (IsHotEdge(horz) && IsJoined(*e))
|
|
Split(*e, e->top);
|
|
Split(*e, e->top);
|
|
|
|
|
|
- //if (IsHotEdge(horz) != IsHotEdge(*e))
|
|
|
|
- // DoError(undefined_error_i);
|
|
|
|
|
|
+ //if (IsHotEdge(horz) != IsHotEdge(*e))
|
|
|
|
+ // DoError(undefined_error_i);
|
|
|
|
|
|
if (IsHotEdge(horz))
|
|
if (IsHotEdge(horz))
|
|
{
|
|
{
|
|
@@ -2641,7 +2688,7 @@ namespace Clipper2Lib {
|
|
ResetHorzDirection(horz, vertex_max, horz_left, horz_right);
|
|
ResetHorzDirection(horz, vertex_max, horz_left, horz_right);
|
|
}
|
|
}
|
|
|
|
|
|
- if (IsHotEdge(horz))
|
|
|
|
|
|
+ if (IsHotEdge(horz))
|
|
{
|
|
{
|
|
OutPt* op = AddOutPt(horz, horz.top);
|
|
OutPt* op = AddOutPt(horz, horz.top);
|
|
AddTrialHorzJoin(op);
|
|
AddTrialHorzJoin(op);
|
|
@@ -2754,21 +2801,23 @@ namespace Clipper2Lib {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- void ClipperBase::CheckJoinLeft(Active& e,
|
|
|
|
|
|
+ void ClipperBase::CheckJoinLeft(Active& e,
|
|
const Point64& pt, bool check_curr_x)
|
|
const Point64& pt, bool check_curr_x)
|
|
{
|
|
{
|
|
Active* prev = e.prev_in_ael;
|
|
Active* prev = e.prev_in_ael;
|
|
- if (IsOpen(e) || !IsHotEdge(e) || !prev ||
|
|
|
|
- IsOpen(*prev) || !IsHotEdge(*prev)) return;
|
|
|
|
|
|
+ if (!prev ||
|
|
|
|
+ !IsHotEdge(e) || !IsHotEdge(*prev) ||
|
|
|
|
+ IsHorizontal(e) || IsHorizontal(*prev) ||
|
|
|
|
+ IsOpen(e) || IsOpen(*prev) ) return;
|
|
if ((pt.y < e.top.y + 2 || pt.y < prev->top.y + 2) &&
|
|
if ((pt.y < e.top.y + 2 || pt.y < prev->top.y + 2) &&
|
|
- ((e.bot.y > pt.y) || (prev->bot.y > pt.y))) return; // avoid trivial joins
|
|
|
|
|
|
+ ((e.bot.y > pt.y) || (prev->bot.y > pt.y))) return; // avoid trivial joins
|
|
|
|
|
|
if (check_curr_x)
|
|
if (check_curr_x)
|
|
{
|
|
{
|
|
- if (DistanceFromLineSqrd(pt, prev->bot, prev->top) > 0.25) return;
|
|
|
|
|
|
+ if (PerpendicDistFromLineSqrd(pt, prev->bot, prev->top) > 0.25) return;
|
|
}
|
|
}
|
|
else if (e.curr_x != prev->curr_x) return;
|
|
else if (e.curr_x != prev->curr_x) return;
|
|
- if (CrossProduct(e.top, pt, prev->top)) return;
|
|
|
|
|
|
+ if (!IsCollinear(e.top, pt, prev->top)) return;
|
|
|
|
|
|
if (e.outrec->idx == prev->outrec->idx)
|
|
if (e.outrec->idx == prev->outrec->idx)
|
|
AddLocalMaxPoly(*prev, e, pt);
|
|
AddLocalMaxPoly(*prev, e, pt);
|
|
@@ -2780,22 +2829,24 @@ namespace Clipper2Lib {
|
|
e.join_with = JoinWith::Left;
|
|
e.join_with = JoinWith::Left;
|
|
}
|
|
}
|
|
|
|
|
|
- void ClipperBase::CheckJoinRight(Active& e,
|
|
|
|
|
|
+ void ClipperBase::CheckJoinRight(Active& e,
|
|
const Point64& pt, bool check_curr_x)
|
|
const Point64& pt, bool check_curr_x)
|
|
{
|
|
{
|
|
Active* next = e.next_in_ael;
|
|
Active* next = e.next_in_ael;
|
|
- if (IsOpen(e) || !IsHotEdge(e) ||
|
|
|
|
- !next || IsOpen(*next) || !IsHotEdge(*next)) return;
|
|
|
|
|
|
+ if (!next ||
|
|
|
|
+ !IsHotEdge(e) || !IsHotEdge(*next) ||
|
|
|
|
+ IsHorizontal(e) || IsHorizontal(*next) ||
|
|
|
|
+ IsOpen(e) || IsOpen(*next)) return;
|
|
if ((pt.y < e.top.y +2 || pt.y < next->top.y +2) &&
|
|
if ((pt.y < e.top.y +2 || pt.y < next->top.y +2) &&
|
|
- ((e.bot.y > pt.y) || (next->bot.y > pt.y))) return; // avoid trivial joins
|
|
|
|
|
|
+ ((e.bot.y > pt.y) || (next->bot.y > pt.y))) return; // avoid trivial joins
|
|
|
|
|
|
if (check_curr_x)
|
|
if (check_curr_x)
|
|
{
|
|
{
|
|
- if (DistanceFromLineSqrd(pt, next->bot, next->top) > 0.35) return;
|
|
|
|
|
|
+ if (PerpendicDistFromLineSqrd(pt, next->bot, next->top) > 0.35) return;
|
|
}
|
|
}
|
|
else if (e.curr_x != next->curr_x) return;
|
|
else if (e.curr_x != next->curr_x) return;
|
|
- if (CrossProduct(e.top, pt, next->top)) return;
|
|
|
|
-
|
|
|
|
|
|
+ if (!IsCollinear(e.top, pt, next->top)) return;
|
|
|
|
+
|
|
if (e.outrec->idx == next->outrec->idx)
|
|
if (e.outrec->idx == next->outrec->idx)
|
|
AddLocalMaxPoly(e, *next, pt);
|
|
AddLocalMaxPoly(e, *next, pt);
|
|
else if (e.outrec->idx < next->outrec->idx)
|
|
else if (e.outrec->idx < next->outrec->idx)
|
|
@@ -2863,7 +2914,7 @@ namespace Clipper2Lib {
|
|
op2 = op2->next;
|
|
op2 = op2->next;
|
|
}
|
|
}
|
|
|
|
|
|
- if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
|
|
|
|
|
|
+ if (!isOpen && path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
|
|
else return true;
|
|
else return true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2872,8 +2923,8 @@ namespace Clipper2Lib {
|
|
if (!outrec->pts) return false;
|
|
if (!outrec->pts) return false;
|
|
if (!outrec->bounds.IsEmpty()) return true;
|
|
if (!outrec->bounds.IsEmpty()) return true;
|
|
CleanCollinear(outrec);
|
|
CleanCollinear(outrec);
|
|
- if (!outrec->pts ||
|
|
|
|
- !BuildPath64(outrec->pts, reverse_solution_, false, outrec->path)){
|
|
|
|
|
|
+ if (!outrec->pts ||
|
|
|
|
+ !BuildPath64(outrec->pts, reverse_solution_, false, outrec->path)){
|
|
return false;}
|
|
return false;}
|
|
outrec->bounds = GetBounds(outrec->path);
|
|
outrec->bounds = GetBounds(outrec->path);
|
|
return true;
|
|
return true;
|
|
@@ -2887,10 +2938,10 @@ namespace Clipper2Lib {
|
|
if(!split || split == outrec || split->recursive_split == outrec) continue;
|
|
if(!split || split == outrec || split->recursive_split == outrec) continue;
|
|
split->recursive_split = outrec; // prevent infinite loops
|
|
split->recursive_split = outrec; // prevent infinite loops
|
|
|
|
|
|
- if (split->splits && CheckSplitOwner(outrec, split->splits))
|
|
|
|
|
|
+ if (split->splits && CheckSplitOwner(outrec, split->splits))
|
|
return true;
|
|
return true;
|
|
- else if (CheckBounds(split) &&
|
|
|
|
- IsValidOwner(outrec, split) &&
|
|
|
|
|
|
+ else if (CheckBounds(split) &&
|
|
|
|
+ IsValidOwner(outrec, split) &&
|
|
split->bounds.Contains(outrec->bounds) &&
|
|
split->bounds.Contains(outrec->bounds) &&
|
|
Path1InsidePath2(outrec->pts, split->pts))
|
|
Path1InsidePath2(outrec->pts, split->pts))
|
|
{
|
|
{
|
|
@@ -2919,7 +2970,7 @@ namespace Clipper2Lib {
|
|
|
|
|
|
if (outrec->owner)
|
|
if (outrec->owner)
|
|
{
|
|
{
|
|
- if (!outrec->owner->polypath)
|
|
|
|
|
|
+ if (!outrec->owner->polypath)
|
|
RecursiveCheckOwners(outrec->owner, polypath);
|
|
RecursiveCheckOwners(outrec->owner, polypath);
|
|
outrec->polypath = outrec->owner->polypath->AddChild(outrec->path);
|
|
outrec->polypath = outrec->owner->polypath->AddChild(outrec->path);
|
|
}
|
|
}
|
|
@@ -2968,7 +3019,7 @@ namespace Clipper2Lib {
|
|
open_paths.resize(0);
|
|
open_paths.resize(0);
|
|
if (has_open_paths_)
|
|
if (has_open_paths_)
|
|
open_paths.reserve(outrec_list_.size());
|
|
open_paths.reserve(outrec_list_.size());
|
|
-
|
|
|
|
|
|
+
|
|
// outrec_list_.size() is not static here because
|
|
// outrec_list_.size() is not static here because
|
|
// CheckBounds below can indirectly add additional
|
|
// CheckBounds below can indirectly add additional
|
|
// OutRec (via FixOutRecPts & CleanCollinear)
|
|
// OutRec (via FixOutRecPts & CleanCollinear)
|
|
@@ -2991,7 +3042,7 @@ namespace Clipper2Lib {
|
|
|
|
|
|
bool BuildPathD(OutPt* op, bool reverse, bool isOpen, PathD& path, double inv_scale)
|
|
bool BuildPathD(OutPt* op, bool reverse, bool isOpen, PathD& path, double inv_scale)
|
|
{
|
|
{
|
|
- if (!op || op->next == op || (!isOpen && op->next == op->prev))
|
|
|
|
|
|
+ if (!op || op->next == op || (!isOpen && op->next == op->prev))
|
|
return false;
|
|
return false;
|
|
|
|
|
|
path.resize(0);
|
|
path.resize(0);
|
|
@@ -3024,7 +3075,7 @@ namespace Clipper2Lib {
|
|
#else
|
|
#else
|
|
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
|
|
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
|
|
#endif
|
|
#endif
|
|
-
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
if (reverse)
|
|
if (reverse)
|
|
op2 = op2->prev;
|
|
op2 = op2->prev;
|