Files
OpenNest/OpenNest.Tests/Engine/RemnantEngineTests.cs
T
ajandClaude Opus 5.5 5761eefd37 refactor(engine): merge the plate fillers into one PlateFiller
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>
2026-10-25 23:44:51 -04:00

116 lines
3.9 KiB
C#

using OpenNest.Engine;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Jobs.Placement;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
namespace OpenNest.Tests.Engine;
public class RemnantEngineTests
{
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 VerticalRemnantPlateFiller_UsesHorizontalPreferredDirection()
{
var plate = new Plate(60, 120);
var filler = new PlateFiller(plate, PlateFillPolicy.VerticalRemnant);
Assert.Equal(NestDirection.Horizontal, filler.PreferredDirection);
}
[Fact]
public void HorizontalRemnantPlateFiller_UsesVerticalPreferredDirection()
{
var plate = new Plate(60, 120);
var filler = new PlateFiller(plate, PlateFillPolicy.HorizontalRemnant);
Assert.Equal(NestDirection.Vertical, filler.PreferredDirection);
}
[Fact]
public void VerticalRemnantPlateFiller_Fill_ProducesResults()
{
var plate = new Plate(60, 120);
var filler = new PlateFiller(plate, PlateFillPolicy.VerticalRemnant);
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, "VerticalRemnantPlateFiller should fill parts");
}
[Fact]
public void HorizontalRemnantPlateFiller_Fill_ProducesResults()
{
var plate = new Plate(60, 120);
var filler = new PlateFiller(plate, PlateFillPolicy.HorizontalRemnant);
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, "HorizontalRemnantPlateFiller should fill parts");
}
[Fact]
public void PlateFillService_ListsBothRemnantStrategies()
{
Assert.Contains("Vertical Remnant", PlateFillService.BuiltInStrategies);
Assert.Contains("Horizontal Remnant", PlateFillService.BuiltInStrategies);
}
[Fact]
public void VerticalRemnantPlateFiller_ProducesTighterXExtent_ThanDefault()
{
var plate = new Plate(60, 120);
var drawing = MakeRectDrawing(20, 10);
var item = new NestItem { Drawing = drawing };
var defaultFiller = new PlateFiller(plate);
var remnantFiller = new PlateFiller(plate, PlateFillPolicy.VerticalRemnant);
var defaultParts = defaultFiller.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
var remnantParts = remnantFiller.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
Assert.True(defaultParts.Count > 0);
Assert.True(remnantParts.Count > 0);
var defaultXExtent =
defaultParts.Max(p => p.BoundingBox.Right) - defaultParts.Min(p => p.BoundingBox.Left);
var remnantXExtent =
remnantParts.Max(p => p.BoundingBox.Right) - remnantParts.Min(p => p.BoundingBox.Left);
Assert.True(
remnantXExtent <= defaultXExtent + 0.01,
$"Remnant X-extent ({remnantXExtent:F1}) should be <= default filler ({defaultXExtent:F1})"
);
}
}