Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests pass after reformat, full solution builds 0 errors. Added .csharpierignore so csproj/config XML keeps its existing layout (CSharpier's XML wrapping churns attributes with zero benefit). Formatting is now enforceable: dotnet csharpier check . passes.
87 lines
2.8 KiB
C#
87 lines
2.8 KiB
C#
using System.Threading;
|
|
using OpenNest.CNC;
|
|
using OpenNest.Engine;
|
|
using OpenNest.Engine.BestFit;
|
|
using OpenNest.Geometry;
|
|
using OpenNest.Math;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|