From 83f3ca27dcd8912fbf463e7b87fea095ef17853a Mon Sep 17 00:00:00 2001 From: PavelMikus Date: Wed, 13 Apr 2022 14:32:09 +0200 Subject: [PATCH] reworked and improved the find_next_seam_in_layer method: Now uses find nearby_points with radius to save some computations if all points are far. From the nearby points, it finds the nearest and best point, and tries to use them in this order (preivously only nearest was considered). This helps to snap the alignment to nearby sharp corners if present. --- src/libslic3r/GCode/SeamPlacer.cpp | 69 +++++++++++++++++++++++------- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 712c8d724..07b8b8ee3 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -460,7 +460,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const }; size_t first_enforced_idx = perimeter.start_index; - for (int _ = 0; _ < perimeter_size; ++_) { + for (size_t _ = 0; _ < perimeter_size; ++_) { if (result.points[first_enforced_idx].type != EnforcedBlockedSeamPoint::Enforced && result.points[next_index(first_enforced_idx)].type == EnforcedBlockedSeamPoint::Enforced) { break; @@ -474,7 +474,7 @@ void process_perimeter_polygon(const Polygon &orig_polygon, float z_coord, const std::vector orig_large_angle_points_indices { }; std::vector viable_points_indices { }; size_t last_enforced_idx = first_enforced_idx; - for (int _ = 0; _ < perimeter_size; ++_) { + for (size_t _ = 0; _ < perimeter_size; ++_) { if (result.points[last_enforced_idx].type != EnforcedBlockedSeamPoint::Enforced) { break; } @@ -1025,35 +1025,72 @@ bool SeamPlacer::find_next_seam_in_layer( const SeamCandidate &last_point = layers[last_point_indexes.first].points[last_point_indexes.second]; Vec3f projected_position { last_point.position.x(), last_point.position.y(), slice_z }; - //find closest point in next layer - size_t closest_point_index = find_closest_point(*layers[layer_idx].points_tree, projected_position); + std::vector nearby_points_indices = find_nearby_points(*layers[layer_idx].points_tree, projected_position, + SeamPlacer::seam_align_tolerable_dist); - const SeamCandidate &closest_point = layers[layer_idx].points[closest_point_index]; - - if (closest_point.perimeter.finalized) { //already finalized, skip + if (nearby_points_indices.empty()) { return false; } - //from the closest point, deduce index of seam in the next layer - const SeamCandidate &next_layer_seam = layers[layer_idx].points[closest_point.perimeter.seam_index]; + size_t best_nearby_point_index = nearby_points_indices[0]; + size_t nearest_point_index = nearby_points_indices[0]; + // Now find best nearby point, nearest point, and corresponding indices + for (const size_t &nearby_point_index : nearby_points_indices) { + const SeamCandidate &point = layers[layer_idx].points[nearby_point_index]; + if (point.perimeter.finalized) { + continue; // skip over finalized perimeters, try to find some that is not finalized + } + if (comparator.is_first_better(point, layers[layer_idx].points[best_nearby_point_index], + projected_position.head<2>()) + || layers[layer_idx].points[best_nearby_point_index].perimeter.finalized) { + best_nearby_point_index = nearby_point_index; + } + if ((point.position - projected_position).squaredNorm() + < (layers[layer_idx].points[nearest_point_index].position - projected_position).squaredNorm() + || layers[layer_idx].points[nearest_point_index].perimeter.finalized) { + nearest_point_index = nearby_point_index; + } + } + + const SeamCandidate &best_nearby_point = layers[layer_idx].points[best_nearby_point_index]; + const SeamCandidate &nearest_point = layers[layer_idx].points[nearest_point_index]; + + if (nearest_point.perimeter.finalized) { + //all points are from already finalized perimeter, skip + return false; + } + + //from the nearest_point, deduce index of seam in the next layer + const SeamCandidate &next_layer_seam = layers[layer_idx].points[nearest_point.perimeter.seam_index]; + + // 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)) { - last_point_indexes = std::pair { layer_idx, closest_point.perimeter.seam_index }; + last_point_indexes = std::pair { layer_idx, nearest_point.perimeter.seam_index }; seam_string.push_back(last_point_indexes); return true; } - if ((closest_point.position - projected_position).squaredNorm() < sqr(SeamPlacer::seam_align_tolerable_dist) - && comparator.is_first_not_much_worse(closest_point, next_layer_seam) - && comparator.are_similar(last_point, closest_point)) { - last_point_indexes = std::pair { layer_idx, closest_point_index }; + // Next compare nearest and nearby point. If they are similar pick nearest, Otherwise expect curvy lines on smooth surfaces like chimney of benchy model + // We also compare it to the last point, to detect sharp changes in the scoring - that points to change in the model geometry and string should be ended. + if (comparator.are_similar(nearest_point, best_nearby_point) + && comparator.is_first_not_much_worse(nearest_point, next_layer_seam) + && comparator.are_similar(last_point, nearest_point)) { + last_point_indexes = std::pair { layer_idx, nearest_point_index }; seam_string.push_back(last_point_indexes); return true; - } else { - return false; } + // If nearest point is not good enough, try it with the best nearby point. + if (comparator.is_first_not_much_worse(best_nearby_point, next_layer_seam) + && comparator.are_similar(last_point, nearest_point)) { + last_point_indexes = std::pair { layer_idx, best_nearby_point_index }; + seam_string.push_back(last_point_indexes); + return true; + } + + return false; } // clusters already chosen seam points into strings across multiple layers, and then