Skip to content

Commit

Permalink
Port "No Unsupported Perimeters" feature from SS (#3189)
Browse files Browse the repository at this point in the history
* first impl

* Properly handle extra bridges in `detect_surfaces_type()`

* Pass `perimeter_spacing` and `ext_perimeter_width` as parameters instead of instance property

* Make `process_no_bridge()` private

* Attempt to run `process_no_bridge()` in arachne

* Update `BridgeDetector::coverage` to give us more precise bridge coverage

Co-authored-by: supermerill <[email protected]>

* Fix bridge infill margin scaling

* Rename the option name as well as add tooltip

---------

Co-authored-by: Noisyfox <[email protected]>
Co-authored-by: supermerill <[email protected]>
Co-authored-by: SoftFever <[email protected]>
  • Loading branch information
4 people authored Jan 28, 2024
1 parent 1487bdd commit 3b7b10f
Show file tree
Hide file tree
Showing 9 changed files with 370 additions and 28 deletions.
113 changes: 100 additions & 13 deletions src/libslic3r/BridgeDetector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,56 @@ static void get_trapezoids2(const ExPolygon &expoly, Polygons* polygons, double
polygon.rotate(-(PI/2 - angle), Point(0,0));
}

// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons BridgeDetector::coverage(double angle) const


void get_trapezoids3_half(const ExPolygon& expoly, Polygons* polygons, float spacing)
{

// get all points of this ExPolygon
Points pp = to_points(expoly);

if (pp.empty()) return;

// build our bounding box
BoundingBox bb(pp);

// get all x coordinates
coord_t min_x = pp[0].x(), max_x = pp[0].x();
std::vector<coord_t> xx;
for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) {
if (min_x > p->x()) min_x = p->x();
if (max_x < p->x()) max_x = p->x();
}
for (coord_t x = min_x; x < max_x - (coord_t)(spacing / 2); x += (coord_t)spacing) {
xx.push_back(x);
}
xx.push_back(max_x);
//std::sort(xx.begin(), xx.end());

// find trapezoids by looping from first to next-to-last coordinate
for (std::vector<coord_t>::const_iterator x = xx.begin(); x != xx.end() - 1; ++x) {
coord_t next_x = *(x + 1);
if (*x == next_x) continue;

// build rectangle
Polygon poly;
poly.points.resize(4);
poly[0].x() = *x + (coord_t)spacing / 4;
poly[0].y() = bb.min(1);
poly[1].x() = next_x - (coord_t)spacing / 4;
poly[1].y() = bb.min(1);
poly[2].x() = next_x - (coord_t)spacing / 4;
poly[2].y() = bb.max(1);
poly[3].x() = *x + (coord_t)spacing / 4;
poly[3].y() = bb.max(1);

// intersect with this expolygon
// append results to return value
polygons_append(*polygons, intersection(Polygons{ poly }, to_polygons(expoly)));
}
}

Polygons BridgeDetector::coverage(double angle, bool precise) const
{
if (angle == -1)
angle = this->angle;
Expand All @@ -283,26 +331,65 @@ Polygons BridgeDetector::coverage(double angle) const
if (angle != -1) {
// Get anchors, convert them to Polygons and rotate them.
Polygons anchors = to_polygons(this->_anchor_regions);
polygons_rotate(anchors, PI/2.0 - angle);

polygons_rotate(anchors, PI / 2.0 - angle);
//same for region which do not need bridging
//Polygons supported_area = diff(this->lower_slices.expolygons, this->_anchor_regions, true);
//polygons_rotate(anchors, PI / 2.0 - angle);

for (ExPolygon expolygon : this->expolygons) {
// Clone our expolygon and rotate it so that we work with vertical lines.
expolygon.rotate(PI/2.0 - angle);
expolygon.rotate(PI / 2.0 - angle);
// Outset the bridge expolygon by half the amount we used for detecting anchors;
// we'll use this one to generate our trapezoids and be sure that their vertices
// are inside the anchors and not on their contours leading to false negatives.
for (ExPolygon &expoly : offset_ex(expolygon, 0.5f * float(this->spacing))) {
// Compute trapezoids according to a vertical orientation
Polygons trapezoids;
get_trapezoids2(expoly, &trapezoids, PI/2.0);
for (const Polygon &trapezoid : trapezoids) {
// not nice, we need a more robust non-numeric check
if (!precise) get_trapezoids2(expoly, &trapezoids, PI / 2);
else get_trapezoids3_half(expoly, &trapezoids, float(this->spacing));
for (Polygon &trapezoid : trapezoids) {
size_t n_supported = 0;
for (const Line &supported_line : intersection_ln(trapezoid.lines(), anchors))
if (supported_line.length() >= this->spacing)
++ n_supported;
if (n_supported >= 2)
if (!precise) {
// not nice, we need a more robust non-numeric check
// imporvment 1: take into account when we go in the supported area.
for (const Line &supported_line : intersection_ln(trapezoid.lines(), anchors))
if (supported_line.length() >= this->spacing)
++n_supported;
} else {
Polygons intersects = intersection(Polygons{trapezoid}, anchors);
n_supported = intersects.size();

if (n_supported >= 2) {
// trim it to not allow to go outside of the intersections
BoundingBox center_bound = intersects[0].bounding_box();
coord_t min_y = center_bound.center()(1), max_y = center_bound.center()(1);
for (Polygon &poly_bound : intersects) {
center_bound = poly_bound.bounding_box();
if (min_y > center_bound.center()(1)) min_y = center_bound.center()(1);
if (max_y < center_bound.center()(1)) max_y = center_bound.center()(1);
}
coord_t min_x = trapezoid[0](0), max_x = trapezoid[0](0);
for (Point &p : trapezoid.points) {
if (min_x > p(0)) min_x = p(0);
if (max_x < p(0)) max_x = p(0);
}
//add what get_trapezoids3 has removed (+EPSILON)
min_x -= (this->spacing / 4 + 1);
max_x += (this->spacing / 4 + 1);
coord_t mid_x = (min_x + max_x) / 2;
for (Point &p : trapezoid.points) {
if (p(1) < min_y) p(1) = min_y;
if (p(1) > max_y) p(1) = max_y;
if (p(0) > min_x && p(0) < mid_x) p(0) = min_x;
if (p(0) < max_x && p(0) > mid_x) p(0) = max_x;
}
}
}

if (n_supported >= 2) {
//add it
covered.push_back(std::move(trapezoid));
}
}
}
}
Expand All @@ -312,7 +399,7 @@ Polygons BridgeDetector::coverage(double angle) const
covered = union_(covered);
// Intersect trapezoids with actual bridge area to remove extra margins and append it to result.
polygons_rotate(covered, -(PI/2.0 - angle));
covered = intersection(this->expolygons, covered);
//covered = intersection(this->expolygons, covered);
#if 0
{
my @lines = map @{$_->lines}, @$trapezoids;
Expand Down
3 changes: 1 addition & 2 deletions src/libslic3r/BridgeDetector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@ class BridgeDetector {
BridgeDetector(const ExPolygons &_expolygons, const ExPolygons &_lower_slices, coord_t _extrusion_width);
// If bridge_direction_override != 0, then the angle is used instead of auto-detect.
bool detect_angle(double bridge_direction_override = 0.);
// Coverage is currently only used by the unit tests. It is extremely slow and unreliable!
Polygons coverage(double angle = -1) const;
Polygons coverage(double angle = -1, bool precise = true) const;
void unsupported_edges(double angle, Polylines* unsupported) const;
Polylines unsupported_edges(double angle = -1) const;

Expand Down
Loading

0 comments on commit 3b7b10f

Please sign in to comment.