diff --git a/src/libslic3r/GCode/SeamPlacerNG.cpp b/src/libslic3r/GCode/SeamPlacerNG.cpp index 5b2a743e3..086cb0fdc 100644 --- a/src/libslic3r/GCode/SeamPlacerNG.cpp +++ b/src/libslic3r/GCode/SeamPlacerNG.cpp @@ -518,12 +518,6 @@ void pick_seam_point(std::vector &perimeter_points, size_t start_ indices[index - start_index] = index; } - std::sort(indices.begin(), indices.end(), - [&](size_t left, size_t right) { - return std::abs(perimeter_points[left].local_ccw_angle - 0.1 * PI) - > std::abs(perimeter_points[right].local_ccw_angle - 0.1 * PI); - }); - size_t seam_index = indices[0]; for (size_t index : indices) { if (comparator.is_first_better(perimeter_points[index], perimeter_points[seam_index])) { @@ -580,17 +574,13 @@ void gather_global_model_info(GlobalModelInfo &result, const PrintObject *po) { } struct DefaultSeamComparator { - static constexpr float angle_clusters[] { -1.0, 0.4 * PI, 0.65 * PI, 0.9 * PI }; + float compute_angle_penalty(float ccw_angle) const { + if (ccw_angle >= 0) { + return PI - ccw_angle; + } else { + return (PI - ccw_angle) * 1.1f; + } - const float get_angle_category(float ccw_angle) const { - float concave_bonus = ccw_angle < 0 ? 0.1 * PI : 0; - float abs_angle = abs(ccw_angle) + concave_bonus; - auto category = std::find_if_not(std::begin(angle_clusters), std::end(angle_clusters), - [&](float category_limit) { - return abs_angle > category_limit; - }); - category--; - return *category; } bool is_first_better(const SeamCandidate &a, const SeamCandidate &b) const { @@ -603,24 +593,12 @@ struct DefaultSeamComparator { } //avoid overhangs - if (a.overhang > 0.3f && b.overhang < a.overhang) { + if (a.overhang > 0.2f && b.overhang < a.overhang) { return false; } - { //local angles - float a_local_category = get_angle_category(a.local_ccw_angle); - float b_local_category = get_angle_category(b.local_ccw_angle); - - if (a_local_category > b_local_category) { - return true; - } - if (a_local_category < b_local_category) { - return false; - } - } - - return a.visibility < b.visibility; - + return (a.visibility + 0.01) * compute_angle_penalty(a.local_ccw_angle) < + (b.visibility + 0.01) * compute_angle_penalty(b.local_ccw_angle); } bool is_first_not_much_worse(const SeamCandidate &a, const SeamCandidate &b) const { @@ -633,24 +611,12 @@ struct DefaultSeamComparator { } //avoid overhangs - if (a.overhang > 0.3f && b.overhang < a.overhang) { + if (a.overhang > 0.2f && b.overhang < a.overhang) { return false; } - { //local angles - float a_local_category = get_angle_category(a.local_ccw_angle); - float b_local_category = get_angle_category(b.local_ccw_angle); - - if (a_local_category > b_local_category) { - return true; - } - if (a_local_category < b_local_category) { - return false; - } - } - - return (a.visibility <= b.visibility - || (std::abs(a.visibility - b.visibility) < SeamPlacer::expected_hits_per_area / 17.0f)); + return (a.visibility + 0.01) * compute_angle_penalty(a.local_ccw_angle) * 0.8f <= + (b.visibility + 0.01) * compute_angle_penalty(b.local_ccw_angle); } } ; @@ -814,7 +780,15 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const Comparator &comp std::sort(seams.begin(), seams.end(), [&](const std::pair &left, const std::pair &right) { return m_perimeter_points_per_object[po][left.first][left.second].visibility - < m_perimeter_points_per_object[po][right.first][right.second].visibility; + * (1.2 * PI + - std::abs( + m_perimeter_points_per_object[po][left.first][left.second].local_ccw_angle + - 0.2 * PI)) + < m_perimeter_points_per_object[po][right.first][right.second].visibility + * (1.2 * PI + - std::abs( + m_perimeter_points_per_object[po][right.first][right.second].local_ccw_angle + - 0.2 * PI)); } ); @@ -889,7 +863,7 @@ void SeamPlacer::align_seam_points(const PrintObject *po, const Comparator &comp // //https://en.wikipedia.org/wiki/Exponential_smoothing // //inititalization -// float smoothing_factor = SeamPlacer::seam_align_strength; +// float smoothing_factor = 0.8; // std::pair init = seam_string[0]; // Vec2f prev_pos_xy = m_perimeter_points_per_object[po][init.first][init.second].position.head<2>(); // for (const auto &pair : seam_string) { diff --git a/src/libslic3r/GCode/SeamPlacerNG.hpp b/src/libslic3r/GCode/SeamPlacerNG.hpp index 2f8bba728..bcd178aed 100644 --- a/src/libslic3r/GCode/SeamPlacerNG.hpp +++ b/src/libslic3r/GCode/SeamPlacerNG.hpp @@ -34,32 +34,38 @@ enum class EnforcedBlockedSeamPoint { Enforced = 2, }; +// struct representing single perimeter loop struct Perimeter { size_t start_index; size_t end_index; //inclusive! size_t seam_index; + // During alignment, a final position may be stored here. In that case, aligned is set to true. + // Note that final seam position is not limited to points of the perimeter loop. In theory it can be any position bool aligned = false; Vec3f final_seam_position; }; +//Struct over which all processing of perimeters is done. For each perimeter point, its respective candidate is created, +// then all the needed attributes are computed and finally, for each perimeter one point is chosen as seam. +// This seam position can be than further aligned struct SeamCandidate { SeamCandidate(const Vec3f &pos, std::shared_ptr perimeter, float local_ccw_angle, EnforcedBlockedSeamPoint type) : - position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), higher_layer_overhang( - 0.0f), local_ccw_angle( + position(pos), perimeter(perimeter), visibility(0.0f), overhang(0.0f), local_ccw_angle( local_ccw_angle), type(type) { } const Vec3f position; + // pointer to Perimter loop of this point. It is shared across all points of the loop const std::shared_ptr perimeter; float visibility; float overhang; - float higher_layer_overhang; // represents how much is the position covered by the upper layer, useful for local visibility float local_ccw_angle; EnforcedBlockedSeamPoint type; }; +// struct to represent hits of the mesh during occulision raycasting. struct HitInfo { Vec3f position; Vec3f surface_normal; @@ -90,22 +96,37 @@ class SeamPlacer { public: using SeamCandidatesTree = KDTreeIndirect<3, float, SeamPlacerImpl::SeamCandidateCoordinateFunctor>; + // Rough estimates of hits of the mesh during raycasting per surface circle defined by considered_area_radius static constexpr float expected_hits_per_area = 600.0f; + // area considered when computing number of rays and then gathering visiblity info from the hits static constexpr float considered_area_radius = 3.0f; - static constexpr float raycasting_decimation_target_error = 0.6f; + // quadric error limit of quadric decimation function used on the mesh before raycasting + static constexpr float raycasting_decimation_target_error = 0.3f; + // cosine sampling power represents how prefered are forward directions when raycasting from given spot + // in this case, forward direction means towards the center of the mesh static constexpr float cosine_hemisphere_sampling_power = 4.0f; + // arm length used during angles computation static constexpr float polygon_local_angles_arm_distance = 0.6f; + // If enforcer or blocker is closer to the seam candidate than this limit, the seam candidate is set to Blocer or Enforcer static constexpr float enforcer_blocker_sqr_distance_tolerance = 0.2f; + // When searching for seam clusters for alignment: + // seam_align_tolerable_dist - if seam is closer to the previous seam position projected to the current layer than this value, + //it belongs automaticaly to the cluster static constexpr float seam_align_tolerable_dist = 1.0f; + // if the seam of the current layer is too far away, and the closest seam candidate is not very good, layer is skipped. + // this param limits the number of allowed skips static constexpr size_t seam_align_tolerable_skips = 6; + // minimum number of seams needed in cluster to make alignemnt happen static constexpr size_t seam_align_minimum_string_seams = 5; - //perimeter points per object per layer idx, and their corresponding KD trees + //The following data structures hold all perimeter points for all PrintObject. The structure is as follows: + // Map of PrintObjects (PO) -> vector of layers of PO -> vector of perimeter points of the given layer std::unordered_map>> m_perimeter_points_per_object; + // Map of PrintObjects (PO) -> vector of layers of PO -> unique_ptr to KD tree of all points of the given layer std::unordered_map>> m_perimeter_points_trees_per_object; void init(const Print &print);