The best-fit filter rejected pairs over a 5:1 aspect (or the plate's)
unless 75% utilized. A long part such as U251-DET3 (27.4 x 3.5, aspect
7.7) is past that alone, so its tightest interlocked pairs (5.1:1) were
all dropped even though they are less elongated than the part itself.
On the 60 x 120 sheet that cost 12 parts: 66 placed instead of 78.
The limit now widens to the part's own bounding-box aspect, so
side-by-side pairs survive while end-to-end pairs of compact parts are
still rejected.
The learned-angle characterization nests re-captured: their 46 x 3 bar
now nests as an interlocked pair, which left the Fill nest identical to
a full sweep, so the notched quantity drops from 6 to 4 to keep the
fixture sensitive to learned angles.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A quantity-limited fill trimmed the parts farthest along the trim axis,
which could take one half from each of two pairs. TrimToCount now finds
interlocked pairs and keeps or drops them whole (from d1d68a91), so the
spare space stays one usable cell.
After a fill, leftovers now run in two orders, pack-first and pairs-first,
and the strategy's comparer keeps the better whole layout, so its ranking
of this step cannot get worse. Even quantities go in as best-fit pairs,
may turn a quarter when unrestricted, are tried in every remnant and are
ranked with the layout around them. Each placed pair slides left and down
against true outlines to take the space its bounding box could not.
On compare.nest Vertical Remnant goes from 6665.1 to 5862.6 and Lattice
from 7200 to 5915.8. Nine characterization pins change from the trim with
counts unchanged; the fill pins now also check layout validity. Vertical
Remnant's golden layout shortens from 28 to 26.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engine tests drew the same rectangle, square, L-shape and arc part in
private helpers across the Expander, golden-layout, fill-stack and
fixed-strategy tests. They now use TestDrawingFactory; files whose
helper had its own default size keep a one-line wrapper for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FillItem_WithClampZones has flipped between two digests because each was
correct for the machine that pinned it. PairFiller sized its parallel
batches from Environment.ProcessorCount, and a batch shares the best count
and work area from before it, so core count decides which candidates are
tried. With 10+ logical processors candidate 9 runs before the area shrinks
and its 46-part layout wins for every comparer (9BF5FC7FC47364A9); with 8 or
fewer the area has shrunk, it can only reach 45, and Fill/Strip and Vertical
Remnant settle on different 45-part ties. 40 of the parts are kept either
way. So the same nest differed between shop PCs, and CI failed whenever the
digests were pinned on a 12-thread desktop.
Fix the batch at 8, which keeps the pins CI has always produced. Also claim
GridDedup keys in candidate order before the parallel loop: the claim was a
race inside a batch, seen as one candidate returning 42 parts and then 33
in the same process.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
0719476 re-pinned the Fill, Strip and Vertical Remnant clamp-zone
characterization digests to 9BF5FC7FC47364A9, but that layout never
reproduced: CI and local Linux runs at that commit and since give the
previous digests unchanged, so Cross-platform tests has failed on every
push since. Clamp clearance defaults to the bottom edge spacing, which
these plates already used, so their layouts were never expected to move.
Checked the produced layouts before restoring them: all four strategies
place 40 parts inside the work area with no NestLayoutCheck violations
against the clamp clearance.
A clamp rail can now carry its own Clearance, the gap parts keep from
every clamp footprint, independent of part spacing. Unset, it keeps the
sheet's bottom edge spacing as before. Clamp blocks drawn under the
sheet can use close to zero so the laser only stays off them.
Plate.ClampClearance and NestPlateStock.ClampClearance resolve it once;
the engines, interactive fill/pack/push, the layout check, Expander walls
and automatic cut-off placement all read it. The interactive push now
holds clamps at their square clearance keep-out (the layout check's
shape) instead of the part spacing, so parts no longer tuck into its
corners; the clamped fill characterization digests are re-pinned after
checking the new layouts validate.
Persisted as an optional `clearance` on the .nest clamp rail and the
machine clamp settings; edited in Nest > Clamps and the machine's
Clamps tab.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FillItem_WithClampZones_PinnedLayout (Fill, Strip, Vertical Remnant) has
failed in the Engine.Tests CI job on every push since it was added in
ccd361d: the pinned digest 9BF5FC7FC47364A9 is not reproducible at that
commit or any later one, locally or on GitHub runners. The engine
deterministically yields 9B3EFF9B72243576 (Fill, Strip) and
039C0D607166D805 (Vertical Remnant) at ccd361d, 36c8de8 and master, so the
later filler consolidation is still layout-neutral for these cases.
Before repinning, all four strategies' layouts were checked: 40 parts, all
inside the work area, bounding boxes clear of both clamps, and no
overlapping parts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
NestLayoutCheck rejected Fill layouts whose interlocked arcs sat exactly
at the part spacing: its SpacingOutline circumscribes arcs by up to 0.001
each, more than the 0.0005 slack, so facing arcs overlapped. The runner's
placement validator measured inscribed 0.001 polygons instead and so
accepted gaps up to ~0.002 under the slack.
Both now find candidates with SpacingOutline and confirm them on
NativeContours, the native contours flattened at a twentieth of the slack
(moved out of PartSpacingReview, which keeps using them). The runner calls
NestLayoutCheck.KeepsSpacing, the same outline, tie rule and
confirmation, so the two validators accept exactly the same pairs.
Clears stays unconfirmed and stricter for engine certification. No
tolerance changed.
FixedStrategyEngine_IrregularJob pins now assert LayoutAssert.Valid with
unchanged digests; the NativeU 70-part grid's 28 reports were the same
cause and its test now requires none.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
BestFitFinder gathered each rotation strategy's candidates, and PairEvaluator
gathered evaluated results, in ConcurrentBags, so their order depended on which
worker finished first. The stable area sort then broke equal-area ties in that
arbitrary order, and fills, which try candidates in order and keep the first of
equal layouts, could nest the same parts differently between runs.
Both now fill index-addressed slots: candidates keep rotation-angle and
slide-offset order, results keep candidate order, and ties break the same way
every run. The candidates produced and their scores are unchanged.
The Strip whole-job pin in FillStackCharacterizationTests is re-pinned
(A66602F707290A36 -> FD03A4529D37E32C). That job ties between best-fit
pairs; the old pin recorded whichever tied pair the bag happened to return
first. The new layout places the same 26 parts, passes LayoutAssert.Valid
and gave the same digest in five separate test processes. The other 28
pins are unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Characterization digests for the interactive PlateFillService surface and
the fixed-strategy whole-job engines on L-shaped, notched, arc, bar and
chevron parts: single-item fills, whole-plate nests (including one where
learned angles change the layout, guarded by a full-sweep comparison),
fills beside clamp zones, and one job per Fill/Strip/remnant engine.
They let the planned filler/nester consolidation be shown layout-neutral.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>