diff --git a/src/libslic3r/GCode/ExtrusionProcessor.cpp b/src/libslic3r/GCode/ExtrusionProcessor.cpp index eb89b5ed57..be1bd1af8e 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.cpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.cpp @@ -17,8 +17,14 @@ ExtrusionPaths calculate_and_split_overhanging_extrusions(const ExtrusionPath const AABBTreeLines::LinesDistancer &unscaled_prev_layer, const AABBTreeLines::LinesDistancer &prev_layer_curled_lines) { - std::vector extended_points = estimate_points_properties(path.polyline.points, - unscaled_prev_layer, path.width()); + ExtrusionProcessor::PropertiesEstimationConfig config{}; + config.add_corners = true; + config.prev_layer_boundary_offset = true; + config.flow_width = path.width(); + std::vector extended_points = estimate_points_properties( + path.polyline.points, unscaled_prev_layer, config + ); + std::vector> calculated_distances(extended_points.size()); for (size_t i = 0; i < extended_points.size(); i++) { @@ -118,9 +124,28 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(const Extru } else if (auto *loop = dynamic_cast(e)) { ExtrusionLoop new_loop = *loop; new_loop.paths.clear(); - for (const ExtrusionPath &p : loop->paths) { - auto paths = calculate_and_split_overhanging_extrusions(p, unscaled_prev_layer, prev_layer_curled_lines); - new_loop.paths.insert(new_loop.paths.end(), paths.begin(), paths.end()); + + ExtrusionPaths paths{loop->paths}; + if (!paths.empty()) { + ExtrusionPath& first_path{paths.front()}; + ExtrusionPath& last_path{paths.back()}; + + if (first_path.attributes() == last_path.attributes()) { + if (first_path.polyline.size() > 1 && last_path.polyline.size() > 2) { + const Line start{first_path.polyline.front(), *std::next(first_path.polyline.begin())}; + const Line end{last_path.polyline.back(), *std::next(last_path.polyline.rbegin())}; + + if (std::abs(start.direction() - end.direction()) < 1e-5) { + first_path.polyline.points.front() = *std::next(last_path.polyline.points.rbegin()); + last_path.polyline.points.pop_back(); + } + } + } + } + + for (const ExtrusionPath &p : paths) { + auto resulting_paths = calculate_and_split_overhanging_extrusions(p, unscaled_prev_layer, prev_layer_curled_lines); + new_loop.paths.insert(new_loop.paths.end(), resulting_paths.begin(), resulting_paths.end()); } result.append(new_loop); } else if (auto *mp = dynamic_cast(e)) { diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index c197f91a76..d283388d8a 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -61,13 +61,20 @@ struct OverhangSpeeds float fan_speed; }; -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(); +struct PropertiesEstimationConfig { + bool add_corners{}; + bool prev_layer_boundary_offset{}; + float flow_width; + float max_line_length{-1.0f}; +}; + +template +std::vector estimate_points_properties( + const POINTS &input_points, + const AABBTreeLines::LinesDistancer &unscaled_prev_layer, + const PropertiesEstimationConfig &config +) { + 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; @@ -95,32 +102,28 @@ std::vector estimate_points_properties(const POINTS }; }; - 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; - auto maybe_unscale = [](const P &p) { return SCALED_INPUT ? unscaled(p) : p.template cast(); }; + float boundary_offset = config.prev_layer_boundary_offset ? 0.5 * config.flow_width : 0.0f; std::vector points; - points.reserve(input_points.size() * (ADD_INTERSECTIONS ? 1.5 : 1)); + points.reserve(input_points.size() * 1.5); { - ExtendedPoint start_point{maybe_unscale(input_points.front())}; + ExtendedPoint start_point{unscaled(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; points.push_back(start_point); } for (size_t i = 1; i < input_points.size(); i++) { - ExtendedPoint next_point{maybe_unscale(input_points[i])}; + ExtendedPoint next_point{unscaled(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; - if (ADD_INTERSECTIONS && - ((points.back().distance > boundary_offset + EPSILON) != (next_point.distance > boundary_offset + EPSILON))) { + if (((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()}); @@ -134,7 +137,7 @@ std::vector estimate_points_properties(const POINTS points.push_back(next_point); } - if (PREV_LAYER_BOUNDARY_OFFSET && ADD_INTERSECTIONS) { + if (config.add_corners) { std::vector new_points; new_points.reserve(points.size() * 2); new_points.push_back(points.front()); @@ -176,7 +179,7 @@ std::vector estimate_points_properties(const POINTS points = std::move(new_points); } - if (max_line_length > 0) { + if (config.max_line_length > 0) { std::vector new_points; new_points.reserve(points.size() * 2); { @@ -185,7 +188,7 @@ std::vector estimate_points_properties(const POINTS const ExtendedPoint &next = points[i + 1]; new_points.push_back(curr); double len = (next.position - curr.position).squaredNorm(); - double t = sqrt((max_line_length * max_line_length) / len); + double t = sqrt((config.max_line_length * config.max_line_length) / len); size_t new_point_count = 1.0 / t; for (size_t j = 1; j < new_point_count + 1; j++) { Vec2d pos = curr.position * (1.0 - j * t) + next.position * (j * t); diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index 629ddd6f93..f3481dad9b 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -4,6 +4,7 @@ ///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher ///|/ #include "SupportSpotsGenerator.hpp" +#include #include #include @@ -337,9 +338,16 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit return {}; } const float flow_width = get_flow_width(layer_region, entity->role()); + + ExtrusionProcessor::PropertiesEstimationConfig config{}; + config.add_corners = true; + config.prev_layer_boundary_offset = true; + config.max_line_length = params.bridge_distance; + config.flow_width = flow_width; + std::vector annotated_points = - ExtrusionProcessor::estimate_points_properties(entity->as_polyline().points, prev_layer_boundary, - flow_width, params.bridge_distance); + ExtrusionProcessor::estimate_points_properties< + true>(entity->as_polyline().points, prev_layer_boundary, config); std::vector lines_out; lines_out.reserve(annotated_points.size()); @@ -391,9 +399,12 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit const float flow_width = get_flow_width(layer_region, entity->role()); // Compute only unsigned distance - prev_layer_lines can contain unconnected paths, thus the sign of the distance is unreliable + + ExtrusionProcessor::PropertiesEstimationConfig config{}; + config.max_line_length = params.bridge_distance; + config.flow_width = flow_width; std::vector annotated_points = - ExtrusionProcessor::estimate_points_properties(entity->as_polyline().points, prev_layer_lines, - flow_width, params.bridge_distance); + ExtrusionProcessor::estimate_points_properties(entity->as_polyline().points, prev_layer_lines, config); std::vector lines_out; lines_out.reserve(annotated_points.size()); @@ -1248,8 +1259,10 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, Polygon pol(pl.points); pol.make_counter_clockwise(); - auto annotated_points = ExtrusionProcessor::estimate_points_properties(pol.points, prev_layer_lines, - flow_width); + ExtrusionProcessor::PropertiesEstimationConfig config{}; + config.flow_width = flow_width; + auto annotated_points = ExtrusionProcessor::estimate_points_properties< + false>(pol.points, prev_layer_lines, config); for (size_t i = 0; i < annotated_points.size(); ++i) { const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; @@ -1324,10 +1337,14 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms) Points extrusion_pts; extrusion->collect_points(extrusion_pts); float flow_width = get_flow_width(layer_region, extrusion->role()); - auto annotated_points = ExtrusionProcessor::estimate_points_properties(extrusion_pts, - prev_layer_lines, - flow_width, - params.bridge_distance); + + ExtrusionProcessor::PropertiesEstimationConfig config{}; + config.max_line_length = params.bridge_distance; + config.add_corners = true; + config.flow_width = flow_width; + auto annotated_points = ExtrusionProcessor::estimate_points_properties< + false>(extrusion_pts, prev_layer_lines, config); + for (size_t i = 0; i < annotated_points.size(); ++i) { const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; const ExtrusionProcessor::ExtendedPoint &b = annotated_points[i];