fix(engine): isolate job identity and engine selection
Replace name-based quantity deduction with reference-based drawing identity in the engine paths the whole-job runner reaches (NestEngineBase fill/pack, StripNestEngine deduction, RemnantFiller ledger, IterativeShrinkFiller leftovers). Add instance-scoped PlateNesterFactory that resolves built-in strategies without touching the global NestEngineRegistry. Add identity and engine-selection tests. 44 net8.0 tests pass in Debug and Release; no new warnings.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
using OpenNest.Geometry;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -130,17 +131,13 @@ namespace OpenNest.Engine.Fill
|
||||
|
||||
var placed = filler.FillItems(workItems, shrinkWrapper, token);
|
||||
|
||||
// Build leftovers: compare placed count to original quantities.
|
||||
// RemnantFiller.FillItems does NOT mutate NestItem.Quantity.
|
||||
// Build leftovers: compare placed count to original quantities by drawing
|
||||
// reference. RemnantFiller.FillItems does NOT mutate NestItem.Quantity.
|
||||
var leftovers = new List<NestItem>();
|
||||
foreach (var item in items)
|
||||
{
|
||||
var placedCount = 0;
|
||||
foreach (var p in placed)
|
||||
{
|
||||
if (p.BaseDrawing.Name == item.Drawing.Name)
|
||||
placedCount++;
|
||||
}
|
||||
var placedCount = placed.Count(p =>
|
||||
ReferenceEquals(p.BaseDrawing, item.Drawing));
|
||||
|
||||
if (item.Quantity <= 0)
|
||||
continue; // unlimited items are always "satisfied" — no leftover
|
||||
|
||||
@@ -58,20 +58,20 @@ namespace OpenNest.Engine.Fill
|
||||
return allParts;
|
||||
}
|
||||
|
||||
private static Dictionary<string, int> BuildLocalQuantities(List<NestItem> items)
|
||||
private static Dictionary<Drawing, int> BuildLocalQuantities(List<NestItem> items)
|
||||
{
|
||||
var localQty = new Dictionary<string, int>(items.Count);
|
||||
var localQty = new Dictionary<Drawing, int>(items.Count, ReferenceEqualityComparer.Instance);
|
||||
foreach (var item in items)
|
||||
localQty[item.Drawing.Name] = item.Quantity;
|
||||
localQty[item.Drawing] = item.Quantity;
|
||||
return localQty;
|
||||
}
|
||||
|
||||
private static double FindMinItemDimension(List<NestItem> items, Dictionary<string, int> localQty)
|
||||
private static double FindMinItemDimension(List<NestItem> items, Dictionary<Drawing, int> localQty)
|
||||
{
|
||||
var minDim = double.MaxValue;
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (localQty[item.Drawing.Name] <= 0)
|
||||
if (localQty[item.Drawing] <= 0)
|
||||
continue;
|
||||
var bb = item.Drawing.Program.BoundingBox();
|
||||
var dim = System.Math.Min(bb.Width, bb.Length);
|
||||
@@ -84,7 +84,7 @@ namespace OpenNest.Engine.Fill
|
||||
private bool TryFillOneItem(
|
||||
List<NestItem> items,
|
||||
List<Box> freeBoxes,
|
||||
Dictionary<string, int> localQty,
|
||||
Dictionary<Drawing, int> localQty,
|
||||
Func<NestItem, Box, List<Part>> fillFunc,
|
||||
List<Part> allParts,
|
||||
CancellationToken token)
|
||||
@@ -94,7 +94,7 @@ namespace OpenNest.Engine.Fill
|
||||
if (token.IsCancellationRequested)
|
||||
return false;
|
||||
|
||||
var qty = localQty[item.Drawing.Name];
|
||||
var qty = localQty[item.Drawing];
|
||||
if (qty <= 0)
|
||||
continue;
|
||||
|
||||
@@ -110,7 +110,7 @@ namespace OpenNest.Engine.Fill
|
||||
RemoveTopmostPart(placed);
|
||||
|
||||
allParts.AddRange(placed);
|
||||
localQty[item.Drawing.Name] = System.Math.Max(0, qty - placed.Count);
|
||||
localQty[item.Drawing] = System.Math.Max(0, qty - placed.Count);
|
||||
|
||||
// Add the envelope of all placed parts as a single obstacle
|
||||
// rather than individual bounding boxes, preventing the
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
namespace OpenNest;
|
||||
|
||||
/// <summary>
|
||||
/// Instance-scoped strategy resolution for the whole-job runner. The built-in strategies map
|
||||
/// to private engine factories; the process-global NestEngineRegistry (including plugin
|
||||
/// registrations and ActiveEngineName) is neither read nor modified. Unknown keys reject.
|
||||
/// </summary>
|
||||
public static class PlateNesterFactory
|
||||
{
|
||||
public static IPlateNester Create(string strategy)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(strategy);
|
||||
return strategy switch
|
||||
{
|
||||
"Default" => new LegacyPlateNesterAdapter(plate => new DefaultNestEngine(plate)),
|
||||
"Strip" => new LegacyPlateNesterAdapter(plate => new StripNestEngine(plate)),
|
||||
"Vertical Remnant" => new LegacyPlateNesterAdapter(plate => new VerticalRemnantEngine(plate)),
|
||||
"Horizontal Remnant" => new LegacyPlateNesterAdapter(plate => new HorizontalRemnantEngine(plate)),
|
||||
_ => throw new NotSupportedException($"Unknown placement strategy: {strategy}.")
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -113,11 +113,11 @@ namespace OpenNest
|
||||
{
|
||||
allParts.AddRange(fillParts);
|
||||
|
||||
// Deduct placed quantities
|
||||
// Deduct placed quantities by drawing reference, not name.
|
||||
foreach (var item in fillItems)
|
||||
{
|
||||
var placed = fillParts.Count(p =>
|
||||
p.BaseDrawing.Name == item.Drawing.Name);
|
||||
ReferenceEquals(p.BaseDrawing, item.Drawing));
|
||||
item.Quantity = System.Math.Max(0, item.Quantity - placed);
|
||||
}
|
||||
|
||||
@@ -147,10 +147,11 @@ namespace OpenNest
|
||||
{
|
||||
allParts.AddRange(packParts);
|
||||
|
||||
// Deduct placed quantities by drawing reference, not name.
|
||||
foreach (var item in regularPackItems)
|
||||
{
|
||||
var placed = packParts.Count(p =>
|
||||
p.BaseDrawing.Name == item.Drawing.Name);
|
||||
ReferenceEquals(p.BaseDrawing, item.Drawing));
|
||||
item.Quantity = System.Math.Max(0, item.Quantity - placed);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,13 +128,14 @@ namespace OpenNest
|
||||
}
|
||||
}
|
||||
|
||||
// Deduct placed quantities from original items.
|
||||
// Deduct placed quantities from original items by drawing reference.
|
||||
foreach (var item in items)
|
||||
{
|
||||
if (item.Quantity <= 0)
|
||||
continue;
|
||||
|
||||
var placed = allParts.Count(p => p.BaseDrawing.Name == item.Drawing.Name);
|
||||
var placed = allParts.Count(p =>
|
||||
ReferenceEquals(p.BaseDrawing, item.Drawing));
|
||||
item.Quantity = System.Math.Max(0, item.Quantity - placed);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user