Skip to content

Fix sequential print collision check depending on object list order - #630

Open
KuzuriAo wants to merge 1 commit into
Snapmaker:mainfrom
KuzuriAo:patch-1
Open

Fix sequential print collision check depending on object list order#630
KuzuriAo wants to merge 1 commit into
Snapmaker:mainfrom
KuzuriAo:patch-1

Conversation

@KuzuriAo

@KuzuriAo KuzuriAo commented Jul 28, 2026

Copy link
Copy Markdown

Hi @zackaree-shen,

I believe this is a solid fix for issue #586 that we were discussing.

Fix sequential print collision check depending on object list order, not actual geometry

The bug

I ran into this with models designed for Bambu printers, mostly 3mf files pulled from MakerWorld. They'd slice and print fine in Bambu Studio on an actual Bambu printer. But opening the same file in Snapmaker Orca (or Orca) and switching the printer profile over to a Snapmaker U1 would sometimes throw "Assembly is too tall, and collisions will be caused.", error.

That's was the hint that this isn't a real geometry problem. If a file slices and prints cleanly on in Bambu Studio on a Bambu printer, there's no physical reason it shouldn't also slice cleanly on a Snapmaker U1 or any other printer. Swapping the printer profile doesn't change the objects' heights or positions relative to each other. So the error had to be coming from the slicer's own collision check, not from an actual collision.

That's what turned up in sequential_print_clearance_valid() in src/libslic3r/Print.cpp. It's supposed to check whether a sequential print's object heights and positions can actually be printed without the toolhead colliding with already-finished objects. Instead, it just sorts objects by their raw position in the object list (object_index) and checks clearance against that order. If the list order happens to put a tall object before a short one it shouldn't, you get the "too tall" error, even when a valid, non-colliding print order exists. Since a 3mf's object-list order is just an artifact of how the file was authored (Bambu Studio, MakerWorld, whatever produced it), and not something the printer profile changes, this made the error effectively random with respect to which printer profile you picked.

The workaround right now is cutting an object out of the model and pasting it back in, which reshuffles its position in the object list and sometimes gets you a list order that happens to work. That's luck, not a fix, and it's easy to end up with a file where no amount of cut/paste helps because the check was never actually looking for a valid order in the first place. It was just checking the one it was handed.

There's also a disabled (#if 0) block above the current logic that tried to solve this properly with a score-propagation heuristic, but it wasn't guaranteed to converge and was turned off.

Where "the object list" actually is

The object list lives in 3D/3dmodel.model, in two places that stay in lockstep: a <resources> block with one <object id="N"> entry per top-level printable object, and a <build> block with one <item objectid="N" transform="..."> entry per instance placed on the plate. Whatever order those entries appear in the XML is the order libslic3r assigns as each object's object_index when it loads the file. It's just file order, with no geometric meaning at all. (Each <object> can itself be a multi-part "Assembly": several sub-meshes with their own per-part extruder/color assignments merged into one printable item, which is exactly what the "Assembly is too tall" wording refers to; that's a separate, unrelated feature from the ordering bug.)

I confirmed this directly on one of my failing files, saved twice from the same project: once with a Bambu printer profile selected (worked fine) and once after switching to the Snapmaker U1 profile (threw the error). Diffing the two 3dmodel.model files, the geometry, transforms, and part assignments are identical. The only thing that changed is which of the two top-level "Assembly" objects (a shorter Hilt assembly and a taller Body assembly with arms and wings) is listed first:

Bambu-profile save:  <resources> order = [ Hilt (extruder 6), Body (extruder 3) ]
                      <build> order    = [ item objectid=Hilt, item objectid=Body ]

U1-profile save:      <resources> order = [ Body (extruder 3), Hilt (extruder 6) ]
                       <build> order    = [ item objectid=Body, item objectid=Hilt ]

Same two objects, same everything else, just swapped in the list. Under the old code, only the object printed last gets the full printable_height allowance; whichever one lands earlier is capped at extruder_clearance_height_to_lid. So depending purely on which of these two saves you opened, either the taller Body assembly got the "last" slot (fine) or the shorter Hilt did (Body then gets capped and throws "too tall"). Nothing about switching the printer profile changes this ordering. It's an incidental side effect of when and how the file gets re-saved (cut/paste, re-export, whatever). Bambu Studio's own sequential-print handling clearly doesn't treat that raw list order as the print order, or the same 3MF file would have thrown the same false collision on the Bambu printer it was designed for, and it didn't.

The Fix

Replace the list-order sort with an actual search for a valid print order. The constraint is: every instance except the one printed last is capped at extruder_clearance_height_to_lid, or the stricter extruder_clearance_height_to_rod if some later-printed instance overlaps it in Y. So at most one instance can need the "last slot," and among the rest, any two instances that overlap in Y and are both taller than the rod-clearance height need the taller one scheduled first.

That's a topological sort over a "must print before" constraint graph. The fix builds that graph and runs Kahn's algorithm, breaking ties by the original object index so the result is the smallest reordering of what you already had, not something arbitrary. If a valid order exists, it's used. If it genuinely doesn't (a real, unavoidable collision), it falls back to the original object-list order so the vertical-clearance check below still fires the same descriptive error it always has. The goal here is to stop false positives, not to hide real ones.

Testing

Test files:

The following was a 3mf that sliced cleanly and printed with no problems in Bambu Studio on a Bambu X1C:

Z-bambu.3mf.zip

You can see it will slice cleanly in Bambu Studio:

Screenshot 2026-07-28 at 2 41 17 AM

However, this is the same file opened in Sn(orca) and had the printer profile changed to Snapmaker U1:

Z-U1 2.3mf.zip

Screenshot 2026-07-28 at 2 41 52 AM

Here is by macOS (Apple Silicon) build with the patch applied and no error, slices cleanly:

Screenshot 2026-07-28 at 2 41 17 AM

Here is by Ubuntu 25.10 (questing) build with the patch applied and no error, slices cleanly:

Screenshot 2026-07-28 at 2 48 54 AM

Tested Builds

Built and tested locally against both OrcaSlicer and Snapmaker Orca on:

  • macOS Tahoe, Version 26.3 (25D125), Apple Silicon
  • Ubuntu 25.10 (questing)

Results:

  • Files that previously failed with "Assembly is too tall, and collisions will be caused" now slice cleanly with no manual reordering.
  • No cut/paste workaround needed anymore. The object list order is left as-is and the fix finds a valid print order on its own.
  • Genuine collisions (verified with a case that has no valid order) still produce the same error as before.
  • Confirmed on both macOS and Linux.

This is a pure logic change in one function. No platform-specific code, so it should behave identically everywhere.

Other bugs

While I don't really see any issues opened on Snapmaker/Orcaslicer (other than mine that I think this applies to), I did find a bunch on the main OrcaSlicer github repository that seem like are referring to this bug:

On OrcaSlicer/OrcaSlicer:

#6876: the same false "too tall" warning, reported in 2024 and closed as completed. It clearly came back (or was never fixed at the root), which lines up with what's in this repo now: a disabled #if 0 heuristic block that looks like an earlier, half-working attempt at this exact problem, later turned off in favor of the naive list-order sort that reintroduced the bug.
#14435: a feature request making essentially the same diagnosis, that using height-to-rod/height-to-lid as blind cutoffs "without checking actual geometry is too crude." Its proposed fix is more ambitious than this one (axis-based bounding-box sectors instead of a height plane), but the root-cause framing matches.
#12386: a cruder version of the same idea, force the tallest object last and skip the check for it. This fix effectively derives that outcome as a special case when it's actually needed, instead of asserting it unconditionally, and without giving up the check for genuine unavoidable collisions. Links its own related cluster: #6601 and #6828.
#12505: the mirror-image bug, where the slicer doesn't warn when it should and a real collision gets through during abort or end-of-print parking. Not something this PR touches (that's end-of-print G-code behavior, closer to the Snapmaker #453 family above), but it's a good reminder that getting the ordering logic right matters in both directions.

@KuzuriAo

Copy link
Copy Markdown
Author

/bot add-label bug-fix

@zackaree-shen

Copy link
Copy Markdown

Hi, @KuzuriAo

I am very glad to see your root cause analysis and fix attempts.
I will review and verify it locally as soon as possible. If I have any feedback, I will contact you promptly.
Thank you again for your contribution.

@KuzuriAo

KuzuriAo commented Jul 30, 2026

Copy link
Copy Markdown
Author

Follow-up: when this fix still isn't enough

@zackaree-shen I wanted to bring this up, since I ran into it myself right after posting this PR: this fix resolves the case where a valid print order exists but the old code never searched for it. It does not, and should not, silence a genuinely unavoidable collision. If two objects are both taller than extruder_clearance_height_to_rod and overlap each other in Y, there is no print order that avoids one of them being in the toolhead's way while the other prints. The fix correctly detects that (it's a real cycle in the ordering constraint graph, not a false one) and falls back to the same "too tall" error instead of pretending it's safe. That's intentional, not a bug.

So if you hit the error after this fix and reordering, cutting/pasting, or nudging objects around doesn't clear it no matter what you try, don't assume the fix is broken. It probably means the printer's clearance settings genuinely can't be satisfied by the current plate layout.

How to actually fix a genuine one

The check only cares about Y position, not X. Two tall objects can sit anywhere in X without conflict, they just can't occupy overlapping Y bands (specifically, within extruder_clearance_radius of each other) if both exceed the height-to-rod threshold. Repositioning along Y so the tall objects land in separate bands is a legitimate fix.

In practice this is fiddlier than it sounds if the objects are large: I tried it on a real case and the two conflicting objects each needed to span nearly the plate's full Y depth, leaving only a few mm of margin to work with after finding a split that satisfied both directions of the constraint.

A much easier and more reliable fix, if the flagged object is a merged multi-part "Assembly": split it apart and reposition the pieces individually.

  1. Right-click the assembly, Split -> To Objects.
  2. Reposition the resulting pieces as needed. Auto-arrange is fine for this if you don't care where the seams between parts end up.
  3. Select all of the pieces you just split and rearranged.
  4. Right-click, Assemble, to regroup them back into a single multi-part object now that they're laid out differently.
  5. Re-slice.

Why this works: the collision check uses print_object->height(), which for a merged assembly is the height of the combined bounding box across all its sub-parts, not any individual part's height. A tall assembly can end up flagged even when most of its individual pieces are well under the clearance threshold, if just one sub-part is tall enough to push the combined bounding box over the line. Splitting means each piece gets auto-arranged on its own footprint instead of being dragged around as one large rigid block, which gives the arranger a lot more freedom to land on a layout where the genuinely tall piece isn't sitting in another tall object's Y band. In a real case I checked, a merged assembly measured 31mm tall overall, but of its six sub-parts, only one was actually over the printer's 27.5mm height-to-rod threshold; the rest weren't fighting for placement at all. Re-assembling afterward just bakes that new, collision-free layout back into one printable item, so you get the convenience of a single grouped object again without reintroducing the problem.

Quick summary

  • Reordering fixes it: the object-list order was arbitrary and this fix finds a valid order automatically. No manual steps needed anymore.
  • Reordering doesn't fix it, and the flagged object is a plain single object: it's a genuine collision under your printer's clearance settings. You'll need to move it in Y (not X) relative to whatever else it conflicts with, or accept the fewer-objects-per-plate tradeoff, or revisit the printer profile's clearance values if you believe they're overly conservative for your actual hardware.
  • Reordering doesn't fix it, and the flagged object is a merged multi-part "Assembly": split it to objects, reposition (auto-arrange is fine), select the pieces and Assemble them back together, then re-slice. This is usually the easiest path, since it turns one large, hard-to-place footprint into several smaller ones during arrangement, most of which likely don't need to be separated from anything at all, then regroups them once a working layout is found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants