From b50aa3168515d23f536da4b3745deaacb2ba5a1e Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 29 May 2024 16:59:38 +0200 Subject: [PATCH 1/9] Seam (potentially) not on vertex for walls. For certain seam-types (user-specified and shortest). This implements it for walls only. CURA-9474 --- include/InsetOrderOptimizer.h | 2 ++ src/InsetOrderOptimizer.cpp | 48 ++++++++++++++++++++++++++++++++++- 2 files changed, 49 insertions(+), 1 deletion(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index f03a7fc461..d0e508fdd8 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -113,6 +113,8 @@ class InsetOrderOptimizer Shape retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see // retraction_region_calculated). + void insertSeamPoint(ExtrusionLine& closed_line); + /*! * Determine if the paths should be reversed * If there is one extruder used, and we're currently printing the inner walls then Reversing the insets now depends on the inverse of diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 7be4d8f6ba..91a8bd3a23 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -110,10 +110,11 @@ bool InsetOrderOptimizer::addToLayer() group_outer_walls, disallowed_areas_for_seams_); - for (const auto& line : walls_to_be_added) + for (auto& line : walls_to_be_added) { if (line.is_closed_) { + insertSeamPoint(line); order_optimizer.addPolygon(&line); } else @@ -164,6 +165,51 @@ bool InsetOrderOptimizer::addToLayer() return added_something; } +void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) +{ + assert(closed_line.is_closed_); + + Point2LL request_point; + switch (z_seam_config_.type_) + { + case EZSeamType::USER_SPECIFIED: request_point = z_seam_config_.pos_; break; + case EZSeamType::SHORTEST: request_point = gcode_layer_.getLastPlannedPositionOrStartingPosition(); break; + default: return; + } + + size_t closest_junction_idx = 0; + coord_t closest_distance_sqd = std::numeric_limits::max(); + for (const auto& [i, junction] : closed_line.junctions_ | ranges::views::enumerate) + { + const coord_t distance_sqd = vSize2(junction.p_ - request_point); + if (distance_sqd < closest_distance_sqd) + { + closest_distance_sqd = distance_sqd; + closest_junction_idx = i; + } + } + + const auto& start_pt = closed_line.junctions_[closest_junction_idx]; + const auto& end_pt = closed_line.junctions_[(closest_junction_idx + 1) % closed_line.junctions_.size()]; + const auto closest_point = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); + constexpr coord_t smallest_dist_sqd = 25; + if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - end_pt.p_) <= smallest_dist_sqd) + { + return; + } + + // NOTE: This could also be done on a single axis (skipping the implied sqrt), but figuring out which one and then using the right values became a bit messy/verbose. + const coord_t total_dist = vSize(end_pt.p_ - start_pt.p_); + const coord_t start_dist = vSize(closest_point - start_pt.p_); + const coord_t end_dist = vSize(closest_point - end_pt.p_); + const coord_t w = end_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; + + closed_line.junctions_.insert( + closed_line.junctions_.begin() + closest_junction_idx + 1, + ExtrusionJunction( closest_point, w, start_pt.perimeter_index_ ) + ); +} + InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::vector& extrusion_lines, const bool outer_to_inner) { if (extrusion_lines.empty()) From 03da1b10e1c7b048c417fe4705d360e054b5c5fe Mon Sep 17 00:00:00 2001 From: rburema Date: Wed, 29 May 2024 15:00:27 +0000 Subject: [PATCH 2/9] Applied clang-format. --- src/InsetOrderOptimizer.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 91a8bd3a23..710c456b7f 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -172,9 +172,14 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) Point2LL request_point; switch (z_seam_config_.type_) { - case EZSeamType::USER_SPECIFIED: request_point = z_seam_config_.pos_; break; - case EZSeamType::SHORTEST: request_point = gcode_layer_.getLastPlannedPositionOrStartingPosition(); break; - default: return; + case EZSeamType::USER_SPECIFIED: + request_point = z_seam_config_.pos_; + break; + case EZSeamType::SHORTEST: + request_point = gcode_layer_.getLastPlannedPositionOrStartingPosition(); + break; + default: + return; } size_t closest_junction_idx = 0; @@ -204,10 +209,7 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) const coord_t end_dist = vSize(closest_point - end_pt.p_); const coord_t w = end_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; - closed_line.junctions_.insert( - closed_line.junctions_.begin() + closest_junction_idx + 1, - ExtrusionJunction( closest_point, w, start_pt.perimeter_index_ ) - ); + closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + 1, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); } InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::vector& extrusion_lines, const bool outer_to_inner) From d22d3dea7c3708a190e698892a0e273e7cabeeb9 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 4 Jun 2024 15:44:42 +0200 Subject: [PATCH 3/9] Also take previous polygon-edge into account. part of CURA-9474 --- src/InsetOrderOptimizer.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 710c456b7f..5d7c95d742 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -194,22 +194,30 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) } } + const auto& before_pt = closed_line.junctions_[(closest_junction_idx + closed_line.junctions_.size() - 1) % closed_line.junctions_.size()]; const auto& start_pt = closed_line.junctions_[closest_junction_idx]; const auto& end_pt = closed_line.junctions_[(closest_junction_idx + 1) % closed_line.junctions_.size()]; - const auto closest_point = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); + const auto closest_point_a = LinearAlg2D::getClosestOnLineSegment(request_point, before_pt.p_, start_pt.p_); + const auto closest_point_b = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); + constexpr int direction_a = 0; + constexpr int direction_b = 1; + const auto& [closest_point, other_pt, direction] = + vSize2(closest_point_a - request_point) < vSize2(closest_point_b - request_point) ? + std::tie(closest_point_a, before_pt, direction_a) : + std::tie(closest_point_b, end_pt, direction_b); constexpr coord_t smallest_dist_sqd = 25; - if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - end_pt.p_) <= smallest_dist_sqd) + if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - other_pt.p_) <= smallest_dist_sqd) { return; } // NOTE: This could also be done on a single axis (skipping the implied sqrt), but figuring out which one and then using the right values became a bit messy/verbose. - const coord_t total_dist = vSize(end_pt.p_ - start_pt.p_); + const coord_t total_dist = vSize(other_pt.p_ - start_pt.p_); const coord_t start_dist = vSize(closest_point - start_pt.p_); - const coord_t end_dist = vSize(closest_point - end_pt.p_); - const coord_t w = end_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; + const coord_t end_dist = vSize(closest_point - other_pt.p_); + const coord_t w = other_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; - closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + 1, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); + closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + direction, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); } InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::vector& extrusion_lines, const bool outer_to_inner) From 15624d5dfcfebc6b97f754824410472fc35eea57 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 4 Jun 2024 13:47:20 +0000 Subject: [PATCH 4/9] Applied clang-format. --- src/InsetOrderOptimizer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 5d7c95d742..bd3f961f60 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -201,10 +201,9 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) const auto closest_point_b = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); constexpr int direction_a = 0; constexpr int direction_b = 1; - const auto& [closest_point, other_pt, direction] = - vSize2(closest_point_a - request_point) < vSize2(closest_point_b - request_point) ? - std::tie(closest_point_a, before_pt, direction_a) : - std::tie(closest_point_b, end_pt, direction_b); + const auto& [closest_point, other_pt, direction] = vSize2(closest_point_a - request_point) < vSize2(closest_point_b - request_point) + ? std::tie(closest_point_a, before_pt, direction_a) + : std::tie(closest_point_b, end_pt, direction_b); constexpr coord_t smallest_dist_sqd = 25; if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - other_pt.p_) <= smallest_dist_sqd) { From 88076047e2eadd3b551e5e934b840292fdc6f013 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 4 Jun 2024 17:10:13 +0200 Subject: [PATCH 5/9] Check closest against segments instead of points. Just to be sure. Also simplifies code a bit. part of CURA-9474 --- src/InsetOrderOptimizer.cpp | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index bd3f961f60..825230e90e 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -182,11 +182,13 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) return; } + //NOTE: Maybe rewrite this once we can use C++23 ranges::views::adjacent size_t closest_junction_idx = 0; coord_t closest_distance_sqd = std::numeric_limits::max(); for (const auto& [i, junction] : closed_line.junctions_ | ranges::views::enumerate) { - const coord_t distance_sqd = vSize2(junction.p_ - request_point); + const auto& next_junction = closed_line.junctions_[(i + 1) % closed_line.junctions_.size()]; + const coord_t distance_sqd = LinearAlg2D::getDist2FromLineSegment(junction.p_, request_point, next_junction.p_); if (distance_sqd < closest_distance_sqd) { closest_distance_sqd = distance_sqd; @@ -194,29 +196,22 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) } } - const auto& before_pt = closed_line.junctions_[(closest_junction_idx + closed_line.junctions_.size() - 1) % closed_line.junctions_.size()]; const auto& start_pt = closed_line.junctions_[closest_junction_idx]; const auto& end_pt = closed_line.junctions_[(closest_junction_idx + 1) % closed_line.junctions_.size()]; - const auto closest_point_a = LinearAlg2D::getClosestOnLineSegment(request_point, before_pt.p_, start_pt.p_); - const auto closest_point_b = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); - constexpr int direction_a = 0; - constexpr int direction_b = 1; - const auto& [closest_point, other_pt, direction] = vSize2(closest_point_a - request_point) < vSize2(closest_point_b - request_point) - ? std::tie(closest_point_a, before_pt, direction_a) - : std::tie(closest_point_b, end_pt, direction_b); + const auto closest_point = LinearAlg2D::getClosestOnLineSegment(request_point, start_pt.p_, end_pt.p_); constexpr coord_t smallest_dist_sqd = 25; - if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - other_pt.p_) <= smallest_dist_sqd) + if (vSize2(closest_point - start_pt.p_) <= smallest_dist_sqd || vSize2(closest_point - end_pt.p_) <= smallest_dist_sqd) { return; } // NOTE: This could also be done on a single axis (skipping the implied sqrt), but figuring out which one and then using the right values became a bit messy/verbose. - const coord_t total_dist = vSize(other_pt.p_ - start_pt.p_); + const coord_t total_dist = vSize(end_pt.p_ - start_pt.p_); const coord_t start_dist = vSize(closest_point - start_pt.p_); - const coord_t end_dist = vSize(closest_point - other_pt.p_); - const coord_t w = other_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; + const coord_t end_dist = vSize(closest_point - end_pt.p_); + const coord_t w = end_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; - closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + direction, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); + closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + 1, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); } InsetOrderOptimizer::value_type InsetOrderOptimizer::getRegionOrder(const std::vector& extrusion_lines, const bool outer_to_inner) From 891beb72946b02a391e41ea4f317f094a000a250 Mon Sep 17 00:00:00 2001 From: rburema Date: Tue, 4 Jun 2024 15:12:50 +0000 Subject: [PATCH 6/9] Applied clang-format. --- src/InsetOrderOptimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 825230e90e..491b86bc3d 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -182,7 +182,7 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) return; } - //NOTE: Maybe rewrite this once we can use C++23 ranges::views::adjacent + // NOTE: Maybe rewrite this once we can use C++23 ranges::views::adjacent size_t closest_junction_idx = 0; coord_t closest_distance_sqd = std::numeric_limits::max(); for (const auto& [i, junction] : closed_line.junctions_ | ranges::views::enumerate) From 8554db490bba9657ca1ddcc341e828452d18d661 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Wed, 5 Jun 2024 14:59:38 +0200 Subject: [PATCH 7/9] Make seam on-non-vertex-pos. code listen to setting. part of CURA-9474 --- src/InsetOrderOptimizer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index 491b86bc3d..f943058faf 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -114,7 +114,10 @@ bool InsetOrderOptimizer::addToLayer() { if (line.is_closed_) { - insertSeamPoint(line); + if (! settings_.get("z_seam_on_vertex")) + { + insertSeamPoint(line); + } order_optimizer.addPolygon(&line); } else From f9daec4478f9a954ae25ee0dafc69bda48e2f8e2 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 11 Jun 2024 09:31:08 +0200 Subject: [PATCH 8/9] Apply code-review comments. - Add comments to previously undocumented function. - Add round brackets to a foruma for readability. - Add assert to detect situations where the closed polygon loop has a strange numner of vertices. part of CURA-9474 --- include/InsetOrderOptimizer.h | 7 +++++++ src/InsetOrderOptimizer.cpp | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/InsetOrderOptimizer.h b/include/InsetOrderOptimizer.h index d0e508fdd8..3b242d8900 100644 --- a/include/InsetOrderOptimizer.h +++ b/include/InsetOrderOptimizer.h @@ -113,6 +113,13 @@ class InsetOrderOptimizer Shape retraction_region_; // After printing an outer wall, move into this region so that retractions do not leave visible blobs. Calculated lazily if needed (see // retraction_region_calculated). + /*! + * Given a closed polygon, insert a seam point at the point where the seam should be placed. + * This should result in the seam-finding algorithm finding that exact point, instead of the + * 'best' vertex on that polygon. Under certain circumstances, the seam-placing algorithm can + * however still deviate from this, for example when the seam-point placed here isn't suppored + * by the layer below. + */ void insertSeamPoint(ExtrusionLine& closed_line); /*! diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index f943058faf..b92d534841 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -171,6 +171,7 @@ bool InsetOrderOptimizer::addToLayer() void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) { assert(closed_line.is_closed_); + assert(closed_line.size() >= 3); Point2LL request_point; switch (z_seam_config_.type_) @@ -212,7 +213,7 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) const coord_t total_dist = vSize(end_pt.p_ - start_pt.p_); const coord_t start_dist = vSize(closest_point - start_pt.p_); const coord_t end_dist = vSize(closest_point - end_pt.p_); - const coord_t w = end_pt.w_ * end_dist / total_dist + start_pt.w_ * start_dist / total_dist; + const coord_t w = (end_pt.w_ * (end_dist / total_dist)) + (start_pt.w_ * (start_dist / total_dist)); closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + 1, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); } From bab5a095303abe2b127f0fe15e7999fea4576c20 Mon Sep 17 00:00:00 2001 From: Remco Burema Date: Tue, 18 Jun 2024 14:23:21 +0200 Subject: [PATCH 9/9] Fix integer-math mistake by (apply brackets correctly). Adding more brackets made this problem appear, since this is integer math and the total-dist might be large compared to the dividend. Shuffling the brackets around makes this ok. part of CURA-9497 --- src/InsetOrderOptimizer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/InsetOrderOptimizer.cpp b/src/InsetOrderOptimizer.cpp index b92d534841..c093aae5d2 100644 --- a/src/InsetOrderOptimizer.cpp +++ b/src/InsetOrderOptimizer.cpp @@ -213,7 +213,7 @@ void InsetOrderOptimizer::insertSeamPoint(ExtrusionLine& closed_line) const coord_t total_dist = vSize(end_pt.p_ - start_pt.p_); const coord_t start_dist = vSize(closest_point - start_pt.p_); const coord_t end_dist = vSize(closest_point - end_pt.p_); - const coord_t w = (end_pt.w_ * (end_dist / total_dist)) + (start_pt.w_ * (start_dist / total_dist)); + const coord_t w = ((end_pt.w_ * end_dist) / total_dist) + ((start_pt.w_ * start_dist) / total_dist); closed_line.junctions_.insert(closed_line.junctions_.begin() + closest_junction_idx + 1, ExtrusionJunction(closest_point, w, start_pt.perimeter_index_)); }