mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-10-10 11:04:13 -04:00
Default is the engine every front end uses when none is named. It now runs Irregular, then Rectangles, checks both layouts with NestLayoutCheck and keeps the best: valid first, then fewest unplaced parts, then lowest salvage-credited cost; ties keep Irregular. A candidate that throws or returns nothing is skipped, cancellation stops the search, and only the chosen layout's plate commits are reported. Neither engine wins every job in the lane benchmarks, and Rectangles adds little time while also covering Irregular's invalid layouts. The registry lists Default first and no longer maps the name to Fill; fill strategy callers still read Default as Fill. A future circle/ring engine joins as another candidate.
123 lines
8.3 KiB
Markdown
123 lines
8.3 KiB
Markdown
# 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/<Name>/`, its tests in `OpenNest.Engine.Tests/NestingEngines/`.
|
|
|
|
| Engine | Best for | Method |
|
|
|---|---|---|
|
|
| Default | Any job; used when no engine is named | Runs Irregular, then Rectangles, checks both layouts with the layout check and keeps the best: valid first, then fewest unplaced parts, then lowest salvage-credited cost; ties keep Irregular |
|
|
| 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 and best-fit pairs, six whole-job strategy variants and a tail re-plan |
|
|
| StockLadder | Caller-supplied stock ladders | Constrained-first fill with equivalent-demand area repacking |
|
|
| Fill, Strip, Vertical Remnant, Horizontal Remnant | Single-strategy fills | The fixed placement strategies behind interactive fill; Fill is the multi-phase lattice fill (linear, pairs, rectangle best-fit, remainder) |
|
|
|
|
Neither Irregular nor Rectangles wins every job, even within its own lane, so Default runs both
|
|
rather than choosing by part shape; Rectangles adds little time and is also the fallback when an
|
|
Irregular layout fails the check. A candidate that throws is skipped. Default routes the whole job:
|
|
engines cannot share a sheet, so a job mixing plain and irregular parts goes to both engines whole.
|
|
A future circle/ring engine joins Default as another candidate.
|
|
|
|
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.
|
|
|
|
Interactive/full-area box packing uses the same 90% work-area slack allowance as Rectangles.
|
|
A free box may absorb a slightly oversized side only at its right/top edge when that edge
|
|
coincides with the plate work-area boundary. Internal leftover edges keep the strict packing
|
|
tolerance, and actual part dimensions still determine spacing away from the plate boundary.
|
|
|
|
Irregular keeps nominal orientation bounds for line-only outlines, so an allowed rotation can
|
|
fit exactly between the configured plate-edge gaps. These bounds use original rotated line
|
|
endpoints, retaining material extents even when polygon cleanup discards short-edge chains.
|
|
Curved outlines retain conservative flattening-error padding. This does not relax part-spacing
|
|
footprints, no-fit polygons or layout validation tolerances; a part extending beyond the accepted
|
|
work-area bounds remains invalid.
|
|
|
|
Irregular fills gaps and open notches using outer profiles; it does not yet place parts inside
|
|
enclosed cutouts. For a part with two or more copies it also offers its best-fit pairs (two copies
|
|
interlocked, as the Best Fit viewer shows them) alongside the single copies, and places a pair
|
|
where both members' free regions allow it. Each pair's internal spacing is re-checked with the
|
|
layout check before it is offered, and only rotations the part's policy allows are used. A pair
|
|
may introduce legal rotations beyond the sampled single poses; these remain eligible even when
|
|
none of the sampled singles fits the stock. Both members block space separately, leaving their
|
|
notches and intervening gaps available for later parts. Concave no-fit polygons are prepared
|
|
with a single boundary/containment union.
|
|
Any remaining numerical hole is filled only when its entire ring is certified to lie in forbidden
|
|
space, preserving genuine enclosed placement pockets without changing spacing tolerances.
|
|
|
|
When remaining demand exceeds two, Irregular also offers Fill patterns as optional
|
|
multi-member candidates, not as solid bounding boxes or a whole-job Fill fallback. It searches
|
|
the empty work area and physical leftover space for up to two high-area rectangles. Occupied
|
|
outlines are expanded by part spacing before rectangle search. Each sheet prepares blocks initially
|
|
and after its first placement, for up to four high-demand-area types; each type has at most eight
|
|
new Fill preparations per spacing per solve. Repeated rectangles reuse private drawing/candidate
|
|
caches. Quantity-one and quantity-two requests never run block Fill.
|
|
|
|
Block members are trimmed to remaining demand, mapped back to source-frame rotations, and checked
|
|
for legal rotations and internal material clearance before competing with singles and pairs.
|
|
Group-only rotations do not expand the single-part rotation choices. Placement intersects all
|
|
member free regions and subtracts each placed member separately, preserving usable gaps. A failed
|
|
or invalid Fill proposal leaves singles and pairs available. Large enclosed-pocket blocks remain
|
|
pending the hole-geometry integration; containment cutting order and shop-use safety acceptance
|
|
remain separate sequencer/verification work.
|
|
|
|
## Filling cutouts (not yet in production)
|
|
|
|
Placing parts inside another part's enclosed cutout is being built as a step that runs before any
|
|
engine, so every engine benefits. Nothing calls it yet: a part inside a cutout must be cut before
|
|
the cutout's contour, and the sequencer does not enforce that order.
|
|
|
|
`CutoutLatticeFill` (`OpenNest.Engine/Jobs/Cutouts/`) fills one closed cutout with copies of one
|
|
part. It runs Fill over the cutout's bounds plus one part step on every side, then shifts
|
|
that lattice across a grid of offsets of up to half a step each way. At each offset it keeps the
|
|
copies whose spacing-grown outline lies inside the cutout, using the part's inner-fit region of
|
|
the inscribed, flattened cutout, and the offset keeping the most copies wins. Every returned pose
|
|
is then checked against the frame and the other copies with `NestLayoutCheck.Clears`, the test the
|
|
layout check uses. The method suits many small copies in a large cutout; a few large inserts are
|
|
meant for no-fit-polygon placement. Fill can return different, equally scored lattices on repeated
|
|
calls for some parts, so results are not yet guaranteed identical between runs.
|
|
|
|
## Renamed engines
|
|
|
|
The registry maps names used by earlier releases (the first two shipped as plug-ins) so saved
|
|
desktop selections, scripts and API requests keep working:
|
|
|
|
| Old name | Now |
|
|
|---|---|
|
|
| `Opus55NestingEngine` | Irregular |
|
|
| `RectanglesNestingEngine` | Rectangles |
|
|
|
|
In v0.3.0 and earlier, `Default` was the multi-phase fill engine now named Fill. `Default` now names the
|
|
choosing engine above, so saved selections, scripts and API requests that name it get that
|
|
engine. Fill-strategy calls (interactive fill, `PlateFillService`, console fill without
|
|
`--autonest`, MCP fill tools) still read `Default` as Fill.
|
|
|
|
Gpt6Astra and Qwen38FlashNext are no longer shipped and have no alias. A saved selection of either
|
|
falls back to the default engine 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<TEngine>` (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.
|