Nest windows now rerun the overlap check once the layout has been
unchanged for 0.5 s, instead of leaving 'Overlaps: not checked'. Edits
show 'Overlaps: check pending...'; drags are caught by the paint-time
pose stamp, collection edits by their events. The check waits while a
mouse button, modal dialog or fill is active, supersedes a running check
when the layout moves again, and does not retry a canceled or failed
layout until it changes. Rechecks use the incremental analyzer, so only
the moved parts' neighbors are recomputed.
Automatic results update only the canvas label (the status bar keeps the
last command's message) and keep Display > Off. Check Active Plate still
runs immediately. InvalidateOverlapCheck now also drops cached material.
New post-processor plugin OpenNest.Posts.CincinnatiCIFiber for the CI
Fiber laser family (nLight CLX / Beckhoff TF5200 / Precitec ProCutter,
e.g. the CI Fiber 4020 8kW). Named by machine family, not table size.
Emits the machine program contract of the Cincinnati-supplied sample NC
(12992-4SS_NEST.nc): V.E.* header, restart jump, per-part V.E.R4 blocks,
per-contour N labels with V.E.R3, skippable /L macro lines (L0/L2+G41
interior, L4+G42 exterior, L6 cut-on, ZHSOFF cut-end), G162 incremental
arc I/J, trimmed 3-decimal spaceless coordinates, CRLF, M50/M30/%.
Contour classification (interior vs exterior) derives from the material
side of the closed cut path, not hardcoded winding. SubProgramCall holes
are flattened to sheet coordinates (rotation-safe). Arc lead-ins are
rejected per TF5200 13.2.4.1 (first motion block after G41/G42 selection
must be linear). Table envelope (default 160.25 x 81.25 in) validated.
Tests: structure golden on a square-with-hole nest, rotated-hole flatten,
coordinate format, arc-lead-in rejection, table validation, suppressed/
scribe skipping, plus a SkippableFact regression against the real sample
NC (109 parts, 2071 contours, L2=1962, L4=109, perimeter vertices match
within 0.001). Fixtures configure through OpenNest.Tests/test-config.json
and the regression skips when absent.
Group the Cincinnati and GravographIS plugin projects in a Posts/
folder so new machine posts have one home. Project names, namespaces,
and the runtime Posts/ deploy target are unchanged; only relative
paths in the solution and project references move.
Long whole-job solves ran silently, so there was no way to tell a slow
engine from a hung one until the timeout fired. --progress hands each
solve a JobProgressLog that prints [job/engine] lines for start, finish
(or failure/timeout), every plate commit, and candidate evaluations
throttled to one line per 2 s so parallel runs stay readable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Engines now live in https://git.thecozycat.net/aj/OpenNest-Engines (history
carried over) so they can be published independently, and so a copy of
OpenNest handed to a model for an engine-building run contains no
competing engines. Engines still load at runtime from an Engines/ folder
next to the app/benchmark output; nothing in the solution referenced them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop deep engine/validator/benchmark internals (covered by CLAUDE.md and
code comments) and per-option reference tables in favor of a quick-start
level guide.
One-off helper utilities don't belong in the repo. PepNestExport moved to
/home/aj/src/PepNestExport as a standalone companion project; NestDxfJob and
StreamGravographJob are removed (recoverable from history).
Plugin engines (Opus55, Qwen, Terra) each add two projects at the repo
root, and more are coming; at a dozen they would outnumber the core
projects. They are also a different kind of thing: out-of-solution,
runtime-loaded plugins. Grouping them under Engines/ keeps the root
readable.
Engines/Directory.Build.props now holds the shared TFM, nullable and
implicit-usings settings and the OpenNest.Engine reference, so a new
engine's csproj is nearly empty. The tests/ compile exclusion lives in
Directory.Build.targets because a removal in .props runs before the SDK
adds its default Compile glob and has no effect.
Build-Engines.ps1 replaces the per-README manual build-and-copy steps
for deploying engines into the benchmark's runtime Engines/ folder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Converts a PepApi year of PEP nests into .nest files that keep PEP's own
placements, so OpenNest.Benchmark can score PEP as its Baseline row.
Micro-joint tabs: PEP leaves tabs uncut by jumping them with a rapid, at a
contour's seam or partway along it (a cutout cut as two halves 0.02 apart).
The part still occupies that material, so open cut runs are chained end to
start across gaps up to 0.25 and bridged with a cut line, but only where
they close into a loop, so separate contours that lie close together (two
circles 0.25 apart) are never merged. Previously only seam tabs were closed,
leaving mid-contour tabbed cutouts open and the validator reading them as
garbage regions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spacing offsets now go through Clipper for CPU preparation while the
per-pair Collision test stays hand-rolled for a future GPU port; record
that split, which offset path each caller uses, and the missing Clipper2
entry in the NuGet list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The benchmark is about to be used as the objective for LLM-designed
engines, and several gaps would have rewarded the wrong behavior:
- Ranking was utilization-first, so dropping awkward parts raised the
score. Rank valid > fully placed > cost > plates, where cost is
salvage-credited sheet area plus a largest-sheet penalty per unplaced
part; placing a part is never scored worse than omitting it.
- Salvage rate was ignored in scoring; cost now uses EstimateNetArea,
recomputed from job geometry rather than trusted from the engine.
- Rotation constraints were never validated. Add RotationPolicy.Allows
(shared with NestJobPlacementValidator) and check every placement.
- Returned sheets were trusted, so an engine could loosen spacing or
invent a size. Sheets must now match offered stock.
- Part-in-part placements were flagged as overlaps; spacing now accounts
for cutouts, with an X-sorted sweep to prune distant pairs.
- Summary averaged per-job percentages; it now sums areas and cost.
- --spacing and sheet sizes parsed with the current culture.
- Warn when .nest jobs offer only their original sheet sizes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Console --engine now names a jobs engine for --autonest (solved once
through NestingEngineRegistry.Create and committed onto the plate) or a
built-in fill strategy for single-plate fill through the public
PlateFillService; unknown names exit with the valid choices instead of
consulting the process-global legacy registry. MCP nesting tools take an
explicit engine argument per call with the session default, never read
process-global active-engine state, and reject whole-job engine names on
single-plate fill tools. NestingEngineRegistry gains an explicit Create
(name) resolution; PlateFillService gains a public ResolveStrategy and a
plate-number Nest overload used by interactive callers.
NestDxfJob imports a DXF folder plus a quantity workbook, runs a
registered whole-job engine, and only publishes a nest that passes
quantity, bounds, overlap/spacing, and cut-only checks both before and
after save/reload. Writes import and validation reports; partial or
invalid results exit nonzero. Standalone project (not in the solution);
documented in the README.
Benchmark jobs could only come from .nest files. A JSON manifest now lists
DXF files with quantities (plus sheet sizes, spacing, edge spacing, quadrant
and per-part allowRotation), imported through CadImporter. DXF paths resolve
relative to the manifest; sheet sizes are required from the manifest or
--sheet-sizes and are read in the DXFs' own units. Folder scans pick up
*.nest and *.manifest.json, and invalid manifests fail loudly.
BenchmarkRunner now runs (job x engine) solves concurrently, capped by
--parallel N (CLI default 3; --parallel 1 is sequential). Results are written
by index so report order is unchanged. Concurrent solves compete for cores,
so Time(ms) is only clean at --parallel 1; the run prints a note when N > 1.
Also fixes --output for manifest jobs, which tried to read the manifest as a
.nest to copy metadata from.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add OpenNest.IO/Bending/BendRepair: opt-in repair of unambiguous paired
ETCH/SCRIBE bend ticks, bounded to <=3.175 mm endpoint movement with
explicit source units. Cut geometry is never modified.
- CadImportOptions.BendRepair configures it; CadImportResult exposes
per-bend BendRepairReports; CadImporter/Dxf wire it into import.
- Console: --repair-bends-mm <limit> --cad-units inches|mm prints
per-bend reports for newly imported DXFs.
- New OpenNest.IO.Tests project (net8.0, synthetic DXFs, 30 tests)
covering bend detection and repair, added to the solution.
- Update README.md and CLAUDE.md for the new pipeline and build/test
instructions.