diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index dfd3bd82c..ffa90c354 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -2915,12 +2915,11 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de ); } - bool variable_speed = false; - double last_set_speed = 0.0; - std::vector points_quality{}; + bool variable_speed = false; + std::vector new_points{}; if (!this->on_first_layer() && is_perimeter(path.role())) { - points_quality = m_extrusion_quality_estimator.estimate_extrusion_quality(path); - variable_speed = std::any_of(points_quality.begin(), points_quality.end(), [](float q) { return q != 1.0; }); + new_points = m_extrusion_quality_estimator.estimate_extrusion_quality(path); + variable_speed = std::any_of(new_points.begin(), new_points.end(), [](const ProcessedPoint &p) { return p.speed_factor != 1.0; }); } double F = speed * 60; // convert mm/sec to mm/min @@ -2984,12 +2983,10 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de comment += ";_EXTERNAL_PERIMETER"; } - // F is mm per minute. - if (!variable_speed){ + if (!variable_speed) { + // F is mm per minute. gcode += m_writer.set_speed(F, "", comment); - } - - { + double path_length = 0.; std::string comment; if (m_config.gcode_comments) { comment = description; @@ -2998,23 +2995,36 @@ std::string GCode::_extrude(const ExtrusionPath &path, const std::string_view de Vec2d prev = this->point_to_gcode_quantized(path.polyline.points.front()); auto it = path.polyline.points.begin(); auto end = path.polyline.points.end(); - int i = 0; - for (++ it; it != end; ++ it) { - if (variable_speed) { - double new_speed = std::max(5.0, points_quality[i] * speed); - if (last_set_speed != new_speed) { - last_set_speed = new_speed; - gcode += m_writer.set_speed(new_speed * 60.0, "", comment); - } - } - - Vec2d p = this->point_to_gcode_quantized(*it); + for (++it; it != end; ++it) { + Vec2d p = this->point_to_gcode_quantized(*it); + const double line_length = (p - prev).norm(); + path_length += line_length; + gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); + prev = p; + } + } else { + std::string comment; + if (m_config.gcode_comments) { + comment = description; + comment += description_bridge; + } + double last_set_speed = std::max(5.0, new_points[0].speed_factor * speed) * 60.0; + gcode += m_writer.set_speed(last_set_speed, "", comment); + Vec2d prev = this->point_to_gcode_quantized(new_points[0].p); + for (size_t i = 1; i < new_points.size(); i++) { + const ProcessedPoint& procesed_point = new_points[i]; + Vec2d p = this->point_to_gcode_quantized(procesed_point.p); const double line_length = (p - prev).norm(); gcode += m_writer.extrude_to_xy(p, e_per_mm * line_length, comment); prev = p; - i++; + double new_speed = std::max(5.0, procesed_point.speed_factor * speed) * 60.0; + if (last_set_speed != new_speed) { + gcode += m_writer.set_speed(new_speed, "", comment); + last_set_speed = new_speed; + } } } + if (m_enable_cooling_markers) gcode += is_bridge(path.role()) ? ";_BRIDGE_FAN_END\n" : ";_EXTRUDE_END\n"; diff --git a/src/libslic3r/GCode/ExtrusionProcessor.hpp b/src/libslic3r/GCode/ExtrusionProcessor.hpp index c3225f79f..faa5df723 100644 --- a/src/libslic3r/GCode/ExtrusionProcessor.hpp +++ b/src/libslic3r/GCode/ExtrusionProcessor.hpp @@ -86,9 +86,10 @@ public: } }; -struct ProcessedPoint{ +struct ProcessedPoint +{ Point p; - float speed_factor; + float speed_factor = 1.0f; }; class ExtrusionQualityEstimator @@ -123,7 +124,7 @@ public: inside.insert(inside.end(), in.begin(), in.end()); } - ::Slic3r::SVG svg(debug_out_path(("path_jps" + std::to_string(rand() % 1000)).c_str()).c_str(), bb); + ::Slic3r::SVG svg(debug_out_path(("processing" + std::to_string(rand() % 1000)).c_str()).c_str(), bb); svg.draw(scaled_lines, "black", scale_(0.10)); for (Point p : inside) { auto [distance, line_idx, nearest_point] = next_layer_boundary.signed_distance_from_lines_extra(unscaled(p)); @@ -133,96 +134,96 @@ public: auto li = next_layer_boundary.get_line(line_idx); Line ls{Point::new_scale(li.a), Point::new_scale(li.b)}; svg.draw(ls, "yellow", scale_(0.2)); - - } } + + if (inside.size() > 0) { + Line line{inside[0], inside[inside.size() * 0.5]}; + auto inters = next_layer_boundary.intersections_with_line({unscaled(line.a), unscaled(line.b)}); + svg.draw(line, "purple", scale_(0.15)); + for (auto inter : inters) { + svg.draw(Point::new_scale(inter), "red", scale_(0.2)); + } + } + #endif } std::vector estimate_extrusion_quality(const ExtrusionPath &path) { - struct ExtendedPoint{ - Vec2f position; - float distance; + struct ExtendedPoint + { + ExtendedPoint(const Vec2d &pos, float dist, float quality) : position(pos), distance(dist), quality(quality) {} + Vec2d position; + float distance; // in multiples of flow_width + float quality; }; 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.7 * flow_width; + float min_malformation_dist = 0.2; - const Points& original_points = path.polyline.points; + const Points &original_points = path.polyline.points; std::vector points; - float distance = prev_layer_boundary.signed_distance_from_lines(unscaled(original_points[0])); - points.push_back({unscaled(original_points[0]).cast(),distance}); + float distance = prev_layer_boundary.signed_distance_from_lines(unscaled(original_points[0])) / flow_width + flow_width * 0.5f; + points.push_back({unscaled(original_points[0]), distance, 1.0f}); for (size_t i = 1; i < original_points.size(); i++) { - Vec2f next_point_pos = unscaled(original_points[i]).cast(); - float distance_of_next = prev_layer_boundary.signed_distance_from_lines(next_point_pos); - if ((points[i-1].distance > min_malformation_dist ) != (distance_of_next > min_malformation_dist)) { //not same sign, so one is grounded, one not - auto intersections = prev_layer_boundary.intersections_with_line({points[i-1].position, next_point_pos}); - for (const auto& intersection : intersections) { - points.push_back({intersection.cast(), 0.0f}); - } + Vec2d next_point_pos = unscaled(original_points[i]); + float distance_of_next = prev_layer_boundary.signed_distance_from_lines(next_point_pos) / flow_width + flow_width * 0.5f; + if ((points.back().distance > min_malformation_dist) != + (distance_of_next > min_malformation_dist)) { // not same sign, so one is grounded, one not + auto intersections = prev_layer_boundary.intersections_with_line({points.back().position, next_point_pos}); + for (const auto &intersection : intersections) { points.push_back({intersection, 0.0f, 1.0}); } } - points.push_back({next_point_pos, distance_of_next}); + points.push_back({next_point_pos, distance_of_next, 1.0}); } - for (int point_idx = 0; point_idx < int(points.size()); ++point_idx) { - const ExtendedPoint p = points[point_idx]; - double dist_from_prev_layer = prev_layer_boundary.signed_distance_from_lines(p.cast()) + flow_width * 0.5f; - - float default_dist_quality = 0.3f; - float distance_quality = 1.0f; - if (dist_from_prev_layer < min_malformation_dist) { - distance_quality = 1.0f; + for (int point_idx = 0; point_idx < int(points.size()) - 1; ++point_idx) { + ExtendedPoint &a = points[point_idx]; + ExtendedPoint &b = points[point_idx+1]; + if (a.distance < min_malformation_dist && b.distance < min_malformation_dist) { + a.quality = 1.0; 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; } - int prev_point_idx = point_idx; - while (prev_point_idx > 0) { - prev_point_idx--; - if ((p - points[prev_point_idx]).squaredNorm() > EPSILON) { break; } - } + float distance = fmax(a.distance, b.distance); + float distance_quality = 1.0f - fmin(1.0f, distance - min_malformation_dist); - 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; } - } + // int prev_point_idx = point_idx; + // while (prev_point_idx > 0) { + // prev_point_idx--; + // if ((b.position - points[prev_point_idx].position).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); + // int next_point_index = point_idx; + // while (next_point_index < int(points.size()) - 1) { + // next_point_index++; + // if ((b.position - points[next_point_index].position).squaredNorm() > EPSILON) { break; } + // } - 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; - } - } + // float curvature_penalty = 0.0f; + // if (prev_point_idx != point_idx && next_point_index != point_idx) { + // float distance = (b.position - a.position).norm(); + // float alfa = angle(b.position - points[prev_point_idx].position, points[next_point_index].position - b.position); + // cestim.add_point(distance, alfa); - point_qualities[point_idx] = std::clamp(distance_quality - curvature_penalty, 0.0f, 1.0f); + // float curvature = std::abs(cestim.get_curvature()); + // if (curvature > 1.0f) { + // curvature_penalty = 1.0f; + // } else if (curvature > 0.1f) { + // curvature_penalty = fmin(1.0, distance - min_malformation_dist) * curvature; + // } + // } + a.quality = std::clamp(distance_quality, 0.0f, 1.0f); } - 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]); - } + std::vector result; + result.reserve(points.size()); + for (const ExtendedPoint &p : points) { result.push_back({Point::new_scale(p.position), p.quality}); } - return point_qualities; + return result; } };