SPE-1950: Optimization of extrusion sorting for the ensuring infill.

This commit is contained in:
Lukáš Hejl 2024-07-08 14:21:07 +02:00 committed by Lukas Matena
parent b3510ac808
commit 82fb648cb7
4 changed files with 94 additions and 31 deletions

View File

@ -18,8 +18,39 @@
#include <type_traits>
#include <unordered_set>
namespace Slic3r {
namespace Algorithm {
namespace Slic3r::Algorithm {
bool is_first_path_touching_second_path(const AABBTreeLines::LinesDistancer<Line> &first_distancer,
const AABBTreeLines::LinesDistancer<Line> &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<false>(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<false>(first_distancer_last_pt) < touch_distance_threshold) {
return true;
}
return false;
}
bool are_paths_touching(const AABBTreeLines::LinesDistancer<Line> &first_distancer, const BoundingBox &first_distancer_bbox,
const AABBTreeLines::LinesDistancer<Line> &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<typename RandomAccessIterator, typename ToLines>
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<Line> &left,
const AABBTreeLines::LinesDistancer<Line> &right) {
for (const Line &l : left.get_lines()) {
if (right.distance_from_lines<false>(l.a) < touch_limit_distance) {
return true;
}
}
if (right.distance_from_lines<false>(left.get_lines().back().b) < touch_limit_distance) {
return true;
}
for (const Line &l : right.get_lines()) {
if (left.distance_from_lines<false>(l.a) < touch_limit_distance) {
return true;
}
}
if (left.distance_from_lines<false>(right.get_lines().back().b) < touch_limit_distance) {
return true;
}
return false;
};
std::vector<AABBTreeLines::LinesDistancer<Line>> distancers(paths_count);
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
distancers[path_idx] = AABBTreeLines::LinesDistancer<Line>{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<std::unordered_set<size_t>> 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_*/

View File

@ -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<double>(axis_distance));
}
return std::sqrt(bboxes_distance_squared);
}
template<class T>
BoundingBoxBase<Vec<2, T>> to_2d(const BoundingBox3Base<Vec<3, T>> &bb)
{

View File

@ -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;

View File

@ -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: