Skip to content

Commit 258da5b

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 258da5b

File tree

5 files changed

+131
-31
lines changed

5 files changed

+131
-31
lines changed

xs/src/libslic3r/BridgeDetector.cpp

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -181,15 +181,11 @@ BridgeDetector::detect_angle()
181181
}
182182

183183
Polygons
184-
BridgeDetector::coverage() const
185-
{
186-
if (this->angle == -1) return Polygons();
187-
return this->coverage(this->angle);
188-
}
189-
190-
Polygons
191-
BridgeDetector::coverage(double angle) const
184+
BridgeDetector::coverage(double angle, bool precise) const
192185
{
186+
if (angle == -1) angle = this->angle;
187+
if (angle == -1) return Polygons();
188+
193189
// Clone our expolygon and rotate it so that we work with vertical lines.
194190
ExPolygon expolygon = this->expolygon;
195191
expolygon.rotate(PI/2.0 - angle, Point(0,0));
@@ -214,18 +210,46 @@ BridgeDetector::coverage(double angle) const
214210
}
215211

216212
Polygons covered;
217-
for (const Polygon &trapezoid : trapezoids) {
218-
Lines supported = intersection_ln(trapezoid.lines(), anchors);
213+
for (Polygon &trapezoid : trapezoids) {
219214

220-
// not nice, we need a more robust non-numeric check
221-
for (size_t i = 0; i < supported.size(); ++i) {
222-
if (supported[i].length() < this->extrusion_width) {
223-
supported.erase(supported.begin() + i);
224-
i--;
225-
}
226-
}
215+
size_t n_supported = 0;
216+
if (!precise) {
217+
// not nice, we need a more robust non-numeric check
218+
for (const Line &supported_line : intersection_ln(trapezoid.lines(), anchors))
219+
if (supported_line.length() >= this->extrusion_width)
220+
++n_supported;
221+
} else {
222+
Polygons intersects = intersection(trapezoid, anchors);
223+
n_supported = intersects.size();
224+
225+
if (n_supported >= 2) {
226+
// trim it to not allow to go outside of the intersections
227+
BoundingBox center_bound = intersects[0].bounding_box();
228+
coord_t min_y = center_bound.center().y, max_y = center_bound.center().y;
229+
for (const Polygon &poly_bound : intersects) {
230+
center_bound = poly_bound.bounding_box();
231+
if (min_y > center_bound.center().y) min_y = center_bound.center().y;
232+
if (max_y < center_bound.center().y) max_y = center_bound.center().y;
233+
}
234+
coord_t min_x = trapezoid[0].x, max_x = trapezoid[0].x;
235+
for (const Point &p : trapezoid.points) {
236+
if (min_x > p.x) min_x = p.x;
237+
if (max_x < p.x) max_x = p.x;
238+
}
239+
//add what get_trapezoids3 has removed (+EPSILON)
240+
min_x -= (this->extrusion_width / 4 + 1);
241+
max_x += (this->extrusion_width / 4 + 1);
242+
coord_t mid_x = (min_x + max_x) / 2;
243+
for (Point &p : trapezoid.points) {
244+
if (p.y < min_y) p.y = min_y;
245+
if (p.y > max_y) p.y = max_y;
246+
if (p.x > min_x && p.x < mid_x) p.x = min_x;
247+
if (p.x < max_x && p.x > mid_x) p.x = max_x;
248+
}
249+
}
250+
}
227251

228-
if (supported.size() >= 2) covered.push_back(trapezoid);
252+
if (n_supported >= 2) covered.push_back(trapezoid);
229253
}
230254

231255
// merge trapezoids and rotate them back

xs/src/libslic3r/BridgeDetector.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ class BridgeDetector {
2323

2424
BridgeDetector(const ExPolygon &_expolygon, const ExPolygonCollection &_lower_slices, coord_t _extrusion_width);
2525
bool detect_angle();
26-
Polygons coverage() const;
27-
Polygons coverage(double angle) const;
26+
Polygons coverage(double angle = -1, bool precise = false) const;
2827

2928
/// Return the bridge edges that are not currently supported but would permit use of the supplied
3029
/// bridge angle if it was supported.

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: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "PerimeterGenerator.hpp"
22
#include "ClipperUtils.hpp"
3+
#include "BridgeDetector.hpp"
34
#include "ExtrusionEntityCollection.hpp"
45
#include <cmath>
56
#include <cassert>
@@ -80,6 +81,48 @@ PerimeterGenerator::process()
8081
std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
8182
std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops
8283
ThickPolylines thin_walls;
84+
85+
86+
// We can add more perimeters if there are uncovered overhangs
87+
bool has_overhang = false;
88+
if (this->config->extra_perimeters && !last.empty()
89+
&& this->lower_slices != NULL && !this->lower_slices->expolygons.empty()){
90+
//split the polygons with bottom/notbottom
91+
ExPolygons unsupported = diff_ex(last, (Polygons)this->lower_slices->expolygons, true);
92+
if (!unsupported.empty()) {
93+
//only consider overhangs and let bridges alone
94+
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, (Polygons)unsupported, true));
99+
BridgeDetector detector(unsupported,
100+
lower_island,
101+
pspacing);
102+
if (detector.detect_angle()) {
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(pspacing / 2, &bridgeable_simplified);
109+
}
110+
111+
if (!bridgeable_simplified.empty())
112+
bridgeable_simplified = offset_ex(bridgeable_simplified, pspacing/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+
if (!unsupported.empty()) {
120+
//allow to add an other perimeter
121+
has_overhang = true;
122+
}
123+
}
124+
}
125+
83126

84127
// we loop one time more than needed in order to find gaps after the last perimeter was applied
85128
for (int i = 0; i <= loop_number+1; ++i) { // outer loop is 0
@@ -181,19 +224,43 @@ PerimeterGenerator::process()
181224
}
182225
}
183226

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

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);
230+
if (offsets.empty()) {
231+
// Store the number of loops actually generated.
232+
loop_number = i - 1;
233+
break;
234+
} else if (i > loop_number) {
235+
if (has_overhang) {
236+
loop_number++;
237+
contours.emplace_back();
238+
holes.emplace_back();
193239
} else {
194-
holes[i].push_back(loop);
240+
// If i > loop_number, we were looking just for gaps.
241+
break;
195242
}
196243
}
244+
245+
for (const Polygon &polygon : offsets) {
246+
if(polygon->is_counter_clockwise()){
247+
contours[i].emplace_back(PerimeterGeneratorLoop(polygon, i, true, has_overhang));
248+
}else{
249+
holes[i].emplace_back(PerimeterGeneratorLoop(polygon, i, false, has_overhang));
250+
}
251+
}
252+
last = std::move(offsets);
253+
254+
// last = offsets;
255+
// for (Polygons::const_iterator polygon = offsets.begin(); polygon != offsets.end(); ++polygon) {
256+
// PerimeterGeneratorLoop loop(*polygon, i);
257+
// loop.is_contour = polygon->is_counter_clockwise();
258+
// if (loop.is_contour) {
259+
// contours[i].push_back(loop);
260+
// } else {
261+
// holes[i].push_back(loop);
262+
// }
263+
// }
197264
}
198265

199266
// nest loops: holes first
@@ -450,7 +517,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
450517

451518
ExtrusionEntityCollection children = this->_traverse_loops(loop.children, thin_walls);
452519
if (loop.is_contour) {
453-
eloop.make_counter_clockwise();
520+
if (loop.is_overhang && this->layer_id % 2 == 1)
521+
eloop.make_clockwise();
522+
else
523+
eloop.make_counter_clockwise();
454524
entities.append(children.entities);
455525
entities.append(eloop);
456526
} 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)