From ec4cc2e6946b524ee630a7db006ede5d8828f779 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Thu, 22 Dec 2022 19:16:35 +0100 Subject: [PATCH] refactored and unified code for curled up filament estimation --- src/libslic3r/GCode/ExtrusionProcessor.hpp | 23 +- src/libslic3r/SupportSpotsGenerator.cpp | 276 +++++++++------------ src/libslic3r/SupportSpotsGenerator.hpp | 2 +- 3 files changed, 139 insertions(+), 162 deletions(-) diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index eeffe7554..2402a086e 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -68,23 +68,32 @@ public: class CurvatureEstimator { static const size_t sliders_count = 2; - SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{4.0}, {12.0}}; + SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{4.0}, {10.0}}; public: void add_point(float distance, float angle) { - if (distance < EPSILON) return; - for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.add_point(distance, angle); } + if (distance < EPSILON) + return; + for (SlidingWindowCurvatureAccumulator &slider : sliders) { + slider.add_point(distance, angle); + } } float get_curvature() { - float max_curvature = std::numeric_limits::min(); - for (const SlidingWindowCurvatureAccumulator &slider : sliders) { max_curvature = std::max(max_curvature, slider.get_curvature()); } + float max_curvature = 0.0f; + for (const SlidingWindowCurvatureAccumulator &slider : sliders) { + if (abs(slider.get_curvature()) > abs(max_curvature)) { + max_curvature = slider.get_curvature(); + } + } return max_curvature; } void reset() { - for (SlidingWindowCurvatureAccumulator &slider : sliders) { slider.reset(); } + for (SlidingWindowCurvatureAccumulator &slider : sliders) { + slider.reset(); + } } }; @@ -111,7 +120,6 @@ std::vector estimate_points_properties(const std::vector

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(); }; std::vector

extrusion_points; @@ -218,7 +226,6 @@ std::vector estimate_points_properties(const std::vector

cestim.add_point(distance, alfa); } - if (a.distance < min_malformation_dist) { cestim.reset(); } a.curvature = cestim.get_curvature(); } diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 98dfca0cd..cb8d0f5d6 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -181,31 +181,6 @@ float get_flow_width(const LayerRegion *region, ExtrusionRole role) } } -// Accumulator of current extrusion path properties -// It remembers unsuported distance and maximum accumulated curvature over that distance. -// Used to determine local stability issues (too long bridges, extrusion curves into air) -struct ExtrusionPropertiesAccumulator -{ - float distance = 0; // accumulated distance - float curvature = 0; // accumulated signed ccw angles - float max_curvature = 0; // max absolute accumulated value - - void add_distance(float dist) { distance += dist; } - - void add_angle(float ccw_angle) - { - curvature += ccw_angle; - max_curvature = std::max(max_curvature, std::abs(curvature)); - } - - void reset() - { - distance = 0; - curvature = 0; - max_curvature = 0; - } -}; - std::vector to_short_lines(const ExtrusionEntity *e, float length_limit) { assert(!e->is_collection()); @@ -229,6 +204,24 @@ std::vector to_short_lines(const ExtrusionEntity *e, float length return lines; } +float estimate_curled_up_height( + const ExtendedPoint &point, float layer_height, float flow_width, float prev_line_curled_height, Params params) +{ + float curled_up_height = 0.0f; + if (fabs(point.distance) < 1.5 * flow_width) { + curled_up_height = 0.85 * prev_line_curled_height; + } + if (point.distance > params.malformation_distance_factors.first * flow_width && + point.distance < params.malformation_distance_factors.second * flow_width && point.curvature > -0.1f) { + float dist_factor = (point.distance - params.malformation_distance_factors.first * flow_width) / + ((params.malformation_distance_factors.second - params.malformation_distance_factors.first) * flow_width); + + curled_up_height = layer_height * 2.0f * sqrt(sqrt(dist_factor)) * std::clamp(6.0f * point.curvature, 1.0f, 6.0f); + curled_up_height = std::min(curled_up_height, params.max_malformation_factor * layer_height); + } + return curled_up_height; +} + std::vector check_extrusion_entity_stability(const ExtrusionEntity *entity, const LayerRegion *layer_region, const LD &prev_layer_lines, @@ -244,9 +237,11 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit } return checked_lines_out; } else { // single extrusion path, with possible varying parameters - if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) { return {}; } + if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) { + return {}; + } - const float flow_width = get_flow_width(layer_region, entity->role()); + const float flow_width = get_flow_width(layer_region, entity->role()); std::vector annotated_points = estimate_points_properties(entity->as_polyline().points, prev_layer_lines, flow_width, @@ -258,15 +253,15 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit 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() : curr_point.position.cast(), + 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() : curr_point.position.cast(), curr_point.position.cast(), line_len, entity}; - ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ? + const 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(curr_point.position) - 0.5f * flow_width < 0.0f ? -1.0f : 1.0f; + float sign = (prev_layer_boundary.distance_from_lines(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) { @@ -282,8 +277,7 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit } } 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); + 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; @@ -292,10 +286,8 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit bridged_distance = 0.0f; } - 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)); - } + line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width, + nearest_prev_layer_line.curled_up_height, params); lines_out.push_back(line_out); } @@ -765,7 +757,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms) auto ls = to_unscaled_linesf({layer->lower_layer->lslices[link.slice_idx]}); boundary_lines.insert(boundary_lines.end(), ls.begin(), ls.end()); } - AABBTreeLines::LinesDistancer boundary{std::move(boundary_lines)}; + AABBTreeLines::LinesDistancer prev_layer_boundary{std::move(boundary_lines)}; std::vector current_slice_ext_perims_lines{}; @@ -803,7 +795,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,boundary, params)) { + check_extrusion_entity_stability(entity, fill_region, prev_layer_ext_perim_lines,prev_layer_boundary, params)) { if (bridge.support_point_generated) { reckon_new_support_point(create_support_point_position(bridge.b), -EPSILON, Vec2f::Zero()); } @@ -816,7 +808,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 perims = check_extrusion_entity_stability(entity, perimeter_region, - prev_layer_ext_perim_lines,boundary, params); + prev_layer_ext_perim_lines,prev_layer_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()); @@ -851,7 +843,7 @@ SupportPoints check_stability(const PrintObject *po, const Params ¶ms) } #ifdef DEBUG_FILES -void debug_export(Issues issues, std::string file_name) +void debug_export(SupportPoints support_points, std::string file_name) { Slic3r::CNumericLocalesSetter locales_setter; { @@ -861,13 +853,13 @@ void debug_export(Issues issues, std::string file_name) return; } - for (size_t i = 0; i < issues.support_points.size(); ++i) { - if (issues.support_points[i].force <= 0) { - fprintf(fp, "v %f %f %f %f %f %f\n", issues.support_points[i].position(0), issues.support_points[i].position(1), - issues.support_points[i].position(2), 0.0, 1.0, 0.0); + for (size_t i = 0; i < support_points.size(); ++i) { + if (support_points[i].force <= 0) { + fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1), + support_points[i].position(2), 0.0, 1.0, 0.0); } else { - fprintf(fp, "v %f %f %f %f %f %f\n", issues.support_points[i].position(0), issues.support_points[i].position(1), - issues.support_points[i].position(2), 1.0, 0.0, 0.0); + fprintf(fp, "v %f %f %f %f %f %f\n", support_points[i].position(0), support_points[i].position(1), + support_points[i].position(2), 1.0, 0.0, 0.0); } } @@ -883,105 +875,70 @@ SupportPoints full_search(const PrintObject *po, const Params ¶ms) { SupportPoints supp_points = check_stability(po, params); #ifdef DEBUG_FILES - debug_export(issues, "issues"); + debug_export(supp_points, "issues"); #endif return supp_points; } - -struct LayerCurlingEstimator -{ - LD prev_layer_lines; - Params params; - std::function flow_width_getter; - - LayerCurlingEstimator(std::function flow_width_getter, const Params ¶ms) - : flow_width_getter(flow_width_getter), params(params) - {} - - void estimate_curling(std::vector &extrusion_lines, Layer *l) - { - ExtrusionPropertiesAccumulator malformation_acc{}; - for (size_t line_idx = 0; line_idx < extrusion_lines.size(); ++line_idx) { - ExtrusionLine ¤t_line = extrusion_lines[line_idx]; - - float flow_width = flow_width_getter(current_line); - - 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; - - float curr_angle = 0; - if (line_idx + 1 < extrusion_lines.size()) { - const Vec2f v1 = current_line.b - current_line.a; - const Vec2f v2 = extrusion_lines[line_idx + 1].b - extrusion_lines[line_idx + 1].a; - curr_angle = angle(v1, v2); - } - // 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(); } - - auto [dist_from_prev_layer, nearest_line_idx, nearest_point] = prev_layer_lines.distance_from_lines_extra(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.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.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.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); - } -}; - - -void estimate_supports_malformations(SupportLayerPtrs &layers, float supports_flow_width, const Params ¶ms) +void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, const Params ¶ms) { #ifdef DEBUG_FILES FILE *debug_file = boost::nowide::fopen(debug_out_path("supports_malformations.obj").c_str(), "w"); #endif - auto flow_width_getter = [=](const ExtrusionLine& l) { - return supports_flow_width; - }; - LayerCurlingEstimator lce{flow_width_getter, params}; + AABBTreeLines::LinesDistancer prev_layer_lines{}; for (SupportLayer *l : layers) { - std::vector extrusion_lines; + std::vector current_layer_lines; + for (const ExtrusionEntity *extrusion : l->support_fills.flatten().entities) { Polyline pl = extrusion->as_polyline(); - Polygon pol(pl.points); + Polygon pol(pl.points); pol.make_counter_clockwise(); - pl = pol.split_at_first_point(); - for (int point_idx = 0; point_idx < int(pl.points.size() - 1); ++point_idx) { - Vec2f start = unscaled(pl.points[point_idx]).cast(); - Vec2f next = unscaled(pl.points[point_idx + 1]).cast(); - ExtrusionLine line{start, next, (start - next).norm(), extrusion}; - extrusion_lines.push_back(line); + + auto annotated_points = estimate_points_properties(pol.points, prev_layer_lines, flow_width); + + 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() : curr_point.position.cast(), + curr_point.position.cast(), line_len, extrusion}; + + const ExtrusionLine nearest_prev_layer_line = prev_layer_lines.get_lines().size() > 0 ? + prev_layer_lines.get_line(curr_point.nearest_prev_layer_line) : + ExtrusionLine{}; + + Vec2f v1 = (nearest_prev_layer_line.b - nearest_prev_layer_line.a); + Vec2f v2 = (curr_point.position.cast() - nearest_prev_layer_line.a); + auto d = (v1.x() * v2.y()) - (v1.y() * v2.x()); + if (d > 0) { + curr_point.distance *= -1.0f; + } + + line_out.curled_up_height = estimate_curled_up_height(curr_point, l->height, flow_width, + nearest_prev_layer_line.curled_up_height, params); + + current_layer_lines.push_back(line_out); } } - lce.estimate_curling(extrusion_lines, l); + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > 0.3f) { + l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); + } + } #ifdef DEBUG_FILES - for (const ExtrusionLine &line : extrusion_lines) { - if (line.malformation > 0.3f) { - Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.malformation); + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > 0.3f) { + Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.curled_up_height); fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]); } } #endif + + prev_layer_lines = LD{current_layer_lines}; } #ifdef DEBUG_FILES @@ -994,44 +951,58 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms) #ifdef DEBUG_FILES FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w"); #endif - auto flow_width_getter = [](const ExtrusionLine &l) { return 0.0; }; - LayerCurlingEstimator lce{flow_width_getter, params}; + + LD prev_layer_lines{}; for (Layer *l : layers) { - if (l->regions().empty()) { - continue; - } - struct Visitor { - Visitor(const Params ¶ms) : params(params) {} - void recursive_do(const ExtrusionEntityCollection &collection, const LayerRegion *region) { - for (const ExtrusionEntity* entity : collection.entities) - if (entity->is_collection()) - this->recursive_do(*static_cast(entity), region); - else { - append(extrusion_lines, to_short_lines(entity, params.bridge_distance)); - extrusions_widths.emplace(entity, get_flow_width(region, entity->role())); - } + std::vector boundary_lines = l->lower_layer != nullptr ? to_unscaled_linesf(l->lower_layer->lslices) : std::vector(); + AABBTreeLines::LinesDistancer prev_layer_boundary{std::move(boundary_lines)}; + std::vector current_layer_lines; + for (const LayerRegion *layer_region : l->regions()) { + for (const ExtrusionEntity *extrusion : layer_region->perimeters().flatten().entities) { + Points extrusion_pts; + extrusion->collect_points(extrusion_pts); + float flow_width = get_flow_width(layer_region, extrusion->role()); + auto annotated_points = estimate_points_properties(extrusion_pts, prev_layer_lines, flow_width, + params.bridge_distance); + 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() : curr_point.position.cast(), + curr_point.position.cast(), line_len, extrusion}; + + const 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(curr_point.position) + 0.5f * flow_width) < 0.0f ? -1.0f : + 1.0f; + curr_point.distance *= sign; + + line_out.curled_up_height = estimate_curled_up_height(curr_point, layer_region->layer()->height, flow_width, + nearest_prev_layer_line.curled_up_height, params); + + current_layer_lines.push_back(line_out); + } } - const Params ¶ms; - std::unordered_map extrusions_widths; - std::vector extrusion_lines; - } visitor(params); + } - for (const LayerRegion *region : l->regions()) - visitor.recursive_do(region->perimeters(), region); - - lce.flow_width_getter = [&](const ExtrusionLine &l) { return visitor.extrusions_widths[l.origin_entity]; }; - - lce.estimate_curling(visitor.extrusion_lines, l); + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > 0.3f) { + l->malformed_lines.push_back(Line{Point::new_scale(line.a), Point::new_scale(line.b)}); + } + } #ifdef DEBUG_FILES - for (const ExtrusionLine &line : extrusion_lines) { - if (line.malformation > 0.3f) { - Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.malformation); + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > 0.3f) { + Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_malformation_factor, line.curled_up_height); fprintf(debug_file, "v %f %f %f %f %f %f\n", line.b[0], line.b[1], l->print_z, color[0], color[1], color[2]); } } #endif + + prev_layer_lines = LD{current_layer_lines}; } #ifdef DEBUG_FILES @@ -1039,6 +1010,5 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms) #endif } -} //SupportableIssues End -} - +} // namespace SupportSpotsGenerator +} // namespace Slic3r diff --git a/src/libslic3r/SupportSpotsGenerator.hpp b/src/libslic3r/SupportSpotsGenerator.hpp index 6f5c2a746..3515ec57f 100644 --- a/src/libslic3r/SupportSpotsGenerator.hpp +++ b/src/libslic3r/SupportSpotsGenerator.hpp @@ -28,7 +28,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 = 10.0f; // allowed bridge distance = bridge_distance / (1 + this factor * curvature ) - const std::pair malformation_overlap_factor = std::pair { 0.50, -0.1 }; + const std::pair malformation_distance_factors = std::pair { 0.4, 1.2 }; const float max_malformation_factor = 10.0f; const float min_distance_between_support_points = 3.0f; //mm