diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index a1fc00a96..233a05549 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2705,6 +2705,7 @@ std::string GCode::extrude_multi_path(ExtrusionMultiPath multipath, const std::s std::string GCode::extrude_entity(const ExtrusionEntity &entity, const std::string_view description, double speed) { + m_extrusion_quality_estimator.reset_for_next_extrusion(); if (const ExtrusionPath* path = dynamic_cast(&entity)) return this->extrude_path(*path, description, speed); else if (const ExtrusionMultiPath* multipath = dynamic_cast(&entity)) diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index b93e542c0..1bdc67668 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -6,7 +6,10 @@ #include "../libslic3r.h" #include "../ExtrusionEntity.hpp" #include "../Layer.hpp" +#include "../Point.hpp" +#include +#include #include #include #include @@ -42,7 +45,7 @@ public: float get_curvature() const { - if (total_distance <= 0.0) { return 0.0; } + if (total_distance < EPSILON) { return 0.0; } return total_curvature / std::max(total_distance, window_size); } @@ -58,8 +61,8 @@ public: class CurvatureEstimator { - static const size_t sliders_count = 4; - SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0}, {4.0}, {8.0}, {16.0}}; + static const size_t sliders_count = 3; + SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{2.0},{4.0}, {8.0}}; public: void add_point(float distance, float angle) @@ -83,8 +86,11 @@ class ExtrusionQualityEstimator { AABBTreeLines::LinesDistancer prev_layer_boundary; AABBTreeLines::LinesDistancer next_layer_boundary; + CurvatureEstimator cestim; public: + void reset_for_next_extrusion() { cestim.reset(); } + void prepare_for_new_layer(const std::vector &layers) { std::vector layer_lines; @@ -102,7 +108,7 @@ public: float flow_width = path.width; float min_malformation_dist = 0.0 * flow_width; float max_malformation_dist = 1.1 * flow_width; - float worst_malformation_dist = 0.5 * (min_malformation_dist + max_malformation_dist); + float worst_malformation_dist = 0.7 * flow_width; std::vector points; Polyline pl = path.as_polyline(); @@ -110,24 +116,55 @@ public: for (const Point &p : pl) { points.push_back(unscaled(p).cast()); } std::vector point_qualities(points.size(), 1.0); - for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) { + for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) { const Vec2f &p = points[point_idx]; double dist_from_prev_layer = prev_layer_boundary.signed_distance_from_lines(p.cast()) + flow_width * 0.5f; - if (dist_from_prev_layer < min_malformation_dist) continue; - float basic_distance_quality = 0.5f * fmin(1.0f, (1.0f - (dist_from_prev_layer - min_malformation_dist) / - (max_malformation_dist - min_malformation_dist))); - float curling_distance_quality = 0.5f * fmin(1.0f, std::abs(dist_from_prev_layer - worst_malformation_dist) / - (worst_malformation_dist - min_malformation_dist)); + float default_dist_quality = 0.5f; + float distance_quality = 1.0f; + if (dist_from_prev_layer < min_malformation_dist) { + distance_quality = 1.0f; + cestim.reset(); + continue; + } else if (dist_from_prev_layer < worst_malformation_dist) { + distance_quality = (worst_malformation_dist - dist_from_prev_layer) / (worst_malformation_dist - min_malformation_dist); + } else if (dist_from_prev_layer < max_malformation_dist) { + distance_quality = default_dist_quality * (1.0f - (max_malformation_dist - dist_from_prev_layer) / + (max_malformation_dist - worst_malformation_dist)); + } else { // completely in the air. use the default value in that case + distance_quality = default_dist_quality; + } - float distance_quality = basic_distance_quality + curling_distance_quality; + int prev_point_idx = point_idx; + while (prev_point_idx > 0) { + prev_point_idx--; + if ((p - points[prev_point_idx]).squaredNorm() > EPSILON) { break; } + } - point_qualities[point_idx] = distance_quality; + int next_point_index = point_idx; + while (next_point_index < int(points.size()) - 1) { + next_point_index++; + if ((p - points[next_point_index]).squaredNorm() > EPSILON) { break; } + } + + float curvature_penalty = 0.0f; + if (prev_point_idx != point_idx && next_point_index != point_idx) { + float distance = (p - points[prev_point_idx]).norm(); + float alfa = angle(p - points[prev_point_idx], points[next_point_index] - p); + cestim.add_point(distance, alfa); + + float curvature = std::abs(cestim.get_curvature()); + if (curvature > 1.0f) { + curvature_penalty = 1.0f; + } else if (curvature > 0.1f) { + curvature_penalty = std::min(1.0, dist_from_prev_layer - min_malformation_dist) * curvature; + } + } + + point_qualities[point_idx] = std::clamp(distance_quality - curvature_penalty, 0.0f, 1.0f); } - if (points.size() > 1) { point_qualities[0] = point_qualities[1]; } - for (size_t point_idx = 1; point_idx < points.size(); ++point_idx) { point_qualities[point_idx - 1] = std::max(point_qualities[point_idx - 1], point_qualities[point_idx]); }