From 9a1dcc47204c5eba620d27b399f2d74c2124ca7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20=C5=A0ach?= Date: Fri, 3 May 2024 17:28:01 +0200 Subject: [PATCH] Handle special seam case of just 2 or 3 perimeters. If there are only 2 or 3 perimeters on a layer, exactly two of them are external and just one of them is a hole, then the seams should be choosen next to each other on the external perimeters. --- src/libslic3r/GCode/SeamPerimeters.cpp | 6 ++++ src/libslic3r/GCode/SeamPerimeters.hpp | 2 ++ src/libslic3r/GCode/SeamPlacer.cpp | 38 +++++++++++++++++++++++- src/libslic3r/GCode/SeamShells.cpp | 7 +++-- src/libslic3r/GCode/SeamShells.hpp | 1 + tests/fff_print/test_seam_aligned.cpp | 1 + tests/fff_print/test_seam_perimeters.cpp | 1 + tests/fff_print/test_seam_random.cpp | 1 + tests/fff_print/test_seam_rear.cpp | 1 + 9 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/libslic3r/GCode/SeamPerimeters.cpp b/src/libslic3r/GCode/SeamPerimeters.cpp index e83b694afd..a2db061d16 100644 --- a/src/libslic3r/GCode/SeamPerimeters.cpp +++ b/src/libslic3r/GCode/SeamPerimeters.cpp @@ -269,6 +269,7 @@ Perimeter::PointTrees get_kd_trees( Perimeter::Perimeter( const double slice_z, const std::size_t layer_index, + const bool is_hole, std::vector &&positions, std::vector &&angles, std::vector &&point_types, @@ -277,6 +278,7 @@ Perimeter::Perimeter( ) : slice_z(slice_z) , layer_index(layer_index) + , is_hole(is_hole) , positions(std::move(positions)) , angles(std::move(angles)) , index_to_coord(IndexToCoord{tcb::span{this->positions}}) @@ -304,6 +306,7 @@ Perimeter Perimeter::create_degenerate( Perimeter perimeter{ slice_z, layer_index, + false, std::move(points), std::move(angles), std::move(point_types), @@ -368,9 +371,12 @@ Perimeter Perimeter::create( Impl::get_angle_types(smooth_angles, params.convex_threshold, params.concave_threshold)}; angle_types = Impl::merge_angle_types(angle_types, smooth_angle_types, perimeter_points, params.smooth_angle_arm_length); + const bool is_hole{polygon.is_clockwise()}; + return Perimeter{ layer_info.slice_z, layer_info.index, + is_hole, std::move(perimeter_points), std::move(angles), std::move(point_types), diff --git a/src/libslic3r/GCode/SeamPerimeters.hpp b/src/libslic3r/GCode/SeamPerimeters.hpp index 20705754fd..aaebe6e5a6 100644 --- a/src/libslic3r/GCode/SeamPerimeters.hpp +++ b/src/libslic3r/GCode/SeamPerimeters.hpp @@ -127,6 +127,7 @@ struct Perimeter Perimeter( const double slice_z, const std::size_t layer_index, + const bool is_hole, std::vector &&positions, std::vector &&angles, std::vector &&point_types, @@ -147,6 +148,7 @@ struct Perimeter bool is_degenerate{false}; double slice_z{}; + bool is_hole{false}; std::size_t layer_index{}; std::vector positions{}; std::vector angles{}; diff --git a/src/libslic3r/GCode/SeamPlacer.cpp b/src/libslic3r/GCode/SeamPlacer.cpp index 21b42584e0..d1fd54e069 100644 --- a/src/libslic3r/GCode/SeamPlacer.cpp +++ b/src/libslic3r/GCode/SeamPlacer.cpp @@ -298,6 +298,21 @@ std::pair place_seam_near( return {choice, choice_index}; } +int get_perimeter_count(const Layer *layer){ + int count{0}; + for (const LayerRegion *layer_region : layer->regions()) { + for (const ExtrusionEntity *ex_entity : layer_region->perimeters()) { + if (ex_entity->is_collection()) { //collection of inner, outer, and overhang perimeters + count += static_cast(ex_entity)->entities.size(); + } + else { + count += 1; + } + } + } + return count; +} + Point Placer::place_seam(const Layer *layer, const ExtrusionLoop &loop, const Point &last_pos) const { const PrintObject *po = layer->object(); // Must not be called with supprot layer. @@ -311,12 +326,33 @@ Point Placer::place_seam(const Layer *layer, const ExtrusionLoop &loop, const Po const bool do_staggering{this->params.staggered_inner_seams && loop.role() == ExtrusionRole::Perimeter}; const double loop_width{loop.paths.empty() ? 0.0 : loop.paths.front().width()}; + if (this->params.seam_preference == spNearest) { const std::vector &perimeters{this->perimeters_per_layer.at(po)[layer_index]}; const auto [seam_choice, perimeter_index] = place_seam_near(perimeters, loop, last_pos, this->params.max_nearest_detour); return finalize_seam_position(loop_polygon, seam_choice, perimeters[perimeter_index].perimeter, loop_width, do_staggering); } else { - const SeamPerimeterChoice &seam_perimeter_choice{choose_closest_seam(this->seams_per_object.at(po)[layer_index], loop_polygon)}; + const std::vector &seams_on_perimeters{this->seams_per_object.at(po)[layer_index]}; + + // Special case. + // If there are only two perimeters and the current perimeter is hole (clockwise). + const int perimeter_count{get_perimeter_count(layer)}; + const bool has_2_or_3_perimeters{perimeter_count == 2 || perimeter_count == 3}; + if (has_2_or_3_perimeters) { + if (seams_on_perimeters.size() == 2 && + seams_on_perimeters[0].perimeter.is_hole != + seams_on_perimeters[1].perimeter.is_hole) { + const SeamPerimeterChoice &seam_perimeter_choice{ + seams_on_perimeters[0].perimeter.is_hole ? seams_on_perimeters[1] : + seams_on_perimeters[0]}; + return finalize_seam_position( + loop_polygon, seam_perimeter_choice.choice, seam_perimeter_choice.perimeter, + loop_width, do_staggering + ); + } + } + + const SeamPerimeterChoice &seam_perimeter_choice{choose_closest_seam(seams_on_perimeters, loop_polygon)}; return finalize_seam_position(loop_polygon, seam_perimeter_choice.choice, seam_perimeter_choice.perimeter, loop_width, do_staggering); } } diff --git a/src/libslic3r/GCode/SeamShells.cpp b/src/libslic3r/GCode/SeamShells.cpp index f90ce0881c..6cf5f328d4 100644 --- a/src/libslic3r/GCode/SeamShells.cpp +++ b/src/libslic3r/GCode/SeamShells.cpp @@ -19,10 +19,11 @@ BoundedPolygons project_to_geometry(const Geometry::Extrusions &external_perimet external_perimeter.island_boundary_bounding_boxes )}; + const bool is_hole{choosen_index != 0}; const Polygon &adjacent_boundary{ - choosen_index == 0 ? external_perimeter.island_boundary.contour : - external_perimeter.island_boundary.holes[choosen_index - 1]}; - return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index]}; + !is_hole ? external_perimeter.island_boundary.contour : + external_perimeter.island_boundary.holes[choosen_index - 1]}; + return BoundedPolygon{adjacent_boundary, external_perimeter.island_boundary_bounding_boxes[choosen_index], is_hole}; } ); return result; diff --git a/src/libslic3r/GCode/SeamShells.hpp b/src/libslic3r/GCode/SeamShells.hpp index 555332708e..4d775865a4 100644 --- a/src/libslic3r/GCode/SeamShells.hpp +++ b/src/libslic3r/GCode/SeamShells.hpp @@ -20,6 +20,7 @@ namespace Slic3r::Seams::Shells::Impl { struct BoundedPolygon { Polygon polygon; BoundingBox bounding_box; + bool is_hole{false}; }; using BoundedPolygons = std::vector; diff --git a/tests/fff_print/test_seam_aligned.cpp b/tests/fff_print/test_seam_aligned.cpp index 66288c3ff5..1ab755cfaf 100644 --- a/tests/fff_print/test_seam_aligned.cpp +++ b/tests/fff_print/test_seam_aligned.cpp @@ -25,6 +25,7 @@ Perimeters::Perimeter get_perimeter() { return { slice_z, layer_index, + false, std::move(positions), std::move(angles), std::move(point_types), diff --git a/tests/fff_print/test_seam_perimeters.cpp b/tests/fff_print/test_seam_perimeters.cpp index b97b59832f..405eb3731d 100644 --- a/tests/fff_print/test_seam_perimeters.cpp +++ b/tests/fff_print/test_seam_perimeters.cpp @@ -76,6 +76,7 @@ TEST_CASE("Perimeter constructs KD trees", "[Seams][SeamPerimeters]") { Perimeters::Perimeter perimeter{ 3.0, 2, + false, std::move(positions), std::move(angles), std::move(point_types), diff --git a/tests/fff_print/test_seam_random.cpp b/tests/fff_print/test_seam_random.cpp index c877b39a70..8a69c6b66a 100644 --- a/tests/fff_print/test_seam_random.cpp +++ b/tests/fff_print/test_seam_random.cpp @@ -23,6 +23,7 @@ Perimeters::Perimeter get_perimeter() { return { slice_z, layer_index, + false, std::move(positions), std::move(angles), std::move(point_types), diff --git a/tests/fff_print/test_seam_rear.cpp b/tests/fff_print/test_seam_rear.cpp index dda99b219e..c6ee01c5b3 100644 --- a/tests/fff_print/test_seam_rear.cpp +++ b/tests/fff_print/test_seam_rear.cpp @@ -25,6 +25,7 @@ Perimeters::Perimeter get_perimeter() { return { slice_z, layer_index, + false, std::move(positions), std::move(angles), std::move(point_types),