diff --git a/src/libslic3r/Algorithm/PathSorting.hpp b/src/libslic3r/Algorithm/PathSorting.hpp index 7d47eb43aa..758430c679 100644 --- a/src/libslic3r/Algorithm/PathSorting.hpp +++ b/src/libslic3r/Algorithm/PathSorting.hpp @@ -18,8 +18,39 @@ #include #include -namespace Slic3r { -namespace Algorithm { +namespace Slic3r::Algorithm { + +bool is_first_path_touching_second_path(const AABBTreeLines::LinesDistancer &first_distancer, + const AABBTreeLines::LinesDistancer &second_distancer, + const BoundingBox &second_distancer_bbox, + const double touch_distance_threshold) +{ + for (const Line &line : first_distancer.get_lines()) { + if (bbox_point_distance(second_distancer_bbox, line.a) < touch_distance_threshold && second_distancer.distance_from_lines(line.a) < touch_distance_threshold) { + return true; + } + } + + const Point first_distancer_last_pt = first_distancer.get_lines().back().b; + if (bbox_point_distance(second_distancer_bbox, first_distancer_last_pt) && second_distancer.distance_from_lines(first_distancer_last_pt) < touch_distance_threshold) { + return true; + } + + return false; +} + +bool are_paths_touching(const AABBTreeLines::LinesDistancer &first_distancer, const BoundingBox &first_distancer_bbox, + const AABBTreeLines::LinesDistancer &second_distancer, const BoundingBox &second_distancer_bbox, + const double touch_distance_threshold) +{ + if (is_first_path_touching_second_path(first_distancer, second_distancer, second_distancer_bbox, touch_distance_threshold)) { + return true; + } else if (is_first_path_touching_second_path(second_distancer, first_distancer, first_distancer_bbox, touch_distance_threshold)) { + return true; + } + + return false; +} //Sorts the paths such that all paths between begin and last_seed are printed first, in some order. The rest of the paths is sorted // such that the paths that are touching some of the already printed are printed first, sorted secondary by the distance to the last point of the last @@ -28,44 +59,34 @@ namespace Algorithm { // to the second, then they touch. // convert_to_lines is a lambda that should accept the path as argument and return it as Lines vector, in correct order. template -void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point start, double touch_limit_distance, ToLines convert_to_lines) +void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point start, const double touch_distance_threshold, ToLines convert_to_lines) { - size_t paths_count = std::distance(begin, end); + const size_t paths_count = std::distance(begin, end); if (paths_count <= 1) return; - auto paths_touch = [touch_limit_distance](const AABBTreeLines::LinesDistancer &left, - const AABBTreeLines::LinesDistancer &right) { - for (const Line &l : left.get_lines()) { - if (right.distance_from_lines(l.a) < touch_limit_distance) { - return true; - } - } - if (right.distance_from_lines(left.get_lines().back().b) < touch_limit_distance) { - return true; - } - - for (const Line &l : right.get_lines()) { - if (left.distance_from_lines(l.a) < touch_limit_distance) { - return true; - } - } - if (left.distance_from_lines(right.get_lines().back().b) < touch_limit_distance) { - return true; - } - return false; - }; - std::vector> distancers(paths_count); for (size_t path_idx = 0; path_idx < paths_count; path_idx++) { distancers[path_idx] = AABBTreeLines::LinesDistancer{convert_to_lines(*std::next(begin, path_idx))}; } + BoundingBoxes bboxes; + bboxes.reserve(paths_count); + for (auto tp_it = begin; tp_it != end; ++tp_it) { + bboxes.emplace_back(tp_it->bounding_box()); + } + std::vector> dependencies(paths_count); - for (size_t path_idx = 0; path_idx < paths_count; path_idx++) { - for (size_t next_path_idx = path_idx + 1; next_path_idx < paths_count; next_path_idx++) { - if (paths_touch(distancers[path_idx], distancers[next_path_idx])) { - dependencies[next_path_idx].insert(path_idx); + for (size_t curr_path_idx = 0; curr_path_idx < paths_count; ++curr_path_idx) { + for (size_t next_path_idx = curr_path_idx + 1; next_path_idx < paths_count; ++next_path_idx) { + const BoundingBox &curr_path_bbox = bboxes[curr_path_idx]; + const BoundingBox &next_path_bbox = bboxes[next_path_idx]; + + if (bbox_bbox_distance(curr_path_bbox, next_path_bbox) >= touch_distance_threshold) + continue; + + if (are_paths_touching(distancers[curr_path_idx], curr_path_bbox, distancers[next_path_idx], next_path_bbox, touch_distance_threshold)) { + dependencies[next_path_idx].insert(curr_path_idx); } } } @@ -127,6 +148,6 @@ void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point star } } -}} // namespace Slic3r::Algorithm +} // namespace Slic3r::Algorithm #endif /*SRC_LIBSLIC3R_PATH_SORTING_HPP_*/ diff --git a/src/libslic3r/BoundingBox.hpp b/src/libslic3r/BoundingBox.hpp index 0b52e28738..a8e27b99d5 100644 --- a/src/libslic3r/BoundingBox.hpp +++ b/src/libslic3r/BoundingBox.hpp @@ -328,6 +328,23 @@ inline double bbox_point_distance_squared(const BoundingBox &bbox, const Point & coord_t(0)); } +// Minimum distance between two Bounding boxes. +// Returns zero when Bounding boxes overlap. +inline double bbox_bbox_distance(const BoundingBox &first_bbox, const BoundingBox &second_bbox) { + if (first_bbox.overlap(second_bbox)) + return 0.; + + double bboxes_distance_squared = 0.; + + for (size_t axis = 0; axis < 2; ++axis) { + const coord_t axis_distance = std::max(std::max(0, first_bbox.min[axis] - second_bbox.max[axis]), + second_bbox.min[axis] - first_bbox.max[axis]); + bboxes_distance_squared += Slic3r::sqr(static_cast(axis_distance)); + } + + return std::sqrt(bboxes_distance_squared); +} + template BoundingBoxBase> to_2d(const BoundingBox3Base> &bb) { diff --git a/src/libslic3r/Polyline.cpp b/src/libslic3r/Polyline.cpp index 92878c34ac..dbf4838f78 100644 --- a/src/libslic3r/Polyline.cpp +++ b/src/libslic3r/Polyline.cpp @@ -201,6 +201,10 @@ bool Polyline::is_straight() const return true; } +BoundingBox ThickPolyline::bounding_box() const { + return BoundingBox(this->points); +} + BoundingBox get_extents(const Polyline &polyline) { return polyline.bounding_box(); @@ -335,6 +339,22 @@ Lines to_lines(const ThickPolylines &thick_polylines) { return lines; } +BoundingBox get_extents(const ThickPolyline &thick_polyline) { + return thick_polyline.bounding_box(); +} + +BoundingBox get_extents(const ThickPolylines &thick_polylines) { + BoundingBox bbox; + if (!thick_polylines.empty()) { + bbox = thick_polylines.front().bounding_box(); + for (size_t i = 1; i < thick_polylines.size(); ++i) { + bbox.merge(thick_polylines[i].points); + } + } + + return bbox; +} + ThickLines ThickPolyline::thicklines() const { ThickLines lines; diff --git a/src/libslic3r/Polyline.hpp b/src/libslic3r/Polyline.hpp index 0f928328a7..ec13b8e2c3 100644 --- a/src/libslic3r/Polyline.hpp +++ b/src/libslic3r/Polyline.hpp @@ -241,6 +241,8 @@ struct ThickPolyline { // On open ThickPolyline make no effect. void start_at_index(int index); + BoundingBox bounding_box() const; + Points points; // vector of startpoint width and endpoint width of each line segment. The size should be always (points.size()-1) * 2 // e.g. let four be points a,b,c,d. that are three lines ab, bc, cd. for each line, there should be start width, so the width vector is: @@ -266,6 +268,9 @@ size_t total_lines_count(const ThickPolylines &thick_polylines); Lines to_lines(const ThickPolyline &thick_polyline); Lines to_lines(const ThickPolylines &thick_polylines); +BoundingBox get_extents(const ThickPolyline &thick_polyline); +BoundingBox get_extents(const ThickPolylines &thick_polylines); + class Polyline3 : public MultiPoint3 { public: