1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-17 14:11:06 +00:00

clipper2: Update to 1.4.0

This commit is contained in:
Jakub Marcowski
2024-08-22 18:23:26 +02:00
parent d09d82d433
commit 1bd52fed76
16 changed files with 872 additions and 617 deletions

View File

@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 22 November 2023 *
* Date : 27 April 2024 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2023 *
* Copyright : Angus Johnson 2010-2024 *
* Purpose : This is the main polygon clipping module *
* License : http://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -31,11 +31,11 @@ namespace Clipper2Lib {
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 {
int64_t y = 0;
@@ -63,6 +63,7 @@ namespace Clipper2Lib {
}
};
inline bool IsOdd(int val)
{
return (val & 1) ? true : false;
@@ -188,7 +189,7 @@ namespace Clipper2Lib {
}
//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)
{
if (ae.wind_dx > 0)
@@ -233,15 +234,15 @@ namespace Clipper2Lib {
Vertex* result = e.vertex_top;
if (e.wind_dx > 0)
while ((result->next->pt.y == result->pt.y) &&
((result->flags & (VertexFlags::OpenEnd |
((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
result = result->next;
else
while (result->prev->pt.y == result->pt.y &&
((result->flags & (VertexFlags::OpenEnd |
((result->flags & (VertexFlags::OpenEnd |
VertexFlags::LocalMax)) == VertexFlags::None))
result = result->prev;
if (!IsMaxima(*result)) result = nullptr; // not a maxima
if (!IsMaxima(*result)) result = nullptr; // not a maxima
return result;
}
@@ -252,7 +253,7 @@ namespace Clipper2Lib {
while (result->next->pt.y == result->pt.y) result = result->next;
else
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;
}
@@ -613,13 +614,13 @@ namespace Clipper2Lib {
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)
{
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)
{return a + static_cast<unsigned>(path.size()); });
{return a + path.size(); });
if (total_vertex_count == 0) return;
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)
{
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
if (GetPolyType(e1) == PathType::Subject)
{
@@ -845,11 +846,11 @@ namespace Clipper2Lib {
if (is_open) has_open_paths_ = true;
minima_list_sorted_ = false;
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.
succeeded_ = false;
minima_list_sorted_ = false;
@@ -1117,7 +1118,6 @@ namespace Clipper2Lib {
}
}
bool IsValidAelOrder(const Active& resident, const Active& newcomer)
{
if (newcomer.curr_x != resident.curr_x)
@@ -1149,8 +1149,8 @@ namespace Clipper2Lib {
//resident must also have just been inserted
else if (resident.is_left_bound != 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
//compare turning direction of the alternate bound
return (CrossProduct(PrevPrevVertex(resident)->pt,
@@ -1385,7 +1385,7 @@ namespace Clipper2Lib {
{
if (IsJoined(e1)) Split(e1, pt);
if (IsJoined(e2)) Split(e2, pt);
if (IsFront(e1) == IsFront(e2))
{
if (IsOpenEnd(e1))
@@ -1409,7 +1409,7 @@ namespace Clipper2Lib {
{
Active* e = GetPrevHotEdge(e1);
if (!e)
outrec.owner = nullptr;
outrec.owner = nullptr;
else
SetOwner(&outrec, e->outrec);
// nb: outRec.owner here is likely NOT the real
@@ -1476,7 +1476,7 @@ namespace Clipper2Lib {
e2.outrec->pts = e1.outrec->pts;
e1.outrec->pts = nullptr;
}
else
else
SetOwner(e2.outrec, e1.outrec);
//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;
}
void ClipperBase::CleanCollinear(OutRec* outrec)
{
outrec = GetRealOutRec(outrec);
@@ -1541,7 +1540,7 @@ namespace Clipper2Lib {
for (; ; )
{
//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->next->pt || !preserve_collinear_ ||
DotProduct(op2->prev->pt, op2->pt, op2->next->pt) < 0))
@@ -1566,14 +1565,14 @@ namespace Clipper2Lib {
void ClipperBase::DoSplitOp(OutRec* outrec, OutPt* splitOp)
{
// splitOp.prev -> splitOp &&
// splitOp.prev -> splitOp &&
// splitOp.next -> splitOp.next.next are intersecting
OutPt* prevOp = splitOp->prev;
OutPt* nextNextOp = splitOp->next->next;
outrec->pts = prevOp;
Point64 ip;
GetIntersectPoint(prevOp->pt, splitOp->pt,
GetSegmentIntersectPt(prevOp->pt, splitOp->pt,
splitOp->next->pt, nextNextOp->pt, ip);
#ifdef USINGZ
@@ -1617,7 +1616,7 @@ namespace Clipper2Lib {
{
OutRec* newOr = NewOutRec();
newOr->owner = outrec->owner;
splitOp->outrec = newOr;
splitOp->next->outrec = 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 ...
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;
if (IsOpen(e1))
{
@@ -1791,29 +1790,40 @@ namespace Clipper2Lib {
}
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_)
{
case ClipType::Union:
if (!IsHotEdge(*edge_c)) return nullptr;
if (!IsHotEdge(*edge_c)) return;
break;
default:
if (edge_c->local_min->polytype == PathType::Subject)
return nullptr;
return;
}
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;
#endif
//toggle contribution ...
if (IsHotEdge(*edge_o))
{
#ifdef USINGZ
resultOp = AddOutPt(*edge_o, pt);
#else
AddOutPt(*edge_o, pt);
#endif
if (IsFront(*edge_o)) edge_o->outrec->front_edge = nullptr;
else edge_o->outrec->back_edge = nullptr;
edge_o->outrec = nullptr;
@@ -1833,18 +1843,26 @@ namespace Clipper2Lib {
SetSides(*e3->outrec, *edge_o, *e3);
else
SetSides(*e3->outrec, *e3, *edge_o);
return e3->outrec->pts;
return;
}
else
#ifdef USINGZ
resultOp = StartOpenPath(*edge_o, pt);
#else
StartOpenPath(*edge_o, pt);
#endif
}
else
#ifdef USINGZ
resultOp = StartOpenPath(*edge_o, pt);
#else
StartOpenPath(*edge_o, pt);
#endif
#ifdef USINGZ
if (zCallback_) SetZ(*edge_o, *edge_c, resultOp->pt);
#endif
return resultOp;
return;
} // end of an open path intersection
//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 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 ...
#ifdef USINGZ
OutPt* resultOp = nullptr;
#endif
//if both edges are 'hot' ...
if (IsHotEdge(e1) && IsHotEdge(e2))
{
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))
{
resultOp = AddLocalMaxPoly(e1, e2, pt);
#ifdef USINGZ
resultOp = AddLocalMaxPoly(e1, e2, pt);
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
#else
AddLocalMaxPoly(e1, e2, pt);
#endif
}
else if (IsFront(e1) || (e1.outrec == e2.outrec))
@@ -1937,19 +1958,20 @@ namespace Clipper2Lib {
//it's sensible to split polygons that ony touch at
//a common vertex (not at common edges).
resultOp = AddLocalMaxPoly(e1, e2, pt);
#ifdef USINGZ
resultOp = AddLocalMaxPoly(e1, e2, pt);
OutPt* op2 = AddLocalMinPoly(e1, e2, pt);
if (zCallback_ && resultOp) SetZ(e1, e2, resultOp->pt);
if (zCallback_) SetZ(e1, e2, op2->pt);
#else
AddLocalMaxPoly(e1, e2, pt);
AddLocalMinPoly(e1, e2, pt);
#endif
}
else
{
resultOp = AddOutPt(e1, pt);
#ifdef USINGZ
resultOp = AddOutPt(e1, pt);
OutPt* op2 = AddOutPt(e2, pt);
if (zCallback_)
{
@@ -1957,6 +1979,7 @@ namespace Clipper2Lib {
SetZ(e1, e2, op2->pt);
}
#else
AddOutPt(e1, pt);
AddOutPt(e2, pt);
#endif
SwapOutrecs(e1, e2);
@@ -1964,17 +1987,21 @@ namespace Clipper2Lib {
}
else if (IsHotEdge(e1))
{
resultOp = AddOutPt(e1, pt);
#ifdef USINGZ
resultOp = AddOutPt(e1, pt);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
#else
AddOutPt(e1, pt);
#endif
SwapOutrecs(e1, e2);
}
else if (IsHotEdge(e2))
{
resultOp = AddOutPt(e2, pt);
#ifdef USINGZ
resultOp = AddOutPt(e2, pt);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
#else
AddOutPt(e2, pt);
#endif
SwapOutrecs(e1, e2);
}
@@ -2004,33 +2031,53 @@ namespace Clipper2Lib {
if (!IsSamePolyType(e1, e2))
{
resultOp = AddLocalMinPoly(e1, e2, pt, false);
#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
if (zCallback_) SetZ(e1, e2, resultOp->pt);
#else
AddLocalMinPoly(e1, e2, pt, false);
#endif
}
else if (old_e1_windcnt == 1 && old_e2_windcnt == 1)
{
#ifdef USINGZ
resultOp = nullptr;
#endif
switch (cliptype_)
{
case ClipType::Union:
if (e1Wc2 <= 0 && e2Wc2 <= 0)
#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
#else
AddLocalMinPoly(e1, e2, pt, false);
#endif
break;
case ClipType::Difference:
if (((GetPolyType(e1) == PathType::Clip) && (e1Wc2 > 0) && (e2Wc2 > 0)) ||
((GetPolyType(e1) == PathType::Subject) && (e1Wc2 <= 0) && (e2Wc2 <= 0)))
{
#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
#else
AddLocalMinPoly(e1, e2, pt, false);
#endif
}
break;
case ClipType::Xor:
#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
#else
AddLocalMinPoly(e1, e2, pt, false);
#endif
break;
default:
if (e1Wc2 > 0 && e2Wc2 > 0)
#ifdef USINGZ
resultOp = AddLocalMinPoly(e1, e2, pt, false);
#else
AddLocalMinPoly(e1, e2, pt, false);
#endif
break;
}
#ifdef USINGZ
@@ -2038,7 +2085,6 @@ namespace Clipper2Lib {
#endif
}
}
return resultOp;
}
inline void ClipperBase::DeleteFromAEL(Active& e)
@@ -2065,7 +2111,7 @@ namespace Clipper2Lib {
e->next_in_sel = e->next_in_ael;
e->jump = e->next_in_sel;
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
e->curr_x = TopX(*e, top_y);
e = e->next_in_ael;
@@ -2138,7 +2184,7 @@ namespace Clipper2Lib {
if (outrecHasEdges)
{
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;
while (opN != opA && opN->next->pt.y == curr_y)
opN = opN->next;
@@ -2150,7 +2196,7 @@ namespace Clipper2Lib {
while (opN->next != opP && opN->next->pt.y == curr_y)
opN = opN->next;
}
bool result =
bool result =
SetHorzSegHeadingForward(hs, opP, opN) &&
!hs.left_op->horz;
@@ -2160,13 +2206,14 @@ namespace Clipper2Lib {
hs.right_op = nullptr; // (for sorting)
return result;
}
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(),
[](HorzSegment& hs) { return UpdateHorzSegment(hs); });
if (j < 2) return;
std::stable_sort(horz_seg_list_.begin(), horz_seg_list_.end(), HorzSegSorter());
HorzSegmentList::iterator hs1 = horz_seg_list_.begin(), hs2;
@@ -2207,8 +2254,8 @@ namespace Clipper2Lib {
DuplicateOp(hs1->left_op, false));
horz_join_list_.push_back(join);
}
}
}
}
}
}
void MoveSplits(OutRec* fromOr, OutRec* toOr)
@@ -2301,7 +2348,7 @@ namespace Clipper2Lib {
void ClipperBase::AddNewIntersectNode(Active& e1, Active& e2, int64_t top_y)
{
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
//rounding errors can occasionally place the calculated intersection
@@ -2321,7 +2368,7 @@ namespace Clipper2Lib {
ip = GetClosestPointOnSegment(ip, e1.bot, e1.top);
else if (abs_dx2 > 100)
ip = GetClosestPointOnSegment(ip, e2.bot, e2.top);
else
else
{
if (ip.y < top_y) ip.y = top_y;
else ip.y = bot_y_;
@@ -2453,7 +2500,7 @@ namespace Clipper2Lib {
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)
{
if (horz.bot.x == horz.top.x)
@@ -2536,8 +2583,8 @@ namespace Clipper2Lib {
if (IsHotEdge(horz) && IsJoined(*e))
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))
{
@@ -2641,7 +2688,7 @@ namespace Clipper2Lib {
ResetHorzDirection(horz, vertex_max, horz_left, horz_right);
}
if (IsHotEdge(horz))
if (IsHotEdge(horz))
{
OutPt* op = AddOutPt(horz, horz.top);
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)
{
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) &&
((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 (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;
if (CrossProduct(e.top, pt, prev->top)) return;
if (!IsCollinear(e.top, pt, prev->top)) return;
if (e.outrec->idx == prev->outrec->idx)
AddLocalMaxPoly(*prev, e, pt);
@@ -2780,22 +2829,24 @@ namespace Clipper2Lib {
e.join_with = JoinWith::Left;
}
void ClipperBase::CheckJoinRight(Active& e,
void ClipperBase::CheckJoinRight(Active& e,
const Point64& pt, bool check_curr_x)
{
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) &&
((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 (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;
if (CrossProduct(e.top, pt, next->top)) return;
if (!IsCollinear(e.top, pt, next->top)) return;
if (e.outrec->idx == next->outrec->idx)
AddLocalMaxPoly(e, *next, pt);
else if (e.outrec->idx < next->outrec->idx)
@@ -2863,7 +2914,7 @@ namespace Clipper2Lib {
op2 = op2->next;
}
if (path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
if (!isOpen && path.size() == 3 && IsVerySmallTriangle(*op2)) return false;
else return true;
}
@@ -2872,8 +2923,8 @@ namespace Clipper2Lib {
if (!outrec->pts) return false;
if (!outrec->bounds.IsEmpty()) return true;
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;}
outrec->bounds = GetBounds(outrec->path);
return true;
@@ -2887,10 +2938,10 @@ namespace Clipper2Lib {
if(!split || split == outrec || split->recursive_split == outrec) continue;
split->recursive_split = outrec; // prevent infinite loops
if (split->splits && CheckSplitOwner(outrec, split->splits))
if (split->splits && CheckSplitOwner(outrec, split->splits))
return true;
else if (CheckBounds(split) &&
IsValidOwner(outrec, split) &&
else if (CheckBounds(split) &&
IsValidOwner(outrec, split) &&
split->bounds.Contains(outrec->bounds) &&
Path1InsidePath2(outrec->pts, split->pts))
{
@@ -2919,7 +2970,7 @@ namespace Clipper2Lib {
if (outrec->owner)
{
if (!outrec->owner->polypath)
if (!outrec->owner->polypath)
RecursiveCheckOwners(outrec->owner, polypath);
outrec->polypath = outrec->owner->polypath->AddChild(outrec->path);
}
@@ -2968,7 +3019,7 @@ namespace Clipper2Lib {
open_paths.resize(0);
if (has_open_paths_)
open_paths.reserve(outrec_list_.size());
// outrec_list_.size() is not static here because
// CheckBounds below can indirectly add additional
// OutRec (via FixOutRecPts & CleanCollinear)
@@ -2991,7 +3042,7 @@ namespace Clipper2Lib {
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;
path.resize(0);
@@ -3024,7 +3075,7 @@ namespace Clipper2Lib {
#else
path.push_back(PointD(lastPt.x * inv_scale, lastPt.y * inv_scale));
#endif
}
if (reverse)
op2 = op2->prev;