diff --git a/src/libslic3r/AABBTreeLines.hpp b/src/libslic3r/AABBTreeLines.hpp index 7d6ff1ccc..89a8a7cd5 100644 --- a/src/libslic3r/AABBTreeLines.hpp +++ b/src/libslic3r/AABBTreeLines.hpp @@ -1,6 +1,8 @@ #ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_ #define SRC_LIBSLIC3R_AABBTREELINES_HPP_ +#include "Utils.hpp" +#include "libslic3r.h" #include "libslic3r/AABBTreeIndirect.hpp" #include "libslic3r/Line.hpp" #include @@ -127,12 +129,26 @@ public: 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; } + auto d1 = (v1.x() * v2.y()) - (v1.y() * v2.x()); + + LineType second_line = line; + if ((line.a.template cast() - nearest_point_out).squaredNorm() < SCALED_EPSILON) { + second_line = lines[prev_idx_modulo(nearest_line_index_out, lines.size())]; + } else { + second_line = lines[next_idx_modulo(nearest_line_index_out, lines.size())]; + } + v1 = (second_line.b - second_line.a).template cast(); + v2 = (point - second_line.a).template cast(); + auto d2 = (v1.x() * v2.y()) - (v1.y() * v2.x()); + + auto d = abs(d1) > abs(d2) ? d1 : d2; + + if (d > 0.0) { distance *= -1.0; } + return {distance, nearest_line_index_out, nearest_point_out}; } diff --git a/src/libslic3r/ExPolygon.hpp b/src/libslic3r/ExPolygon.hpp index 3e42c8670..7f2aac628 100644 --- a/src/libslic3r/ExPolygon.hpp +++ b/src/libslic3r/ExPolygon.hpp @@ -1,6 +1,7 @@ #ifndef slic3r_ExPolygon_hpp_ #define slic3r_ExPolygon_hpp_ +#include "Point.hpp" #include "libslic3r.h" #include "Polygon.hpp" #include "Polyline.hpp" @@ -124,6 +125,28 @@ inline Lines to_lines(const ExPolygons &src) return lines; } +inline std::vector to_linesf(const ExPolygons &src) +{ + size_t n_lines = 0; + for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++ it_expoly) { + n_lines += it_expoly->contour.points.size(); + for (size_t i = 0; i < it_expoly->holes.size(); ++ i) + n_lines += it_expoly->holes[i].points.size(); + } + std::vector lines; + lines.reserve(n_lines); + for (ExPolygons::const_iterator it_expoly = src.begin(); it_expoly != src.end(); ++ it_expoly) { + for (size_t i = 0; i <= it_expoly->holes.size(); ++ i) { + const Points &points = ((i == 0) ? it_expoly->contour : it_expoly->holes[i - 1]).points; + for (Points::const_iterator it = points.begin(); it != points.end()-1; ++it) + lines.push_back(Linef(unscaled(*it), unscaled(*(it + 1)))); + lines.push_back(Linef(unscaled(points.back()), unscaled(points.front()))); + } + } + return lines; +} + + inline Polylines to_polylines(const ExPolygon &src) { Polylines polylines; diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 926538ec9..e18984a64 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1,6 +1,7 @@ #include "SeamPlacer.hpp" #include "Color.hpp" +#include "Polygon.hpp" #include "PrintConfig.hpp" #include "tbb/parallel_for.h" #include "tbb/blocked_range.h" @@ -995,49 +996,6 @@ void pick_random_seam_point(const std::vector &perimeter_points, perimeter.finalized = true; } -class PerimeterDistancer { - std::vector lines; - AABBTreeIndirect::Tree<2, double> tree; - -public: - PerimeterDistancer(const Layer *layer) { - ExPolygons layer_outline = layer->lslices; - 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 Vec2f &point) const { - Vec2d p = point.cast(); - size_t hit_idx_out { }; - Vec2d hit_point_out = Vec2d::Zero(); - 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; - } -} -; - } // namespace SeamPlacerImpl // Parallel process and extract each perimeter polygon of the given print object. @@ -1089,13 +1047,14 @@ void SeamPlacer::calculate_candidates_visibility(const PrintObject *po, void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) { using namespace SeamPlacerImpl; + using PerimeterDistancer = AABBTreeLines::LinesDistancer; 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_distancer; if (r.begin() > 0) { // previous layer exists - prev_layer_distancer = std::make_unique(po->layers()[r.begin() - 1]); + prev_layer_distancer = std::make_unique(to_linesf(po->layers()[r.begin() - 1]->lslices)); } for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { @@ -1106,12 +1065,12 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) } }; bool should_compute_layer_embedding = regions_with_perimeter > 1; - std::unique_ptr current_layer_distancer = std::make_unique(po->layers()[layer_idx]); + std::unique_ptr current_layer_distancer = std::make_unique(to_linesf(po->layers()[layer_idx]->lslices)); for (SeamCandidate &perimeter_point : layers[layer_idx].points) { Vec2f point = Vec2f { perimeter_point.position.head<2>() }; if (prev_layer_distancer.get() != nullptr) { - perimeter_point.overhang = prev_layer_distancer->distance_from_perimeter(point) + perimeter_point.overhang = prev_layer_distancer->signed_distance_from_lines(point.cast()) + 0.6f * perimeter_point.perimeter.flow_width - tan(SeamPlacer::overhang_angle_threshold) * po->layers()[layer_idx]->height; @@ -1120,7 +1079,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) } if (should_compute_layer_embedding) { // search for embedded perimeter points (points hidden inside the print ,e.g. multimaterial join, best position for seam) - perimeter_point.embedded_distance = current_layer_distancer->distance_from_perimeter(point) + perimeter_point.embedded_distance = current_layer_distancer->signed_distance_from_lines(point.cast()) + 0.6f * perimeter_point.perimeter.flow_width; } }