Polygons ExtrusionLoop::grow() const { if (this->paths.empty()) return Polygons(); // collect all the path widths std::vector<float> widths; for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) widths.push_back(path->width); // grow this polygon with the minimum common width // (this ensures vertices are grown correctly, which doesn't happen if we just // union the paths grown individually) const float min_width = *std::min_element(widths.begin(), widths.end()); const Polygon p = this->polygon(); Polygons pp = diff( offset(p, +scale_(min_width/2)), offset(p, -scale_(min_width/2)) ); // if we have thicker segments, grow them if (min_width != *std::max_element(widths.begin(), widths.end())) { for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) append_to(pp, path->grow()); } return union_(pp); }
// Splitting an extrusion loop, possibly made of multiple segments, some of the segments may be bridging. void ExtrusionLoop::split_at(const Point &point, bool prefer_non_overhang) { if (this->paths.empty()) return; // Find the closest path and closest point belonging to that path. Avoid overhangs, if asked for. size_t path_idx = 0; Point p; { double min = std::numeric_limits<double>::max(); Point p_non_overhang; size_t path_idx_non_overhang = 0; double min_non_overhang = std::numeric_limits<double>::max(); for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { Point p_tmp = point.projection_onto(path->polyline); double dist = point.distance_to(p_tmp); if (dist < min) { p = p_tmp; min = dist; path_idx = path - this->paths.begin(); } if (prefer_non_overhang && ! path->is_bridge() && dist < min_non_overhang) { p_non_overhang = p_tmp; min_non_overhang = dist; path_idx_non_overhang = path - this->paths.begin(); } } if (prefer_non_overhang && min_non_overhang != std::numeric_limits<double>::max()) { // Only apply the non-overhang point if there is one. path_idx = path_idx_non_overhang; p = p_non_overhang; } } // now split path_idx in two parts const ExtrusionPath &path = this->paths[path_idx]; ExtrusionPath p1(path.role, path.mm3_per_mm, path.width, path.height); ExtrusionPath p2(path.role, path.mm3_per_mm, path.width, path.height); path.polyline.split_at(p, &p1.polyline, &p2.polyline); if (this->paths.size() == 1) { if (! p1.polyline.is_valid()) std::swap(this->paths.front().polyline.points, p2.polyline.points); else if (! p2.polyline.is_valid()) std::swap(this->paths.front().polyline.points, p1.polyline.points); else { p2.polyline.points.insert(p2.polyline.points.end(), p1.polyline.points.begin() + 1, p1.polyline.points.end()); std::swap(this->paths.front().polyline.points, p2.polyline.points); } } else { // install the two paths this->paths.erase(this->paths.begin() + path_idx); if (p2.polyline.is_valid()) this->paths.insert(this->paths.begin() + path_idx, p2); if (p1.polyline.is_valid()) this->paths.insert(this->paths.begin() + path_idx, p1); } // split at the new vertex this->split_at_vertex(p); }
Polygons ExtrusionLoop::grow() const { Polygons pp; for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { Polygons path_pp = path->grow(); pp.insert(pp.end(), path_pp.begin(), path_pp.end()); } return pp; }
bool ExtrusionLoop::has_overhang_point(const Point &point) const { for (ExtrusionPaths::const_iterator path = this->paths.begin(); path != this->paths.end(); ++path) { int pos = path->polyline.find_point(point); if (pos != -1) { // point belongs to this path // we consider it overhang only if it's not an endpoint return (path->is_bridge() && pos > 0 && pos != (int)(path->polyline.points.size())-1); } } return false; }