diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index 08a0694e3ec..c6c1c102dea 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -27,125 +27,81 @@ namespace Slic3r { -class SlidingWindowCurvatureAccumulator -{ - float window_size; - float total_distance = 0; // accumulated distance - float total_curvature = 0; // accumulated signed ccw angles - deque distances; - deque angles; - -public: - SlidingWindowCurvatureAccumulator(float window_size) : window_size(window_size) {} - - void add_point(float distance, float angle) - { - total_distance += distance; - total_curvature += angle; - distances.push_back(distance); - angles.push_back(angle); - - while (distances.size() > 1 && total_distance > window_size) { - total_distance -= distances.front(); - total_curvature -= angles.front(); - distances.pop_front(); - angles.pop_front(); - } - } - - float get_curvature() const - { - return total_curvature / window_size; - } - - void reset() - { - total_curvature = 0; - total_distance = 0; - distances.clear(); - angles.clear(); - } -}; - -class CurvatureEstimator -{ - static const size_t sliders_count = 3; - SlidingWindowCurvatureAccumulator sliders[sliders_count] = {{3.0},{9.0}, {16.0}}; - -public: - void add_point(float distance, float angle) - { - if (distance < EPSILON) - return; - for (SlidingWindowCurvatureAccumulator &slider : sliders) { - slider.add_point(distance, angle); - } - } - float 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(); - } - } -}; - struct ExtendedPoint { - ExtendedPoint(Vec2d position, float distance = 0.0, size_t nearest_prev_layer_line = size_t(-1), float curvature = 0.0) - : position(position), distance(distance), nearest_prev_layer_line(nearest_prev_layer_line), curvature(curvature) - {} - - Vec2d position; - float distance; - size_t nearest_prev_layer_line; - float curvature; + Vec2d position; + float distance; + float curvature; }; -template -std::vector estimate_points_properties(const std::vector

&input_points, +template +std::vector estimate_points_properties(const POINTS &input_points, const AABBTreeLines::LinesDistancer &unscaled_prev_layer, float flow_width, float max_line_length = -1.0f) { + bool looped = input_points.front() == input_points.back(); + std::function get_prev_index = [](size_t idx, size_t count) { + if (idx > 0) { + return idx - 1; + } else + return idx; + }; + if (looped) { + get_prev_index = [](size_t idx, size_t count) { + if (idx == 0) + idx = count; + return --idx; + }; + }; + std::function get_next_index = [](size_t idx, size_t size) { + if (idx + 1 < size) { + return idx + 1; + } else + return idx; + }; + if (looped) { + get_next_index = [](size_t idx, size_t count) { + if (++idx == count) + idx = 0; + return idx; + }; + }; + + using P = typename POINTS::value_type; + using AABBScalar = typename AABBTreeLines::LinesDistancer::Scalar; if (input_points.empty()) return {}; - float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f; - CurvatureEstimator cestim; - auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast(); }; + float boundary_offset = PREV_LAYER_BOUNDARY_OFFSET ? 0.5 * flow_width : 0.0f; + auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast(); }; std::vector points; points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1)); { ExtendedPoint start_point{maybe_unscale(input_points.front())}; - auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra(start_point.position.cast()); - start_point.distance = distance + boundary_offset; - start_point.nearest_prev_layer_line = nearest_line; + auto [distance, nearest_line, + x] = unscaled_prev_layer.template distance_from_lines_extra(start_point.position.cast()); + start_point.distance = distance + boundary_offset; points.push_back(start_point); } for (size_t i = 1; i < input_points.size(); i++) { ExtendedPoint next_point{maybe_unscale(input_points[i])}; - auto [distance, nearest_line, x] = unscaled_prev_layer.template distance_from_lines_extra(next_point.position.cast()); - next_point.distance = distance + boundary_offset; - next_point.nearest_prev_layer_line = nearest_line; + auto [distance, nearest_line, + x] = unscaled_prev_layer.template distance_from_lines_extra(next_point.position.cast()); + next_point.distance = distance + boundary_offset; 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(L{prev_point.position.cast(), next_point.position.cast()}); + const ExtendedPoint &prev_point = points.back(); + auto intersections = unscaled_prev_layer.template intersections_with_line( + L{prev_point.position.cast(), next_point.position.cast()}); for (const auto &intersection : intersections) { - points.emplace_back(intersection.first.template cast(), boundary_offset, intersection.second); + ExtendedPoint p{}; + p.position = intersection.first.template cast(); + p.distance = boundary_offset; + points.push_back(p); } } points.push_back(next_point); @@ -153,41 +109,49 @@ std::vector estimate_points_properties(const std::vector

if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) { std::vector new_points; - new_points.reserve(points.size()*2); + new_points.reserve(points.size() * 2); new_points.push_back(points.front()); for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) { const ExtendedPoint &curr = points[point_idx]; const ExtendedPoint &next = points[point_idx + 1]; - if ((curr.distance > 0 && curr.distance < boundary_offset + 2.0f) || - (next.distance > 0 && next.distance < boundary_offset + 2.0f)) { + if ((curr.distance > -boundary_offset && curr.distance < boundary_offset + 2.0f) || + (next.distance > -boundary_offset && next.distance < boundary_offset + 2.0f)) { double line_len = (next.position - curr.position).norm(); if (line_len > 4.0f) { - double a0 = std::clamp((curr.distance + 2 * boundary_offset) / line_len, 0.0, 1.0); - double a1 = std::clamp(1.0f - (next.distance + 2 * boundary_offset) / line_len, 0.0, 1.0); + double a0 = std::clamp((curr.distance + 3 * boundary_offset) / line_len, 0.0, 1.0); + double a1 = std::clamp(1.0f - (next.distance + 3 * boundary_offset) / line_len, 0.0, 1.0); double t0 = std::min(a0, a1); double t1 = std::max(a0, a1); if (t0 < 1.0) { - auto p0 = curr.position + t0 * (next.position - curr.position); - auto [p0_dist, p0_near_l, p0_x] = unscaled_prev_layer.template distance_from_lines_extra(p0.cast()); - new_points.push_back(ExtendedPoint{p0, float(p0_dist + boundary_offset), p0_near_l}); + auto p0 = curr.position + t0 * (next.position - curr.position); + auto [p0_dist, p0_near_l, + p0_x] = unscaled_prev_layer.template distance_from_lines_extra(p0.cast()); + ExtendedPoint new_p{}; + new_p.position = p0; + new_p.distance = float(p0_dist + boundary_offset); + new_points.push_back(new_p); } if (t1 > 0.0) { - auto p1 = curr.position + t1 * (next.position - curr.position); - auto [p1_dist, p1_near_l, p1_x] = unscaled_prev_layer.template distance_from_lines_extra(p1.cast()); - new_points.push_back(ExtendedPoint{p1, float(p1_dist + boundary_offset), p1_near_l}); + auto p1 = curr.position + t1 * (next.position - curr.position); + auto [p1_dist, p1_near_l, + p1_x] = unscaled_prev_layer.template distance_from_lines_extra(p1.cast()); + ExtendedPoint new_p{}; + new_p.position = p1; + new_p.distance = float(p1_dist + boundary_offset); + new_points.push_back(new_p); } } } new_points.push_back(next); } - points = new_points; + points = std::move(new_points); } if (max_line_length > 0) { std::vector new_points; - new_points.reserve(points.size()*2); + new_points.reserve(points.size() * 2); { for (size_t i = 0; i + 1 < points.size(); i++) { const ExtendedPoint &curr = points[i]; @@ -200,38 +164,78 @@ std::vector estimate_points_properties(const std::vector

Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t); auto [p_dist, p_near_l, p_x] = unscaled_prev_layer.template distance_from_lines_extra(pos.cast()); - new_points.push_back(ExtendedPoint{pos, float(p_dist + boundary_offset), p_near_l}); + ExtendedPoint new_p{}; + new_p.position = pos; + new_p.distance = float(p_dist + boundary_offset); + new_points.push_back(new_p); } } new_points.push_back(points.back()); } - points = new_points; + points = std::move(new_points); } - for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) { - ExtendedPoint &a = points[point_idx]; - ExtendedPoint &prev = points[point_idx > 0 ? point_idx - 1 : point_idx]; + float accumulated_distance = 0; + std::vector distances_for_curvature(points.size()); + for (size_t point_idx = 0; point_idx < points.size(); ++point_idx) { + const ExtendedPoint &a = points[point_idx]; + const ExtendedPoint &b = points[get_prev_index(point_idx, points.size())]; - int prev_point_idx = point_idx; - while (prev_point_idx > 0) { - prev_point_idx--; - if ((a.position - points[prev_point_idx].position).squaredNorm() > EPSILON) { break; } - } + distances_for_curvature[point_idx] = (b.position - a.position).norm(); + accumulated_distance += distances_for_curvature[point_idx]; + } - int next_point_index = point_idx; - while (next_point_index < int(points.size()) - 1) { - next_point_index++; - if ((a.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; } - } + if (accumulated_distance > EPSILON) + for (float window_size : {3.0f, 9.0f, 16.0f}) { + for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) { + ExtendedPoint ¤t = points[point_idx]; + + Vec2d back_position = current.position; + { + size_t back_point_index = point_idx; + float dist_backwards = 0; + while (dist_backwards < window_size * 0.5 && back_point_index != get_prev_index(back_point_index, points.size())) { + float line_dist = distances_for_curvature[get_prev_index(back_point_index, points.size())]; + if (dist_backwards + line_dist > window_size * 0.5) { + back_position = points[back_point_index].position + + (window_size * 0.5 - dist_backwards) * + (points[get_prev_index(back_point_index, points.size())].position - + points[back_point_index].position) + .normalized(); + dist_backwards += window_size * 0.5 - dist_backwards + EPSILON; + } else { + dist_backwards += line_dist; + back_point_index = get_prev_index(back_point_index, points.size()); + } + } + } - if (prev_point_idx != point_idx && next_point_index != point_idx) { - 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); - } + Vec2d front_position = current.position; + { + size_t front_point_index = point_idx; + float dist_forwards = 0; + while (dist_forwards < window_size * 0.5 && front_point_index != get_next_index(front_point_index, points.size())) { + float line_dist = distances_for_curvature[front_point_index]; + if (dist_forwards + line_dist > window_size * 0.5) { + front_position = points[front_point_index].position + + (window_size * 0.5 - dist_forwards) * + (points[get_next_index(front_point_index, points.size())].position - + points[front_point_index].position) + .normalized(); + dist_forwards += window_size * 0.5 - dist_forwards + EPSILON; + } else { + dist_forwards += line_dist; + front_point_index = get_next_index(front_point_index, points.size()); + } + } + } - a.curvature = cestim.get_curvature(); - } + float new_curvature = angle(current.position - back_position, front_position - current.position) / window_size; + if (abs(current.curvature) < abs(new_curvature)) { + current.curvature = new_curvature; + } + } + } return points; } @@ -377,11 +381,11 @@ class ExtrusionQualityEstimator float extrusion_speed = std::min(calculate_speed(curr.distance), calculate_speed(next.distance)); if(slowdown_for_curled_edges) { - float curled_speed = calculate_speed(artificial_distance_to_curled_lines); + float curled_speed = calculate_speed(artificial_distance_to_curled_lines); extrusion_speed = std::min(curled_speed, extrusion_speed); // adjust extrusion speed based on what is smallest - the calculated overhang speed or the artificial curled speed } - float overlap = std::min(1 - curr.distance * width_inv, 1 - next.distance * width_inv); + float overlap = std::min(1 - (curr.distance+artificial_distance_to_curled_lines) * width_inv, 1 - (next.distance+artificial_distance_to_curled_lines) * width_inv); processed_points.push_back({ scaled(curr.position), extrusion_speed, overlap }); } diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 52f3424d352..c7c205fc454 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -105,15 +105,10 @@ float estimate_curled_up_height( float curled_up_height = 0; if (fabs(distance) < 3.0 * flow_width) { curled_up_height = std::max(prev_line_curled_height - layer_height * 0.75f, 0.0f); - //printf("If 1 %d\n",curled_up_height); } - - //printf("distance %f, params.malformation_distance_factors.first %f, params.malformation_distance_factors.second %f, flow_width %f\n", distance, params.malformation_distance_factors.first, params.malformation_distance_factors.second, flow_width); - //printf("distance %f,params.malformation_distance_factors.first * flow_width %f, params.malformation_distance_factors.second * flow_width %f\n", distance, params.malformation_distance_factors.first * flow_width, params.malformation_distance_factors.second * flow_width); if (distance > params.malformation_distance_factors.first * flow_width && distance < params.malformation_distance_factors.second * flow_width) { - // imagine the extrusion profile. The part that has been glued (melted) with the previous layer will be called anchored section // and the rest will be called curling section // float anchored_section = flow_width - point.distance; @@ -145,49 +140,79 @@ float estimate_curled_up_height( void estimate_malformations(LayerPtrs &layers, const Params ¶ms) { - LD prev_layer_lines{}; - for (Layer *l : layers) { +#ifdef DEBUG_FILES + FILE *debug_file = boost::nowide::fopen(debug_out_path("object_malformations.obj").c_str(), "w"); + FILE *full_file = boost::nowide::fopen(debug_out_path("object_full.obj").c_str(), "w"); +#endif + + LD prev_layer_lines{}; + + for (Layer *l : layers) { l->curled_lines.clear(); 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) { - if (extrusion->role() != Slic3r::erExternalPerimeter) + for (const ExtrusionEntity *extrusion : layer_region->perimeters.flatten().entities) { + if (extrusion->role() != Slic3r::erExternalPerimeter) continue; - Points extrusion_pts; + + 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); + 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) { - const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + const ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; const ExtendedPoint &b = annotated_points[i]; ExtrusionLine line_out{a.position.cast(), b.position.cast(), float((a.position - b.position).norm()), extrusion}; + Vec2f middle = 0.5 * (line_out.a + line_out.b); auto [middle_distance, bottom_line_idx, x] = prev_layer_lines.distance_from_lines_extra(middle); ExtrusionLine bottom_line = prev_layer_lines.get_lines().empty() ? ExtrusionLine{} : prev_layer_lines.get_line(bottom_line_idx); // correctify the distance sign using slice polygons - float sign = (prev_layer_boundary.distance_from_lines(middle.cast()) + 0.5f * flow_width) < 0.0f ? -1.0f : 1.0f; + float sign = (prev_layer_boundary.distance_from_lines(middle.cast()) + 0.5f * flow_width) < 0.0f ? -1.0f : + 1.0f; - line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign, 0.5 * (a.curvature + b.curvature), + line_out.curled_up_height = estimate_curled_up_height(middle_distance * sign * params.curled_distance_expansion, 0.5 * (a.curvature + b.curvature), l->height, flow_width, bottom_line.curled_up_height, params); current_layer_lines.push_back(line_out); } - } + } } + for (const ExtrusionLine &line : current_layer_lines) { if (line.curled_up_height > params.curling_tolerance_limit) { l->curled_lines.push_back(CurledLine{Point::new_scale(line.a), Point::new_scale(line.b), line.curled_up_height}); } } - + +#ifdef DEBUG_FILES + for (const ExtrusionLine &line : current_layer_lines) { + if (line.curled_up_height > params.curling_tolerance_limit) { + Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_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]); + } + } + for (const ExtrusionLine &line : current_layer_lines) { + Vec3f color = value_to_rgbf(-EPSILON, l->height * params.max_curled_height_factor, line.curled_up_height); + fprintf(full_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 + fclose(debug_file); + fclose(full_file); +#endif } /* diff --git a/src/libslic3r/SupportSpotsGenerator.hpp b/src/libslic3r/SupportSpotsGenerator.hpp index eed2351f825..73a34190677 100644 --- a/src/libslic3r/SupportSpotsGenerator.hpp +++ b/src/libslic3r/SupportSpotsGenerator.hpp @@ -43,8 +43,9 @@ struct Params BrimType brim_type; const float brim_width; - const std::pair malformation_distance_factors = std::pair { 0.33, 0.7 }; + const std::pair malformation_distance_factors = std::pair { 0.2, 1.1 }; const float max_curled_height_factor = 10.0f; + const float curled_distance_expansion = 1.0f; // controls the spread of the area where slow down for curled overhangs is applied const float curling_tolerance_limit = 0.1f; const float min_distance_between_support_points = 3.0f; //mm