Fix path sorting
This commit is contained in:
parent
ebbbb1505c
commit
aa85d050fe
3 changed files with 118 additions and 142 deletions
|
@ -2,12 +2,15 @@
|
||||||
#define SRC_LIBSLIC3R_PATH_SORTING_HPP_
|
#define SRC_LIBSLIC3R_PATH_SORTING_HPP_
|
||||||
|
|
||||||
#include "AABBTreeLines.hpp"
|
#include "AABBTreeLines.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
|
#include "Line.hpp"
|
||||||
#include "ankerl/unordered_dense.h"
|
#include "ankerl/unordered_dense.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <libslic3r/Point.hpp>
|
#include <libslic3r/Point.hpp>
|
||||||
#include <libslic3r/Polygon.hpp>
|
#include <libslic3r/Polygon.hpp>
|
||||||
#include <libslic3r/ExPolygon.hpp>
|
#include <libslic3r/ExPolygon.hpp>
|
||||||
|
#include <limits>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <unordered_set>
|
||||||
|
|
||||||
|
@ -21,154 +24,122 @@ namespace Algorithm {
|
||||||
// to the second, then they touch.
|
// 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.
|
// 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>
|
template<typename RandomAccessIterator, typename ToLines>
|
||||||
void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, RandomAccessIterator last_seed, double touch_limit_distance, ToLines convert_to_lines)
|
void sort_paths(RandomAccessIterator begin, RandomAccessIterator end, Point start, double touch_limit_distance, ToLines convert_to_lines)
|
||||||
{
|
{
|
||||||
size_t paths_count = std::distance(begin, end);
|
size_t paths_count = std::distance(begin, end);
|
||||||
if (paths_count <= 1)
|
if (paths_count <= 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
auto paths_min_distance = [](const AABBTreeLines::LinesDistancer<Line> &left, const AABBTreeLines::LinesDistancer<Line> &right) {
|
||||||
|
double min_distance = std::numeric_limits<double>::max();
|
||||||
|
for (const Line &l : left.get_lines()) {
|
||||||
|
if (double dist = right.distance_from_lines<false>(l.a); dist < min_distance) {
|
||||||
|
min_distance = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (double dist = right.distance_from_lines<false>(left.get_lines().back().b); dist < min_distance) {
|
||||||
|
min_distance = dist;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const Line &l : right.get_lines()) {
|
||||||
|
if (double dist = left.distance_from_lines<false>(l.a); dist < min_distance) {
|
||||||
|
min_distance = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (double dist = left.distance_from_lines<false>(right.get_lines().back().b); dist < min_distance) {
|
||||||
|
min_distance = dist;
|
||||||
|
}
|
||||||
|
return min_distance;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<AABBTreeLines::LinesDistancer<Line>> distancers(paths_count);
|
std::vector<AABBTreeLines::LinesDistancer<Line>> distancers(paths_count);
|
||||||
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
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))};
|
distancers[path_idx] = AABBTreeLines::LinesDistancer<Line>{convert_to_lines(*std::next(begin, path_idx))};
|
||||||
}
|
}
|
||||||
|
|
||||||
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<std::unordered_set<size_t>> dependencies(paths_count);
|
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 path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
for (size_t prev_path_idx = 0; prev_path_idx < path_idx; prev_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[prev_path_idx])) {
|
double dist = paths_min_distance(distancers[path_idx], distancers[next_path_idx]);
|
||||||
dependencies[path_idx].insert(prev_path_idx);
|
if (dist < touch_limit_distance) {
|
||||||
dependencies[prev_path_idx].insert(path_idx);
|
dependencies[next_path_idx].insert(path_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index_of_last_fixed = std::distance(begin, last_seed);
|
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
|
std::cout << "Dependencies of " << path_idx << " are ";
|
||||||
std::vector<bool> processed(paths_count, false);
|
for (size_t dep : dependencies[path_idx])
|
||||||
for (size_t path_idx = 0; path_idx <= index_of_last_fixed; path_idx++) {
|
std::cout << dep << ", ";
|
||||||
processed[path_idx] = true;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = index_of_last_fixed + 1; i < paths_count; i++) {
|
Point current_point = start;
|
||||||
bool change = false;
|
|
||||||
for (size_t path_idx = index_of_last_fixed + 1; path_idx < paths_count; path_idx++) {
|
std::vector<std::pair<size_t, bool>> correct_order_and_direction(paths_count);
|
||||||
if (processed[path_idx])
|
size_t unsorted_idx = 0;
|
||||||
|
size_t null_idx = size_t(-1);
|
||||||
|
size_t next_idx = null_idx;
|
||||||
|
bool reverse = false;
|
||||||
|
while (unsorted_idx < paths_count) {
|
||||||
|
next_idx = null_idx;
|
||||||
|
double lines_dist = std::numeric_limits<double>::max();
|
||||||
|
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
|
if (!dependencies[path_idx].empty())
|
||||||
continue;
|
continue;
|
||||||
auto processed_dep = std::find_if(dependencies[path_idx].begin(), dependencies[path_idx].end(),
|
|
||||||
[&](size_t dep) { return processed[dep]; });
|
double ldist = distancers[path_idx].distance_from_lines<false>(current_point);
|
||||||
if (processed_dep != dependencies[path_idx].end()) {
|
if (ldist < lines_dist) {
|
||||||
for (auto it = dependencies[path_idx].begin(); it != dependencies[path_idx].end();) {
|
const auto &lines = distancers[path_idx].get_lines();
|
||||||
if (!processed[*it]) {
|
double dist_a = line_alg::distance_to(lines.front(), current_point);
|
||||||
dependencies[*it].insert(path_idx);
|
double dist_b = line_alg::distance_to(lines.back(), current_point);
|
||||||
dependencies[path_idx].erase(it++);
|
if (std::abs(dist_a - dist_b) < touch_limit_distance) {
|
||||||
} else {
|
dist_a = (lines.front().a - current_point).squaredNorm();
|
||||||
++it;
|
dist_b = (lines.back().b - current_point).squaredNorm();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
processed[path_idx] = true;
|
next_idx = path_idx;
|
||||||
change = true;
|
reverse = dist_b < dist_a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!change) {
|
|
||||||
|
// we have valid next_idx, sort it, update dependencies, update current point
|
||||||
|
correct_order_and_direction[next_idx] = {unsorted_idx, reverse};
|
||||||
|
unsorted_idx++;
|
||||||
|
current_point = reverse ? distancers[next_idx].get_lines().front().a : distancers[next_idx].get_lines().back().b;
|
||||||
|
|
||||||
|
dependencies[next_idx].insert(null_idx); // prevent it from being selected again
|
||||||
|
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
|
dependencies[path_idx].erase(next_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "Final order is ";
|
||||||
|
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
|
std::cout << correct_order_and_direction[path_idx].first << ", ";
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
||||||
|
if (correct_order_and_direction[path_idx].second) {
|
||||||
|
std::next(begin, path_idx)->reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < correct_order_and_direction.size() - 1; i++) {
|
||||||
|
bool swapped = false;
|
||||||
|
for (size_t j = 0; j < correct_order_and_direction.size() - i - 1; j++) {
|
||||||
|
if (correct_order_and_direction[j].first > correct_order_and_direction[j + 1].first) {
|
||||||
|
std::swap(correct_order_and_direction[j], correct_order_and_direction[j + 1]);
|
||||||
|
std::iter_swap(std::next(begin, j), std::next(begin, j + 1));
|
||||||
|
swapped = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (swapped == false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Point current_point = distancers.begin()->get_lines().begin()->a;
|
|
||||||
|
|
||||||
size_t null_idx = size_t(-1);
|
|
||||||
size_t unsorted_idx = 0;
|
|
||||||
size_t next_idx = null_idx;
|
|
||||||
bool reverse = false;
|
|
||||||
while (true) {
|
|
||||||
if (next_idx == null_idx) { // find next pidx to print
|
|
||||||
double dist = std::numeric_limits<double>::max();
|
|
||||||
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
|
||||||
if (!dependencies[path_idx].empty())
|
|
||||||
continue;
|
|
||||||
const auto& lines = distancers[path_idx].get_lines();
|
|
||||||
double dist_a = (lines.front().a - current_point).cast<double>().squaredNorm();
|
|
||||||
if (dist_a < dist) {
|
|
||||||
dist = dist_a;
|
|
||||||
next_idx = path_idx;
|
|
||||||
reverse = false;
|
|
||||||
}
|
|
||||||
double dist_b = (lines.back().b - current_point).cast<double>().squaredNorm();
|
|
||||||
if (dist_b < dist) {
|
|
||||||
dist = dist_b;
|
|
||||||
next_idx = path_idx;
|
|
||||||
reverse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (next_idx == null_idx) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// we have valid next_idx, sort it, update dependencies, update current point and potentialy set new next_idx
|
|
||||||
std::iter_swap(std::next(begin, unsorted_idx), std::next(begin, next_idx)); // next_path is now at sorted spot
|
|
||||||
if (reverse) {
|
|
||||||
std::next(begin, unsorted_idx)->reverse();
|
|
||||||
}
|
|
||||||
unsorted_idx++;
|
|
||||||
|
|
||||||
assert(dependencies[next_idx].empty());
|
|
||||||
dependencies[next_idx].insert(null_idx);
|
|
||||||
current_point = reverse ? distancers[next_idx].get_lines().front().a : distancers[next_idx].get_lines().back().b;
|
|
||||||
for (size_t path_idx = 0; path_idx < paths_count; path_idx++) {
|
|
||||||
dependencies[path_idx].erase(next_idx);
|
|
||||||
}
|
|
||||||
double dist = std::numeric_limits<double>::max();
|
|
||||||
next_idx = null_idx;
|
|
||||||
|
|
||||||
for (size_t path_idx = next_idx + 1; path_idx < paths_count; path_idx++) {
|
|
||||||
if (!dependencies[path_idx].empty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto &lines = distancers[path_idx].get_lines();
|
|
||||||
double dist_a = (lines.front().a - current_point).cast<double>().squaredNorm();
|
|
||||||
if (dist_a < dist) {
|
|
||||||
dist = dist_a;
|
|
||||||
next_idx = path_idx;
|
|
||||||
reverse = false;
|
|
||||||
}
|
|
||||||
double dist_b = (lines.back().b - current_point).cast<double>().squaredNorm();
|
|
||||||
if (dist_b < dist) {
|
|
||||||
dist = dist_b;
|
|
||||||
next_idx = path_idx;
|
|
||||||
reverse = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (dist > scaled(5.0)) {
|
|
||||||
next_idx = null_idx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}} // namespace Slic3r::Algorithm
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /*SRC_LIBSLIC3R_PATH_SORTING_HPP_*/
|
#endif /*SRC_LIBSLIC3R_PATH_SORTING_HPP_*/
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include "AABBTreeLines.hpp"
|
#include "AABBTreeLines.hpp"
|
||||||
#include "Algorithm/PathSorting.hpp"
|
#include "Algorithm/PathSorting.hpp"
|
||||||
|
#include "BoundingBox.hpp"
|
||||||
#include "ExPolygon.hpp"
|
#include "ExPolygon.hpp"
|
||||||
#include "FillEnsuring.hpp"
|
#include "FillEnsuring.hpp"
|
||||||
#include "KDTreeIndirect.hpp"
|
#include "KDTreeIndirect.hpp"
|
||||||
|
@ -322,14 +323,14 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
|
||||||
}
|
}
|
||||||
// gaps_for_additional_filling = opening_ex(gaps_for_additional_filling, 0.3 * scaled_spacing);
|
// gaps_for_additional_filling = opening_ex(gaps_for_additional_filling, 0.3 * scaled_spacing);
|
||||||
|
|
||||||
// BoundingBox bbox = get_extents(filled_area);
|
BoundingBox bbox = get_extents(filled_area);
|
||||||
// bbox.offset(scale_(1.));
|
bbox.offset(scale_(1.));
|
||||||
// ::Slic3r::SVG svg(debug_out_path(("surface" + std::to_string(surface->area())).c_str()).c_str(), bbox);
|
::Slic3r::SVG svg(debug_out_path(("surface" + std::to_string(surface->area())).c_str()).c_str(), bbox);
|
||||||
// svg.draw(to_lines(filled_area), "red", scale_(0.4));
|
svg.draw(to_lines(filled_area), "red", scale_(0.4));
|
||||||
// svg.draw(to_lines(reconstructed_area), "blue", scale_(0.3));
|
svg.draw(to_lines(reconstructed_area), "blue", scale_(0.3));
|
||||||
// svg.draw(to_lines(gaps_for_additional_filling), "green", scale_(0.2));
|
svg.draw(to_lines(gaps_for_additional_filling), "green", scale_(0.2));
|
||||||
// svg.draw(vertical_lines, "black", scale_(0.1));
|
svg.draw(vertical_lines, "black", scale_(0.1));
|
||||||
// svg.Close();
|
svg.Close();
|
||||||
|
|
||||||
for (ExPolygon &ex_poly : gaps_for_additional_filling) {
|
for (ExPolygon &ex_poly : gaps_for_additional_filling) {
|
||||||
Point bbox_size = ex_poly.contour.bounding_box().size();
|
Point bbox_size = ex_poly.contour.bounding_box().size();
|
||||||
|
@ -447,8 +448,6 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate_thick_polylines(thick_polylines_out, cos(-aligning_angle), sin(-aligning_angle));
|
|
||||||
|
|
||||||
thick_polylines_out.erase(std::remove_if(thick_polylines_out.begin(), thick_polylines_out.end(),
|
thick_polylines_out.erase(std::remove_if(thick_polylines_out.begin(), thick_polylines_out.end(),
|
||||||
[scaled_spacing](const ThickPolyline &tp) {
|
[scaled_spacing](const ThickPolyline &tp) {
|
||||||
return tp.length() < scaled_spacing &&
|
return tp.length() < scaled_spacing &&
|
||||||
|
@ -457,17 +456,22 @@ ThickPolylines FillEnsuring::fill_surface_arachne(const Surface *surface, const
|
||||||
}),
|
}),
|
||||||
thick_polylines_out.end());
|
thick_polylines_out.end());
|
||||||
|
|
||||||
Algorithm::sort_paths(thick_polylines_out.begin(), thick_polylines_out.end(), thick_polylines_out.begin(), scaled_spacing * 2,
|
std::sort(thick_polylines_out.begin(), thick_polylines_out.end(), [](const ThickPolyline &left, const ThickPolyline &right) {
|
||||||
[](const ThickPolyline &tp) {
|
return BoundingBox(left.points).min.x() < BoundingBox(right.points).min.x();
|
||||||
Lines ls;
|
});
|
||||||
Point prev = tp.first_point();
|
|
||||||
for (size_t i = 1; i < tp.points.size(); i++) {
|
|
||||||
ls.emplace_back(prev, tp.points[i]);
|
|
||||||
prev = ls.back().b;
|
|
||||||
}
|
|
||||||
return ls;
|
|
||||||
});
|
|
||||||
|
|
||||||
|
Algorithm::sort_paths(thick_polylines_out.begin(), thick_polylines_out.end(), bb.min, scaled_spacing * 1.2, [](const ThickPolyline
|
||||||
|
&tp) {
|
||||||
|
Lines ls;
|
||||||
|
Point prev = tp.first_point();
|
||||||
|
for (size_t i = 1; i < tp.points.size(); i++) {
|
||||||
|
ls.emplace_back(prev, tp.points[i]);
|
||||||
|
prev = ls.back().b;
|
||||||
|
}
|
||||||
|
return ls;
|
||||||
|
});
|
||||||
|
|
||||||
|
rotate_thick_polylines(thick_polylines_out, cos(-aligning_angle), sin(-aligning_angle));
|
||||||
return thick_polylines_out;
|
return thick_polylines_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue