fix: improve fill progress reporting and engine pipeline

- Strategies now promote results to IsOverallBest when they beat the
  pipeline best, so the UI updates immediately on improvement rather
  than waiting for each phase to complete
- PlateView only updates the main view on overall-best results, fixing
  intermediate angle-sweep layouts leaking to the plate display
- Skip Row/Column strategies for rectangle parts (redundant with Linear)
- Intercept Escape key at MainForm level via ProcessCmdKey so it always
  reaches the active PlateView regardless of focus state
- Restore keyboard focus to PlateView after fill progress form closes
- Remnant engines use SelectBestFitPair for orientation-aware pair
  selection; DefaultNestEngine tries both landscape and portrait pairs
- RemnantFiller preserves more parts during topmost-part removal

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-05 18:30:07 -04:00
parent 37130e8a28
commit f78cc78a65
10 changed files with 135 additions and 23 deletions

View File

@@ -11,6 +11,9 @@ public class ColumnFillStrategy : IFillStrategy
public List<Part> Fill(FillContext context)
{
if (context.PartType == PartType.Rectangle)
return null;
var filler = new StripeFiller(context, NestDirection.Vertical) { CompleteStripesOnly = true };
return filler.Fill();
}

View File

@@ -32,16 +32,29 @@ namespace OpenNest.Engine.Strategies
/// <summary>
/// Standard progress reporting for strategies and fillers. Reports intermediate
/// results using the current ActivePhase, PlateNumber, and WorkArea.
/// When the reported parts beat the current pipeline best, promotes the
/// result to IsOverallBest so the UI updates immediately.
/// </summary>
public void ReportProgress(List<Part> parts, string description)
{
var isNewBest = parts != null && parts.Count > 0
&& Policy.Comparer.IsBetter(parts, CurrentBest, WorkArea);
if (isNewBest)
{
CurrentBest = parts;
CurrentBestScore = FillScore.Compute(parts, WorkArea);
WinnerPhase = ActivePhase;
}
NestEngineBase.ReportProgress(Progress, new ProgressReport
{
Phase = ActivePhase,
PlateNumber = PlateNumber,
Parts = parts,
Parts = isNewBest ? parts : CurrentBest,
WorkArea = WorkArea,
Description = description,
IsOverallBest = isNewBest,
});
}
}

View File

@@ -11,6 +11,9 @@ public class RowFillStrategy : IFillStrategy
public List<Part> Fill(FillContext context)
{
if (context.PartType == PartType.Rectangle)
return null;
var filler = new StripeFiller(context, NestDirection.Horizontal) { CompleteStripesOnly = true };
return filler.Fill();
}