#include "IntersectionPoints.hpp" //#define USE_CGAL_SWEEP_LINE #ifdef USE_CGAL_SWEEP_LINE #include #include #include #include #include using NT = CGAL::Quotient; using Kernel = CGAL::Cartesian; using P2 = Kernel::Point_2; using Traits_2 = CGAL::Arr_segment_traits_2; using Segment = Traits_2::Curve_2; using Segments = std::vector; namespace priv { P2 convert(const Slic3r::Point &p) { return P2(p.x(), p.y()); } Slic3r::Vec2d convert(const P2 &p) { return Slic3r::Vec2d(CGAL::to_double(p.x()), CGAL::to_double(p.y())); } Slic3r::Pointfs compute_intersections(const Segments &segments) { std::vector intersections; // Compute all intersection points. CGAL::compute_intersection_points(segments.begin(), segments.end(), std::back_inserter(intersections)); if (intersections.empty()) return {}; Slic3r::Pointfs pts; pts.reserve(intersections.size()); for (const P2 &p : intersections) pts.push_back(convert(p)); return pts; } void add_polygon(const Slic3r::Polygon &polygon, Segments &segments) { if (polygon.points.size() < 2) return; P2 prev_point = priv::convert(polygon.last_point()); for (const Slic3r::Point &p : polygon.points) { P2 act_point = priv::convert(p); if (prev_point == act_point) continue; segments.emplace_back(prev_point, act_point); prev_point = act_point; } } Slic3r::Pointfs Slic3r::intersection_points(const Lines &lines) { return priv::compute_intersections2(lines); Segments segments; segments.reserve(lines.size()); for (Line l : lines) segments.emplace_back(priv::convert(l.a), priv::convert(l.b)); return priv::compute_intersections(segments); } Slic3r::Pointfs Slic3r::intersection_points(const Polygon &polygon) { Segments segments; segments.reserve(polygon.points.size()); priv::add_polygon(polygon, segments); return priv::compute_intersections(segments); } Slic3r::Pointfs Slic3r::intersection_points(const Polygons &polygons) { Segments segments; segments.reserve(count_points(polygons)); for (const Polygon &polygon : polygons) priv::add_polygon(polygon, segments); return priv::compute_intersections(segments); } Slic3r::Pointfs Slic3r::intersection_points(const ExPolygon &expolygon) { Segments segments; segments.reserve(count_points(expolygon)); priv::add_polygon(expolygon.contour, segments); for (const Polygon &hole : expolygon.holes) priv::add_polygon(hole, segments); return priv::compute_intersections(segments); } Slic3r::Pointfs Slic3r::intersection_points(const ExPolygons &expolygons) { Segments segments; segments.reserve(count_points(expolygons)); for (const ExPolygon &expolygon : expolygons) { priv::add_polygon(expolygon.contour, segments); for (const Polygon &hole : expolygon.holes) priv::add_polygon(hole, segments); } return priv::compute_intersections(segments); } } // namespace priv #else // USE_CGAL_SWEEP_LINE // use bounding boxes #include namespace priv { Slic3r::Pointfs compute_intersections(const Slic3r::Lines &lines) { using namespace Slic3r; // IMPROVE0: BoundingBoxes of Polygons // IMPROVE1: Polygon's neighbor lines can't intersect // e.g. use indices to Point to find same points // IMPROVE2: Use BentleyOttmann algorithm // https://doc.cgal.org/latest/Surface_sweep_2/index.html -- CGAL implementation is significantly slower // https://stackoverflow.com/questions/4407493/is-there-a-robust-c-implementation-of-the-bentley-ottmann-algorithm Pointfs pts; Point i; for (size_t li = 0; li < lines.size(); ++li) { const Line &l = lines[li]; const Point &a = l.a; const Point &b = l.b; Point min(std::min(a.x(), b.x()), std::min(a.y(), b.y())); Point max(std::max(a.x(), b.x()), std::max(a.y(), b.y())); BoundingBox bb(min, max); for (size_t li_ = li + 1; li_ < lines.size(); ++li_) { const Line &l_ = lines[li_]; const Point &a_ = l_.a; const Point &b_ = l_.b; if (a == b_ || b == a_ || a == a_ || b == b_) continue; Point min_(std::min(a_.x(), b_.x()), std::min(a_.y(), b_.y())); Point max_(std::max(a_.x(), b_.x()), std::max(a_.y(), b_.y())); BoundingBox bb_(min_, max_); // intersect of BB compare min max if (bb.intersects(bb_) && l.intersection(l_, &i)) pts.push_back(i.cast()); } } return pts; } } // namespace priv Slic3r::Pointfs Slic3r::intersection_points(const Lines &lines) { return priv::compute_intersections(lines); } Slic3r::Pointfs Slic3r::intersection_points(const Polygon &polygon) { return priv::compute_intersections(to_lines(polygon)); } Slic3r::Pointfs Slic3r::intersection_points(const Polygons &polygons) { return priv::compute_intersections(to_lines(polygons)); } Slic3r::Pointfs Slic3r::intersection_points(const ExPolygon &expolygon) { return priv::compute_intersections(to_lines(expolygon)); } Slic3r::Pointfs Slic3r::intersection_points(const ExPolygons &expolygons) { return priv::compute_intersections(to_lines(expolygons)); } #endif // USE_CGAL_SWEEP_LINE