refactor: replace ShrinkFiller shrink loop with TrimToCount
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -16,9 +16,8 @@ namespace OpenNest.Engine.Fill
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills a box then iteratively shrinks one axis by the spacing amount
|
/// Fills a box and trims excess parts by removing those farthest from
|
||||||
/// until the part count drops. Returns the tightest box that still fits
|
/// the origin along the shrink axis.
|
||||||
/// the target number of parts.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class ShrinkFiller
|
public static class ShrinkFiller
|
||||||
{
|
{
|
||||||
@@ -28,22 +27,17 @@ namespace OpenNest.Engine.Fill
|
|||||||
double spacing,
|
double spacing,
|
||||||
ShrinkAxis axis,
|
ShrinkAxis axis,
|
||||||
CancellationToken token = default,
|
CancellationToken token = default,
|
||||||
int maxIterations = 20,
|
|
||||||
int targetCount = 0,
|
int targetCount = 0,
|
||||||
IProgress<NestProgress> progress = null,
|
IProgress<NestProgress> progress = null,
|
||||||
int plateNumber = 0,
|
int plateNumber = 0,
|
||||||
List<Part> placedParts = null)
|
List<Part> placedParts = null)
|
||||||
{
|
{
|
||||||
// If a target count is specified, estimate a smaller starting box
|
|
||||||
// to avoid an expensive full-area fill.
|
|
||||||
var startBox = box;
|
var startBox = box;
|
||||||
if (targetCount > 0)
|
if (targetCount > 0)
|
||||||
startBox = EstimateStartBox(item, box, spacing, axis, targetCount);
|
startBox = EstimateStartBox(item, box, spacing, axis, targetCount);
|
||||||
|
|
||||||
var parts = fillFunc(item, startBox);
|
var parts = fillFunc(item, startBox);
|
||||||
|
|
||||||
// If estimate was too aggressive and we got fewer than target,
|
|
||||||
// fall back to the full box.
|
|
||||||
if (targetCount > 0 && startBox != box
|
if (targetCount > 0 && startBox != box
|
||||||
&& (parts == null || parts.Count < targetCount))
|
&& (parts == null || parts.Count < targetCount))
|
||||||
{
|
{
|
||||||
@@ -53,47 +47,18 @@ namespace OpenNest.Engine.Fill
|
|||||||
if (parts == null || parts.Count == 0)
|
if (parts == null || parts.Count == 0)
|
||||||
return new ShrinkResult { Parts = parts ?? new List<Part>(), Dimension = 0 };
|
return new ShrinkResult { Parts = parts ?? new List<Part>(), Dimension = 0 };
|
||||||
|
|
||||||
// Shrink target: if a target count was given and we got at least that many,
|
|
||||||
// shrink to fit targetCount (not the full count). This produces a tighter box.
|
|
||||||
// If we got fewer than target, shrink to maintain what we have.
|
|
||||||
var shrinkTarget = targetCount > 0
|
var shrinkTarget = targetCount > 0
|
||||||
? System.Math.Min(targetCount, parts.Count)
|
? System.Math.Min(targetCount, parts.Count)
|
||||||
: parts.Count;
|
: parts.Count;
|
||||||
|
|
||||||
var bestParts = parts;
|
if (parts.Count > shrinkTarget)
|
||||||
var bestDim = MeasureDimension(parts, box, axis);
|
parts = TrimToCount(parts, shrinkTarget, axis);
|
||||||
|
|
||||||
ReportShrinkProgress(progress, plateNumber, placedParts, bestParts, box, axis, bestDim);
|
var dim = MeasureDimension(parts, box, axis);
|
||||||
|
|
||||||
for (var i = 0; i < maxIterations; i++)
|
ReportShrinkProgress(progress, plateNumber, placedParts, parts, box, axis, dim);
|
||||||
{
|
|
||||||
if (token.IsCancellationRequested)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var trialDim = bestDim - spacing;
|
return new ShrinkResult { Parts = parts, Dimension = dim };
|
||||||
if (trialDim <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var trialBox = axis == ShrinkAxis.Width
|
|
||||||
? new Box(box.X, box.Y, trialDim, box.Length)
|
|
||||||
: new Box(box.X, box.Y, box.Width, trialDim);
|
|
||||||
|
|
||||||
// Report the trial box before the fill so the UI updates the
|
|
||||||
// work area border immediately rather than after the fill completes.
|
|
||||||
ReportShrinkProgress(progress, plateNumber, placedParts, bestParts, trialBox, axis, trialDim);
|
|
||||||
|
|
||||||
var trialParts = fillFunc(item, trialBox);
|
|
||||||
|
|
||||||
if (trialParts == null || trialParts.Count < shrinkTarget)
|
|
||||||
break;
|
|
||||||
|
|
||||||
bestParts = trialParts;
|
|
||||||
bestDim = MeasureDimension(trialParts, box, axis);
|
|
||||||
|
|
||||||
ReportShrinkProgress(progress, plateNumber, placedParts, bestParts, trialBox, axis, bestDim);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new ShrinkResult { Parts = bestParts, Dimension = bestDim };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void ReportShrinkProgress(
|
private static void ReportShrinkProgress(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ public class ShrinkFillerTests
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Shrink_ReducesDimension_UntilCountDrops()
|
public void Shrink_FillsAndReturnsDimension()
|
||||||
{
|
{
|
||||||
var drawing = MakeSquareDrawing(10);
|
var drawing = MakeSquareDrawing(10);
|
||||||
var item = new NestItem { Drawing = drawing };
|
var item = new NestItem { Drawing = drawing };
|
||||||
@@ -59,25 +59,6 @@ public class ShrinkFillerTests
|
|||||||
Assert.True(result.Dimension <= 100);
|
Assert.True(result.Dimension <= 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
|
||||||
public void Shrink_RespectsMaxIterations()
|
|
||||||
{
|
|
||||||
var callCount = 0;
|
|
||||||
Func<NestItem, Box, List<Part>> fillFunc = (ni, b) =>
|
|
||||||
{
|
|
||||||
callCount++;
|
|
||||||
return new List<Part> { TestHelpers.MakePartAt(0, 0, 5) };
|
|
||||||
};
|
|
||||||
|
|
||||||
var item = new NestItem { Drawing = MakeSquareDrawing(5) };
|
|
||||||
var box = new Box(0, 0, 100, 100);
|
|
||||||
|
|
||||||
ShrinkFiller.Shrink(fillFunc, item, box, 1.0, ShrinkAxis.Height, maxIterations: 3);
|
|
||||||
|
|
||||||
// 1 initial + up to 3 shrink iterations = max 4 calls
|
|
||||||
Assert.True(callCount <= 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void Shrink_RespectsCancellation()
|
public void Shrink_RespectsCancellation()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user