Files
OpenNest/OpenNest.Engine/Jobs/Placement/PrivatePlateFill.cs
T
ajandClaude Opus 5.5 5761eefd37 refactor(engine): merge the plate fillers into one PlateFiller
DefaultPlateFiller becomes PlateFiller(plate, policy, layout); PlateFillerBase
and StripPlateFiller are gone. PlateLayout.FillThenPack is the old
orchestrator path (Fill and both Remnants); PlateLayout.Strips is the old
StripPlateFiller.Nest, and Strip is Fill policy plus Strips layout.

Lifetimes are unchanged: a strip-layout filler runs every Fill, group Fill
and PackArea on a fresh inner filler and gives each strip fresh remnant
fillers, so learned angles and PlateNumber never leak into them. The
comparer, preferred direction, trim axis and angle recording now read the
policy directly. The base class's unsorted two-angle BuildAngles is dropped:
only DefaultPlateFiller's pipeline called BuildAngles, and Strip never ran it.

Layout-neutral: all 29 FillStackCharacterizationTests pins pass unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 23:44:51 -04:00

46 lines
2.1 KiB
C#

#nullable enable
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using OpenNest.Engine.BestFit;
using OpenNest.Engine.Jobs.Adapters;
using OpenNest.Engine.Jobs.Placement.Fillers;
using OpenNest.Geometry;
namespace OpenNest.Engine.Jobs.Placement;
/// <summary>
/// Runs the Fill strategy 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
/// <see cref="BestFitCache.Invalidate"/> for it when finished.
/// </summary>
internal static class PrivatePlateFill
{
/// <param name="length">X extent of the plate and work area.</param>
/// <param name="width">Y extent of the plate and work area.</param>
/// <param name="quantity">Copies wanted; zero fills the whole area.</param>
internal static List<Part> 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);
// A positive quantity lets supporting strategies avoid surplus rows. Zero still
// fills the whole area (the cutout lattice caller requires an uncapped lattice).
var filler = new PlateFiller(plate) { StopAtQuantity = true };
return filler.Fill(new NestItem
{
Drawing = drawing,
Quantity = quantity,
RotationStart = rotation.Start,
RotationEnd = rotation.End,
StepAngle = DrawingJobMapper.LegacyStep(rotation),
}, new Box(0, 0, length, width), null!, token);
}
}