You've already forked godot
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:
225
thirdparty/clipper2/src/clipper.engine.cpp
vendored
225
thirdparty/clipper2/src/clipper.engine.cpp
vendored
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user