From 04d6b17c572bf732292b84bca875cf2ccb406efb Mon Sep 17 00:00:00 2001 From: Vojtech Bubnik Date: Tue, 10 Aug 2021 09:41:28 +0200 Subject: [PATCH] Fix of Some FDM supports fail to generate due to wrongly-translated enforcer polygons. #6739 Thanks @n8bot for finding the bug. Also removed some dead code in MM segmentation. --- src/libslic3r/MultiMaterialSegmentation.cpp | 219 +------------------- src/libslic3r/Print.hpp | 3 + src/libslic3r/PrintObject.cpp | 6 +- src/libslic3r/PrintObjectSlice.cpp | 7 +- 4 files changed, 8 insertions(+), 227 deletions(-) diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 95475b0d7..9456f5077 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1240,221 +1240,6 @@ static inline std::vector> mmu_segmentation_top_and_bott const size_t num_layers = input_expolygons.size(); const ConstLayerPtrsAdaptor layers = print_object.layers(); -#if 0 - auto get_extrusion_width = [&layers = std::as_const(layers)](const size_t layer_idx) -> float { - auto extrusion_width_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(), - [](const LayerRegion *l1, const LayerRegion *l2) { - return l1->region().config().perimeter_extrusion_width < - l2->region().config().perimeter_extrusion_width; - }); - assert(extrusion_width_it != layers[layer_idx]->regions().end()); - return float((*extrusion_width_it)->region().config().perimeter_extrusion_width); - }; - - auto get_top_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int { - auto top_solid_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(), - [](const LayerRegion *l1, const LayerRegion *l2) { - return l1->region().config().top_solid_layers < l2->region().config().top_solid_layers; - }); - assert(top_solid_layer_it != layers[layer_idx]->regions().end()); - return (*top_solid_layer_it)->region().config().top_solid_layers; - }; - - auto get_bottom_solid_layers = [&layers = std::as_const(layers)](const size_t layer_idx) -> int { - auto top_bottom_layer_it = std::max_element(layers[layer_idx]->regions().begin(), layers[layer_idx]->regions().end(), - [](const LayerRegion *l1, const LayerRegion *l2) { - return l1->region().config().bottom_solid_layers < l2->region().config().bottom_solid_layers; - }); - assert(top_bottom_layer_it != layers[layer_idx]->regions().end()); - return (*top_bottom_layer_it)->region().config().bottom_solid_layers; - }; - - std::vector top_layers(num_layers); - top_layers.back() = input_expolygons.back(); - tbb::parallel_for(tbb::blocked_range(1, num_layers), [&](const tbb::blocked_range &range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { - throw_on_cancel_callback(); - float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx))); - top_layers[layer_idx - 1] = diff_ex(input_expolygons[layer_idx - 1], offset_ex(input_expolygons[layer_idx], extrusion_width)); - } - }); // end of parallel_for - - std::vector bottom_layers(num_layers); - bottom_layers.front() = input_expolygons.front(); - tbb::parallel_for(tbb::blocked_range(0, num_layers - 1), [&](const tbb::blocked_range &range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { - throw_on_cancel_callback(); - float extrusion_width = 0.1f * float(scale_(get_extrusion_width(layer_idx))); - bottom_layers[layer_idx + 1] = diff_ex(input_expolygons[layer_idx + 1], offset_ex(input_expolygons[layer_idx], extrusion_width)); - } - }); // end of parallel_for - - std::vector> triangles_by_color_raw(num_extruders, std::vector(layers.size())); - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - begin"; - { - auto delta = float(10 * SCALED_EPSILON); - std::vector deltas { delta, delta, delta }; - Points projected_facet; - for (const ModelVolume *mv : print_object.model_object()->volumes) - if (mv->is_model_part()) { - const Transform3f tr = print_object.trafo().cast() * mv->get_matrix().cast(); - - for (size_t extruder_idx = 0; extruder_idx < num_extruders; ++extruder_idx) { - const indexed_triangle_set custom_facets = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); - if (custom_facets.indices.empty()) - continue; - - throw_on_cancel_callback(); - for (size_t facet_idx = 0; facet_idx < custom_facets.indices.size(); ++facet_idx) { - float min_z = std::numeric_limits::max(); - float max_z = std::numeric_limits::lowest(); - - std::array facet; - for (int p_idx = 0; p_idx < 3; ++p_idx) { - facet[p_idx] = tr * custom_facets.vertices[custom_facets.indices[facet_idx](p_idx)]; - max_z = std::max(max_z, facet[p_idx].z()); - min_z = std::min(min_z, facet[p_idx].z()); - } - - // Sort the vertices by z-axis for simplification of projected_facet on slices - std::sort(facet.begin(), facet.end(), [](const Vec3f &p1, const Vec3f &p2) { return p1.z() < p2.z(); }); - projected_facet.clear(); - projected_facet.reserve(3); - for (int p_idx = 0; p_idx < 3; ++p_idx) - projected_facet.emplace_back(Point(scale_(facet[p_idx].x()), scale_(facet[p_idx].y())) - print_object.center_offset()); - if (cross2((projected_facet[1] - projected_facet[0]).cast(), (projected_facet[2] - projected_facet[1]).cast()) < 0) - // Make CCW. - std::swap(projected_facet[1], projected_facet[2]); - ClipperLib::Path offsetted = mittered_offset_path_scaled(projected_facet, deltas, 3.); - - // Find lowest slice not below the triangle. - auto first_layer = std::upper_bound(layers.begin(), layers.end(), float(min_z - EPSILON), - [](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; }); - auto last_layer = std::upper_bound(layers.begin(), layers.end(), float(max_z - EPSILON), - [](float z, const Layer *l1) { return z < l1->slice_z + l1->height * 0.5; }); - - if (last_layer == layers.end()) - --last_layer; - - if (first_layer == layers.end() || (first_layer != layers.begin() && facet[0].z() < (*first_layer)->print_z - EPSILON)) - --first_layer; - - for (auto layer_it = first_layer; (layer_it != (last_layer + 1) && layer_it != layers.end()); ++layer_it) - if (size_t layer_idx = layer_it - layers.begin(); ! top_layers[layer_idx].empty() || ! bottom_layers[layer_idx].empty()) - triangles_by_color_raw[extruder_idx][layer_idx].emplace_back(offsetted); - } - } - } - } - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - top and bottom layers - projection of painted triangles - end"; - - std::vector> triangles_by_color(num_extruders, std::vector(layers.size())); - tbb::parallel_for(tbb::blocked_range(0, num_layers), [&](const tbb::blocked_range &range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { - throw_on_cancel_callback(); - float offset_factor = 0.1f * float(scale_(get_extrusion_width(layer_idx))); - for (size_t extruder_id = 0; extruder_id < num_extruders; ++ extruder_id) - if (ClipperLib::Paths &src_paths = triangles_by_color_raw[extruder_id][layer_idx]; !src_paths.empty()) - triangles_by_color[extruder_id][layer_idx] = offset_ex(offset_ex(ClipperPaths_to_Slic3rExPolygons(src_paths), -offset_factor), offset_factor); - } - }); // end of parallel_for - triangles_by_color_raw.clear(); - - std::vector> triangles_by_color_bottom(num_extruders); - std::vector> triangles_by_color_top(num_extruders); - triangles_by_color_bottom.assign(num_extruders, std::vector(num_layers)); - triangles_by_color_top.assign(num_extruders, std::vector(num_layers)); - - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - begin"; - for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { - float extrusion_width = scale_(get_extrusion_width(layer_idx)); - int top_solid_layers = get_top_solid_layers(layer_idx); - ExPolygons top_expolygon = top_layers[layer_idx]; - if (top_expolygon.empty()) - continue; - - for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) { - throw_on_cancel_callback(); - if (triangles_by_color[color_idx][layer_idx].empty()) - continue; - ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], top_expolygon); - if (!intersection_poly.empty()) { - triangles_by_color_top[color_idx][layer_idx].insert(triangles_by_color_top[color_idx][layer_idx].end(), intersection_poly.begin(), - intersection_poly.end()); - for (int last_idx = int(layer_idx) - 1; last_idx >= std::max(int(layer_idx - top_solid_layers), int(0)); --last_idx) { - float offset_value = float(layer_idx - last_idx) * (-1.0f) * extrusion_width; - if (offset_ex(top_expolygon, offset_value).empty()) - continue; - ExPolygons layer_slices_trimmed = input_expolygons[last_idx]; - - for (int last_idx_1 = last_idx; last_idx_1 < int(layer_idx); ++last_idx_1) { - layer_slices_trimmed = intersection_ex(layer_slices_trimmed, input_expolygons[last_idx_1 + 1]); - } - - ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value); - ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_top[color_idx][layer_idx], offset_e); - triangles_by_color_top[color_idx][last_idx].insert(triangles_by_color_top[color_idx][last_idx].end(), intersection_poly_2.begin(), - intersection_poly_2.end()); - } - } - } - } - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of top layer - end"; - - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - begin"; - for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { - float extrusion_width = scale_(get_extrusion_width(layer_idx)); - int bottom_solid_layers = get_bottom_solid_layers(layer_idx); - const ExPolygons &bottom_expolygon = bottom_layers[layer_idx]; - if (bottom_expolygon.empty()) - continue; - - for (size_t color_idx = 0; color_idx < triangles_by_color.size(); ++color_idx) { - throw_on_cancel_callback(); - if (triangles_by_color[color_idx][layer_idx].empty()) - continue; - - ExPolygons intersection_poly = intersection_ex(triangles_by_color[color_idx][layer_idx], bottom_expolygon); - if (!intersection_poly.empty()) { - triangles_by_color_bottom[color_idx][layer_idx].insert(triangles_by_color_bottom[color_idx][layer_idx].end(), intersection_poly.begin(), - intersection_poly.end()); - for (size_t last_idx = layer_idx + 1; last_idx < std::min(layer_idx + bottom_solid_layers, num_layers); ++last_idx) { - float offset_value = float(last_idx - layer_idx) * (-1.0f) * extrusion_width; - if (offset_ex(bottom_expolygon, offset_value).empty()) - continue; - ExPolygons layer_slices_trimmed = input_expolygons[last_idx]; - for (int last_idx_1 = int(last_idx); last_idx_1 > int(layer_idx); --last_idx_1) { - layer_slices_trimmed = intersection_ex(layer_slices_trimmed, offset_ex(input_expolygons[last_idx_1 - 1], offset_value)); - } - - ExPolygons offset_e = offset_ex(layer_slices_trimmed, offset_value); - ExPolygons intersection_poly_2 = intersection_ex(triangles_by_color_bottom[color_idx][layer_idx], offset_e); - append(triangles_by_color_bottom[color_idx][last_idx], std::move(intersection_poly_2)); - } - } - } - } - BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - segmentation of bottom layer - end"; - - std::vector> triangles_by_color_merged(num_extruders); - triangles_by_color_merged.assign(num_extruders, std::vector(num_layers)); - for (size_t layer_idx = 0; layer_idx < num_layers; ++layer_idx) { - throw_on_cancel_callback(); - for (size_t color_idx = 0; color_idx < triangles_by_color_merged.size(); ++color_idx) { - auto &self = triangles_by_color_merged[color_idx][layer_idx]; - append(self, std::move(triangles_by_color_bottom[color_idx][layer_idx])); - append(self, std::move(triangles_by_color_top[color_idx][layer_idx])); - self = union_ex(self); - } - - // Cut all colors for cases when two colors are overlapping - for (size_t color_idx = 1; color_idx < triangles_by_color_merged.size(); ++color_idx) { - triangles_by_color_merged[color_idx][layer_idx] = diff_ex(triangles_by_color_merged[color_idx][layer_idx], - triangles_by_color_merged[color_idx - 1][layer_idx]); - } - } -#else - // Maximum number of top / bottom layers accounts for maximum overlap of one thread group into a neighbor thread group. int max_top_layers = 0; int max_bottom_layers = 0; @@ -1470,8 +1255,7 @@ static inline std::vector> mmu_segmentation_top_and_bott // project downards pointing painted triangles over bottom surfaces. std::vector> top_raw(num_extruders), bottom_raw(num_extruders); std::vector zs = zs_from_layers(print_object.layers()); - Transform3d object_trafo = print_object.trafo(); - object_trafo.pretranslate(Vec3d(- unscale(print_object.center_offset().x()), - unscale(print_object.center_offset().y()), 0)); + Transform3d object_trafo = print_object.trafo_centered(); #ifdef MMU_SEGMENTATION_DEBUG_TOP_BOTTOM static int iRun = 0; @@ -1650,7 +1434,6 @@ static inline std::vector> mmu_segmentation_top_and_bott triangles_by_color_merged[color_idx - 1][layer_idx]); } }); -#endif return triangles_by_color_merged; } diff --git a/src/libslic3r/Print.hpp b/src/libslic3r/Print.hpp index 1854800cc..491960705 100644 --- a/src/libslic3r/Print.hpp +++ b/src/libslic3r/Print.hpp @@ -253,6 +253,9 @@ public: ConstLayerPtrsAdaptor layers() const { return ConstLayerPtrsAdaptor(&m_layers); } ConstSupportLayerPtrsAdaptor support_layers() const { return ConstSupportLayerPtrsAdaptor(&m_support_layers); } const Transform3d& trafo() const { return m_trafo; } + // 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; } const PrintInstances& instances() const { return m_instances; } // Whoever will get a non-const pointer to PrintObject will be able to modify its layers. diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 8ebe1eb10..ae9816531 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -428,10 +428,8 @@ 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. - Transform3d m = m_trafo; - m.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0)); auto to_octree = transform_to_octree().toRotationMatrix(); - its_transform(mesh, to_octree * m, true); + its_transform(mesh, to_octree * this->trafo_centered(), true); // Triangulate internal bridging surfaces. std::vector> overhangs(this->layers().size()); @@ -2298,7 +2296,7 @@ void PrintObject::project_and_append_custom_facets( : mv->supported_facets.get_facets_strict(*mv, type); if (! custom_facets.indices.empty()) project_triangles_to_slabs(this->layers(), custom_facets, - (Eigen::Translation3d(to_3d(unscaled(this->center_offset()), 0.)) * this->trafo() * mv->get_matrix()).cast(), + (this->trafo_centered() * mv->get_matrix()).cast(), seam, out); } } diff --git a/src/libslic3r/PrintObjectSlice.cpp b/src/libslic3r/PrintObjectSlice.cpp index 818519be4..ad6a23abc 100644 --- a/src/libslic3r/PrintObjectSlice.cpp +++ b/src/libslic3r/PrintObjectSlice.cpp @@ -695,11 +695,9 @@ void PrintObject::slice_volumes() } std::vector slice_zs = zs_from_layers(m_layers); - Transform3d trafo = this->trafo(); - trafo.pretranslate(Vec3d(- unscale(m_center_offset.x()), - unscale(m_center_offset.y()), 0)); std::vector> region_slices = slices_to_regions(this->model_object()->volumes, *m_shared_regions, slice_zs, slice_volumes_inner( - print->config(), this->config(), trafo, + print->config(), this->config(), this->trafo_centered(), this->model_object()->volumes, m_shared_regions->layer_ranges, slice_zs, throw_on_cancel_callback), m_config.clip_multipart_objects, throw_on_cancel_callback); @@ -832,8 +830,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(); - params.trafo.pretranslate(Vec3d(-unscale(m_center_offset.x()), -unscale(m_center_offset.y()), 0)); + params.trafo = this->trafo_centered(); 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);