Move fill algorithms to OpenNest.Engine.Fill namespace: FillLinear, FillExtents, PairFiller, ShrinkFiller, Compactor, RemnantFiller, RemnantFinder, FillScore, Pattern, PatternTiler, PartBoundary, RotationAnalysis, AngleCandidateBuilder, and AccumulatingProgress. Move strategy layer to OpenNest.Engine.Strategies namespace: IFillStrategy, FillContext, FillStrategyRegistry, FillHelpers, and all built-in strategy implementations. Add using directives to all consuming files across Engine, UI, MCP, and Tests projects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
85 lines
2.9 KiB
C#
85 lines
2.9 KiB
C#
using OpenNest.Engine.Fill;
|
|
using OpenNest.Geometry;
|
|
|
|
namespace OpenNest.Tests;
|
|
|
|
public class AngleCandidateBuilderTests
|
|
{
|
|
private static Drawing MakeRectDrawing(double w, double h)
|
|
{
|
|
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("rect", pgm);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_ReturnsAtLeastTwoAngles()
|
|
{
|
|
var builder = new AngleCandidateBuilder();
|
|
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
|
|
var workArea = new Box(0, 0, 100, 100);
|
|
|
|
var angles = builder.Build(item, 0, workArea);
|
|
|
|
Assert.True(angles.Count >= 2);
|
|
}
|
|
|
|
[Fact]
|
|
public void Build_NarrowWorkArea_ProducesMoreAngles()
|
|
{
|
|
var builder = new AngleCandidateBuilder();
|
|
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
|
|
var wideArea = new Box(0, 0, 100, 100);
|
|
var narrowArea = new Box(0, 0, 100, 8); // narrower than part's longest side
|
|
|
|
var wideAngles = builder.Build(item, 0, wideArea);
|
|
var narrowAngles = builder.Build(item, 0, narrowArea);
|
|
|
|
Assert.True(narrowAngles.Count > wideAngles.Count,
|
|
$"Narrow ({narrowAngles.Count}) should have more angles than wide ({wideAngles.Count})");
|
|
}
|
|
|
|
[Fact]
|
|
public void ForceFullSweep_ProducesFullSweep()
|
|
{
|
|
var builder = new AngleCandidateBuilder { ForceFullSweep = true };
|
|
var item = new NestItem { Drawing = MakeRectDrawing(5, 5) };
|
|
var workArea = new Box(0, 0, 100, 100);
|
|
|
|
var angles = builder.Build(item, 0, workArea);
|
|
|
|
// Full sweep at 5deg steps = ~36 angles (0 to 175), plus base angles
|
|
Assert.True(angles.Count > 10);
|
|
}
|
|
|
|
[Fact]
|
|
public void RecordProductive_PrunesSubsequentBuilds()
|
|
{
|
|
var builder = new AngleCandidateBuilder { ForceFullSweep = true };
|
|
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
|
|
var workArea = new Box(0, 0, 100, 8);
|
|
|
|
// First build — full sweep
|
|
var firstAngles = builder.Build(item, 0, workArea);
|
|
|
|
// Record some as productive
|
|
var productive = new List<AngleResult>
|
|
{
|
|
new AngleResult { AngleDeg = 0, PartCount = 5 },
|
|
new AngleResult { AngleDeg = 45, PartCount = 3 },
|
|
};
|
|
builder.RecordProductive(productive);
|
|
|
|
// Second build — should be pruned to known-good + base angles
|
|
builder.ForceFullSweep = false;
|
|
var secondAngles = builder.Build(item, 0, workArea);
|
|
|
|
Assert.True(secondAngles.Count < firstAngles.Count,
|
|
$"Pruned ({secondAngles.Count}) should be fewer than full ({firstAngles.Count})");
|
|
}
|
|
}
|