Improve Lines Distancer quality, use it also in SeamPlacer

This commit is contained in:
Pavel Mikus 2022-10-04 19:27:15 +02:00
parent 20bd7f9a26
commit b49a2425ca
3 changed files with 47 additions and 49 deletions

View File

@ -1,6 +1,8 @@
#ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_ #ifndef SRC_LIBSLIC3R_AABBTREELINES_HPP_
#define SRC_LIBSLIC3R_AABBTREELINES_HPP_ #define SRC_LIBSLIC3R_AABBTREELINES_HPP_
#include "Utils.hpp"
#include "libslic3r.h"
#include "libslic3r/AABBTreeIndirect.hpp" #include "libslic3r/AABBTreeIndirect.hpp"
#include "libslic3r/Line.hpp" #include "libslic3r/Line.hpp"
#include <type_traits> #include <type_traits>
@ -127,12 +129,26 @@ public:
auto distance = AABBTreeLines::squared_distance_to_indexed_lines(lines, tree, p, nearest_line_index_out, nearest_point_out); 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<Floating>::infinity(), nearest_line_index_out, nearest_point_out}; } if (distance < 0) { return {std::numeric_limits<Floating>::infinity(), nearest_line_index_out, nearest_point_out}; }
distance = sqrt(distance); distance = sqrt(distance);
const LineType &line = lines[nearest_line_index_out]; const LineType &line = lines[nearest_line_index_out];
Vec<2, Floating> v1 = (line.b - line.a).template cast<Floating>(); Vec<2, Floating> v1 = (line.b - line.a).template cast<Floating>();
Vec<2, Floating> v2 = (point - line.a).template cast<Floating>(); Vec<2, Floating> v2 = (point - line.a).template cast<Floating>();
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<Floating>() - 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<Floating>();
v2 = (point - second_line.a).template cast<Floating>();
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}; return {distance, nearest_line_index_out, nearest_point_out};
} }

View File

@ -1,6 +1,7 @@
#ifndef slic3r_ExPolygon_hpp_ #ifndef slic3r_ExPolygon_hpp_
#define slic3r_ExPolygon_hpp_ #define slic3r_ExPolygon_hpp_
#include "Point.hpp"
#include "libslic3r.h" #include "libslic3r.h"
#include "Polygon.hpp" #include "Polygon.hpp"
#include "Polyline.hpp" #include "Polyline.hpp"
@ -124,6 +125,28 @@ inline Lines to_lines(const ExPolygons &src)
return lines; return lines;
} }
inline std::vector<Linef> 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<Linef> 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) inline Polylines to_polylines(const ExPolygon &src)
{ {
Polylines polylines; Polylines polylines;

View File

@ -1,6 +1,7 @@
#include "SeamPlacer.hpp" #include "SeamPlacer.hpp"
#include "Color.hpp" #include "Color.hpp"
#include "Polygon.hpp"
#include "PrintConfig.hpp" #include "PrintConfig.hpp"
#include "tbb/parallel_for.h" #include "tbb/parallel_for.h"
#include "tbb/blocked_range.h" #include "tbb/blocked_range.h"
@ -995,49 +996,6 @@ void pick_random_seam_point(const std::vector<SeamCandidate> &perimeter_points,
perimeter.finalized = true; perimeter.finalized = true;
} }
class PerimeterDistancer {
std::vector<Linef> 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<double>();
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<float>::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 } // namespace SeamPlacerImpl
// Parallel process and extract each perimeter polygon of the given print object. // 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) { void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) {
using namespace SeamPlacerImpl; using namespace SeamPlacerImpl;
using PerimeterDistancer = AABBTreeLines::LinesDistancer<Linef>;
std::vector<PrintObjectSeamData::LayerSeams> &layers = m_seam_per_object[po].layers; std::vector<PrintObjectSeamData::LayerSeams> &layers = m_seam_per_object[po].layers;
tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()), tbb::parallel_for(tbb::blocked_range<size_t>(0, layers.size()),
[po, &layers](tbb::blocked_range<size_t> r) { [po, &layers](tbb::blocked_range<size_t> r) {
std::unique_ptr<PerimeterDistancer> prev_layer_distancer; std::unique_ptr<PerimeterDistancer> prev_layer_distancer;
if (r.begin() > 0) { // previous layer exists if (r.begin() > 0) { // previous layer exists
prev_layer_distancer = std::make_unique<PerimeterDistancer>(po->layers()[r.begin() - 1]); prev_layer_distancer = std::make_unique<PerimeterDistancer>(to_linesf(po->layers()[r.begin() - 1]->lslices));
} }
for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { 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; bool should_compute_layer_embedding = regions_with_perimeter > 1;
std::unique_ptr<PerimeterDistancer> current_layer_distancer = std::make_unique<PerimeterDistancer>(po->layers()[layer_idx]); std::unique_ptr<PerimeterDistancer> current_layer_distancer = std::make_unique<PerimeterDistancer>(to_linesf(po->layers()[layer_idx]->lslices));
for (SeamCandidate &perimeter_point : layers[layer_idx].points) { for (SeamCandidate &perimeter_point : layers[layer_idx].points) {
Vec2f point = Vec2f { perimeter_point.position.head<2>() }; Vec2f point = Vec2f { perimeter_point.position.head<2>() };
if (prev_layer_distancer.get() != nullptr) { 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<double>())
+ 0.6f * perimeter_point.perimeter.flow_width + 0.6f * perimeter_point.perimeter.flow_width
- tan(SeamPlacer::overhang_angle_threshold) - tan(SeamPlacer::overhang_angle_threshold)
* po->layers()[layer_idx]->height; * 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) 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<double>())
+ 0.6f * perimeter_point.perimeter.flow_width; + 0.6f * perimeter_point.perimeter.flow_width;
} }
} }