Commit Graph
28 Commits
Author SHA1 Message Date
aj 74f32f0516 fix(nests): keep etch marks when clearing lead-ins of PEP nests
PEP-converted nests stored etch marks only in each placed part's locked
cutting program; the drawing program held the contour cuts alone. Because
Remove Lead-ins rebuilds a part from its drawing, clearing lead-ins also
erased the marks from every part.

Recover the marks while reading the nest: when a drawing has no scribe
moves and every placement that kept its saved program carries the same
marks, add them to the drawing in its own frame and refresh that drawing's
clean placements. Saved programs are never rewritten, drawings that already
have marks are untouched, and drawings whose saved programs disagree are
left alone rather than guessed at.
2026-10-14 06:58:24 -04:00
aj d9273c889f fix(io): keep a sheet's own clamp rail and its removals through save and reload
Commit can attach the stock's rail to a sheet whose nest has no (or another)
default rail, but only the default rail was saved and the reader re-attached
sheets only to it, so the removed clamp and its time vanished on reload. A
sheet following a rail other than the default now saves it in an optional
per-plate clampRail (read leniently, omitted otherwise), and the reader
re-attaches the sheet to it.

PM 22daec3d-dabb-4aae-95f7-c1d090d5dcdf
2026-10-13 18:15:50 -04:00
aj 65754957cc fix(io): keep the clamp rail when its saved removal time is invalid
A negative removalMinutes in a saved nest made the ClampRail constructor
throw, so the reader dropped the whole rail and every sheet lost its
removed-clamp state and time. An invalid value now falls back to the
default five minutes, like a missing one.

PM 6ded8ac4-84fd-4e8b-9a3b-6f41e494542c item (b)
2026-10-13 18:15:49 -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 5674764447 feat(io): persist the nest clamp rail
Write the nest's machine clamp rail under plateDefaults.clampRail
(width, depth, centers) so plates created or resized after a reload
still get the clamps. The key is omitted for nests without a rail, and
a missing, empty or malformed rail loads as none while each plate's
saved zones still load.

On load a plate follows the rail again only when its saved zones are
exactly the rail's for that sheet; other zones are kept as written.
The empty-plate filter now drops an empty sheet whose zones the saved
rail recreates, so the editor's trailing empty sheet is not written
for every clamped nest; empty sheets with other zones are still kept.
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 c55e375cf3 refactor(engine): remove legacy multi-plate auto-nest orchestration
Desktop Auto Nest, Console --autonest, MCP autonest_plate and the API
NestRunner all run through NestPipeline, so nothing calls the old
orchestration any more.

Delete MultiPlateNester (with MultiPlateNestOptions, MultiPlateResult,
PlateResult, PartClass and PartSortOrder), PlateOptimizer and
PlateOptimizerResult, plus their tests. The explicit-strategy contract
those tests checked now lives at PlateFillService.ResolveStrategy, which
keeps its null-means-Default, canonical-name and unknown-name tests.
CreateFiller loses its internal visibility, which only the deleted
orchestrators used.

This breaks source and binary compatibility for external callers of the
removed types; whole-job callers use NestPipeline.Run or INestingEngine.
2026-09-30 21:07:32 -04:00
aj ef2f9aa714 feat(core,io): persist nest status and made-by in nest files
Add NestStatus (Quote/ToBeCut/HasBeenCut) plus MadeBy on Nest, written as
additive camelCase nest.json fields with PascalCase enum strings matching
the units convention. Legacy files and unknown status values fall back to
Quote. The nest info dialog gains a Status dropdown and Made By box.
2026-09-29 16:21:17 -04:00
aj b254a0bd3e feat(io): persist part cutting programs and plate parameters 2026-09-28 19:17:59 -04:00
aj 74302761ce fix(io): restore hole sub-programs with negative IDs 2026-09-28 19:05:11 -04:00
aj 4da48eed68 fix(core): keep cut-offs in their cut sequence through regenerate and save
A cut-off's place in Plate.Parts is its cut sequence number, but
RegenerateCutOffs removed every cut-off part and appended it again, so
any part drag, fill or cut-off move sent the cut-offs to the end. The
nest file didn't store the position either, so reopening did the same.

RegenerateCutOffs now puts each cut-off back at its previous index (new
cut-offs go at the end), and CutOffDto.Sequence saves the index. Older
files without it load the cut-offs at the end, as before.
2026-09-28 18:44:04 -04:00
ajandClaude Opus 5.5 1b5e1b14a6 fix: leave etch/scribe marks out of nesting geometry
Every nesting-geometry consumer filtered only rapids, so scribe/etch
moves counted as part material. An etch tick that ends a hair outside
the outline (PEP bend ticks start on the notch edge) made the part
"open geometry leaving the material region": the job validator threw
and every built-in engine plus Gpt6Astra crashed on real PEP jobs
(PT75, drawing 4980 A01 PT77). Marks are only on the surface, so they
should never affect placement, collision, area, or validation.

- SpecialLayers.IsMaterial excludes Rapid and Scribe; used by drawing
  area, canonical angle, part collision, PartGeometry, plate perimeter,
  best-fit/pair evaluation, rotation analysis, GPU evaluators, and both
  validators. Timing, display, splitting and posts still see marks.
- ConvertGeometry also maps the saved SCRIBE layer name to Scribe, so
  programs rebuilt from stored entities keep their marks.
- NestReader repairs older files (e.g. PepNestExport output) whose
  programs saved etch as cut moves while source entities kept SCRIBE.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 06:44:29 -04:00
aj aec0523062 style: apply CSharpier formatting to all C# sources
Repo-wide sweep with the pinned CSharpier 1.3.0 tool. Whitespace and
line-wrapping only; OpenNest.Engine.Tests (109) and OpenNest.IO.Tests
pass after reformat, full solution builds 0 errors.

Added .csharpierignore so csproj/config XML keeps its existing layout
(CSharpier's XML wrapping churns attributes with zero benefit).

Formatting is now enforceable: dotnet csharpier check . passes.
2026-09-20 16:41:50 -04:00
ajandClaude Opus 4.6 df65414a9d feat: serialize and deserialize hole sub-programs in nest file format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 14:40:13 -04:00
ajandClaude Opus 4.6 c1e6092e83 feat: add entity-based suppression with stable GUIDs
Entities now have a Guid Id for stable identity across edit sessions.
Drawing stores the full source entity set (SourceEntities) and a set of
suppressed entity IDs (SuppressedEntityIds), replacing the previous
SuppressedProgram approach. Unchecked entities in the converter are
suppressed rather than permanently removed, so they can be re-enabled
when editing drawings again.

Entities are serialized as JSON in the nest file (entities/entities-N)
alongside the existing G-code programs. Backward compatible with older
nest files that lack entity data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 13:25:48 -04:00
ajandClaude Opus 4.6 ffd060bf61 feat: serialize plate optimizer settings in nest files
Add PlateOptions and SalvageRate properties to the Nest class and
round-trip them through NestWriter/NestReader via a new PlateOptionDto.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:38:02 -04:00
ajandClaude Opus 4.6 9db7abcd37 refactor: move material and thickness from Plate to Nest
Material and thickness are properties of the nest (all plates share the
same material/gauge), not individual plates. This moves them to the Nest
class, removes them from Plate and PlateSettings, and updates the UI so
EditNestInfoForm has a material field while EditPlateForm no longer shows
thickness. The nest file format gains top-level thickness/material fields
with backward-compatible reading from PlateDefaults for old files.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 21:00:59 -04:00
ajandClaude Opus 4.6 27bbe99e7e fix: preserve part rotation through lead-in assign/remove cycle
Track preLeadInRotation when parts are rotated so lead-in removal
can restore the correct rotation. Remove stale HasManualLeadIns and
LeadInsLocked deserialization from NestReader since these flags are
transient state, not persisted data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 17:39:07 -04:00
ajandClaude Opus 4.6 c9b5ee1918 feat: serialize HasManualLeadIns, LeadInsLocked, and :SUPPRESSED in nest files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 13:29:49 -04:00
ajandClaude Sonnet 4.6 dd2892a9fe feat: serialize/deserialize bends in nest file format
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-24 20:22:55 -04:00
ajandClaude Opus 4.6 b970629a59 feat: add material library resolution, assist gas support, and UI fixes
- Add MaterialLibraryResolver for Cincinnati post processor to resolve
  G89 library files from material/thickness/gas configuration
- Add Nest.AssistGas property with serialization support in nest format
- Add etch library support with separate gas configuration
- Fix CutOff tests to match AwayFromOrigin default cut direction
- Fix plate info label not updating after ResizePlateToFitParts
- Add cutoff and remnants toolbar button icons

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 22:00:57 -04:00
ajandClaude Opus 4.6 2f19f47a85 feat: serialize/deserialize cut-off definitions in nest file format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 19:40:01 -04:00
ajandClaude Opus 4.6 cdf8e4e40e refactor: use IDistanceComputer and rename Type to StrategyIndex
Wire IDistanceComputer into RotationSlideStrategy, replacing inline
CPU/GPU branching. BestFitFinder constructs the appropriate implementation.
Replace PushDirection enum with direction vectors in BuildOffsets.
Rename IBestFitStrategy.Type and PairCandidate.StrategyType to StrategyIndex
for clarity (JSON field name unchanged for backward compatibility).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 00:04:19 -04:00
ajandClaude Opus 4.6 1d9bcc63d2 chore: sort using directives
Auto-formatter reordering of using statements across the solution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:47:42 -04:00
ajandClaude Opus 4.6 d6ffa77f35 feat(console): improve training data collection and best-fit persistence
- Add verbose per-file and per-sheet-size console output during collection
- Skip already-processed parts at the sheet-size level instead of all-or-nothing
- Precompute best-fits once per part and reuse across all sheet sizes
- Clear best-fit cache after each part to prevent memory growth
- Save best-fits in separate bestfits/ zip entries instead of embedding in nest.json
- Filter to Keep=true results only and scope to plate sizes in the nest
- Set nest name to match filename (includes sheet size and part count)
- Add TrainingDatabase with per-run skip logic and SQLite schema

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 12:39:24 -04:00
ajandClaude Opus 4.6 7e0edd112a refactor: use 'length' instead of 'height' in nest JSON format
Rename SizeDto.Height to SizeDto.Length so the serialized JSON
uses "width"/"length" which is more natural for plate materials.
The core Size struct still uses Height internally.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 21:50:53 -04:00
ajandClaude Opus 4.6 c2534ef08b feat: replace XML nest file format with JSON (v2)
Replace three separate XML metadata files (info, drawing-info,
plate-info) and per-plate G-code placement files with a single
nest.json inside the ZIP archive. Programs remain as G-code text
under a programs/ folder.

This eliminates ~400 lines of hand-written XML read/write code
and fragile ID-based dictionary linking. Now uses System.Text.Json
with DTO records for clean serialization. Also adds Priority and
Constraints fields to drawing serialization (previously omitted).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 18:44:43 -04:00
ajandClaude Opus 4.6 cc286dd9b7 refactor: extract OpenNest.IO class library from WinForms project
Move DxfImporter, DxfExporter, NestReader, NestWriter, ProgramReader,
and Extensions into a new OpenNest.IO class library. The WinForms project
now references OpenNest.IO instead of ACadSharp directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 15:41:07 -04:00