feat(engine): show running ledger in progress descriptions

Linear phase shows "Linear: 12/36 angles, 45° = 48 parts" with a
running count. Pairs phase shows "Pairs: 8/50 candidates, best = 252
parts" tracking the best result seen so far. Reports on every
completion so the UI always reflects current state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 20:57:01 -04:00
parent 91281c8813
commit 9783d417bd
+20 -18
View File
@@ -285,7 +285,7 @@ namespace OpenNest
var linearBag = new System.Collections.Concurrent.ConcurrentBag<(FillScore score, List<Part> parts)>(); var linearBag = new System.Collections.Concurrent.ConcurrentBag<(FillScore score, List<Part> parts)>();
var angleBag = new System.Collections.Concurrent.ConcurrentBag<AngleResult>(); var angleBag = new System.Collections.Concurrent.ConcurrentBag<AngleResult>();
long lastLinearReport = 0; var anglesCompleted = 0;
System.Threading.Tasks.Parallel.ForEach(angles, System.Threading.Tasks.Parallel.ForEach(angles,
new System.Threading.Tasks.ParallelOptions { CancellationToken = token }, new System.Threading.Tasks.ParallelOptions { CancellationToken = token },
@@ -307,19 +307,14 @@ namespace OpenNest
angleBag.Add(new AngleResult { AngleDeg = angleDeg, Direction = NestDirection.Vertical, PartCount = v.Count }); angleBag.Add(new AngleResult { AngleDeg = angleDeg, Direction = NestDirection.Vertical, PartCount = v.Count });
} }
var now = linearSw.ElapsedMilliseconds; var done = Interlocked.Increment(ref anglesCompleted);
if (progress != null && now - Interlocked.Read(ref lastLinearReport) >= 150)
{
Interlocked.Exchange(ref lastLinearReport, now);
var bestDir = (h?.Count ?? 0) >= (v?.Count ?? 0) ? "H" : "V";
var bestCount = System.Math.Max(h?.Count ?? 0, v?.Count ?? 0); var bestCount = System.Math.Max(h?.Count ?? 0, v?.Count ?? 0);
progress.Report(new NestProgress progress?.Report(new NestProgress
{ {
Phase = NestPhase.Linear, Phase = NestPhase.Linear,
PlateNumber = PlateNumber, PlateNumber = PlateNumber,
Description = $"Linear: {angleDeg:F0}° {bestDir} - {bestCount} parts" Description = $"Linear: {done}/{angles.Count} angles, {angleDeg:F0}° = {bestCount} parts"
}); });
}
}); });
linearSw.Stop(); linearSw.Stop();
AngleResults.AddRange(angleBag); AngleResults.AddRange(angleBag);
@@ -522,8 +517,8 @@ namespace OpenNest
try try
{ {
var pairsSw = Stopwatch.StartNew(); var pairsCompleted = 0;
long lastPairsReport = 0; var pairsBestCount = 0;
System.Threading.Tasks.Parallel.For(0, candidates.Count, System.Threading.Tasks.Parallel.For(0, candidates.Count,
new System.Threading.Tasks.ParallelOptions { CancellationToken = token }, new System.Threading.Tasks.ParallelOptions { CancellationToken = token },
@@ -538,17 +533,14 @@ namespace OpenNest
if (filled != null && filled.Count > 0) if (filled != null && filled.Count > 0)
resultBag.Add((FillScore.Compute(filled, workArea), filled)); resultBag.Add((FillScore.Compute(filled, workArea), filled));
var now = pairsSw.ElapsedMilliseconds; var done = Interlocked.Increment(ref pairsCompleted);
if (progress != null && now - Interlocked.Read(ref lastPairsReport) >= 150) InterlockedMax(ref pairsBestCount, filled?.Count ?? 0);
{ progress?.Report(new NestProgress
Interlocked.Exchange(ref lastPairsReport, now);
progress.Report(new NestProgress
{ {
Phase = NestPhase.Pairs, Phase = NestPhase.Pairs,
PlateNumber = PlateNumber, PlateNumber = PlateNumber,
Description = $"Pairs: candidate {i + 1}/{candidates.Count} - {filled?.Count ?? 0} parts" Description = $"Pairs: {done}/{candidates.Count} candidates, best = {pairsBestCount} parts"
}); });
}
}); });
} }
catch (OperationCanceledException) catch (OperationCanceledException)
@@ -1103,5 +1095,15 @@ namespace OpenNest
return result; return result;
} }
private static void InterlockedMax(ref int location, int value)
{
int current;
do
{
current = location;
if (value <= current) return;
} while (Interlocked.CompareExchange(ref location, value, current) != current);
}
} }
} }