refactor: simplify NestProgress with computed properties and ProgressReport struct
Replace stored property setters (BestPartCount, BestDensity, NestedWidth, NestedLength, NestedArea) with computed properties that derive values from BestParts, with a lazy cache invalidated on setter. Add internal ProgressReport struct to replace the 7-parameter ReportProgress signature. Update all 13 callsites and AccumulatingProgress. Delete FormatPhaseName in favor of NestPhase.ShortName() extension. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -66,8 +66,15 @@ namespace OpenNest
|
|||||||
if (item.Quantity > 0 && best.Count > item.Quantity)
|
if (item.Quantity > 0 && best.Count > item.Quantity)
|
||||||
best = ShrinkFiller.TrimToCount(best, item.Quantity, ShrinkAxis.Width);
|
best = ShrinkFiller.TrimToCount(best, item.Quantity, ShrinkAxis.Width);
|
||||||
|
|
||||||
ReportProgress(progress, WinnerPhase, PlateNumber, best, workArea, BuildProgressSummary(),
|
ReportProgress(progress, new ProgressReport
|
||||||
isOverallBest: true);
|
{
|
||||||
|
Phase = WinnerPhase,
|
||||||
|
PlateNumber = PlateNumber,
|
||||||
|
Parts = best,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = BuildProgressSummary(),
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
|
|
||||||
return best;
|
return best;
|
||||||
}
|
}
|
||||||
@@ -94,8 +101,15 @@ namespace OpenNest
|
|||||||
|
|
||||||
Debug.WriteLine($"[Fill(groupParts,Box)] Linear pattern: {best?.Count ?? 0} parts | WorkArea: {workArea.Width:F1}x{workArea.Length:F1}");
|
Debug.WriteLine($"[Fill(groupParts,Box)] Linear pattern: {best?.Count ?? 0} parts | WorkArea: {workArea.Width:F1}x{workArea.Length:F1}");
|
||||||
|
|
||||||
ReportProgress(progress, NestPhase.Linear, PlateNumber, best, workArea, BuildProgressSummary(),
|
ReportProgress(progress, new ProgressReport
|
||||||
isOverallBest: true);
|
{
|
||||||
|
Phase = NestPhase.Linear,
|
||||||
|
PlateNumber = PlateNumber,
|
||||||
|
Parts = best,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = BuildProgressSummary(),
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
|
|
||||||
return best ?? new List<Part>();
|
return best ?? new List<Part>();
|
||||||
}
|
}
|
||||||
@@ -151,9 +165,15 @@ namespace OpenNest
|
|||||||
|
|
||||||
if (context.CurrentBest != null && context.CurrentBest.Count > 0)
|
if (context.CurrentBest != null && context.CurrentBest.Count > 0)
|
||||||
{
|
{
|
||||||
ReportProgress(context.Progress, context.WinnerPhase, PlateNumber,
|
ReportProgress(context.Progress, new ProgressReport
|
||||||
context.CurrentBest, context.WorkArea, BuildProgressSummary(),
|
{
|
||||||
isOverallBest: true);
|
Phase = context.WinnerPhase,
|
||||||
|
PlateNumber = PlateNumber,
|
||||||
|
Parts = context.CurrentBest,
|
||||||
|
WorkArea = context.WorkArea,
|
||||||
|
Description = BuildProgressSummary(),
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ namespace OpenNest.Engine.Fill
|
|||||||
combined.AddRange(previousParts);
|
combined.AddRange(previousParts);
|
||||||
combined.AddRange(value.BestParts);
|
combined.AddRange(value.BestParts);
|
||||||
value.BestParts = combined;
|
value.BestParts = combined;
|
||||||
value.BestPartCount = combined.Count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inner.Report(value);
|
inner.Report(value);
|
||||||
|
|||||||
@@ -36,18 +36,36 @@ namespace OpenNest.Engine.Fill
|
|||||||
if (column.Count == 0)
|
if (column.Count == 0)
|
||||||
return new List<Part>();
|
return new List<Part>();
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Extents, plateNumber,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
column, workArea, $"Extents: initial column {column.Count} parts");
|
{
|
||||||
|
Phase = NestPhase.Extents,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = column,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"Extents: initial column {column.Count} parts",
|
||||||
|
});
|
||||||
|
|
||||||
var adjusted = AdjustColumn(pair.Value, column, token);
|
var adjusted = AdjustColumn(pair.Value, column, token);
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Extents, plateNumber,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
adjusted, workArea, $"Extents: adjusted column {adjusted.Count} parts");
|
{
|
||||||
|
Phase = NestPhase.Extents,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = adjusted,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"Extents: adjusted column {adjusted.Count} parts",
|
||||||
|
});
|
||||||
|
|
||||||
var result = RepeatColumns(adjusted, token);
|
var result = RepeatColumns(adjusted, token);
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Extents, plateNumber,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
result, workArea, $"Extents: {result.Count} parts total");
|
{
|
||||||
|
Phase = NestPhase.Extents,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = result,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"Extents: {result.Count} parts total",
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,8 +108,15 @@ namespace OpenNest.Engine.Fill
|
|||||||
var allParts = new List<Part>(placedSoFar.Count + best.Count);
|
var allParts = new List<Part>(placedSoFar.Count + best.Count);
|
||||||
allParts.AddRange(placedSoFar);
|
allParts.AddRange(placedSoFar);
|
||||||
allParts.AddRange(best);
|
allParts.AddRange(best);
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Custom, plateNumber,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
allParts, box, $"Shrink: {best.Count} parts placed", isOverallBest: true);
|
{
|
||||||
|
Phase = NestPhase.Custom,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = allParts,
|
||||||
|
WorkArea = box,
|
||||||
|
Description = $"Shrink: {best.Count} parts placed",
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accumulate for the next item's progress reports.
|
// Accumulate for the next item's progress reports.
|
||||||
|
|||||||
@@ -88,8 +88,14 @@ namespace OpenNest.Engine.Fill
|
|||||||
sinceImproved++;
|
sinceImproved++;
|
||||||
}
|
}
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Pairs, plateNumber, best, workArea,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
$"Pairs: {i + 1}/{candidates.Count} candidates, best = {best?.Count ?? 0} parts");
|
{
|
||||||
|
Phase = NestPhase.Pairs,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = best,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"Pairs: {i + 1}/{candidates.Count} candidates, best = {best?.Count ?? 0} parts",
|
||||||
|
});
|
||||||
|
|
||||||
if (i + 1 >= EarlyExitMinTried && sinceImproved >= EarlyExitStaleLimit)
|
if (i + 1 >= EarlyExitMinTried && sinceImproved >= EarlyExitStaleLimit)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -79,8 +79,14 @@ namespace OpenNest.Engine.Fill
|
|||||||
|
|
||||||
var desc = $"Shrink {axis}: {bestParts.Count} parts, dim={dim:F1}";
|
var desc = $"Shrink {axis}: {bestParts.Count} parts, dim={dim:F1}";
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Custom, plateNumber,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
allParts, workArea, desc);
|
{
|
||||||
|
Phase = NestPhase.Custom,
|
||||||
|
PlateNumber = plateNumber,
|
||||||
|
Parts = allParts,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = desc,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -93,9 +93,14 @@ public class StripeFiller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(_context.Progress, NestPhase.Custom,
|
NestEngineBase.ReportProgress(_context.Progress, new ProgressReport
|
||||||
_context.PlateNumber, bestParts, workArea,
|
{
|
||||||
$"{strategyName}: {i + 1}/{bestFits.Count} pairs, best = {bestParts?.Count ?? 0} parts");
|
Phase = NestPhase.Custom,
|
||||||
|
PlateNumber = _context.PlateNumber,
|
||||||
|
Parts = bestParts,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"{strategyName}: {i + 1}/{bestFits.Count} pairs, best = {bestParts?.Count ?? 0} parts",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return bestParts ?? new List<Part>();
|
return bestParts ?? new List<Part>();
|
||||||
|
|||||||
@@ -210,55 +210,26 @@ namespace OpenNest
|
|||||||
// --- Protected utilities ---
|
// --- Protected utilities ---
|
||||||
|
|
||||||
internal static void ReportProgress(
|
internal static void ReportProgress(
|
||||||
IProgress<NestProgress> progress,
|
IProgress<NestProgress> progress, ProgressReport report)
|
||||||
NestPhase phase,
|
|
||||||
int plateNumber,
|
|
||||||
List<Part> best,
|
|
||||||
Box workArea,
|
|
||||||
string description,
|
|
||||||
bool isOverallBest = false)
|
|
||||||
{
|
{
|
||||||
if (progress == null || best == null || best.Count == 0)
|
if (progress == null || report.Parts == null || report.Parts.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var score = FillScore.Compute(best, workArea);
|
var clonedParts = new List<Part>(report.Parts.Count);
|
||||||
var clonedParts = new List<Part>(best.Count);
|
foreach (var part in report.Parts)
|
||||||
var totalPartArea = 0.0;
|
|
||||||
|
|
||||||
foreach (var part in best)
|
|
||||||
{
|
|
||||||
clonedParts.Add((Part)part.Clone());
|
clonedParts.Add((Part)part.Clone());
|
||||||
totalPartArea += part.BaseDrawing.Area;
|
|
||||||
}
|
|
||||||
|
|
||||||
var bounds = best.GetBoundingBox();
|
Debug.WriteLine($"[Progress] Phase={report.Phase}, Plate={report.PlateNumber}, " +
|
||||||
|
$"Parts={clonedParts.Count} | {report.Description}");
|
||||||
var msg = $"[Progress] Phase={phase}, Plate={plateNumber}, Parts={score.Count}, " +
|
|
||||||
$"Density={score.Density:P1}, Nested={bounds.Width:F1}x{bounds.Length:F1}, " +
|
|
||||||
$"PartArea={totalPartArea:F0}, Remnant={workArea.Area() - totalPartArea:F0}, " +
|
|
||||||
$"WorkArea={workArea.Width:F1}x{workArea.Length:F1} | {description}";
|
|
||||||
Debug.WriteLine(msg);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
System.IO.File.AppendAllText(
|
|
||||||
System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "nest-debug.log"),
|
|
||||||
$"{DateTime.Now:HH:mm:ss.fff} {msg}\n");
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
|
|
||||||
progress.Report(new NestProgress
|
progress.Report(new NestProgress
|
||||||
{
|
{
|
||||||
Phase = phase,
|
Phase = report.Phase,
|
||||||
PlateNumber = plateNumber,
|
PlateNumber = report.PlateNumber,
|
||||||
BestPartCount = score.Count,
|
|
||||||
BestDensity = score.Density,
|
|
||||||
NestedWidth = bounds.Width,
|
|
||||||
NestedLength = bounds.Length,
|
|
||||||
NestedArea = totalPartArea,
|
|
||||||
BestParts = clonedParts,
|
BestParts = clonedParts,
|
||||||
Description = description,
|
Description = report.Description,
|
||||||
ActiveWorkArea = workArea,
|
ActiveWorkArea = report.WorkArea,
|
||||||
IsOverallBest = isOverallBest,
|
IsOverallBest = report.IsOverallBest,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +241,7 @@ namespace OpenNest
|
|||||||
var parts = new List<string>(PhaseResults.Count);
|
var parts = new List<string>(PhaseResults.Count);
|
||||||
|
|
||||||
foreach (var r in PhaseResults)
|
foreach (var r in PhaseResults)
|
||||||
parts.Add($"{FormatPhaseName(r.Phase)}: {r.PartCount}");
|
parts.Add($"{r.Phase.ShortName()}: {r.PartCount}");
|
||||||
|
|
||||||
return string.Join(" | ", parts);
|
return string.Join(" | ", parts);
|
||||||
}
|
}
|
||||||
@@ -323,17 +294,5 @@ namespace OpenNest
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static string FormatPhaseName(NestPhase phase)
|
|
||||||
{
|
|
||||||
switch (phase)
|
|
||||||
{
|
|
||||||
case NestPhase.Pairs: return "Pairs";
|
|
||||||
case NestPhase.Linear: return "Linear";
|
|
||||||
case NestPhase.RectBestFit: return "BestFit";
|
|
||||||
case NestPhase.Extents: return "Extents";
|
|
||||||
case NestPhase.Custom: return "Custom";
|
|
||||||
default: return phase.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,18 +70,93 @@ namespace OpenNest
|
|||||||
public int PartCount { get; set; }
|
public int PartCount { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal readonly struct ProgressReport
|
||||||
|
{
|
||||||
|
public NestPhase Phase { get; init; }
|
||||||
|
public int PlateNumber { get; init; }
|
||||||
|
public List<Part> Parts { get; init; }
|
||||||
|
public Box WorkArea { get; init; }
|
||||||
|
public string Description { get; init; }
|
||||||
|
public bool IsOverallBest { get; init; }
|
||||||
|
}
|
||||||
|
|
||||||
public class NestProgress
|
public class NestProgress
|
||||||
{
|
{
|
||||||
public NestPhase Phase { get; set; }
|
public NestPhase Phase { get; set; }
|
||||||
public int PlateNumber { get; set; }
|
public int PlateNumber { get; set; }
|
||||||
public int BestPartCount { get; set; }
|
|
||||||
public double BestDensity { get; set; }
|
private List<Part> bestParts;
|
||||||
public double NestedWidth { get; set; }
|
public List<Part> BestParts
|
||||||
public double NestedLength { get; set; }
|
{
|
||||||
public double NestedArea { get; set; }
|
get => bestParts;
|
||||||
public List<Part> BestParts { get; set; }
|
set { bestParts = value; cachedParts = null; }
|
||||||
|
}
|
||||||
|
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public Box ActiveWorkArea { get; set; }
|
public Box ActiveWorkArea { get; set; }
|
||||||
public bool IsOverallBest { get; set; }
|
public bool IsOverallBest { get; set; }
|
||||||
|
|
||||||
|
public int BestPartCount => BestParts?.Count ?? 0;
|
||||||
|
|
||||||
|
private List<Part> cachedParts;
|
||||||
|
private Box cachedBounds;
|
||||||
|
private double cachedPartArea;
|
||||||
|
|
||||||
|
private void EnsureCache()
|
||||||
|
{
|
||||||
|
if (cachedParts == bestParts) return;
|
||||||
|
cachedParts = bestParts;
|
||||||
|
if (bestParts == null || bestParts.Count == 0)
|
||||||
|
{
|
||||||
|
cachedBounds = default;
|
||||||
|
cachedPartArea = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cachedBounds = bestParts.GetBoundingBox();
|
||||||
|
cachedPartArea = 0;
|
||||||
|
foreach (var p in bestParts)
|
||||||
|
cachedPartArea += p.BaseDrawing.Area;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double BestDensity
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BestParts == null || BestParts.Count == 0) return 0;
|
||||||
|
EnsureCache();
|
||||||
|
var bboxArea = cachedBounds.Width * cachedBounds.Length;
|
||||||
|
return bboxArea > 0 ? cachedPartArea / bboxArea : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double NestedWidth
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BestParts == null || BestParts.Count == 0) return 0;
|
||||||
|
EnsureCache();
|
||||||
|
return cachedBounds.Width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double NestedLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BestParts == null || BestParts.Count == 0) return 0;
|
||||||
|
EnsureCache();
|
||||||
|
return cachedBounds.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double NestedArea
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (BestParts == null || BestParts.Count == 0) return 0;
|
||||||
|
EnsureCache();
|
||||||
|
return cachedPartArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,8 +74,15 @@ namespace OpenNest.Engine.Nfp
|
|||||||
|
|
||||||
Debug.WriteLine($"[AutoNest] Result: {parts.Count} parts placed, {result.Iterations} SA iterations");
|
Debug.WriteLine($"[AutoNest] Result: {parts.Count} parts placed, {result.Iterations} SA iterations");
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Nfp, 0, parts, workArea,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
$"NFP: {parts.Count} parts, {result.Iterations} iterations", isOverallBest: true);
|
{
|
||||||
|
Phase = NestPhase.Nfp,
|
||||||
|
PlateNumber = 0,
|
||||||
|
Parts = parts,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"NFP: {parts.Count} parts, {result.Iterations} iterations",
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
|
|
||||||
return parts;
|
return parts;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -277,8 +277,15 @@ namespace OpenNest.Engine.Nfp
|
|||||||
private static void ReportBest(IProgress<NestProgress> progress, List<Part> parts,
|
private static void ReportBest(IProgress<NestProgress> progress, List<Part> parts,
|
||||||
Box workArea, string description)
|
Box workArea, string description)
|
||||||
{
|
{
|
||||||
NestEngineBase.ReportProgress(progress, NestPhase.Nfp, 0, parts, workArea,
|
NestEngineBase.ReportProgress(progress, new ProgressReport
|
||||||
description, isOverallBest: true);
|
{
|
||||||
|
Phase = NestPhase.Nfp,
|
||||||
|
PlateNumber = 0,
|
||||||
|
Parts = parts,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = description,
|
||||||
|
IsOverallBest = true,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,9 +47,14 @@ namespace OpenNest.Engine.Strategies
|
|||||||
best = result;
|
best = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
NestEngineBase.ReportProgress(context.Progress, NestPhase.Linear,
|
NestEngineBase.ReportProgress(context.Progress, new ProgressReport
|
||||||
context.PlateNumber, best, workArea,
|
{
|
||||||
$"Linear: {ai + 1}/{angles.Count} angles, {angleDeg:F0}° best = {best?.Count ?? 0} parts");
|
Phase = NestPhase.Linear,
|
||||||
|
PlateNumber = context.PlateNumber,
|
||||||
|
Parts = best,
|
||||||
|
WorkArea = workArea,
|
||||||
|
Description = $"Linear: {ai + 1}/{angles.Count} angles, {angleDeg:F0}° best = {best?.Count ?? 0} parts",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return best ?? new List<Part>();
|
return best ?? new List<Part>();
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public class AccumulatingProgressTests
|
|||||||
var accumulating = new AccumulatingProgress(inner, previous);
|
var accumulating = new AccumulatingProgress(inner, previous);
|
||||||
|
|
||||||
var newParts = new List<Part> { TestHelpers.MakePartAt(20, 0, 10) };
|
var newParts = new List<Part> { TestHelpers.MakePartAt(20, 0, 10) };
|
||||||
accumulating.Report(new NestProgress { BestParts = newParts, BestPartCount = 1 });
|
accumulating.Report(new NestProgress { BestParts = newParts });
|
||||||
|
|
||||||
Assert.NotNull(inner.Last);
|
Assert.NotNull(inner.Last);
|
||||||
Assert.Equal(2, inner.Last.BestParts.Count);
|
Assert.Equal(2, inner.Last.BestParts.Count);
|
||||||
@@ -32,7 +32,7 @@ public class AccumulatingProgressTests
|
|||||||
var accumulating = new AccumulatingProgress(inner, new List<Part>());
|
var accumulating = new AccumulatingProgress(inner, new List<Part>());
|
||||||
|
|
||||||
var newParts = new List<Part> { TestHelpers.MakePartAt(0, 0, 10) };
|
var newParts = new List<Part> { TestHelpers.MakePartAt(0, 0, 10) };
|
||||||
accumulating.Report(new NestProgress { BestParts = newParts, BestPartCount = 1 });
|
accumulating.Report(new NestProgress { BestParts = newParts });
|
||||||
|
|
||||||
Assert.NotNull(inner.Last);
|
Assert.NotNull(inner.Last);
|
||||||
Assert.Single(inner.Last.BestParts);
|
Assert.Single(inner.Last.BestParts);
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
using OpenNest.Geometry;
|
||||||
|
|
||||||
|
namespace OpenNest.Tests;
|
||||||
|
|
||||||
|
public class NestProgressTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void BestPartCount_NullParts_ReturnsZero()
|
||||||
|
{
|
||||||
|
var progress = new NestProgress { BestParts = null };
|
||||||
|
Assert.Equal(0, progress.BestPartCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BestPartCount_ReturnsBestPartsCount()
|
||||||
|
{
|
||||||
|
var parts = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(10, 0, 5),
|
||||||
|
};
|
||||||
|
var progress = new NestProgress { BestParts = parts };
|
||||||
|
Assert.Equal(2, progress.BestPartCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BestDensity_NullParts_ReturnsZero()
|
||||||
|
{
|
||||||
|
var progress = new NestProgress { BestParts = null };
|
||||||
|
Assert.Equal(0, progress.BestDensity);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void BestDensity_MatchesFillScoreFormula()
|
||||||
|
{
|
||||||
|
var parts = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(5, 0, 5),
|
||||||
|
};
|
||||||
|
var workArea = new Box(0, 0, 100, 100);
|
||||||
|
var progress = new NestProgress { BestParts = parts, ActiveWorkArea = workArea };
|
||||||
|
Assert.Equal(1.0, progress.BestDensity, precision: 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NestedWidth_ReturnsPartsSpan()
|
||||||
|
{
|
||||||
|
var parts = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(10, 0, 5),
|
||||||
|
};
|
||||||
|
var progress = new NestProgress { BestParts = parts };
|
||||||
|
Assert.Equal(15, progress.NestedWidth, precision: 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NestedLength_ReturnsPartsSpan()
|
||||||
|
{
|
||||||
|
var parts = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(0, 10, 5),
|
||||||
|
};
|
||||||
|
var progress = new NestProgress { BestParts = parts };
|
||||||
|
Assert.Equal(15, progress.NestedLength, precision: 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void NestedArea_ReturnsSumOfPartAreas()
|
||||||
|
{
|
||||||
|
var parts = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(10, 0, 5),
|
||||||
|
};
|
||||||
|
var progress = new NestProgress { BestParts = parts };
|
||||||
|
Assert.Equal(50, progress.NestedArea, precision: 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void SettingBestParts_InvalidatesCache()
|
||||||
|
{
|
||||||
|
var parts1 = new List<Part> { TestHelpers.MakePartAt(0, 0, 5) };
|
||||||
|
var parts2 = new List<Part>
|
||||||
|
{
|
||||||
|
TestHelpers.MakePartAt(0, 0, 5),
|
||||||
|
TestHelpers.MakePartAt(10, 0, 5),
|
||||||
|
};
|
||||||
|
|
||||||
|
var progress = new NestProgress { BestParts = parts1 };
|
||||||
|
Assert.Equal(1, progress.BestPartCount);
|
||||||
|
Assert.Equal(25, progress.NestedArea, precision: 4);
|
||||||
|
|
||||||
|
progress.BestParts = parts2;
|
||||||
|
Assert.Equal(2, progress.BestPartCount);
|
||||||
|
Assert.Equal(50, progress.NestedArea, precision: 4);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user