From 9d35904f20a05f20b2bf977681d7eda3f82b1b14 Mon Sep 17 00:00:00 2001 From: Saumya Jain Date: Tue, 23 Apr 2024 13:48:59 +0200 Subject: [PATCH] Update z-seam handling and improve path optimization This update tweaks handling of the z-seam by allowing it to shift away from the model based on specific settings. It also introduces better path optimization, by calculating the shortest distance from a point to a line segment, optimizing how the best position is retrieved if such support exists and dealing with edge cases where no optimal starting path is found. CURA-11227 --- include/PathOrderOptimizer.h | 61 ++++++++++++++++++++++++++++++------ src/FffGcodeWriter.cpp | 15 ++++++--- 2 files changed, 63 insertions(+), 13 deletions(-) diff --git a/include/PathOrderOptimizer.h b/include/PathOrderOptimizer.h index 684128a5f9..a8d6cec840 100644 --- a/include/PathOrderOptimizer.h +++ b/include/PathOrderOptimizer.h @@ -211,7 +211,7 @@ class PathOrderOptimizer // For some Z seam types the start position can be pre-computed. // This is faster since we don't need to re-compute the start position at each step then. - precompute_start &= seam_config_.type_ == EZSeamType::SUPPORT || seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED + precompute_start &= seam_config_.type_ == EZSeamType::RANDOM || seam_config_.type_ == EZSeamType::USER_SPECIFIED || seam_config_.type_ == EZSeamType::SHARPEST_CORNER; if (precompute_start) { @@ -578,17 +578,46 @@ class PathOrderOptimizer { for (const auto& points : ranges::front(mesh_paths_)) { - for (const auto& polygon_point : points) + const int len = points.size(); + + for (int i = 0; i < len; ++i) { - double distance = std::sqrt(std::pow(static_cast(polygon_point.X - point.X), 2) + std::pow(static_cast(polygon_point.Y - point.Y), 2)); + const auto& polygon_point1 = points[i]; + const auto& polygon_point2 = points[(i + 1) % len]; // Ensures looping back to the first point to create the final segment + + // Definitions + double x = static_cast(point.X); + double y = static_cast(point.Y); + double x1 = static_cast(polygon_point1.X); + double y1 = static_cast(polygon_point1.Y); + double x2 = static_cast(polygon_point2.X); + double y2 = static_cast(polygon_point2.Y); + + // Calculate the shortest distance from the point to the line segment + double dx = x2 - x1; + double dy = y2 - y1; + + // Calculate the t parameter + double t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); + + // If t is outside bounds [0,1], point is closest to an endpoint of the segment + t = std::max(0.0, std::min(1.0, t)); + + // Compute the coordinates of the point on the line segment nearest to the external point + double nearestX = x1 + t * dx; + double nearestY = y1 + t * dy; + + // Calculate squared distance from external point to its nearest point on the line segment + double dx_nearest = x - nearestX; + double dy_nearest = y - nearestY; + double squared_distance = dx_nearest*dx_nearest + dy_nearest*dy_nearest; - if (distance <= min_size_support_zeam_) + if (squared_distance <= min_size_support_zeam_ * min_size_support_zeam_) { return true; } } } - return false; } @@ -638,14 +667,28 @@ class PathOrderOptimizer size_t pathIfzeamSupportIsCloseToModel(size_t best_pos, const OrderablePath& path) { - if (! mesh_paths_.empty()) + static size_t number_of_paths_analysed = 0; + size_t path_size = path.converted_->size(); + if (path_size > number_of_paths_analysed) { - Point2LL current_candidate = (*path.converted_)[best_pos]; - if (isVertexCloseToPolygonPath(current_candidate)) + if (! mesh_paths_.empty()) { - best_pos = pathIfzeamSupportIsCloseToModel(best_pos + 1, path); + Point2LL current_candidate = (path.converted_)->at(best_pos); + if (isVertexCloseToPolygonPath(current_candidate)) + { + size_t next_best_position = (path_size > best_pos + 1) ? best_pos + 1 : 0; + best_pos = pathIfzeamSupportIsCloseToModel(next_best_position, path); + number_of_paths_analysed +=1; + } } } + else + { + number_of_paths_analysed = 0; + spdlog::warn("no start path found for support z seam distance"); + // We can also calculate the best point to start at this point. + // This usually happens when the distance of support seam from model is bigger than the whole support wall points. + } return best_pos; } diff --git a/src/FffGcodeWriter.cpp b/src/FffGcodeWriter.cpp index da17d2c13c..b34b284c25 100644 --- a/src/FffGcodeWriter.cpp +++ b/src/FffGcodeWriter.cpp @@ -33,9 +33,9 @@ #include "utils/Simplify.h" //Removing micro-segments created by offsetting. #include "utils/ThreadPool.h" #include "utils/linearAlg2D.h" +#include "utils/polygonUtils.h" #include "utils/math.h" #include "utils/orderOptimizer.h" -#include "utils/polygonUtils.h" namespace cura { @@ -3452,11 +3452,18 @@ bool FffGcodeWriter::processSupportInfill(const SliceDataStorage& storage, Layer const GCodePathConfig& config = configs[0]; constexpr bool retract_before_outer_wall = false; constexpr coord_t wipe_dist = 0; + EZSeamType z_seam_type = EZSeamType::SHORTEST; ZSeamConfig z_seam_config; - Point2LL start_pos; + Point2LL start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); + if (infill_extruder.settings_.get("support_z_seam_away_from_model")) + { + z_seam_type = EZSeamType::SUPPORT; + } - start_pos = gcode_layer.getLastPlannedPositionOrStartingPosition(); - z_seam_config = ZSeamConfig(EZSeamType::SUPPORT, start_pos, EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, false); + z_seam_config = ZSeamConfig(z_seam_type, + start_pos, + EZSeamCornerPrefType::Z_SEAM_CORNER_PREF_NONE, + false); InsetOrderOptimizer wall_orderer(