refactor(engine): make jobs plate nesters filler-backed
This commit is contained in:
@@ -1,15 +1,18 @@
|
||||
using OpenNest.CNC;
|
||||
using OpenNest.Engine.Fill;
|
||||
using OpenNest.Geometry;
|
||||
using OpenNest.Engine.Jobs;
|
||||
using OpenNest.Engine.Jobs.Adapters;
|
||||
using OpenNest.Engine.Jobs.Placement;
|
||||
using OpenNest.Engine.Jobs.Placement.Fillers;
|
||||
|
||||
namespace OpenNest.Engine.Tests.Jobs;
|
||||
|
||||
/// <summary>
|
||||
/// Names are never identity: two distinct drawings that share a display name must keep
|
||||
/// independent quantities, and two requirements that share one source drawing must not
|
||||
/// cross-count each other's placements through the legacy engine paths.
|
||||
/// cross-count each other's placements. Production identity runs through the built-in nesters'
|
||||
/// <see cref="CandidatePlacementContext"/>; the filler probes exercise the orchestrator's
|
||||
/// reference-identity quantity deduction directly.
|
||||
/// </summary>
|
||||
public class NestJobIdentityTests
|
||||
{
|
||||
@@ -27,7 +30,7 @@ public class NestJobIdentityTests
|
||||
new[] { new NestPlateStock("s", new Size(90, 90), 1) }
|
||||
);
|
||||
|
||||
var result = new NestJobRunner(LegacyPlateNesterAdapter.Create).Solve(job);
|
||||
var result = new NestJobRunner(PlateNesterFactory.Create).Solve(job);
|
||||
|
||||
// Every placed part maps to a known requirement ID; no part is invented or cross-counted.
|
||||
Assert.True(result.Plates.SelectMany(p => p.Placements).All(p => p.PartId is "a" or "b"));
|
||||
@@ -56,7 +59,7 @@ public class NestJobIdentityTests
|
||||
new[] { new NestPlateStock("s", new Size(90, 90), 1) }
|
||||
);
|
||||
|
||||
var result = new NestJobRunner(LegacyPlateNesterAdapter.Create).Solve(job);
|
||||
var result = new NestJobRunner(PlateNesterFactory.Create).Solve(job);
|
||||
|
||||
Assert.Equal(new[] { "first", "second" }, result.Fulfillment.Select(f => f.PartId));
|
||||
foreach (var f in result.Fulfillment)
|
||||
@@ -72,7 +75,7 @@ public class NestJobIdentityTests
|
||||
[Fact]
|
||||
public void EngineDeductionCountsByDrawingReferenceNotName()
|
||||
{
|
||||
// Plate 90x40 fits exactly two 40x40 parts. The engine fills item A with both and
|
||||
// Plate 90x40 fits exactly two 40x40 parts. The filler fills item A with both and
|
||||
// starves item B. Name-based deduction would then zero BOTH items (the two placed
|
||||
// parts carry the shared name, so each item counts 2 as "its own"). Reference-based
|
||||
// deduction leaves B at 2.
|
||||
@@ -84,7 +87,7 @@ public class NestJobIdentityTests
|
||||
new() { Drawing = a, Quantity = 2 },
|
||||
new() { Drawing = b, Quantity = 2 },
|
||||
};
|
||||
// Place exactly 2 parts from item A and none from item B, then run the base-class
|
||||
// Place exactly 2 parts from item A and none from item B, then run the orchestrator's
|
||||
// deduction. Deterministic regardless of any fill heuristic.
|
||||
var placed = new StarvingProbe(plate).Nest(items, null, default);
|
||||
|
||||
@@ -111,45 +114,41 @@ public class NestJobIdentityTests
|
||||
new() { Drawing = a, Quantity = 1 },
|
||||
new() { Drawing = b, Quantity = 1 },
|
||||
};
|
||||
var placed = new BaseNestEngineProbe(plate).Nest(items, null, default);
|
||||
var placed = new DefaultFillerProbe(plate).Nest(items, null, default);
|
||||
Assert.Equal(2, placed.Count);
|
||||
Assert.Equal(new[] { 0, 0 }, new[] { items[0].Quantity, items[1].Quantity });
|
||||
}
|
||||
|
||||
private sealed class BaseNestEngineProbe(Plate plate) : NestEngineBase(plate)
|
||||
/// <summary>Orchestrator probe whose fill/pack delegates run the Default filler.</summary>
|
||||
private sealed class DefaultFillerProbe(Plate plate) : PlateFillerBase(plate)
|
||||
{
|
||||
public override string Name => "probe";
|
||||
public override string Description => "probe";
|
||||
|
||||
public override List<Part> Fill(
|
||||
NestItem item,
|
||||
Box workArea,
|
||||
IProgress<NestProgress> progress,
|
||||
CancellationToken token
|
||||
) => new DefaultNestEngine(Plate).Fill(item, workArea, progress, token);
|
||||
) => new DefaultPlateFiller(Plate).Fill(item, workArea, progress, token);
|
||||
|
||||
public override List<Part> Fill(
|
||||
List<Part> groupParts,
|
||||
Box workArea,
|
||||
IProgress<NestProgress> progress,
|
||||
CancellationToken token
|
||||
) => new DefaultNestEngine(Plate).Fill(groupParts, workArea, progress, token);
|
||||
) => new DefaultPlateFiller(Plate).Fill(groupParts, workArea, progress, token);
|
||||
|
||||
public override List<Part> PackArea(
|
||||
Box box,
|
||||
List<NestItem> items,
|
||||
IProgress<NestProgress> progress,
|
||||
CancellationToken token
|
||||
) => new DefaultNestEngine(Plate).PackArea(box, items, progress, token);
|
||||
) => new DefaultPlateFiller(Plate).PackArea(box, items, progress, token);
|
||||
}
|
||||
|
||||
/// <summary>Places exactly 2 parts from the first multi-quantity item and none from the
|
||||
/// rest, forcing the base-class deduction to run on an asymmetric placement result.</summary>
|
||||
private sealed class StarvingProbe(Plate plate) : NestEngineBase(plate)
|
||||
/// rest, forcing the orchestrator's deduction to run on an asymmetric placement result.</summary>
|
||||
private sealed class StarvingProbe(Plate plate) : PlateFillerBase(plate)
|
||||
{
|
||||
private int _first = -1;
|
||||
public override string Name => "starving";
|
||||
public override string Description => "starves all but the first fill item";
|
||||
|
||||
public override List<Part> Fill(
|
||||
NestItem item,
|
||||
|
||||
Reference in New Issue
Block a user