Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/supermerill/SuperSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/libslic3r/BridgeDetector.cpp')
-rw-r--r--src/libslic3r/BridgeDetector.cpp454
1 files changed, 382 insertions, 72 deletions
diff --git a/src/libslic3r/BridgeDetector.cpp b/src/libslic3r/BridgeDetector.cpp
index 03d671db4..407a8d7ce 100644
--- a/src/libslic3r/BridgeDetector.cpp
+++ b/src/libslic3r/BridgeDetector.cpp
@@ -34,8 +34,8 @@ BridgeDetector::BridgeDetector(
void BridgeDetector::initialize()
{
- // 5 degrees stepping
- this->resolution = PI/36.0;
+ // 2 degrees stepping
+ this->resolution = PI/(90);
// output angle not known
this->angle = -1.;
@@ -46,10 +46,10 @@ void BridgeDetector::initialize()
// Detect what edges lie on lower slices by turning bridge contour and holes
// into polylines and then clipping them with each lower slice's contour.
// Currently _edges are only used to set a candidate direction of the bridge (see bridge_direction_candidates()).
- Polygons contours;
- contours.reserve(this->lower_slices.size());
- for (const ExPolygon &expoly : this->lower_slices)
- contours.push_back(expoly.contour);
+ Polygons contours;
+ contours.reserve(this->lower_slices.size());
+ for (const ExPolygon &expoly : this->lower_slices)
+ contours.push_back(expoly.contour);
this->_edges = intersection_pl(to_polylines(grown), contours);
#ifdef SLIC3R_DEBUG
@@ -80,10 +80,7 @@ bool BridgeDetector::detect_angle(double bridge_direction_override)
std::vector<BridgeDirection> candidates;
if (bridge_direction_override == 0.) {
- std::vector<double> angles = bridge_direction_candidates();
- candidates.reserve(angles.size());
- for (size_t i = 0; i < angles.size(); ++ i)
- candidates.emplace_back(BridgeDirection(angles[i]));
+ candidates = bridge_direction_candidates();
} else
candidates.emplace_back(BridgeDirection(bridge_direction_override));
@@ -100,63 +97,239 @@ bool BridgeDetector::detect_angle(double bridge_direction_override)
for (size_t i_angle = 0; i_angle < candidates.size(); ++ i_angle)
{
const double angle = candidates[i_angle].angle;
-
Lines lines;
{
// Get an oriented bounding box around _anchor_regions.
BoundingBox bbox = get_extents_rotated(this->_anchor_regions, - angle);
// Cover the region with line segments.
- lines.reserve((bbox.max(1) - bbox.min(1) + this->spacing) / this->spacing);
+ lines.reserve((bbox.max.y() - bbox.min.y() + this->spacing - SCALED_EPSILON) / this->spacing);
double s = sin(angle);
double c = cos(angle);
- //FIXME Vojtech: The lines shall be spaced half the line width from the edge, but then
- // some of the test cases fail. Need to adjust the test cases then?
-// for (coord_t y = bbox.min(1) + this->spacing / 2; y <= bbox.max(1); y += this->spacing)
- for (coord_t y = bbox.min(1); y <= bbox.max(1); y += this->spacing)
+ // As The lines be spaced half the line width from the edge
+ // FIXME: some of the test cases may fail. Need to adjust the test cases
+ for (coord_t y = bbox.min.y() + this->spacing / 2; y <= bbox.max.y(); y += this->spacing)
+ //for (coord_t y = bbox.min.y(); y <= bbox.max.y(); y += this->spacing) //this is the old version
lines.push_back(Line(
- Point((coord_t)round(c * bbox.min(0) - s * y), (coord_t)round(c * y + s * bbox.min(0))),
- Point((coord_t)round(c * bbox.max(0) - s * y), (coord_t)round(c * y + s * bbox.max(0)))));
+ Point((coord_t)round(c * bbox.min.x() - s * y), (coord_t)round(c * y + s * bbox.min.x())),
+ Point((coord_t)round(c * bbox.max.x() - s * y), (coord_t)round(c * y + s * bbox.max.x()))));
+ }
+
+ //create boundingbox for anchor regions
+ std::vector<BoundingBox> anchor_bb;
+ for (ExPolygon& poly : this->_anchor_regions) {
+ anchor_bb.emplace_back(poly.contour.bounding_box());
}
- double total_length = 0;
- double max_length = 0;
+ //compute stat on line with anchors, and their lengths.
+ BridgeDirection& c = candidates[i_angle];
+ std::vector<coordf_t> dist_anchored;
{
Lines clipped_lines = intersection_ln(lines, clip_area);
for (size_t i = 0; i < clipped_lines.size(); ++i) {
+ // this can be called 100 000 time per detect_angle, please optimise
const Line &line = clipped_lines[i];
- if (expolygons_contain(this->_anchor_regions, line.a) && expolygons_contain(this->_anchor_regions, line.b)) {
- // This line could be anchored.
- double len = line.length();
- total_length += len;
- max_length = std::max(max_length, len);
+ bool good_line = false;
+ coordf_t len = line.length();
+ //is anchored?
+ size_t line_a_anchor_idx = -1;
+ size_t line_b_anchor_idx = -1;
+ for (int i = 0; i < _anchor_regions.size(); ++i) {
+ ExPolygon& poly = this->_anchor_regions[i];
+ BoundingBox& polybb = anchor_bb[i];
+ if (polybb.contains(line.a) && poly.contains(line.a)) { // using short-circuit evaluation to test boundingbox and only then the other
+ line_a_anchor_idx = i;
+ }
+ if (polybb.contains(line.b) && poly.contains(line.b)) { // using short-circuit evaluation to test boundingbox and only then the other
+ line_b_anchor_idx = i;
+ }
+ if (line_a_anchor_idx < clipped_lines.size() && line_b_anchor_idx < clipped_lines.size())
+ break;
+ }
+ //check if the anchor search has been successful
+ if ( (line_a_anchor_idx < clipped_lines.size()) & (line_b_anchor_idx < clipped_lines.size())) { // this 'if' isn't very effective (culls ~ 10% on a benchy) but it's almost free to compute
+ good_line = true;
+ //test if it's not a fake bridge
+ if (line_a_anchor_idx == line_b_anchor_idx) {
+ good_line = false;
+ //check that the line go out of the anchor into the briding area
+ // don't call intersection_ln here, as even if we succeed to limit the number of candidates to ~100, here we can have hundreds of lines, so that means dozen of thousands of calls (or more)!
+ // add some points (at least the middle) to test, it's quick
+ Point middle_point = line.midpoint();
+ for (int i = 0; i < _anchor_regions.size(); ++i) {
+ ExPolygon& poly = this->_anchor_regions[i];
+ BoundingBox& polybb = anchor_bb[i];
+ if (!polybb.contains(middle_point) || !poly.contains(middle_point)) { // using short-circuit evaluation to test boundingbox and only then the other
+ good_line = true;
+ break;
+ }
+ }
+ // if still bad, the line is long enough to warrant two more test point? (1/2000 on a benchy)
+ if (!good_line && len > this->spacing * 10) {
+ //now test with to more points
+ Line middle_line;
+ middle_line.a = (line.a + middle_point) / 2;
+ middle_line.b = (line.b + middle_point) / 2;
+ for (int i = 0; i < _anchor_regions.size(); ++i) {
+ ExPolygon& poly = this->_anchor_regions[i];
+ BoundingBox& polybb = anchor_bb[i];
+ if (!polybb.contains(middle_line.a) || !poly.contains(middle_line.a)) { // using short-circuit evaluation to test boundingbox and only then the other
+ good_line = true;
+ break;
+ }
+ if (!polybb.contains(middle_line.b) || !poly.contains(middle_line.b)) { // using short-circuit evaluation to test boundingbox and only then the other
+ good_line = true;
+ break;
+ }
+ }
+ }
+ // If the line is still bad and is a long one, use the more costly intersection_ln. This case is rare enough to swallow the cost. (1/10000 on a benchy)
+ if (!good_line && len > this->spacing * 40) {
+ //now test with intersection_ln
+ Lines lines = intersection_ln(line, to_polygons(this->_anchor_regions));
+ good_line = lines.size() > 1;
+ }
+ }
+ }
+ if(good_line) {
+ // This line could be anchored at both side and goes over the void to bridge it in its middle.
+ //store stats
+ c.total_length_anchored += len;
+ c.max_length_anchored = std::max(c.max_length_anchored, len);
+ c.nb_lines_anchored++;
+ dist_anchored.push_back(len);
+ } else {
+ // this line could NOT be anchored.
+ c.total_length_free += len;
+ c.max_length_free = std::max(c.max_length_free, len);
+ c.nb_lines_free++;
}
}
}
- if (total_length == 0.)
+ if (c.total_length_anchored == 0. || c.nb_lines_anchored == 0) {
continue;
+ } else {
+ have_coverage = true;
+ // compute median
+ if (!dist_anchored.empty()) {
+ std::sort(dist_anchored.begin(), dist_anchored.end());
+ c.median_length_anchor = dist_anchored[dist_anchored.size() / 2];
+ }
+
- have_coverage = true;
- // Sum length of bridged lines.
- candidates[i_angle].coverage = total_length;
- /* The following produces more correct results in some cases and more broken in others.
- TODO: investigate, as it looks more reliable than line clipping. */
- // $directions_coverage{$angle} = sum(map $_->area, @{$self->coverage($angle)}) // 0;
- // max length of bridged lines
- candidates[i_angle].max_length = max_length;
+ // size is 20%
+ }
+ }
+
+ // if no direction produced coverage, then there's no bridge direction ?
+ if (!have_coverage) {
+ //try again to choose the least worse
+ // use only poly contour angles
+ if (bridge_direction_override == 0.) {
+ candidates = bridge_direction_candidates(true);
+ } else
+ candidates.emplace_back(BridgeDirection(bridge_direction_override));
+ for (size_t i_angle = 0; i_angle < candidates.size(); ++i_angle)
+ {
+ const double angle = candidates[i_angle].angle;
+ //use the whole polygon
+ Lines lines;
+ {
+ // Get an oriented bounding box around _anchor_regions.
+ BoundingBox bbox = get_extents_rotated(clip_area, -angle);
+ // Cover the region with line segments.
+ lines.reserve((bbox.max.y() - bbox.min.y() + this->spacing - SCALED_EPSILON) / this->spacing);
+ double s = sin(angle);
+ double c = cos(angle);
+ // The lines be spaced half the line width from the edge
+ for (coord_t y = bbox.min.y() + this->spacing / 2; y <= bbox.max.y(); y += this->spacing)
+ lines.push_back(Line(
+ Point((coord_t)round(c * bbox.min.x() - s * y), (coord_t)round(c * y + s * bbox.min.x())),
+ Point((coord_t)round(c * bbox.max.x() - s * y), (coord_t)round(c * y + s * bbox.max.x()))));
+ }
+ //compute stat on line with anchors, and their lengths.
+ BridgeDirection& c = candidates[i_angle];
+ std::vector<coordf_t> dist_anchored;
+ {
+ Lines clipped_lines = intersection_ln(lines, clip_area);
+ for (size_t i = 0; i < clipped_lines.size(); ++i) {
+ const Line& line = clipped_lines[i];
+ if (expolygons_contain(this->_anchor_regions, line.a) || expolygons_contain(this->_anchor_regions, line.b)) {
+ // This line has one anchor (or is totally anchored)
+ coordf_t len = line.length();
+ //store stats
+ c.total_length_anchored += len;
+ c.max_length_anchored = std::max(c.max_length_anchored, len);
+ c.nb_lines_anchored++;
+ dist_anchored.push_back(len);
+ } else {
+ // this line could NOT be anchored.
+ coordf_t len = line.length();
+ c.total_length_free += len;
+ c.max_length_free = std::max(c.max_length_free, len);
+ c.nb_lines_free++;
+ }
+ }
+ }
+ if (c.total_length_anchored == 0. || c.nb_lines_anchored == 0) {
+ continue;
+ } else {
+ have_coverage = true;
+ // compute median
+ if (!dist_anchored.empty()) {
+ std::sort(dist_anchored.begin(), dist_anchored.end());
+ c.median_length_anchor = dist_anchored[dist_anchored.size() / 2];
+ }
+
+
+ // size is 20%
+ }
+ }
}
// if no direction produced coverage, then there's no bridge direction
- if (! have_coverage)
+ if (!have_coverage)
return false;
-
- // sort directions by coverage - most coverage first
- std::sort(candidates.begin(), candidates.end());
+
+ //compute global stat (max & min median & max length)
+ std::vector<coordf_t> all_median_length;
+ std::vector<coordf_t> all_max_length;
+ for (BridgeDirection &c : candidates) {
+ all_median_length.push_back(c.median_length_anchor);
+ all_max_length.push_back(c.max_length_anchored);
+ }
+ std::sort(all_median_length.begin(), all_median_length.end());
+ std::sort(all_max_length.begin(), all_max_length.end());
+ coordf_t median_max_length = all_max_length[all_max_length.size() / 2];
+ coordf_t min_max_length = all_max_length.front();
+ coordf_t max_max_length = all_max_length.back();
+ coordf_t median_median_length = all_median_length[all_median_length.size() / 2];
+ coordf_t min_median_length = all_median_length.front();
+ coordf_t max_median_length = all_median_length.back();
+
+ //compute individual score
+ for (BridgeDirection& c : candidates) {
+ c.coverage = 0;
+ //ratio_anchored is 70% of the score
+ double ratio_anchored = c.total_length_anchored / (c.total_length_anchored + c.total_length_free);
+ c.coverage = 70 * ratio_anchored;
+ //median is 15% (and need to invert it)
+ double ratio_median = 1 - double(c.median_length_anchor - min_median_length) / (double)std::max(1., max_median_length - min_median_length);
+ c.coverage += 15 * ratio_median;
+ //max is 15 % (and need to invert it)
+ double ratio_max = 1 - double(c.max_length_anchored - min_max_length) / (double)std::max(1., max_max_length - min_max_length);
+ c.coverage += 15 * ratio_max;
+ //bonus for perimeter dir
+ if (c.along_perimeter_length > 0)
+ c.coverage += 5;
+
+ }
// if any other direction is within extrusion width of coverage, prefer it if shorter
+ // shorter = shorter max length, or if in espilon (10) range, the shorter mean length.
// TODO: There are two options here - within width of the angle with most coverage, or within width of the currently perferred?
size_t i_best = 0;
- for (size_t i = 1; i < candidates.size() && candidates[i_best].coverage - candidates[i].coverage < this->spacing; ++ i)
- if (candidates[i].max_length < candidates[i_best].max_length)
+ for (size_t i = 1; i < candidates.size(); ++ i)
+ if (candidates[i].coverage > candidates[i_best].coverage)
i_best = i;
this->angle = candidates[i_best].angle;
@@ -166,42 +339,95 @@ bool BridgeDetector::detect_angle(double bridge_direction_override)
#ifdef SLIC3R_DEBUG
printf(" Optimal infill angle is %d degrees\n", (int)Slic3r::Geometry::rad2deg(this->angle));
#endif
-
+
return true;
}
-std::vector<double> BridgeDetector::bridge_direction_candidates() const
+std::vector<BridgeDetector::BridgeDirection> BridgeDetector::bridge_direction_candidates(bool only_from_polygon) const
{
+ std::vector<BridgeDirection> angles;
// we test angles according to configured resolution
- std::vector<double> angles;
- for (int i = 0; i <= PI/this->resolution; ++i)
- angles.push_back(i * this->resolution);
+ if (!only_from_polygon)
+ for (int i = 0; i <= PI/this->resolution; ++i)
+ angles.emplace_back(i * this->resolution);
// we also test angles of each bridge contour
{
Lines lines = to_lines(this->expolygons);
- for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
- angles.push_back(line->direction());
+ //if many lines, only takes the bigger ones.
+ float mean_sqr_size = 0;
+ if (lines.size() > 200) {
+ for (int i = 0; i < 200; i++) {
+ mean_sqr_size += (float)lines[i].a.distance_to_square(lines[i].b);
+ }
+ mean_sqr_size /= 200;
+ for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) {
+ float dist_sqr = line->a.distance_to_square(line->b);
+ if (dist_sqr > mean_sqr_size)
+ angles.emplace_back(line->direction(), dist_sqr);
+ }
+ }else
+ for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line)
+ angles.emplace_back(line->direction(), line->a.distance_to_square(line->b));
}
/* we also test angles of each open supporting edge
(this finds the optimal angle for C-shaped supports) */
for (const Polyline &edge : this->_edges)
if (edge.first_point() != edge.last_point())
- angles.push_back(Line(edge.first_point(), edge.last_point()).direction());
+ angles.emplace_back(Line(edge.first_point(), edge.last_point()).direction());
// remove duplicates
- double min_resolution = PI/180.0; // 1 degree
- std::sort(angles.begin(), angles.end());
+ std::sort(angles.begin(), angles.end(), [](const BridgeDirection& bt1, const BridgeDirection& bt2) { return bt1.angle < bt2.angle; });
+
+ //first delete angles too close to an angle from a perimeter
+ for (size_t i = 1; i < angles.size(); ++i) {
+ if (angles[i - 1].along_perimeter_length > 0 && angles[i].along_perimeter_length == 0)
+ if (Slic3r::Geometry::directions_parallel(angles[i].angle, angles[i - 1].angle, this->resolution)) {
+ angles.erase(angles.begin() + i);
+ --i;
+ continue;
+ }
+ if (angles[i].along_perimeter_length > 0 && angles[i - 1].along_perimeter_length == 0)
+ if (Slic3r::Geometry::directions_parallel(angles[i].angle, angles[i - 1].angle, this->resolution)) {
+ angles.erase(angles.begin() + (i-1));
+ --i;
+ continue;
+ }
+ }
+ //then delete angle to close to each other (high resolution)
+ double min_resolution = this->resolution / 8;
for (size_t i = 1; i < angles.size(); ++i) {
- if (Slic3r::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) {
- angles.erase(angles.begin() + i);
- --i;
+ if (Slic3r::Geometry::directions_parallel(angles[i].angle, angles[i - 1].angle, min_resolution)) {
+ // keep the longest of the two.
+ if (angles[i].along_perimeter_length < angles[i - 1].along_perimeter_length) {
+ angles.erase(angles.begin() + i);
+ --i;
+ } else {
+ angles.erase(angles.begin() + (i-1));
+ --i;
+ }
+ }
+ }
+ //then, if too much angles, delete more
+ while (angles.size() > 200) {
+ min_resolution *= 2;
+ for (size_t i = 1; i < angles.size(); ++i) {
+ if (Slic3r::Geometry::directions_parallel(angles[i].angle, angles[i - 1].angle, min_resolution)) {
+ // keep the longest of the two.
+ if (angles[i].along_perimeter_length < angles[i - 1].along_perimeter_length) {
+ angles.erase(angles.begin() + i);
+ --i;
+ } else {
+ angles.erase(angles.begin() + (i - 1));
+ --i;
+ }
+ }
}
}
/* compare first value with last one and remove the greatest one (PI)
in case they are parallel (PI, 0) */
- if (Slic3r::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution))
+ if (Slic3r::Geometry::directions_parallel(angles.front().angle, angles.back().angle, min_resolution))
angles.pop_back();
return angles;
@@ -266,8 +492,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 = 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;
@@ -277,26 +551,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));
+ }
}
}
}
@@ -306,7 +619,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;
@@ -329,8 +642,7 @@ Polygons BridgeDetector::coverage(double angle) const
/* This method returns the bridge edges (as polylines) that are not supported
but would allow the entire bridge area to be bridged with detected angle
if supported too */
-void
-BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
+void BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
{
if (angle == -1) angle = this->angle;
if (angle == -1) return;
@@ -370,9 +682,7 @@ BridgeDetector::unsupported_edges(double angle, Polylines* unsupported) const
*/
}
-Polylines
-BridgeDetector::unsupported_edges(double angle) const
-{
+Polylines BridgeDetector::unsupported_edges(double angle) const {
Polylines pp;
this->unsupported_edges(angle, &pp);
return pp;