|
1 | 1 | #include "PerimeterGenerator.hpp"
|
2 | 2 | #include "ClipperUtils.hpp"
|
| 3 | +#include "BridgeDetector.hpp" |
3 | 4 | #include "ExtrusionEntityCollection.hpp"
|
4 | 5 | #include <cmath>
|
5 | 6 | #include <cassert>
|
@@ -80,6 +81,48 @@ PerimeterGenerator::process()
|
80 | 81 | std::vector<PerimeterGeneratorLoops> contours(loop_number+1); // depth => loops
|
81 | 82 | std::vector<PerimeterGeneratorLoops> holes(loop_number+1); // depth => loops
|
82 | 83 | 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 | + |
83 | 126 |
|
84 | 127 | // we loop one time more than needed in order to find gaps after the last perimeter was applied
|
85 | 128 | for (int i = 0; i <= loop_number+1; ++i) { // outer loop is 0
|
@@ -181,19 +224,43 @@ PerimeterGenerator::process()
|
181 | 224 | }
|
182 | 225 | }
|
183 | 226 |
|
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 |
186 | 229 |
|
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(); |
193 | 239 | } else {
|
194 |
| - holes[i].push_back(loop); |
| 240 | + // If i > loop_number, we were looking just for gaps. |
| 241 | + break; |
195 | 242 | }
|
196 | 243 | }
|
| 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 | + // } |
197 | 264 | }
|
198 | 265 |
|
199 | 266 | // nest loops: holes first
|
@@ -450,7 +517,10 @@ PerimeterGenerator::_traverse_loops(const PerimeterGeneratorLoops &loops,
|
450 | 517 |
|
451 | 518 | ExtrusionEntityCollection children = this->_traverse_loops(loop.children, thin_walls);
|
452 | 519 | 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(); |
454 | 524 | entities.append(children.entities);
|
455 | 525 | entities.append(eloop);
|
456 | 526 | } else {
|
|
0 commit comments