From a4ecf2f2a6d140a25e9b76e90ae5f4cf8457bd91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Hejl?= Date: Mon, 7 Feb 2022 13:36:09 +0100 Subject: [PATCH] Replaced smooth_outward in multi-material segmentation with a function that removes duplicate points with angle threshold. It should fix #7838 and #6892. The main contribution of the smooth_outward function for multi-material segmentation was the removal of duplicate points in polygons using MutablePolygon::remove_duplicates(). But the issue with this function is that it deletes points only based on their distances, which could cause problems like in #7838. --- src/libslic3r/MultiMaterialSegmentation.cpp | 46 ++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/libslic3r/MultiMaterialSegmentation.cpp b/src/libslic3r/MultiMaterialSegmentation.cpp index 75537b6c64..922f28a635 100644 --- a/src/libslic3r/MultiMaterialSegmentation.cpp +++ b/src/libslic3r/MultiMaterialSegmentation.cpp @@ -1676,6 +1676,50 @@ static bool has_layer_only_one_color(const std::vector> return true; } +// Remove nearly duplicate points. If a distance between two points is less than point_eps +// and if the angle between its surrounding lines is less than max_angle, the point will be removed. +void remove_duplicates_points(MutablePolygon &polygon, double point_eps, double max_angle) +{ + if (polygon.size() >= 3) { + auto eps2 = point_eps * point_eps; + auto begin = polygon.begin(); + auto it = begin; + for (++it; it != begin;) { + auto prev = it.prev(); + auto next = (it.next() == polygon.end() ? begin : it.next()); + if ((*it - *prev).cast().squaredNorm() < eps2) { + Vec2i64 vector1 = (*it - *prev).cast(); + Vec2i64 vector2 = (*next - *prev).cast(); + if (double angle = atan2(cross2(vector1, vector2), vector1.dot(vector2)); angle < max_angle) { + it = it.remove(); + continue; + } + } + ++it; + } + } +} + +// Remove nearly duplicate points. If a distance between two points is less than point_eps +// and if the angle between its surrounding lines is less than max_angle, the point will be removed. +inline ExPolygons remove_duplicates_points(ExPolygons expolygons, double point_eps, double max_angle) +{ + MutablePolygon mp; + for (ExPolygon &expolygon : expolygons) { + mp.assign(expolygon.contour, expolygon.contour.size() * 2); + remove_duplicates_points(mp, point_eps, max_angle); + mp.polygon(expolygon.contour); + for (Polygon &hole : expolygon.holes) { + mp.assign(hole, hole.size() * 2); + remove_duplicates_points(mp, point_eps, max_angle); + mp.polygon(hole); + } + expolygon.holes.erase(std::remove_if(expolygon.holes.begin(), expolygon.holes.end(), [](const auto &p) { return p.empty(); }), expolygon.holes.end()); + } + expolygons.erase(std::remove_if(expolygons.begin(), expolygons.end(), [](const auto &p) { return p.empty(); }), expolygons.end()); + return expolygons; +} + std::vector> multi_material_segmentation_by_painting(const PrintObject &print_object, const std::function &throw_on_cancel_callback) { const size_t num_extruders = print_object.print()->config().nozzle_diameter.size(); @@ -1711,7 +1755,7 @@ std::vector> multi_material_segmentation_by_painting(con // Such close points sometimes caused that the Voronoi diagram has self-intersecting edges around these vertices. // This consequently leads to issues with the extraction of colored segments by function extract_colored_segments. // Calling expolygons_simplify fixed these issues. - input_expolygons[layer_idx] = smooth_outward(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), 10 * coord_t(SCALED_EPSILON)); + input_expolygons[layer_idx] = remove_duplicates_points(expolygons_simplify(offset_ex(ex_polygons, -10.f * float(SCALED_EPSILON)), 5 * SCALED_EPSILON), scaled(0.01), PI/6); #ifdef MMU_SEGMENTATION_DEBUG_INPUT {