Engines had to reverse-engineer the benchmark validator: Opus55 assumed a 0.01 arc tolerance (the validator uses 0.001), Gpt6Astra added hand-tuned paddings and copied the validator's check order, Qwen picked its chord tolerance to stay under a constant it could not reference. NestTolerances publishes the validator's arc tolerance, the Clipper grid and SafeClearanceMargin (with its derivation). NestLayoutCheck moves the benchmark NestValidator's checks into OpenNest.Engine as a public API (Clears for a part pair, Violations for a whole result); NestValidator is now a thin wrapper. Verdicts are unchanged: tests compare ordered violation lists against a frozen copy of the old validator, and a tangent-disc stress test covers 432 pairs at the safe margin. Co-Authored-By: Codex <noreply@openai.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
51 lines
2.2 KiB
C#
51 lines
2.2 KiB
C#
using OpenNest.CNC;
|
|
using OpenNest.Engine.Jobs;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Engine.Tests.Jobs;
|
|
|
|
public class NestLayoutCheckTests
|
|
{
|
|
[Fact]
|
|
public void TangentDiscsClearAtSafeMarginAcrossRadiiAnglesAndTolerances()
|
|
{
|
|
var count = 0;
|
|
foreach (var radius in new[] { 0.1, 1.0, 10.0 })
|
|
foreach (var tolerance in new[] { 0.0, 0.0005, 0.01 })
|
|
foreach (var spacing in new[] { 0.0, 0.25 })
|
|
{
|
|
var program = new Program();
|
|
program.MoveTo(radius, 0);
|
|
program.Codes.Add(new ArcMove(radius, 0, 0, 0, RotationType.CW));
|
|
var geometry = JobPartGeometry.Read(PartGeometrySnapshot.FromProgram(program));
|
|
// Two inscribed engine outlines can underestimate true extent by t each.
|
|
var distance = 2 * radius + spacing
|
|
+ NestTolerances.SafeClearanceMargin(tolerance) - 2 * tolerance;
|
|
for (var degrees = 0; degrees < 360; degrees += 15)
|
|
{
|
|
var angle = degrees * System.Math.PI / 180;
|
|
var a = new NestJobPlacement("disc", 0, 0.12345, -0.54321, angle / 3);
|
|
var b = new NestJobPlacement("disc", 1, a.X + distance * System.Math.Cos(angle),
|
|
a.Y + distance * System.Math.Sin(angle), -angle / 7);
|
|
Assert.True(NestLayoutCheck.Clears(geometry, a, geometry, b, spacing));
|
|
Assert.True(NestLayoutCheck.Clears(geometry, b, geometry, a, spacing));
|
|
count++;
|
|
}
|
|
}
|
|
Assert.Equal(432, count);
|
|
}
|
|
|
|
[Fact]
|
|
public void PairCheckDetectsOverlapAndLeavesGeometryUnchanged()
|
|
{
|
|
var geometry = JobPartGeometry.Read(PartGeometrySnapshot.FromProgram(TestDrawingFactory.Rectangle(4, 3)));
|
|
var bounds = geometry.Bounds;
|
|
Assert.False(NestLayoutCheck.Clears(geometry, new("p", 0, 0, 0, 0),
|
|
geometry, new("p", 1, 2, 0, 0), 0.25));
|
|
Assert.Equal(bounds, geometry.Bounds);
|
|
Assert.Equal(0.0032, NestTolerances.SafeClearanceMargin(0.0005), 12);
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => NestTolerances.SafeClearanceMargin(-1));
|
|
Assert.Throws<ArgumentOutOfRangeException>(() => NestTolerances.SafeClearanceMargin(double.NaN));
|
|
}
|
|
}
|