fix: consolidation pass packs medium/small parts onto shared plates
After the main single-pass placement, leftover items are now packed together using the engine's multi-item Nest()/PackArea() methods instead of creating one plate per drawing. First tries packing into remaining space on existing plates, then creates shared plates for anything still remaining. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -228,10 +228,97 @@ namespace OpenNest
|
|||||||
plateOptions, salvageRate, minRemnantSize, progress, token) || placed;
|
plateOptions, salvageRate, minRemnantSize, progress, token) || placed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.Quantity > 0)
|
// Don't add to unplaced yet — consolidation pass will handle leftovers.
|
||||||
result.UnplacedItems.Add(item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Consolidation pass: pack remaining items together on shared plates
|
||||||
|
// using the engine's multi-item Nest() method instead of one-drawing-per-plate.
|
||||||
|
var leftovers = sorted.Where(i => i.Quantity > 0).ToList();
|
||||||
|
|
||||||
|
if (leftovers.Count > 0 && allowPlateCreation && !token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
// First try to pack leftovers into remaining space on existing plates.
|
||||||
|
foreach (var pr in platePool)
|
||||||
|
{
|
||||||
|
if (token.IsCancellationRequested)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var remaining = leftovers.Where(i => i.Quantity > 0).ToList();
|
||||||
|
if (remaining.Count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var finder = RemnantFinder.FromPlate(pr.Plate);
|
||||||
|
var remnants = finder.FindRemnants();
|
||||||
|
|
||||||
|
foreach (var remnant in remnants)
|
||||||
|
{
|
||||||
|
remaining = remaining.Where(i => i.Quantity > 0).ToList();
|
||||||
|
if (remaining.Count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
var engine = NestEngineRegistry.Create(pr.Plate);
|
||||||
|
var cloned = remaining.Select(CloneItem).ToList();
|
||||||
|
var parts = engine.PackArea(remnant, cloned, progress, token);
|
||||||
|
|
||||||
|
if (parts.Count > 0)
|
||||||
|
{
|
||||||
|
pr.Plate.Parts.AddRange(parts);
|
||||||
|
pr.Parts.AddRange(parts);
|
||||||
|
|
||||||
|
// Deduct placed quantities from originals.
|
||||||
|
foreach (var item in remaining)
|
||||||
|
{
|
||||||
|
var placed = parts.Count(p => p.BaseDrawing.Name == item.Drawing.Name);
|
||||||
|
item.Quantity = System.Math.Max(0, item.Quantity - placed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then create new shared plates for anything still remaining.
|
||||||
|
leftovers = leftovers.Where(i => i.Quantity > 0).ToList();
|
||||||
|
|
||||||
|
while (leftovers.Count > 0 && !token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
var plate = CreatePlate(template, plateOptions, null);
|
||||||
|
var engine = NestEngineRegistry.Create(plate);
|
||||||
|
var cloned = leftovers.Select(CloneItem).ToList();
|
||||||
|
var parts = engine.Nest(cloned, progress, token);
|
||||||
|
|
||||||
|
if (parts.Count == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
plate.Parts.AddRange(parts);
|
||||||
|
var pr = new PlateResult
|
||||||
|
{
|
||||||
|
Plate = plate,
|
||||||
|
Parts = parts.ToList(),
|
||||||
|
IsNew = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (plateOptions != null)
|
||||||
|
{
|
||||||
|
pr.ChosenSize = plateOptions.FirstOrDefault(o =>
|
||||||
|
o.Width.IsEqualTo(plate.Size.Width) && o.Length.IsEqualTo(plate.Size.Length));
|
||||||
|
}
|
||||||
|
|
||||||
|
platePool.Add(pr);
|
||||||
|
|
||||||
|
// Deduct placed quantities from originals.
|
||||||
|
foreach (var item in leftovers)
|
||||||
|
{
|
||||||
|
var placed = parts.Count(p => p.BaseDrawing.Name == item.Drawing.Name);
|
||||||
|
item.Quantity = System.Math.Max(0, item.Quantity - placed);
|
||||||
|
}
|
||||||
|
|
||||||
|
leftovers = leftovers.Where(i => i.Quantity > 0).ToList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Anything still remaining is truly unplaced.
|
||||||
|
foreach (var item in sorted.Where(i => i.Quantity > 0))
|
||||||
|
result.UnplacedItems.Add(item);
|
||||||
|
|
||||||
result.Plates.AddRange(platePool.Where(p => p.Parts.Count > 0 || p.IsNew));
|
result.Plates.AddRange(platePool.Where(p => p.Parts.Count > 0 || p.IsNew));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user