fix: prioritize width-fitting candidates in PairFiller strip mode

In strip mode, build candidate list entirely from pairs whose
ShortestSide fits the narrow work area dimension, sorted by
estimated tile count. Previously, the top-50 utilization cut
ran first, excluding good strip candidates like #183.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 14:43:45 -04:00
parent 708d895a04
commit ae88c34361

View File

@@ -168,35 +168,30 @@ namespace OpenNest.Engine.Fill
private List<BestFitResult> SelectPairCandidates(List<BestFitResult> bestFits, Box workArea) private List<BestFitResult> SelectPairCandidates(List<BestFitResult> bestFits, Box workArea)
{ {
var kept = bestFits.Where(r => r.Keep).ToList(); var kept = bestFits.Where(r => r.Keep).ToList();
var top = kept.Take(MaxTopCandidates).ToList();
var workShortSide = System.Math.Min(workArea.Width, workArea.Length); var workShortSide = System.Math.Min(workArea.Width, workArea.Length);
var plateShortSide = System.Math.Min(plateSize.Width, plateSize.Length); var plateShortSide = System.Math.Min(plateSize.Width, plateSize.Length);
if (workShortSide < plateShortSide * 0.5) if (workShortSide < plateShortSide * 0.5)
{ {
var stripCandidates = bestFits // Strip mode: prioritize candidates that fit the narrow dimension.
var stripCandidates = kept
.Where(r => r.ShortestSide <= workShortSide + Tolerance.Epsilon .Where(r => r.ShortestSide <= workShortSide + Tolerance.Epsilon
&& r.Utilization >= MinStripUtilization) && r.Utilization >= MinStripUtilization)
.OrderByDescending(r => r.Utilization); .ToList();
var existing = new HashSet<BestFitResult>(top); SortByEstimatedCount(stripCandidates, workArea);
foreach (var r in stripCandidates) var top = stripCandidates.Take(MaxStripCandidates).ToList();
{
if (top.Count >= MaxStripCandidates)
break;
if (existing.Add(r))
top.Add(r);
}
Debug.WriteLine($"[PairFiller] Strip mode: {top.Count} candidates (shortSide <= {workShortSide:F1})"); Debug.WriteLine($"[PairFiller] Strip mode: {top.Count} candidates (shortSide <= {workShortSide:F1})");
return top;
} }
SortByEstimatedCount(top, workArea); var result = kept.Take(MaxTopCandidates).ToList();
SortByEstimatedCount(result, workArea);
return top; return result;
} }
private void SortByEstimatedCount(List<BestFitResult> candidates, Box workArea) private void SortByEstimatedCount(List<BestFitResult> candidates, Box workArea)