Revert "feat(engine): live sheet preview while Irregular packs"

This reverts commit 9f0e536eeed85e4417f285b94913e03f594400f7.
This commit is contained in:
aj committed 2026-10-18 23:56:38 -04:00
1 parent b11225135e
commit a2fb945669
5 files changed
+5 -114

No files matched your search

@@ -1,13 +1,13 @@
using OpenNest.Engine.NestingEngines.Irregular;
using static OpenNest.Engine.Tests.NestingEngines.JobBuilder;
using static OpenNest.Engine.Tests.NestingEngines.Shapes;
using System;
using System.Collections.Generic;
using System.Linq;
using OpenNest.CNC;
using OpenNest.Engine.Jobs;
using OpenNest.Engine.Jobs.Adapters;
using OpenNest.Engine.NestingEngines.Irregular;
using OpenNest.Geometry;
using static OpenNest.Engine.Tests.NestingEngines.JobBuilder;
using static OpenNest.Engine.Tests.NestingEngines.Shapes;
namespace OpenNest.Engine.Tests.NestingEngines;
@@ -211,42 +211,6 @@ public class IrregularNestingEngineTests
Assert.Equal(2, Assert.Single(result.Plates).Placements.Count);
}
[Fact]
public void ReportsLiveSheetPreviewWithoutChangingTheLayout()
{
var job = Job(new[] { Part("disc", Disc(3), 10), Part("ell", LShape(12, 8, 4), 10) },
new[] { Stock("sheet", 40, 60, spacing: 0.5) });
var reports = new List<NestJobProgress>();
var withPreview = new IrregularNestingEngine().Solve(job, new SyncProgress(reports.Add));
var without = new IrregularNestingEngine().Solve(job);
var previews = reports.Where(r => r.LegacyProgress?.BestParts is { Count: > 0 }).ToList();
Assert.NotEmpty(previews);
var work = job.Plates[0].WorkArea;
foreach (var preview in previews.Select(r => r.LegacyProgress))
{
Assert.True(preview.IsOverallBest);
Assert.Equal((work.Left, work.Bottom, work.Right, work.Top), (preview.ActiveWorkArea.Left,
preview.ActiveWorkArea.Bottom, preview.ActiveWorkArea.Right, preview.ActiveWorkArea.Top));
foreach (var part in preview.BestParts)
{
Assert.InRange(part.BoundingBox.Left, work.Left - 1e-6, work.Right);
Assert.InRange(part.BoundingBox.Right, work.Left, work.Right + 1e-6);
Assert.InRange(part.BoundingBox.Bottom, work.Bottom - 1e-6, work.Top);
Assert.InRange(part.BoundingBox.Top, work.Bottom, work.Top + 1e-6);
}
}
Assert.Equal(
without.Plates.SelectMany(p => p.Placements),
withPreview.Plates.SelectMany(p => p.Placements));
}
private sealed class SyncProgress(Action<NestJobProgress> report) : IProgress<NestJobProgress>
{
public void Report(NestJobProgress value) => report(value);
}
[Fact]
public void HasPublicParameterlessConstructorForPluginDiscovery()
{
@@ -64,9 +64,6 @@ internal sealed class FrontierPacker
private readonly BlockCatalog? blocks;
private readonly ClampObstacles? clamps;
/// <summary>Observer of the placements so far (live preview); read-only, it never steers packing.</summary>
private readonly Action<IReadOnlyList<Placed>>? placedChanged;
public FrontierPacker(
IReadOnlyList<PartType> types,
NoFitCache nfps,
@@ -76,11 +73,9 @@ internal sealed class FrontierPacker
double beta,
WorkCounter counter,
BlockCatalog? blocks = null,
ClampObstacles? clamps = null,
Action<IReadOnlyList<Placed>>? placedChanged = null
ClampObstacles? clamps = null
)
{
this.placedChanged = placedChanged;
this.blocks = blocks;
this.clamps = stock.ClampZones.Count == 0 ? null : clamps ?? new ClampObstacles(stock);
this.counter = counter;
@@ -187,7 +182,6 @@ internal sealed class FrontierPacker
partArea += types[typeIndex].Area;
front = System.Math.Max(front, axis == PackAxis.X ? part.Right : part.Top);
}
placedChanged?.Invoke(placed);
left[typeIndex] -= choice.Count;
blockStates.RemoveAll(b => b.Members.Count > left[b.Members[0].Orientation.TypeIndex]);
@@ -131,7 +131,6 @@ public sealed class IrregularNestingEngine : INestingEngine
}
private const int MaxTail = 3;
private readonly SheetPreview? preview = progress == null ? null : new SheetPreview(progress, types, drawingFor);
private readonly Dictionary<double, NoFitCache> caches = new();
private readonly Dictionary<NestPlateStock, ClampObstacles> clamps = new();
private readonly Dictionary<double, IReadOnlyDictionary<int, IReadOnlyList<PairPose>>> pairs = new();
@@ -290,10 +289,8 @@ public sealed class IrregularNestingEngine : INestingEngine
if (stock.Quantity is int available && used[stock.Id] >= available)
continue;
progress?.Report(new NestJobProgress(NestJobStage.EvaluatingCandidate, stock.Id, sheets.Count, 0, 0));
var plateIndex = sheets.Count;
var packer = new FrontierPacker(types, CacheFor(stock), PairsFor(stock), stock, axis, beta, Work,
BlocksFor(stock), ClampsFor(stock),
preview == null ? null : placed => preview.Report(stock, plateIndex, placed));
BlocksFor(stock), ClampsFor(stock));
var fill = packer.Fill(remaining, token);
sheetPacked?.Invoke();
if (fill.Parts.Count > 0)
@@ -1,57 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Diagnostics;
using OpenNest.Engine.Jobs;
using OpenNest.Geometry;
namespace OpenNest.Engine.NestingEngines.Irregular;
/// <summary>
/// Live preview of the sheet a packer is filling, sent as job progress detail
/// (<see cref="NestJobProgress.LegacyProgress"/>) for front ends that draw it. Reports are
/// throttled to one per <see cref="Interval"/>; the clock only gates reporting and never feeds
/// back into packing, so the solve stays deterministic.
/// </summary>
internal sealed class SheetPreview(
IProgress<NestJobProgress> progress,
IReadOnlyList<PartType> types,
Func<NestJobPart, Drawing> drawingFor
)
{
internal static readonly TimeSpan Interval = TimeSpan.FromMilliseconds(250);
private readonly Stopwatch clock = Stopwatch.StartNew();
private TimeSpan? last;
/// <summary>Called after each placement on a sheet trial; reports when the interval has passed.</summary>
public void Report(NestPlateStock stock, int plateIndex, IReadOnlyList<Placed> placed)
{
var now = clock.Elapsed;
if (last is TimeSpan previous && now - previous < Interval)
return;
last = now;
var parts = new List<Part>(placed.Count);
foreach (var pose in placed)
{
// Same pose mapping as the materialized result: rotate about the snapshot origin, then move.
var part = new Part(drawingFor(types[pose.Orientation.TypeIndex].Part));
part.Rotate(pose.Orientation.Rotation);
part.Location = new Vector(pose.X, pose.Y);
part.UpdateBounds();
parts.Add(part);
}
progress.Report(new NestJobProgress(NestJobStage.EvaluatingCandidate, stock.Id, plateIndex, 0, 0,
new NestProgress
{
Phase = NestPhase.Custom,
PlateNumber = plateIndex + 1,
BestParts = parts,
ActiveWorkArea = stock.WorkArea,
IsOverallBest = true,
Description = $"Irregular: packing plate {plateIndex + 1} on stock {stock.Id} ({parts.Count} parts)",
}));
}
}
-7
View File
@@ -63,13 +63,6 @@ Curved outlines retain conservative flattening-error padding. This does not rela
footprints, no-fit polygons or layout validation tolerances; a part extending beyond the accepted
work-area bounds remains invalid.
While it runs with a progress sink, Irregular previews the sheet it is packing: at most four
times a second it reports the placements so far as `NestProgress.BestParts` with the stock's
work area, and desktop Auto Nest draws them on the plate view. The preview follows every trial
(each stock, sheet, strategy variant and tail re-plan), so it shows the search at work, not the
layout that will be kept. Reporting only reads finished placements, so layouts are identical
with or without a sink.
Irregular fills gaps and open notches using outer profiles; it does not yet place parts inside
enclosed cutouts. For a part with two or more copies it also offers its best-fit pairs (two copies
interlocked, as the Best Fit viewer shows them) alongside the single copies, and places a pair