Files
OpenNest-Engines/OpenNest.Engine.Qwen38FlashNext
ajandClaude Opus 5.5 90f07603e2 feat(qwen38flashnext): add the finished engine
Qwen3.8-Flash-Next's final version after a 14.5-hour optimization run
(its commit 7d7fca3): cost-first sheet trials, largest-area-first
demand order, and a cached-triangulation exact gate that brought a
219-part production job from timeout to ~106 s. 13/13 tests pass
against OpenNest master.

README cleaned for publishing: the model-facing template rules are
replaced by a one-line independence statement, the production job is
described generically instead of by its PEP job/file name (also in a
JobSolver comment), results show both sheet pools as re-measured here
(the 9-size claim in its report didn't reproduce: it grabs 96x240 and
under-fills them), and the stale StockLadder-crash note is gone now
that core leaves etch marks out of nesting.

Also drops a stale Aurora plugin reference from Opus55's README and
lists the engine in the repo README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 06:57:11 -04:00
..

OpenNest.Engine.Qwen38FlashNext

An independent whole-job INestingEngine built by Qwen3.8-Flash-Next: bottom-left greedy insertion over convex no-fit polygons with an exact clearance gate. It does not call, wrap, or select over any built-in engine, nester, filler, or runner.

Algorithm

Bottom-left greedy insertion over convex No-Fit-Polygons, with an exact material-clearance gate, driven sheet by sheet by a greedy demand scheduler. All geometry math is the engine's own (Engine/); it calls no built-in nester, filler, or runner.

  • PartPreparation rebuilds each snapshot into a closed contour topology (perimeter + cutouts; rapids/scribe marks dropped), flattens it circumscribed (the collision polygon always contains the true material), and caches per-(part, angle, spacing) geometry: bounds, convex hull, and the spacing-inflated outline rotated into that orientation's frame (offset commutes with rotation; an unrotated inflation tests the candidate against the material of a different angle - this was a real overlap bug, caught by RotatedConcavePartsKeepSpacingAtFixedAngles). Candidate angles are the policy angles, or 0/90/180/270 plus the rotating-calipers minimum-bounding-rectangle angle for automatic rotation.
  • SheetPacker places one part instance at a time. Per already-placed part it builds a convex NFP as placedHull (+) disk(spacing) (+) reflect(candidateHull) via its own Minkowski edge-merge (Convex.cs; the merge picks the more-clockwise frontier edge, an inverted comparison here corrupts every non-parallel sum into a self-intersecting contour), then enumerates corner-point candidates: anchor work-box corners, NFP vertices, and NFP-edge/box-line slides, tried in ascending bottom-left order. Because the NFP is hull-based it only certifies clearance when both parts are convex solids with uncapped hulls; everything else falls through to the exact gate - placed material inflated by the spacing (holes shrunk, closed holes treated solid) versus the candidate's raw material with holes subtracted, the same inflation rule the benchmark validator uses, so interlocking concave parts are placed legally where the convex NFP alone would reject them. A uniform spatial grid keeps the pair tests near-constant as the sheet fills, and an overlap memo keyed by world pose collapses repeated clipper work across stock trials.
  • FastPoly / CachedCollision (TriSet) make the exact gate cheap. Each orientation caches flat-array triangulations of its raw material and its spacing-inflated gate material; a candidate-vs-placed pair then runs the built-in clipper algorithm on plain double arrays with the anchor offsets as translations - no Polygon clones, no per-check re-triangulation, no LINQ. A uniform edge grid on the gate outlines certifies disjoint shell pairs (clear) and convex-solid crossings (overlap) before any clip work; the certification is three-state (touch and collinear contact defer to the clip, containment is decided by sampled interior tests) so it can never report a false clear - cross-validated against Collision.HasOverlap over ~2.5M decisions per job run with zero verdict mismatches, and hole-clipping overflow falls back to the exact Polygon gate (0.2% of checks on the production job below).
  • JobSolver walks demands in its own order (priority, then largest material area - big parts first lay down the sheet skeleton the small parts fill against; measured 12% lower job cost than smallest-extent-first on the production job below) and drains each greedily, then a time-boxed gap-fill pass. For the next sheet it trials every available stock size independently and commits the trial delivering the cheapest plate area per unit of part area placed (the benchmark's cost function), breaking ties by priority coverage, instance count, then plate area; lost trials change no job state. The job stops on met demand, exhausted stock, no further placement, or the plate cap. Deterministic: identical input, identical layout.

Trade-offs: greedy BLFG insertion leaves some of the density interlocking-pair and compaction pipelines find on regular jobs, and every stock size is trialled per sheet (O(sheets x stocks x fill)); on the 69-drawing/219-part production job below that costs ~110 s against the benchmark's 5-minute per-solve timeout. In exchange it places arcs, concaves, and holed parts under one uniform gate with no per-shape-class special cases.

Benchmark results

A real laser-cutting production job: 69 drawings, 219 parts, 3/16 mild steel, spacing 0.3, --parallel 1, same OpenNest build for every engine.

Sheet sizes offered Result Sheets Utilization Cost Time
The job's own 4 sizes (60x96, 60x120, 72x120, 48x144) valid, 219/219 28 78.4% 219,744 ~106 s
OpenNest's standard 9-size catalog valid, 219/219 14 56.6% 304,128 ~132 s

It uses the fewest sheets of any engine tested, but not the least material. The shop's original hand layout used 29 sheets (191,232 sq in). Known weakness: sheet choice is greedy one sheet at a time, so with large stock available it grabs 96x240 sheets and under-fills them.

Optimization history on this job (all valid, 219/219): count-first trial scoring and span-first demand order cost 258048/39 plates; cost-first trial scoring brought it to 249696 (39); area-first demand order to 219744 (28). Wall time went from timeout (>400 s) to ~110 s via the cached-triangulation exact gate and the fast shell prefilter.

Tests

tests/ holds acceptance tests whose layouts are checked by the benchmark's own NestValidator (bounds, spacing, quantities, stock, rotation), plus NFP geometry tests and a rotated-concave spacing regression test.

dotnet test OpenNest.Engine.Qwen38FlashNext/tests/OpenNest.Engine.Qwen38FlashNext.Tests.csproj

Build and benchmark

The project is a plugin outside OpenNest.sln. OpenNest.Benchmark loads plugin engines from an Engines/ folder next to its own build output:

dotnet build OpenNest.Engine.Qwen38FlashNext/OpenNest.Engine.Qwen38FlashNext.csproj -c Release
dotnet build <OpenNest>/OpenNest.Benchmark/OpenNest.Benchmark.csproj -c Release

mkdir -p <OpenNest>/OpenNest.Benchmark/bin/Release/net8.0/Engines
cp OpenNest.Engine.Qwen38FlashNext/bin/Release/net8.0/OpenNest.Engine.Qwen38FlashNext.dll <OpenNest>/OpenNest.Benchmark/bin/Release/net8.0/Engines/

dotnet <OpenNest>/OpenNest.Benchmark/bin/Release/net8.0/OpenNest.Benchmark.dll <path-to-.nest-or-folder> --parallel 1

<OpenNest> is the OpenNest checkout root. Or build and deploy in one step with ./Build-Engines.ps1 -Engines Qwen38FlashNext. The engine appears in reports as Qwen38FlashNextNestingEngine.