Fixed a bug in ClipperBase::FixSelfIntersects (#1067)

Fixed a bug in Clipper.pas (Delphi only) re. left to right evaluation of if statements (#1061)
Replaced throw statements with DoError function. (C++ only; #1068)
This commit is contained in:
angusj
2026-02-22 11:20:26 +10:00
parent 20f05b475e
commit 4da1564fb1
9 changed files with 57 additions and 86 deletions
+12 -23
View File
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 5 November 2025 *
* Date : 21 February 2026 *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2025 *
* Copyright : Angus Johnson 2010-2026 *
* Purpose : This is the main polygon clipping module *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -617,7 +617,7 @@ namespace Clipper2Lib {
{return a + path.size(); });
if (total_vertex_count == 0) return;
Vertex* vertices = new Vertex[total_vertex_count], * v = vertices;
Vertex* allVertices = new Vertex[total_vertex_count], * v = allVertices;
for (const Path64& path : paths)
{
//for each path create a circular double linked list of vertices
@@ -709,7 +709,7 @@ namespace Clipper2Lib {
}
} // end processing current path
vertexLists.emplace_back(vertices);
vertexLists.emplace_back(allVertices);
}
//------------------------------------------------------------------------------
@@ -1653,25 +1653,14 @@ namespace Clipper2Lib {
if (SegmentsIntersect(op2->prev->pt,
op2->pt, op2->next->pt, op2->next->next->pt))
{
if (SegmentsIntersect(op2->prev->pt,
op2->pt, op2->next->next->pt, op2->next->next->next->pt))
{
// adjacent intersections (ie a micro self-intersections)
op2 = DuplicateOp(op2, false);
op2->pt = op2->next->next->next->pt;
op2 = op2->next;
}
else
{
if (op2 == outrec->pts || op2->next == outrec->pts)
outrec->pts = outrec->pts->prev;
DoSplitOp(outrec, op2);
if (!outrec->pts) break;
op2 = outrec->pts;
if (op2->prev == op2->next->next)
break; // again, because triangles can't self-intersect
continue;
}
if (op2 == outrec->pts || op2->next == outrec->pts)
outrec->pts = outrec->pts->prev;
DoSplitOp(outrec, op2);
if (!outrec->pts) break;
op2 = outrec->pts;
if (op2->prev == op2->next->next)
break; // again, because triangles can't self-intersect
continue;
}
else
op2 = op2->next;
@@ -1,9 +1,9 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 13 December 2025 *
* Date : 21 February 2026 *
* Release : BETA RELEASE *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2025 *
* Copyright : Angus Johnson 2010-2026 *
* Purpose : Constrained Delaunay Triangulation *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************/
@@ -196,7 +196,7 @@ namespace Clipper2Lib
static void RemoveEdgeFromVertex(Vertex2* vert, Edge* edge)
{
auto it = std::find(vert->edges.begin(), vert->edges.end(), edge);
if (it == vert->edges.end()) throw "oops!";
if (it == vert->edges.end()) DoError(undefined_error_i);
vert->edges.erase(it);
}
@@ -436,7 +436,7 @@ namespace Clipper2Lib
for (int i = 1; i < 3; ++i)
{
edge->triA->edges[i] = edgesA[i];
if (!edgesA[i]) throw "oops"; // stops compiler warnings
if (!edgesA[i]) DoError(undefined_error_i);
if (IsLooseEdge(*edgesA[i]))
pendingDelaunayStack.push(edgesA[i]);
// since each edge has its own triangleA and triangleB, we have to be careful
@@ -447,14 +447,14 @@ namespace Clipper2Lib
edgesA[i]->triA = edge->triA;
else if (edgesA[i]->triB == edge->triB)
edgesA[i]->triB = edge->triA;
else throw "oops";
else DoError(undefined_error_i);
}
edge->triB->edges[0] = edge;
for (int i = 1; i < 3; ++i)
{
edge->triB->edges[i] = edgesB[i];
if (!edgesB[i]) throw "oops"; // stops compiler warnings
if (!edgesB[i]) DoError(undefined_error_i);
if (IsLooseEdge(*edgesB[i]))
pendingDelaunayStack.push(edgesB[i]);
// since each edge has its own triangleA and triangleB, we have to be careful
@@ -465,7 +465,7 @@ namespace Clipper2Lib
edgesB[i]->triA = edge->triB;
else if (edgesB[i]->triB == edge->triA)
edgesB[i]->triB = edge->triB;
else throw "oops";
else DoError(undefined_error_i);
}
}
+10 -21
View File
@@ -1,8 +1,8 @@
/*******************************************************************************
* Author : Angus Johnson *
* Date : 5 November 2025 *
* Date : 21 February 2026 *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2025 *
* Copyright : Angus Johnson 2010-2026 *
* Purpose : This is the main polygon clipping module *
* Thanks : Special thanks to Thong Nguyen, Guus Kuiper, Phil Stopford, *
* : and Daniel Gosnell for their invaluable assistance with C#. *
@@ -2970,25 +2970,14 @@ private void DoHorizontal(Active horz)
if (InternalClipper.SegsIntersect(op2!.prev.pt,
op2.pt, op2.next!.pt, op2.next.next!.pt))
{
if (InternalClipper.SegsIntersect(op2.prev.pt,
op2.pt, op2.next.next!.pt, op2.next.next.next!.pt))
{
// adjacent intersections (ie a micro self-intersection)
op2 = DuplicateOp(op2, false);
op2.pt = op2.next!.next!.next!.pt;
op2 = op2.next;
}
else
{
if (op2 == outrec.pts || op2.next == outrec.pts)
outrec.pts = outrec.pts.prev;
DoSplitOp(outrec, op2);
if (outrec.pts == null) return;
op2 = outrec.pts;
// triangles can't self-intersect
if (op2.prev == op2.next!.next) break;
continue;
}
if (op2 == outrec.pts || op2.next == outrec.pts)
outrec.pts = outrec.pts.prev;
DoSplitOp(outrec, op2);
if (outrec.pts == null) return;
op2 = outrec.pts;
// triangles can't self-intersect
if (op2.prev == op2.next!.next) break;
continue;
}
op2 = op2.next!;
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<ApplicationIcon>Clipper2.ico</ApplicationIcon>
</PropertyGroup>
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<ApplicationIcon>Clipper2.ico</ApplicationIcon>
</PropertyGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<ApplicationIcon>Clipper2.ico</ApplicationIcon>
<Platforms>AnyCPU;x86</Platforms>
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<EnableNETAnalyzers>false</EnableNETAnalyzers>
<ApplicationIcon>Clipper2.ico</ApplicationIcon>
</PropertyGroup>
+1 -1
View File
@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
+23 -30
View File
@@ -2,9 +2,9 @@ unit Clipper.Engine;
(*******************************************************************************
* Author : Angus Johnson *
* Date : 5 November 2025 *
* Date : 21 February 2026 *
* Website : https://www.angusj.com *
* Copyright : Angus Johnson 2010-2025 *
* Copyright : Angus Johnson 2010-2026 *
* Purpose : This is the main polygon clipping module *
* License : https://www.boost.org/LICENSE_1_0.txt *
*******************************************************************************)
@@ -1945,7 +1945,8 @@ begin
begin
if IsHeadingLeftHorz(rightB) then SwapActives(leftB, rightB);
end
else if (leftB.dx < rightB.dx) then SwapActives(leftB, rightB);
else if (leftB.dx < rightB.dx) then
SwapActives(leftB, rightB);
//so when leftB has windDx == 1, the polygon will be oriented
//counter-clockwise in Cartesian coords (clockwise with inverted Y).
end
@@ -1987,7 +1988,7 @@ begin
begin
rbn := rightB.nextInAEL;
IntersectEdges(rightB, rbn, rightB.bot);
SwapPositionsInAEL(rightB, rightB.nextInAEL);
SwapPositionsInAEL(rightB, rbn);
end;
if IsHorizontal(rightB) then
@@ -2229,25 +2230,15 @@ begin
if SegmentsIntersect(op2.prev.pt, op2.pt,
op2.next.pt, op2.next.next.pt) then
begin
if SegmentsIntersect(op2.prev.pt, op2.pt,
op2.next.next.pt, op2.next.next.next.pt) then
begin
// adjacent intersections (ie a micro self-intersection)
op2 := DuplicateOp(op2, false);
op2.pt := op2.next.next.next.pt;
op2 := op2.next;
end else
begin
if (op2 = outrec.pts) or (op2.next = outrec.pts) then
outrec.pts := outrec.pts.prev;
// split required
DoSplitOp(outrec, op2);
if not assigned(outrec.pts) then Break;
op2 := outrec.pts;
if (op2.prev = op2.next.next) then
Break; // because triangles can't self-intersect
Continue;
end;
// split required.
if (op2 = outrec.pts) or (op2.next = outrec.pts) then
outrec.pts := outrec.pts.prev;
DoSplitOp(outrec, op2);
if not assigned(outrec.pts) then Break;
op2 := outrec.pts;
if (op2.prev = op2.next.next) then
Break; // because triangles can't self-intersect
Continue;
end else
op2 := op2.next;
if (op2 = outrec.pts) then Break;
@@ -2919,14 +2910,14 @@ function HorzontalsOverlap(const horz1a, horz1b, horz2a, horz2b: TPoint64): bool
begin
if horz1a.X < horz1b.X then
begin
Result := Iif(horz2a.X < horz2b.X,
HorzOverlapWithLRSet(horz1a, horz1b, horz2a, horz2b),
HorzOverlapWithLRSet(horz1a, horz1b, horz2b, horz2a));
if (horz2a.X < horz2b.X) then
Result := HorzOverlapWithLRSet(horz1a, horz1b, horz2a, horz2b) else
Result := HorzOverlapWithLRSet(horz1a, horz1b, horz2b, horz2a);
end else
begin
Result := Iif(horz2a.X < horz2b.X,
HorzOverlapWithLRSet(horz1b, horz1a, horz2a, horz2b),
HorzOverlapWithLRSet(horz1b, horz1a, horz2b, horz2a));
if (horz2a.X < horz2b.X) then
Result := HorzOverlapWithLRSet(horz1b, horz1a, horz2a, horz2b) else
Result := HorzOverlapWithLRSet(horz1b, horz1a, horz2b, horz2a);
end;
end;
//------------------------------------------------------------------------------
@@ -3188,7 +3179,9 @@ begin
else
begin
ip.Y := Iif(ip.Y < topY, topY , fBotY);
ip.X := Iif(absDx1 < absDx2, TopX(e1, ip.Y), TopX(e2, ip.Y));
if absDx1 < absDx2 then
ip.X := TopX(e1, ip.Y) else
ip.X := TopX(e2, ip.Y);
end;
end;
new(node);