Rework OpenNest.Benchmark into a full multi-plate, multi-size nest

Previously each job fixed one plate size and ran a single Nest() call,
which doesn't reflect the actual problem: a real job is fulfilled
across however many plates are needed, drawn from a pool of standard
sheet sizes, not forced onto one fixed sheet.

NestEngineBase.Nest() has no way to pick its own plate's size - it
fills whatever Plate it's given - so size selection now lives in the
harness itself, applied identically to every engine:

- BenchmarkJob carries the full candidate size pool (CandidateSizes)
  instead of one fixed PlateSize; one job per file, not one per size.
- BenchmarkRunner drives a loop: while items remain, pick the smallest
  candidate size that fits the largest still-unplaced drawing (reusing
  the codebase's own MultiPlateNester.CreatePlate/FitsBounds), build a
  fresh plate of that size, and run one Nest() call to fill it. Repeat
  until everything is placed, no candidate size fits what's left, or a
  safety cap (40 plates) is hit.
- NestValidator now validates bounds/spacing per plate but the
  quantity cap once globally across all plates, since that limit
  belongs to the whole order, not any one sheet.
- JobResult/Report report PlatesUsed and a per-size breakdown instead
  of a single-plate bounding-box compactness metric; utilization is
  now aggregated across every plate the engine used. Ranking keeps the
  same rule (utilization first), with fewer plates as the tie-break
  when both are fully placed and tied - the natural multi-plate
  analogue of the old single-plate compactness tie-break.

Smoke-tested against the synthetic sample across 5 candidate sizes:
correctly builds one job, picks the smallest fitting size, uses
however many plates each engine needs (1-2 here), and still catches
StripNestEngine's pre-existing out-of-bounds bug.
This commit is contained in:
aj
2026-09-15 21:36:31 -04:00
parent 20da5477b6
commit a9e0f8a1d4
7 changed files with 237 additions and 113 deletions
+15 -18
View File
@@ -8,11 +8,12 @@ using System.Linq;
namespace OpenNest.Benchmark
{
/// <summary>
/// Builds BenchmarkJobs from .nest files on disk. Fully generic: works on any
/// valid .nest file, using whatever drawings/quantities/plate settings it contains.
/// Optionally sweeps a fixed list of sheet sizes instead of the sizes embedded
/// in the file, so the same drawing set can be benchmarked across a standard
/// sheet-size lineup.
/// Builds BenchmarkJobs from .nest files on disk. Fully generic: works on
/// any valid .nest file, using whatever drawings/quantities/plate settings
/// it contains. One job per file, carrying the full pool of candidate
/// sheet sizes the engine may use across the whole nest - by default the
/// distinct sizes already present in that file, or a fixed override list
/// (e.g. a standard sheet-size lineup) applied to every file.
/// </summary>
public static class JobLoader
{
@@ -46,22 +47,18 @@ namespace OpenNest.Benchmark
var template = ResolvePlateTemplate(nest);
var sizes = sheetSizeOverrides != null && sheetSizeOverrides.Count > 0
? sheetSizeOverrides
? sheetSizeOverrides.ToList()
: ResolveSheetSizes(nest);
foreach (var size in sizes)
jobs.Add(new BenchmarkJob
{
jobs.Add(new BenchmarkJob
{
SourceFile = file,
SheetSizeLabel = size.ToString(1),
PlateSize = size,
EdgeSpacing = template.EdgeSpacing,
PartSpacing = partSpacingOverride ?? template.PartSpacing,
Quadrant = template.Quadrant,
Requests = requests,
});
}
SourceFile = file,
CandidateSizes = sizes,
EdgeSpacing = template.EdgeSpacing,
PartSpacing = partSpacingOverride ?? template.PartSpacing,
Quadrant = template.Quadrant,
Requests = requests,
});
}
return jobs;