From ba55d5bff09cde1ac3b311aa806eacc87eeb012d Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sat, 24 Oct 2026 21:24:57 -0400 Subject: [PATCH] revert: drop the duplicate near-vertex hole-cut fix Master already starts such entries exactly at the vertex (45592a81), so the cherry-picked snap was redundant and its test's off-vertex precondition no longer holds. Co-Authored-By: Claude Opus 5.5 --- .../CuttingStrategy/ContourCuttingStrategy.cs | 17 ------- .../CuttingPlanning/NearVertexEntryTests.cs | 50 ------------------- 2 files changed, 67 deletions(-) delete mode 100644 OpenNest.Tests/CuttingPlanning/NearVertexEntryTests.cs diff --git a/OpenNest.Core/CNC/CuttingStrategy/ContourCuttingStrategy.cs b/OpenNest.Core/CNC/CuttingStrategy/ContourCuttingStrategy.cs index 35757329..17eb2e31 100644 --- a/OpenNest.Core/CNC/CuttingStrategy/ContourCuttingStrategy.cs +++ b/OpenNest.Core/CNC/CuttingStrategy/ContourCuttingStrategy.cs @@ -433,22 +433,6 @@ namespace OpenNest.CNC.CuttingStrategy private static bool SameVector(Vector a, Vector b) => SameBits(a.X, b.X) && SameBits(a.Y, b.Y); private static bool SameBits(double a, double b) => BitConverter.DoubleToInt64Bits(a) == BitConverter.DoubleToInt64Bits(b); - // ReindexAt starts the contour at the vertex when the entry is within Tolerance.Epsilon of it - // (Line/Arc.SplitAt keep the entity whole), so the lead-in must end there too; otherwise the - // cut closes at the vertex, short of the entry by that sliver. - private static Vector SnapToSplitVertex(Vector point, Entity entity) - { - var (start, end) = entity switch - { - Line line => (line.StartPoint, line.EndPoint), - Arc arc => (arc.StartPoint(), arc.EndPoint()), - _ => (point, point), - }; - if (point.DistanceTo(start) < Tolerance.Epsilon) - return start; - return point.DistanceTo(end) < Tolerance.Epsilon ? end : point; - } - private void EmitContour( Program program, Shape shape, @@ -459,7 +443,6 @@ namespace OpenNest.CNC.CuttingStrategy Vector? scrapPierce = null ) { - point = SnapToSplitVertex(point, entity); var contourType = forceType ?? DetectContourType(shape); var winding = DetermineWinding(shape); var normal = ComputeNormal(point, entity, contourType, winding); diff --git a/OpenNest.Tests/CuttingPlanning/NearVertexEntryTests.cs b/OpenNest.Tests/CuttingPlanning/NearVertexEntryTests.cs deleted file mode 100644 index 760b41c3..00000000 --- a/OpenNest.Tests/CuttingPlanning/NearVertexEntryTests.cs +++ /dev/null @@ -1,50 +0,0 @@ -using OpenNest.CNC; -using OpenNest.CNC.CuttingPlanning; -using OpenNest.Geometry; - -namespace OpenNest.Tests.CuttingPlanning; - -/// -/// A closest-point entry can land a hair off an entity's vertex. Emission starts the contour -/// at that vertex (the split keeps the entity whole), so the lead-in must end there too, or -/// the cut closes short of where it started and replay refuses the whole plate. -/// -public class NearVertexEntryTests -{ - private static readonly Vector Center = new(5, 5); - private const double Radius = 0.3125; - - // A hole drawn as two half arcs meeting at its top and bottom, inside a square perimeter. - private static Program HalfArcHole() - { - var p = ExplicitContourTests.Square(false); - p.MoveTo(Center.X, Center.Y + Radius); - p.ArcTo(Center.X, Center.Y - Radius, Center.X, Center.Y, RotationType.CCW); - p.ArcTo(Center.X, Center.Y + Radius, Center.X, Center.Y, RotationType.CCW); - return p; - } - - [Theory] - [InlineData(4.1e-6)] // just before the top vertex, at the end of the second arc - [InlineData(-4.1e-6)] // just after it, at the start of the first arc - public void HoleCutClosesWhereItsLeadInEnds(double angleFromTop) - { - var prepared = PreparedContours.Capture(HalfArcHole(), ExplicitContourTests.Parameters()); - var hole = Enumerable.Range(0, prepared.Count).Single(c => c != prepared.PerimeterOrdinal); - var approach = Center + new Vector(System.Math.Sin(angleFromTop), System.Math.Cos(angleFromTop)) * 10; - var entry = prepared.ClosestEntry(hole, approach); - var top = new Vector(Center.X, Center.Y + Radius); - Assert.InRange(entry.Point.DistanceTo(top), 1e-6, 1e-5); - - var program = prepared.Emit(new[] { entry, prepared.ClosestEntry(prepared.PerimeterOrdinal, new Vector(0, 0)) }); - program.Mode = Mode.Absolute; - var holeMotions = program.Codes.OfType().SkipWhile(m => m is RapidMove) - .TakeWhile(m => m is not RapidMove).ToArray(); - - // Line lead-in, then the two half arcs back to the lead-in's end. - Assert.Equal(3, holeMotions.Length); - Assert.True(holeMotions[^1].EndPoint.DistanceTo(holeMotions[0].EndPoint) <= 1e-9, - $"cut ends {holeMotions[^1].EndPoint.DistanceTo(holeMotions[0].EndPoint)} from its start"); - Assert.True(holeMotions[0].EndPoint.DistanceTo(top) <= 1e-9); - } -}