From 1b4153f0cded628d02ab5442c0bf9dc675ae428c Mon Sep 17 00:00:00 2001 From: harrierpigeon Date: Sun, 4 Oct 2026 19:22:42 -0500 Subject: [PATCH] Precise Seam: slice modifiers in the belt slicing frame slice_single_volume_regions() sliced Precise Seam modifiers with trafo_centered(), but a belt printer slices its layers with trafo_sliced(): the belt rotation, any pre-slice remap and the lift off the plate on top. On a belt print the modifier regions landed in the unrotated frame, away from the walls they were meant to place the seam on. Slice them with trafo_sliced(), as the support volumes and the seam enforcers already are. It equals trafo_centered() off a belt printer. --- src/libslic3r/PrintObjectSlice.cpp | 5 ++-- tests/fff_print/test_precise_seam.cpp | 42 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 6c2c9f9fd9..88f44466ff 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1832,10 +1832,11 @@ std::vector PrintObject::slice_single_volume_regions(const ModelVolu { if (volume == nullptr) return {}; - // Match the existing slicing heights and centered transform without flattening holes. + // Match the existing slicing heights and the frame the layers were sliced in (belt + // pre-slice transforms included) without flattening holes. const std::vector zs = zs_from_layers(this->layers()); MeshSlicingParamsEx params; - params.trafo = this->trafo_centered(); + params.trafo = this->trafo_sliced(); const Print *print = this->print(); return slice_volume(*volume, zs, params, [print]() { print->throw_if_canceled(); }); } diff --git a/tests/fff_print/test_precise_seam.cpp b/tests/fff_print/test_precise_seam.cpp index 2f48c626cc..6d28b57b6f 100644 --- a/tests/fff_print/test_precise_seam.cpp +++ b/tests/fff_print/test_precise_seam.cpp @@ -1426,3 +1426,45 @@ TEST_CASE("Full containment warns for Blocked but not for Enforced", "[PreciseSe else CHECK(fixture.warning().empty()); } + +TEST_CASE("Belt printers slice Precise Seam modifiers in the frame the object was sliced in", "[PreciseSeam][belt]") +{ + Model model; + Print print; + Test::init_print({Test::cube(20)}, print, model, { + { "belt_printer", 1 }, + { "belt_slice_rotation", "x" }, + { "belt_slice_rotation_angle", 45 }, + { "belt_slice_rotation_global", 1 }, + { "layer_height", 0.2 }, + { "initial_layer_print_height", 0.2 }, + { "skirt_loops", 0 }, + // Keep the first layer's islands the raw slice, like the modifier's. + { "elefant_foot_compensation", 0 }, + }); + print.process(); + const PrintObject *object = print.get_object(0); + REQUIRE(object->layer_count() > 0); + + // A modifier with the object's own mesh and placement must slice to the object's own islands + // on every layer. Sliced without the belt rotation it would give 20 mm squares on the lower + // layers and nothing above 20 mm, while the tilted cube reaches about 28 mm. + Model modifiers; + ModelVolume *modifier = modifiers.add_object()->add_volume(*model.objects.front()->volumes.front()); + modifier->set_type(ModelVolumeType::PRECISE_SEAM_BLOCKED); + const std::vector slices = object->slice_single_volume_regions(modifier); + REQUIRE(slices.size() == object->layer_count()); + + const double tolerance = scale_(0.05) * scale_(20.); + for (size_t i = 0; i < slices.size(); ++i) { + CAPTURE(i, object->get_layer(int(i))->slice_z); + const ExPolygons &islands = object->get_layer(int(i))->lslices; + double object_area = 0., modifier_area = 0.; + for (const ExPolygon &island : islands) + object_area += island.area(); + for (const ExPolygon ®ion : slices[i]) + modifier_area += region.area(); + CHECK(std::abs(modifier_area - object_area) < tolerance); + CHECK(get_extents(slices[i]).inflated(scale_(0.05)).contains(get_extents(islands))); + } +}