Loads any .nest file (or folder of them) via NestReader and nests every drawing with quantity > 0 using each registered NestEngineBase, so it works sight-unseen against arbitrary real jobs without any hardcoded geometry. Optionally sweeps a fixed --sheet-sizes list instead of each file's own plate size. - BenchmarkJob/JobLoader build immutable job specs; a fresh Plate and NestItem list is created per (job, engine) run so state never leaks between engines or jobs. - NestValidator rejects a layout if any part falls outside the work area, any two parts are closer than PartSpacing (checked via each part's own world-space polygon inflated by the spacing, so it holds for arbitrary concave/holed geometry, not just bounding boxes), or a drawing gets more parts than requested. - Scoring matches Plate.Utilization() (placed area / full sheet area); ties among fully-placed layouts break on the smaller used bounding box (more usable remnant). - Report prints a per-job ranked breakdown plus a per-engine summary (wins, avg utilization, time), and can write a flat CSV. Verified end-to-end against a synthetic .nest file (not committed) against the four built-in engines; caught a genuine out-of-work-area bug in StripNestEngine in the process.
66 lines
2.2 KiB
C#
66 lines
2.2 KiB
C#
using OpenNest.Geometry;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
|
|
namespace OpenNest.Benchmark
|
|
{
|
|
/// <summary>
|
|
/// One request to nest a specific drawing, with the quantity and rotation
|
|
/// constraints pulled from its source .nest file.
|
|
/// </summary>
|
|
public class DrawingRequest
|
|
{
|
|
public Drawing Drawing { get; init; }
|
|
public int Quantity { get; init; }
|
|
public int Priority { get; init; }
|
|
public double StepAngle { get; init; }
|
|
public double RotationStart { get; init; }
|
|
public double RotationEnd { get; init; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// An immutable specification for one benchmark job: a set of drawings/quantities
|
|
/// to be nested onto a plate of a given size. Every engine under test gets a fresh
|
|
/// Plate and NestItem list built from this spec via CreatePlate()/CreateItems(),
|
|
/// so one engine's run can never leak mutated state into another's.
|
|
/// </summary>
|
|
public class BenchmarkJob
|
|
{
|
|
public string SourceFile { get; init; }
|
|
public string SheetSizeLabel { get; init; }
|
|
public Size PlateSize { get; init; }
|
|
public Spacing EdgeSpacing { get; init; }
|
|
public double PartSpacing { get; init; }
|
|
public int Quadrant { get; init; }
|
|
public List<DrawingRequest> Requests { get; init; }
|
|
|
|
public string Name => $"{Path.GetFileNameWithoutExtension(SourceFile)} [{SheetSizeLabel}]";
|
|
|
|
public int TotalRequestedQuantity => Requests.Sum(r => r.Quantity);
|
|
|
|
public Plate CreatePlate()
|
|
{
|
|
return new Plate(PlateSize)
|
|
{
|
|
EdgeSpacing = EdgeSpacing,
|
|
PartSpacing = PartSpacing,
|
|
Quadrant = Quadrant,
|
|
};
|
|
}
|
|
|
|
public List<NestItem> CreateItems()
|
|
{
|
|
return Requests.Select(r => new NestItem
|
|
{
|
|
Drawing = r.Drawing,
|
|
Quantity = r.Quantity,
|
|
Priority = r.Priority,
|
|
StepAngle = r.StepAngle,
|
|
RotationStart = r.RotationStart,
|
|
RotationEnd = r.RotationEnd,
|
|
}).ToList();
|
|
}
|
|
}
|
|
}
|