From 20bd7f9a263b7b23a5c0f8d08065f6ff45a4b485 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Mon, 3 Oct 2022 15:59:34 +0200 Subject: [PATCH] improvements in islands recognition; LinesDistancer class for both Point based and Floating based lines --- src/libslic3r/AABBTreeLines.hpp | 56 +++++++++-- src/libslic3r/SupportSpotsGenerator.cpp | 127 ++++++------------------ 2 files changed, 77 insertions(+), 106 deletions(-) diff --git a/src/libslic3r/AABBTreeLines.hpp b/src/libslic3r/AABBTreeLines.hpp index 39f828b558..7d6ff1ccc6 100644 --- a/src/libslic3r/AABBTreeLines.hpp +++ b/src/libslic3r/AABBTreeLines.hpp @@ -3,6 +3,7 @@ #include "libslic3r/AABBTreeIndirect.hpp" #include "libslic3r/Line.hpp" +#include namespace Slic3r { @@ -24,16 +25,16 @@ struct IndexedLinesDistancer { inline VectorType closest_point_to_origin(size_t primitive_index, ScalarType &squared_distance) { - VectorType nearest_point; + Vec nearest_point; const LineType &line = lines[primitive_index]; - squared_distance = line_alg::distance_to_squared(line, origin, &nearest_point); - return nearest_point; + squared_distance = line_alg::distance_to_squared(line, origin.template cast(), &nearest_point); + return nearest_point.template cast(); } }; } -// Build a balanced AABB Tree over a vector of float lines, balancing the tree +// Build a balanced AABB Tree over a vector of lines, balancing the tree // on centroids of the lines. // Epsilon is applied to the bounding boxes of the AABB Tree to cope with numeric inaccuracies // during tree traversal. @@ -41,7 +42,7 @@ template inline AABBTreeIndirect::Tree<2, typename LineType::Scalar> build_aabb_tree_over_indexed_lines( const std::vector &lines, //FIXME do we want to apply an epsilon? - const float eps = 0) + const double eps = 0) { using TreeType = AABBTreeIndirect::Tree<2, typename LineType::Scalar>; // using CoordType = typename TreeType::CoordType; @@ -103,8 +104,49 @@ inline typename VectorType::Scalar squared_distance_to_indexed_lines( std::numeric_limits::infinity(), hit_idx_out, hit_point_out); } -} +template class LinesDistancer +{ +private: + std::vector lines; + using Scalar = typename LineType::Scalar; + using Floating = typename std::conditional::value, Scalar, double>::type; + AABBTreeIndirect::Tree<2, Scalar> tree; -} +public: + explicit LinesDistancer(const std::vector &lines) : lines(lines) + { + tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines); + } + + // negative sign means inside + std::tuple> signed_distance_from_lines_extra(const Vec<2, Scalar> &point) const + { + size_t nearest_line_index_out = size_t(-1); + Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero(); + Vec<2, Floating> p = point.template cast(); + auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out); + + if (distance < 0) { return {std::numeric_limits::infinity(), nearest_line_index_out, nearest_point_out}; } + + distance = sqrt(distance); + const LineType &line = lines[nearest_line_index_out]; + Vec<2, Floating> v1 = (line.b - line.a).template cast(); + Vec<2, Floating> v2 = (point - line.a).template cast(); + if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) { distance *= -1.0; } + return {distance, nearest_line_index_out, nearest_point_out}; + } + + Floating signed_distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const + { + auto [dist, idx, np] = signed_distance_from_lines_extra(point); + return dist; + } + + const LineType &get_line(size_t line_idx) const { return lines[line_idx]; } + + const std::vector &get_lines() const { return lines; } +}; + +}} // namespace Slic3r::AABBTreeLines #endif /* SRC_LIBSLIC3R_AABBTREELINES_HPP_ */ diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 697518bd08..09b2bc5aea 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -1,6 +1,9 @@ #include "SupportSpotsGenerator.hpp" +#include "ExPolygon.hpp" #include "ExtrusionEntity.hpp" +#include "Line.hpp" +#include "Polygon.hpp" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" #include "tbb/blocked_range2d.h" @@ -70,46 +73,10 @@ SupportPoint::SupportPoint(const Vec3f &position, float force, float spot_radius position(position), force(force), spot_radius(spot_radius), direction(direction) { } -class LinesDistancer { -private: - std::vector lines; - AABBTreeIndirect::Tree<2, float> tree; - -public: - explicit LinesDistancer(const std::vector &lines) : - lines(lines) { - tree = AABBTreeLines::build_aabb_tree_over_indexed_lines(this->lines); - } - - // negative sign means inside - float signed_distance_from_lines(const Vec2f &point, size_t &nearest_line_index_out, - Vec2f &nearest_point_out) const { - auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, point, nearest_line_index_out, - nearest_point_out); - if (distance < 0) - return std::numeric_limits::infinity(); - - distance = sqrt(distance); - const ExtrusionLine &line = lines[nearest_line_index_out]; - Vec2f v1 = line.b - line.a; - Vec2f v2 = point - line.a; - if ((v1.x() * v2.y()) - (v1.y() * v2.x()) > 0.0) { - distance *= -1; - } - return distance; - } - - const ExtrusionLine& get_line(size_t line_idx) const { - return lines[line_idx]; - } - - const std::vector& get_lines() const { - return lines; - } -}; - static const size_t NULL_ISLAND = std::numeric_limits::max(); +using LD = AABBTreeLines::LinesDistancer; + class PixelGrid { Vec2f pixel_size; Vec2f origin; @@ -387,7 +354,7 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity, std::vector &checked_lines_out, float layer_z, const LayerRegion *layer_region, - const LinesDistancer &prev_layer_lines, + const LD &prev_layer_lines, Issues &issues, const Params ¶ms) { @@ -429,11 +396,7 @@ void check_extrusion_entity_stability(const ExtrusionEntity *entity, // malformation in concave angles does not happen malformation_acc.add_angle(std::max(0.0f, curr_angle)); - size_t nearest_line_idx; - Vec2f nearest_point; - float dist_from_prev_layer = prev_layer_lines.signed_distance_from_lines(current_line.b, nearest_line_idx, - nearest_point); - + auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.signed_distance_from_lines_extra(current_line.b); if (fabs(dist_from_prev_layer) < overhang_dist) { bridging_acc.reset(); } else { @@ -491,53 +454,18 @@ std::tuple reckon_islands( } } - std::vector islands; // these search trees will be used to determine to which island does the extrusion belong. - std::vector> island_extrusions; //final assigment of each extrusion to an island. - // initliaze the search from external perimeters - at the beginning, there is island candidate for each external perimeter. - // some of them will disappear (e.g. holes) - for (size_t e = 0; e < extrusions.size(); ++e) { - if (layer_lines[extrusions[e].first].origin_entity->is_loop() && - layer_lines[extrusions[e].first].is_external_perimeter()) { - std::vector copy(extrusions[e].second - extrusions[e].first); - for (size_t ex_line_idx = extrusions[e].first; ex_line_idx < extrusions[e].second; ++ex_line_idx) { - copy[ex_line_idx - extrusions[e].first] = layer_lines[ex_line_idx]; - } - islands.emplace_back(copy); - island_extrusions.push_back( { e }); - } + std::vector> islands; // these search trees will be used to determine to which island does the extrusion belong. + for (const ExPolygon& island : layer->lslices) { + islands.emplace_back(to_lines(island)); } - // backup code if islands not found - // If that happens, just make the first extrusion into island - it may be wrong, but it won't crash. - if (islands.empty() && !extrusions.empty()) { - std::vector copy(extrusions[0].second - extrusions[0].first); - for (size_t ex_line_idx = extrusions[0].first; ex_line_idx < extrusions[0].second; ++ex_line_idx) { - copy[ex_line_idx - extrusions[0].first] = layer_lines[ex_line_idx]; - } - islands.emplace_back(copy); - island_extrusions.push_back( { 0 }); - } - - // assign non external extrusions to islands - for (size_t e = 0; e < extrusions.size(); ++e) { - if (!layer_lines[extrusions[e].first].origin_entity->is_loop() || - !layer_lines[extrusions[e].first].is_external_perimeter()) { - bool island_assigned = false; - for (size_t i = 0; i < islands.size(); ++i) { - if (island_extrusions[i].empty()) { - continue; - } - size_t idx = 0; - Vec2f pt = Vec2f::Zero(); - if (islands[i].signed_distance_from_lines(layer_lines[extrusions[e].first].a, idx, pt) < 0) { - island_extrusions[i].push_back(e); - island_assigned = true; - break; - } - } - if (!island_assigned) { // If extrusion is not assigned for some reason, push it into the first island. As with the previous backup code, - // it may be wrong, but it won't crash - island_extrusions[0].push_back(e); + std::vector> island_extrusions(islands.size(), + std::vector{}); // final assigment of each extrusion to an island. + for (size_t extrusion_idx = 0; extrusion_idx < extrusions.size(); extrusion_idx++) { + Point second_point = Point::new_scale(layer_lines[extrusions[extrusion_idx].first].b); + for (size_t island_idx = 0; island_idx < islands.size(); island_idx++) { + if (islands[island_idx].signed_distance_from_lines(second_point) <= 0.0) { + island_extrusions[island_idx].push_back(extrusion_idx); } } } @@ -553,10 +481,14 @@ std::tuple reckon_islands( } Island island { }; - island.external_lines.insert(island.external_lines.end(), - layer_lines.begin() + extrusions[island_ex[0]].first, - layer_lines.begin() + extrusions[island_ex[0]].second); for (size_t extrusion_idx : island_ex) { + + if (layer_lines[extrusions[extrusion_idx].first].is_external_perimeter()) { + island.external_lines.insert(island.external_lines.end(), + layer_lines.begin() + extrusions[extrusion_idx].first, + layer_lines.begin() + extrusions[extrusion_idx].second); + } + for (size_t lidx = extrusions[extrusion_idx].first; lidx < extrusions[extrusion_idx].second; ++lidx) { line_to_island_mapping[lidx] = result.islands.size(); const ExtrusionLine &line = layer_lines[lidx]; @@ -1050,7 +982,7 @@ Issues check_global_stability(SupportGridFilter supports_presence_grid, #ifdef DETAILED_DEBUG_LOGS weakest_conn.print_info("weakest connection info: "); #endif - LinesDistancer island_lines_dist(island.external_lines); + LD island_lines_dist(island.external_lines); float unchecked_dist = params.min_distance_between_support_points + 1.0f; for (const ExtrusionLine &line : island.external_lines) { @@ -1059,12 +991,9 @@ Issues check_global_stability(SupportGridFilter supports_presence_grid, unchecked_dist += line.len; } else { unchecked_dist = line.len; - Vec2f target_point; - size_t idx; Vec3f pivot_site_search_point = to_3d(Vec2f(line.b + (line.b - line.a).normalized() * 300.0f), layer_z); - island_lines_dist.signed_distance_from_lines(pivot_site_search_point.head<2>(), idx, - target_point); + auto [dist, nidx, target_point] = island_lines_dist.signed_distance_from_lines_extra(pivot_site_search_point.head<2>()); Vec3f support_point = to_3d(target_point, layer_z); auto force = part.is_stable_while_extruding(weakest_conn, line, support_point, layer_z, params); if (force > 0) { @@ -1147,7 +1076,7 @@ std::tuple> check_extrusions_and_build_graph(c } } #endif - LinesDistancer external_lines(layer_lines); + LD external_lines(layer_lines); layer_lines.clear(); prev_layer_grid = layer_grid; @@ -1199,7 +1128,7 @@ std::tuple> check_extrusions_and_build_graph(c } } #endif - external_lines = LinesDistancer(layer_lines); + external_lines = LD(layer_lines); layer_lines.clear(); prev_layer_grid = layer_grid; }