2bae5340f0
Verify that filling an L-shaped part produces consistent counts regardless of the orientation it was imported at, and that all placed parts stay within the plate work area. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
85 lines
2.8 KiB
C#
85 lines
2.8 KiB
C#
using OpenNest.CNC;
|
|
using OpenNest.Engine;
|
|
using OpenNest.Engine.BestFit;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Math;
|
|
using System.Threading;
|
|
|
|
namespace OpenNest.Tests.Engine;
|
|
|
|
public class NestInvarianceTests
|
|
{
|
|
private static OpenNest.CNC.Program MakeLShapedProgram()
|
|
{
|
|
// L-shape: 100x50 outer rect with a 50x30 notch removed from top-right.
|
|
var pgm = new OpenNest.CNC.Program();
|
|
pgm.Codes.Add(new RapidMove(new Vector(0, 0)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(100, 0)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(100, 20)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(50, 20)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(50, 50)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(0, 50)));
|
|
pgm.Codes.Add(new LinearMove(new Vector(0, 0)));
|
|
return pgm;
|
|
}
|
|
|
|
private static Drawing MakeImportedAt(double rotation)
|
|
{
|
|
var pgm = MakeLShapedProgram();
|
|
if (!Tolerance.IsEqualTo(rotation, 0))
|
|
pgm.Rotate(rotation, pgm.BoundingBox().Center);
|
|
return new Drawing("L", pgm);
|
|
}
|
|
|
|
private static Plate MakePlate() => new Plate(new Size(500, 500))
|
|
{
|
|
Quadrant = 1,
|
|
PartSpacing = 2,
|
|
};
|
|
|
|
private static int RunFillCount(Drawing drawing, Plate plate)
|
|
{
|
|
BestFitCache.Clear();
|
|
var engine = new DefaultNestEngine(plate);
|
|
var item = new NestItem { Drawing = drawing };
|
|
var parts = engine.Fill(item, plate.WorkArea(), progress: null, token: CancellationToken.None);
|
|
return parts?.Count ?? 0;
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(0.0)]
|
|
[InlineData(0.3)]
|
|
[InlineData(0.8)]
|
|
[InlineData(1.2)]
|
|
public void Fill_SameCount_AcrossImportOrientations(double theta)
|
|
{
|
|
var baseline = RunFillCount(MakeImportedAt(0.0), MakePlate());
|
|
var rotated = RunFillCount(MakeImportedAt(theta), MakePlate());
|
|
|
|
// Allow +/-1 tolerance for sweep quantization edge effects near plate boundaries.
|
|
Assert.InRange(rotated, baseline - 1, baseline + 1);
|
|
}
|
|
|
|
[Fact]
|
|
public void Fill_PlacedPartsStayWithinWorkArea_AcrossImportOrientations()
|
|
{
|
|
var plate = MakePlate();
|
|
var workArea = plate.WorkArea();
|
|
|
|
foreach (var theta in new[] { 0.0, 0.3, 0.8, 1.2 })
|
|
{
|
|
BestFitCache.Clear();
|
|
var engine = new DefaultNestEngine(plate);
|
|
var item = new NestItem { Drawing = MakeImportedAt(theta) };
|
|
var parts = engine.Fill(item, workArea, progress: null, token: CancellationToken.None);
|
|
|
|
Assert.NotNull(parts);
|
|
foreach (var p in parts)
|
|
{
|
|
Assert.InRange(p.BoundingBox.Left, workArea.Left - 0.5, workArea.Right + 0.5);
|
|
Assert.InRange(p.BoundingBox.Bottom, workArea.Bottom - 0.5, workArea.Top + 0.5);
|
|
}
|
|
}
|
|
}
|
|
}
|