mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-28 11:31:08 -04:00
DefaultPlateFiller becomes PlateFiller(plate, policy, layout); PlateFillerBase and StripPlateFiller are gone. PlateLayout.FillThenPack is the old orchestrator path (Fill and both Remnants); PlateLayout.Strips is the old StripPlateFiller.Nest, and Strip is Fill policy plus Strips layout. Lifetimes are unchanged: a strip-layout filler runs every Fill, group Fill and PackArea on a fresh inner filler and gives each strip fresh remnant fillers, so learned angles and PlateNumber never leak into them. The comparer, preferred direction, trim axis and angle recording now read the policy directly. The base class's unsorted two-angle BuildAngles is dropped: only DefaultPlateFiller's pipeline called BuildAngles, and Strip never ran it. Layout-neutral: all 29 FillStackCharacterizationTests pins pass unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
144 lines
4.8 KiB
C#
144 lines
4.8 KiB
C#
using OpenNest.Engine;
|
|
using OpenNest.Engine.Jobs.Placement.Fillers;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Tests.Engine;
|
|
|
|
public class EngineRefactorSmokeTests
|
|
{
|
|
private static Drawing MakeRectDrawing(double w, double h, string name = "rect")
|
|
{
|
|
var pgm = new OpenNest.CNC.Program();
|
|
pgm.Codes.Add(new OpenNest.CNC.RapidMove(new Vector(0, 0)));
|
|
pgm.Codes.Add(new OpenNest.CNC.LinearMove(new Vector(w, 0)));
|
|
pgm.Codes.Add(new OpenNest.CNC.LinearMove(new Vector(w, h)));
|
|
pgm.Codes.Add(new OpenNest.CNC.LinearMove(new Vector(0, h)));
|
|
pgm.Codes.Add(new OpenNest.CNC.LinearMove(new Vector(0, 0)));
|
|
return new Drawing(name, pgm);
|
|
}
|
|
|
|
[Fact]
|
|
public void PlateFiller_FillNestItem_ProducesResults()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var filler = new PlateFiller(plate);
|
|
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
|
|
|
|
var parts = filler.Fill(
|
|
item,
|
|
plate.WorkArea(),
|
|
null,
|
|
System.Threading.CancellationToken.None
|
|
);
|
|
|
|
Assert.True(parts.Count > 0, "PlateFiller should fill parts");
|
|
}
|
|
|
|
[Fact]
|
|
public void PlateFiller_FillGroupParts_ProducesResults()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var filler = new PlateFiller(plate);
|
|
var drawing = MakeRectDrawing(20, 10);
|
|
var groupParts = new List<Part> { new Part(drawing) };
|
|
|
|
var parts = filler.Fill(
|
|
groupParts,
|
|
plate.WorkArea(),
|
|
null,
|
|
System.Threading.CancellationToken.None
|
|
);
|
|
|
|
Assert.True(parts.Count > 0, "PlateFiller group fill should produce parts");
|
|
}
|
|
|
|
[Fact]
|
|
public void PlateFiller_ForceFullAngleSweep_StillWorks()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var filler = new PlateFiller(plate);
|
|
filler.ForceFullAngleSweep = true;
|
|
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
|
|
|
|
var parts = filler.Fill(
|
|
item,
|
|
plate.WorkArea(),
|
|
null,
|
|
System.Threading.CancellationToken.None
|
|
);
|
|
|
|
Assert.True(parts.Count > 0, "ForceFullAngleSweep should still produce results");
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(false)]
|
|
[InlineData(true)]
|
|
public void PlateFiller_StopAtQuantity_StillDeliversExactlyTheQuantity(bool stopAtQuantity)
|
|
{
|
|
var plate = new Plate(60, 120) { PartSpacing = 0.5 };
|
|
var filler = new PlateFiller(plate) { StopAtQuantity = stopAtQuantity };
|
|
var item = new NestItem { Drawing = MakeRectDrawing(7, 3), Quantity = 23 };
|
|
|
|
var parts = filler.Fill(item, plate.WorkArea(), null, System.Threading.CancellationToken.None);
|
|
|
|
Assert.Equal(23, parts.Count);
|
|
plate.Parts.AddRange(parts);
|
|
Assert.False(plate.HasOverlappingParts(out _), "Fill overlaps");
|
|
var area = plate.WorkArea();
|
|
Assert.All(parts, p => Assert.True(
|
|
p.BoundingBox.Left >= area.Left - 1e-6 && p.BoundingBox.Right <= area.Right + 1e-6
|
|
&& p.BoundingBox.Bottom >= area.Bottom - 1e-6 && p.BoundingBox.Top <= area.Top + 1e-6,
|
|
"Part outside the work area"));
|
|
}
|
|
|
|
[Fact]
|
|
public void StripLayout_Nest_ProducesResults()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var filler = new PlateFiller(plate, PlateFillPolicy.Fill, PlateLayout.Strips);
|
|
var items = new List<NestItem>
|
|
{
|
|
new NestItem { Drawing = MakeRectDrawing(20, 10, "large"), Quantity = 10 },
|
|
new NestItem { Drawing = MakeRectDrawing(8, 5, "small"), Quantity = 5 },
|
|
};
|
|
|
|
var parts = filler.Nest(items, null, System.Threading.CancellationToken.None);
|
|
|
|
Assert.True(parts.Count > 0, "Strip layout should nest parts");
|
|
}
|
|
|
|
[Fact]
|
|
public void PlateFiller_Nest_ProducesResults()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var filler = new PlateFiller(plate);
|
|
var items = new List<NestItem>
|
|
{
|
|
new NestItem { Drawing = MakeRectDrawing(20, 10, "a"), Quantity = 5 },
|
|
new NestItem { Drawing = MakeRectDrawing(15, 8, "b"), Quantity = 3 },
|
|
};
|
|
|
|
var parts = filler.Nest(items, null, System.Threading.CancellationToken.None);
|
|
|
|
Assert.True(parts.Count > 0, "Base Nest method should place parts");
|
|
}
|
|
|
|
[Fact]
|
|
public void BruteForceRunner_StillWorks()
|
|
{
|
|
var plate = new Plate(60, 120);
|
|
var drawing = MakeRectDrawing(20, 10);
|
|
|
|
var result = OpenNest.Engine.ML.BruteForceRunner.Run(
|
|
drawing,
|
|
plate,
|
|
forceFullAngleSweep: true
|
|
);
|
|
|
|
Assert.NotNull(result);
|
|
Assert.True(result.PartCount > 0);
|
|
Assert.False(string.IsNullOrWhiteSpace(result.WinnerEngine));
|
|
Assert.NotEmpty(result.AngleResults);
|
|
}
|
|
}
|