From 509283100709d8653e801a0e95331a50b8ab613b Mon Sep 17 00:00:00 2001 From: Hanif Koh Date: Sun, 13 Sep 2026 16:28:09 +0800 Subject: [PATCH] Apply the Belt Slicing Transform to Painted Supports and Seams Painted support/seam facets, support volumes, seam occlusion, MMU and fuzzy skin painting (top/bottom and side facets) and the adaptive infill octree used trafo_centered(), or trafo() with a centre-offset shift, while the layers were sliced with the belt rotation, remap and Z lift; they now share PrintObject::trafo_sliced(). --- src/libslic3r/GCode/SeamPlacer.cpp | 4 ++-- src/libslic3r/MultiMaterialSegmentation.cpp | 11 ++++++----- src/libslic3r/Print.hpp | 3 +++ src/libslic3r/PrintObject.cpp | 10 +++++++--- src/libslic3r/PrintObjectSlice.cpp | 9 ++++++++- 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 35bc436d5a..7562c7745d 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -627,7 +627,7 @@ void compute_global_occlusion(GlobalModelInfo &result, const PrintObject *po, SeamPosition seam_position = spAligned) { BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: gather occlusion meshes: start"; - auto obj_transform = po->trafo_centered(); + auto obj_transform = po->trafo_sliced(); indexed_triangle_set triangle_set; indexed_triangle_set negative_volumes_set; //add all parts @@ -712,7 +712,7 @@ void gather_enforcers_blockers(GlobalModelInfo &result, const PrintObject *po) { BOOST_LOG_TRIVIAL(debug) << "SeamPlacer: build AABB trees for raycasting enforcers/blockers: start"; - auto obj_transform = po->trafo_centered(); + auto obj_transform = po->trafo_sliced(); for (const ModelVolume *mv : po->model_object()->volumes) { if (mv->is_seam_painted()) { diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 6f80f7b759..0016d96ac2 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1215,7 +1215,7 @@ static inline std::vector> segmentation_top_and_bottom_l // project downards pointing painted triangles over bottom surfaces. std::vector> top_raw(num_facets_states), bottom_raw(num_facets_states); std::vector zs = zs_from_layers(layers); - Transform3d object_trafo = print_object.trafo_centered(); + Transform3d object_trafo = print_object.trafo_sliced(); #ifdef MM_SEGMENTATION_DEBUG_TOP_BOTTOM static int iRun = 0; @@ -2039,17 +2039,19 @@ std::vector> segmentation_by_painting(const PrintObject } BOOST_LOG_TRIVIAL(debug) << "Print object segmentation - Projection of painted triangles - Begin"; + // The layers were sliced in this frame (belt rotation, remap and Z lift included), and it already centers the object. + const Transform3d object_trafo = print_object.trafo_sliced(); for (const ModelVolume *mv : print_object.model_object()->volumes) { const ModelVolumeFacetsInfo facets_info = extract_facets_info(*mv); - tbb::parallel_for(tbb::blocked_range(1, num_facets_states), [&mv, &print_object, &facets_info, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(1, num_facets_states), [&mv, &object_trafo, &facets_info, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t extruder_idx = range.begin(); extruder_idx < range.end(); ++extruder_idx) { throw_on_cancel_callback(); const indexed_triangle_set custom_facets = facets_info.facets_annotation.get_facets(*mv, EnforcerBlockerType(extruder_idx)); if (!mv->is_model_part() || custom_facets.indices.empty()) continue; - const Transform3f tr = print_object.trafo().cast() * mv->get_matrix().cast(); - tbb::parallel_for(tbb::blocked_range(0, custom_facets.indices.size()), [&tr, &custom_facets, &print_object, &layers, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range &range) { + const Transform3f tr = (object_trafo * mv->get_matrix()).cast(); + tbb::parallel_for(tbb::blocked_range(0, custom_facets.indices.size()), [&tr, &custom_facets, &layers, &edge_grids, &input_expolygons, &painted_lines, &painted_lines_mutex, &extruder_idx](const tbb::blocked_range &range) { for (size_t facet_idx = range.begin(); facet_idx < range.end(); ++facet_idx) { float min_z = std::numeric_limits::max(); float max_z = std::numeric_limits::lowest(); @@ -2102,7 +2104,6 @@ std::vector> segmentation_by_painting(const PrintObject Line line_to_test(Point(scale_(line_start_f.x()), scale_(line_start_f.y())), Point(scale_(line_end_f.x()), scale_(line_end_f.y()))); - line_to_test.translate(-print_object.center_offset()); // BoundingBoxes for EdgeGrids are computed from printable regions. It is possible that the painted line (line_to_test) could // be outside EdgeGrid's BoundingBox, for example, when the negative volume is used on the painted area (GH #7618). diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index c387dcd552..a801e0688f 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -359,6 +359,9 @@ public: // Trafo with the center_offset() applied after the transformation, to center the object in XY before slicing. Transform3d trafo_centered() const { Transform3d t = this->trafo(); t.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0)); return t; } + // trafo_centered() with the belt pre-slice transforms applied: the frame the layers were sliced in (Layer::slice_z). + // Equal to trafo_centered() unless a belt rotation or pre-slice remap is active. + Transform3d trafo_sliced() const; const PrintInstances& instances() const { return m_instances; } PrintInstances &instances() { return m_instances; } diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index ac7f34baa7..275998018d 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -1101,7 +1101,10 @@ std::pair PrintObject::prepare indexed_triangle_set mesh = this->model_object()->raw_indexed_triangle_set(); // Rotate mesh and build octree on it with axis-aligned (standart base) cubes. auto to_octree = transform_to_octree().toRotationMatrix(); - its_transform(mesh, to_octree * this->trafo_centered(), true); + // Overhangs below are placed at Layer::bottom_z(), which includes the belt global Z offset. + Transform3d object_trafo = this->trafo_sliced(); + object_trafo.translation().z() += m_belt_global_z_offset; + its_transform(mesh, to_octree * object_trafo, true); // Triangulate internal bridging surfaces. std::vector> overhangs(std::max(surfaces_w_bottom_z.size(), size_t(1))); @@ -5124,6 +5127,7 @@ static void project_triangles_to_slabs(ConstLayerPtrsAdaptor layers, const index void PrintObject::project_and_append_custom_facets( bool seam, EnforcerBlockerType type, std::vector& out, std::vector>* vertical_points) const { + const Transform3d object_trafo = this->trafo_sliced(); for (const ModelVolume* mv : this->model_object()->volumes) if (mv->is_model_part()) { const indexed_triangle_set custom_facets = seam @@ -5132,12 +5136,12 @@ void PrintObject::project_and_append_custom_facets( if (! custom_facets.indices.empty()) { if (seam) project_triangles_to_slabs(this->layers(), custom_facets, - (this->trafo_centered() * mv->get_matrix()).cast(), + (object_trafo * mv->get_matrix()).cast(), seam, out); else { std::vector projected; // Support blockers or enforcers. Project downward facing painted areas upwards to their respective slicing plane. - slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), this->trafo_centered() * mv->get_matrix(), nullptr, &projected, vertical_points, [](){}); + slice_mesh_slabs(custom_facets, zs_from_layers(this->layers()), object_trafo * mv->get_matrix(), nullptr, &projected, vertical_points, [](){}); // Merge these projections with the output, layer by layer. assert(! projected.empty()); assert(out.empty() || out.size() == projected.size()); diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 2b6c4ffcff..8360a9562f 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -1806,6 +1806,13 @@ ExPolygons PrintObject::_shrink_contour_holes(double contour_delta, double hole_ return union_ex(new_ex_polys); } +Transform3d PrintObject::trafo_sliced() const +{ + Transform3d trafo = this->trafo_centered(); + BeltSliceStrategy::apply_preslice_transforms(trafo, this->print()->config(), this->model_object()->volumes); + return trafo; +} + std::vector PrintObject::slice_support_volumes(const ModelVolumeType model_volume_type) const { auto it_volume = this->model_object()->volumes.begin(); @@ -1820,7 +1827,7 @@ std::vector PrintObject::slice_support_volumes(const ModelVolumeType m const Print *print = this->print(); auto throw_on_cancel_callback = std::function([print](){ print->throw_if_canceled(); }); MeshSlicingParamsEx params; - params.trafo = this->trafo_centered(); + params.trafo = this->trafo_sliced(); for (; it_volume != it_volume_end; ++ it_volume) if ((*it_volume)->type() == model_volume_type) { std::vector slices2 = slice_volume(*(*it_volume), zs, params, throw_on_cancel_callback);