From 702cf43a0a9a86c2db9dfb27d50aa631cffe6b19 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sat, 18 Mar 2017 14:56:23 +0100 Subject: [PATCH] Bugfix: prevent crashes from rounding issues caused by almost-collinear points in the new FillRectilinear. #3684 --- xs/src/libslic3r/ExPolygon.cpp | 8 +++++++ xs/src/libslic3r/ExPolygon.hpp | 1 + xs/src/libslic3r/Fill/FillRectilinear.cpp | 15 ++++++++----- xs/src/libslic3r/Polygon.cpp | 26 +++++++++++++++++++++++ xs/src/libslic3r/Polygon.hpp | 2 ++ 5 files changed, 47 insertions(+), 5 deletions(-) diff --git a/xs/src/libslic3r/ExPolygon.cpp b/xs/src/libslic3r/ExPolygon.cpp index 19c3184f3..ec02acc35 100644 --- a/xs/src/libslic3r/ExPolygon.cpp +++ b/xs/src/libslic3r/ExPolygon.cpp @@ -129,6 +129,14 @@ ExPolygon::has_boundary_point(const Point &point) const return false; } +void +ExPolygon::remove_vertical_collinear_points(coord_t tolerance) +{ + this->contour.remove_vertical_collinear_points(tolerance); + for (Polygon &p : this->holes) + p.remove_vertical_collinear_points(tolerance); +} + void ExPolygon::simplify_p(double tolerance, Polygons* polygons) const { diff --git a/xs/src/libslic3r/ExPolygon.hpp b/xs/src/libslic3r/ExPolygon.hpp index 4289eb390..63cc560cd 100644 --- a/xs/src/libslic3r/ExPolygon.hpp +++ b/xs/src/libslic3r/ExPolygon.hpp @@ -29,6 +29,7 @@ class ExPolygon bool contains(const Point &point) const; bool contains_b(const Point &point) const; bool has_boundary_point(const Point &point) const; + void remove_vertical_collinear_points(coord_t tolerance); void simplify_p(double tolerance, Polygons* polygons) const; Polygons simplify_p(double tolerance) const; ExPolygons simplify(double tolerance) const; diff --git a/xs/src/libslic3r/Fill/FillRectilinear.cpp b/xs/src/libslic3r/Fill/FillRectilinear.cpp index cc7b0ca13..2d3c84eb0 100644 --- a/xs/src/libslic3r/Fill/FillRectilinear.cpp +++ b/xs/src/libslic3r/Fill/FillRectilinear.cpp @@ -1,3 +1,9 @@ +//#define DEBUG_RECTILINEAR +#ifdef DEBUG_RECTILINEAR + #undef NDEBUG + #include "../SVG.hpp" +#endif + #include "../ClipperUtils.hpp" #include "../ExPolygon.hpp" #include "../PolylineCollection.hpp" @@ -7,17 +13,16 @@ #include "FillRectilinear.hpp" -//#define DEBUG_RECTILINEAR -#ifdef DEBUG_RECTILINEAR - #include "../SVG.hpp" -#endif - namespace Slic3r { void FillRectilinear::_fill_single_direction(ExPolygon expolygon, const direction_t &direction, coord_t x_shift, Polylines* out) { + // Remove almost collinear points (vertical ones might break this algorithm + // because of rounding). + expolygon.remove_vertical_collinear_points(1); + // rotate polygons so that we can work with vertical lines here expolygon.rotate(-direction.first); diff --git a/xs/src/libslic3r/Polygon.cpp b/xs/src/libslic3r/Polygon.cpp index e36512970..3d87a986b 100644 --- a/xs/src/libslic3r/Polygon.cpp +++ b/xs/src/libslic3r/Polygon.cpp @@ -148,6 +148,32 @@ Polygon::contains(const Point &point) const return result; } +void +Polygon::douglas_peucker(double tolerance) +{ + this->points.push_back(this->points.front()); + this->points = MultiPoint::_douglas_peucker(this->points, tolerance); + this->points.pop_back(); +} + +void +Polygon::remove_vertical_collinear_points(coord_t tolerance) +{ + Points &pp = this->points; + pp.push_back(pp.front()); + for (size_t i = 0; i < pp.size()-1; ++i) { + while (i < pp.size()-1) { + Point &next = pp[i+1]; + if (std::abs(next.x - pp[i].x) <= tolerance) { + pp.erase(pp.begin() + i+1); + } else { + break; + } + } + } + pp.pop_back(); +} + // this only works on CCW polygons as CW will be ripped out by Clipper's simplify_polygons() Polygons Polygon::simplify(double tolerance) const diff --git a/xs/src/libslic3r/Polygon.hpp b/xs/src/libslic3r/Polygon.hpp index 1b9887218..b1576ad27 100644 --- a/xs/src/libslic3r/Polygon.hpp +++ b/xs/src/libslic3r/Polygon.hpp @@ -39,6 +39,8 @@ class Polygon : public MultiPoint { // Does an unoriented polygon contain a point? // Tested by counting intersections along a horizontal line. bool contains(const Point &point) const; + void douglas_peucker(double tolerance); + void remove_vertical_collinear_points(coord_t tolerance); Polygons simplify(double tolerance) const; void simplify(double tolerance, Polygons &polygons) const; void triangulate_convex(Polygons* polygons) const;