Replace expensive ShrinkFiller re-fill loop with axis-aware edge-sorted trim. Also replaces blind Take(N) in DefaultNestEngine.Fill. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2.7 KiB
Trim-to-Count: Replace ShrinkFiller Loop with Edge-Sorted Trim
Problem
When a fill produces more parts than needed, ShrinkFiller iteratively shrinks the work area and re-fills from scratch until the count drops below target. Each iteration runs the full fill pipeline (pairs, bestfit, linear), making this expensive. Meanwhile, DefaultNestEngine.Fill trims excess parts with a blind Take(N) that ignores spatial position.
Solution
Add ShrinkFiller.TrimToCount — a static method that sorts parts by their trailing edge and removes from the far end until the target count is reached. Replace the shrink loop and the blind Take(N) with calls to this method.
Design
New method: ShrinkFiller.TrimToCount
internal static List<Part> TrimToCount(List<Part> parts, int targetCount, ShrinkAxis axis)
- Returns input unchanged if
parts.Count <= targetCount - Sorts by trailing edge descending:
ShrinkAxis.Width→ sort byBoundingBox.RightShrinkAxis.Height→ sort byBoundingBox.Top
- Removes parts from the far end until
targetCountremains - Returns a new list (does not mutate input)
Changes to ShrinkFiller.Shrink
Replace the iterative shrink loop:
- Fill once using existing
EstimateStartBox+ fallback logic (unchanged) - If count exceeds
shrinkTarget, callTrimToCount(parts, shrinkTarget, axis) - Measure dimension from trimmed result via existing
MeasureDimension - Report progress once after trim
- Return
ShrinkResult
The maxIterations parameter becomes unused and can be removed.
Changes to DefaultNestEngine.Fill
Replace line 55-56:
// Before:
if (item.Quantity > 0 && best.Count > item.Quantity)
best = best.Take(item.Quantity).ToList();
// After:
if (item.Quantity > 0 && best.Count > item.Quantity)
best = ShrinkFiller.TrimToCount(best, item.Quantity, ShrinkAxis.Width);
Defaults to ShrinkAxis.Width (trim by right edge) since this is the natural "end of nest" direction outside of a shrink context.
Design Decisions
- Axis-aware trimming: Height shrink trims by top edge, width shrink trims by right edge. This respects the strip direction.
- No pair integrity: Trimming may split interlocking pairs. This is acceptable because if the layout is suboptimal, a better candidate will replace it during evaluation.
- No edge spacing concerns: The new dimension is simply the max edge of remaining parts. No snapping to spacing increments.
Files Changed
OpenNest.Engine/Fill/ShrinkFiller.cs— addTrimToCount, replace shrink loop, removemaxIterationsOpenNest.Engine/DefaultNestEngine.cs— replaceTake(N)withTrimToCountOpenNest.Tests/ShrinkFillerTests.cs— update tests for new behavior, addTrimToCounttests