diff --git a/OpenNest.Engine/Jobs/Placement/PrivatePlateFill.cs b/OpenNest.Engine/Jobs/Placement/PrivatePlateFill.cs
new file mode 100644
index 0000000..71ca769
--- /dev/null
+++ b/OpenNest.Engine/Jobs/Placement/PrivatePlateFill.cs
@@ -0,0 +1,41 @@
+#nullable enable
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using OpenNest.Engine.BestFit;
+using OpenNest.Engine.Jobs.Adapters;
+using OpenNest.Geometry;
+
+namespace OpenNest.Engine.Jobs.Placement;
+
+///
+/// Runs the Default Fill for one private drawing on a private plate, for callers that turn the
+/// result into job poses. The caller owns the drawing and must call
+/// for it when finished.
+///
+internal static class PrivatePlateFill
+{
+ /// X extent of the plate and work area.
+ /// Y extent of the plate and work area.
+ /// Copies wanted; zero fills the whole area.
+ internal static List Run(Drawing drawing, RotationPolicy rotation, double spacing,
+ double length, double width, int quantity, CancellationToken token)
+ {
+ var plate = new Plate(new Size(width, length)) { PartSpacing = spacing };
+ // The drawing is private: stabilize this cache entry before Fill's candidate pruning.
+ var fits = BestFitCache.GetOrCompute(drawing, plate.Size.Length, plate.Size.Width, spacing);
+ var sorted = fits.OrderBy(f => f.RotatedArea).ThenBy(f => f.Candidate.StrategyIndex)
+ .ThenBy(f => f.Candidate.Part2Rotation).ThenBy(f => f.Candidate.Part2Offset.X)
+ .ThenBy(f => f.Candidate.Part2Offset.Y).ThenBy(f => f.OptimalRotation).ToArray();
+ fits.Clear();
+ fits.AddRange(sorted);
+ return PlateFillService.FillItem("Default", plate, new NestItem
+ {
+ Drawing = drawing,
+ Quantity = quantity,
+ RotationStart = rotation.Start,
+ RotationEnd = rotation.End,
+ StepAngle = DrawingJobMapper.LegacyStep(rotation),
+ }, new Box(0, 0, length, width), null!, token);
+ }
+}
diff --git a/OpenNest.Engine/NestingEngines/Irregular/BlockCatalog.cs b/OpenNest.Engine/NestingEngines/Irregular/BlockCatalog.cs
index c00b04d..78c0991 100644
--- a/OpenNest.Engine/NestingEngines/Irregular/BlockCatalog.cs
+++ b/OpenNest.Engine/NestingEngines/Irregular/BlockCatalog.cs
@@ -77,24 +77,10 @@ internal sealed class BlockCatalog : IDisposable
{
if (!drawings.TryGetValue(type.Index, out var drawing))
drawings[type.Index] = drawing = DrawingJobMapper.CreateDrawing(type.Part);
- var plate = new Plate(new Size(rectangle.Width, rectangle.Length)) { PartSpacing = spacing };
try
{
- // The drawing is private: stabilize this cache entry before Fill's candidate pruning.
- var fits = BestFitCache.GetOrCompute(drawing, plate.Size.Length, plate.Size.Width, spacing);
- var sorted = fits.OrderBy(f => f.RotatedArea).ThenBy(f => f.Candidate.StrategyIndex)
- .ThenBy(f => f.Candidate.Part2Rotation).ThenBy(f => f.Candidate.Part2Offset.X)
- .ThenBy(f => f.Candidate.Part2Offset.Y).ThenBy(f => f.OptimalRotation).ToArray();
- fits.Clear();
- fits.AddRange(sorted);
- var members = PlateFillService.FillItem("Default", plate, new NestItem
- {
- Drawing = drawing,
- Quantity = quantity,
- RotationStart = type.Part.Rotation.Start,
- RotationEnd = type.Part.Rotation.End,
- StepAngle = DrawingJobMapper.LegacyStep(type.Part.Rotation),
- }, new Box(0, 0, rectangle.Length, rectangle.Width), null!, token);
+ var members = PrivatePlateFill.Run(drawing, type.Part.Rotation, spacing,
+ rectangle.Length, rectangle.Width, quantity, token);
token.ThrowIfCancellationRequested();
return Resolve(type, members.Take(quantity).ToArray(), orientations[type.Index], spacing, token);
}