From 2f568b45888cf9a684435a387ce3ad3554d9b44b Mon Sep 17 00:00:00 2001 From: Noisyfox Date: Sat, 14 Oct 2023 23:56:24 +0800 Subject: [PATCH] Perimeters for both contours and holes can have alternating direction, to support overhangs on both side. Also fixes wipe on loop. --- src/libslic3r/ExtrusionEntity.hpp | 11 +++++++---- src/libslic3r/GCode.cpp | 24 +++++++++-------------- src/libslic3r/PerimeterGenerator.cpp | 29 ++++++++++++---------------- 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/src/libslic3r/ExtrusionEntity.hpp b/src/libslic3r/ExtrusionEntity.hpp index 786a99b95ef..9921887b76d 100644 --- a/src/libslic3r/ExtrusionEntity.hpp +++ b/src/libslic3r/ExtrusionEntity.hpp @@ -43,10 +43,13 @@ enum ExtrusionRole : uint8_t { }; // Special flags describing loop -enum ExtrusionLoopRole { - elrDefault, - elrContourInternalPerimeter, - elrSkirt, +enum ExtrusionLoopRole : uint8_t { + elrDefault=0x0, + // Loop for the hole, not for the contour + elrHole=0x1, + // Loop that is the most closest to infill + elrInternal = 0x2, + elrSkirt=0x4, }; diff --git a/src/libslic3r/GCode.cpp b/src/libslic3r/GCode.cpp index 21a31d9ba74..765d331e5cd 100644 --- a/src/libslic3r/GCode.cpp +++ b/src/libslic3r/GCode.cpp @@ -4182,11 +4182,11 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // get a copy; don't modify the orientation of the original loop object otherwise // next copies (if any) would not detect the correct orientation - // extrude all loops ccw - bool was_clockwise = false;//loop.make_counter_clockwise(); - // if spiral vase, we have to ensure that all loops are in the same orientation. - if (m_config.spiral_mode) { - was_clockwise = loop.make_counter_clockwise(); + bool is_hole = (loop.loop_role() & elrHole) == elrHole; + + if (m_config.spiral_mode && !is_hole) { + // if spiral vase, we have to ensure that all contour are in the same orientation. + loop.make_counter_clockwise(); } // find the point of the loop that is closest to the current extruder position @@ -4244,26 +4244,20 @@ std::string GCode::extrude_loop(ExtrusionLoop loop, std::string description, dou // make a little move inwards before leaving loop if (m_config.wipe_on_loops.value && paths.back().role() == erExternalPerimeter && m_layer != NULL && m_config.wall_loops.value > 1 && paths.front().size() >= 2 && paths.back().polyline.points.size() >= 3) { // detect angle between last and first segment - // the side depends on the original winding order of the polygon (left for contours, right for holes) + // the side depends on the original winding order of the polygon (inwards for contours, outwards for holes) //FIXME improve the algorithm in case the loop is tiny. //FIXME improve the algorithm in case the loop is split into segments with a low number of points (see the Point b query). Point a = paths.front().polyline.points[1]; // second point Point b = *(paths.back().polyline.points.end()-3); // second to last point - if (was_clockwise) { + if (is_hole == loop.is_counter_clockwise()) { // swap points Point c = a; a = b; b = c; - - // double angle = paths.front().first_point().ccw_angle(a, b) / 3; - - // // turn left if contour, turn right if hole - // if (was_clockwise) angle *= -1; - } double angle = paths.front().first_point().ccw_angle(a, b) / 3; - // turn left if contour, turn right if hole - if (was_clockwise) angle *= -1; + // turn inwards if contour, turn outwards if hole + if (is_hole == loop.is_counter_clockwise()) angle *= -1; // create the destination point along the first segment and rotate it // we make sure we don't exceed the segment length because we don't know diff --git a/src/libslic3r/PerimeterGenerator.cpp b/src/libslic3r/PerimeterGenerator.cpp index f3a29105e8b..7cfb97ef828 100644 --- a/src/libslic3r/PerimeterGenerator.cpp +++ b/src/libslic3r/PerimeterGenerator.cpp @@ -233,9 +233,9 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime // Note that we set loop role to ContourInternalPerimeter // also when loop is both internal and external (i.e. // there's only one contour loop). - loop_role = elrContourInternalPerimeter; + loop_role = elrInternal; } else { - loop_role = elrDefault; + loop_role = loop.is_contour? elrDefault : elrHole; } // detect overhanging/bridging perimeters @@ -379,16 +379,15 @@ static ExtrusionEntityCollection traverse_loops(const PerimeterGenerator &perime out.entities.reserve(out.entities.size() + children.entities.size() + 1); ExtrusionLoop *eloop = static_cast(coll.entities[idx.first]); coll.entities[idx.first] = nullptr; + if (perimeter_generator.layer_id % 2 == 1) { + eloop->make_clockwise(); + } else { + eloop->make_counter_clockwise(); + } if (loop.is_contour) { - if (perimeter_generator.layer_id % 2 == 1) { - eloop->make_clockwise(); - } else { - eloop->make_counter_clockwise(); - } out.append(std::move(children.entities)); out.entities.emplace_back(eloop); } else { - eloop->make_clockwise(); out.entities.emplace_back(eloop); out.append(std::move(children.entities)); } @@ -723,17 +722,13 @@ static ExtrusionEntityCollection traverse_extrusions(const PerimeterGenerator& p // Append paths to collection. if (!paths.empty()) { if (extrusion->is_closed) { - ExtrusionLoop extrusion_loop(std::move(paths)); + ExtrusionLoop extrusion_loop(std::move(paths), pg_extrusion.is_contour ? elrDefault : elrHole); // Restore the orientation of the extrusion loop. - if (pg_extrusion.is_contour) { - if (perimeter_generator.layer_id % 2 == 1) { - extrusion_loop.make_clockwise(); - } else { - extrusion_loop.make_counter_clockwise(); - } - } - else + if (perimeter_generator.layer_id % 2 == 1) { extrusion_loop.make_clockwise(); + } else { + extrusion_loop.make_counter_clockwise(); + } for (auto it = std::next(extrusion_loop.paths.begin()); it != extrusion_loop.paths.end(); ++it) { assert(it->polyline.points.size() >= 2);