From d854a1f5d2e2c9c1811caf190a79591d8079978c Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Sat, 28 Mar 2026 15:53:20 -0400 Subject: [PATCH] fix: use arc joins at convex corners in offset geometry Convex corners were being miter-joined (lines extended to a point) because IntersectsUnbounded always finds an intersection for non-parallel lines. Now checks the cross product of original line directions to detect convex corners and inserts an arc instead. Co-Authored-By: Claude Opus 4.6 (1M context) --- OpenNest.Core/Geometry/Shape.cs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/OpenNest.Core/Geometry/Shape.cs b/OpenNest.Core/Geometry/Shape.cs index 52190c8..7a8aea4 100644 --- a/OpenNest.Core/Geometry/Shape.cs +++ b/OpenNest.Core/Geometry/Shape.cs @@ -532,9 +532,29 @@ namespace OpenNest.Geometry Line line, Line offsetLine, double distance, OffsetSide side, Shape offsetShape) { - Vector intersection; + // Determine if this is a convex corner using the cross product of + // the original line directions. Convex corners need an arc; concave + // corners use the line intersection (miter join). + var d1 = lastLine.EndPoint - lastLine.StartPoint; + var d2 = line.EndPoint - line.StartPoint; + var cross = d1.X * d2.Y - d1.Y * d2.X; - if (Intersect.IntersectsUnbounded(offsetLine, lastOffsetLine, out intersection)) + var isConvex = (side == OffsetSide.Left && cross < -OpenNest.Math.Tolerance.Epsilon) || + (side == OffsetSide.Right && cross > OpenNest.Math.Tolerance.Epsilon); + + if (isConvex) + { + var arc = new Arc( + line.StartPoint, + distance, + line.StartPoint.AngleTo(lastOffsetLine.EndPoint), + line.StartPoint.AngleTo(offsetLine.StartPoint), + side == OffsetSide.Left + ); + + offsetShape.Entities.Add(arc); + } + else if (Intersect.IntersectsUnbounded(offsetLine, lastOffsetLine, out var intersection)) { offsetLine.StartPoint = intersection; lastOffsetLine.EndPoint = intersection;