Commit Graph
10 Commits
Author SHA1 Message Date
ajandClaude Fable 5.2 cd5a400a22 refactor(core): move clamps into OpenNest.Clamps
Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
2026-11-12 19:38:20 -05:00
ajandClaude Opus 5.5 4d55e11318 style: use one spelling across the codebase
The repo mixed variants such as center/centre and color/colour, so a
name could be spelled either way and searches missed half the hits.
Standardize on the US spelling, matching .NET's own APIs (Color, Center).

Wire values owned by other systems keep their spelling: the material
ledger's "Cancelled" hold status and GitHub's "cancelled" job status.

No behavior change beyond the spelling of a few status messages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 16:11:30 -04:00
ajandClaude Opus 5.5 0719476618 feat(clamps): give clamps their own clearance from parts
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>
2026-10-29 17:25:27 -04:00
ajandClaude Opus 5.5 d35178c3b5 feat(clamps): edit clamps on the plate view, on any sheet edge
Clamps could only sit on the origin-side edge and be edited as a list in
Nest > Clamps. Setting them up against a real sheet is easier by dragging
them where they are, so Plate > Edit Clamps adds an edit mode: drag a clamp
along its edge or onto another edge, click near an edge to add one, click a
clamp's locating dimension to type its distance from the origin, Delete to
remove. Dimensions measure to the clamp center or its near edge
(remembered per user). Edits replace the nest's rail so every sheet follows,
like the dialog.

Rail clamps now carry a ClampEdge (origin side, far side, origin end, far
end), positioned from the origin along that edge. Origin-side clamps keep
their ids and files; other edges persist in optional per-edge arrays in
.nest files and clamps.json, omitted when empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 11:09:04 -04:00
ajandClaude Opus 5.5 7d254ce18d feat(desktop): remove or restore a clamp by right-click
Operators sometimes pull a clamp for a manual layout, but only Auto Nest's
last-resort search could take clamps off a sheet. Right-clicking a clamp in
Select mode now offers to remove it from that sheet or put it back, reusing
the existing per-sheet RemovedClamps, so the zones, cut-time charge, display
and .nest persistence all behave as they do for Auto Nest removals.

The change is refused while a nest run or fill may be reading the clamps,
sharing the guard the Clamps dialog already used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 06:20:30 -04:00
aj 6b995ac40a fix(core): make a plate's removed-clamp set immutable
Plate.RemovedClamps exposed a HashSet (and every untouched plate shared one
static empty HashSet), so a downcast could change one plate's removal state
or every plate's at once without re-resolving zones. It is now an
ImmutableHashSet.

PM 6ded8ac4-84fd-4e8b-9a3b-6f41e494542c item (e)
2026-10-13 18:15:50 -04:00
aj 7ed40d4bb8 fix(core): charge removal time only for removed clamps on the sheet
Plate.ClampRemovalMinutes multiplied every listed removed id by the
removal time, including ids the rail places beyond the sheet after a resize
or does not know at all. Only removed clamps the rail resolves on this sheet
are pulled, so only those add time; the ids themselves stay listed (C13).

PM 6ded8ac4-84fd-4e8b-9a3b-6f41e494542c item (a)
2026-10-13 18:15:50 -04:00
aj ec058d270c feat(core): remove individual rail clamps on one plate
Slice 3b task 1 (D8/D9): ClampRail gains RemovalMinutes (D9, default
5 minutes, validated finite >= 0) and Plate gains RemovedClamps (rail
clamp ids taken off this sheet as a last resort) plus the computed
ClampRemovalMinutes. Plate.SetClampRail gains an overload that
attaches a rail with a removed-clamp set; zones become the rail's
resolution for the sheet minus those ids, re-resolved on every
resize/rotate so a removed clamp stays off and reappears removed if a
later resize brings it back onto the sheet. ClampRail.Matches gains an
overload comparing against the reduced resolution.

IO: PlateDto.RemovedClamps and ClampRailDto.RemovalMinutes persist
(missing removalMinutes falls back to the default; missing
removedClamps means none). The writer's empty-plate drop logic no
longer drops a sheet whose only content is a removal state the
defaults can't recreate. The reader re-attaches the nest rail to a
plate only when its saved zones equal the rail's resolution minus its
saved removed ids, so a reduced-clamp sheet keeps following the rail
(and the removal) through later resizes instead of freezing as static
zones.

Engine/desktop wiring (minimal-removal computation, Auto Nest
last-resort removal, cut-time, UI) is Slice 3b tasks 2-3, not yet
done.

Tests: 16 new Core (ClampRailTests) + 5 new IO (ClampRailPersistenceTests)
covering validation, resize/resolve behavior, round-trip, legacy
missing-key defaults, and the empty-plate-with-removal-only retention
case. Mutation check (reverting the RemovedClamps subtraction) turns
3 Core + 2 IO assertions red, confirming real coverage.

Gates: Release OpenNest.Tests 3884 passed/31 skipped, OpenNest.IO.Tests
105 passed, OpenNest.Engine.Tests (Clamp filter) 98 passed; scoped
dotnet format --verify-no-changes clean.
2026-10-13 18:15:49 -04:00
aj bafb311735 feat(clamps): keep the whole footprint of a partly used clamp
A clamp is an avoidance area, so a clamp that only partly reaches a
sheet (for example centered at 60.5" on a 60" sheet, or near the
origin) now keeps its whole 1.5" x 0.625" footprint instead of being
clipped to the sheet; clamps wholly beyond the sheet are still left
off. Job validation accepts a zone that hangs past the sheet edges and
still rejects one that does not reach the sheet at all. Both packing
lanes already block keep-outs extending past the bin; a hanging-clamp
solve through Rectangles, Irregular and Default keeps every part clear
of the whole inflated footprint.

User decision 2026-10-12, settling the plan's pending D2 question.
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