refactor(engine): extract progress reporting seam

This commit is contained in:
aj
2026-09-21 14:43:46 -04:00
parent 451841401a
commit 9b9e510510
6 changed files with 118 additions and 26 deletions
@@ -0,0 +1,75 @@
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
namespace OpenNest.Engine.Tests.Jobs;
public class PlateFillerContractTests
{
[Fact]
public void NestProgressReporter_Report_ClonesPartsAndPreservesReportFields()
{
var source = new Part(
new Drawing("part", TestDrawingFactory.Rectangle(10, 20)),
new Vector(3, 5)
);
source.Rotate(0.5);
var progress = new CapturingProgress();
var workArea = new Box(1, 2, 30, 40);
NestProgressReporter.Report(
progress,
new ProgressReport
{
Phase = NestPhase.Pairs,
PlateNumber = 3,
Parts = new List<Part> { source },
WorkArea = workArea,
Description = "candidate preview",
IsOverallBest = true,
}
);
var reported = Assert.Single(progress.Reports);
Assert.Equal(NestPhase.Pairs, reported.Phase);
Assert.Equal(3, reported.PlateNumber);
Assert.Equal("candidate preview", reported.Description);
Assert.True(reported.IsOverallBest);
Assert.Equal(workArea.X, reported.ActiveWorkArea.X);
Assert.Equal(workArea.Y, reported.ActiveWorkArea.Y);
Assert.Equal(workArea.Width, reported.ActiveWorkArea.Width);
Assert.Equal(workArea.Length, reported.ActiveWorkArea.Length);
var preview = Assert.Single(reported.BestParts);
Assert.NotSame(source, preview);
Assert.Same(source.BaseDrawing, preview.BaseDrawing);
Assert.Equal(source.Location.X, preview.Location.X);
Assert.Equal(source.Location.Y, preview.Location.Y);
Assert.Equal(source.Rotation, preview.Rotation);
}
[Fact]
public void NestProgressReporter_Report_DoesNotForwardMissingProgressOrParts()
{
var progress = new CapturingProgress();
var part = new Part(new Drawing("part", TestDrawingFactory.Rectangle()));
NestProgressReporter.Report(
null,
new ProgressReport { Parts = new List<Part> { part } }
);
NestProgressReporter.Report(progress, new ProgressReport { Parts = null });
NestProgressReporter.Report(progress, new ProgressReport { Parts = new List<Part>() });
Assert.Empty(progress.Reports);
}
private sealed class CapturingProgress : IProgress<NestProgress>
{
public List<NestProgress> Reports { get; } = new();
public void Report(NestProgress value)
{
Reports.Add(value);
}
}
}
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
namespace OpenNest.Engine.Fill
@@ -136,7 +137,7 @@ namespace OpenNest.Engine.Fill
var allParts = new List<Part>(placedSoFar.Count + best.Count);
allParts.AddRange(placedSoFar);
allParts.AddRange(best);
NestEngineBase.ReportProgress(
NestProgressReporter.Report(
progress,
new ProgressReport
{
+2 -1
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using OpenNest.Geometry;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Engine.RectanglePacking;
namespace OpenNest.Engine.Fill
@@ -89,7 +90,7 @@ namespace OpenNest.Engine.Fill
var desc = $"Shrink {axis}: {bestParts.Count} parts, dim={dim:F1}";
NestEngineBase.ReportProgress(
NestProgressReporter.Report(
progress,
new ProgressReport
{
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace OpenNest.Engine.Jobs.Placement.Fillers;
internal static class NestProgressReporter
{
internal static void Report(IProgress<NestProgress> progress, ProgressReport report)
{
if (progress == null || report.Parts == null || report.Parts.Count == 0)
return;
var clonedParts = new List<Part>(report.Parts.Count);
foreach (var part in report.Parts)
clonedParts.Add((Part)part.Clone());
Debug.WriteLine(
$"[Progress] Phase={report.Phase}, Plate={report.PlateNumber}, "
+ $"Parts={clonedParts.Count} | {report.Description}"
);
progress.Report(
new NestProgress
{
Phase = report.Phase,
PlateNumber = report.PlateNumber,
BestParts = clonedParts,
Description = report.Description,
ActiveWorkArea = report.WorkArea,
IsOverallBest = report.IsOverallBest,
}
);
}
}
+2 -23
View File
@@ -6,6 +6,7 @@ using System.Threading;
using OpenNest.Engine;
using OpenNest.Engine.BestFit;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Engine.Strategies;
using OpenNest.Geometry;
using OpenNest.Math;
@@ -261,29 +262,7 @@ namespace OpenNest.Engine
internal static void ReportProgress(IProgress<NestProgress> progress, ProgressReport report)
{
if (progress == null || report.Parts == null || report.Parts.Count == 0)
return;
var clonedParts = new List<Part>(report.Parts.Count);
foreach (var part in report.Parts)
clonedParts.Add((Part)part.Clone());
Debug.WriteLine(
$"[Progress] Phase={report.Phase}, Plate={report.PlateNumber}, "
+ $"Parts={clonedParts.Count} | {report.Description}"
);
progress.Report(
new NestProgress
{
Phase = report.Phase,
PlateNumber = report.PlateNumber,
BestParts = clonedParts,
Description = report.Description,
ActiveWorkArea = report.WorkArea,
IsOverallBest = report.IsOverallBest,
}
);
NestProgressReporter.Report(progress, report);
}
protected string BuildProgressSummary()
+2 -1
View File
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Threading;
using OpenNest.Engine;
using OpenNest.Engine.Fill;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
namespace OpenNest.Engine.Strategies
@@ -50,7 +51,7 @@ namespace OpenNest.Engine.Strategies
WinnerPhase = ActivePhase;
}
NestEngineBase.ReportProgress(
NestProgressReporter.Report(
Progress,
new ProgressReport
{