diff --git a/src/libslic3r/GCode/SmoothPath.cpp b/src/libslic3r/GCode/SmoothPath.cpp index 7c2e8b999c..30361aa3a7 100644 --- a/src/libslic3r/GCode/SmoothPath.cpp +++ b/src/libslic3r/GCode/SmoothPath.cpp @@ -31,75 +31,46 @@ std::optional sample_path_point_at_distance_from_start(const SmoothPath & { if (distance >= 0) { for (const SmoothPathElement &el : path) { - auto it = el.path.begin(); - auto end = el.path.end(); - Point prev_point = it->point; - for (++ it; it != end; ++ it) { - Point point = it->point; - if (it->linear()) { + Point prev_point = el.path.front().point; + for (auto segment_it = el.path.begin() + 1; segment_it != el.path.end(); ++segment_it) { + Point point = segment_it->point; + if (segment_it->linear()) { // Linear segment - Vec2d v = (point - prev_point).cast(); - double lsqr = v.squaredNorm(); + const Vec2d v = (point - prev_point).cast(); + const double lsqr = v.squaredNorm(); if (lsqr > sqr(distance)) - return std::make_optional(prev_point + (v * (distance / sqrt(lsqr))).cast()); + return prev_point + (v * (distance / sqrt(lsqr))).cast(); distance -= sqrt(lsqr); } else { // Circular segment - float angle = Geometry::ArcWelder::arc_angle(prev_point.cast(), point.cast(), it->radius); - double len = std::abs(it->radius) * angle; + const float angle = Geometry::ArcWelder::arc_angle(prev_point.cast(), point.cast(), segment_it->radius); + const double len = std::abs(segment_it->radius) * angle; if (len > distance) { - // Rotate the segment end point in reverse towards the start point. - return std::make_optional(prev_point.rotated(- angle * (distance / len), - Geometry::ArcWelder::arc_center(prev_point.cast(), point.cast(), it->radius, it->ccw()).cast())); + const Point center_pt = Geometry::ArcWelder::arc_center(prev_point.cast(), point.cast(), segment_it->radius, segment_it->ccw()).cast(); + const float rotation_dir = (segment_it->ccw() ? 1.f : -1.f); + // Rotate the segment start point based on the arc orientation. + return prev_point.rotated(rotation_dir * angle * (distance / len), center_pt); } + distance -= len; } + if (distance < 0) - return std::make_optional(point); + return point; + prev_point = point; } } } + // Failed. return {}; } -std::optional sample_path_point_at_distance_from_end(const SmoothPath &path, double distance) -{ - if (distance >= 0) { - for (const SmoothPathElement& el : path) { - auto it = el.path.begin(); - auto end = el.path.end(); - Point prev_point = it->point; - for (++it; it != end; ++it) { - Point point = it->point; - if (it->linear()) { - // Linear segment - Vec2d v = (point - prev_point).cast(); - double lsqr = v.squaredNorm(); - if (lsqr > sqr(distance)) - return std::make_optional(prev_point + (v * (distance / sqrt(lsqr))).cast()); - distance -= sqrt(lsqr); - } - else { - // Circular segment - float angle = Geometry::ArcWelder::arc_angle(prev_point.cast(), point.cast(), it->radius); - double len = std::abs(it->radius) * angle; - if (len > distance) { - // Rotate the segment end point in reverse towards the start point. - return std::make_optional(prev_point.rotated(-angle * (distance / len), - Geometry::ArcWelder::arc_center(prev_point.cast(), point.cast(), it->radius, it->ccw()).cast())); - } - distance -= len; - } - if (distance < 0) - return std::make_optional(point); - prev_point = point; - } - } - } - // Failed. - return {}; +std::optional sample_path_point_at_distance_from_end(const SmoothPath &path, double distance) { + SmoothPath path_reversed = path; + reverse(path_reversed); + return sample_path_point_at_distance_from_start(path_reversed, distance); } // Clip length of a smooth path, for seam hiding. diff --git a/src/libslic3r/GCode/Wipe.cpp b/src/libslic3r/GCode/Wipe.cpp index c773b0f8c3..b5f9151b03 100644 --- a/src/libslic3r/GCode/Wipe.cpp +++ b/src/libslic3r/GCode/Wipe.cpp @@ -211,7 +211,7 @@ std::optional wipe_hide_seam(const SmoothPath &path, bool is_hole, double // Wipe move cannot be calculated, the loop is not long enough. This should not happen due to the longer_than() test above. return {}; } - if (std::optional p = sample_path_point_at_distance_from_end(path, wipe_length); p) + if (std::optional p = sample_path_point_at_distance_from_start(path, wipe_length); p) p_prev = *p; else // Wipe move cannot be calculated, the loop is not long enough. This should not happen due to the longer_than() test above. @@ -231,7 +231,7 @@ std::optional wipe_hide_seam(const SmoothPath &path, bool is_hole, double } // Rotate the forward segment inside by 1/3 of the wedge angle. auto v_rotated = Eigen::Rotation2D(angle_inside) * (p_next - p_current).cast().normalized(); - return std::make_optional(p_current + (v_rotated * wipe_length).cast()); + return p_current + (v_rotated * wipe_length).cast(); } return {};