refactor(geometry): delete RemoveSelfIntersections

Its callers now take Clipper region offsets, which never produce the
self-intersections it patched over (and it only caught proper crossings,
so spikes survived it anyway). Polygon.OffsetEntity was its last caller;
the override is required by Entity but has no callers, so it becomes a
Clipper miter offset that keeps the Left/Right semantics and the input
winding. FindCrossing, SplitAtCrossing, SegmentsIntersect and the static
CalculateArea helper go with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
aj
2026-09-23 09:24:37 -04:00
co-authored by Claude Opus 5.5
parent 9b9386b029
commit 10fe00d8ab
3 changed files with 75 additions and 198 deletions
@@ -174,6 +174,31 @@ public class ClipperBridgeTests
}
}
[Theory]
[InlineData(true, OffsetSide.Left, 12 * 12)]
[InlineData(true, OffsetSide.Right, 8 * 8)]
[InlineData(false, OffsetSide.Left, 8 * 8)]
[InlineData(false, OffsetSide.Right, 12 * 12)]
public void PolygonOffsetEntity_MitersToSideAndKeepsWinding(
bool ccw,
OffsetSide side,
double expectedArea
)
{
var square = new Polygon();
square.Vertices.AddRange(new[] { new Vector(0, 0), new Vector(10, 0), new Vector(10, 10), new Vector(0, 10) });
if (!ccw)
square.Vertices.Reverse();
square.Close();
var result = (Polygon)square.OffsetEntity(1, side);
Assert.Equal(expectedArea, result.Area(), 6);
Assert.Equal(square.RotationDirection(), result.RotationDirection());
}
private static bool SegmentsCross(Vector a, Vector b, Vector c, Vector d)
{
static double Cross(Vector o, Vector p, Vector q) =>