diff --git a/src/libslic3r/Fill/FillBase.cpp b/src/libslic3r/Fill/FillBase.cpp index 88eba9a51..fa7dd2851 100644 --- a/src/libslic3r/Fill/FillBase.cpp +++ b/src/libslic3r/Fill/FillBase.cpp @@ -2,6 +2,7 @@ #include "../ClipperUtils.hpp" #include "../EdgeGrid.hpp" +#include "../Geometry.hpp" #include "../Surface.hpp" #include "../PrintConfig.hpp" #include "../libslic3r.h" @@ -777,6 +778,8 @@ void mark_boundary_segments_touching_infill( const Vec2d *pt2; } visitor(grid, boundary, boundary_data, distance_colliding * distance_colliding); + BoundingBoxf bboxf(boundary_bbox.min.cast(), boundary_bbox.max.cast()); + bboxf.offset(- SCALED_EPSILON); for (const Polyline &polyline : infill) { // Clip the infill polyline by the Eucledian distance along the polyline. SegmentPoint start_point = clip_start_segment_and_point(polyline.points, clip_distance); @@ -814,10 +817,12 @@ void mark_boundary_segments_touching_infill( Vec2d vperp(-v.y(), v.x()); Vec2d a = pt1 - v - vperp; Vec2d b = pt1 + v - vperp; - grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); + if (Geometry::liang_barsky_line_clipping(a, b, bboxf)) + grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); a = pt1 - v + vperp; b = pt1 + v + vperp; - grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); + if (Geometry::liang_barsky_line_clipping(a, b, bboxf)) + grid.visit_cells_intersecting_line(a.cast(), b.cast(), visitor); #endif } } diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index d996658f2..283d1edb0 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -137,6 +137,79 @@ inline bool segments_intersect( segments_could_intersect(jp1, jp2, ip1, ip2) <= 0; } +// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html +template +bool liang_barsky_line_clipping( + // Start and end points of the source line, result will be stored there as well. + Eigen::Matrix &x0, + Eigen::Matrix &x1, + // Bounding box to clip with. + const BoundingBoxBase> &bbox) +{ + Eigen::Matrix v = x1 - x0; + double t0 = 0.0; + double t1 = 1.0; + + // Traverse through left, right, bottom, top edges. + for (int edge = 0; edge < 4; ++ edge) + { + double p, q; + switch (edge) { + case 0: p = - v.x(); q = - bbox.min.x() + x0.x(); break; + case 1: p = v.x(); q = bbox.max.x() - x0.x(); break; + case 2: p = - v.y(); q = - bbox.min.y() + x0.y(); break; + default: p = v.y(); q = bbox.max.y() - x0.y(); break; + } + + if (p == 0) { + if (q < 0) + // Line parallel to the bounding box edge is fully outside of the bounding box. + return false; + // else don't clip + } else { + double r = q / p; + if (p < 0) { + if (r > t1) + // Fully clipped. + return false; + if (r > t0) + // Partially clipped. + t0 = r; + } else { + assert(p > 0); + if (r < t0) + // Fully clipped. + return false; + if (r < t1) + // Partially clipped. + t1 = r; + } + } + } + + // Clipped successfully. + x1 = x0 + t1 * v; + x0 += t0 * v; + return true; +} + +// Based on Liang-Barsky function by Daniel White @ http://www.skytopia.com/project/articles/compsci/clipping.html +template +bool liang_barsky_line_clipping( + // Start and end points of the source line. + const Eigen::Matrix &x0src, + const Eigen::Matrix &x1src, + // Bounding box to clip with. + const BoundingBoxBase> &bbox, + // Start and end points of the clipped line. + Eigen::Matrix &x0clip, + Eigen::Matrix &x1clip) +{ + x0clip = x0src; + x1clip = x1src; + return liang_barsky_line_clipping(x0clip, x1clip, bbox); +} + Pointf3s convex_hull(Pointf3s points); Polygon convex_hull(Points points); Polygon convex_hull(const Polygons &polygons); diff --git a/src/libslic3r/Line.cpp b/src/libslic3r/Line.cpp index e5f7b8fa9..05cbfee4e 100644 --- a/src/libslic3r/Line.cpp +++ b/src/libslic3r/Line.cpp @@ -107,6 +107,17 @@ bool Line::intersection(const Line &l2, Point *intersection) const return false; // not intersecting } +bool Line::clip_with_bbox(const BoundingBox &bbox) +{ + Vec2d x0clip, x1clip; + bool result = Geometry::liang_barsky_line_clipping(this->a.cast(), this->b.cast(), BoundingBoxf(bbox.min.cast(), bbox.max.cast()), x0clip, x1clip); + if (result) { + this->a = x0clip.cast(); + this->b = x1clip.cast(); + } + return result; +} + Vec3d Linef3::intersect_plane(double z) const { auto v = (this->b - this->a).cast(); diff --git a/src/libslic3r/Line.hpp b/src/libslic3r/Line.hpp index 559ca946a..06809c02a 100644 --- a/src/libslic3r/Line.hpp +++ b/src/libslic3r/Line.hpp @@ -6,6 +6,7 @@ namespace Slic3r { +class BoundingBox; class Line; class Line3; class Linef3; @@ -43,6 +44,8 @@ public: Vector normal() const { return Vector((this->b(1) - this->a(1)), -(this->b(0) - this->a(0))); } bool intersection(const Line& line, Point* intersection) const; double ccw(const Point& point) const { return point.ccw(*this); } + // Clip a line with a bounding box. Returns false if the line is completely outside of the bounding box. + bool clip_with_bbox(const BoundingBox &bbox); static double distance_to_squared(const Point &point, const Point &a, const Point &b); static double distance_to(const Point &point, const Point &a, const Point &b) { return sqrt(distance_to_squared(point, a, b)); }