From 55ab8ec4a59bc5a61d3c818be982de649cee4ef5 Mon Sep 17 00:00:00 2001 From: AJ Isaacs Date: Wed, 28 Oct 2026 22:16:37 -0400 Subject: [PATCH] docs: describe irregular stock sheets Co-Authored-By: Claude Fable 5.1 --- AGENTS.md | 2 ++ docs/irregular-stock.md | 63 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 docs/irregular-stock.md diff --git a/AGENTS.md b/AGENTS.md index be7f5e63..239ab797 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -51,6 +51,7 @@ Releases: follow [the release procedure](docs/releasing.md) and `scripts/Publish - `FillLinear` geometry caches are per public call, keyed by `Program` reference identity; never share them across calls/threads. `PartOverlapChecker` is per check; parts/programs must not mutate during its lifetime. - `FillScore` ranks count, utilization, compactness; exact ties keep the current layout. Custom comparers remain authoritative. Preserve extents' negative/nonfinite-input fallback, pair preparation and adjusted-column overlap checks. Do not remove bounds recomputations without threshold/rounding characterization. - `ObservableList` events own drawing/plate quantity tracking; avoid double accounting. Cutoff parts are excluded from quantity, utilization and overlap checks. +- `Plate.Outline`/`NestPlateStock.Outline` (`SheetOutline`) make a sheet irregular; `Size` stays its bounding box. Only Irregular fills it (`PackBoundary` eroded by the largest edge spacing); every other engine and fill strategy must place nothing on it, validation must reject parts outside it or over its obstacles, and automatic cut-offs refuse it. See [irregular stock](docs/irregular-stock.md). - Cutoffs persist as definitions on `Plate.CutOffs`; apply through `RegenerateCutOffs`, never preview parts. Preserve sequence positions. Batch planning must finish before mutation and roll back on failure. Use `PlateSequencing.Apply` for automatic cutoff dependencies, with nominal spans/reference identity rather than trimmed geometry/names. - A cutoff starts only at the origin-side edge: stock can be oversize, so the far edge is unknown. Only a head-locked overcut (`CutOff.HeadLockOvercut`, `HeadHeightLock` markers) may start its far-edge segment there; posts refuse it without lock codes. - Fixed emissions (locked programs, drawing-pinned contours) are accepted as given: their violations warn on an UNVERIFIED proposal and never steer the search, while every planner-chosen motion stays strict. Plates without them must keep the `PlanningCharacterizationTests` digests. @@ -61,6 +62,7 @@ Releases: follow [the release procedure](docs/releasing.md) and `scripts/Publish Read the relevant contract before changing its behavior: - [Nest file format](docs/nest-file-format.md) +- [Irregular stock](docs/irregular-stock.md): outlined sheets, what honors the outline and what refuses it - [Directional slides](docs/geometry/directional-slides.md) and [pair-spacing limits](docs/geometry/pair-spacing.md) - [Lead-in placement](docs/geometry/lead-in-placement.md) (including the planner's eroded pierce for cutouts too small for their lead-in) and [pierce zones](docs/geometry/pierce-zone.md): opt-in `PierceDiameter` clearance, the hole pole fallback and the planner's perimeter scrap fallback - [Breakoffs](docs/breakoffs.md): tabbed scrap; `Break`-layer open cuts that are cut but are not material diff --git a/docs/irregular-stock.md b/docs/irregular-stock.md new file mode 100644 index 00000000..f62b8082 --- /dev/null +++ b/docs/irregular-stock.md @@ -0,0 +1,63 @@ +# Irregular stock sheets + +A sheet need not be a rectangle: a remnant or drop, a sheet with a burned or damaged area, or +one already cut into can be nested on as it is. Such a sheet carries a `SheetOutline` +(`OpenNest.Core/SheetOutline.cs`): a closed polygon in plate coordinates (the sheet's +lower-left frame, as clamp zones) with optional obstacle polygons for areas inside it that must +stay empty. The plate's `Size` stays the outline's bounding box, so every rectangular code path +keeps working on the box; the outline narrows what may hold parts. + +## Defining an outline + +- **Import a CAD file.** `SheetOutline.FromGeometry` takes the file's entities: the largest + closed contour (by bounding box) is the sheet and every other closed contour an obstacle; + marks and open contours are ignored. Arcs are chorded at 0.001 model units, then the outline is + eroded and each obstacle inflated by that much, so the stored polygons never reach past the + true edges. The file's units are taken as the nest's, exactly as drawing import does. + - Desktop: Plate > Edit Plate > **Outline...** reads a DXF/DWG; **Clear** makes the sheet a + rectangle of its current size again. The size box is read-only while there is an outline. + - Console: `--outline ` with `--autonest` makes the target plate that sheet. +- The constructor normalizes any polygon: counterclockwise, starting at its lowest-left vertex, + translated so the bounds start at the origin. It refuses fewer than three distinct vertices, + nonfinite coordinates, zero area and self-crossing polygons, and drops an obstacle wholly + outside the outline. + +Drawing an outline in the plate view and taking the leftover of a cut plate are not implemented. + +## What honors it + +| Area | Behavior | +|---|---| +| Irregular engine (and Default through it) | Fills the outline: the stock's usable material (outline less obstacles, eroded by the outline inset below) is the `FrontierPacker`'s `PackBoundary`, the same boundary the cutout packer uses, so every orientation's free region starts inside it | +| Rectangles, Circles, FlatBar, the fill strategies (Fill, Strip, remnants) | Place nothing on an outlined sheet; Default then keeps Irregular's layout. Interactive fills (`PlateFillService`) refuse an outlined plate with a message | +| Layout check and the runner's candidate validation | A part's circumscribed material must lie inside the usable area, within the shared work-area slack; a part in a missing corner or over an obstacle is a violation ("falls outside the outline ... or over one of its obstacles"). The area budget is the usable area | +| Edge spacing | The outline is eroded by the **largest** of the four edge spacings (`NestPlateStock.OutlineInset`), so no outline edge is closer to a part than the rectangle's own sides would be. The rectangular work area still applies and is never larger than that erosion | +| Clamps | Unchanged: the rail is resolved for the bounding box, zones are keep-outs as before | +| Support bed | Unchanged: it is fixed to the machine and reports contacts under material | +| Area, utilization, cost | `Plate.Area` and `NestPlateStock.Area` are the material area (outline less obstacles); area-based cost prices that area and utilization divides by it | +| Salvage and remnants | No salvage credit and no `expectedRemnant`: no rectangular edge strip is guaranteed inside an outline | +| Manual cut-offs | A line is cut only where it crosses material: each crossing is a segment of its own, started at the material's edge and overtravelled past the far one, within the user's limits and the usual part clearance. The head-locked overcut applies only to a span that reaches the bounding box's far edge | +| Automatic cut-offs | Refused: `AutomaticCutOffPlanner` rejects an outlined plate ("Automatic cut-offs need a rectangular sheet") | +| AutoSize, Snap to Standard Size | Leave an outlined plate unchanged: the outline is a particular piece of material | +| Rotate 90/180 | Turn the outline with the sheet | +| Repeated layouts, clamp-removal recovery, stock matching | An outlined stock is never the same stock as its rectangle | + +Setting `Plate.Outline` sets the plate's size to the outline's bounds; setting any other size +drops the outline. The Edit Plate dialog therefore applies the outline instead of a parsed size. + +## File format and undo + +The outline is saved per plate under an optional `outline` key (see +[nest file format](nest-file-format.md#sheet-outline)); files without it load rectangles as +before, and a malformed value loads the saved size as a rectangle with a reader warning. Undo +snapshots go through the same writer and reader, so a restore rebuilds the outline. + +## Limits + +- Only the Irregular engine nests on an outlined sheet. A job offering an outlined sheet and a + rectangle to Default may well land on the rectangle: Default keeps the cheaper valid layout. +- Auto Nest's stock-options grid offers rectangles only; an outlined sheet is nested through + the target plate (no options), or through `NestPlateStock` directly (console, MCP, API callers + that pass an outline). +- The stored polygon is inside the true material by up to the chord tolerance (0.001) on + imported arcs and exactly on straight edges.