void PolylineCollection::chained_path_from(Point start_near, PolylineCollection* retval, bool no_reverse) const { Polylines my_paths = this->polylines; Points endpoints; //里面存储所有polyline里面的第一个点和允许翻转时的最后一个点的坐标 for (Polylines::const_iterator it = my_paths.begin(); it != my_paths.end(); ++it) { endpoints.push_back(it->first_point()); if (no_reverse) { endpoints.push_back(it->first_point()); } else { endpoints.push_back(it->last_point()); } } while (!my_paths.empty()) { // find nearest point int start_index = start_near.nearest_point_index(endpoints); int path_index = start_index/2; if (start_index % 2 && !no_reverse) { my_paths.at(path_index).reverse(); } retval->polylines.push_back(my_paths.at(path_index)); my_paths.erase(my_paths.begin() + path_index); endpoints.erase(endpoints.begin() + 2*path_index, endpoints.begin() + 2*path_index + 2); start_near = retval->polylines.back().last_point(); } }
ExtrusionEntityCollection PerimeterGenerator::_fill_gaps(double min, double max, double w, const Polygons &gaps) const { ExtrusionEntityCollection coll; min *= (1 - INSET_OVERLAP_TOLERANCE); ExPolygons curr = diff_ex( offset2(gaps, -min/2, +min/2), offset2(gaps, -max/2, +max/2), true ); Polylines polylines; for (ExPolygons::const_iterator ex = curr.begin(); ex != curr.end(); ++ex) ex->medial_axis(max, min/2, &polylines); if (polylines.empty()) return coll; #ifdef SLIC3R_DEBUG if (!curr.empty()) printf(" %zu gaps filled with extrusion width = %f\n", curr.size(), w); #endif //my $flow = $layerm->flow(FLOW_ROLE_SOLID_INFILL, 0, $w); Flow flow( w, this->layer_height, this->solid_infill_flow.nozzle_diameter ); double mm3_per_mm = flow.mm3_per_mm(); for (Polylines::const_iterator p = polylines.begin(); p != polylines.end(); ++p) { ExtrusionPath path(erGapFill); path.polyline = *p; path.mm3_per_mm = mm3_per_mm; path.width = flow.width; path.height = this->layer_height; if (p->is_valid() && p->first_point().coincides_with(p->last_point())) { // since medial_axis() now returns only Polyline objects, detect loops here ExtrusionLoop loop; loop.paths.push_back(path); coll.append(loop); } else { coll.append(path); } } return coll; }
bool BridgeDetector::detect_angle() { if (this->_edges.empty() || this->_anchors.empty()) return false; /* Outset the bridge expolygon by half the amount we used for detecting anchors; we'll use this one to clip our test lines and be sure that their endpoints are inside the anchors and not on their contours leading to false negatives. */ Polygons clip_area; offset(this->expolygon, &clip_area, +this->extrusion_width/2); /* we'll now try several directions using a rudimentary visibility check: bridge in several directions and then sum the length of lines having both endpoints within anchors */ // 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); // we also test angles of each bridge contour { Polygons pp = this->expolygon; for (Polygons::const_iterator p = pp.begin(); p != pp.end(); ++p) { Lines lines = p->lines(); for (Lines::const_iterator line = lines.begin(); line != lines.end(); ++line) angles.push_back(line->direction()); } } /* we also test angles of each open supporting edge (this finds the optimal angle for C-shaped supports) */ for (Polylines::const_iterator edge = this->_edges.begin(); edge != this->_edges.end(); ++edge) { if (edge->first_point().coincides_with(edge->last_point())) continue; angles.push_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()); for (size_t i = 1; i < angles.size(); ++i) { if (xd::Geometry::directions_parallel(angles[i], angles[i-1], min_resolution)) { angles.erase(angles.begin() + i); --i; } } /* compare first value with last one and remove the greatest one (PI) in case they are parallel (PI, 0) */ if (xd::Geometry::directions_parallel(angles.front(), angles.back(), min_resolution)) angles.pop_back(); BridgeDirectionComparator bdcomp(this->extrusion_width); double line_increment = this->extrusion_width; bool have_coverage = false; for (std::vector<double>::const_iterator angle = angles.begin(); angle != angles.end(); ++angle) { Polygons my_clip_area = clip_area; ExPolygons my_anchors = this->_anchors; // rotate everything - the center point doesn't matter for (Polygons::iterator it = my_clip_area.begin(); it != my_clip_area.end(); ++it) it->rotate(-*angle, Point(0,0)); for (ExPolygons::iterator it = my_anchors.begin(); it != my_anchors.end(); ++it) it->rotate(-*angle, Point(0,0)); // generate lines in this direction BoundingBox bb; for (ExPolygons::const_iterator it = my_anchors.begin(); it != my_anchors.end(); ++it) bb.merge((Points)*it); Lines lines; for (coord_t y = bb.min.y; y <= bb.max.y; y += line_increment) lines.push_back(Line(Point(bb.min.x, y), Point(bb.max.x, y))); Lines clipped_lines; intersection(lines, my_clip_area, &clipped_lines); // remove any line not having both endpoints within anchors for (size_t i = 0; i < clipped_lines.size(); ++i) { Line &line = clipped_lines[i]; if (!xd::Geometry::contains(my_anchors, line.a) || !xd::Geometry::contains(my_anchors, line.b)) { clipped_lines.erase(clipped_lines.begin() + i); --i; } } std::vector<double> lengths; double total_length = 0; for (Lines::const_iterator line = clipped_lines.begin(); line != clipped_lines.end(); ++line) { double len = line->length(); lengths.push_back(len); total_length += len; } if (total_length) have_coverage = true; // sum length of bridged lines bdcomp.dir_coverage[*angle] = 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 bdcomp.dir_avg_length[*angle] = !lengths.empty() ? *std::max_element(lengths.begin(), lengths.end()) : 0; } // if no direction produced coverage, then there's no bridge direction if (!have_coverage) return false; // sort directions by score std::sort(angles.begin(), angles.end(), bdcomp); this->angle = angles.front(); if (this->angle >= PI) this->angle -= PI; // #ifdef SLIC3R_DEBUG // printf(" Optimal infill angle is %d degrees\n", (int)Slic3r::Geometry::rad2deg(this->angle)); // #endif return true; }