diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index b765c9c76d..e2d80b3212 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -45,11 +45,12 @@ #include "libslic3r/libslic3r.h" #include "MultiMaterialSegmentation.hpp" -constexpr bool MM_SEGMENTATION_DEBUG_GRAPH = false; -constexpr bool MM_SEGMENTATION_DEBUG_REGIONS = false; -constexpr bool MM_SEGMENTATION_DEBUG_INPUT = false; -constexpr bool MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS = false; -constexpr bool MM_SEGMENTATION_DEBUG_TOP_BOTTOM = false; +constexpr bool MM_SEGMENTATION_DEBUG_GRAPH = false; +constexpr bool MM_SEGMENTATION_DEBUG_REGIONS = false; +constexpr bool MM_SEGMENTATION_DEBUG_INPUT = false; +constexpr bool MM_SEGMENTATION_DEBUG_FILTERED_COLOR_LINES = false; +constexpr bool MM_SEGMENTATION_DEBUG_COLORIZED_POLYGONS = false; +constexpr bool MM_SEGMENTATION_DEBUG_TOP_BOTTOM = false; namespace Slic3r { @@ -66,6 +67,19 @@ enum VD_ANNOTATION : Voronoi::VD::cell_type::color_type { DELETED = 2 }; +struct ColorLine { + static const constexpr int Dim = 2; + using Scalar = Point::Scalar; + + ColorLine(const Point &a, const Point &b, ColorPolygon::Color color) : a(a), b(b), color(color) {} + + Point a; + Point b; + ColorPolygon::Color color; +}; + +using ColorLines = std::vector; + struct ColorChange { explicit ColorChange(double t, uint8_t color_next) : t(t), color_next(color_next) {} @@ -196,6 +210,38 @@ using ColorPoints = std::vector; } } +[[maybe_unused]] static void export_color_polygons_to_svg(const std::string &path, const ColorPolygons &color_polygons, const ExPolygons &lslices) { + const std::vector colors = {"blue", "cyan", "red", "orange", "pink", "yellow", "magenta", "purple", "black"}; + const std::string default_color = "black"; + const coordf_t stroke_width = scaled(0.05); + const BoundingBox bbox = get_extents(lslices); + + ::Slic3r::SVG svg(path.c_str(), bbox); + for (const ColorPolygon &color_polygon : color_polygons) { + for (size_t pt_idx = 1; pt_idx < color_polygon.size(); ++pt_idx) { + const uint8_t color = color_polygon.colors[pt_idx - 1]; + svg.draw(Line(color_polygon.points[pt_idx - 1], color_polygon.points[pt_idx]), (color < colors.size() ? colors[color] : default_color), stroke_width); + } + + const uint8_t color = color_polygon.colors.back(); + svg.draw(Line(color_polygon.points.back(), color_polygon.points.front()), (color < colors.size() ? colors[color] : default_color), stroke_width); + } +} + +[[maybe_unused]] static void export_color_polygons_lines_to_svg(const std::string &path, const std::vector &color_polygons_lines, const ExPolygons &lslices) { + const std::vector colors = {"blue", "cyan", "red", "orange", "pink", "yellow", "magenta", "purple", "black"}; + const std::string default_color = "black"; + const coordf_t stroke_width = scaled(0.05); + const BoundingBox bbox = get_extents(lslices); + + ::Slic3r::SVG svg(path.c_str(), bbox); + for (const ColorLines &color_polygon_lines : color_polygons_lines) { + for (const ColorLine &color_line : color_polygon_lines) { + svg.draw(Line(color_line.a, color_line.b), (color_line.color < colors.size() ? colors[color_line.color] : default_color), stroke_width); + } + } +} + template inline OutputIterator douglas_peucker(ColorPoints::const_iterator begin, ColorPoints::const_iterator end, OutputIterator out, const double tolerance, const double max_different_color_length) { const int64_t tolerance_sq = static_cast(sqr(tolerance)); @@ -1016,6 +1062,21 @@ std::vector color_points_to_colored_lines(const std::vector get_print_object_layers_zs(const SpanOfConstPtrs &layers) { std::vector layers_zs; layers_zs.reserve(layers.size()); @@ -1350,6 +1411,7 @@ std::vector> multi_material_segmentation_by_painting(con std::vector input_expolygons(num_layers); std::vector> input_polygons_projection_lines_layers(num_layers); + std::vector> color_polygons_lines_layers(num_layers); // Merge all regions and remove small holes BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Slices preprocessing in parallel - Begin"; @@ -1384,19 +1446,9 @@ std::vector> multi_material_segmentation_by_painting(con } } }); // end of parallel_for - - std::vector> color_projection_lines_distancer_layers(num_layers); - - tbb::parallel_for(tbb::blocked_range(0, num_layers), [&input_polygons_projection_lines_layers, &color_projection_lines_distancer_layers, &throw_on_cancel_callback](const tbb::blocked_range &range) { - for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { - throw_on_cancel_callback(); - - color_projection_lines_distancer_layers[layer_idx] = AABBTreeLines::LinesDistancer{create_color_projection_lines_mapping(input_polygons_projection_lines_layers[layer_idx])}; - } - }); // end of parallel_for BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Slices preprocessing in parallel - End"; - BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Projection of painted triangles - Begin"; + BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Slicing painted triangles - Begin"; const std::vector layer_zs = get_print_object_layers_zs(layers); for (const ModelVolume *mv : print_object.model_object()->volumes) { const indexed_triangle_set_with_color mesh_with_color = mv->mm_segmentation_facets.get_all_facets_strict_with_colors(*mv); @@ -1405,21 +1457,19 @@ std::vector> multi_material_segmentation_by_painting(con std::vector color_polygons_per_layer = slice_mesh(mesh_with_color, layer_zs, slicing_params); - // Project sliced ColorPolygons on sliced layers (input_expolygons). - tbb::parallel_for(tbb::blocked_range(0, num_layers), [&color_projection_lines_distancer_layers, &color_polygons_per_layer, &throw_on_cancel_callback](const tbb::blocked_range &range) { + tbb::parallel_for(tbb::blocked_range(0, num_layers), [&color_polygons_per_layer, &color_polygons_lines_layers, &throw_on_cancel_callback](const tbb::blocked_range &range) { for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { throw_on_cancel_callback(); - const AABBTreeLines::LinesDistancer &color_projection_lines_distancer = color_projection_lines_distancer_layers[layer_idx]; - ColorPolygons &color_polygons = color_polygons_per_layer[layer_idx]; + ColorPolygons &raw_color_polygons = color_polygons_per_layer[layer_idx]; + filter_out_small_color_polygons(raw_color_polygons, POLYGON_FILTER_MIN_AREA_SCALED, POLYGON_FILTER_MIN_OFFSET_SCALED); - filter_out_small_color_polygons(color_polygons, POLYGON_FILTER_MIN_AREA_SCALED, POLYGON_FILTER_MIN_OFFSET_SCALED); - - if (color_polygons.empty()) + if (raw_color_polygons.empty()) continue; - const std::vector color_polygons_points = color_polygons_to_color_points(color_polygons); - for (const ColorPoints &color_polygon_points : color_polygons_points) { + // Convert ColorPolygons into the vector of ColorPoints to perform several filtrations that are performed on points. + color_polygons_lines_layers[layer_idx].reserve(color_polygons_lines_layers[layer_idx].size() + raw_color_polygons.size()); + for (const ColorPoints &color_polygon_points : color_polygons_to_color_points(raw_color_polygons)) { ColorPoints color_polygon_points_filtered; color_polygon_points_filtered.reserve(color_polygon_points.size()); @@ -1431,21 +1481,41 @@ std::vector> multi_material_segmentation_by_painting(con filter_color_of_small_segments(color_polygon_points_filtered, POLYGON_COLOR_FILTER_DISTANCE_SCALED); assert(is_valid_color_polygon_points(color_polygon_points_filtered)); - for (const ColorPoint &color_pt : color_polygon_points_filtered) { - auto [proj_distance, nearest_line_index, nearest_point] = color_projection_lines_distancer.distance_from_lines_extra(color_pt.p); - - if (proj_distance > MM_SEGMENTATION_MAX_PROJECTION_DISTANCE_SCALED) - continue; - - ColorProjectionLine &color_projection_line = *color_projection_lines_distancer.get_line(nearest_line_index).color_projection_line; - const double line_t_value = std::clamp((nearest_point - color_projection_line.a.cast()).norm() / (color_projection_line.b - color_projection_line.a).cast().norm(), 0., 1.); - - color_projection_line.color_changes.emplace_back(line_t_value, color_pt.color_next); - } + color_polygons_lines_layers[layer_idx].emplace_back(color_points_to_color_lines(color_polygon_points_filtered)); } } }); // end of parallel_for } + BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Slicing painted triangles - End"; + + if constexpr (MM_SEGMENTATION_DEBUG_FILTERED_COLOR_LINES) { + for (size_t layer_idx = 0; layer_idx < print_object.layers().size(); ++layer_idx) { + export_color_polygons_lines_to_svg(debug_out_path("mm-filtered-color-line-%d.svg", layer_idx), color_polygons_lines_layers[layer_idx], input_expolygons[layer_idx]); + } + } + + // Project sliced ColorPolygons on sliced layers (input_expolygons). + BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Projection of painted triangles - Begin"; + tbb::parallel_for(tbb::blocked_range(0, num_layers), [&color_polygons_lines_layers, &input_polygons_projection_lines_layers, &throw_on_cancel_callback](const tbb::blocked_range &range) { + for (size_t layer_idx = range.begin(); layer_idx < range.end(); ++layer_idx) { + throw_on_cancel_callback(); + + const AABBTreeLines::LinesDistancer color_projection_lines_distancer{create_color_projection_lines_mapping(input_polygons_projection_lines_layers[layer_idx])}; + for (const ColorLines &color_polygon : color_polygons_lines_layers[layer_idx]) { + for (const ColorLine &color_line : color_polygon) { + auto [proj_distance, nearest_line_index, nearest_point] = color_projection_lines_distancer.distance_from_lines_extra(color_line.a); + + if (proj_distance > MM_SEGMENTATION_MAX_PROJECTION_DISTANCE_SCALED) + continue; + + ColorProjectionLine &color_projection_line = *color_projection_lines_distancer.get_line(nearest_line_index).color_projection_line; + const double line_t_value = std::clamp((nearest_point - color_projection_line.a.cast()).norm() / (color_projection_line.b - color_projection_line.a).cast().norm(), 0., 1.); + + color_projection_line.color_changes.emplace_back(line_t_value, color_line.color); + } + } + } + }); // end of parallel_for BOOST_LOG_TRIVIAL(debug) << "MM segmentation - Projection of painted triangles - End"; std::vector> segmented_regions(num_layers);