Commit Graph
1542 Commits
Author SHA1 Message Date
aj 81e3e58f13 feat(data): clamp settings store
Persist the machine clamp rail in %APPDATA%\OpenNest\clamps.json, in
the same shape as the nest defaults store: camelCase JSON written with
retry, and a read that never throws. Clamps are off by default: a
missing or unreadable file keeps them off, and nothing changes until
the settings are enabled with at least one center.

Each value is read independently; an invalid one (including a single
bad clamp center) is ignored and reported as Partial so the desktop
can warn that the rail may lack a physical clamp. Values carry their
units and convert between inches and millimeters for a new nest.
2026-10-13 18:15:49 -04:00
aj cc85a9e068 feat(core): resolve a fixed clamp rail onto nest plates
Add ClampRail: identical clamps (width along the edge, depth into the
sheet) at X centers measured from the plate origin on the origin-side
edge. It resolves onto any sheet size and quadrant without re-scaling:
clamps wholly beyond the sheet are skipped, one still reaching onto it
is clipped to it, and ids follow rail position (clamp-N) so a physical
clamp keeps its id on every sheet.

A plate can follow a rail (Plate.SetClampRail); its ClampZones are then
derived and re-resolved whenever Size or Quadrant changes, because the
clamps are fixed to the machine. Plates without a rail keep explicit
zones unchanged. Nest.PlateDefaults.ClampRail is the template new plates
follow, and Nest.SetClampRail applies a nest-wide rail to every plate
(an empty rail removes it).
2026-10-13 18:15:49 -04:00
aj 040776807a fix(engine): keep solved clamp zones on committed plates
ApplyToEmptyPlates copied size, spacing, quadrant and quantity from the
solved stock but not its clamp zones, so a sheet the commit created had
no keep-outs although its parts were validated against them, and a
reused plate could keep zones the layout was not solved with.

Map the stock's placement-frame zones back to plate coordinates on every
committed plate; zones already equal in the placement frame are left
untouched so an unchanged plate raises no change events.

Project Memory: bcc2dd2a-2ab6-4a2a-9c13-197e0aeb24bc
2026-10-13 18:15:49 -04:00
aj fbca54637b fix(irregular): retain sub-grid clamp obstacles 2026-10-13 18:15:49 -04:00
aj c374e02614 feat(irregular): treat clamp zones as static NFP obstacles 2026-10-13 18:15:49 -04:00
aj de9a087027 feat(rectangles): avoid clamp zones in sheet packing
Block each clamp's keep-out into the max-rects free list before any
packing: same split logic as placements, not a used item (no contact
score, no material). The blocked rectangle accounts for the inflated
item model exactly - material keeps the bottom-edge clearance from the
clamp without paying an extra part-spacing tax; degenerate spans
collapse to the zone centerline (conservative, never permissive).

Zero-clamp sheets skip blocking entirely: three fixture layout hashes
(rectangle grid, mixed shapes, multi-sheet overflow), captured from the
unchanged packer at a3f1124, stay bit-identical (C2). With clamps:
placements never intrude, demand lands between two clamps when it fits,
a full-width front rail makes an otherwise feasible job Incomplete, and
a far-away zone leaves the layout hash equal to no-clamps.

Rectangles lane only; Irregular parity is Slice 2.
2026-10-13 18:15:49 -04:00
aj dc87911b2f feat(engine): carry clamp zones into stock, validation and repeat identity
NestPlateStock takes an optional clamp-zone list, translated into the
placement frame exactly like WorkArea (quadrants 1-4) and detached from
caller boxes; empty input keeps stock bit-identical to before. Plate
mappings (DrawingJobMapper.FromPlate/CreatePlate, NestStockBuilder) map
zones across; materialized plates carry them for checking.
NestJobValidator rejects zones outside the sheet or duplicate ids.
RepeatedPlateGrouping and NestLayoutCheck treat clamp sets as stock
identity (C8), and the layout checker flags part material inside a zone
inflated by bottom-edge spacing with the shared spacing slack (C1/C5) -
no tolerance loosened.
2026-10-13 18:15:49 -04:00
aj d001abcf69 feat(io): persist clamp zones in nest files
Add the additive per-plate clamps array (id, x, y, length, width) to the
nest DTO with writer and reader support. Files without the key load with
zero zones; an individually malformed entry is dropped while the rest of
the nest loads. A plate carrying only clamp definitions now survives the
writer's empty-plate filter; genuinely empty plates remain omitted.
Format documented in docs/nest-file-format.md.
2026-10-13 18:15:49 -04:00
aj c16092c293 feat(core): add rectangular clamp zones to plates
Introduce ClampZone: an axis-aligned rectangular keep-out in plate
coordinates (id + detached Box), validated finite, positive-size and
identified. Plate.ClampZones is a first-class collection alongside
Parts/CutOffs with a ClampZonesChanged event for view refresh. Zones are
never parts: quantity, utilization, cut sequence and CNC output ignore
them (locked by tests); they carry no z-height reasoning.
2026-10-13 18:15:49 -04:00
aj c04562f56d test(ui): pin the SegmentedCut notice the cutoff dialog details box shows
Windows CI proved the default single-plate fixture is not notice-free;
the details box now surfaces the SegmentedCut notice that the old text
wall buried. Assert the real content instead of a clean box.
2026-10-13 14:10:41 -04:00
aj b66af8658b refactor(ui): make the automatic cutoff dialog scannable at a glance
The dialog buried its verdict in a scrollable text box that restated the
same numbers per plate behind a paragraph-length warning. Replace it
with:

- a bold colored status line stating exactly what Apply will do
  (Ready / Blocked / No new cut-offs / Error with the reason);
- the occupied span, used span, separator X and retained tail as
  compact caption+value cells with tooltips instead of four sentences;
- the warning paragraph reduced to one amber line with the full text
  in its tooltip;
- a per-plate table (cut-offs, spans, tail, Ready/Blocked/No change)
  for the All Plates command, replacing repeated text blocks;
- the details box now lists only issues and notices, prefixed by plate
  number when planning a nest, instead of echoing every measurement.

Planning, preview, apply and rollback behavior is unchanged; tests and
the cutoffs document follow the new presentation.
2026-10-13 13:54:21 -04:00
ajandClaude Opus 5.5 311178c15a fix(cutting): trim baked-in seam overcuts and route parts nested in cutouts
Nests converted from another CAM system carry its seam overcut inside the
clean contour: the last cut runs on past the contour's own start along its
first cut, then a straight jog returns to the start. The ring then touches
itself at its seam, so neither the cutting planner nor the overlap analyzer
could certify it and the whole plate refused.

SeamOvercut recognizes exactly that shape (same line, or same circle and
direction) and trims it from an owned copy; the retraced tail encloses no
area, so material is unchanged and the drawing is never edited. Any other
self-contact still refuses. Arcs of one circle whose centers were each derived
from their own endpoints agree only within Epsilon, so their spans are now
compared at the seam tolerance: shared spans still refuse as overlap, while
arcs that only meet at a joint or lie apart no longer do.

Plates with parts nested in other parts' cutouts then failed to route, since
the host is cut last and every straight approach from the middle of a crowded
cutout crosses a finished neighbour. CuttingNestedOrder tours each host's
inner parts as one run ending beside the host's own contours, hosts follow
the parts beside them, and learned rules still win. Outside entries are
ordered by clear sight lines to the next cut, the look-ahead toward a host is
its nearest contour point rather than its centre, a cutout containing the
arrival point is routed from that point, and a pass that teaches an order
rule ends the round instead of repeating the blocked approach.

Tests: SeamOvercutTests and CuttingNestedOrderTests; the cutting-planning,
diagnostics and overlap tests in OpenNest.Tests pass (1023 passed, 6 skipped).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 13:40:32 -04:00
aj b36db41769 Merge remote-tracking branch 'github/master' 2026-10-12 13:33:13 -04:00
aj e5c82e2c92 fix(mcp): release repeated stock reservations with their owner 2026-10-12 13:10:38 -04:00
aj 522de2761c feat(irregular): reuse completed plate layouts for repeat batches 2026-10-12 12:54:15 -04:00
aj 49017c4a91 feat(rectangles): repeat completed sheets from remaining demand 2026-10-12 12:53:59 -04:00
aj c1d5a827bc fix(nesting): preserve repeated-layout quantities through commit 2026-10-12 12:53:18 -04:00
ajandClaude Sonnet 5 937448242f feat(machine-config): add a material grade tier
MaterialConfig only ever had one grade per material name, so the tree
and GetMaterial/GetParameters couldn't represent e.g. Mild Steel A36
vs. A1011 as distinct, independently-parameterized entries. Prep work
for an upcoming drawing database that will store material + grade per
drawing and needs to resolve cut parameters by that pair.

- MachineConfig gains GetMaterial(name, grade), GetGrades(name), and a
  GetParameters(material, grade, thickness) overload, all keyed through
  the existing SharedListNames normalization. The name-only overloads
  stay for back-compat ("first grade found").
- MachineConfigForm's tree gains a real tier: Machine -> Material name
  (synthetic grouping node) -> Grade -> Thickness. Add/remove gained
  "Add Grade" and split "Delete Material" (all grades) from "Delete
  Grade" (one entry). Renaming a grade's Name relocates its node to the
  matching (or a new) group on focus-loss, keeping the tree in sync
  without a full reload.
- No schema/JSON changes; existing machine files keep working as-is.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-12 09:26:42 -04:00
ajandClaude Sonnet 5 f74da248b3 refactor(ui): split MachineConfigForm into a Designer-backed partial class
The form's static chrome (tree/detail split, Save/Export/Import bar) was
built entirely in the regular constructor, so Visual Studio's WinForms
designer had no InitializeComponent() to read and showed a blank/broken
surface. Move that static layout into MachineConfigForm.Designer.cs and
add a private parameterless constructor for the designer to instantiate,
following the same pattern already used by EditNestForm. The dynamic,
data-driven detail panel content stays in the regular constructor/methods.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-12 08:34:05 -04:00
ajandClaude Sonnet 5 c67577d463 refactor(ui): redesign Machine Configuration form
Replace the flat label/textbox list and always-destructive +/- button
row with a tabbed detail panel (General/Lead In/Lead Out/Cut Off/Plate
Sizes for thicknesses) and a right-click context menu on the tree.

Move add/remove/edit to a single "editing session" model: mutations
only touch the in-memory tree until Save, which also prompts on close
if there are unsaved changes. Tree labels now update live instead of
requiring a full reload, which previously collapsed the tree and lost
selection on every add/remove.

Reuse existing domain data instead of free text: Lead Type and Cut Off
Direction become dropdowns sourced from the real option sets elsewhere
in the codebase (CuttingPanel's lead types, OpenNest.CutDirection), and
Plate Sizes becomes a checklist seeded from OpenNest.Shapes.PlateSizes
with a custom-size fallback. Assist Gas becomes an editable dropdown.
Numeric fields show their unit (in/mm) and have sane per-field ranges
instead of a blanket 10000 max. Input controls are capped to a fixed
width instead of stretching across the panel, and the tree pane is
widened to make room for longer machine/material/thickness names.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-12 08:27:57 -04:00
aj 565dc90762 refactor(ui): rephrase negative-tone disclaimers as affirmative guidance
Report, dialog and diagnostic text across post verification, cutoff
planning, alignment and cutting-plan review repeatedly told the user
what checks weren't (safety certifications, proof, guarantees) instead
of what to do. Reworded these to state the same caveats affirmatively
(inspect X, confirm Y, review Z) without changing the underlying
safety guidance, and updated the tests/docs that pinned the old wording.
2026-10-12 07:45:23 -04:00
ajandClaude Sonnet 5 18d63ffd61 feat(desktop): add Velopack auto-update support
Lets the desktop app self-update like CncSender, but only restarts after
the user confirms via a clickable status-bar prompt -- an open, unsaved
nest must never be discarded automatically. The feed URL is a blank-by-
default, per-machine setting (File > Options), since it's operator
infrastructure that doesn't belong in source control; Deploy-OpenNest.ps1
packages releases for whatever feed host/path the operator supplies.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-12 06:54:46 -04:00
aj e3bcc77145 fix(cutting): keep ray parity consistent across nominal closure seams
Point-in-material used exact Y comparisons, but rings are only nominally
closed: capture admits closure seams and PEP-converted or rotated geometry
carries sub-micro-inch vertex jogs. When a jog straddled the test ray's Y,
the two edges at that shared vertex disagreed which side it was on and the
parity flipped, so a point ten inches outside a material read as interior.
LeadMaterialSnapshot reported leads as entering a neighbour they could not
touch, and the enclosing-perimeter check refused to capture materials whose
rings it misclassified.

Snap the ray comparison by the admitted seam tolerance so both edges at a
shared vertex decide together. Features larger than the tolerance still
count, and containment of a point within the tolerance of an edge stays as
ambiguous as before. On the 93-plate corpus 83 plates are untouched, one
previously refused plate now plans and replays, and 48/93 plates reach
Ready. Accepting more leads also changed one plate's first-found route to a
longer rapid path; that is search ranking, recorded with the measurements.

Also drops an extent-prefilter fast path measured at -6.8% corpus time: it
cleared leads whose native contact was reported beyond any fixed bbox
margin, which NearbyMaterialCheckTests deliberately pins as a refusal.
2026-10-12 03:50:54 -04:00
aj df94824054 fix(cutting): replay rings closed within nominal tolerance
Capture and preparation agree that a nominal contour may close within
NominalContourClosure.Tolerance inclusively, which converted drawings rely on:
the sampled production corpus carries vertex gaps up to 1e-6. Replay
verification still compared those rings at the exact geometry epsilon, so the
one joint a rotated tool path legitimately bridges refused the whole plate
after the search had already spent its budget.

Census of 91 plates from 60 stored nests: every searched plate containing such
a seam refused with contour-accounting (4 plates, 76.5s of wasted search, worst
71.7s for one 11-part plate), and none of the 42 ready plates had one. Replay
now carries that same admitted endpoint gap as positional and length slack for
the affected ring only. Direction sign, coverage order, retrace detection, ring
counting and selected-emission binding keep the exact epsilon, and capture's
closure admission is unchanged.

With the fix the census yields 45 ready plates instead of 42, no plate changed
any other way, and expansion counts are identical wherever status matched.
P260805-01's 16-part plate plans in 0.76s rather than refusing after 4,129
expansions.

Tests: SeamClosureReplayTests covers seams of 0, 5e-7 and 1e-6 plus four
accounting faults (missing edge, reversed edge, interior shift beyond the
admitted seam, second circuit) that must still refuse, and the beyond-tolerance
capture refusal. OpenNest.Tests 3751, OpenNest.Engine.Tests 690 and
OpenNest.IO.Tests 79 pass; Windows-only projects cannot build on Linux.
2026-10-12 00:36:48 -04:00
aj 9bd5d0dfa7 fix(cutting-ui): navigate selected source plate in planner 2026-10-11 22:45:54 -04:00
aj d6ae706098 refactor(cutting-ui): retire redundant planning and validation forms 2026-10-11 22:15:35 -04:00
aj f9b2e1282a feat(cutting-ui): inspect live nest validation in docked panel 2026-10-11 21:55:59 -04:00
aj 943b63937d feat(cutting-ui): plan and apply all plates from docked panel 2026-10-11 21:40:26 -04:00
aj 6ed7ab7392 fix(cutting-ui): restore canvas after panel layout and clamp splitter 2026-10-11 21:31:01 -04:00
aj 4738a0390e feat(cutting-ui): inspect one proposal on the main canvas 2026-10-11 21:21:07 -04:00
aj 322dc3eda6 fix(cutoffs): use outward union for fitted arc bounds 2026-10-11 20:56:34 -04:00
aj ddc4710dfd perf(cutting): defer alternate hole entries in preferred pass 2026-10-11 20:26:47 -04:00
aj 97a468ee2c fix(cutting): recover checked routes through interlocking holed parts 2026-10-11 19:51:29 -04:00
aj 09dd19ca66 feat(ui): show nest versions in database details tab 2026-10-11 19:42:06 -04:00
aj fae37dd1d0 fix(data): retry absent pending uploads without changing identity 2026-10-11 17:15:16 -04:00
aj 94ed8a0f8f fix(backup): refuse uncertain or reused restore volumes 2026-10-11 17:10:26 -04:00
aj 028832debc fix(data): reconcile ambiguous nest uploads before retry 2026-10-11 17:10:26 -04:00
aj 51ad700bec docs(storage): explain version browser and recovery 2026-10-11 17:02:41 -04:00
aj 0216a9e9e2 test(server): verify complete revision backup and restore 2026-10-11 17:02:31 -04:00
aj a7c8e8541e feat(ui): inspect and restore nest history 2026-10-11 17:01:01 -04:00
aj 5f1eeb00eb test(data): verify legacy metadata guard before mutation 2026-10-11 16:51:56 -04:00
aj 914c197181 feat(server): restore historical nest as new revision 2026-10-11 16:49:12 -04:00
aj 5598804942 feat(server): preserve deleted nests with guarded recovery 2026-10-11 16:49:12 -04:00
aj d216bcd406 feat(server): version guarded metadata edits 2026-10-11 16:49:12 -04:00
aj 11471e3c71 test(server): exercise version history through real client 2026-10-11 16:39:48 -04:00
aj ed7600dc90 feat(data): fetch bounded nest history and guard saves 2026-10-11 16:38:35 -04:00
aj a47b414392 feat(server): preserve file-save nest revisions 2026-10-11 16:37:28 -04:00
aj 3d512c794c fix(cnc): show first internal rapid after cut-first programs 2026-10-11 15:48:07 -04:00
aj 08acb092a7 fix(cutting): anchor near-corner entries to their native edge 2026-10-11 01:14:50 -04:00
aj dc142cc88d docs(readme): streamline engine guidance and tabulate CLI options 2026-10-10 21:31:11 -04:00