From 1e05d093240113bf9bfb7e6d5dab15e7f719f8d0 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Mon, 4 Jul 2022 14:43:58 +0200 Subject: [PATCH 01/14] search points based on updated linear regression model (line), make search raidus dynamic based on layer thickenss --- src/libslic3r/GCode/SeamPlacer.cpp | 59 +++++++++++++++++++++++------- src/libslic3r/GCode/SeamPlacer.hpp | 9 ++--- 2 files changed, 49 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 4185ae41b..aca4c7a3c 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -22,7 +22,7 @@ #include "libslic3r/Utils.hpp" -//#define DEBUG_FILES +#define DEBUG_FILES #ifdef DEBUG_FILES #include @@ -1135,16 +1135,12 @@ void SeamPlacer::calculate_overhangs_and_layer_embedding(const PrintObject *po) // Used by align_seam_points(). std::optional> SeamPlacer::find_next_seam_in_layer( const std::vector &layers, - const std::pair &prev_point_index, - const size_t layer_idx, const float slice_z, + const Vec3f& projected_position, + const size_t layer_idx, const float max_distance, const SeamPlacerImpl::SeamComparator &comparator) const { using namespace SeamPlacerImpl; - - const SeamCandidate &last_point = layers[prev_point_index.first].points[prev_point_index.second]; - - Vec3f projected_position { last_point.position.x(), last_point.position.y(), slice_z }; std::vector nearby_points_indices = find_nearby_points(*layers[layer_idx].points_tree, projected_position, - SeamPlacer::seam_align_tolerable_dist); + max_distance); if (nearby_points_indices.empty()) { return {}; @@ -1185,7 +1181,7 @@ std::optional> SeamPlacer::find_next_seam_in_layer( // First try to pick central enforcer if any present if (next_layer_seam.central_enforcer && (next_layer_seam.position - projected_position).squaredNorm() - < sqr(3 * SeamPlacer::seam_align_tolerable_dist)) { + < sqr(3 * max_distance)) { return {std::pair {layer_idx, nearest_point.perimeter.seam_index}}; } @@ -1214,13 +1210,28 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int next_layer = layer_idx + 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; + Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; + Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; //find seams or potential seams in forward direction; there is a budget of skips allowed while (next_layer < int(layers.size())) { - auto maybe_next_seam = find_next_seam_in_layer(layers, prev_point_index, next_layer, - float(po->get_layer(next_layer)->slice_z), comparator); - if (maybe_next_seam.has_value()) { + std::optional> maybe_next_seam; + float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); + float f = 2.71828f - logf(po->get_layer(next_layer)->height); + float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * f * f; + if (fabs(next_layer - layer_idx) > 3){ + Vec3f projected_position = origin_position + z_distance * surface_line_dir; + maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, + comparator); + } + if (!maybe_next_seam.has_value()) { + Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; + Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); + maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, + max_distance, comparator); + } + if (maybe_next_seam.has_value()) { // For old macOS (pre 10.14), std::optional does not have .value() method, so the code is using operator*() instead. std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; @@ -1235,6 +1246,9 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated + Vec3f line_dir = next_seam.position - origin_position; + surface_line_dir += line_dir / line_dir.z(); + surface_line_dir /= surface_line_dir.z(); } else { break; } @@ -1245,8 +1259,22 @@ std::vector> SeamPlacer::find_seam_string(const PrintO next_layer = layer_idx - 1; prev_point_index = std::pair(layer_idx, seam_index); while (next_layer >= 0) { - auto maybe_next_seam = find_next_seam_in_layer(layers, prev_point_index, next_layer, - float(po->get_layer(next_layer)->slice_z), comparator); + std::optional> maybe_next_seam; + float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); + float f = 2.71828f - logf(po->get_layer(next_layer)->height); + float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * f * f; + if (fabs(next_layer - layer_idx) > 3){ + Vec3f projected_position = origin_position + z_distance * surface_line_dir; + maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, + comparator); + } + if (!maybe_next_seam.has_value()) { + Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; + Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); + maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, + max_distance, comparator); + } + if (maybe_next_seam.has_value()) { std::pair next_seam_coords = maybe_next_seam.operator*(); @@ -1262,6 +1290,9 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated + Vec3f line_dir = next_seam.position - origin_position; + surface_line_dir += line_dir / line_dir.z(); + surface_line_dir /= surface_line_dir.z(); } else { break; } diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index cfad8c1ba..229e13731 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -128,7 +128,7 @@ public: // arm length used during angles computation static constexpr float polygon_local_angles_arm_distance = 0.3f; - static constexpr float sharp_angle_snapping_threshold = 0.3f * float(PI); + static constexpr float sharp_angle_snapping_threshold = 0.25f * float(PI); // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width static constexpr float overhang_distance_tolerance_factor = 0.5f; @@ -145,8 +145,7 @@ public: // When searching for seam clusters for alignment: // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer static constexpr float seam_align_score_tolerance = 0.3f; - // seam_align_tolerable_dist - if next layer closest point is too far away, break aligned string - static constexpr float seam_align_tolerable_dist = 1.0f; + static constexpr float seam_align_tolerable_dist_factor = 0.3f; // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 10; // points covered by spline; determines number of splines for the given string @@ -173,8 +172,8 @@ private: size_t& out_moved_seams_count) const; std::optional> find_next_seam_in_layer( const std::vector &layers, - const std::pair &prev_point_index, - const size_t layer_idx, const float slice_z, + const Vec3f& projected_position, + const size_t layer_idx, const float max_distance, const SeamPlacerImpl::SeamComparator &comparator) const; }; From fec3afa490fef26c46aea4114de3d08f5021e893 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Mon, 4 Jul 2022 17:02:25 +0200 Subject: [PATCH 02/14] cubic spline segment size based on the length of string --- src/libslic3r/GCode/SeamPlacer.cpp | 34 ++++++++++++------------------ src/libslic3r/GCode/SeamPlacer.hpp | 12 ++++++----- src/libslic3r/Geometry/Curves.hpp | 4 ++-- 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index aca4c7a3c..a42619668 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -22,7 +22,7 @@ #include "libslic3r/Utils.hpp" -#define DEBUG_FILES +//#define DEBUG_FILES #ifdef DEBUG_FILES #include @@ -1217,9 +1217,8 @@ std::vector> SeamPlacer::find_seam_string(const PrintO while (next_layer < int(layers.size())) { std::optional> maybe_next_seam; float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); - float f = 2.71828f - logf(po->get_layer(next_layer)->height); - float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * f * f; - if (fabs(next_layer - layer_idx) > 3){ + float max_distance = SeamPlacer::seam_align_tolerable_dist; + if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ Vec3f projected_position = origin_position + z_distance * surface_line_dir; maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, comparator); @@ -1246,9 +1245,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated - Vec3f line_dir = next_seam.position - origin_position; - surface_line_dir += line_dir / line_dir.z(); - surface_line_dir /= surface_line_dir.z(); + surface_line_dir += (next_seam.position - origin_position).normalized(); } else { break; } @@ -1261,10 +1258,9 @@ std::vector> SeamPlacer::find_seam_string(const PrintO while (next_layer >= 0) { std::optional> maybe_next_seam; float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); - float f = 2.71828f - logf(po->get_layer(next_layer)->height); - float max_distance = SeamPlacer::seam_align_tolerable_dist_factor * f * f; - if (fabs(next_layer - layer_idx) > 3){ - Vec3f projected_position = origin_position + z_distance * surface_line_dir; + float max_distance = SeamPlacer::seam_align_tolerable_dist; + if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ + Vec3f projected_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, comparator); } @@ -1290,9 +1286,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated - Vec3f line_dir = next_seam.position - origin_position; - surface_line_dir += line_dir / line_dir.z(); - surface_line_dir /= surface_line_dir.z(); + surface_line_dir += (next_seam.position - origin_position).normalized(); } else { break; } @@ -1402,20 +1396,20 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: weights.resize(seam_string.size()); //gather points positions and weights - // The algorithm uses only angle to compute penalty, to enforce snapping to sharp corners, if they are present - // after several experiments approach that gives best results is to snap the weight to one for sharp corners, and - // leave it small for others. However, this can result in non-smooth line over area with a lot of unaligned sharp corners. + float total_length = 0.0f; + Vec3f last_point_pos = layers[seam_string[0].first].points[seam_string[0].second].position; for (size_t index = 0; index < seam_string.size(); ++index) { Vec3f pos = layers[seam_string[index].first].points[seam_string[index].second].position; + total_length += (last_point_pos - pos).norm(); + last_point_pos = pos; observations[index] = pos.head<2>(); observation_points[index] = pos.z(); - weights[index] = std::min(1.0f, - comparator.weight(layers[seam_string[index].first].points[seam_string[index].second])); + weights[index] = comparator.weight(layers[seam_string[index].first].points[seam_string[index].second]); } // Curve Fitting size_t number_of_segments = std::max(size_t(1), - size_t(observations.size() / SeamPlacer::seam_align_seams_per_segment)); + size_t(total_length / SeamPlacer::seam_align_mm_per_segment)); auto curve = Geometry::fit_cubic_bspline(observations, observation_points, weights, number_of_segments); // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 229e13731..50eebb78f 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -128,7 +128,7 @@ public: // arm length used during angles computation static constexpr float polygon_local_angles_arm_distance = 0.3f; - static constexpr float sharp_angle_snapping_threshold = 0.25f * float(PI); + static constexpr float sharp_angle_snapping_threshold = 0.3f * float(PI); // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width static constexpr float overhang_distance_tolerance_factor = 0.5f; @@ -143,13 +143,15 @@ public: static constexpr float enforcer_oversampling_distance = 0.2f; // When searching for seam clusters for alignment: + static constexpr size_t seam_align_min_seams_for_linear_projection = 1; // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer static constexpr float seam_align_score_tolerance = 0.3f; - static constexpr float seam_align_tolerable_dist_factor = 0.3f; + // seam_align_tolerable_dist - if next layer closest point is too far away, break aligned string + static constexpr float seam_align_tolerable_dist = 3.0f; // minimum number of seams needed in cluster to make alignment happen - static constexpr size_t seam_align_minimum_string_seams = 10; - // points covered by spline; determines number of splines for the given string - static constexpr size_t seam_align_seams_per_segment = 16; + static constexpr size_t seam_align_minimum_string_seams = 6; + // millimeters covered by spline; determines number of splines for the given string + static constexpr size_t seam_align_mm_per_segment = 8.0f; //The following data structures hold all perimeter points for all PrintObject. std::unordered_map m_seam_per_object; diff --git a/src/libslic3r/Geometry/Curves.hpp b/src/libslic3r/Geometry/Curves.hpp index 5a0d5481f..6ccdea366 100644 --- a/src/libslic3r/Geometry/Curves.hpp +++ b/src/libslic3r/Geometry/Curves.hpp @@ -15,8 +15,8 @@ template struct PolynomialCurve { Eigen::MatrixXf coefficients; - Vec3f get_fitted_value(const NumberType value) const { - auto result = Vec::Zero(); + Vec get_fitted_value(const NumberType& value) const { + Vec result = Vec::Zero(); size_t order = this->coefficients.rows() - 1; auto x = NumberType(1.); for (size_t index = 0; index < order + 1; ++index, x *= value) From feeb9b2b1bd2989984841bf80a8908fcff11f89f Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Wed, 6 Jul 2022 10:32:05 +0200 Subject: [PATCH 03/14] bug fixes in the linear regression --- src/libslic3r/GCode/SeamPlacer.cpp | 6 +++--- src/libslic3r/GCode/SeamPlacer.hpp | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index a42619668..3a9d4a1cd 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1210,7 +1210,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int next_layer = layer_idx + 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; + Vec3f surface_line_dir { 0.0f, 0.0f, 20.0f }; Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; //find seams or potential seams in forward direction; there is a budget of skips allowed @@ -1219,7 +1219,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); float max_distance = SeamPlacer::seam_align_tolerable_dist; if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ - Vec3f projected_position = origin_position + z_distance * surface_line_dir; + Vec3f projected_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, comparator); } @@ -1286,7 +1286,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated - surface_line_dir += (next_seam.position - origin_position).normalized(); + surface_line_dir -= (next_seam.position - origin_position).normalized(); } else { break; } diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 50eebb78f..0a3315472 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -147,7 +147,7 @@ public: // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer static constexpr float seam_align_score_tolerance = 0.3f; // seam_align_tolerable_dist - if next layer closest point is too far away, break aligned string - static constexpr float seam_align_tolerable_dist = 3.0f; + static constexpr float seam_align_tolerable_dist = 1.5f; // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 6; // millimeters covered by spline; determines number of splines for the given string From 232517fe77c77d9a6fc79b221091d8a9eae57303 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Wed, 6 Jul 2022 12:24:04 +0200 Subject: [PATCH 04/14] choose seam string with lower variance weighted by visibility --- src/libslic3r/GCode/SeamPlacer.cpp | 45 +++++++++++++++++------------- src/libslic3r/GCode/SeamPlacer.hpp | 2 +- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 3a9d4a1cd..c8aa2945b 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1199,9 +1199,9 @@ std::optional> SeamPlacer::find_next_seam_in_layer( std::vector> SeamPlacer::find_seam_string(const PrintObject *po, std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator, - std::optional> &out_best_moved_seam, size_t &out_moved_seams_count) const { + std::optional> &out_best_moved_seam, float& seam_variance_out) const { out_best_moved_seam.reset(); - out_moved_seams_count = 0; + seam_variance_out = 0.0f; const std::vector &layers = m_seam_per_object.find(po)->second.layers; int layer_idx = start_seam.first; int seam_index = start_seam.second; @@ -1210,7 +1210,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int next_layer = layer_idx + 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f surface_line_dir { 0.0f, 0.0f, 20.0f }; + Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; //find seams or potential seams in forward direction; there is a budget of skips allowed @@ -1218,9 +1218,9 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::optional> maybe_next_seam; float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); float max_distance = SeamPlacer::seam_align_tolerable_dist; + Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ - Vec3f projected_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); - maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, + maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, comparator); } if (!maybe_next_seam.has_value()) { @@ -1235,7 +1235,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - out_moved_seams_count += is_moved; + seam_variance_out += next_seam.visibility * (linear_position - next_seam.position).squaredNorm(); if (is_moved && (!out_best_moved_seam.has_value() || comparator.is_first_better(next_seam, layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { @@ -1259,9 +1259,9 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::optional> maybe_next_seam; float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); float max_distance = SeamPlacer::seam_align_tolerable_dist; + Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ - Vec3f projected_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); - maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, + maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, comparator); } if (!maybe_next_seam.has_value()) { @@ -1272,11 +1272,10 @@ std::vector> SeamPlacer::find_seam_string(const PrintO } if (maybe_next_seam.has_value()) { - std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - out_moved_seams_count += is_moved; + seam_variance_out += next_seam.visibility * (linear_position - next_seam.position).squaredNorm(); if (is_moved && (!out_best_moved_seam.has_value() || comparator.is_first_better(next_seam, layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { @@ -1293,6 +1292,8 @@ std::vector> SeamPlacer::find_seam_string(const PrintO next_layer--; } + seam_variance_out /= float(seam_string.size()); + return seam_string; } @@ -1363,17 +1364,17 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: continue; } else { std::optional> best_moved_seam; - size_t moved_seams_count; + float seam_variance; seam_string = this->find_seam_string(po, { layer_idx, seam_index }, comparator, best_moved_seam, - moved_seams_count); + seam_variance); if (best_moved_seam.has_value()) { - size_t alternative_moved_seams_count; + float alternative_seam_variance; alternative_seam_string = this->find_seam_string(po, best_moved_seam.operator*(), comparator, - best_moved_seam, alternative_moved_seams_count); + best_moved_seam, alternative_seam_variance); if (alternative_seam_string.size() >= SeamPlacer::seam_align_minimum_string_seams && - alternative_moved_seams_count < moved_seams_count) { + alternative_seam_variance < seam_variance) { seam_string = std::move(alternative_seam_string); - // finish loop. but repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. + //repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. global_index--; } } @@ -1414,12 +1415,16 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into // Perimeter structure of the point; also set flag aligned to true + auto sigmoid_angle_snapping_func = [](float angle){ + float steepness = 10.0f; + float exp_val = steepness * (abs(angle) - SeamPlacer::sharp_angle_snapping_threshold); + float sig_term = exp(exp_val); + return sig_term / (sig_term + 1.0f); + }; + for (size_t index = 0; index < seam_string.size(); ++index) { const auto &pair = seam_string[index]; - const float t = - abs(layers[pair.first].points[pair.second].local_ccw_angle) - > SeamPlacer::sharp_angle_snapping_threshold - ? 1.0 : 0.0f; + float t = sigmoid_angle_snapping_func(layers[pair.first].points[pair.second].local_ccw_angle); Vec3f current_pos = layers[pair.first].points[pair.second].position; Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 0a3315472..de8992d0f 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -171,7 +171,7 @@ private: std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator, std::optional> &out_best_moved_seam, - size_t& out_moved_seams_count) const; + float& seam_variance_out) const; std::optional> find_next_seam_in_layer( const std::vector &layers, const Vec3f& projected_position, From f31865a627fb7d162f243850a0478c7bf6af3f8d Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Wed, 6 Jul 2022 14:11:22 +0200 Subject: [PATCH 05/14] increase weight of central seam enforcers --- src/libslic3r/GCode/SeamPlacer.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index c8aa2945b..68ff4710e 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -838,6 +838,9 @@ struct SeamComparator { } float weight(const SeamCandidate &a) const { + if (setup == SeamPosition::spAligned && a.central_enforcer) { + return 3.0f; + } return a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle) / (1.0f + angle_importance); } }; @@ -1210,7 +1213,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int next_layer = layer_idx + 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; + Vec3f surface_line_dir { 0.0f, 0.0f, 3.0f }; Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; //find seams or potential seams in forward direction; there is a budget of skips allowed @@ -1235,7 +1238,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - seam_variance_out += next_seam.visibility * (linear_position - next_seam.position).squaredNorm(); + seam_variance_out += (linear_position - next_seam.position).squaredNorm() * next_seam.visibility; if (is_moved && (!out_best_moved_seam.has_value() || comparator.is_first_better(next_seam, layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { @@ -1275,7 +1278,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - seam_variance_out += next_seam.visibility * (linear_position - next_seam.position).squaredNorm(); + seam_variance_out += (linear_position - next_seam.position).squaredNorm() * next_seam.visibility; if (is_moved && (!out_best_moved_seam.has_value() || comparator.is_first_better(next_seam, layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { @@ -1337,7 +1340,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: } //sort them before alignment. Alignment is sensitive to initializaion, this gives it better chance to choose something nice - std::sort(seams.begin(), seams.end(), + std::stable_sort(seams.begin(), seams.end(), [&comparator, &layers](const std::pair &left, const std::pair &right) { return comparator.is_first_better(layers[left.first].points[left.second], From 4d8e8afb10de5f7baff50431ae0d2aa93747f70d Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Thu, 7 Jul 2022 13:54:21 +0200 Subject: [PATCH 06/14] Count seam string weight and try mutiple strings; choose highest weight --- src/libslic3r/GCode/SeamPlacer.cpp | 66 +++++++++++++----------------- src/libslic3r/GCode/SeamPlacer.hpp | 8 ++-- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 68ff4710e..ca117badb 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1202,9 +1202,8 @@ std::optional> SeamPlacer::find_next_seam_in_layer( std::vector> SeamPlacer::find_seam_string(const PrintObject *po, std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator, - std::optional> &out_best_moved_seam, float& seam_variance_out) const { - out_best_moved_seam.reset(); - seam_variance_out = 0.0f; + float& string_weight) const { + string_weight = 0.0f; const std::vector &layers = m_seam_per_object.find(po)->second.layers; int layer_idx = start_seam.first; int seam_index = start_seam.second; @@ -1213,7 +1212,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int next_layer = layer_idx + 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f surface_line_dir { 0.0f, 0.0f, 3.0f }; + Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; //find seams or potential seams in forward direction; there is a budget of skips allowed @@ -1222,13 +1221,14 @@ std::vector> SeamPlacer::find_seam_string(const PrintO float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); float max_distance = SeamPlacer::seam_align_tolerable_dist; Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); - if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ + Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; + Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); + + if ((projected_position - linear_position).squaredNorm() < max_distance*max_distance){ maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, comparator); } if (!maybe_next_seam.has_value()) { - Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, max_distance, comparator); } @@ -1238,13 +1238,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - seam_variance_out += (linear_position - next_seam.position).squaredNorm() * next_seam.visibility; - if (is_moved && (!out_best_moved_seam.has_value() || - comparator.is_first_better(next_seam, - layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { - out_best_moved_seam = { next_seam_coords }; - } - + string_weight += comparator.weight(next_seam) - (linear_position - next_seam.position).squaredNorm(); seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated @@ -1263,7 +1257,10 @@ std::vector> SeamPlacer::find_seam_string(const PrintO float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); float max_distance = SeamPlacer::seam_align_tolerable_dist; Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); - if (fabs(next_layer - layer_idx) >= SeamPlacer::seam_align_min_seams_for_linear_projection){ + Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; + Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); + + if ((projected_position - linear_position).squaredNorm() < max_distance*max_distance){ maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, comparator); } @@ -1278,13 +1275,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - seam_variance_out += (linear_position - next_seam.position).squaredNorm() * next_seam.visibility; - if (is_moved && (!out_best_moved_seam.has_value() || - comparator.is_first_better(next_seam, - layers[out_best_moved_seam.operator*().first].points[out_best_moved_seam.operator*().second]))) { - out_best_moved_seam = { next_seam_coords }; - } - + string_weight += comparator.weight(next_seam) - (linear_position - next_seam.position).squaredNorm(); seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated @@ -1295,8 +1286,6 @@ std::vector> SeamPlacer::find_seam_string(const PrintO next_layer--; } - seam_variance_out /= float(seam_string.size()); - return seam_string; } @@ -1366,22 +1355,21 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: // This perimeter is already aligned, skip seam continue; } else { - std::optional> best_moved_seam; - float seam_variance; - seam_string = this->find_seam_string(po, { layer_idx, seam_index }, comparator, best_moved_seam, - seam_variance); - if (best_moved_seam.has_value()) { - float alternative_seam_variance; - alternative_seam_string = this->find_seam_string(po, best_moved_seam.operator*(), comparator, - best_moved_seam, alternative_seam_variance); + float seam_string_weight; + seam_string = this->find_seam_string(po, { layer_idx, seam_index }, comparator, seam_string_weight); + size_t step_size = 1 + seam_string.size() / 20; + for (size_t alternative_start = 0; alternative_start < seam_string.size(); alternative_start+=step_size) { + float alternative_seam_string_weight = 0; + size_t start_layer_idx = seam_string[alternative_start].first; + size_t seam_idx = layers[start_layer_idx].points[seam_string[alternative_start].second].perimeter.seam_index; + alternative_seam_string = this->find_seam_string(po, std::pair(start_layer_idx, seam_idx), comparator, + alternative_seam_string_weight); if (alternative_seam_string.size() >= SeamPlacer::seam_align_minimum_string_seams && - alternative_seam_variance < seam_variance) { + alternative_seam_string_weight > seam_string_weight) { + seam_string_weight = alternative_seam_string_weight; seam_string = std::move(alternative_seam_string); - //repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. - global_index--; } } - if (seam_string.size() < seam_align_minimum_string_seams) { //string NOT long enough to be worth aligning, skip continue; @@ -1394,6 +1382,9 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: return left.first < right.first; }); + //repeat the alignment for the current seam, since it could be skipped due to alternative path being aligned. + global_index--; + // gather all positions of seams and their weights (weights are derived as negative penalty, they are made positive in next step) observations.resize(seam_string.size()); observation_points.resize(seam_string.size()); @@ -1408,7 +1399,8 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: last_point_pos = pos; observations[index] = pos.head<2>(); observation_points[index] = pos.z(); - weights[index] = comparator.weight(layers[seam_string[index].first].points[seam_string[index].second]); + weights[index] = std::min(1.0f, + comparator.weight(layers[seam_string[index].first].points[seam_string[index].second])); } // Curve Fitting diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index de8992d0f..3a205fd92 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -143,15 +143,14 @@ public: static constexpr float enforcer_oversampling_distance = 0.2f; // When searching for seam clusters for alignment: - static constexpr size_t seam_align_min_seams_for_linear_projection = 1; // following value describes, how much worse score can point have and still be picked into seam cluster instead of original seam point on the same layer static constexpr float seam_align_score_tolerance = 0.3f; // seam_align_tolerable_dist - if next layer closest point is too far away, break aligned string - static constexpr float seam_align_tolerable_dist = 1.5f; + static constexpr float seam_align_tolerable_dist = 1.0f; // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 6; // millimeters covered by spline; determines number of splines for the given string - static constexpr size_t seam_align_mm_per_segment = 8.0f; + static constexpr size_t seam_align_mm_per_segment = 3.0f; //The following data structures hold all perimeter points for all PrintObject. std::unordered_map m_seam_per_object; @@ -170,8 +169,7 @@ private: std::vector> find_seam_string(const PrintObject *po, std::pair start_seam, const SeamPlacerImpl::SeamComparator &comparator, - std::optional> &out_best_moved_seam, - float& seam_variance_out) const; + float& string_weight) const; std::optional> find_next_seam_in_layer( const std::vector &layers, const Vec3f& projected_position, From c65e22e6bbcbfb87aa6e50effa9ea3291ad4ea93 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Thu, 7 Jul 2022 16:19:45 +0200 Subject: [PATCH 07/14] refactored find_seam_string func --- src/libslic3r/GCode/SeamPlacer.cpp | 93 +++++++++++------------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index ca117badb..a63aae3f1 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1210,80 +1210,57 @@ std::vector> SeamPlacer::find_seam_string(const PrintO //initialize searching for seam string - cluster of nearby seams on previous and next layers int next_layer = layer_idx + 1; + int step = 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f surface_line_dir { 0.0f, 0.0f, 1.0f }; - Vec3f origin_position = layers[start_seam.first].points[start_seam.second].position; + Vec3f straightening_dir { 0.0f, 0.0f, 1.0f }; - //find seams or potential seams in forward direction; there is a budget of skips allowed - while (next_layer < int(layers.size())) { - std::optional> maybe_next_seam; - float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); - float max_distance = SeamPlacer::seam_align_tolerable_dist; - Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); + auto reverse_lookup_direction = [&]() { + step = -1; + prev_point_index = start_seam; + straightening_dir = Vec3f(0.0f, 0.0f, -1.0f); + next_layer = layer_idx - 1; + }; + + while (next_layer >= 0) { + if (next_layer >= layers.size()) { + reverse_lookup_direction(); + if (next_layer < 0) { + break; + } + } + float max_distance = SeamPlacer::seam_align_tolerable_dist + straightening_dir.head<2>().norm(); Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); + float z_diff = fabs(float(po->get_layer(next_layer)->slice_z) - prev_position.z()); + Vec3f projected_position = prev_position + z_diff * straightening_dir / fabs(straightening_dir.z()); - if ((projected_position - linear_position).squaredNorm() < max_distance*max_distance){ - maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, - comparator); - } - if (!maybe_next_seam.has_value()) { - maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, - max_distance, comparator); - } + std::optional> maybe_next_seam = find_next_seam_in_layer(layers, projected_position, + next_layer, + max_distance, comparator); if (maybe_next_seam.has_value()) { // For old macOS (pre 10.14), std::optional does not have .value() method, so the code is using operator*() instead. std::pair next_seam_coords = maybe_next_seam.operator*(); const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - string_weight += comparator.weight(next_seam) - (linear_position - next_seam.position).squaredNorm(); + string_weight += comparator.weight(next_seam) - + is_moved ? comparator.weight(layers[next_seam_coords.first].points[next_seam.perimeter.seam_index]) : 0.0f; seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated - surface_line_dir += (next_seam.position - origin_position).normalized(); + Vec3f dir = (next_seam.position - prev_position); + straightening_dir = Vec3f(-dir.x()* 0.5f , -dir.y() * 0.5f, dir.z()); } else { - break; + if (step == 1) { + reverse_lookup_direction(); + if (next_layer < 0) { + break; + } + } else { + break; + } } - next_layer++; - } - - //do additional check in back direction - next_layer = layer_idx - 1; - prev_point_index = std::pair(layer_idx, seam_index); - while (next_layer >= 0) { - std::optional> maybe_next_seam; - float z_distance = float(po->get_layer(next_layer)->slice_z) - origin_position.z(); - float max_distance = SeamPlacer::seam_align_tolerable_dist; - Vec3f linear_position = origin_position + z_distance * (surface_line_dir / surface_line_dir.z()); - Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); - - if ((projected_position - linear_position).squaredNorm() < max_distance*max_distance){ - maybe_next_seam = find_next_seam_in_layer(layers, linear_position, next_layer, max_distance, - comparator); - } - if (!maybe_next_seam.has_value()) { - Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - Vec3f projected_position(prev_position.x(), prev_position.y(), float(po->get_layer(next_layer)->slice_z)); - maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, - max_distance, comparator); - } - - if (maybe_next_seam.has_value()) { - std::pair next_seam_coords = maybe_next_seam.operator*(); - const auto &next_seam = layers[next_seam_coords.first].points[next_seam_coords.second]; - bool is_moved = next_seam.perimeter.seam_index != next_seam_coords.second; - string_weight += comparator.weight(next_seam) - (linear_position - next_seam.position).squaredNorm(); - seam_string.push_back(maybe_next_seam.operator*()); - prev_point_index = seam_string.back(); - //String added, prev_point_index updated - surface_line_dir -= (next_seam.position - origin_position).normalized(); - } else { - break; - } - next_layer--; + next_layer += step; } return seam_string; From 768bfd5c7f3ffd345aa49d75bf37d61740a99648 Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Thu, 7 Jul 2022 16:56:07 +0200 Subject: [PATCH 08/14] reduce curling --- src/libslic3r/GCode/SeamPlacer.cpp | 2 +- src/libslic3r/GCode/SeamPlacer.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index a63aae3f1..950b3d064 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -1249,7 +1249,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO prev_point_index = seam_string.back(); //String added, prev_point_index updated Vec3f dir = (next_seam.position - prev_position); - straightening_dir = Vec3f(-dir.x()* 0.5f , -dir.y() * 0.5f, dir.z()); + straightening_dir = Vec3f(-dir.x()*0.7, -dir.y()*0.7, dir.z()); } else { if (step == 1) { reverse_lookup_direction(); diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 3a205fd92..1a8be9bc2 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -150,7 +150,7 @@ public: // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 6; // millimeters covered by spline; determines number of splines for the given string - static constexpr size_t seam_align_mm_per_segment = 3.0f; + static constexpr size_t seam_align_mm_per_segment = 8.0f; //The following data structures hold all perimeter points for all PrintObject. std::unordered_map m_seam_per_object; From 40408c2178798417693358d389afa3a3c042e1a0 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Fri, 8 Jul 2022 19:35:26 +0200 Subject: [PATCH 09/14] increase snapping angle --- src/libslic3r/GCode/SeamPlacer.cpp | 19 +++++++------------ src/libslic3r/GCode/SeamPlacer.hpp | 6 +++--- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 950b3d064..8b48d181c 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -839,7 +839,7 @@ struct SeamComparator { float weight(const SeamCandidate &a) const { if (setup == SeamPosition::spAligned && a.central_enforcer) { - return 3.0f; + return 2.0f; } return a.visibility + angle_importance * compute_angle_penalty(a.local_ccw_angle) / (1.0f + angle_importance); } @@ -1206,7 +1206,6 @@ std::vector> SeamPlacer::find_seam_string(const PrintO string_weight = 0.0f; const std::vector &layers = m_seam_per_object.find(po)->second.layers; int layer_idx = start_seam.first; - int seam_index = start_seam.second; //initialize searching for seam string - cluster of nearby seams on previous and next layers int next_layer = layer_idx + 1; @@ -1223,7 +1222,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO }; while (next_layer >= 0) { - if (next_layer >= layers.size()) { + if (next_layer >= int(layers.size())) { reverse_lookup_direction(); if (next_layer < 0) { break; @@ -1249,7 +1248,7 @@ std::vector> SeamPlacer::find_seam_string(const PrintO prev_point_index = seam_string.back(); //String added, prev_point_index updated Vec3f dir = (next_seam.position - prev_position); - straightening_dir = Vec3f(-dir.x()*0.7, -dir.y()*0.7, dir.z()); + straightening_dir = Vec3f(-dir.x()*0.0, -dir.y()*0.0, dir.z()); } else { if (step == 1) { reverse_lookup_direction(); @@ -1387,16 +1386,12 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: // Do alignment - compute fitted point for each point in the string from its Z coord, and store the position into // Perimeter structure of the point; also set flag aligned to true - auto sigmoid_angle_snapping_func = [](float angle){ - float steepness = 10.0f; - float exp_val = steepness * (abs(angle) - SeamPlacer::sharp_angle_snapping_threshold); - float sig_term = exp(exp_val); - return sig_term / (sig_term + 1.0f); - }; - for (size_t index = 0; index < seam_string.size(); ++index) { const auto &pair = seam_string[index]; - float t = sigmoid_angle_snapping_func(layers[pair.first].points[pair.second].local_ccw_angle); + const float t = + abs(layers[pair.first].points[pair.second].local_ccw_angle) + > SeamPlacer::sharp_angle_snapping_threshold + ? 1.0 : 0.0f; Vec3f current_pos = layers[pair.first].points[pair.second].position; Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 1a8be9bc2..3e2f348e0 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -127,8 +127,8 @@ public: static constexpr size_t sqr_rays_per_sample_point = 5; // arm length used during angles computation - static constexpr float polygon_local_angles_arm_distance = 0.3f; - static constexpr float sharp_angle_snapping_threshold = 0.3f * float(PI); + static constexpr float polygon_local_angles_arm_distance = 1.5f; + static constexpr float sharp_angle_snapping_threshold = 0.4f * float(PI); // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width static constexpr float overhang_distance_tolerance_factor = 0.5f; @@ -150,7 +150,7 @@ public: // minimum number of seams needed in cluster to make alignment happen static constexpr size_t seam_align_minimum_string_seams = 6; // millimeters covered by spline; determines number of splines for the given string - static constexpr size_t seam_align_mm_per_segment = 8.0f; + static constexpr size_t seam_align_mm_per_segment = 4.0f; //The following data structures hold all perimeter points for all PrintObject. std::unordered_map m_seam_per_object; From 4a9f9aa89bcdac1762a7df5cbc39391839df12fe Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Mon, 11 Jul 2022 17:38:06 +0200 Subject: [PATCH 10/14] oversample smooth surfaces, which reduces curling on those surfaces, because the shortest path down is better defined --- src/libslic3r/GCode/SeamPlacer.cpp | 44 ++++++++++++++++++++++-------- src/libslic3r/GCode/SeamPlacer.hpp | 5 ++-- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 8b48d181c..430030184 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -461,17 +461,41 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const if (orig_polygon.size() == 0) { return; } - Polygon polygon = orig_polygon; + bool was_clockwise = polygon.make_counter_clockwise(); + std::vector lengths { }; for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); } lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); - - bool was_clockwise = polygon.make_counter_clockwise(); - std::vector local_angles = calculate_polygon_angles_at_vertices(polygon, lengths, + std::vector polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, SeamPlacer::polygon_local_angles_arm_distance); + std::vector global_angles = calculate_polygon_angles_at_vertices(polygon, lengths, + SeamPlacer::polygon_global_angles_arm_distance); + for (size_t angle_index = 0; angle_index < polygon_angles.size(); ++angle_index) { + if (fabs(global_angles[angle_index] > fabs(polygon_angles[angle_index]))){ + polygon_angles[angle_index] = global_angles[angle_index]; + } + } + + // resample smooth surfaces, so that alignment finds short path down, and does not create unnecesary curves + if (std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) { + return fabs(angle) < SeamPlacer::sharp_angle_snapping_threshold; + })) { + float avg_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f) / float(lengths.size()); + coord_t sampling_dist = scaled(avg_dist*0.2f); + + polygon.points = polygon.equally_spaced_points(sampling_dist); + lengths.clear(); + for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { + lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); + } + lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); + polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, + SeamPlacer::polygon_global_angles_arm_distance); + } + result.perimeters.push_back( { }); Perimeter &perimeter = result.perimeters.back(); @@ -498,7 +522,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const } else { position = orig_polygon_points.front(); orig_polygon_points.pop(); - local_ccw_angle = was_clockwise ? -local_angles[orig_angle_index] : local_angles[orig_angle_index]; + local_ccw_angle = was_clockwise ? -polygon_angles[orig_angle_index] : polygon_angles[orig_angle_index]; orig_angle_index++; orig_point = true; } @@ -1212,12 +1236,10 @@ std::vector> SeamPlacer::find_seam_string(const PrintO int step = 1; std::pair prev_point_index = start_seam; std::vector> seam_string { start_seam }; - Vec3f straightening_dir { 0.0f, 0.0f, 1.0f }; auto reverse_lookup_direction = [&]() { step = -1; prev_point_index = start_seam; - straightening_dir = Vec3f(0.0f, 0.0f, -1.0f); next_layer = layer_idx - 1; }; @@ -1228,10 +1250,10 @@ std::vector> SeamPlacer::find_seam_string(const PrintO break; } } - float max_distance = SeamPlacer::seam_align_tolerable_dist + straightening_dir.head<2>().norm(); + float max_distance = SeamPlacer::seam_align_tolerable_dist; Vec3f prev_position = layers[prev_point_index.first].points[prev_point_index.second].position; - float z_diff = fabs(float(po->get_layer(next_layer)->slice_z) - prev_position.z()); - Vec3f projected_position = prev_position + z_diff * straightening_dir / fabs(straightening_dir.z()); + Vec3f projected_position = prev_position; + projected_position.z() = float(po->get_layer(next_layer)->slice_z); std::optional> maybe_next_seam = find_next_seam_in_layer(layers, projected_position, next_layer, @@ -1247,8 +1269,6 @@ std::vector> SeamPlacer::find_seam_string(const PrintO seam_string.push_back(maybe_next_seam.operator*()); prev_point_index = seam_string.back(); //String added, prev_point_index updated - Vec3f dir = (next_seam.position - prev_position); - straightening_dir = Vec3f(-dir.x()*0.0, -dir.y()*0.0, dir.z()); } else { if (step == 1) { reverse_lookup_direction(); diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 3e2f348e0..2c66fd5d6 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -127,8 +127,9 @@ public: static constexpr size_t sqr_rays_per_sample_point = 5; // arm length used during angles computation - static constexpr float polygon_local_angles_arm_distance = 1.5f; - static constexpr float sharp_angle_snapping_threshold = 0.4f * float(PI); + static constexpr float polygon_local_angles_arm_distance = 0.3f; + static constexpr float polygon_global_angles_arm_distance = 1.5f; + static constexpr float sharp_angle_snapping_threshold = (60.0f / 180.0f) * float(PI); // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width static constexpr float overhang_distance_tolerance_factor = 0.5f; From f5efb0d0aa87a062ce19b3329919c735d17abf50 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Mon, 11 Jul 2022 18:44:34 +0200 Subject: [PATCH 11/14] remove global angle computation, wrong results --- src/libslic3r/GCode/SeamPlacer.cpp | 27 +++++++++++---------------- src/libslic3r/GCode/SeamPlacer.hpp | 1 - 2 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 430030184..6213d44e5 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -471,29 +471,24 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); std::vector polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, SeamPlacer::polygon_local_angles_arm_distance); - std::vector global_angles = calculate_polygon_angles_at_vertices(polygon, lengths, - SeamPlacer::polygon_global_angles_arm_distance); - for (size_t angle_index = 0; angle_index < polygon_angles.size(); ++angle_index) { - if (fabs(global_angles[angle_index] > fabs(polygon_angles[angle_index]))){ - polygon_angles[angle_index] = global_angles[angle_index]; - } - } // resample smooth surfaces, so that alignment finds short path down, and does not create unnecesary curves if (std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) { return fabs(angle) < SeamPlacer::sharp_angle_snapping_threshold; })) { - float avg_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f) / float(lengths.size()); - coord_t sampling_dist = scaled(avg_dist*0.2f); + float total_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f); + float avg_dist = total_dist / float(lengths.size()); + if (avg_dist < SeamPlacer::seam_align_tolerable_dist * 2.0f){ + coord_t sampling_dist = scaled(avg_dist*0.2f); - polygon.points = polygon.equally_spaced_points(sampling_dist); - lengths.clear(); - for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { - lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); + polygon.points = polygon.equally_spaced_points(sampling_dist); + lengths.clear(); + for (size_t point_idx = 0; point_idx < polygon.size() - 1; ++point_idx) { + lengths.push_back((unscale(polygon[point_idx]) - unscale(polygon[point_idx + 1])).norm()); + } + lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); + polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, avg_dist); } - lengths.push_back(std::max((unscale(polygon[0]) - unscale(polygon[polygon.size() - 1])).norm(), 0.1)); - polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, - SeamPlacer::polygon_global_angles_arm_distance); } diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 2c66fd5d6..ae7a1a2ab 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -128,7 +128,6 @@ public: // arm length used during angles computation static constexpr float polygon_local_angles_arm_distance = 0.3f; - static constexpr float polygon_global_angles_arm_distance = 1.5f; static constexpr float sharp_angle_snapping_threshold = (60.0f / 180.0f) * float(PI); // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width From d5d1633e2b824995c22291215a759e70474a5bb8 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Tue, 12 Jul 2022 09:10:42 +0200 Subject: [PATCH 12/14] Bugfix: seam enforcers and blockers not respected on different nozzle widths - now flow width is used instead of fixed distance param --- src/libslic3r/GCode/SeamPlacer.cpp | 4 ++-- src/libslic3r/GCode/SeamPlacer.hpp | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 6213d44e5..ee6bde8d8 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -522,11 +522,11 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const orig_point = true; } - if (global_model_info.is_enforced(position, SeamPlacer::enforcer_blocker_distance_tolerance)) { + if (global_model_info.is_enforced(position, perimeter.flow_width)) { type = EnforcedBlockedSeamPoint::Enforced; } - if (global_model_info.is_blocked(position, SeamPlacer::enforcer_blocker_distance_tolerance)) { + if (global_model_info.is_blocked(position, perimeter.flow_width)) { type = EnforcedBlockedSeamPoint::Blocked; } some_point_enforced = some_point_enforced || type == EnforcedBlockedSeamPoint::Enforced; diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index ae7a1a2ab..69c53767b 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -135,10 +135,8 @@ public: // determines angle importance compared to visibility ( neutral value is 1.0f. ) static constexpr float angle_importance_aligned = 0.6f; - static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visiblity info noise + static constexpr float angle_importance_nearest = 1.0f; // use much higher angle importance for nearest mode, to combat the visibility info noise - // If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocker or Enforcer - static constexpr float enforcer_blocker_distance_tolerance = 0.35f; // For long polygon sides, if they are close to the custom seam drawings, they are oversampled with this step size static constexpr float enforcer_oversampling_distance = 0.2f; From 2e437d17615d3c55ef0af66ddc7c22645d9c3413 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Thu, 14 Jul 2022 11:47:29 +0200 Subject: [PATCH 13/14] curling improvements --- src/libslic3r/GCode/SeamPlacer.cpp | 36 +++++++++++++++--------------- src/libslic3r/GCode/SeamPlacer.hpp | 3 ++- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index ee6bde8d8..f81521660 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -64,6 +64,16 @@ float gauss(float value, float mean_x_coord, float mean_value, float falloff_spe return mean_value * (std::exp(exponent) - 1.0f) / (std::exp(1.0f) - 1.0f); } +float compute_angle_penalty(float ccw_angle) { + // This function is used: + // ((ℯ^(((1)/(x^(2)*3+1)))-1)/(ℯ-1))*1+((1)/(2+ℯ^(-x))) + // looks scary, but it is gaussian combined with sigmoid, + // so that concave points have much smaller penalty over convex ones + // https://github.com/prusa3d/PrusaSlicer/tree/master/doc/seam_placement/corner_penalty_function.png + return gauss(ccw_angle, 0.0f, 1.0f, 3.0f) + + 1.0f / (2 + std::exp(-ccw_angle)); +} + /// Coordinate frame class Frame { public: @@ -474,7 +484,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const // resample smooth surfaces, so that alignment finds short path down, and does not create unnecesary curves if (std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) { - return fabs(angle) < SeamPlacer::sharp_angle_snapping_threshold; + return compute_angle_penalty(angle) > SeamPlacer::sharp_angle_penalty_snapping_threshold; })) { float total_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f); float avg_dist = total_dist / float(lengths.size()); @@ -579,7 +589,8 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const break; } viable_points_indices.push_back(last_enforced_idx); - if (abs(result.points[last_enforced_idx].local_ccw_angle) > SeamPlacer::sharp_angle_snapping_threshold) { + if (compute_angle_penalty(result.points[last_enforced_idx].local_ccw_angle) + < SeamPlacer::sharp_angle_penalty_snapping_threshold) { orig_large_angle_points_indices.push_back(last_enforced_idx); } last_enforced_idx = next_index(last_enforced_idx); @@ -846,16 +857,6 @@ struct SeamComparator { return is_first_not_much_worse(a, b) && is_first_not_much_worse(b, a); } - float compute_angle_penalty(float ccw_angle) const { - // This function is used: - // ((ℯ^(((1)/(x^(2)*3+1)))-1)/(ℯ-1))*1+((1)/(2+ℯ^(-x))) - // looks scary, but it is gaussian combined with sigmoid, - // so that concave points have much smaller penalty over convex ones - // https://github.com/prusa3d/PrusaSlicer/tree/master/doc/seam_placement/corner_penalty_function.png - return gauss(ccw_angle, 0.0f, 1.0f, 3.0f) + - 1.0f / (2 + std::exp(-ccw_angle)); - } - float weight(const SeamCandidate &a) const { if (setup == SeamPosition::spAligned && a.central_enforcer) { return 2.0f; @@ -1390,8 +1391,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: last_point_pos = pos; observations[index] = pos.head<2>(); observation_points[index] = pos.z(); - weights[index] = std::min(1.0f, - comparator.weight(layers[seam_string[index].first].points[seam_string[index].second])); + weights[index] = comparator.weight(layers[seam_string[index].first].points[seam_string[index].second]); } // Curve Fitting @@ -1404,14 +1404,14 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const SeamPlacerImpl:: for (size_t index = 0; index < seam_string.size(); ++index) { const auto &pair = seam_string[index]; const float t = - abs(layers[pair.first].points[pair.second].local_ccw_angle) - > SeamPlacer::sharp_angle_snapping_threshold - ? 1.0 : 0.0f; + compute_angle_penalty(layers[pair.first].points[pair.second].local_ccw_angle) + < SeamPlacer::sharp_angle_penalty_snapping_threshold + ? 0.8f : 0.0f; Vec3f current_pos = layers[pair.first].points[pair.second].position; Vec2f fitted_pos = curve.get_fitted_value(current_pos.z()); //interpolate between current and fitted position, prefer current pos for large weights. - Vec3f final_position = t * current_pos + (1 - t) * to_3d(fitted_pos, current_pos.z()); + Vec3f final_position = t * current_pos + (1.0f - t) * to_3d(fitted_pos, current_pos.z()); Perimeter &perimeter = layers[pair.first].points[pair.second].perimeter; perimeter.seam_index = pair.second; diff --git a/src/libslic3r/GCode/SeamPlacer.hpp b/src/libslic3r/GCode/SeamPlacer.hpp index 69c53767b..1f1643d0d 100644 --- a/src/libslic3r/GCode/SeamPlacer.hpp +++ b/src/libslic3r/GCode/SeamPlacer.hpp @@ -128,7 +128,8 @@ public: // arm length used during angles computation static constexpr float polygon_local_angles_arm_distance = 0.3f; - static constexpr float sharp_angle_snapping_threshold = (60.0f / 180.0f) * float(PI); + // value for angles with penalty lower than this threshold - such angles will be snapped to their original position instead of spline interpolated position + static constexpr float sharp_angle_penalty_snapping_threshold = 0.6f; // max tolerable distance from the previous layer is overhang_distance_tolerance_factor * flow_width static constexpr float overhang_distance_tolerance_factor = 0.5f; From 70677858a1f858bd21c4d28cac82dca566a26f54 Mon Sep 17 00:00:00 2001 From: Pavel Mikus Date: Thu, 14 Jul 2022 18:00:59 +0200 Subject: [PATCH 14/14] Use resampling only with smooth surfaces generated by Arachne --- src/libslic3r/GCode/SeamPlacer.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index f81521660..2a716a300 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -467,7 +467,7 @@ Polygons extract_perimeter_polygons(const Layer *layer, const SeamPosition confi //each SeamCandidate also contains pointer to shared Perimeter structure representing the polygon // if Custom Seam modifiers are present, oversamples the polygon if necessary to better fit user intentions void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const LayerRegion *region, - const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) { + bool arachne_generated, const GlobalModelInfo &global_model_info, PrintObjectSeamData::LayerSeams &result) { if (orig_polygon.size() == 0) { return; } @@ -482,8 +482,8 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const std::vector polygon_angles = calculate_polygon_angles_at_vertices(polygon, lengths, SeamPlacer::polygon_local_angles_arm_distance); - // resample smooth surfaces, so that alignment finds short path down, and does not create unnecesary curves - if (std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) { + // resample smooth surfaces from arachne, so that alignment finds short path down, and does not create unnecesary curves + if (arachne_generated && std::all_of(polygon_angles.begin(), polygon_angles.end(), [](float angle) { return compute_angle_penalty(angle) > SeamPlacer::sharp_angle_penalty_snapping_threshold; })) { float total_dist = std::accumulate(lengths.begin(), lengths.end(), 0.0f); @@ -1069,12 +1069,14 @@ public: void SeamPlacer::gather_seam_candidates(const PrintObject *po, const SeamPlacerImpl::GlobalModelInfo &global_model_info, const SeamPosition configured_seam_preference) { using namespace SeamPlacerImpl; + bool arachne_generated = po->config().perimeter_generator == PerimeterGeneratorType::Arachne; PrintObjectSeamData &seam_data = m_seam_per_object.emplace(po, PrintObjectSeamData { }).first->second; seam_data.layers.resize(po->layer_count()); tbb::parallel_for(tbb::blocked_range(0, po->layers().size()), - [po, configured_seam_preference, &global_model_info, &seam_data](tbb::blocked_range r) { + [po, configured_seam_preference, arachne_generated, &global_model_info, &seam_data] + (tbb::blocked_range r) { for (size_t layer_idx = r.begin(); layer_idx < r.end(); ++layer_idx) { PrintObjectSeamData::LayerSeams &layer_seams = seam_data.layers[layer_idx]; const Layer *layer = po->get_layer(layer_idx); @@ -1084,7 +1086,7 @@ void SeamPlacer::gather_seam_candidates(const PrintObject *po, Polygons polygons = extract_perimeter_polygons(layer, configured_seam_preference, regions); for (size_t poly_index = 0; poly_index < polygons.size(); ++poly_index) { process_perimeter_polygon(polygons[poly_index], unscaled_z, - regions[poly_index], global_model_info, layer_seams); + regions[poly_index], arachne_generated, global_model_info, layer_seams); } auto functor = SeamCandidateCoordinateFunctor { layer_seams.points }; seam_data.layers[layer_idx].points_tree =