AutoNestJob builds the desktop dialog's default job, each drawing's
remaining quantity (cut-offs excluded) on stock like a template plate,
and commits a NestPipeline result only when it is valid, keepable and
places something, onto the nest's empty plates first. RefusalReason
names why nothing was committed instead of NestRenest's release-flow
note.
The engine selection and the whole-job progress adapter use only Engine
and Data, so they move into the toolkit-neutral library for the Avalonia
front end to share. The namespace stays OpenNest.Forms, so WinForms
callers are unchanged.
Linux tests now cover the adapter's stage routing, one-based plate
numbers and descriptions, and the fill-strategy mapping; the saved
selection is left out because it reads and writes the real per-user file.
Adds the Edit a plate by hand, Cut order and simulation and Nest settings
pages, the machine's Outside/Inside Cuts tabs, the Arc lead-in sweep, and
a recaptured Edit Drawing dialog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Machine Configuration held one lead-in and lead-out per thickness and
applied it to every contour. Each thickness now has Outside Cuts and
Inside Cuts tabs; inside cuts follow the outside leads until "Same as
outside cuts" is cleared, and configurations without inside leads keep
applying one pair to both.
The lead type lists, per-type fields and preview from Cutting Settings
are now a reusable LeadsEditor control that both dialogs use. The
machine tabs hide what the configuration cannot hold: the arc sweep,
the clean-hole kerf (taken from the thickness) and Line + Line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New installs now start with a generic fiber laser: mild steel, 304
stainless and 5052 aluminum, gauge-named thicknesses, fiber-sized
kerfs and arc lead-ins, and no lead-out. It has its own id, so
uploading local machines never replaces an existing CL-980. A test
checks that the shipped values grow sensibly with thickness.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Thicknesses take an optional name or gauge shown beside the value in
the tree. The Machine Configuration form keeps the selected tab while
moving between thicknesses or machines, and opens fully expanded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Document and Undo/ (ChangeScope, NestFingerprint, NestUndoState) use
only Core, Data, IO and Engine, so they move into the toolkit-neutral
library both desktop front ends share. Namespaces are unchanged, so the
WinForms app compiles as before; it keeps using the internal scope
factories and fingerprint through InternalsVisibleTo.
The scope, fingerprint and SaveAs/save-point rules now have Linux tests
in OpenNest.Desktop.Tests; before, only the Windows-only WinForms suite
covered them.
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>
The Help menu's F1 shortcut took the key before the plate view, so F1
in Clone/Add Part opened help rather than setting the part in place as
it always has. Actions can now claim F1; Clone does, and MainForm lets
the key through to the plate view while it is active.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a part's outline is open (a tab gap, say), cut-off trimming falls back
to a convex hull. That hull still included lead-in/lead-out points, so it ran
from the lead's pierce point back to the part and stopped cut-offs far short
of the material. Cutting through a lead is harmless, so the hull now uses the
material contour only, as the closed-outline path already did.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Operators could only drag or delete a cut-off, so changing which line runs
through a junction (e.g. letting a vertical split the sheet to keep a whole
remnant beyond it) meant deleting and re-adding lines. Trim/Extend edits the
existing start/end limits instead, so no file-format or planner change is
needed: trims stop on the crossing line's centre, extends run to the next
crossing or the sheet edge, and Swap Through-Cut (right-click a junction)
does both at once, trimming the through line's far side because only the
origin-side edge is certain. Edits undo as one step and re-place the changed
segments with PlateSequencing.PlaceCutOffs so a new separator is cut last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Regenerating a cut-off into more segments than were saved inserted each
segment at its old index, pushing later parts and cut-offs down; a reloaded
nest could cut its sheet separator before parts it splits off. Segments now
go after the parts saved before them, so a changed segment count never shifts
anything else. Files record every segment's place, and an older file's
sheet-separating cut-off loads last.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan Cutting spent most of its time on work that never changed the outcome:
many-holed parts paid quadratic shape-pair and ring-containment costs before
any search, every plate was captured twice, and failing plates burned their
whole budget in exhaustive fallback passes that never found a plan on 127
production plates.
- OverlapMaterial: skip native shape pairs whose bounds are clear by more
than the query allowance; gate polygon touch and winding tests on vertex
bounds.
- LeadMaterialSnapshot: gate ring enclosure tests on ring extents when
finding the perimeter and rejecting nested cutouts.
- CuttingPlanBatch: capture each plate once; the kept-order retry derives
from the same capture through CuttingPlanSnapshot.WithPreservedOrder.
- JointCuttingPlanSearch: end the kept-order full pass and the sequence-free
recovery and full passes after FallbackStalls (2) stalls' worth of
expansions when programs are regenerated; plates with only fixed programs
keep the exhaustive search so a refusal stays genuine.
On 127 archive plates (lead-ins cleared, 35" scrap cut-offs) total time fell
from 164 s to 102 s with identical outcomes; the problem-nest corpus gives
the same status and expansion count on every plate.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An arc lead-in meeting a straight window edge tangentially has a double
root at its joint. Rounding split it into two contacts a few 1e-8 apart,
or dropped it so the exact ray fallback reported the joint as an
uncertain contact. Either refused a valid entry, so N26-27U's windows
lost most of their entries and the plate never planned.
Treat a contact within 1e-6 of a joint its boundary passes through as
the joint, and let the exact line fallback skip ray hits at contacts
already recorded. The pinned-hole test now expects the other hole's
nearest entry rather than the fallback both runs used to share.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Undo regenerates each restored plate's cut-offs, which removes the
cut-off parts first. A plate holding nothing but cut-offs became empty
for a moment, so the new-plate sentinel dropped a trailing plate while
the restore was still enumerating the plates, throwing "Collection was
modified". Regenerate inside a PlateManager batch so the sentinel only
settles once every plate is done.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v0.5.0 adds the sheet-cutoff topic the Sheet Cut-Off tool opens on F1;
with v0.4.0 that F1 fell back to the help home page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Issue #13 asked whether a Sheet Cut-Off can be rotated; Space already
toggles vertical/horizontal, but nothing said so. The tool now shows a
"Space: turn horizontal" tag by the pointer, spells out its keys in the
status bar, and F1 opens a new sheet-cutoff help topic while it is
active (actions can now supply a status hint and a help topic).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plan Cutting saved its settings only on a successful Apply, so a plate
that would not plan lost them. Each open then laid the machine's leads
back over the last parameters, and the cutting panel rebuilt parameters
from scratch, dropping kerf and the machine/material/thickness stamp.
Save the settings when the dialog is accepted, keep the panel's
unexposed fields, and only apply the machine's leads when the last
parameters were not already taken from that machine, material, grade
and thickness.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The simulator reuses Plan Cutting's inspection lock: the canvas pans and
zooms and plates can be stepped through, but selection, part edits,
menus, toolbars, lists and Undo/Redo are disabled until it closes.
Escape or closing the nest closes the simulator first.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PlateFillService throws for a plate with a sheet outline, but the desktop
swallowed it: Fill (Ctrl+F) caught every exception and showed nothing, and
Fill Area's async void either completed silently or let it escape.
PlateFillService.Refusal(plate) names the reason, and every caller checks
it first: Fill and Fill Area put it in the status bar and add nothing,
Pattern Tile offers a new plate only, the MCP fill/pack tools return it as
an Error result, and the console exits 2 with it unless --autonest is given.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Rectangular stock serializes exactly as before, so result digests that
hash the whole result are unchanged.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The plate view fills the outline, hatches obstacles and draws the usable
area; Edit Plate imports an outline from a CAD file or clears it, with
the size read-only while the sheet has one.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
NestPlateStock carries the outline; its usable material (less obstacles,
eroded by the largest edge spacing) becomes the FrontierPacker's
PackBoundary. The layout check and the runner's candidate validation
reject a part outside the outline or over an obstacle, area-based cost
and the area budget use the material area, salvage credits nothing, and
Rectangles, Circles, FlatBar and the fill strategies place nothing on it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
An optional per-plate `outline` key holds the vertices and obstacles;
rectangular plates write nothing new, an empty outlined plate is kept,
and a malformed value loads the saved size as a rectangle with a reader
warning. Undo snapshots restore it through the same path.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A SheetOutline is a closed polygon in plate coordinates with optional
obstacle polygons, normalized to start at the origin; the plate's Size
stays its bounding box. Plate.Area is the material area, rotations turn
the outline, AutoSize and Snap to Standard Size leave it, manual cut-offs
are trimmed to the material the line crosses, the automatic planner
refuses it and no expected remnant is reported.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
CutoutPackerProposal runs the Irregular engine's FrontierPacker on one
hole, frame-local, with the hole as its boundary and already seated
inserts as obstacles, for all six strategy variants; every pose is
certified with NestLayoutCheck.Clears against the frame, the occupants
and the other poses, and the variant seating the most copies wins, ties
going to the tighter layout. CutoutRouter keeps that proposal over the
lattice-and-NFP one when it seats more copies, or the same number more
compactly, so the pre-pass gets it on every non-round hole.
Two copies of a bar in a frame window, which the lattice never tried and
the sampled NFP search scattered across the window (one at the inner
fit's centre), now stand together against one wall. The test rebuilds
that frame and bar from embedded G-code; the residual-accounting
pipeline tests use a hole that holds one insert so their second copy
stays an ordinary requirement.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Add PackBoundary: a closed outline with obstacles, bound to one
NoFitCache, whose per-orientation inner-fit polygon (the clearance
footprint inside the outline eroded by the other half clearance) is
computed once and shared. FrontierPacker takes an optional boundary and
seeds each region from that inner fit, drops orientations with no fit
and subtracts obstacle no-fit polygons like clamp ones; without a
boundary it is unchanged, so rectangular stock layouts are identical.
CutoutLatticeFill.InnerFit now calls the shared kernel with the same
Clipper operations, so lattice results are unchanged. The engine's
strategy variants are internal so a cutout proposal can reuse them.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
PEP-rounded drawings can leave a contour 1e-6 short of closing. ShapeBuilder
chains it as a loop at Tolerance.ChainTolerance, but the slide classifier
re-recovered loops at 1e-7, so the whole part became unresolved and every
contact with it blocked. Parts placed in its cutout at exactly the part
spacing could not be pushed (Y/X keys) in any direction, even away from the
wall. Recover loops with the same tolerance ShapeBuilder uses.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When no search finds a route that keeps every rapid off parts already
cut, Plan Cutting used to offer only an unverified safest route needing
explicit acceptance. Cincinnati's own software instead raises the head
for such a rapid. Now the safest-route fallback marks each planner-chosen
rapid that still crosses cut parts with a HEAD RAISE comment, and the
plan is Ready with every raise listed. The strict search never marks a
rapid, and the batch prefers fewer broken checks, then fewer raises,
then less travel, so a plate that can be cut head-down never gets one.
The reader flags marked rapids and the checker sets their crossings
apart, in replay and pre-post verification alike. The Cincinnati CL
post writes M47 before a marked rapid whatever the M47 mode (the
distance-based safety raise is unchanged); the CI Fiber post writes a
new Head raise block and refuses marked nests while it is blank, since
its raise code is unconfirmed. Rapids into locked programs, cut-offs
and hole sub-programs are never marked and keep their findings.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cutout pre-pass offered lattice/NFP inserts only when they had no
cutouts at all, so a strap with 0.25" bolt holes was never tried in a
frame's window. On N26-264 that left both PT11s loose on the sheet and
Rectangles' staggered PT10s won, although both PT11s fit one PT10's end
window. Holes matter only if another part could land in them, so a part
whose every cutout is smaller in area than the job's smallest outline is
now an ordinary insert; proxies and parts with usable holes stay out.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every corpus nest guards Plan Cutting, yet agents ran the whole corpus
after any change, including nesting-engine work, and the 5k washers
alone take about 90 s of a two-minute run. Each nest now names the
planner areas it guards in a "checks:" comment line, and
OPENNEST_PROBLEM_NESTS_CHECKS limits a run to nests guarding those
areas. Untagged nests always run and an unknown area fails the run, so
nothing is skipped by accident. AGENTS.md now limits the corpus to Plan
Cutting changes and asks for the filter; the doc maps code to areas.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a part could not be reached without crossing parts already cut, the
free search always learned "cut the blocked part before them". When the
crossed part was the one cut just before the part the tool left from, the
tool had gone on past it and come back: the cheap repair is to cut those
two the other way round. Without it, N26-23S learned a chain of wrong
rules (8 before 4 and 5, 3 before 1, ...) that excluded every valid order
and ran the full search out of budget, although swapping parts 5 and 6
gives a valid plan. It now plans ready in 786 expansions.
The problem-nest corpus keeps every outcome; three P260417-17 plates stay
Ready with more expansions (5341 -> 8937 the largest).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Playback rewrites the status labels every frame, and a plain Label erases
its background before drawing the new text, so the time blinked. The status
values now use a double-buffered label.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Browsing nests in Database mode crashed with ObjectDisposedException on
DataGridView: selecting another nest drops the embedded version history,
and WinForms leaves its grid's keyboard-tooltip auto-pop timer running.
When the timer fired it hid the tooltip through the disposed grid.
GridStyle now hides that tooltip when a styled grid's window is destroyed,
which stops the timer for every grid in the app.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
8dded7f1 draws cut-off ids white on a disc of the cut-off line's orange,
so the old assertion that no orange touches the id failed on the Windows
CI job. The test now checks what the disc is for: the disc is there, and
the id's white strokes survive on the cut's own pixels. Drawing the lines
after the labels fails it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every installed copy checked GitHub Releases on its own, so a shop's
workstations shared GitHub's 60-requests-per-hour unauthenticated limit
per public address and each downloaded the ~90 MB package over the
internet. Shops large enough to hit that already run the nest server.
The server now mirrors the Velopack feed at /updates/{stable|dev}: one
GitHub API request per 30-minute refresh, each package downloaded once
and checked against the feed's size and SHA-256 before it is served. A
channel is mirrored only while clients ask for it, so stable-only shops
never download development builds. Database-mode clients read the
server first and fall back to GitHub when it has no feed (old server,
mirror off, not mirrored yet), downloading each package from whichever
source listed it. A hand-set feed URL still takes precedence.
OPENNEST_UPDATES=off turns the mirror off.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plate-colored disc behind a cut-off id read as a notch in any part edge
the cut runs along. An orange-red disc with a white id reads as a tag on the
cut-off line instead, and still keeps the dashed line from striking it through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The strip's built-in item tooltips open below the cursor. With the window
maximized the strip is at the bottom of the screen, so Windows pushes the
tooltip back over the cursor; the strip then sees a mouse leave, hides it,
re-shows it on the next hover, and it flickers. Show the tooltips above the
strip instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The explanation at the top of the dialog was long and duplicated the help
guide. A link beside OK/Cancel (and F1) opens the existing support-grid
topic, which the pinned help release already maps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Highlighting an earlier version on the Versions tab left the plates,
drawings and plate preview on the current version, so there was no way
to see what a historical version looked like without opening it. The
embedded history now reports its selection and the browser downloads
that version (debounced, cached per history view) and shows it, labelled
as historical; selecting the current version returns to it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A drawing every nest needs, such as the operator's test square cut before
the job, had to be saved once per material and thickness or found with Show
all materials. A blank material or grade, or a zero thickness, now means
any: the server's library filter returns such drawings for every value,
and adding one to a nest is not a difference, so it keeps its cut pins and
takes the nest's material for the fields it left blank. Duplicate detection
still compares every key exactly on the client.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Python tool that finds drawings resembling a hand sketch, photo or MS Paint
outline. It indexes the OpenNest server's drawing library (read-only) and/or
DXF folders, compares DINOv2 embeddings of normalized renderings across all
8 rotations/mirrors, and writes an HTML page of the closest matches with an
optional overall-size filter.
train.py fine-tunes the embedding contrastively on synthetic sketches of the
library itself (no labelling); evaluate.py measures recall on held-out
drawings or a folder of real sketches. On 40,757 server drawings, held-out
synthetic sketches find the right shape in the top 20 75% of the time,
up from 18% zero-shot.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The panel gains a Current plate only / All plates selector, shown when the
two scopes differ. Changing it takes the unapplied scrap cut-offs off,
cancels any running plan and replans. The toolbar button opens with the
scope last chosen there (default all plates); the Plate and Nest menu items
keep their fixed scopes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each lead tab draws a sample part with a hole and the configured leads and
pierce points, emphasizing the tab's own contour and updating as values change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Auto Nest leaves out ledger item codes already on other open server nests,
and save and post re-check a nest's codes before going on.
- Server: GET /api/nests/stock-item-codes?exclude= lists the codes on
non-deleted Draft, Quote and To Be Cut nests. Codes are stored in
nest_stock_codes (schema v14) at every archive write; the upgrade reads
each current archive once.
- Data: INestRepository.GetStockCodesInUseAsync, LedgerCodesInUse (5 s,
failures become an unknown answer), the pure LedgerCodeFilter for ledger
rows (reusable by release-time nesting) and LedgerCodeCheck for the
re-check.
- Desktop: the Auto Nest ledger summary counts "(N on other nests)" or says
other nests were not checked. Save, Save As and post open Ledger Stock
Changed when codes are taken: proceed after a per-attempt
acknowledgement, remove the codes (undoable), or cancel. A ledger that
cannot be read skips the check with a status note.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WinForms user settings lived in user.config under %LOCALAPPDATA%\OpenNest,
the Velopack install folder that setup clears on a reinstall, and the
default provider starts empty at each assembly version. Store them in
%APPDATA%\OpenNest\user-settings.json instead, carrying over any values
the old user.config still holds on first run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>