use new extrusion quality estimator function in support spot generator; fix issue with local support points and incorrect distance sign;
This commit is contained in:
parent
0b655e4b60
commit
72a25e7ad0
6 changed files with 171 additions and 126 deletions
|
@ -117,18 +117,18 @@ inline std::tuple<int, int> coordinate_aligned_ray_hit_count(size_t
|
|||
}
|
||||
|
||||
template<typename LineType, typename TreeType, typename VectorType>
|
||||
inline std::vector<VectorType> get_intersections_with_line(size_t node_idx,
|
||||
const TreeType &tree,
|
||||
const std::vector<LineType> &lines,
|
||||
const LineType &line,
|
||||
const typename TreeType::BoundingBox &line_bb)
|
||||
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(size_t node_idx,
|
||||
const TreeType &tree,
|
||||
const std::vector<LineType> &lines,
|
||||
const LineType &line,
|
||||
const typename TreeType::BoundingBox &line_bb)
|
||||
{
|
||||
const auto &node = tree.node(node_idx);
|
||||
assert(node.is_valid());
|
||||
if (node.is_leaf()) {
|
||||
VectorType intersection_pt;
|
||||
if (line_alg::intersection(line, lines[node.idx], &intersection_pt)) {
|
||||
return {intersection_pt};
|
||||
return {std::pair<VectorType, size_t>(intersection_pt, node_idx)};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
@ -140,17 +140,17 @@ inline std::vector<VectorType> get_intersections_with_line(size_t
|
|||
assert(node_left.is_valid());
|
||||
assert(node_right.is_valid());
|
||||
|
||||
std::vector<VectorType> result;
|
||||
std::vector<std::pair<VectorType, size_t>> result;
|
||||
|
||||
if (node_left.bbox.intersects(line_bb)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(left_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
if (node_right.bbox.intersects(line_bb)) {
|
||||
std::vector<VectorType> intersections = get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines,
|
||||
line, line_bb);
|
||||
std::vector<std::pair<VectorType, size_t>> intersections =
|
||||
get_intersections_with_line<LineType, TreeType, VectorType>(right_node_idx, tree, lines, line, line_bb);
|
||||
result.insert(result.end(), intersections.begin(), intersections.end());
|
||||
}
|
||||
|
||||
|
@ -263,9 +263,13 @@ inline int point_outside_closed_contours(const std::vector<LineType> &lines, con
|
|||
}
|
||||
|
||||
template<bool sorted, typename VectorType, typename LineType, typename TreeType>
|
||||
inline std::vector<VectorType> get_intersections_with_line(const std::vector<LineType> &lines, const TreeType &tree, const LineType &line)
|
||||
inline std::vector<std::pair<VectorType, size_t>> get_intersections_with_line(const std::vector<LineType> &lines,
|
||||
const TreeType &tree,
|
||||
const LineType &line)
|
||||
{
|
||||
if (tree.empty()) { return {}; }
|
||||
if (tree.empty()) {
|
||||
return {};
|
||||
}
|
||||
auto line_bb = typename TreeType::BoundingBox(line.a, line.a);
|
||||
line_bb.extend(line.b);
|
||||
|
||||
|
@ -274,15 +278,16 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
|||
using Floating =
|
||||
typename std::conditional<std::is_floating_point<typename LineType::Scalar>::value, typename LineType::Scalar, double>::type;
|
||||
|
||||
std::vector<std::pair<Floating, VectorType>> points_with_sq_distance{};
|
||||
for (const VectorType &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
std::vector<std::pair<Floating, std::pair<VectorType, size_t>>> points_with_sq_distance{};
|
||||
for (const auto &p : intersections) {
|
||||
points_with_sq_distance.emplace_back((p.first - line.a).template cast<Floating>().squaredNorm(), p);
|
||||
}
|
||||
std::sort(points_with_sq_distance.begin(), points_with_sq_distance.end(),
|
||||
[](const std::pair<Floating, VectorType> &left, std::pair<Floating, VectorType> &right) {
|
||||
return left.first < right.first;
|
||||
});
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) { intersections[i] = points_with_sq_distance[i].second; }
|
||||
[](const std::pair<Floating, std::pair<VectorType, size_t>> &left,
|
||||
std::pair<Floating, std::pair<VectorType, size_t>> &right) { return left.first < right.first; });
|
||||
for (size_t i = 0; i < points_with_sq_distance.size(); i++) {
|
||||
intersections[i] = points_with_sq_distance[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
return intersections;
|
||||
|
@ -290,10 +295,11 @@ inline std::vector<VectorType> get_intersections_with_line(const std::vector<Lin
|
|||
|
||||
template<typename LineType> class LinesDistancer
|
||||
{
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
public:
|
||||
using Scalar = typename LineType::Scalar;
|
||||
using Floating = typename std::conditional<std::is_floating_point<Scalar>::value, Scalar, double>::type;
|
||||
private:
|
||||
std::vector<LineType> lines;
|
||||
AABBTreeIndirect::Tree<2, Scalar> tree;
|
||||
|
||||
public:
|
||||
|
@ -313,23 +319,29 @@ public:
|
|||
int outside(const Vec<2, Scalar> &point) const { return point_outside_closed_contours(lines, tree, point); }
|
||||
|
||||
// negative sign means inside
|
||||
std::tuple<Floating, size_t, Vec<2, Floating>> signed_distance_from_lines_extra(const Vec<2, Scalar> &point) const
|
||||
template<bool SIGNED_DISTANCE>
|
||||
std::tuple<Floating, size_t, Vec<2, Floating>> distance_from_lines_extra(const Vec<2, Scalar> &point) const
|
||||
{
|
||||
size_t nearest_line_index_out = size_t(-1);
|
||||
Vec<2, Floating> nearest_point_out = Vec<2, Floating>::Zero();
|
||||
Vec<2, Floating> p = point.template cast<Floating>();
|
||||
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 *= outside(point);
|
||||
|
||||
if (SIGNED_DISTANCE) {
|
||||
distance *= outside(point);
|
||||
}
|
||||
|
||||
return {distance, nearest_line_index_out, nearest_point_out};
|
||||
}
|
||||
|
||||
Floating signed_distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const
|
||||
template<bool SIGNED_DISTANCE> Floating distance_from_lines(const Vec<2, typename LineType::Scalar> &point) const
|
||||
{
|
||||
auto [dist, idx, np] = signed_distance_from_lines_extra(point);
|
||||
auto [dist, idx, np] = distance_from_lines_extra<SIGNED_DISTANCE>(point);
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
@ -338,7 +350,7 @@ public:
|
|||
return all_lines_in_radius(this->lines, this->tree, point, radius * radius);
|
||||
}
|
||||
|
||||
template<bool sorted> std::vector<Vec<2, Scalar>> intersections_with_line(const LineType &line) const
|
||||
template<bool sorted> std::vector<std::pair<Vec<2, Scalar>, size_t>> intersections_with_line(const LineType &line) const
|
||||
{
|
||||
return get_intersections_with_line<sorted, Vec<2, Scalar>>(lines, tree, line);
|
||||
}
|
||||
|
|
|
@ -39,9 +39,9 @@ public:
|
|||
void add_point(float distance, float angle)
|
||||
{
|
||||
total_distance += distance;
|
||||
total_curvature += std::abs(angle);
|
||||
total_curvature += angle;
|
||||
distances.push_back(distance);
|
||||
angles.push_back(std::abs(angle));
|
||||
angles.push_back(angle);
|
||||
|
||||
while (distances.size() > 1 && total_distance > window_size) {
|
||||
total_distance -= distances.front();
|
||||
|
@ -53,8 +53,6 @@ public:
|
|||
|
||||
float get_curvature() const
|
||||
{
|
||||
if (total_distance < EPSILON) { return 0.0; }
|
||||
|
||||
return total_curvature / window_size;
|
||||
}
|
||||
|
||||
|
@ -70,7 +68,7 @@ public:
|
|||
class CurvatureEstimator
|
||||
{
|
||||
static const size_t sliders_count = 2;
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{1.5}, {3.0}};
|
||||
SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{4.0}, {12.0}};
|
||||
|
||||
public:
|
||||
void add_point(float distance, float angle)
|
||||
|
@ -102,45 +100,69 @@ struct ExtendedPoint
|
|||
float curvature;
|
||||
};
|
||||
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_ONLY, bool CONCAVITY_RESETS_CURVATURE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &extrusion_points,
|
||||
template<bool SCALED_INPUT, bool ADD_INTERSECTIONS, bool PREV_LAYER_BOUNDARY_OFFSET, bool SIGNED_DISTANCE, typename P, typename L>
|
||||
std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P> &input_points,
|
||||
const AABBTreeLines::LinesDistancer<L> &unscaled_prev_layer,
|
||||
float flow_width)
|
||||
float flow_width,
|
||||
float max_line_length = -1.0f)
|
||||
{
|
||||
if (extrusion_points.empty()) return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_ONLY ? 0.5 * flow_width : 0.0f;
|
||||
using AABBScalar = typename AABBTreeLines::LinesDistancer<L>::Scalar;
|
||||
if (input_points.empty())
|
||||
return {};
|
||||
float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f;
|
||||
CurvatureEstimator cestim;
|
||||
float min_malformation_dist = 0.55 * flow_width;
|
||||
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||
|
||||
std::vector<P> extrusion_points;
|
||||
{
|
||||
if (max_line_length <= 0) {
|
||||
extrusion_points = input_points;
|
||||
} else {
|
||||
extrusion_points.reserve(input_points.size() * 2);
|
||||
for (size_t i = 0; i + 1 < input_points.size(); i++) {
|
||||
const P &curr = input_points[i];
|
||||
const P &next = input_points[i + 1];
|
||||
extrusion_points.push_back(curr);
|
||||
auto len = maybe_unscale(next - curr).squaredNorm();
|
||||
double t = sqrt((max_line_length * max_line_length) / len);
|
||||
size_t new_point_count = 1.0 / (t + EPSILON);
|
||||
for (size_t j = 1; j < new_point_count + 1; j++) {
|
||||
extrusion_points.push_back(curr * (1.0 - j * t) + next * (j * t));
|
||||
}
|
||||
}
|
||||
extrusion_points.push_back(input_points.back());
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ExtendedPoint> points;
|
||||
points.reserve(extrusion_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1));
|
||||
auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast<double>(); };
|
||||
|
||||
{
|
||||
ExtendedPoint start_point{maybe_unscale(extrusion_points.front())};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(start_point.position);
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(start_point.position.cast<AABBScalar>());
|
||||
start_point.distance = distance + boundary_offset;
|
||||
start_point.nearest_prev_layer_line = nearest_line;
|
||||
points.push_back(start_point);
|
||||
}
|
||||
for (size_t i = 1; i < extrusion_points.size(); i++) {
|
||||
ExtendedPoint next_point{maybe_unscale(extrusion_points[i])};
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.signed_distance_from_lines_extra(next_point.position);
|
||||
auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(next_point.position.cast<AABBScalar>());
|
||||
next_point.distance = distance + boundary_offset;
|
||||
next_point.nearest_prev_layer_line = nearest_line;
|
||||
|
||||
if (ADD_INTERSECTIONS &&
|
||||
((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) {
|
||||
const ExtendedPoint &prev_point = points.back();
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position, next_point.position});
|
||||
auto intersections = unscaled_prev_layer.template intersections_with_line<true>(L{prev_point.position.cast<AABBScalar>(), next_point.position.cast<AABBScalar>()});
|
||||
for (const auto &intersection : intersections) {
|
||||
points.emplace_back(intersection, boundary_offset);
|
||||
points.emplace_back(intersection.first.template cast<double>(), boundary_offset, intersection.second);
|
||||
}
|
||||
}
|
||||
points.push_back(next_point);
|
||||
}
|
||||
|
||||
if (PREV_LAYER_BOUNDARY_ONLY && ADD_INTERSECTIONS) {
|
||||
if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) {
|
||||
std::vector<ExtendedPoint> new_points;
|
||||
new_points.reserve(points.size() * 2);
|
||||
new_points.push_back(points.front());
|
||||
|
@ -159,12 +181,12 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
|||
|
||||
if (t0 < 1.0) {
|
||||
auto p0 = curr.position + t0 * (next.position - curr.position);
|
||||
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p0);
|
||||
auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p0.cast<AABBScalar>());
|
||||
new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l});
|
||||
}
|
||||
if (t1 > 0.0) {
|
||||
auto p1 = curr.position + t1 * (next.position - curr.position);
|
||||
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.signed_distance_from_lines_extra(p1);
|
||||
auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra<SIGNED_DISTANCE>(p1.cast<AABBScalar>());
|
||||
new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l});
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +216,6 @@ std::vector<ExtendedPoint> estimate_points_properties(const std::vector<P>
|
|||
float distance = (prev.position - a.position).norm();
|
||||
float alfa = angle(a.position - points[prev_point_idx].position, points[next_point_index].position - a.position);
|
||||
cestim.add_point(distance, alfa);
|
||||
if (CONCAVITY_RESETS_CURVATURE && alfa < 0.0) { cestim.reset(); }
|
||||
}
|
||||
|
||||
if (a.distance < min_malformation_dist) { cestim.reset(); }
|
||||
|
@ -244,7 +265,7 @@ public:
|
|||
[](const std::pair<float, float> &a, const std::pair<float, float> &b) { return a.first < b.first; });
|
||||
|
||||
std::vector<ExtendedPoint> extended_points =
|
||||
estimate_points_properties<true, true, true, false>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||
estimate_points_properties<true, true, true, true>(path.polyline.points, prev_layer_boundaries[current_object], path.width);
|
||||
|
||||
std::vector<ProcessedPoint> processed_points;
|
||||
processed_points.reserve(extended_points.size());
|
||||
|
|
|
@ -1071,7 +1071,7 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po)
|
|||
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->signed_distance_from_lines(point.cast<double>())
|
||||
perimeter_point.overhang = prev_layer_distancer->distance_from_lines<true>(point.cast<double>())
|
||||
+ 0.6f * perimeter_point.perimeter.flow_width
|
||||
- tan(SeamPlacer::overhang_angle_threshold)
|
||||
* po->layers()[layer_idx]->height;
|
||||
|
@ -1080,7 +1080,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->signed_distance_from_lines(point.cast<double>())
|
||||
perimeter_point.embedded_distance = current_layer_distancer->distance_from_lines<true>(point.cast<double>())
|
||||
+ 0.6f * perimeter_point.perimeter.flow_width;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -664,11 +664,11 @@ bool paths_touch(const ExtrusionPath &path_one, const ExtrusionPath &path_two, d
|
|||
AABBTreeLines::LinesDistancer<Line> lines_two{path_two.as_polyline().lines()};
|
||||
|
||||
for (size_t pt_idx = 0; pt_idx < path_one.polyline.size(); pt_idx++) {
|
||||
if (std::abs(lines_two.signed_distance_from_lines(path_one.polyline.points[pt_idx])) < limit_distance) { return true; }
|
||||
if (lines_two.distance_from_lines<false>(path_one.polyline.points[pt_idx]) < limit_distance) { return true; }
|
||||
}
|
||||
|
||||
for (size_t pt_idx = 0; pt_idx < path_two.polyline.size(); pt_idx++) {
|
||||
if (std::abs(lines_one.signed_distance_from_lines(path_two.polyline.points[pt_idx])) < limit_distance) { return true; }
|
||||
if (lines_one.distance_from_lines<false>(path_two.polyline.points[pt_idx]) < limit_distance) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "ExPolygon.hpp"
|
||||
#include "ExtrusionEntity.hpp"
|
||||
#include "ExtrusionEntityCollection.hpp"
|
||||
#include "GCode/ExtrusionProcessor.hpp"
|
||||
#include "Line.hpp"
|
||||
#include "Point.hpp"
|
||||
#include "Polygon.hpp"
|
||||
|
@ -13,13 +14,16 @@
|
|||
#include "tbb/blocked_range.h"
|
||||
#include "tbb/blocked_range2d.h"
|
||||
#include "tbb/parallel_reduce.h"
|
||||
#include <algorithm>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <stack>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "AABBTreeLines.hpp"
|
||||
|
@ -41,12 +45,14 @@ namespace Slic3r {
|
|||
class ExtrusionLine
|
||||
{
|
||||
public:
|
||||
ExtrusionLine() : a(Vec2f::Zero()), b(Vec2f::Zero()), len(0.0f), origin_entity(nullptr) {}
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b, const ExtrusionEntity *origin_entity)
|
||||
: a(a), b(b), len((a - b).norm()), origin_entity(origin_entity)
|
||||
ExtrusionLine() : a(Vec2f::Zero()), b(Vec2f::Zero()), origin_entity(nullptr) {}
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b, float len, const ExtrusionEntity *origin_entity)
|
||||
: a(a), b(b), len(len), origin_entity(origin_entity)
|
||||
{}
|
||||
|
||||
float length() { return (a - b).norm(); }
|
||||
ExtrusionLine(const Vec2f &a, const Vec2f &b)
|
||||
: a(a), b(b), len((a-b).norm()), origin_entity(nullptr)
|
||||
{}
|
||||
|
||||
bool is_external_perimeter() const
|
||||
{
|
||||
|
@ -60,7 +66,8 @@ public:
|
|||
const ExtrusionEntity *origin_entity;
|
||||
|
||||
bool support_point_generated = false;
|
||||
float malformation = 0.0f;
|
||||
float form_quality = 1.0f;
|
||||
float curled_up_height = 0.0f;
|
||||
|
||||
static const constexpr int Dim = 2;
|
||||
using Scalar = Vec2f::Scalar;
|
||||
|
@ -205,7 +212,6 @@ std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length
|
|||
Polyline pl = e->as_polyline();
|
||||
std::vector<ExtrusionLine> lines;
|
||||
lines.reserve(pl.points.size() * 1.5f);
|
||||
lines.emplace_back(unscaled(pl.points[0]).cast<float>(), unscaled(pl.points[0]).cast<float>(), e);
|
||||
for (int point_idx = 0; point_idx < int(pl.points.size()) - 1; ++point_idx) {
|
||||
Vec2f start = unscaled(pl.points[point_idx]).cast<float>();
|
||||
Vec2f next = unscaled(pl.points[point_idx + 1]).cast<float>();
|
||||
|
@ -217,87 +223,84 @@ std::vector<ExtrusionLine> to_short_lines(const ExtrusionEntity *e, float length
|
|||
for (int i = 0; i < lines_count; ++i) {
|
||||
Vec2f a(start + v * (i * step_size));
|
||||
Vec2f b(start + v * ((i + 1) * step_size));
|
||||
lines.emplace_back(a, b, e);
|
||||
lines.emplace_back(a, b, (a-b).norm(), e);
|
||||
}
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntity *entity,
|
||||
const LayerRegion *layer_region,
|
||||
const LD &prev_layer_lines,
|
||||
const Params ¶ms)
|
||||
std::vector<ExtrusionLine> check_extrusion_entity_stability(const ExtrusionEntity *entity,
|
||||
const LayerRegion *layer_region,
|
||||
const LD &prev_layer_lines,
|
||||
const AABBTreeLines::LinesDistancer<Linef> &prev_layer_boundary,
|
||||
const Params ¶ms)
|
||||
{
|
||||
if (entity->is_collection()) {
|
||||
std::vector<ExtrusionLine> checked_lines_out;
|
||||
checked_lines_out.reserve(prev_layer_lines.get_lines().size() / 3);
|
||||
for (const auto *e : static_cast<const ExtrusionEntityCollection *>(entity)->entities) {
|
||||
auto tmp = check_extrusion_entity_stability(e, layer_region, prev_layer_lines, params);
|
||||
auto tmp = check_extrusion_entity_stability(e, layer_region, prev_layer_lines, prev_layer_boundary, params);
|
||||
checked_lines_out.insert(checked_lines_out.end(), tmp.begin(), tmp.end());
|
||||
}
|
||||
return checked_lines_out;
|
||||
} else { // single extrusion path, with possible varying parameters
|
||||
if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) { return {}; }
|
||||
|
||||
std::vector<ExtrusionLine> lines = to_short_lines(entity, params.bridge_distance);
|
||||
|
||||
ExtrusionPropertiesAccumulator bridging_acc{};
|
||||
ExtrusionPropertiesAccumulator malformation_acc{};
|
||||
bridging_acc.add_distance(params.bridge_distance + 1.0f);
|
||||
const float flow_width = get_flow_width(layer_region, entity->role());
|
||||
float min_malformation_dist = flow_width - params.malformation_overlap_factor.first * flow_width;
|
||||
float max_malformation_dist = flow_width - params.malformation_overlap_factor.second * flow_width;
|
||||
|
||||
for (size_t line_idx = 0; line_idx < lines.size(); ++line_idx) {
|
||||
ExtrusionLine ¤t_line = lines[line_idx];
|
||||
if (line_idx + 1 == lines.size() && current_line.b != lines.begin()->a) {
|
||||
bridging_acc.add_distance(params.bridge_distance + 1.0f);
|
||||
}
|
||||
float curr_angle = 0;
|
||||
if (line_idx + 1 < lines.size()) {
|
||||
const Vec2f v1 = current_line.b - current_line.a;
|
||||
const Vec2f v2 = lines[line_idx + 1].b - lines[line_idx + 1].a;
|
||||
curr_angle = angle(v1, v2);
|
||||
}
|
||||
bridging_acc.add_angle(curr_angle);
|
||||
// malformation in concave angles does not happen
|
||||
malformation_acc.add_angle(std::max(0.0f, curr_angle));
|
||||
if (curr_angle < -20.0 * PI / 180.0) { malformation_acc.reset(); }
|
||||
std::vector<ExtendedPoint> annotated_points = estimate_points_properties<true, true, false, false>(entity->as_polyline().points,
|
||||
prev_layer_lines, flow_width,
|
||||
params.bridge_distance);
|
||||
|
||||
auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.signed_distance_from_lines_extra(current_line.b);
|
||||
if (dist_from_prev_layer < flow_width) {
|
||||
bridging_acc.reset();
|
||||
} else {
|
||||
bridging_acc.add_distance(current_line.len);
|
||||
std::vector<ExtrusionLine> lines_out;
|
||||
lines_out.reserve(annotated_points.size());
|
||||
float bridged_distance = annotated_points.front().position != annotated_points.back().position ? (params.bridge_distance + 1.0f) :
|
||||
0.0f;
|
||||
for (size_t i = 0; i < annotated_points.size(); ++i) {
|
||||
ExtendedPoint &curr_point = annotated_points[i];
|
||||
float line_len = i > 0 ? ((annotated_points[i - 1].position - curr_point.position).norm()) : 0.0f;
|
||||
ExtrusionLine line_out{i > 0 ? annotated_points[i - 1].position.cast<float>() : curr_point.position.cast<float>(),
|
||||
curr_point.position.cast<float>(), line_len, entity};
|
||||
|
||||
ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ?
|
||||
prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) :
|
||||
ExtrusionLine{};
|
||||
|
||||
float sign = prev_layer_boundary.distance_from_lines<true>(curr_point.position) - 0.5f * flow_width < 0.0f ? -1.0f : 1.0f;
|
||||
curr_point.distance *= sign;
|
||||
|
||||
if (curr_point.distance > 0.9f * flow_width) {
|
||||
line_out.form_quality = 0.7f;
|
||||
bridged_distance += line_len;
|
||||
// if unsupported distance is larger than bridge distance linearly decreased by curvature, enforce supports.
|
||||
bool in_layer_dist_condition = bridging_acc.distance >
|
||||
params.bridge_distance / (1.0f + (bridging_acc.max_curvature *
|
||||
params.bridge_distance_decrease_by_curvature_factor / PI));
|
||||
bool between_layers_condition = dist_from_prev_layer > max_malformation_dist;
|
||||
if (in_layer_dist_condition && between_layers_condition) {
|
||||
current_line.support_point_generated = true;
|
||||
bridging_acc.reset();
|
||||
bool in_layer_dist_condition = bridged_distance >
|
||||
params.bridge_distance / (1.0f + std::abs(curr_point.curvature) *
|
||||
params.bridge_distance_decrease_by_curvature_factor);
|
||||
if (in_layer_dist_condition) {
|
||||
line_out.support_point_generated = true;
|
||||
bridged_distance = 0.0f;
|
||||
}
|
||||
} else if (curr_point.distance > flow_width * (0.8 + std::clamp(curr_point.curvature, -0.2f, 0.2f))) {
|
||||
bridged_distance += line_len;
|
||||
line_out.form_quality = nearest_prev_layer_line.form_quality -
|
||||
std::abs(curr_point.curvature);
|
||||
if (line_out.form_quality < 0) {
|
||||
line_out.support_point_generated = true;
|
||||
line_out.form_quality = 0.7f;
|
||||
}
|
||||
} else {
|
||||
bridged_distance = 0.0f;
|
||||
}
|
||||
|
||||
// malformation propagation from below
|
||||
if (fabs(dist_from_prev_layer) < 2.0f * flow_width) {
|
||||
const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
|
||||
current_line.malformation += 0.85 * nearest_line.malformation;
|
||||
}
|
||||
// current line maformation
|
||||
if (dist_from_prev_layer > min_malformation_dist && dist_from_prev_layer < max_malformation_dist) {
|
||||
float factor = std::abs(dist_from_prev_layer - (max_malformation_dist + min_malformation_dist) * 0.5) /
|
||||
(max_malformation_dist - min_malformation_dist);
|
||||
malformation_acc.add_distance(current_line.len);
|
||||
current_line.malformation += layer_region->layer()->height * factor * (2.0f + 3.0f * (malformation_acc.max_curvature / PI));
|
||||
current_line.malformation = std::min(current_line.malformation,
|
||||
float(layer_region->layer()->height * params.max_malformation_factor));
|
||||
} else {
|
||||
malformation_acc.reset();
|
||||
line_out.curled_up_height = 0.8 * nearest_prev_layer_line.curled_up_height;
|
||||
if (curr_point.distance > 0.6 * flow_width && curr_point.distance < 0.9 * flow_width && curr_point.curvature > 0.0) {
|
||||
line_out.curled_up_height = layer_region->layer()->height * (0.6f + std::min(1.0f, curr_point.curvature));
|
||||
}
|
||||
|
||||
lines_out.push_back(line_out);
|
||||
}
|
||||
return lines;
|
||||
|
||||
return lines_out;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -474,7 +477,7 @@ public:
|
|||
float movement_force = params.max_acceleration * mass;
|
||||
|
||||
float extruder_conflict_force = params.standard_extruder_conflict_force +
|
||||
std::min(extruded_line.malformation, 1.0f) * params.malformations_additive_conflict_extruder_force;
|
||||
std::min(extruded_line.curled_up_height, 1.0f) * params.malformations_additive_conflict_extruder_force;
|
||||
|
||||
// section for bed calculations
|
||||
{
|
||||
|
@ -756,6 +759,15 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
|||
const LayerSlice &slice = layer->lslices_ex.at(slice_idx);
|
||||
ObjectPart &part = active_object_parts.access(prev_slice_idx_to_object_part_mapping[slice_idx]);
|
||||
SliceConnection &weakest_conn = prev_slice_idx_to_weakest_connection[slice_idx];
|
||||
|
||||
std::vector<Linef> boundary_lines;
|
||||
for (const auto &link : slice.overlaps_below) {
|
||||
auto ls = to_unscaled_linesf({layer->lower_layer->lslices[link.slice_idx]});
|
||||
boundary_lines.insert(boundary_lines.end(), ls.begin(), ls.end());
|
||||
}
|
||||
AABBTreeLines::LinesDistancer<Linef> boundary{std::move(boundary_lines)};
|
||||
|
||||
|
||||
std::vector<ExtrusionLine> current_slice_ext_perims_lines{};
|
||||
current_slice_ext_perims_lines.reserve(prev_layer_ext_perim_lines.get_lines().size() / layer->lslices_ex.size());
|
||||
#ifdef DETAILED_DEBUG_LOGS
|
||||
|
@ -791,7 +803,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
|||
const ExtrusionEntity *entity = fill_region->fills().entities[fill_idx];
|
||||
if (entity->role() == erBridgeInfill) {
|
||||
for (const ExtrusionLine &bridge :
|
||||
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines, params)) {
|
||||
check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines,boundary, params)) {
|
||||
if (bridge.support_point_generated) {
|
||||
reckon_new_support_point(create_support_point_position(bridge.b), -EPSILON, Vec2f::Zero());
|
||||
}
|
||||
|
@ -804,7 +816,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
|||
for (const auto &perimeter_idx : island.perimeters) {
|
||||
const ExtrusionEntity *entity = perimeter_region->perimeters().entities[perimeter_idx];
|
||||
std::vector<ExtrusionLine> perims = check_extrusion_entity_stability(entity, perimeter_region,
|
||||
prev_layer_ext_perim_lines, params);
|
||||
prev_layer_ext_perim_lines,boundary, params);
|
||||
for (const ExtrusionLine &perim : perims) {
|
||||
if (perim.support_point_generated) {
|
||||
reckon_new_support_point(create_support_point_position(perim.b), -EPSILON, Vec2f::Zero());
|
||||
|
@ -818,13 +830,13 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms)
|
|||
float unchecked_dist = params.min_distance_between_support_points + 1.0f;
|
||||
|
||||
for (const ExtrusionLine &line : current_slice_ext_perims_lines) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.malformation < 0.3f) || line.len == 0) {
|
||||
if ((unchecked_dist + line.len < params.min_distance_between_support_points && line.curled_up_height < 0.3f) || line.len == 0) {
|
||||
unchecked_dist += line.len;
|
||||
} else {
|
||||
unchecked_dist = line.len;
|
||||
Vec2f pivot_site_search_point = Vec2f(line.b + (line.b - line.a).normalized() * 300.0f);
|
||||
auto [dist, nidx,
|
||||
nearest_point] = current_slice_lines_distancer.signed_distance_from_lines_extra(pivot_site_search_point);
|
||||
nearest_point] = current_slice_lines_distancer.distance_from_lines_extra<false>(pivot_site_search_point);
|
||||
Vec3f support_point = create_support_point_position(nearest_point);
|
||||
auto force = part.is_stable_while_extruding(weakest_conn, line, support_point, bottom_z, params);
|
||||
if (force > 0) { reckon_new_support_point(support_point, force, (line.b - line.a).normalized()); }
|
||||
|
@ -909,25 +921,25 @@ struct LayerCurlingEstimator
|
|||
malformation_acc.add_angle(std::max(0.0f, curr_angle));
|
||||
if (curr_angle < -20.0 * PI / 180.0) { malformation_acc.reset(); }
|
||||
|
||||
auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.signed_distance_from_lines_extra(current_line.b);
|
||||
auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.distance_from_lines_extra<true>(current_line.b);
|
||||
|
||||
if (fabs(dist_from_prev_layer) < 2.0f * flow_width) {
|
||||
const ExtrusionLine &nearest_line = prev_layer_lines.get_line(nearest_line_idx);
|
||||
current_line.malformation += 0.9 * nearest_line.malformation;
|
||||
current_line.curled_up_height += 0.9 * nearest_line.curled_up_height;
|
||||
}
|
||||
if (dist_from_prev_layer > min_malformation_dist && dist_from_prev_layer < max_malformation_dist) {
|
||||
float factor = 0.5f + 0.5f * std::abs(dist_from_prev_layer - (max_malformation_dist + min_malformation_dist) * 0.5) /
|
||||
(max_malformation_dist - min_malformation_dist);
|
||||
malformation_acc.add_distance(current_line.len);
|
||||
current_line.malformation += l->height * factor * (1.5f + 3.0f * (malformation_acc.max_curvature / PI));
|
||||
current_line.malformation = std::min(current_line.malformation, float(l->height * params.max_malformation_factor));
|
||||
current_line.curled_up_height += l->height * factor * (1.5f + 3.0f * (malformation_acc.max_curvature / PI));
|
||||
current_line.curled_up_height = std::min(current_line.curled_up_height, float(l->height * params.max_malformation_factor));
|
||||
} else {
|
||||
malformation_acc.reset();
|
||||
}
|
||||
}
|
||||
|
||||
for (const ExtrusionLine &line : extrusion_lines) {
|
||||
if (line.malformation > 0.3f) { l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); }
|
||||
if (line.curled_up_height > 0.3f) { l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); }
|
||||
}
|
||||
prev_layer_lines = LD(extrusion_lines);
|
||||
}
|
||||
|
@ -955,7 +967,7 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float supports_fl
|
|||
for (int point_idx = 0; point_idx < int(pl.points.size() - 1); ++point_idx) {
|
||||
Vec2f start = unscaled(pl.points[point_idx]).cast<float>();
|
||||
Vec2f next = unscaled(pl.points[point_idx + 1]).cast<float>();
|
||||
ExtrusionLine line{start, next, extrusion};
|
||||
ExtrusionLine line{start, next, (start - next).norm(), extrusion};
|
||||
extrusion_lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ struct Params {
|
|||
|
||||
// the algorithm should use the following units for all computations: distance [mm], mass [g], time [s], force [g*mm/s^2]
|
||||
const float bridge_distance = 12.0f; //mm
|
||||
const float bridge_distance_decrease_by_curvature_factor = 5.0f; // allowed bridge distance = bridge_distance / (1 + this factor * (curvature / PI) )
|
||||
const float bridge_distance_decrease_by_curvature_factor = 10.0f; // allowed bridge distance = bridge_distance / (1 + this factor * curvature )
|
||||
const std::pair<float,float> malformation_overlap_factor = std::pair<float, float> { 0.50, -0.1 };
|
||||
const float max_malformation_factor = 10.0f;
|
||||
|
||||
|
|
Loading…
Reference in a new issue