ENH: Arrange - experimental packer (sparrow) uses up to 50% fewer plates - #12119
Open
timkarnold wants to merge 1 commit into
Open
ENH: Arrange - experimental packer (sparrow) uses up to 50% fewer plates#12119timkarnold wants to merge 1 commit into
timkarnold wants to merge 1 commit into
Conversation
timkarnold
marked this pull request as draft
September 3, 2026 14:17
timkarnold
force-pushed
the
feature/sparrow-arrange
branch
from
September 3, 2026 14:29
6815e6e to
804d48e
Compare
timkarnold
marked this pull request as ready for review
September 3, 2026 14:43
timkarnold
force-pushed
the
feature/sparrow-arrange
branch
from
September 3, 2026 15:17
804d48e to
5358676
Compare
timkarnold
force-pushed
the
feature/sparrow-arrange
branch
from
September 3, 2026 15:21
5358676 to
068adf5
Compare
timkarnold
marked this pull request as draft
September 3, 2026 15:23
timkarnold
force-pushed
the
feature/sparrow-arrange
branch
2 times, most recently
from
September 3, 2026 17:15
5440e9e to
e514986
Compare
timkarnold
marked this pull request as ready for review
September 3, 2026 17:16
…ion, true outlines) ## Summary Adds an optional second backend for Arrange based on the [sparrow](https://github.com/JeroenGar/sparrow) nesting algorithm (MIT, Rust). It is off by default and selected with a new **Use experimental packer** checkbox in the *Arrange* settings popup. The stock `libnest2d` path is untouched and remains the default. The stock arranger packs convex hulls at four fixed angles with a first-fit heuristic. The new backend packs the objects' real projected outlines with continuous rotation and an overlap-tolerant local search, which fills plates considerably tighter. ## GIF Example ## Results 73-object project, CLI arrange from a clean layout, stock libnest2d versus sparrow at 8 s per plate, then a full re-slice of every output. All runs placed every object and every re-slice passed with no printable-area or exclusion-zone errors. | Machine | Plates, libnest2d | Plates, sparrow | Time, libnest2d | Time, sparrow | |---|---|---|---|---| | P1S | 15 | 9 | 4.8 s | 66 s | | A1 | 18 | 9 | 6.3 s | 65 s | | H2C | 10 | 6 | 4.1 s | 45 s | **Averaging 40% fewer plates with sparrow over stock libnest2d.** The set includes three 200 mm parts that each take a plate on their own on the 256 mm beds. Plate counts vary by one between sparrow runs because the search is time-bounded. ## What changes for the user - *Arrange* settings gain **Use experimental packer** and a **Search time per plate** slider (2–60 s, default 8). The packer is a wall-clock local search, so more time means more attempts; total time scales with the number of plates used. - Progress is reported per plate in the existing toast: `plate 2, 31/73 objects placed`. - Both settings persist in the app config. - Applies wherever Arrange is invoked: the toolbar button, the `A` key, the Arrange menu, per-plate arrange and Arrange Selected. - Exclusion zones (e.g. the P1S front-left corner) and the wipe tower are respected. The "too close to exclusion area" checks now use the true outline too, so an object whose convex hull crosses a zone but whose real silhouette does not is no longer rejected. ## What is not covered The packer only handles the 2D problem. These cases automatically fall back to the stock arranger: - Sequential (by-object) printing, which needs height and print-order constraints. - "Allow multiple materials on same plate" disabled. - Fill Bed, which depends on the stock packer's callback protocol. Known limits when the packer does run: - Filament temperature-group and TPU-per-plate rules are not enforced. - Objects are one solid outline each. Holes are ignored and a mesh with several disconnected islands is packed as the convex hull of all of them. - Results are not bit-for-bit reproducible across runs because the search is time-bounded. ## Build Requires a Rust toolchain (`cargo` on PATH, or in `~/.cargo/bin`). CMake builds the crate as a static library and links it into libslic3r; the end user needs nothing extra. Configure with `-DSLIC3R_SPARROW_ARRANGE=OFF` to build without it, in which case the checkbox is absent and nothing else changes. Tested on macOS arm64. The Windows and Linux link lines are written but have not been exercised. ## Implementation - `src/sparrow_arrange/`: Rust crate exposing one C function, `sparrow_arrange()`, behind a frozen C header. It runs the vendored sparrow separator bed by bed: fill largest-first, separate, grow or evict, and move on when the plate is full. Exclusion zones and fixed items are modeled as pinned obstacles. 12 tests, `cargo test` runs in about a second. - `src/sparrow_arrange/vendor/sparrow/`: sparrow at `50690c4` trimmed to the separator, samplers and collision tracker. Local patches are marked `SPARROW_ARRANGE PATCH` and listed in `VENDORED.md`. - `src/libslic3r/ArrangeSparrow.cpp`: converts `ArrangePolygon`s to the C ABI, including the same inflation and bed margin the stock path applies, and dispatches from `arrangement::arrange()` when the flag is set. Any failure falls back to libnest2d. - `src/libslic3r/Model.cpp`: `ModelObject::true_outline_2d()` projects the model-part meshes to a 2D silhouette, cached per object and keyed on the volumes' meshes and transforms. - `ArrangeJob.cpp`, `GLCanvas3D.cpp`: settings plumbing, checkbox, slider, progress. - CLI: `BBS_ARRANGE_SPARROW=1` and `BBS_ARRANGE_SPARROW_TIME=<s>` environment variables select the packer for `--arrange`. Diff is 49 files, about 4700 lines, of which 1850 are the vendored sparrow sources and 790 are `Cargo.lock`. The new code is about 2100 lines. ## Testing - `cargo test` in `src/sparrow_arrange` (12 tests: geometry contract, holes, fixed items, multi-bed spill, cancellation, determinism, FFI edge cases). - CLI arrange of both projects above, then a full re-slice of the output to confirm every plate passes `Print::validate()`. - GUI: toolbar, `A` key, menu and per-plate arrange on A1, P1S, and H2C profiles with their respective exclusion zones; drag-time exclusion checks; settings persistence across restart; progress toast. - An independent adversarial code review; all confirmed findings are fixed in the branch history.
timkarnold
force-pushed
the
feature/sparrow-arrange
branch
from
September 3, 2026 19:07
e514986 to
02609d6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an optional second backend for Arrange based on the sparrow nesting algorithm (MIT, Rust). It is off by default and selected with a new Use experimental packer checkbox in the Arrange settings popup. The stock
libnest2dpath is untouched and remains the default.The stock arranger packs convex hulls at four fixed angles with a first-fit heuristic. The new backend packs the objects' real projected outlines with continuous rotation and an overlap-tolerant local search, which fills plates considerably tighter.
GIF Demo
18% increase in Benchys per plate

Experimental packer fit 33 benchys on single plate vs 28 with stock Arrange.
44% fewer plates on a 73-part project

Experimental packer fit 73 objects onto 10 plates vs 18 with stock Arrange.
Results
73-object project, CLI arrange from a clean layout, stock libnest2d versus sparrow at 8 s per plate, then a full re-slice of every output. All runs placed every object and every re-slice passed with no printable-area or exclusion-zone errors.
Averaging 43% fewer plates with sparrow over stock libnest2d.
The set includes three 200 mm parts that each take a plate on their own on the 256 mm beds. Plate counts vary by one between sparrow runs because the search is time-bounded.
What changes for the user
plate 2, 31/73 objects placed.Akey, the Arrange menu, per-plate arrange and Arrange Selected.Arrange menu including experimental packer options

What is not covered
The packer only handles the 2D problem. These cases automatically fall back to the stock arranger:
Known limits when the packer does run:
Build
Requires a Rust toolchain (
cargoon PATH, or in~/.cargo/bin). CMake builds the crate as a static library and links it into libslic3r; the end user needs nothing extra. Configure with-DSLIC3R_SPARROW_ARRANGE=OFFto build without it, in which case the checkbox is absent and nothing else changes.Tested on macOS arm64. The Windows and Linux link lines are written but have not been exercised.
Implementation
src/sparrow_arrange/: Rust crate exposing one C function,sparrow_arrange(), behind a frozen C header. It runs the vendored sparrow separator bed by bed: fill largest-first, separate, grow or evict, and move on when the plate is full. Before moving on, every remaining part gets a search-free collision check against the plate's gaps, largest first. Exclusion zones and fixed items are modeled as pinned obstacles. 12 tests,cargo testruns in a few seconds.src/sparrow_arrange/vendor/sparrow/: sparrow at50690c4trimmed to the separator, samplers and collision tracker. Local patches are markedSPARROW_ARRANGE PATCHand listed inVENDORED.md.src/libslic3r/ArrangeSparrow.cpp: convertsArrangePolygons to the C ABI, including the same inflation and bed margin the stock path applies, and dispatches fromarrangement::arrange()when the flag is set. Any failure falls back to libnest2d.src/libslic3r/Model.cpp:ModelObject::true_outline_2d()projects the model-part meshes to a 2D silhouette, cached per object and keyed on the volumes' meshes and transforms.ArrangeJob.cpp,GLCanvas3D.cpp: settings plumbing, checkbox, slider, progress.BBS_ARRANGE_SPARROW=1andBBS_ARRANGE_SPARROW_TIME=<s>environment variables select the packer for--arrange.Diff is 49 files, about 4700 lines, of which 1850 are the vendored sparrow sources and 790 are
Cargo.lock. The new code is about 2100 lines.Testing
cargo testinsrc/sparrow_arrange(12 tests: geometry contract, holes, fixed items, multi-bed spill, cancellation, determinism, FFI edge cases).Print::validate().Akey, menu and per-plate arrange on A1, P1S, and H2C profiles with their respective exclusion zones; drag-time exclusion checks; settings persistence across restart; progress toast.