fix(sequencing): cut scrap cutoffs before crossed parts

This commit is contained in:
aj
2026-09-29 00:05:28 -04:00
parent c3dd346b7a
commit 8720580004
6 changed files with 333 additions and 7 deletions
+1
View File
@@ -156,6 +156,7 @@ Keep vendor programming manuals and full-text extracts outside source control un
- `FillScore` uses lexicographic comparison (count > utilization > compactness) to rank fill results consistently across all fill strategies. After its null/empty guards, `DefaultFillComparer` decides unequal counts without scoring; equal counts still use scores, and exact ties retain the current layout. `FillHelpers.FillPattern` computes eager scores only when no custom comparer is supplied; custom comparers remain authoritative and may perform their own scoring.
- **Extents column pitch**: for finite valid geometry, finite pair height, and finite nonnegative spacing, `FillExtents.BuildColumn` uses `pair.Bbox.Width + partSpacing` directly. The old vertical slide calculation clamps to the same pitch, so it need not prepare boundaries or temporary test clones. Negative/nonfinite spacing or nonfinite pair height retains the legacy calculation: public/interactive callers do not all validate spacing. Do not remove `BuildPair` boundary preparation or the adjusted-column overlap fallback, or turn this shortcut into a geometry/validation policy change.
- **Cut-off materialization lifecycle**: `CutOff` objects live on `Plate.CutOffs`. Each generates a `Drawing` (with `IsCutOff = true`) whose `Program` contains trimmed line segments. `Plate.RegenerateCutOffs(settings)` removes old cut-off Parts, recomputes programs, and re-adds each at its previous index in `Plate.Parts` (its cut sequence number; new cut-offs go at the end). Regeneration triggers: cut-off add/remove/move, part drag complete, fill complete, plate transform. Cut-off Parts are excluded from quantity tracking, utilization, overlap detection, and nest file serialization (programs are regenerated from definitions on load; `CutOffDto.Sequence` restores each one's place in the cut sequence). Posts must follow `Plate.Parts` order for cut-offs too, not move them to the end.
- **Plate sequencing**: `PlateSequencing.Apply` in Engine is the shared current/all-plate application boundary. Reverse the sequencer's exit-first route before enforcing cutoff-before-crossed-part dependencies, then commit `Plate.Parts` order. Use nominal cutoff spans and reference-keyed definitions, not trimmed segments or drawing names. The conservative placed-bounds check honors start/end limits, preserves ordinary part order, and does not force noncrossing tail separators to the front. This runs on automatic sequence application, not manual edits or regeneration; see [cutoff sequencing](docs/automatic-scrap-cutoffs.md#part-sequencing).
- **Automatic scrap cutoffs**: `AutomaticCutOffPlanner.Create` in Core proposes detached vertical `CutOff` definitions and preview parts from the real-part envelope, with quadrant-aware pitch and a verified full-width tail separator beyond `max(PartSpacing, PartClearance)` plus tolerance. Planning must not mutate the plate. Apply only an unblocked, current plan by adding its definitions to `Plate.CutOffs` and calling `Plate.RegenerateCutOffs`; never accept preview Parts directly. Existing equivalent full-span lines are suppressed, while same-line limited cuts require manual review. Nominal spacing is not certification of disconnected hopper-sized scrap. Both Plate and Nest menus use the modal `AutomaticCutOffForm`; Nest applies one setting set to every plate through Core's `AutomaticCutOffBatch`, which replans all plates before any changes, refuses the entire batch on blocking diagnostics, and rolls back cutoff programs/sequence on failure. Minimum tail-to-keep defaults to 12 in / 304.8 mm in the dialog; `AutomaticCutOffOptions.MinimumTailLength` is in model units (zero disables the minimum). A shorter tail suppresses only the new final separator, never other grid lines or existing definitions. See [operator workflow and limitations](docs/automatic-scrap-cutoffs.md).
- **User-defined G-code variables**: Programs can contain named variable definitions (`name = expression [inline] [global]`) referenced in coordinates with `$name`. Variables resolve to doubles at parse time for geometry/nesting. `VariableRefs` on `Motion`/`Feedrate` track the symbolic link so post processors can emit machine variable references. Cincinnati post maps non-inline variables to numbered machine variables (`#200+`) with descriptive comments. Global variables share a number across programs; local variables get per-drawing numbers. `ProgramReader` uses a two-pass parse (collect definitions, then parse G-code with substitution). `NestWriter` serializes definitions and `$references` back to text for round-trip fidelity.
- **CAD import pipeline**: All "DXF → Drawing" conversion goes through `OpenNest.IO.CadImporter`. The UI form uses `Import` on file load (storing the mutable result in a `FileListItem`) and `BuildDrawing` on save (passing the user's current visible entities and bends). MCP, API, and Training projects use `ImportDrawing` for headless conversion. The console uses `Import` followed by `BuildDrawing` so it can report bend-repair outcomes. This guarantees all callers produce drawings with the same shape: pierce-point `Source.Offset`, stable `SourceEntities` with GUIDs, `SuppressedEntityIds`, detected bends, and metadata.