From 098159566be3bb321e96d48ef367b9db3944de56 Mon Sep 17 00:00:00 2001 From: supermerill Date: Fri, 9 Sep 2022 19:52:16 +0200 Subject: Fix mmu paint supermerill/SuperSlicer#2639 --- src/libslic3r/EdgeGrid.hpp | 5 ++++ src/libslic3r/Model.cpp | 4 +++ src/libslic3r/Model.hpp | 1 + src/libslic3r/MultiMaterialSegmentation.cpp | 43 +++++++++++++++++------------ 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/libslic3r/EdgeGrid.hpp b/src/libslic3r/EdgeGrid.hpp index 44de5a919..e34be36a3 100644 --- a/src/libslic3r/EdgeGrid.hpp +++ b/src/libslic3r/EdgeGrid.hpp @@ -179,6 +179,11 @@ public: assert(m_bbox.contains(p2)); p1 -= m_bbox.min; p2 -= m_bbox.min; + assert(std::abs(p1.x()) < coord_t(int32_t(0x7FFFFFFF))); + assert(std::abs(p1.y()) < coord_t(int32_t(0x7FFFFFFF))); + assert(std::abs(p2.x()) < coord_t(int32_t(0x7FFFFFFF))); + assert(std::abs(p2.y()) < coord_t(int32_t(0x7FFFFFFF))); + assert(p1.x() >= 0 && p1.x() < coord_t(m_cols) * m_resolution); assert(p1.x() >= 0 && p1.x() < coord_t(m_cols) * m_resolution); assert(p1.y() >= 0 && p1.y() < coord_t(m_rows) * m_resolution); assert(p2.x() >= 0 && p2.x() < coord_t(m_cols) * m_resolution); diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index bb4e7603b..05f521839 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2093,6 +2093,10 @@ indexed_triangle_set FacetsAnnotation::get_facets(const ModelVolume& mv, Enforce selector.deserialize(m_data, false); return selector.get_facets(type); } +void FacetsAnnotation::set_facets_selector(TriangleSelector& selector) const +{ + selector.deserialize(m_data, false); +} indexed_triangle_set FacetsAnnotation::get_facets_strict(const ModelVolume& mv, EnforcerBlockerType type) const { diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index efcacb726..335366d23 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -553,6 +553,7 @@ public: const std::pair>, std::vector>& get_data() const throw() { return m_data; } bool set(const TriangleSelector& selector); indexed_triangle_set get_facets(const ModelVolume& mv, EnforcerBlockerType type) const; + void set_facets_selector(TriangleSelector& selector) const; indexed_triangle_set get_facets_strict(const ModelVolume& mv, EnforcerBlockerType type) const; bool has_facets(const ModelVolume& mv, EnforcerBlockerType type) const; bool empty() const { return m_data.first.empty(); } diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 25b5e0f72..dad03aa05 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -7,6 +7,7 @@ #include "Geometry/VoronoiVisualUtils.hpp" #include "MutablePolygon.hpp" #include "format.hpp" +#include "TriangleSelector.hpp" #include #include @@ -98,6 +99,7 @@ struct PaintedLineVisitor const Vec2d v1 = line_to_test.vector().cast(); const double v1_sqr_norm = v1.squaredNorm(); const double heuristic_thr_part = line_to_test.length() + append_threshold; + double min_res = std::max(Slic3r::sqr(resolution), append_threshold_sqr); for (auto it_contour_and_segment = cell_data_range.first; it_contour_and_segment != cell_data_range.second; ++it_contour_and_segment) { Line grid_line = grid.line(*it_contour_and_segment); const Vec2d v2 = grid_line.vector().cast(); @@ -110,15 +112,14 @@ struct PaintedLineVisitor (grid_line.a - line_to_test.b).cast().squaredNorm() > heuristic_thr_sqr || (grid_line.b - line_to_test.b).cast().squaredNorm() > heuristic_thr_sqr) continue; - // When lines have too different length, it is necessary to normalize them if (Slic3r::sqr(v1.dot(v2)) > cos_threshold2 * v1_sqr_norm * v2.squaredNorm()) { // The two vectors are nearly collinear (their mutual angle is lower than 30 degrees) if (painted_lines_set.find(*it_contour_and_segment) == painted_lines_set.end()) { - if (grid_line.distance_to_squared(line_to_test.a) < append_threshold2 || - grid_line.distance_to_squared(line_to_test.b) < append_threshold2 || - line_to_test.distance_to_squared(grid_line.a) < append_threshold2 || - line_to_test.distance_to_squared(grid_line.b) < append_threshold2) { + if (grid_line.distance_to_squared(line_to_test.a) < min_res || + grid_line.distance_to_squared(line_to_test.b) < min_res || + line_to_test.distance_to_squared(grid_line.a) < min_res || + line_to_test.distance_to_squared(grid_line.b) < min_res) { Line line_to_test_projected; project_line_on_line(grid_line, line_to_test, &line_to_test_projected); @@ -144,10 +145,11 @@ struct PaintedLineVisitor Line line_to_test; std::unordered_set, boost::hash>> painted_lines_set; int color = -1; + double resolution = 50 * SCALED_EPSILON; static inline const double cos_threshold2 = Slic3r::sqr(cos(M_PI * 30. / 180.)); static inline const double append_threshold = 50 * SCALED_EPSILON; - static inline const double append_threshold2 = Slic3r::sqr(append_threshold); + static inline const double append_threshold_sqr = Slic3r::sqr(append_threshold); }; static Polygon colored_points_to_polygon(const std::vector &lines) @@ -1428,9 +1430,9 @@ static inline std::vector> mmu_segmentation_top_and_bott // Number of regions for a queried color. int num_regions { 0 }; // Maximum perimeter extrusion width for a queried color. - float extrusion_width { 0.f }; + coordf_t extrusion_width { 0.f }; // Minimum radius of a region to be printable. Used to filter regions by morphological opening. - float small_region_threshold { 0.f }; + coordf_t small_region_threshold { 0.f }; // Maximum number of top layers for a queried color. int top_solid_layers { 0 }; // Maximum number of bottom layers for a queried color. @@ -1444,19 +1446,20 @@ static inline std::vector> mmu_segmentation_top_and_bott // color_idx == 0 means "don't know" extruder aka the underlying extruder. // As this region may split existing regions, we collect statistics over all regions for color_idx == 0. color_idx == 0 || config.perimeter_extruder == int(color_idx)) { - out.extrusion_width = std::max(out.extrusion_width, float(config.perimeter_extrusion_width)); + double perimeter_extrusion_width = config.get_computed_value("perimeter_extrusion_width"); + out.extrusion_width = std::max(out.extrusion_width, perimeter_extrusion_width); out.top_solid_layers = std::max(out.top_solid_layers, config.top_solid_layers); out.bottom_solid_layers = std::max(out.bottom_solid_layers, config.bottom_solid_layers); - out.small_region_threshold = config.gap_fill_enabled.value && config.gap_fill_speed.value > 0 ? + out.small_region_threshold = config.gap_fill_enabled.value ? // Gap fill enabled. Enable a single line of 1/2 extrusion width. - 0.5f * float(config.perimeter_extrusion_width) : + 0.5f * (perimeter_extrusion_width) : // Gap fill disabled. Enable two lines slightly overlapping. - float(config.perimeter_extrusion_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(float(config.perimeter_extrusion_width), float(layer.height)); - out.small_region_threshold = scaled(out.small_region_threshold * 0.5f); + (perimeter_extrusion_width) + 0.7f * Flow::rounded_rectangle_extrusion_spacing(perimeter_extrusion_width, float(layer.height), 1.f); + out.small_region_threshold = scale_d(out.small_region_threshold * 0.5f); ++ out.num_regions; } assert(out.num_regions > 0); - out.extrusion_width = scaled(out.extrusion_width); + out.extrusion_width = scale_d(out.extrusion_width); return out; }; @@ -1624,7 +1627,7 @@ void export_processed_input_expolygons_to_svg(const std::string &path, const Lay ::Slic3r::SVG svg(path.c_str(), bbox); for (LayerRegion *region : regions) - svg.draw_outline(region->slices.surfaces, "blue", "cyan", stroke_width); + svg.draw_outline(region->slices().surfaces, "blue", "cyan", stroke_width); svg.draw_outline(processed_input_expolygons, "red", "pink", stroke_width); } @@ -1688,6 +1691,7 @@ std::vector> multi_material_segmentation_by_painting(con std::vector edge_grids(num_layers); const ConstLayerPtrsAdaptor layers = print_object.layers(); std::vector input_expolygons(num_layers); + coord_t resolution = scale_t(print_object.config().option("resolution")->getFloat()); throw_on_cancel_callback(); @@ -1747,15 +1751,18 @@ std::vector> multi_material_segmentation_by_painting(con BOOST_LOG_TRIVIAL(debug) << "MMU segmentation - projection of painted triangles - begin"; for (const ModelVolume *mv : print_object.model_object()->volumes) { - tbb::parallel_for(tbb::blocked_range(1, num_extruders + 1), [&mv, &print_object, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &throw_on_cancel_callback](const tbb::blocked_range &range) { + //can reuse the TriangleSelector for each extruder_idx + TriangleSelector tri_selector(mv->mesh()); + mv->mmu_segmentation_facets.set_facets_selector(tri_selector); + tbb::parallel_for(tbb::blocked_range(1, num_extruders + 1), [&mv, &print_object, &layers, &edge_grids, &painted_lines, &painted_lines_mutex, &input_expolygons, &resolution, &tri_selector , &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 = mv->mmu_segmentation_facets.get_facets(*mv, EnforcerBlockerType(extruder_idx)); + const indexed_triangle_set custom_facets = tri_selector.get_facets(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) { + 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, &resolution](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(); -- cgit v1.2.3