mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-05 13:32:13 -04:00
fix(cutting): refuse uncertain native circular contacts
This commit is contained in:
1 parent
085edeea3b
commit
d1109aaa43
2 files changed
+84
No files matched your search
@@ -105,6 +105,20 @@ internal static class PostVerificationGeometry
|
||||
{
|
||||
var entity = ToEntity();
|
||||
var candidate = other.ToEntity();
|
||||
// Native arc filters discard NaN supporting-circle intersections. Inspect
|
||||
// both unfiltered queries first: roundoff can differ by operand direction.
|
||||
// Coincident supports have separate overlap handling below.
|
||||
if (Center is { } center && other.Center is { } otherCenter && !SameSupport(other))
|
||||
{
|
||||
var support = new Circle(center, Radius);
|
||||
var otherSupport = new Circle(otherCenter, other.Radius);
|
||||
support.Intersects(otherSupport, out var forward);
|
||||
otherSupport.Intersects(support, out var reverse);
|
||||
foreach (var point in forward)
|
||||
Validate(point);
|
||||
foreach (var point in reverse)
|
||||
Validate(point);
|
||||
}
|
||||
List<Vector> points;
|
||||
bool intersects;
|
||||
switch (candidate)
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.CNC.CuttingPlanning;
|
||||
using OpenNest.Diagnostics;
|
||||
using OpenNest.Geometry;
|
||||
|
||||
namespace OpenNest.Tests.CuttingPlanning;
|
||||
|
||||
public class NativeContactRegressionTests
|
||||
{
|
||||
[Fact]
|
||||
public void TangentArcLead_RefusesFilteredSupportingCircleNaNs()
|
||||
{
|
||||
var target = LeadMaterialSnapshot.Capture(LeadPathValidationTests.Rectangle(0, -1, 1, 1), Vector.Zero);
|
||||
var obstacle = new Program();
|
||||
obstacle.MoveTo(-0.22, 0.26);
|
||||
obstacle.ArcTo(-0.22, 0.26, -0.22, 0.16, RotationType.CCW);
|
||||
var material = LeadMaterialSnapshot.Capture(obstacle, Vector.Zero);
|
||||
Assert.True(target.IsComplete, target.Reason);
|
||||
Assert.True(material.IsComplete, material.Reason);
|
||||
var lead = new Program();
|
||||
lead.MoveTo(-0.2, 0);
|
||||
lead.Codes.Add(new ArcMove(Vector.Zero, new Vector(-0.1, 0), RotationType.CW) { Layer = LayerType.Leadin });
|
||||
lead.LineTo(0, 1);
|
||||
var execution = ExecutionMotionReader.Read(lead, Vector.Zero, null, default);
|
||||
var witness = new Vector(-0.16, 0.08);
|
||||
Assert.True(execution.Motions[1].Curve.Contains(witness));
|
||||
Assert.True(material.Rings[0][0].Contains(witness));
|
||||
var result = LeadPathValidator.Check(execution, target, [material]);
|
||||
Assert.False(result.IsComplete);
|
||||
Assert.False(result.IsClear);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(0.1, -0.22, 0.16)]
|
||||
[InlineData(0.2, -0.28, 0.24)]
|
||||
[InlineData(0.05, -0.19, 0.12)]
|
||||
public void CircularNearTangency_BothDirectionsNeverCertifyNoContact(double radius, double x, double y)
|
||||
{
|
||||
var a = PostVerificationGeometry.Curve.Create(new Vector(-0.2, 0), Vector.Zero, new Vector(-0.1, 0), true);
|
||||
var center = new Vector(x, y);
|
||||
var b = PostVerificationGeometry.Curve.Create(center + new Vector(0, radius), center + new Vector(0, -radius), center, true);
|
||||
foreach (var reverse in new[] { false, true })
|
||||
{
|
||||
try
|
||||
{
|
||||
var contacts = (reverse ? b : a).Contacts(reverse ? a : b, out var overlap);
|
||||
Assert.True(overlap || contacts.Count > 0, "Near-tangent circular query silently certified no contact.");
|
||||
}
|
||||
catch (Exception ex) when (ex is ArgumentException or NotSupportedException)
|
||||
{
|
||||
// Numerical uncertainty is a refusal, never a disjoint certificate.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TouchingArcSplitHoles_RefuseMaterialCertificate()
|
||||
{
|
||||
var source = LeadPathValidationTests.Rectangle(-1, -1, 1, 1);
|
||||
foreach (var center in new[] { new Vector(-0.1, 0), new Vector(-0.22, 0.16) })
|
||||
{
|
||||
source.MoveTo(center.X, center.Y + 0.1);
|
||||
source.ArcTo(center.X, center.Y - 0.1, center.X, center.Y, RotationType.CCW);
|
||||
source.ArcTo(center.X, center.Y + 0.1, center.X, center.Y, RotationType.CCW);
|
||||
}
|
||||
var snapshot = LeadMaterialSnapshot.Capture(source, Vector.Zero);
|
||||
Assert.False(snapshot.IsComplete);
|
||||
Assert.NotNull(snapshot.Reason);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user