From 355e3ba03a6377763906b51ab0df581b6baa5c32 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Mon, 16 May 2022 14:03:12 +0200 Subject: [PATCH] refactored seam placer to use AABB tree instead of edge grid lowered overhang tolerance for seam places --- src/libslic3r/GCode/SeamPlacer.cpp | 94 ++++++++++++++++----------- tests/libslic3r/test_aabbindirect.cpp | 4 +- 2 files changed, 57 insertions(+), 41 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index a606c9b7d6..8fe8a31b8c 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -8,11 +8,11 @@ #include #include +#include "libslic3r/AABBTreeLines.hpp" #include "libslic3r/ExtrusionEntity.hpp" #include "libslic3r/Print.hpp" #include "libslic3r/BoundingBox.hpp" #include "libslic3r/Color.hpp" -#include "libslic3r/EdgeGrid.hpp" #include "libslic3r/ClipperUtils.hpp" #include "libslic3r/Layer.hpp" #include "libslic3r/QuadricEdgeCollapse.hpp" @@ -678,7 +678,7 @@ struct SeamComparator { } //avoid overhangs - if (a.overhang > 0.0f || b.overhang > 0.0f) { + if (a.overhang > 0.1f || b.overhang > 0.1f) { return a.overhang < b.overhang; } @@ -738,7 +738,7 @@ struct SeamComparator { } //avoid overhangs - if (a.overhang > 0.0f || b.overhang > 0.0f) { + if (a.overhang > 0.1f || b.overhang > 0.1f) { return a.overhang < b.overhang; } @@ -937,28 +937,53 @@ void pick_random_seam_point(const std::vector &perimeter_points, perimeter.finalized = true; } -struct EdgeGridWrapper { - explicit EdgeGridWrapper(ExPolygons ex_polys) : - ex_polys(ex_polys) { +class PerimeterDistancer { + std::vector lines; + AABBTreeIndirect::Tree<2, double> tree; - grid.create(this->ex_polys, distance_field_resolution); - grid.calculate_sdf(); +public: + PerimeterDistancer(const Layer *layer) { + static const float eps = float(scale_(layer->object()->config().slice_closing_radius.value)); + // merge with offset + ExPolygons merged = layer->merged(eps); + // ofsset back + ExPolygons layer_outline = offset_ex(merged, -eps); + for (const ExPolygon &island : layer_outline) { + assert(island.contour.is_counter_clockwise()); + for (const auto &line : island.contour.lines()) { + lines.emplace_back(unscale(line.a), unscale(line.b)); + } + for (const Polygon &hole : island.holes) { + assert(hole.is_clockwise()); + for (const auto &line : hole.lines()) { + lines.emplace_back(unscale(line.a), unscale(line.b)); + } + } + } + tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(lines); + } + + float distance_from_perimeter(const Point &point) const { + Vec2d p = unscale(point); + size_t hit_idx_out; + Vec2d hit_point_out; + auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, hit_idx_out, hit_point_out); + if (distance < 0) { + return std::numeric_limits::max(); + } + + distance = sqrt(distance); + const Linef &line = lines[hit_idx_out]; + Vec2d v1 = line.b - line.a; + Vec2d v2 = p - line.a; + if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) { + distance *= -1; + } + return distance; } - const coord_t distance_field_resolution = coord_t(scale_(1.) + 0.5); - EdgeGrid::Grid grid; - ExPolygons ex_polys; } ; -EdgeGridWrapper compute_layer_merged_edge_grid(const Layer *layer) { - static const float eps = float(scale_(layer->object()->config().slice_closing_radius.value)); - // merge with offset - ExPolygons merged = layer->merged(eps); - // ofsset back - ExPolygons layer_outline = offset_ex(merged, -eps); - return EdgeGridWrapper(layer_outline); -} - } // namespace SeamPlacerImpl // Parallel process and extract each perimeter polygon of the given print object. @@ -1015,42 +1040,33 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) std::vector &layers = m_seam_per_object[po].layers; tbb::parallel_for(tbb::blocked_range(0, layers.size()), [po, &layers](tbb::blocked_range r) { - std::unique_ptr prev_layer_grid; + std::unique_ptr prev_layer_distancer; if (r.begin() > 0) { // previous layer exists - prev_layer_grid = std::make_unique( - compute_layer_merged_edge_grid(po->layers()[r.begin() - 1])); + prev_layer_distancer = std::make_unique(po->layers()[r.begin() - 1]); } for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { bool layer_has_multiple_loops = layers[layer_idx].points[0].perimeter.end_index < layers[layer_idx].points.size() - 1; - std::unique_ptr current_layer_grid = std::make_unique( - compute_layer_merged_edge_grid(po->layers()[layer_idx])); + std::unique_ptr current_layer_distancer = std::make_unique(po->layers()[layer_idx]); for (SeamCandidate &perimeter_point : layers[layer_idx].points) { Point point = Point::new_scale(Vec2f { perimeter_point.position.head<2>() }); - if (prev_layer_grid.get() != nullptr) { - coordf_t overhang_dist; - prev_layer_grid->grid.signed_distance(point, scaled(perimeter_point.perimeter.flow_width), - overhang_dist); - perimeter_point.overhang = - unscale(overhang_dist) - perimeter_point.perimeter.flow_width; + if (prev_layer_distancer.get() != nullptr) { + perimeter_point.overhang = prev_layer_distancer->distance_from_perimeter(point); } if (layer_has_multiple_loops) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) - coordf_t layer_embedded_distance; - current_layer_grid->grid.signed_distance(point, scaled(1.0f), - layer_embedded_distance); - perimeter_point.embedded_distance = unscale(layer_embedded_distance); + perimeter_point.embedded_distance = current_layer_distancer->distance_from_perimeter(point); } } - prev_layer_grid.swap(current_layer_grid); + prev_layer_distancer.swap(current_layer_distancer); } } - ); -} + ); + } // Estimates, if there is good seam point in the layer_idx which is close to last_point_pos // uses comparator.is_first_not_much_worse method to compare current seam with the closest point @@ -1463,7 +1479,7 @@ void SeamPlacer::place_seam(const Layer *layer, ExtrusionLoop &loop, bool extern Vec3f seam_position; size_t seam_index; - if (const Perimeter &perimeter = layer_perimeters.points[closest_perimeter_point_index].perimeter; + if (const Perimeter &perimeter = layer_perimeters.points[closest_perimeter_point_index].perimeter ; perimeter.finalized) { seam_position = perimeter.final_seam_position; seam_index = perimeter.seam_index; diff --git a/tests/libslic3r/test_aabbindirect.cpp b/tests/libslic3r/test_aabbindirect.cpp index 87cf80943a..b30f07fcac 100644 --- a/tests/libslic3r/test_aabbindirect.cpp +++ b/tests/libslic3r/test_aabbindirect.cpp @@ -273,7 +273,7 @@ TEST_CASE("AABBTreeLines vs SignedDistanceGrid time Benchmark", "[AABBIndirect]" std::cout << "Test build and queries together - same number of contour points and query points" << std::endl << - "And with limited contour edge length to 4mm " << std::endl; + "And with limited contour edge length to max 8mm " << std::endl; for (auto count : point_counts) { std::vector lines { Points { } }; @@ -285,7 +285,7 @@ TEST_CASE("AABBTreeLines vs SignedDistanceGrid time Benchmark", "[AABBIndirect]" for (int x = 0; x < count; ++x) { Vec2d cp { rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0, rand() / (double(RAND_MAX) + 1.0f) * 200.0 - 100.0 }; - Vec2d contour = prevf + cp.normalized()*4.0; // limits the cnotour edge len to 4mm + Vec2d contour = prevf + cp.normalized() * (rand() / (double(RAND_MAX) + 1.0f) * 8.0f); // limits the cnotour edge len to 8mm lines[0].push_back(Point::new_scale(contour)); linesf.emplace_back(prevf, contour); prevf = linesf.back().b;