Skip to content

Commit 46ab17d

Browse files
author
supermerill
committed
extra_perimeters: now also add extra perimeters if infill-over-overhangs are detected.
extra_perimeters: Use CW instead of CCW every odd layers for overhangs.
1 parent a4a0d52 commit 46ab17d

File tree

3 files changed

+95
-11
lines changed

3 files changed

+95
-11
lines changed

xs/src/libslic3r/GCode.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,8 @@ GCode::extrude(ExtrusionLoop loop, std::string description, double speed)
305305
// next copies (if any) would not detect the correct orientation
306306

307307
// extrude all loops ccw
308-
bool was_clockwise = loop.make_counter_clockwise();
308+
// no! this was decided by the generator, he know better than us.
309+
bool was_clockwise = false;// loop.make_counter_clockwise();
309310

310311
SeamPosition seam_position = this->config.seam_position;
311312
if (loop.role == elrSkirt) seam_position = spNearest;

xs/src/libslic3r/PerimeterGenerator.cpp

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,55 @@ PerimeterGenerator::process()
8080
std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
8181
std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops
8282
ThickPolylines thin_walls;
83+
84+
85+
// We can add more perimeters if there are uncovered overhangs
86+
bool has_overhang = false;
87+
if (this->config->extra_perimeters && !last.empty()
88+
&& this->lower_slices != NULL && !this->lower_slices->expolygons.empty()){
89+
//split the polygons with bottom/notbottom
90+
ExPolygons unsupported = diff_ex(last, this->lower_slices->expolygons, true);
91+
if (!unsupported.empty()) {
92+
//only consider overhangs and let bridges alone
93+
if (true) {
94+
//only consider the part that can be bridged (really, by the bridge algorithm)
95+
//first, separate into islands (ie, each ExPlolygon)
96+
int numploy = 0;
97+
//only consider the bottom layer that intersect unsupported, to be sure it's only on our island.
98+
ExPolygonCollection lower_island(diff_ex(last, unsupported, true));
99+
BridgeDetector detector(unsupported,
100+
lower_island,
101+
perimeter_spacing);
102+
if (detector.detect_angle(Geometry::deg2rad(this->config->bridge_angle.value))) {
103+
ExPolygons bridgeable = union_ex(detector.coverage(-1, true));
104+
if (!bridgeable.empty()) {
105+
//simplify to avoid most of artefacts from printing lines.
106+
ExPolygons bridgeable_simplified;
107+
for (ExPolygon &poly : bridgeable) {
108+
poly.simplify(perimeter_spacing / 2, &bridgeable_simplified);
109+
}
110+
111+
if (!bridgeable_simplified.empty())
112+
bridgeable_simplified = offset_ex(bridgeable_simplified, perimeter_spacing/1.9);
113+
if (!bridgeable_simplified.empty()) {
114+
//offset by perimeter spacing because the simplify may have reduced it a bit.
115+
unsupported = diff_ex(unsupported, bridgeable_simplified, true);
116+
}
117+
}
118+
}
119+
} else {
120+
ExPolygonCollection coll_last(intersection_ex(last, offset_ex(this->lower_slices->expolygons, -perimeter_spacing / 2)));
121+
ExPolygon hull;
122+
hull.contour = coll_last.convex_hull();
123+
unsupported = diff_ex(offset_ex(unsupported, perimeter_spacing), ExPolygons() = { hull });
124+
}
125+
if (!unsupported.empty()) {
126+
//add fake perimeters here
127+
has_overhang = true;
128+
}
129+
}
130+
}
131+
83132

84133
// we loop one time more than needed in order to find gaps after the last perimeter was applied
85134
for (int i = 0; i <= loop_number+1; ++i) { // outer loop is 0
@@ -181,19 +230,44 @@ PerimeterGenerator::process()
181230
}
182231
}
183232

184-
if (offsets.empty()) break;
185-
if (i > loop_number) break; // we were only looking for gaps this time
233+
// if (offsets.empty()) break;
234+
// if (i > loop_number) break; // we were only looking for gaps this time
186235

187-
last = offsets;
188-
for (Polygons::const_iterator polygon = offsets.begin(); polygon != offsets.end(); ++polygon) {
189-
PerimeterGeneratorLoop loop(*polygon, i);
190-
loop.is_contour = polygon->is_counter_clockwise();
191-
if (loop.is_contour) {
192-
contours[i].push_back(loop);
236+
if (offsets.empty()) {
237+
// Store the number of loops actually generated.
238+
loop_number = i - 1;
239+
break;
240+
} else if (i > loop_number) {
241+
if (has_overhang) {
242+
loop_number++;
243+
contours.emplace_back();
244+
holes.emplace_back();
193245
} else {
194-
holes[i].push_back(loop);
246+
// If i > loop_number, we were looking just for gaps.
247+
break;
248+
}
249+
}
250+
251+
for (const ExPolygon &expolygon : next_onion) {
252+
contours[i].emplace_back(PerimeterGeneratorLoop(expolygon.contour, i, true, has_overhang));
253+
if (! expolygon.holes.empty()) {
254+
holes[i].reserve(holes[i].size() + expolygon.holes.size());
255+
for (const Polygon &hole : expolygon.holes)
256+
holes[i].emplace_back(PerimeterGeneratorLoop(hole, i, false, has_overhang));
195257
}
196258
}
259+
last = std::move(offsets);
260+
261+
// last = offsets;
262+
// for (Polygons::const_iterator polygon = offsets.begin(); polygon != offsets.end(); ++polygon) {
263+
// PerimeterGeneratorLoop loop(*polygon, i);
264+
// loop.is_contour = polygon->is_counter_clockwise();
265+
// if (loop.is_contour) {
266+
// contours[i].push_back(loop);
267+
// } else {
268+
// holes[i].push_back(loop);
269+
// }
270+
// }
197271
}
198272

199273
// nest loops: holes first
@@ -450,7 +524,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
450524

451525
ExtrusionEntityCollection children = this->_traverse_loops(loop.children, thin_walls);
452526
if (loop.is_contour) {
453-
eloop.make_counter_clockwise();
527+
if (loop.is_overhang && this->layer_id % 2 == 1)
528+
eloop.make_clockwise();
529+
else
530+
eloop.make_counter_clockwise();
454531
entities.append(children.entities);
455532
entities.append(eloop);
456533
} else {

xs/src/libslic3r/PerimeterGenerator.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@ class PerimeterGeneratorLoop {
1919
// Is it a contour or a hole?
2020
// Contours are CCW oriented, holes are CW oriented.
2121
bool is_contour;
22+
//overhang may need to be reversed
23+
bool is_overhang;
2224
// Depth in the hierarchy. External perimeter has depth = 0. An external perimeter could be both a contour and a hole.
2325
unsigned short depth;
2426
// Children contour, may be both CCW and CW oriented (outer contours or holes).
2527
std::vector<PerimeterGeneratorLoop> children;
2628

29+
PerimeterGeneratorLoop(Polygon polygon, unsigned short depth, bool is_contour) :
30+
polygon(polygon), is_contour(is_contour), depth(depth), is_overhang(false) {}
31+
PerimeterGeneratorLoop(Polygon polygon, unsigned short depth, bool is_contour, bool is_overhang) :
32+
polygon(polygon), is_contour(is_contour), depth(depth), is_overhang(is_overhang) {}
2733
PerimeterGeneratorLoop(Polygon polygon, unsigned short depth)
2834
: polygon(polygon), is_contour(false), depth(depth)
2935
{};

0 commit comments

Comments
 (0)