diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 5893853364..3930d8f65b 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -103,7 +103,8 @@ inline bool operator==(const ExtrusionFlow &lhs, const ExtrusionFlow &rhs) } struct OverhangAttributes { - float max_distance_from_prev_layer; + float start_distance_from_prev_layer; + float end_distance_from_prev_layer; float proximity_to_curled_lines; //value between 0 and 1 }; @@ -169,6 +170,7 @@ public: double mm3_per_mm() const { return m_attributes.mm3_per_mm; } // Minimum volumetric velocity of this extrusion entity. Used by the constant nozzle pressure algorithm. double min_mm3_per_mm() const override { return m_attributes.mm3_per_mm; } + std::optional& overhang_attributes_mutable() { return m_attributes.overhang_attributes; } // Produce a list of 2D polygons covered by the extruded paths, offsetted by the extrusion width. // Increase the offset by scaled_epsilon to achieve an overlap, so a union will produce no gaps. diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index d4a663c60c..0504645520 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -2775,25 +2776,8 @@ std::string GCodeGenerator::_extrude( ); } + std::pair dynamic_speed_and_fan_speed{-1, -1}; if (path_attr.overhang_attributes.has_value()) { - std::vector> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}}; - if (this->m_config.enable_dynamic_overhang_speeds) { - overhangs_with_speeds = {{0, m_config.overhang_speed_0}, - {25, m_config.overhang_speed_1}, - {50, m_config.overhang_speed_2}, - {75, m_config.overhang_speed_3}, - {100, ConfigOptionFloatOrPercent{speed, false}}}; - } - - std::vector> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}}; - if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) { - overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0}, - {25, m_config.overhang_fan_speed_1}, - {50, m_config.overhang_fan_speed_2}, - {75, m_config.overhang_fan_speed_3}, - {100, ConfigOptionInts{0}}}; - } - double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed"); if (external_perim_reference_speed == 0) external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm; @@ -2805,58 +2789,13 @@ std::string GCodeGenerator::_extrude( EXTRUDER_CONFIG(filament_max_volumetric_speed) / path_attr.mm3_per_mm); } - ExtrusionProcessor::calculate_overhang_speed(); - - - new_points = m_extrusion_quality_estimator.estimate_speed_from_extrusion_quality( - // FIXME convert estimate_speed_from_extrusion_quality() to smooth paths or move it before smooth path interpolation. - Points{}, path_attr, overhangs_with_speeds, overhang_w_fan_speeds, m_writer.extruder()->id(), external_perim_reference_speed, - speed); - variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(), - [speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; }); + dynamic_speed_and_fan_speed = ExtrusionProcessor::calculate_overhang_speed(path_attr, this->m_config, m_writer.extruder()->id(), + external_perim_reference_speed, speed); } - // bool variable_speed_or_fan_speed = false; - // std::vector new_points{}; - // if ((this->m_config.enable_dynamic_overhang_speeds || this->config().enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) && - // !this->on_first_layer() && path_attr.role.is_perimeter()) { - // std::vector> overhangs_with_speeds = {{100, ConfigOptionFloatOrPercent{speed, false}}}; - // if (this->m_config.enable_dynamic_overhang_speeds) { - // overhangs_with_speeds = {{0, m_config.overhang_speed_0}, - // {25, m_config.overhang_speed_1}, - // {50, m_config.overhang_speed_2}, - // {75, m_config.overhang_speed_3}, - // {100, ConfigOptionFloatOrPercent{speed, false}}}; - // } - - // std::vector> overhang_w_fan_speeds = {{100, ConfigOptionInts{0}}}; - // if (this->m_config.enable_dynamic_fan_speeds.get_at(m_writer.extruder()->id())) { - // overhang_w_fan_speeds = {{0, m_config.overhang_fan_speed_0}, - // {25, m_config.overhang_fan_speed_1}, - // {50, m_config.overhang_fan_speed_2}, - // {75, m_config.overhang_fan_speed_3}, - // {100, ConfigOptionInts{0}}}; - // } - - // double external_perim_reference_speed = m_config.get_abs_value("external_perimeter_speed"); - // if (external_perim_reference_speed == 0) - // external_perim_reference_speed = m_volumetric_speed / path_attr.mm3_per_mm; - // if (m_config.max_volumetric_speed.value > 0) - // external_perim_reference_speed = std::min(external_perim_reference_speed, m_config.max_volumetric_speed.value / path_attr.mm3_per_mm); - // if (EXTRUDER_CONFIG(filament_max_volumetric_speed) > 0) { - // external_perim_reference_speed = std::min(external_perim_reference_speed, - // EXTRUDER_CONFIG(filament_max_volumetric_speed) / path_attr.mm3_per_mm); - // } - - // new_points = m_extrusion_quality_estimator.estimate_speed_from_extrusion_quality( - // //FIXME convert estimate_speed_from_extrusion_quality() to smooth paths or move it before smooth path interpolation. - // Points{}, - // path_attr, overhangs_with_speeds, overhang_w_fan_speeds, - // m_writer.extruder()->id(), external_perim_reference_speed, - // speed); - // variable_speed_or_fan_speed = std::any_of(new_points.begin(), new_points.end(), - // [speed](const ProcessedPoint &p) { return p.speed != speed || p.fan_speed != 0; }); - // } + if (dynamic_speed_and_fan_speed.first > -1) { + speed = dynamic_speed_and_fan_speed.first; + } double F = speed * 60; // convert mm/sec to mm/min @@ -2919,86 +2858,62 @@ std::string GCodeGenerator::_extrude( cooling_marker_setspeed_comments += ";_EXTERNAL_PERIMETER"; } - //FIXME Variable speed on overhangs is inactive until the code is adapted to smooth path. - if (! variable_speed_or_fan_speed) { - // F is mm per minute. - gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments); - double path_length = 0.; - std::string comment; - if (m_config.gcode_comments) { - comment = description; - comment += description_bridge; - } - Vec2d prev = this->point_to_gcode_quantized(path.front().point); - auto it = path.begin(); - auto end = path.end(); - const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius; - for (++ it; it != end; ++ it) { - Vec2d p = this->point_to_gcode_quantized(it->point); - if (it->radius == 0) { - // Extrude line segment. - if (const double line_length = (p - prev).norm(); line_length > 0) { - path_length += line_length; - gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); - } - } else { - // Extrude an arc. - assert(m_config.arc_fitting == ArcFittingType::EmitCenter || - m_config.arc_fitting == ArcFittingType::EmitRadius); - double radius = unscaled(it->radius); - if (emit_radius) - // Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values. - radius = GCodeFormatter::quantize_xyzf(radius); - Vec2d ij; - if (! emit_radius) { - // Calculate quantized IJ circle center offset. - Vec2d center_raw = Geometry::ArcWelder::arc_center(prev.cast(), p.cast(), double(radius), it->ccw()) - prev; - ij = GCodeFormatter::quantize(center_raw); - } - double angle = Geometry::ArcWelder::arc_angle(prev.cast(), p.cast(), double(radius)); - assert(angle > 0); - const double line_length = angle * std::abs(radius); + // F is mm per minute. + gcode += m_writer.set_speed(F, "", cooling_marker_setspeed_comments); + if (dynamic_speed_and_fan_speed.second >= 0) + gcode += ";_SET_FAN_SPEED" + std::to_string(int(dynamic_speed_and_fan_speed.second)) + "\n"; + double path_length = 0.; + std::string comment; + if (m_config.gcode_comments) { + comment = description; + comment += description_bridge; + } + Vec2d prev = this->point_to_gcode_quantized(path.front().point); + auto it = path.begin(); + auto end = path.end(); + const bool emit_radius = m_config.arc_fitting == ArcFittingType::EmitRadius; + for (++ it; it != end; ++ it) { + Vec2d p = this->point_to_gcode_quantized(it->point); + if (it->radius == 0) { + // Extrude line segment. + if (const double line_length = (p - prev).norm(); line_length > 0) { path_length += line_length; - const double dE = e_per_mm * line_length; - assert(dE > 0); - gcode += emit_radius ? - m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), dE, comment) : - m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment); + gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); } - prev = p; - } - } else { - std::string marked_comment; - if (m_config.gcode_comments) { - marked_comment = description; - marked_comment += description_bridge; - } - double last_set_speed = new_points[0].speed * 60.0; - double last_set_fan_speed = new_points[0].fan_speed; - gcode += m_writer.set_speed(last_set_speed, "", cooling_marker_setspeed_comments); - gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n"; - Vec2d prev = this->point_to_gcode_quantized(new_points[0].p); - for (size_t i = 1; i < new_points.size(); i++) { - const ProcessedPoint &processed_point = new_points[i]; - Vec2d p = this->point_to_gcode_quantized(processed_point.p); - const double line_length = (p - prev).norm(); - gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, marked_comment); - prev = p; - double new_speed = processed_point.speed * 60.0; - if (last_set_speed != new_speed) { - gcode += m_writer.set_speed(new_speed, "", cooling_marker_setspeed_comments); - last_set_speed = new_speed; - } - if (last_set_fan_speed != processed_point.fan_speed) { - last_set_fan_speed = processed_point.fan_speed; - gcode += "\n;_SET_FAN_SPEED" + std::to_string(int(last_set_fan_speed)) + "\n"; + } else { + // Extrude an arc. + assert(m_config.arc_fitting == ArcFittingType::EmitCenter || + m_config.arc_fitting == ArcFittingType::EmitRadius); + double radius = unscaled(it->radius); + if (emit_radius) + // Only quantize radius if emitting it directly into G-code. Otherwise use the exact radius for calculating the IJ values. + radius = GCodeFormatter::quantize_xyzf(radius); + Vec2d ij; + if (! emit_radius) { + // Calculate quantized IJ circle center offset. + Vec2d center_raw = Geometry::ArcWelder::arc_center(prev.cast(), p.cast(), double(radius), it->ccw()) - prev; + ij = GCodeFormatter::quantize(center_raw); } + double angle = Geometry::ArcWelder::arc_angle(prev.cast(), p.cast(), double(radius)); + assert(angle > 0); + const double line_length = angle * std::abs(radius); + path_length += line_length; + const double dE = e_per_mm * line_length; + assert(dE > 0); + gcode += emit_radius ? + m_writer.extrude_to_xy_G2G3R(p, radius, it->ccw(), dE, comment) : + m_writer.extrude_to_xy_G2G3IJ(p, ij, it->ccw(), dE, comment); } - gcode += "\n;_RESET_FAN_SPEED\n"; + prev = p; } if (m_enable_cooling_markers) - gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n"; + gcode += path_attr.role.is_bridge() ? ";_BRIDGE_FAN_END" : ";_EXTRUDE_END"; + + if (dynamic_speed_and_fan_speed.second >= 0) + gcode += ";_RESET_FAN_SPEED"; + + gcode += "\n"; this->set_last_pos(path.back().point); return gcode; diff --git a/src/libslic3r/GCode/ExtrusionProcessor.cpp b/src/libslic3r/GCode/ExtrusionProcessor.cpp index 2481efb1e2..3f6aa5f5ed 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.cpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.cpp @@ -68,24 +68,27 @@ ExtrusionPaths calculate_and_split_overhanging_extrusions(const ExtrusionPath ExtrusionPaths result; ExtrusionAttributes new_attrs = path.attributes(); - new_attrs.overhang_attributes = std::optional({calculated_distances[0].first, calculated_distances[0].second}); + new_attrs.overhang_attributes = std::optional( + {calculated_distances[0].first, calculated_distances[0].first, calculated_distances[0].second}); result.emplace_back(new_attrs); result.back().polyline.append(Point::new_scale(extended_points[0].position)); + size_t sequence_start_index = 0; for (size_t i = 1; i < extended_points.size(); i++) { - if (std::abs(calculated_distances[i].first - calculated_distances[i - 1].first) < path.width() * 0.1 && - std::abs(calculated_distances[i].second - calculated_distances[i - 1].second) < 0.1) { + result.back().polyline.append(Point::new_scale(extended_points[i].position)); + result.back().overhang_attributes_mutable()->end_distance_from_prev_layer = extended_points[i].distance; + if (std::abs(calculated_distances[sequence_start_index].first - calculated_distances[i - 1].first) < path.width() * 0.05 && + std::abs(calculated_distances[sequence_start_index].second - calculated_distances[i - 1].second) < 0.05) { // do not start new path, the attributes are similar enough - } else { - result.back().polyline.append(Point::new_scale(extended_points[i].position)); - new_attrs.overhang_attributes->max_distance_from_prev_layer = calculated_distances[i].first; - new_attrs.overhang_attributes->proximity_to_curled_lines = calculated_distances[i].second; + } else if (i +1 < extended_points.size()) { // do not start new path if this is last point! + // start new path, parameters differ + new_attrs.overhang_attributes->start_distance_from_prev_layer = calculated_distances[i].first; + new_attrs.overhang_attributes->end_distance_from_prev_layer = calculated_distances[i].first; + new_attrs.overhang_attributes->proximity_to_curled_lines = calculated_distances[i].second; + sequence_start_index = i; result.emplace_back(new_attrs); } - result.back().polyline.append(Point::new_scale(extended_points[i].position)); } - std::cout << "ExtrusionPath " << std::to_string(size_t(&path)) << " split to " << result.size() << " paths"; - return result; }; @@ -129,4 +132,74 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions(const Extru return result; }; + +std::pair calculate_overhang_speed(const ExtrusionAttributes &attributes, + const FullPrintConfig &config, + size_t extruder_id, + float external_perim_reference_speed, + float default_speed) +{ + assert(attributes.overhang_attributes.has_value()); + std::vector> overhangs_with_speeds = { + {100, ConfigOptionFloatOrPercent{default_speed, false}}}; + if (config.enable_dynamic_overhang_speeds) { + overhangs_with_speeds = {{0, config.overhang_speed_0}, + {25, config.overhang_speed_1}, + {50, config.overhang_speed_2}, + {75, config.overhang_speed_3}, + {100, ConfigOptionFloatOrPercent{default_speed, false}}}; + } + + std::vector> overhang_with_fan_speeds = {{100, ConfigOptionInts{0}}}; + if (config.enable_dynamic_fan_speeds.get_at(extruder_id)) { + overhang_with_fan_speeds = {{0, config.overhang_fan_speed_0}, + {25, config.overhang_fan_speed_1}, + {50, config.overhang_fan_speed_2}, + {75, config.overhang_fan_speed_3}, + {100, ConfigOptionInts{0}}}; + } + + float speed_base = external_perim_reference_speed > 0 ? external_perim_reference_speed : default_speed; + std::map speed_sections; + for (size_t i = 0; i < overhangs_with_speeds.size(); i++) { + float distance = attributes.width * (1.0 - (overhangs_with_speeds[i].first / 100.0)); + float speed = overhangs_with_speeds[i].second.percent ? (speed_base * overhangs_with_speeds[i].second.value / 100.0) : + overhangs_with_speeds[i].second.value; + if (speed < EPSILON) + speed = speed_base; + speed_sections[distance] = speed; + } + + std::map fan_speed_sections; + for (size_t i = 0; i < overhang_with_fan_speeds.size(); i++) { + float distance = attributes.width * (1.0 - (overhang_with_fan_speeds[i].first / 100.0)); + float fan_speed = overhang_with_fan_speeds[i].second.get_at(extruder_id); + fan_speed_sections[distance] = fan_speed; + } + + auto interpolate_speed = [](const std::map &values, float distance) { + auto upper_dist = values.lower_bound(distance); + if (upper_dist == values.end()) { + return values.rbegin()->second; + } + if (upper_dist == values.begin()) { + return upper_dist->second; + } + + auto lower_dist = std::prev(upper_dist); + float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first); + return (1.0f - t) * lower_dist->second + t * upper_dist->second; + }; + + float extrusion_speed = std::min(interpolate_speed(speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer), + interpolate_speed(speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer)); + float curled_base_speed = interpolate_speed(speed_sections, + attributes.width * attributes.overhang_attributes->proximity_to_curled_lines); + float final_speed = std::min(curled_base_speed, extrusion_speed); + float fan_speed = std::min(interpolate_speed(fan_speed_sections, attributes.overhang_attributes->start_distance_from_prev_layer), + interpolate_speed(fan_speed_sections, attributes.overhang_attributes->end_distance_from_prev_layer)); + + return {final_speed, fan_speed}; +} + }} // namespace Slic3r::ExtrusionProcessor \ No newline at end of file diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index a9787f212f..dacb2d0f73 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -15,8 +15,10 @@ #include "../Config.hpp" #include "../Line.hpp" #include "../Exception.hpp" +#include "../PrintConfig.hpp" #include +#include #include #include #include @@ -227,147 +229,11 @@ ExtrusionEntityCollection calculate_and_split_overhanging_extrusions( const AABBTreeLines::LinesDistancer &unscaled_prev_layer, const AABBTreeLines::LinesDistancer &prev_layer_curled_lines); -struct ProcessedPoint -{ - Point p; - float speed = 1.0f; - int fan_speed = 0; -}; - -class ExtrusionQualityEstimator -{ - std::unordered_map> prev_layer_boundaries; - std::unordered_map> next_layer_boundaries; - std::unordered_map> prev_curled_extrusions; - std::unordered_map> next_curled_extrusions; - const PrintObject *current_object; - -public: - void set_current_object(const PrintObject *object) { current_object = object; } - - void prepare_for_new_layer(const Layer *layer) - { - if (layer == nullptr) - return; - const PrintObject *object = layer->object(); - prev_layer_boundaries[object] = next_layer_boundaries[object]; - next_layer_boundaries[object] = AABBTreeLines::LinesDistancer{to_unscaled_linesf(layer->lslices)}; - prev_curled_extrusions[object] = next_curled_extrusions[object]; - next_curled_extrusions[object] = AABBTreeLines::LinesDistancer{layer->curled_lines}; - } - - std::vector estimate_speed_from_extrusion_quality( - const Points &path, - const ExtrusionFlow &flow, - const std::vector> overhangs_w_speeds, - const std::vector> overhangs_w_fan_speeds, - size_t extruder_id, - float ext_perimeter_speed, - float original_speed) - { - float speed_base = ext_perimeter_speed > 0 ? ext_perimeter_speed : original_speed; - std::map speed_sections; - for (size_t i = 0; i < overhangs_w_speeds.size(); i++) { - float distance = flow.width * (1.0 - (overhangs_w_speeds[i].first / 100.0)); - float speed = overhangs_w_speeds[i].second.percent ? (speed_base * overhangs_w_speeds[i].second.value / 100.0) : - overhangs_w_speeds[i].second.value; - if (speed < EPSILON) - speed = speed_base; - speed_sections[distance] = speed; - } - - std::map fan_speed_sections; - for (size_t i = 0; i < overhangs_w_fan_speeds.size(); i++) { - float distance = flow.width * (1.0 - (overhangs_w_fan_speeds[i].first / 100.0)); - float fan_speed = overhangs_w_fan_speeds[i].second.get_at(extruder_id); - fan_speed_sections[distance] = fan_speed; - } - - std::vector extended_points = - estimate_points_properties(path, prev_layer_boundaries[current_object], flow.width); - - std::vector processed_points; - processed_points.reserve(extended_points.size()); - for (size_t i = 0; i < extended_points.size(); i++) { - const ExtendedPoint &curr = extended_points[i]; - const ExtendedPoint &next = extended_points[i + 1 < extended_points.size() ? i + 1 : i]; - - // The following code artifically increases the distance to provide slowdown for extrusions that are over curled lines - float artificial_distance_to_curled_lines = 0.0; - const double dist_limit = 10.0 * flow.width; - { - Vec2d middle = 0.5 * (curr.position + next.position); - auto line_indices = prev_curled_extrusions[current_object].all_lines_in_radius(Point::new_scale(middle), scale_(dist_limit)); - if (!line_indices.empty()) { - double len = (next.position - curr.position).norm(); - // For long lines, there is a problem with the additional slowdown. If by accident, there is small curled line near - // the middle of this long line - // The whole segment gets slower unnecesarily. For these long lines, we do additional check whether it is worth slowing - // down. - // NOTE that this is still quite rough approximation, e.g. we are still checking lines only near the middle point - // TODO maybe split the lines into smaller segments before running this alg? but can be demanding, and GCode will be huge - if (len > 8) { - Vec2d dir = Vec2d(next.position - curr.position) / len; - Vec2d right = Vec2d(-dir.y(), dir.x()); - - Polygon box_of_influence = { - scaled(Vec2d(curr.position + right * dist_limit)), - scaled(Vec2d(next.position + right * dist_limit)), - scaled(Vec2d(next.position - right * dist_limit)), - scaled(Vec2d(curr.position - right * dist_limit)), - }; - - double projected_lengths_sum = 0; - for (size_t idx : line_indices) { - const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx); - Lines inside = intersection_ln({{line.a, line.b}}, {box_of_influence}); - if (inside.empty()) - continue; - double projected_length = abs(dir.dot(unscaled(Vec2d((inside.back().b - inside.back().a).cast())))); - projected_lengths_sum += projected_length; - } - if (projected_lengths_sum < 0.4 * len) { - line_indices.clear(); - } - } - - for (size_t idx : line_indices) { - const CurledLine &line = prev_curled_extrusions[current_object].get_line(idx); - float distance_from_curled = unscaled(line_alg::distance_to(line, Point::new_scale(middle))); - float dist = flow.width * (1.0 - (distance_from_curled / dist_limit)) * - (1.0 - (distance_from_curled / dist_limit)) * - (line.curled_height / (flow.height * 10.0f)); // max_curled_height_factor from SupportSpotGenerator - artificial_distance_to_curled_lines = std::max(artificial_distance_to_curled_lines, dist); - } - } - } - - auto interpolate_speed = [](const std::map &values, float distance) { - auto upper_dist = values.lower_bound(distance); - if (upper_dist == values.end()) { - return values.rbegin()->second; - } - if (upper_dist == values.begin()) { - return upper_dist->second; - } - - auto lower_dist = std::prev(upper_dist); - float t = (distance - lower_dist->first) / (upper_dist->first - lower_dist->first); - return (1.0f - t) * lower_dist->second + t * upper_dist->second; - }; - - float extrusion_speed = std::min(interpolate_speed(speed_sections, curr.distance), - interpolate_speed(speed_sections, next.distance)); - float curled_base_speed = interpolate_speed(speed_sections, artificial_distance_to_curled_lines); - float final_speed = std::min(curled_base_speed, extrusion_speed); - float fan_speed = std::min(interpolate_speed(fan_speed_sections, curr.distance), - interpolate_speed(fan_speed_sections, next.distance)); - - processed_points.push_back({scaled(curr.position), final_speed, int(fan_speed)}); - } - return processed_points; - } -}; +std::pair calculate_overhang_speed(const ExtrusionAttributes &attributes, + const FullPrintConfig &config, + size_t extruder_id, + float external_perim_reference_speed, + float default_speed); }} // namespace Slic3r::ExtrusionProcessor diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp index 43e2937238..90e05ae78a 100644 --- a/src/libslic3r/PrintObject.cpp +++ b/src/libslic3r/PrintObject.cpp @@ -561,9 +561,10 @@ void PrintObject::calculate_overhanging_perimeters() continue; } ExPolygons prev_layer_polygon = l->lower_layer == nullptr ? ExPolygons() : l->lower_layer->lslices; - layer_region->m_perimeters = calculate_and_split_overhanging_extrusions(&layer_region->m_perimeters, - unscaled_polygons_lines[l->id()], - curled_lines[l->id()]); + layer_region->m_perimeters = + ExtrusionProcessor::calculate_and_split_overhanging_extrusions(&layer_region->m_perimeters, + unscaled_polygons_lines[l->id()], + curled_lines[l->id()]); } } diff --git a/src/libslic3r/SupportSpotsGenerator.cpp b/src/libslic3r/SupportSpotsGenerator.cpp index e1ae58fd21..8e52dcf6fc 100644 --- a/src/libslic3r/SupportSpotsGenerator.cpp +++ b/src/libslic3r/SupportSpotsGenerator.cpp @@ -327,10 +327,10 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit if (entity->length() < scale_(params.min_distance_to_allow_local_supports)) { return {}; } - const float flow_width = get_flow_width(layer_region, entity->role()); - std::vector annotated_points = estimate_points_properties(entity->as_polyline().points, - prev_layer_boundary, flow_width, - params.bridge_distance); + const float flow_width = get_flow_width(layer_region, entity->role()); + std::vector annotated_points = + ExtrusionProcessor::estimate_points_properties(entity->as_polyline().points, prev_layer_boundary, + flow_width, params.bridge_distance); std::vector lines_out; lines_out.reserve(annotated_points.size()); @@ -339,8 +339,8 @@ std::vector check_extrusion_entity_stability(const ExtrusionEntit std::optional bridging_dir{}; for (size_t i = 0; i < annotated_points.size(); ++i) { - ExtendedPoint &curr_point = annotated_points[i]; - const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + ExtrusionProcessor::ExtendedPoint &curr_point = annotated_points[i]; + const ExtrusionProcessor::ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i]; SupportPointCause potential_cause = std::abs(curr_point.curvature) > 0.1 ? SupportPointCause::FloatingBridgeAnchor : SupportPointCause::LongBridge; @@ -382,19 +382,19 @@ 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 - std::vector annotated_points = estimate_points_properties(entity->as_polyline().points, - prev_layer_lines, flow_width, - params.bridge_distance); + std::vector annotated_points = + ExtrusionProcessor::estimate_points_properties(entity->as_polyline().points, prev_layer_lines, + flow_width, params.bridge_distance); std::vector 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]; - const ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i]; - float line_len = (prev_point.position - curr_point.position).norm(); - ExtrusionLine line_out{prev_point.position.cast(), curr_point.position.cast(), line_len, entity}; + ExtrusionProcessor::ExtendedPoint &curr_point = annotated_points[i]; + const ExtrusionProcessor::ExtendedPoint &prev_point = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + float line_len = (prev_point.position - curr_point.position).norm(); + ExtrusionLine line_out{prev_point.position.cast(), curr_point.position.cast(), line_len, entity}; 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); @@ -1107,12 +1107,13 @@ void estimate_supports_malformations(SupportLayerPtrs &layers, float flow_width, Polygon pol(pl.points); pol.make_counter_clockwise(); - auto annotated_points = estimate_points_properties(pol.points, prev_layer_lines, flow_width); + auto annotated_points = ExtrusionProcessor::estimate_points_properties(pol.points, prev_layer_lines, + flow_width); for (size_t i = 0; i < annotated_points.size(); ++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()), + const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + const ExtrusionProcessor::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); @@ -1182,11 +1183,13 @@ 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 = estimate_points_properties(extrusion_pts, prev_layer_lines, flow_width, - params.bridge_distance); + auto annotated_points = ExtrusionProcessor::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 &b = annotated_points[i]; + const ExtrusionProcessor::ExtendedPoint &a = i > 0 ? annotated_points[i - 1] : annotated_points[i]; + const ExtrusionProcessor::ExtendedPoint &b = annotated_points[i]; ExtrusionLine line_out{a.position.cast(), b.position.cast(), float((a.position - b.position).norm()), extrusion}; @@ -1196,7 +1199,8 @@ void estimate_malformations(LayerPtrs &layers, const Params ¶ms) 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), l->height, flow_width, bottom_line.curled_up_height, params);