Prusa Slicer 2.6.0
Loading...
Searching...
No Matches
Slic3r::BridgeDetector Class Reference

#include <src/libslic3r/BridgeDetector.hpp>

+ Collaboration diagram for Slic3r::BridgeDetector:

Classes

struct  BridgeDirection
 

Public Member Functions

 BridgeDetector (ExPolygon _expolygon, const ExPolygons &_lower_slices, coord_t _extrusion_width)
 
 BridgeDetector (const ExPolygons &_expolygons, const ExPolygons &_lower_slices, coord_t _extrusion_width)
 
bool detect_angle (double bridge_direction_override=0.)
 
Polygons coverage (double angle=-1) const
 
void unsupported_edges (double angle, Polylines *unsupported) const
 
Polylines unsupported_edges (double angle=-1) const
 

Public Attributes

const ExPolygonsexpolygons
 
ExPolygons expolygons_owned
 
const ExPolygonslower_slices
 
coord_t spacing
 
double resolution
 
double angle
 

Private Member Functions

BridgeDetectoroperator= (const BridgeDetector &)
 
void initialize ()
 
std::vector< double > bridge_direction_candidates () const
 

Private Attributes

Polylines _edges
 
ExPolygons _anchor_regions
 

Detailed Description

Constructor & Destructor Documentation

◆ BridgeDetector() [1/2]

Slic3r::BridgeDetector::BridgeDetector ( ExPolygon  _expolygon,
const ExPolygons _lower_slices,
coord_t  _extrusion_width 
)
11 :
12 // The original infill polygon, not inflated.
14 // All surfaces of the object supporting this region.
15 lower_slices(_lower_slices),
16 spacing(_spacing)
17{
18 this->expolygons_owned.push_back(std::move(_expolygon));
19 initialize();
20}
const ExPolygons & lower_slices
Definition BridgeDetector.hpp:32
ExPolygons expolygons_owned
Definition BridgeDetector.hpp:30
coord_t spacing
Definition BridgeDetector.hpp:34
const ExPolygons & expolygons
Definition BridgeDetector.hpp:28
void initialize()
Definition BridgeDetector.cpp:35

References expolygons_owned, and initialize().

+ Here is the call graph for this function:

◆ BridgeDetector() [2/2]

Slic3r::BridgeDetector::BridgeDetector ( const ExPolygons _expolygons,
const ExPolygons _lower_slices,
coord_t  _extrusion_width 
)
25 :
26 // The original infill polygon, not inflated.
27 expolygons(_expolygons),
28 // All surfaces of the object supporting this region.
29 lower_slices(_lower_slices),
30 spacing(_spacing)
31{
32 initialize();
33}

References initialize().

+ Here is the call graph for this function:

Member Function Documentation

◆ bridge_direction_candidates()

std::vector< double > Slic3r::BridgeDetector::bridge_direction_candidates ( ) const
private
174{
175 // we test angles according to configured resolution
176 std::vector<double> angles;
177 for (int i = 0; i <= PI/this->resolution; ++i)
178 angles.push_back(i * this->resolution);
179
180 // we also test angles of each bridge contour
181 {
182 Lines lines = to_lines(this->expolygons);
183 for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
184 angles.push_back(line->direction());
185 }
186
187 /* we also test angles of each open supporting edge
188 (this finds the optimal angle for C-shaped supports) */
189 for (const Polyline &edge : this->_edges)
190 if (edge.first_point() != edge.last_point())
191 angles.push_back(Line(edge.first_point(), edge.last_point()).direction());
192
193 // remove duplicates
194 double min_resolution = PI/180.0; // 1 degree
195 std::sort(angles.begin(), angles.end());
196 for (size_t i = 1; i < angles.size(); ++i) {
197 if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
198 angles.erase(angles.begin() + i);
199 --i;
200 }
201 }
202 /* compare first value with last one and remove the greatest one (PI)
203 in case they are parallel (PI, 0) */
204 if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
205 angles.pop_back();
206
207 return angles;
208}
Polylines _edges
Definition BridgeDetector.hpp:71
double resolution
Definition BridgeDetector.hpp:36
if(!(yy_init))
Definition lexer.c:1190
static constexpr double PI
Definition libslic3r.h:58
bool directions_parallel(double angle1, double angle2, double max_diff)
Definition Geometry.cpp:29
std::vector< Line > Lines
Definition Line.hpp:17
Lines to_lines(const ExPolygon &src)
Definition ExPolygon.hpp:117

References _edges, Slic3r::Line::direction(), Slic3r::Geometry::directions_parallel(), expolygons, PI, resolution, and Slic3r::to_lines().

Referenced by detect_angle().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ coverage()

Polygons Slic3r::BridgeDetector::coverage ( double  angle = -1) const
271{
272 if (angle == -1)
273 angle = this->angle;
274
275 Polygons covered;
276
277 if (angle != -1) {
278 // Get anchors, convert them to Polygons and rotate them.
279 Polygons anchors = to_polygons(this->_anchor_regions);
280 polygons_rotate(anchors, PI/2.0 - angle);
281
282 for (ExPolygon expolygon : this->expolygons) {
283 // Clone our expolygon and rotate it so that we work with vertical lines.
284 expolygon.rotate(PI/2.0 - angle);
285 // Outset the bridge expolygon by half the amount we used for detecting anchors;
286 // we'll use this one to generate our trapezoids and be sure that their vertices
287 // are inside the anchors and not on their contours leading to false negatives.
288 for (ExPolygon &expoly : offset_ex(expolygon, 0.5f * float(this->spacing))) {
289 // Compute trapezoids according to a vertical orientation
290 Polygons trapezoids;
291 get_trapezoids2(expoly, &trapezoids, PI/2.0);
292 for (const Polygon &trapezoid : trapezoids) {
293 // not nice, we need a more robust non-numeric check
294 size_t n_supported = 0;
295 for (const Line &supported_line : intersection_ln(trapezoid.lines(), anchors))
296 if (supported_line.length() >= this->spacing)
297 ++ n_supported;
298 if (n_supported >= 2)
299 covered.push_back(std::move(trapezoid));
300 }
301 }
302 }
303
304 // Unite the trapezoids before rotation, as the rotation creates tiny gaps and intersections between the trapezoids
305 // instead of exact overlaps.
306 covered = union_(covered);
307 // Intersect trapezoids with actual bridge area to remove extra margins and append it to result.
308 polygons_rotate(covered, -(PI/2.0 - angle));
309 covered = intersection(this->expolygons, covered);
310#if 0
311 {
312 my @lines = map @{$_->lines}, @$trapezoids;
313 $_->rotate(-(PI/2 - $angle), [0,0]) for @lines;
314
315 require "Slic3r/SVG.pm";
316 Slic3r::SVG::output(
317 "coverage_" . rad2deg($angle) . ".svg",
318 expolygons => [$self->expolygon],
319 green_expolygons => $self->_anchor_regions,
320 red_expolygons => $coverage,
321 lines => \@lines,
322 );
323 }
324#endif
325 }
326 return covered;
327}
ExPolygons _anchor_regions
Definition BridgeDetector.hpp:73
double angle
Definition BridgeDetector.hpp:38
std::vector< Polygon, PointsAllocator< Polygon > > Polygons
Definition Polygon.hpp:15
Slic3r::Polygons union_(const Slic3r::Polygons &subject)
Definition ClipperUtils.cpp:704
Slic3r::Lines intersection_ln(const Slic3r::Lines &subject, const Slic3r::Polygons &clip)
Definition ClipperUtils.hpp:482
double length(const Points &pts)
Definition MultiPoint.hpp:116
Slic3r::Polygons intersection(const Slic3r::Polygon &subject, const Slic3r::Polygon &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:686
static void get_trapezoids2(const ExPolygon &expoly, Polygons *polygons)
Definition BridgeDetector.cpp:230
Slic3r::ExPolygons offset_ex(const Slic3r::Polygons &polygons, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:421
Polygons to_polygons(const ExPolygon &src)
Definition ExPolygon.hpp:281
void polygons_rotate(Polygons &polys, double angle)
Definition Polygon.hpp:155
double rad2deg(double rad)
Definition agg_basics.h:277

References _anchor_regions, angle, expolygons, Slic3r::get_trapezoids2(), Slic3r::intersection(), Slic3r::intersection_ln(), Slic3r::offset_ex(), PI, Slic3r::polygons_rotate(), spacing, Slic3r::to_polygons(), and Slic3r::union_().

Referenced by detect_angle().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ detect_angle()

bool Slic3r::BridgeDetector::detect_angle ( double  bridge_direction_override = 0.)
76{
77 if (this->_edges.empty() || this->_anchor_regions.empty())
78 // The bridging region is completely in the air, there are no anchors available at the layer below.
79 return false;
80
81 std::vector<BridgeDirection> candidates;
82 if (bridge_direction_override == 0.) {
83 std::vector<double> angles = bridge_direction_candidates();
84 candidates.reserve(angles.size());
85 for (size_t i = 0; i < angles.size(); ++ i)
86 candidates.emplace_back(BridgeDirection(angles[i]));
87 } else
88 candidates.emplace_back(BridgeDirection(bridge_direction_override));
89
90 /* Outset the bridge expolygon by half the amount we used for detecting anchors;
91 we'll use this one to clip our test lines and be sure that their endpoints
92 are inside the anchors and not on their contours leading to false negatives. */
93 Polygons clip_area = offset(this->expolygons, 0.5f * float(this->spacing));
94
95 /* we'll now try several directions using a rudimentary visibility check:
96 bridge in several directions and then sum the length of lines having both
97 endpoints within anchors */
98
99 bool have_coverage = false;
100 for (size_t i_angle = 0; i_angle < candidates.size(); ++ i_angle)
101 {
102 const double angle = candidates[i_angle].angle;
103
104 Lines lines;
105 {
106 // Get an oriented bounding box around _anchor_regions.
107 BoundingBox bbox = get_extents_rotated(this->_anchor_regions, - angle);
108 // Cover the region with line segments.
109 lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing);
110 double s = sin(angle);
111 double c = cos(angle);
112 //FIXME Vojtech: The lines shall be spaced half the line width from the edge, but then
113 // some of the test cases fail. Need to adjust the test cases then?
114// for (coord_t y = bbox.min(1) + this->spacing / 2; y <= bbox.max(1); y += this->spacing)
115 for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing)
116 lines.push_back(Line(
117 Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))),
118 Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0)))));
119 }
120
121 double total_length = 0;
122 double max_length = 0;
123 {
124 Lines clipped_lines = intersection_ln(lines, clip_area);
125 for (size_t i = 0; i < clipped_lines.size(); ++i) {
126 const Line &line = clipped_lines[i];
127 if (expolygons_contain(this->_anchor_regions, line.a) && expolygons_contain(this->_anchor_regions, line.b)) {
128 // This line could be anchored.
129 double len = line.length();
130 total_length += len;
131 max_length = std::max(max_length, len);
132 }
133 }
134 }
135 if (total_length == 0.)
136 continue;
137
138 have_coverage = true;
139 // Sum length of bridged lines.
140 candidates[i_angle].coverage = total_length;
141 /* The following produces more correct results in some cases and more broken in others.
142 TODO: investigate, as it looks more reliable than line clipping. */
143 // $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
144 // max length of bridged lines
145 candidates[i_angle].max_length = max_length;
146 }
147
148 // if no direction produced coverage, then there's no bridge direction
149 if (! have_coverage)
150 return false;
151
152 // sort directions by coverage - most coverage first
153 std::sort(candidates.begin(), candidates.end());
154
155 // if any other direction is within extrusion width of coverage, prefer it if shorter
156 // TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
157 size_t i_best = 0;
158 for (size_t i = 1; i < candidates.size() && candidates[i_best].coverage - candidates[i].coverage < this->spacing; ++ i)
159 if (candidates[i].max_length < candidates[i_best].max_length)
160 i_best = i;
161
162 this->angle = candidates[i_best].angle;
163 if (this->angle >= PI)
164 this->angle -= PI;
165
166 #ifdef SLIC3R_DEBUG
167 printf(" Optimal infill angle is %d degrees\n", (int)Slic3r::Geometry::rad2deg(this->angle));
168 #endif
169
170 return true;
171}
EIGEN_DEVICE_FUNC const CosReturnType cos() const
Definition ArrayCwiseUnaryOps.h:202
EIGEN_DEVICE_FUNC const SinReturnType sin() const
Definition ArrayCwiseUnaryOps.h:220
EIGEN_DEVICE_FUNC const RoundReturnType round() const
Definition ArrayCwiseUnaryOps.h:374
std::vector< double > bridge_direction_candidates() const
Definition BridgeDetector.cpp:173
Polygons coverage(double angle=-1) const
Definition BridgeDetector.cpp:270
int32_t coord_t
Definition libslic3r.h:39
const Scalar & y
Definition MathFunctions.h:552
T rad2deg(T angle)
Definition Geometry.hpp:288
bool expolygons_contain(ExPolygons &expolys, const Point &pt, bool border_result=true)
Definition ExPolygon.hpp:433
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, ClipperLib::JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:416
double total_length(const Polygons &polylines)
Definition Polygon.hpp:112
BoundingBox get_extents_rotated(const ExPolygon &expolygon, double angle)
Definition ExPolygon.cpp:368
Kernel::Point_2 Point
Definition point_areas.cpp:20

References _anchor_regions, _edges, Slic3r::Line::a, angle, Slic3r::Line::b, bridge_direction_candidates(), cos(), coverage(), expolygons, Slic3r::expolygons_contain(), Slic3r::get_extents_rotated(), Slic3r::intersection_ln(), Slic3r::Line::length(), Slic3r::BoundingBoxBase< PointType, APointsType >::max, Slic3r::BoundingBoxBase< PointType, APointsType >::min, Slic3r::offset(), PI, Slic3r::Geometry::rad2deg(), round(), sin(), spacing, and Slic3r::total_length().

+ Here is the call graph for this function:

◆ initialize()

void Slic3r::BridgeDetector::initialize ( )
private
36{
37 // 5 degrees stepping
38 this->resolution = PI/36.0;
39 // output angle not known
40 this->angle = -1.;
41
42 // Outset our bridge by an arbitrary amout; we'll use this outer margin for detecting anchors.
43 Polygons grown = offset(this->expolygons, float(this->spacing));
44
45 // Detect possible anchoring edges of this bridging region.
46 // Detect what edges lie on lower slices by turning bridge contour and holes
47 // into polylines and then clipping them with each lower slice's contour.
48 // Currently _edges are only used to set a candidate direction of the bridge (see bridge_direction_candidates()).
49 Polygons contours;
50 contours.reserve(this->lower_slices.size());
51 for (const ExPolygon &expoly : this->lower_slices)
52 contours.push_back(expoly.contour);
53 this->_edges = intersection_pl(to_polylines(grown), contours);
54
55 #ifdef SLIC3R_DEBUG
56 printf(" bridge has %zu support(s)\n", this->_edges.size());
57 #endif
58
59 // detect anchors as intersection between our bridge expolygon and the lower slices
60 // safety offset required to avoid Clipper from detecting empty intersection while Boost actually found some edges
62
63 /*
64 if (0) {
65 require "Slic3r/SVG.pm";
66 Slic3r::SVG::output("bridge.svg",
67 expolygons => [ $self->expolygon ],
68 red_expolygons => $self->lower_slices,
69 polylines => $self->_edges,
70 );
71 }
72 */
73}
Polylines to_polylines(const ExPolygon &src)
Definition ExPolygon.hpp:209
Slic3r::ExPolygons intersection_ex(const Slic3r::Polygons &subject, const Slic3r::Polygons &clip, ApplySafetyOffset do_safety_offset)
Definition ClipperUtils.cpp:755
Slic3r::Polygons union_safety_offset(const Slic3r::Polygons &polygons)
Definition ClipperUtils.hpp:352
Slic3r::Polylines intersection_pl(const Slic3r::Polylines &subject, const Slic3r::Polygon &clip)
Definition ClipperUtils.cpp:866
const Polygon & contour(const ExPolygon &p)
Definition AGGRaster.hpp:21

References _anchor_regions, _edges, angle, expolygons, Slic3r::intersection_ex(), Slic3r::intersection_pl(), lower_slices, Slic3r::offset(), PI, resolution, spacing, Slic3r::to_polylines(), and Slic3r::union_safety_offset().

Referenced by BridgeDetector(), and BridgeDetector().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ operator=()

BridgeDetector & Slic3r::BridgeDetector::operator= ( const BridgeDetector )
private

◆ unsupported_edges() [1/2]

void Slic3r::BridgeDetector::unsupported_edges ( double  angle,
Polylines unsupported 
) const
334{
335 if (angle == -1) angle = this->angle;
336 if (angle == -1) return;
337
338 Polygons grown_lower = offset(this->lower_slices, float(this->spacing));
339
340 for (ExPolygons::const_iterator it_expoly = this->expolygons.begin(); it_expoly != this->expolygons.end(); ++ it_expoly) {
341 // get unsupported bridge edges (both contour and holes)
342 Lines unsupported_lines = to_lines(diff_pl(to_polylines(*it_expoly), grown_lower));
343 /* Split into individual segments and filter out edges parallel to the bridging angle
344 TODO: angle tolerance should probably be based on segment length and flow width,
345 so that we build supports whenever there's a chance that at least one or two bridge
346 extrusions would be anchored within such length (i.e. a slightly non-parallel bridging
347 direction might still benefit from anchors if long enough)
348 double angle_tolerance = PI / 180.0 * 5.0; */
349 for (const Line &line : unsupported_lines)
350 if (! Slic3r::Geometry::directions_parallel(line.direction(), angle)) {
351 unsupported->emplace_back(Polyline());
352 unsupported->back().points.emplace_back(line.a);
353 unsupported->back().points.emplace_back(line.b);
354 }
355 }
356
357 /*
358 if (0) {
359 require "Slic3r/SVG.pm";
360 Slic3r::SVG::output(
361 "unsupported_" . rad2deg($angle) . ".svg",
362 expolygons => [$self->expolygon],
363 green_expolygons => $self->_anchor_regions,
364 red_expolygons => union_ex($grown_lower),
365 no_arrows => 1,
366 polylines => \@bridge_edges,
367 red_polylines => $unsupported,
368 );
369 }
370 */
371}
Definition avrdude-slic3r.cpp:16
Slic3r::Polylines diff_pl(const Slic3r::Polyline &subject, const Slic3r::Polygons &clip)
Definition ClipperUtils.cpp:852

References angle, Slic3r::diff_pl(), Slic3r::Geometry::directions_parallel(), expolygons, lower_slices, Slic3r::offset(), spacing, Slic3r::to_lines(), and Slic3r::to_polylines().

Referenced by unsupported_edges().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ unsupported_edges() [2/2]

Polylines Slic3r::BridgeDetector::unsupported_edges ( double  angle = -1) const
375{
376 Polylines pp;
377 this->unsupported_edges(angle, &pp);
378 return pp;
379}
void unsupported_edges(double angle, Polylines *unsupported) const
Definition BridgeDetector.cpp:333
std::vector< Polyline > Polylines
Definition Polyline.hpp:14

References unsupported_edges().

+ Here is the call graph for this function:

Member Data Documentation

◆ _anchor_regions

ExPolygons Slic3r::BridgeDetector::_anchor_regions
private

Referenced by coverage(), detect_angle(), and initialize().

◆ _edges

Polylines Slic3r::BridgeDetector::_edges
private

◆ angle

double Slic3r::BridgeDetector::angle

◆ expolygons

const ExPolygons& Slic3r::BridgeDetector::expolygons

◆ expolygons_owned

ExPolygons Slic3r::BridgeDetector::expolygons_owned

Referenced by BridgeDetector().

◆ lower_slices

const ExPolygons& Slic3r::BridgeDetector::lower_slices

Referenced by initialize(), and unsupported_edges().

◆ resolution

double Slic3r::BridgeDetector::resolution

◆ spacing

coord_t Slic3r::BridgeDetector::spacing

The documentation for this class was generated from the following files: