@@ -80,6 +80,55 @@ PerimeterGenerator::process()
80
80
std::vector<PerimeterGeneratorLoops> contours (loop_number+1 ); // depth => loops
81
81
std::vector<PerimeterGeneratorLoops> holes (loop_number+1 ); // depth => loops
82
82
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
+
83
132
84
133
// we loop one time more than needed in order to find gaps after the last perimeter was applied
85
134
for (int i = 0 ; i <= loop_number+1 ; ++i) { // outer loop is 0
@@ -181,19 +230,44 @@ PerimeterGenerator::process()
181
230
}
182
231
}
183
232
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
186
235
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 ();
193
245
} 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));
195
257
}
196
258
}
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
+ // }
197
271
}
198
272
199
273
// nest loops: holes first
@@ -450,7 +524,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
450
524
451
525
ExtrusionEntityCollection children = this ->_traverse_loops (loop.children , thin_walls);
452
526
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 ();
454
531
entities.append (children.entities );
455
532
entities.append (eloop);
456
533
} else {
0 commit comments