diff --git a/OpenNest.Engine/StripNestEngine.cs b/OpenNest.Engine/StripNestEngine.cs index 6ad04ca..283a145 100644 --- a/OpenNest.Engine/StripNestEngine.cs +++ b/OpenNest.Engine/StripNestEngine.cs @@ -292,8 +292,7 @@ namespace OpenNest if (System.Math.Min(box.Width, box.Length) < minItemDim) continue; - var remnantInner = new DefaultNestEngine(Plate); - var remnantParts = remnantInner.Fill( + var remnantParts = ShrinkFill( new NestItem { Drawing = item.Drawing, Quantity = qty }, box, remnantProgress, token); @@ -326,6 +325,73 @@ namespace OpenNest return result; } + /// + /// Fill a box and then shrink it to the tightest area that still fits + /// the same number of parts. This maximizes leftover space for subsequent fills. + /// + private List ShrinkFill(NestItem item, Box box, + IProgress progress, CancellationToken token) + { + var inner = new DefaultNestEngine(Plate); + var parts = inner.Fill(item, box, progress, token); + + if (parts == null || parts.Count < 2) + return parts; + + var targetCount = parts.Count; + var placedBox = parts.Cast().GetBoundingBox(); + + // Try shrinking horizontally + var bestParts = parts; + var shrunkWidth = placedBox.Right - box.X; + var shrunkHeight = placedBox.Top - box.Y; + + for (var i = 0; i < MaxShrinkIterations; i++) + { + if (token.IsCancellationRequested) + break; + + var trialWidth = shrunkWidth - Plate.PartSpacing; + if (trialWidth <= 0) + break; + + var trialBox = new Box(box.X, box.Y, trialWidth, box.Length); + var trialInner = new DefaultNestEngine(Plate); + var trialParts = trialInner.Fill(item, trialBox, null, token); + + if (trialParts == null || trialParts.Count < targetCount) + break; + + bestParts = trialParts; + var trialPlacedBox = trialParts.Cast().GetBoundingBox(); + shrunkWidth = trialPlacedBox.Right - box.X; + } + + // Try shrinking vertically + for (var i = 0; i < MaxShrinkIterations; i++) + { + if (token.IsCancellationRequested) + break; + + var trialHeight = shrunkHeight - Plate.PartSpacing; + if (trialHeight <= 0) + break; + + var trialBox = new Box(box.X, box.Y, box.Width, trialHeight); + var trialInner = new DefaultNestEngine(Plate); + var trialParts = trialInner.Fill(item, trialBox, null, token); + + if (trialParts == null || trialParts.Count < targetCount) + break; + + bestParts = trialParts; + var trialPlacedBox = trialParts.Cast().GetBoundingBox(); + shrunkHeight = trialPlacedBox.Top - box.Y; + } + + return bestParts; + } + /// /// Wraps an IProgress to prepend previously placed parts to each report, /// so the UI shows the full picture (strip + remnant) during remnant fills.