refactor(engine): remove legacy nesting engine surface

This commit is contained in:
aj
2026-09-22 14:25:46 -04:00
parent 98c4929d14
commit e65f849c7a
30 changed files with 184 additions and 1119 deletions
+13 -14
View File
@@ -3,6 +3,7 @@ using OpenNest.Geometry;
using OpenNest.IO;
using Xunit.Abstractions;
using OpenNest.Engine;
using OpenNest.Engine.Jobs.Placement;
namespace OpenNest.Tests.Engine;
@@ -31,7 +32,7 @@ public class EngineOverlapTests
[InlineData("Strip")]
[InlineData("Vertical Remnant")]
[InlineData("Horizontal Remnant")]
public void FillPlate_NoOverlaps(string engineName)
public void FillPlate_NoOverlaps(string strategy)
{
var drawing = ImportDxf();
if (drawing is null)
@@ -39,23 +40,21 @@ public class EngineOverlapTests
var plate = new Plate(60, 120);
NestEngineRegistry.ActiveEngineName = engineName;
var engine = NestEngineRegistry.Create(plate);
var item = new NestItem { Drawing = drawing };
var success = engine.Fill(item);
var parts = PlateFillService.FillItem(
strategy,
plate,
item,
plate.WorkArea(),
progress: null,
token: CancellationToken.None
);
plate.Parts.AddRange(parts);
_output.WriteLine(
$"Engine: {engine.Name}, Parts: {plate.Parts.Count}, Utilization: {plate.Utilization():P1}"
$"Strategy: {strategy}, Parts: {plate.Parts.Count}, Utilization: {plate.Utilization():P1}"
);
if (engine is DefaultNestEngine defaultEngine)
{
_output.WriteLine($"Winner phase: {defaultEngine.WinnerPhase}");
foreach (var pr in defaultEngine.PhaseResults)
_output.WriteLine($" Phase {pr.Phase}: {pr.PartCount} parts in {pr.TimeMs}ms");
}
// Show rotation distribution
var rotGroups = plate
.Parts.GroupBy(p => System.Math.Round(OpenNest.Math.Angle.ToDegrees(p.Rotation), 1))
@@ -74,7 +73,7 @@ public class EngineOverlapTests
Assert.False(
hasOverlaps,
$"Engine '{engineName}' produced {collisionPoints.Count} collision point(s) with {plate.Parts.Count} parts"
$"Strategy '{strategy}' produced {collisionPoints.Count} collision point(s) with {plate.Parts.Count} parts"
);
}
@@ -1,5 +1,6 @@
using OpenNest.Geometry;
using OpenNest.Engine;
using OpenNest.Engine.Jobs.Placement.Fillers;
namespace OpenNest.Tests.Engine;
@@ -17,49 +18,49 @@ public class EngineRefactorSmokeTests
}
[Fact]
public void DefaultEngine_FillNestItem_ProducesResults()
public void DefaultPlateFiller_FillNestItem_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new DefaultNestEngine(plate);
var filler = new DefaultPlateFiller(plate);
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
var parts = engine.Fill(
var parts = filler.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
Assert.True(parts.Count > 0, "DefaultNestEngine should fill parts");
Assert.True(parts.Count > 0, "DefaultPlateFiller should fill parts");
}
[Fact]
public void DefaultEngine_FillGroupParts_ProducesResults()
public void DefaultPlateFiller_FillGroupParts_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new DefaultNestEngine(plate);
var filler = new DefaultPlateFiller(plate);
var drawing = MakeRectDrawing(20, 10);
var groupParts = new List<Part> { new Part(drawing) };
var parts = engine.Fill(
var parts = filler.Fill(
groupParts,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
Assert.True(parts.Count > 0, "DefaultNestEngine group fill should produce parts");
Assert.True(parts.Count > 0, "DefaultPlateFiller group fill should produce parts");
}
[Fact]
public void DefaultEngine_ForceFullAngleSweep_StillWorks()
public void DefaultPlateFiller_ForceFullAngleSweep_StillWorks()
{
var plate = new Plate(60, 120);
var engine = new DefaultNestEngine(plate);
engine.ForceFullAngleSweep = true;
var filler = new DefaultPlateFiller(plate);
filler.ForceFullAngleSweep = true;
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
var parts = engine.Fill(
var parts = filler.Fill(
item,
plate.WorkArea(),
null,
@@ -70,33 +71,33 @@ public class EngineRefactorSmokeTests
}
[Fact]
public void StripEngine_Nest_ProducesResults()
public void StripPlateFiller_Nest_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new StripNestEngine(plate);
var filler = new StripPlateFiller(plate);
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 = engine.Nest(items, null, System.Threading.CancellationToken.None);
var parts = filler.Nest(items, null, System.Threading.CancellationToken.None);
Assert.True(parts.Count > 0, "StripNestEngine should nest parts");
Assert.True(parts.Count > 0, "StripPlateFiller should nest parts");
}
[Fact]
public void DefaultEngine_Nest_ProducesResults()
public void DefaultPlateFiller_Nest_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new DefaultNestEngine(plate);
var filler = new DefaultPlateFiller(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 = engine.Nest(items, null, System.Threading.CancellationToken.None);
var parts = filler.Nest(items, null, System.Threading.CancellationToken.None);
Assert.True(parts.Count > 0, "Base Nest method should place parts");
}
@@ -7,7 +7,7 @@ namespace OpenNest.Tests.Engine;
/// <summary>
/// Phase 3.2: MultiPlateNester and PlateOptimizer take an explicit placement strategy at their
/// top-level call boundary instead of consulting the process-global NestEngineRegistry.
/// top-level call boundary instead of consulting process-global selection state.
/// </summary>
public class ExplicitPlacementStrategyTests
{
+5 -4
View File
@@ -2,6 +2,7 @@ using System.Threading;
using OpenNest.CNC;
using OpenNest.Engine;
using OpenNest.Engine.BestFit;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
using OpenNest.Math;
@@ -37,9 +38,9 @@ public class NestInvarianceTests
private static int RunFillCount(Drawing drawing, Plate plate)
{
BestFitCache.Clear();
var engine = new DefaultNestEngine(plate);
var filler = new DefaultPlateFiller(plate);
var item = new NestItem { Drawing = drawing };
var parts = engine.Fill(
var parts = filler.Fill(
item,
plate.WorkArea(),
progress: null,
@@ -71,9 +72,9 @@ public class NestInvarianceTests
foreach (var theta in new[] { 0.0, 0.3, 0.8, 1.2 })
{
BestFitCache.Clear();
var engine = new DefaultNestEngine(plate);
var filler = new DefaultPlateFiller(plate);
var item = new NestItem { Drawing = MakeImportedAt(theta) };
var parts = engine.Fill(item, workArea, progress: null, token: CancellationToken.None);
var parts = filler.Fill(item, workArea, progress: null, token: CancellationToken.None);
Assert.NotNull(parts);
foreach (var p in parts)
+25 -26
View File
@@ -1,5 +1,7 @@
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;
@@ -18,82 +20,79 @@ public class RemnantEngineTests
}
[Fact]
public void VerticalRemnantEngine_UsesVerticalRemnantComparer()
public void VerticalRemnantPlateFiller_UsesHorizontalPreferredDirection()
{
var plate = new Plate(60, 120);
var engine = new VerticalRemnantEngine(plate);
Assert.Equal("Vertical Remnant", engine.Name);
Assert.Equal(NestDirection.Horizontal, engine.PreferredDirection);
var filler = new RemnantPlateFiller(plate, RemnantFillPolicy.Vertical);
Assert.Equal(NestDirection.Horizontal, filler.PreferredDirection);
}
[Fact]
public void HorizontalRemnantEngine_UsesHorizontalRemnantComparer()
public void HorizontalRemnantPlateFiller_UsesVerticalPreferredDirection()
{
var plate = new Plate(60, 120);
var engine = new HorizontalRemnantEngine(plate);
Assert.Equal("Horizontal Remnant", engine.Name);
Assert.Equal(NestDirection.Vertical, engine.PreferredDirection);
var filler = new RemnantPlateFiller(plate, RemnantFillPolicy.Horizontal);
Assert.Equal(NestDirection.Vertical, filler.PreferredDirection);
}
[Fact]
public void VerticalRemnantEngine_Fill_ProducesResults()
public void VerticalRemnantPlateFiller_Fill_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new VerticalRemnantEngine(plate);
var filler = new RemnantPlateFiller(plate, RemnantFillPolicy.Vertical);
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
var parts = engine.Fill(
var parts = filler.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
Assert.True(parts.Count > 0, "VerticalRemnantEngine should fill parts");
Assert.True(parts.Count > 0, "VerticalRemnantPlateFiller should fill parts");
}
[Fact]
public void HorizontalRemnantEngine_Fill_ProducesResults()
public void HorizontalRemnantPlateFiller_Fill_ProducesResults()
{
var plate = new Plate(60, 120);
var engine = new HorizontalRemnantEngine(plate);
var filler = new RemnantPlateFiller(plate, RemnantFillPolicy.Horizontal);
var item = new NestItem { Drawing = MakeRectDrawing(20, 10) };
var parts = engine.Fill(
var parts = filler.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
Assert.True(parts.Count > 0, "HorizontalRemnantEngine should fill parts");
Assert.True(parts.Count > 0, "HorizontalRemnantPlateFiller should fill parts");
}
[Fact]
public void Registry_ContainsBothRemnantEngines()
public void PlateFillService_ListsBothRemnantStrategies()
{
var names = NestEngineRegistry.AvailableEngines.Select(e => e.Name).ToList();
Assert.Contains("Vertical Remnant", names);
Assert.Contains("Horizontal Remnant", names);
Assert.Contains("Vertical Remnant", PlateFillService.BuiltInStrategies);
Assert.Contains("Horizontal Remnant", PlateFillService.BuiltInStrategies);
}
[Fact]
public void VerticalRemnantEngine_ProducesTighterXExtent_ThanDefault()
public void VerticalRemnantPlateFiller_ProducesTighterXExtent_ThanDefault()
{
var plate = new Plate(60, 120);
var drawing = MakeRectDrawing(20, 10);
var item = new NestItem { Drawing = drawing };
var defaultEngine = new DefaultNestEngine(plate);
var remnantEngine = new VerticalRemnantEngine(plate);
var defaultFiller = new DefaultPlateFiller(plate);
var remnantFiller = new RemnantPlateFiller(plate, RemnantFillPolicy.Vertical);
var defaultParts = defaultEngine.Fill(
var defaultParts = defaultFiller.Fill(
item,
plate.WorkArea(),
null,
System.Threading.CancellationToken.None
);
var remnantParts = remnantEngine.Fill(
var remnantParts = remnantFiller.Fill(
item,
plate.WorkArea(),
null,
@@ -110,7 +109,7 @@ public class RemnantEngineTests
Assert.True(
remnantXExtent <= defaultXExtent + 0.01,
$"Remnant X-extent ({remnantXExtent:F1}) should be <= default ({defaultXExtent:F1})"
$"Remnant X-extent ({remnantXExtent:F1}) should be <= default filler ({defaultXExtent:F1})"
);
}
}