From 0b322817d79309a7eeb766ab1d2b740dc76d07b2 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Thu, 23 Apr 2026 21:32:08 -0400 Subject: [PATCH] fix(core): use chain tolerance for entity gap check to prevent spurious rapids Ellipse-to-arc conversion creates tiny floating-point gaps (~0.00002") between consecutive arc segments. ShapeBuilder chains these with ChainTolerance (0.0001"), but ConvertGeometry checked gaps with Epsilon (0.00001"). Gaps between these thresholds generated spurious rapid moves that broke GraphicsPath figures, causing diagonal fill artifacts from GDI+'s implicit figure closing. Root cause fix: align ConvertGeometry's gap check with ShapeBuilder's ChainTolerance so precision gaps are absorbed instead of generating rapids. Defense-in-depth: GraphicsHelper no longer breaks figures at near-zero rapids, protecting against any programs with residual tiny rapids. Co-Authored-By: Claude Opus 4.6 --- OpenNest.Core/Converters/ConvertGeometry.cs | 6 ++--- OpenNest/GraphicsHelper.cs | 30 +++++++++++++++++---- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/OpenNest.Core/Converters/ConvertGeometry.cs b/OpenNest.Core/Converters/ConvertGeometry.cs index 728c2ae..ed709ce 100644 --- a/OpenNest.Core/Converters/ConvertGeometry.cs +++ b/OpenNest.Core/Converters/ConvertGeometry.cs @@ -82,7 +82,7 @@ namespace OpenNest.Converters var startpt = arc.StartPoint(); var endpt = arc.EndPoint(); - if (startpt != lastpt) + if (startpt.DistanceTo(lastpt) > Tolerance.ChainTolerance) pgm.MoveTo(startpt); lastpt = endpt; @@ -104,7 +104,7 @@ namespace OpenNest.Converters { var startpt = new Vector(circle.Center.X + circle.Radius, circle.Center.Y); - if (startpt != lastpt) + if (startpt.DistanceTo(lastpt) > Tolerance.ChainTolerance) pgm.MoveTo(startpt); pgm.ArcTo(startpt, circle.Center, circle.Rotation); @@ -115,7 +115,7 @@ namespace OpenNest.Converters private static Vector AddLine(Program pgm, Vector lastpt, Line line) { - if (line.StartPoint != lastpt) + if (line.StartPoint.DistanceTo(lastpt) > Tolerance.ChainTolerance) pgm.MoveTo(line.StartPoint); var move = new LinearMove(line.EndPoint); diff --git a/OpenNest/GraphicsHelper.cs b/OpenNest/GraphicsHelper.cs index 55ba34a..51dc8e8 100644 --- a/OpenNest/GraphicsHelper.cs +++ b/OpenNest/GraphicsHelper.cs @@ -138,9 +138,20 @@ namespace OpenNest break; case CodeType.RapidMove: - cutPath.StartFigure(); - leadPath.StartFigure(); - AddLine(cutPath, (RapidMove)code, mode, ref curpos); + { + var rapid = (RapidMove)code; + var endpt = rapid.EndPoint; + if (mode == Mode.Incremental) + endpt += curpos; + var dx = endpt.X - curpos.X; + var dy = endpt.Y - curpos.Y; + if (dx * dx + dy * dy > 0.001 * 0.001) + { + cutPath.StartFigure(); + leadPath.StartFigure(); + } + curpos = endpt; + } break; case CodeType.SubProgramCall: @@ -300,8 +311,17 @@ namespace OpenNest break; case CodeType.RapidMove: - Flush(); - AddLine(path, (RapidMove)code, mode, ref curpos); + { + var rapid = (RapidMove)code; + var endpt = rapid.EndPoint; + if (mode == Mode.Incremental) + endpt += curpos; + var dx = endpt.X - curpos.X; + var dy = endpt.Y - curpos.Y; + if (dx * dx + dy * dy > 0.001 * 0.001) + Flush(); + curpos = endpt; + } break; case CodeType.SubProgramCall: