From d0d334e734c2506886a2774426ddaf7e0922d209 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Thu, 12 Mar 2026 08:37:39 -0400 Subject: [PATCH] fix: use chain tolerance for shape building to handle DXF endpoint gaps DXF files can have endpoint gaps at entity junctions that fall right at the floating-point boundary of Tolerance.Epsilon (0.00001). This caused shapes to not close, resulting in 0 area and 0% utilization in Best-Fit. Added ChainTolerance (0.0001) for endpoint chaining in GetConnected and Shape.IsClosed, keeping the tighter Epsilon for geometric precision. Co-Authored-By: Claude Opus 4.6 --- OpenNest.Core/Geometry/Shape.cs | 7 ++++--- OpenNest.Core/Helper.cs | 10 ++++++---- OpenNest.Core/Math/Tolerance.cs | 6 ++++++ 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/OpenNest.Core/Geometry/Shape.cs b/OpenNest.Core/Geometry/Shape.cs index 33fb910..0654626 100644 --- a/OpenNest.Core/Geometry/Shape.cs +++ b/OpenNest.Core/Geometry/Shape.cs @@ -26,6 +26,7 @@ namespace OpenNest.Geometry if (Entities.Count == 0) return false; + var tol = Math.Tolerance.ChainTolerance; var first = Entities[0]; Vector firstStartPoint; Vector firstEndPoint; @@ -65,7 +66,7 @@ namespace OpenNest.Geometry case EntityType.Arc: var arc = (Arc)geo; - if (arc.StartPoint() != endpt) + if (arc.StartPoint().DistanceTo(endpt) > tol) return false; endpt = arc.EndPoint(); @@ -77,7 +78,7 @@ namespace OpenNest.Geometry case EntityType.Line: var line = (Line)geo; - if (line.StartPoint != endpt) + if (line.StartPoint.DistanceTo(endpt) > tol) return false; endpt = line.EndPoint; @@ -112,7 +113,7 @@ namespace OpenNest.Geometry return false; } - return lastEndPoint == firstStartPoint; + return lastEndPoint.DistanceTo(firstStartPoint) <= tol; } /// diff --git a/OpenNest.Core/Helper.cs b/OpenNest.Core/Helper.cs index 190b8f8..5f0da8d 100644 --- a/OpenNest.Core/Helper.cs +++ b/OpenNest.Core/Helper.cs @@ -339,6 +339,8 @@ namespace OpenNest internal static Entity GetConnected(Vector pt, IEnumerable geometry) { + var tol = Math.Tolerance.ChainTolerance; + foreach (var geo in geometry) { switch (geo.Type) @@ -346,10 +348,10 @@ namespace OpenNest case EntityType.Arc: var arc = (Arc)geo; - if (arc.StartPoint() == pt) + if (arc.StartPoint().DistanceTo(pt) <= tol) return arc; - if (arc.EndPoint() == pt) + if (arc.EndPoint().DistanceTo(pt) <= tol) { arc.Reverse(); return arc; @@ -360,10 +362,10 @@ namespace OpenNest case EntityType.Line: var line = (Line)geo; - if (line.StartPoint == pt) + if (line.StartPoint.DistanceTo(pt) <= tol) return line; - if (line.EndPoint == pt) + if (line.EndPoint.DistanceTo(pt) <= tol) { line.Reverse(); return line; diff --git a/OpenNest.Core/Math/Tolerance.cs b/OpenNest.Core/Math/Tolerance.cs index eeb12b8..105b529 100644 --- a/OpenNest.Core/Math/Tolerance.cs +++ b/OpenNest.Core/Math/Tolerance.cs @@ -6,6 +6,12 @@ namespace OpenNest.Math { public const double Epsilon = 0.00001; + /// + /// Tolerance for chaining entity endpoints when building shapes from DXF imports. + /// Larger than Epsilon to handle floating-point gaps at entity junctions. + /// + public const double ChainTolerance = 0.0001; + public static bool IsEqualTo(this double a, double b, double tolerance = Epsilon) { return System.Math.Abs(b - a) <= tolerance;