#include "Geometry.hpp" #include "clipper.hpp" #include #include #include namespace Slic3r { namespace Geometry { static bool sort_points (Point a, Point b) { return (a.x < b.x) || (a.x == b.x && a.y < b.y); } /* This implementation is based on Andrew's monotone chain 2D convex hull algorithm */ void convex_hull(Points &points, Polygon* hull) { assert(points.size() >= 3); // sort input points std::sort(points.begin(), points.end(), sort_points); int n = points.size(), k = 0; hull->points.resize(2*n); // Build lower hull for (int i = 0; i < n; i++) { while (k >= 2 && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--; hull->points[k++] = points[i]; } // Build upper hull for (int i = n-2, t = k+1; i >= 0; i--) { while (k >= t && points[i].ccw(hull->points[k-2], hull->points[k-1]) <= 0) k--; hull->points[k++] = points[i]; } hull->points.resize(k); assert( hull->points.front().coincides_with(hull->points.back()) ); hull->points.pop_back(); } /* accepts an arrayref of points and returns a list of indices according to a nearest-neighbor walk */ void chained_path(Points &points, std::vector &retval, Point start_near) { PointPtrs my_points; std::map indices; my_points.reserve(points.size()); for (Points::iterator it = points.begin(); it != points.end(); ++it) { my_points.push_back(&*it); indices[&*it] = it - points.begin(); } retval.reserve(points.size()); while (!my_points.empty()) { Points::size_type idx = start_near.nearest_point_index(my_points); start_near = *my_points[idx]; retval.push_back(indices[ my_points[idx] ]); my_points.erase(my_points.begin() + idx); } } void chained_path(Points &points, std::vector &retval) { if (points.empty()) return; // can't call front() on empty vector chained_path(points, retval, points.front()); } /* retval and items must be different containers */ template void chained_path_items(Points &points, T &items, T &retval) { std::vector indices; chained_path(points, indices); for (std::vector::const_iterator it = indices.begin(); it != indices.end(); ++it) retval.push_back(items[*it]); } template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval); } }