Nests every part as the axis-aligned box of its material at its minimum-area rotation and packs boxes with a maximal-rectangles free list (6 placement rules x global/ordered pick). Sheet choice uses the salvage-credited look-ahead cost. Curved extremes read the way the layout check sees them (circumscribed arcs on the Clipper grid), so discs, rings and obrounds stay valid at box contact; an 80-job sweep failed 16-50 jobs before that rule. Local 2026 production lanes (--min-salvage-dimension 12, --parallel 3): - 91 all-rectangular jobs: 91/91 valid, cost 333081 vs best general 332153 (Gpt6Astra, 89/91 valid), 5.9 s vs 13.7 s (Opus55) and 169.5 s (Gpt6Astra) - 77 box-filling (>= 90%) jobs: 77/77 valid, lowest total cost 641637
4.2 KiB
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, forAutomatic, 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 ofNestTolerances.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).