diff --git a/OpenNest.Core/Geometry/SlideContact.cs b/OpenNest.Core/Geometry/SlideContact.cs index e24410f0..89be8eb6 100644 --- a/OpenNest.Core/Geometry/SlideContact.cs +++ b/OpenNest.Core/Geometry/SlideContact.cs @@ -36,6 +36,11 @@ namespace OpenNest.Geometry // tangential classification can admit, so keep it far below spacing tolerances. internal const double IncidenceTolerance = 1e-7; + // Drawing data fixes arc centers to finite precision, so a tangent joint's arc end + // can sit a little past its neighbour's end. A contact this close to a joint takes + // the joint's tangents; otherwise the neighbour reads as a second boundary there. + internal const double JointTolerance = 1e-6; + private readonly List entities; private readonly int[] loopOf; private readonly int[] previous; @@ -254,11 +259,11 @@ namespace OpenNest.Geometry private bool StartsNear(int index, Vector point) => TryEndpoints(entities[index], out var start, out _) - && start.DistanceTo(point) <= IncidenceTolerance; + && start.DistanceTo(point) <= JointTolerance; private bool EndsNear(int index, Vector point) => TryEndpoints(entities[index], out _, out var end) - && end.DistanceTo(point) <= IncidenceTolerance; + && end.DistanceTo(point) <= JointTolerance; private bool InRun(int index, int first, int last) { diff --git a/OpenNest.Tests/Geometry/SlideContactTests.cs b/OpenNest.Tests/Geometry/SlideContactTests.cs index 4206556b..6e851bbc 100644 --- a/OpenNest.Tests/Geometry/SlideContactTests.cs +++ b/OpenNest.Tests/Geometry/SlideContactTests.cs @@ -147,6 +147,28 @@ public class SlideContactTests Assert.Equal(double.MaxValue, EntityDistance(cpu, moving, stationary, new Vector(1, 0))); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FilletWithImpreciseCenter_DoesNotBlockSlidingAlongItsTangentLine(bool cpu) + { + // N26-243: the G-code fixes the fillet center 1.04e-7 off the tangent normal, so + // the arc's top lies just past the flat edge's end rather than on the joint. + var offset = 1.043e-7; + var fillet = new Arc(new Vector(2 - offset, 0.5), System.Math.Sqrt(1 + offset * offset), + 0, System.Math.Atan2(1, offset), false); + var stationary = new List + { + new Line(0, 0, 3, 0), + new Line(new Vector(3, 0), fillet.StartPoint()), + fillet, + new Line(fillet.EndPoint(), new Vector(0, 1.5)), + new Line(0, 1.5, 0, 0), + }; + var moving = Rect(1, 1.5, 2, 1).Cast().ToList(); + Assert.Equal(double.MaxValue, EntityDistance(cpu, moving, stationary, new Vector(-1, 0))); + } + [Theory] [InlineData(false)] [InlineData(true)]