perf(engine): reduce PairFiller work area when count exceeds target
When the first pair candidate places more parts than needed (e.g., 17 when target is 10), sort by BoundingBox.Top, trim from the top until exactly targetCount remain, and use that Top as the new work area height. All subsequent candidates fill this smaller area, dramatically reducing fill time. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -48,6 +48,9 @@ namespace OpenNest.Engine.Fill
|
||||
Debug.WriteLine($"[PairFiller] Total: {BestFits.Count}, Kept: {BestFits.Count(r => r.Keep)}, Trying: {candidates.Count}");
|
||||
Debug.WriteLine($"[PairFiller] Plate: {plateSize.Length:F2}x{plateSize.Width:F2}, WorkArea: {workArea.Width:F2}x{workArea.Length:F2}");
|
||||
|
||||
var targetCount = item.Quantity > 0 ? item.Quantity : 0;
|
||||
var effectiveWorkArea = workArea;
|
||||
|
||||
List<Part> best = null;
|
||||
var bestScore = default(FillScore);
|
||||
var sinceImproved = 0;
|
||||
@@ -58,16 +61,29 @@ namespace OpenNest.Engine.Fill
|
||||
{
|
||||
token.ThrowIfCancellationRequested();
|
||||
|
||||
var filled = EvaluateCandidate(candidates[i], item.Drawing, workArea);
|
||||
var filled = EvaluateCandidate(candidates[i], item.Drawing, effectiveWorkArea);
|
||||
|
||||
if (filled != null && filled.Count > 0)
|
||||
{
|
||||
var score = FillScore.Compute(filled, workArea);
|
||||
var score = FillScore.Compute(filled, effectiveWorkArea);
|
||||
if (best == null || score > bestScore)
|
||||
{
|
||||
best = filled;
|
||||
bestScore = score;
|
||||
sinceImproved = 0;
|
||||
|
||||
// If we exceeded the target, reduce the work area for
|
||||
// subsequent candidates by trimming excess parts and
|
||||
// measuring the tighter bounding box.
|
||||
if (targetCount > 0 && filled.Count > targetCount)
|
||||
{
|
||||
var reduced = ReduceWorkArea(filled, targetCount, workArea);
|
||||
if (reduced.Area() < effectiveWorkArea.Area())
|
||||
{
|
||||
effectiveWorkArea = reduced;
|
||||
Debug.WriteLine($"[PairFiller] Reduced work area to {effectiveWorkArea.Width:F2}x{effectiveWorkArea.Length:F2} (trimmed to {targetCount + 1} parts)");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -98,6 +114,32 @@ namespace OpenNest.Engine.Fill
|
||||
return best ?? new List<Part>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given parts that exceed targetCount, sorts by BoundingBox.Top descending,
|
||||
/// removes parts from the top until exactly targetCount remain, then returns
|
||||
/// the Top of the remaining parts as the new work area height to beat.
|
||||
/// </summary>
|
||||
private static Box ReduceWorkArea(List<Part> parts, int targetCount, Box workArea)
|
||||
{
|
||||
if (parts.Count <= targetCount)
|
||||
return workArea;
|
||||
|
||||
// Sort by Top descending — highest parts get trimmed first.
|
||||
var sorted = parts
|
||||
.OrderByDescending(p => p.BoundingBox.Top)
|
||||
.ToList();
|
||||
|
||||
// Remove from the top until exactly targetCount remain.
|
||||
var trimCount = sorted.Count - targetCount;
|
||||
var remaining = sorted.Skip(trimCount).ToList();
|
||||
|
||||
var newTop = remaining.Max(p => p.BoundingBox.Top);
|
||||
|
||||
return new Box(workArea.X, workArea.Y,
|
||||
workArea.Width,
|
||||
System.Math.Min(newTop - workArea.Y, workArea.Length));
|
||||
}
|
||||
|
||||
private List<Part> EvaluateCandidate(BestFitResult candidate, Drawing drawing, Box workArea)
|
||||
{
|
||||
var pairParts = candidate.BuildParts(drawing);
|
||||
|
||||
Reference in New Issue
Block a user