Skip to content

Commit

Permalink
Perimeters for both contours and holes can have alternating direction…
Browse files Browse the repository at this point in the history
…, to support overhangs on both side
  • Loading branch information
Noisyfox committed Oct 14, 2023
1 parent d07e239 commit 3db8f64
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 36 deletions.
11 changes: 7 additions & 4 deletions src/libslic3r/ExtrusionEntity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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=0x3,
};


Expand Down
24 changes: 9 additions & 15 deletions src/libslic3r/GCode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
29 changes: 12 additions & 17 deletions src/libslic3r/PerimeterGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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<ExtrusionLoop*>(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));
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 3db8f64

Please sign in to comment.