Skip to content

FIX: order-independent overlap carving for multi-part objects#10383

Open
jomixlaf wants to merge 1 commit intobambulab:masterfrom
jomixlaf:fix/order-independent-overlap-carve
Open

FIX: order-independent overlap carving for multi-part objects#10383
jomixlaf wants to merge 1 commit intobambulab:masterfrom
jomixlaf:fix/order-independent-overlap-carve

Conversation

@jomixlaf
Copy link
Copy Markdown
Contributor

Summary

Fixes a long-standing intermittent bug where a contained MODEL_PART volume (e.g. embossed text extruded into a plate body, each assigned a different filament) silently disappears from the slice and the gcode whenever it happens to be listed before its container in the volumes vector.

Reproduction

  1. Export a STEP file from Fusion 360 with two solid bodies: a plate and a smaller body extruded into it (text, logo, recessed feature, etc.).
  2. Open in Bambu Studio, assign different filaments to each body. Both render correctly with their assigned colors in the 3D view.
  3. Slice. The contained body is missing entirely from the gcode.

The bug is intermittent because OCCT's STEP traversal order is not under user control and Fusion 360 does not guarantee a stable body order in exported STEP files. Sometimes the contained body lands first, sometimes last.

A known workaround: right-click the inner body → change Type to Negative Part → slice (it shows as a recess, proving the geometry is in the pipeline) → change Type back to Part → slice (now correct). The toggle works because sort_volumes(true) runs a stable_sort by type that deterministically yanks the just-changed volume to a particular position, accidentally fixing the order.

Root cause

In slices_to_regions (PrintObjectSlice.cpp), the carving loop iterates temp_slices in vector order and unconditionally diff-subtracts each MODEL_PART's slice from every preceding overlapping region:

} else if ((region.model_volume->is_model_part() && clip_multipart_objects) || region.model_volume->is_negative_volume()) {
    for (int idx_region2 = 0; idx_region2 < idx_region; ++ idx_region2)
        if (! temp_slices[idx_region2].expolygons.empty()) {
            if (const PrintObjectRegions::VolumeRegion& region2 = layer_range.volume_regions[idx_region2];
                !region2.model_volume->is_negative_volume() && overlap_in_xy(*region.bbox, *region2.bbox))
                temp_slices[idx_region2].expolygons = diff_ex(temp_slices[idx_region2].expolygons, temp_slices[idx_region].expolygons);
        }
}

The "later wins" rule means a contained body listed before its container is fully carved out by the container's later carve pass and produces an empty region.

Fix

Make the carve order-independent for overlapping MODEL_PARTs: in any overlapping pair, the one with the smaller bounding-box volume always carves the larger, regardless of which appears first in the volumes vector. Negative volumes continue to always carve as before.

  • Behavior for non-overlapping volumes, single-part objects, modifiers, support enforcers/blockers, and negative volumes is unchanged.
  • Equal-bbox ties fall through to the previous "later wins" path (degenerate case).
  • The carve still happens at most once per pair, so no performance regression.

Test plan

  • Open a STEP file with a plate + embossed text inside (filament 1 on text, filament 2 on plate). Slice. Verify text appears in its assigned filament regardless of body order in the part list.
  • Drag the inner body to position 0 in the part list. Re-slice. Verify the inner body still slices correctly (this used to break before this PR).
  • Verify negative-volume subtraction still works (negative bodies always carve, regardless of size).
  • Verify single-part objects and disjoint multi-part objects (no overlap) slice unchanged.

When a ModelObject contains overlapping MODEL_PART volumes (e.g. a STEP
file with embossed text extruded into a plate body, each assigned a
different filament), the slicer's region carving in slices_to_regions
iterates volumes in vector order and unconditionally diff-subtracts each
MODEL_PART's slice from every preceding overlapping region. The "later
wins" rule means a contained body listed before its container gets
erased entirely by the container's later carve pass, and the body
silently disappears from the slice and the gcode.

The same scene with the contained body listed last slices correctly,
which is why the "right-click -> change type to Negative -> change back
to Part" workaround makes the issue go away: sort_volumes(true) runs a
stable_sort by type that yanks the just-changed volume to a deterministic
position, accidentally fixing the order. Because OCCT's STEP traversal
order is not under user control (Fusion 360 in particular does not
guarantee body order in exported STEP files), the bug is intermittent
and has been chased for years.

Resolve by making the carve order-independent: in any pair of
overlapping non-negative MODEL_PARTs, the one with the smaller
bounding-box volume always carves the larger, regardless of vector
position. Negative volumes continue to always carve as before.
Equal-bbox ties fall through to the previous "later wins" path, which
is degenerate anyway. Behavior for non-overlapping volumes, single-part
objects, modifiers, support enforcers/blockers, and negative volumes is
unchanged.
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.

1 participant