diff --git a/AGENTS.md b/AGENTS.md index 6484821..0d43834 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -34,7 +34,7 @@ Releases: follow [the release procedure](docs/releasing.md) and `scripts/Publish - `OpenNest.Core`: domain (`Nest -> Plate -> Part -> Drawing -> CNC.Program`), geometry, cutting strategies and diagnostics. Angles are radians; use `Tolerance.Epsilon` for geometry comparisons. `OpenNest.Math` shadows `System.Math`, so qualify the latter. - `OpenNest.Engine`: whole-job API in `Jobs/`, interactive proposals via `PlateFillService`, fill strategies, best-fit pairs, packing, sequencing and rapid planning. `INestingEngine.Solve(NestJob)` returns stock IDs/poses; boundary adapters map drawings and materialize results. `NestJobRunner` validates its candidates before committing demand/stock accounting. Do not assume arbitrary plug-in output or interactive paths received that validation. Job identity is reference-based, not drawing-name-based. -- Engine plug-ins implement `INestingEngine` with a public parameterless constructor, reference Engine and load from `Engines/` beside the host. Build them outside this repository/solution; do not add their projects here. +- Built-in whole-job engines live in `OpenNest.Engine/NestingEngines//`, named for the jobs they suit; see [nesting engines](docs/nesting-engines.md). A change must beat that engine's current benchmark result with every layout valid. External plug-ins implement `INestingEngine` with a public parameterless constructor and load from `Engines/` beside the host; keep their projects out of this solution. - `OpenNest.IO`: ACadSharp import/export and ZIP-based `.nest` persistence. All DXF-to-Drawing conversion goes through `CadImporter`: `Import` + `BuildDrawing` for editable/reporting flows, `ImportDrawing` for headless callers. Preserve source offsets, entity IDs, suppressed entities and bends. Bend repair is opt-in, requires explicit source units and may not alter cut geometry or unrelated marks. - `OpenNest`: WinForms UI (`Forms/`, `Controls/PlateView`, `Actions/`). `OpenNest.Data` holds cross-platform persistence; new-nest defaults live in `%APPDATA%\OpenNest\defaults.json`. Posts live in `Posts/OpenNest.Posts./` and deploy to the desktop output's `Posts/` directory. - `OpenNest.Console`, `OpenNest.Mcp`, `OpenNest.Api`: front ends; `OpenNest.Benchmark`: whole-job engine comparisons; `OpenNest.Gpu`: GPU evaluators; `OpenNest.Training`: ML data collection. Benchmark timing comparisons require `--parallel 1`; validate layouts and fulfillment, not just elapsed time. diff --git a/README.md b/README.md index e0fbc03..e291fcf 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ A Windows desktop application for CNC nesting — imports DXF drawings, arranges - Windows 10+ for the desktop app; the console, API, and most test projects build on Linux/macOS too. - [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) to build from source. -Windows release ZIPs are self-contained: extract the entire archive into a new folder and run `OpenNest.exe`; no separate .NET installation is needed. The package includes the Gpt6Astra, Opus55, and Qwen38FlashNext engine plug-ins. Use the ZIP and SHA-256 checksum from [GitHub Releases](https://github.com/ajisaacs/OpenNest/releases), not the source-code archives. +Windows release ZIPs are self-contained: extract the entire archive into a new folder and run `OpenNest.exe`; no separate .NET installation is needed. The Rectangles and Irregular nesting engines are built in; see [nesting engines](docs/nesting-engines.md). Use the ZIP and SHA-256 checksum from [GitHub Releases](https://github.com/ajisaacs/OpenNest/releases), not the source-code archives. ## Build, Test, Run @@ -67,7 +67,7 @@ dotnet run --project OpenNest.Benchmark -- ./benchmark-jobs \ --sheet-sizes 48x96,60x120,72x120 --engines Default,StockLadder --csv results.csv ``` -Layouts are validated (bounds, spacing, quantity, rotation, stock match); invalid runs place nothing and pay the penalty. `--parallel` (default 3) speeds up scoring but inflates `Time(ms)` — use `--parallel 1` when comparing speed. Pass `--sheet-sizes` for an unbiased run; otherwise only each file's original sizes are offered. `--progress` logs each solve's start, the engine's `NestJobProgress` (plate evaluations throttled to one line per 2 s, every plate commit) and its finish. Custom engines drop in as DLLs implementing `INestingEngine` (public parameterless constructor) in an `Engines/` folder next to the benchmark. Community engines live in [OpenNest-Engines](https://git.thecozycat.net/aj/OpenNest-Engines). +Layouts are validated (bounds, spacing, quantity, rotation, stock match); invalid runs place nothing and pay the penalty. `--parallel` (default 3) speeds up scoring but inflates `Time(ms)` — use `--parallel 1` when comparing speed. Pass `--sheet-sizes` for an unbiased run; otherwise only each file's original sizes are offered. `--progress` logs each solve's start, the engine's `NestJobProgress` (plate evaluations throttled to one line per 2 s, every plate commit) and its finish. Custom engines drop in as DLLs implementing `INestingEngine` (public parameterless constructor) in an `Engines/` folder next to the benchmark. Built-in engines and how to change them: [nesting engines](docs/nesting-engines.md). ## Project Structure @@ -91,11 +91,15 @@ Engines implement `INestingEngine.Solve(NestJob)`. Desktop Auto Nest, console au | Engine | Description | |--------|-------------| +| **Rectangles** | Plain and near-rectangular plates: maximal-rectangles box packing | +| **Irregular** | Irregular profiles: no-fit-polygon frontier packing | | **Default** | Multi-phase: linear fill → pairs → rect best-fit → extents | | **Strip** | Iterative shrink-fill for mixed-drawing layouts | | **Vertical / Horizontal Remnant** | Optimizes a clean remnant drop on one edge | | **StockLadder** | Whole-job, stock-constrained baseline with salvage-credit ranking | +Which engine suits which jobs, renamed engine names, and the rules for changing an engine: [nesting engines](docs/nesting-engines.md). + ## File Format `.nest` files are ZIP archives containing drawing programs, metadata, plates, and placements. Saved nests retain each part's lead-ins, lead-outs, tab gaps, and locks, plus the plate's cutting settings. Changing a drawing's geometry removes obsolete cutting paths from its parts; name, quantity, and color edits preserve them. See the [file-format reference](docs/nest-file-format.md) for compatibility and recovery behavior. diff --git a/docs/automatic-nesting.md b/docs/automatic-nesting.md index f994db7..0d18c1f 100644 --- a/docs/automatic-nesting.md +++ b/docs/automatic-nesting.md @@ -27,9 +27,10 @@ Every invalid result shows the validation report before any plates are changed: Overlap Check displays material overlaps, not every spacing/stock/rotation failure in the report. A layout passing validation may still be incomplete; completeness and stop reason are separate from geometric validity. This check does not replace pre-post CNC verification. The selected engine is saved in `%APPDATA%\OpenNest\engine-selection.json`. -Selection is restored after plug-ins load. If the saved engine is unavailable, -Default is selected and the status bar reports the fallback; startup does not -replace the saved missing-engine preference. +Selection is restored after plug-ins load. A saved name from an earlier release +maps to the engine that replaced it (see [nesting engines](nesting-engines.md)). +If the saved engine is unavailable, Default is selected and the status bar +reports the fallback; startup does not replace the saved missing-engine preference. ## Integration constraints diff --git a/docs/nesting-engines.md b/docs/nesting-engines.md new file mode 100644 index 0000000..e8c77a9 --- /dev/null +++ b/docs/nesting-engines.md @@ -0,0 +1,54 @@ +# Nesting engines + +Whole-job engines implement `INestingEngine.Solve(NestJob)` and are selected by name through +`NestingEngineRegistry`. Every automatic nesting front end validates engine output the same way; +see [automatic nesting and validation](automatic-nesting.md). + +## Built-in engines + +Engines are named for the jobs they suit, not for how or by whom they were built. Engine code lives +in `OpenNest.Engine/NestingEngines//`, its tests in `OpenNest.Engine.Tests/NestingEngines/`. + +| Engine | Best for | Method | +|---|---|---| +| Rectangles | Plain and near-rectangular plates | Each part packed as the box of its material at its minimum-area rotation, using a maximal-rectangles free list; stock chosen sheet by sheet by salvage-credited look-ahead cost | +| Irregular | Irregular profiles | No-fit-polygon frontier packing with gap filling, six whole-job strategy variants and a tail re-plan | +| StockLadder | Caller-supplied stock ladders | Constrained-first fill with equivalent-demand area repacking | +| Default, Strip, Vertical Remnant, Horizontal Remnant | Single-strategy fills | The fixed placement strategies behind interactive fill | + +Rectangles places irregular parts validly, but only as their bounding boxes; it never nests into a +notch or hole. Box sides account for how the layout check flattens arcs, so round-edged parts stay +valid at box contact. + +## Renamed engines + +Earlier releases shipped these as plug-ins under other names. The registry maps the old names so +saved desktop selections, scripts and API requests keep working: + +| Old name | Now | +|---|---| +| `Opus55NestingEngine` | Irregular | +| `RectanglesNestingEngine` | Rectangles | + +Gpt6Astra and Qwen38FlashNext are no longer shipped and have no alias. A saved selection of either +falls back to Default with the usual status-bar warning. + +## Changing an engine + +- A change lands only when it beats the engine's current result on `OpenNest.Benchmark` for the + jobs that engine targets, with every layout valid. Report cost, validity, unplaced parts and time. +- Placement must be deterministic: no clocks, unseeded randomness or environment variables. Budget + work by counting it; wall time may stop work only through the cancellation token. +- Keep each engine's tests passing, including `EngineContractTests` (quadrants, overflow, + priority, cancellation, stock and plate limits, determinism). Every layout in those tests is + checked with `NestLayoutCheck`, the benchmark's validator. +- Engines may share code. Move a helper into shared Engine code when a second engine needs it, + rather than copying it. + +## Plug-ins + +External engines still load from an `Engines/` folder beside the desktop, console, MCP or benchmark +executable. A plug-in implements `INestingEngine` with a public parameterless constructor and +registers under its CLR type name. A plug-in whose name matches a built-in engine, or a renamed +engine's old name, is skipped: a leftover `OpenNest.Engine.Opus55.dll` cannot shadow Irregular. +Leftover Gpt6Astra or Qwen38FlashNext DLLs still load as ordinary plug-ins until deleted. diff --git a/docs/releasing.md b/docs/releasing.md index a154f9d..f16c54f 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -19,13 +19,12 @@ Git refs are owned by Gitea (`aj/OpenNest`) and push-mirrored to GitHub 4. Download the `OpenNest-X.Y.Z-win-x64` artifact and verify its `.sha256`. It contains `OpenNest.vX.Y.Z.win-x64.zip`, with the .NET runtime, native dependencies, shipped configurations, all three post-processors, license, - and `build-info.json` identifying the exact source commit. Gpt6Astra, Opus55, - and Qwen38FlashNext are bundled in `Engines/` with their MIT license and source - manifest. `scripts/external-engines.json` pins the external repository revision; - no moving branch or prebuilt third-party DLL is used. The script tests and - builds each engine against this host, then exercises actual packaged registry - discovery and an intentionally missing-DLL failure case. Keep the explicit - engine allowlist; never package the template, shared test kit, or test DLLs. + and `build-info.json` identifying the exact source commit. The nesting engines + are built into `OpenNest.Engine.dll`; no external engine repository or plug-in + DLL is packaged. `scripts/ReleaseSmoke` loads the packaged engine assembly and + checks that every built-in engine instantiates from it, that the renamed + `Opus55NestingEngine` selection resolves to Irregular, and that an unknown + engine name is rejected. The workflow has read-only repository permissions and does **not** publish releases. Once present on the default branch, it can also be dispatched manually