# OpenNest.Engine.Rectangles A whole-job `INestingEngine` for the **rectangle lane**: jobs whose parts are plain or near-rectangular plates. Every part is nested as the axis-aligned box of its material at its minimum-area rotation(s), packed with a **maximal-rectangles** free list (Jylänki, *A Thousand Ways to Pack the Bin*, 2010). For these parts the box wastes almost nothing, and exact box packing is both denser and far faster than contour-sliding engines. Irregular parts are still placed validly, but only as their bounding boxes: nothing is nested into another part's notch or hole. Use a general engine (Opus55, Gpt6Astra) for irregular work. ## Algorithm **1. Boxes (`BoxCatalog`)** - Rotations come from the host's `RotationCandidates.ForShape` (the policy angles plus, for `Automatic`, the minimum-bounding-rectangle alignment). Only the rotations whose box area is within 1e-6 of the minimum are kept, with duplicate box shapes removed. A 10 x 4 plate drawn at 30° is squared up; a fixed-rotation part keeps its one angle. - Bounds use material contours only (rapids and scribe/etch excluded), like the layout check. - **Curved extremes:** the layout check circumscribes arcs and snaps to a 1e-4 grid, so a disc or obround reads slightly larger than its true arc. Each box side takes the check's own outline (`ClipperBridge.OffsetForValidation`) plus one grid unit wherever that outline sticks out by more than a quarter of `NestTolerances.SpacingSlack`. Straight-edged parts are unchanged and still pack at exactly the part spacing. **2. One sheet (`MaxRectsSheet`, `SheetPacker`)** - Boxes and the work area are grown by the part spacing on their right/top sides, so touching grown boxes are exactly one spacing apart and the last box can touch the work-area edge. - The free list keeps every maximal empty rectangle; placing a box splits each free rectangle it hits and prunes the contained ones. - Six placement rules: best short side, best long side, best area, bottom-left, left-bottom and contact point. Two pick modes: *global* (each step places whichever remaining box scores best anywhere) and *ordered* (priority, then largest box first, each type filled until it stops fitting). Lower priority numbers are always served first. **3. Whole job (`RectanglesNestingEngine`)** - Sheet by sheet, every available stock is packed under all 12 rule/mode pairs. The candidate with the lowest estimated whole-job cost wins: its salvage-credited `NestJobCost.NetSheetArea`, plus the remaining demand priced at the best net-area-per-part-area ratio any candidate reached. A candidate that leaves more of the most urgent priority tier unplaced never wins. - Deterministic: no clocks or randomness; the only stop besides completion is the host token. ## Results `OpenNest.Benchmark`, `--min-salvage-dimension 12`, each file's own sheet sizes, `--parallel 3` (times are under that load). Synthetic results only here; the real-part corpus stays local. Local corpus of converted 2026 production nests (file names and parts stay out of this repo): | Lane | Jobs | Engine | Valid | Total cost | Time | |---|---|---|---|---|---| | Every part plain or near-rectangular | 91 | **Rectangles** | 91 | 333,081 | 5.9 s | | | | Gpt6Astra | 89 | 332,153 | 169.5 s | | | | Opus55 | 91 | 332,925 | 13.7 s | | | | StockLadder | 89 | 337,641 | 36.0 s | | Every part fills ≥ 90% of its box | 77 | **Rectangles** | 77 | 641,637 | 19.1 s | | | | Gpt6Astra | 76 | 651,514 | 195.6 s | | | | StockLadder | 76 | 671,590 | 93.4 s | | | | Opus55 | 76 | 693,972 | 31.8 s | Rectangles never leaves a part unplaced that another engine placed. Its losses are a handful of multi-sheet jobs where the sheet-by-sheet greedy choice commits to a worse sheet mix (see Next). `tests/` (27 tests): contract, starter and engine tests, including an 80-job sweep of discs, rings, obrounds and triangles at four spacings that failed 16–50 jobs before the curved-extreme rule. ## Next - Multi-sheet jobs: the sheet-by-sheet greedy choice loses to whole-plan search on a few jobs. Re-plan the last sheets and try whole-job variants, as Opus55 does. - Guillotine-only mode for shears and for cut-off-friendly layouts. - Exhaustive search for small jobs (one or two part types).