fix(reporting): fill parts whose arc ends carry post roundoff

The nest report joined contour segments only within 1e-12, but converted
arcs rebuild their end from the start radius and end angle. Rounded or
incremental programs (end radius a few 1e-7 off the start radius, which
the report's own validator accepts up to Tolerance.Epsilon) left every
arc a hair short of the next move, so outlines split into open pieces
and N26-27K's parts printed unshaded as if they had tab gaps.

Join within Tolerance.Epsilon instead, still far below ShapeBuilder's
welding tolerance and real tab gaps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ajandClaude Opus 5.5 committed 2026-11-04 03:09:15 -05:00
1 parent be5fef6875
commit 032854895d
2 files changed
+28 -3

No files matched your search

+7 -3
View File
@@ -165,10 +165,14 @@ internal static class NestReportGeometry
throw Error(context, "nonfinite geometry coordinate.");
}
// Only absorb floating-point trig roundoff, never ShapeBuilder's welding tolerance.
// A deliberate tab/rapid interruption is never joined by contour construction.
// Converted arcs rebuild their end from center, start radius and end angle, so a program
// arc whose end radius differs from its start radius (rounded or incremental posts; the
// validator accepts up to Tolerance.Epsilon) misses the next move's exact start by that
// much. Absorb only that, never ShapeBuilder's larger welding tolerance: a deliberate
// tab/rapid interruption is never joined by contour construction.
private static bool SamePoint(ReportPoint first, ReportPoint second) =>
System.Math.Abs(first.X - second.X) <= 1e-12 && System.Math.Abs(first.Y - second.Y) <= 1e-12;
System.Math.Abs(first.X - second.X) <= Tolerance.Epsilon
&& System.Math.Abs(first.Y - second.Y) <= Tolerance.Epsilon;
private static InvalidOperationException Error(string context, string message) => new($"{context}: {message}");
}
@@ -79,6 +79,27 @@ public class NestReportGeometryTests
Assert.True(geometry.StrokeOnly);
}
[Fact]
public void Capture_ClosesOutlineWhoseArcEndpointIsRebuiltWithRoundoff()
{
// Posted/rounded programs carry arcs whose end radius differs slightly from the start
// radius; the converted arc's rebuilt end then misses the next move's start by that much.
var nest = NestReportTestData.CreateNest();
var codes = nest.Plates[0].Parts[0].Program.Codes;
codes.Clear();
codes.Add(new RapidMove(0, 0));
codes.Add(new LinearMove(10, 0));
codes.Add(new ArcMove(new Vector(12.000004, 2), new Vector(10, 2), RotationType.CCW));
codes.Add(new LinearMove(12.000004, 10));
codes.Add(new LinearMove(0, 10));
codes.Add(new LinearMove(0, 0));
var geometry = NestReportBuilder.Capture(nest, NestReportTestData.GeneratedAt).Plates[0].Parts[0].Geometry;
var contour = Assert.Single(geometry.Contours);
Assert.True(contour.Closed);
Assert.Equal(5, contour.Segments.Length);
Assert.False(geometry.StrokeOnly);
}
[Fact]
public void Capture_ExcludedLayersCannotConnectSeparateMaterialPaths()
{