From 518798beb39831e175d2c82f4d274351667eb502 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Thu, 21 Nov 2013 20:25:24 +0100 Subject: [PATCH] Incomplete work for porting simplify() to XS --- lib/Slic3r/ExtrusionPath.pm | 5 ---- lib/Slic3r/GCode/MotionPlanner.pm | 2 +- lib/Slic3r/GUI/Plater.pm | 2 +- lib/Slic3r/Polygon.pm | 7 ------ lib/Slic3r/Polyline.pm | 8 ------ lib/Slic3r/Print.pm | 10 ++------ lib/Slic3r/Surface.pm | 5 ---- t/clean_polylines.t | 4 +-- xs/src/ExPolygon.cpp | 26 ++++++++++++++++++++ xs/src/ExPolygon.hpp | 3 +++ xs/src/ExPolygonCollection.cpp | 10 ++++++++ xs/src/ExPolygonCollection.hpp | 1 + xs/src/ExtrusionEntity.cpp | 6 +++++ xs/src/ExtrusionEntity.hpp | 1 + xs/src/MultiPoint.cpp | 41 +++++++++++++++++++++++++++++++ xs/src/MultiPoint.hpp | 4 +++ xs/src/Point.cpp | 14 ++++++++--- xs/src/Point.hpp | 1 + xs/src/Polygon.cpp | 6 +++++ xs/src/Polygon.hpp | 2 ++ xs/xsp/ExPolygonCollection.xsp | 1 + xs/xsp/ExtrusionPath.xsp | 1 + xs/xsp/Polygon.xsp | 1 + xs/xsp/Polyline.xsp | 1 + 24 files changed, 121 insertions(+), 41 deletions(-) diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 531c7ab6e..a03ff487e 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -10,9 +10,4 @@ our @EXPORT_OK = qw(EXTR_ROLE_PERIMETER EXTR_ROLE_EXTERNAL_PERIMETER EXTR_ROLE_INTERNALBRIDGE EXTR_ROLE_SKIRT EXTR_ROLE_SUPPORTMATERIAL EXTR_ROLE_GAPFILL); our %EXPORT_TAGS = (roles => \@EXPORT_OK); -sub simplify { - my $self = shift; - $self->polyline($self->polyline->simplify(@_)); -} - 1; diff --git a/lib/Slic3r/GCode/MotionPlanner.pm b/lib/Slic3r/GCode/MotionPlanner.pm index eed0eb851..53f8ce2fa 100644 --- a/lib/Slic3r/GCode/MotionPlanner.pm +++ b/lib/Slic3r/GCode/MotionPlanner.pm @@ -38,7 +38,7 @@ sub BUILD { my $crossing_edges = $self->_crossing_edges; # simplify islands - @{$self->islands} = map $_->simplify($self->_inner_margin), @{$self->islands}; + $_->simplify($self->_inner_margin) for @{$self->islands}; # process individual islands for my $i (0 .. $#{$self->islands}) { diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 93c9e5f41..eff1ad04e 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1360,10 +1360,10 @@ sub make_thumbnail { # remove polygons with area <= 1mm my $area_threshold = Slic3r::Geometry::scale 1; $self->thumbnail->append( - map $_->simplify(0.5), grep $_->area >= $area_threshold, @{ $mesh->horizontal_projection }, ); + $self->thumbnail->simplify(0.5); } else { my $convex_hull = Slic3r::ExPolygon->new($self->convex_hull)->clone; $convex_hull->scale(1/&Slic3r::SCALING_FACTOR); diff --git a/lib/Slic3r/Polygon.pm b/lib/Slic3r/Polygon.pm index 79652b2b4..34ace2427 100644 --- a/lib/Slic3r/Polygon.pm +++ b/lib/Slic3r/Polygon.pm @@ -32,13 +32,6 @@ sub grow { return $self->split_at_first_point->grow(@_); } -# NOTE that this will turn the polygon to ccw regardless of its -# original orientation -sub simplify { - my $self = shift; - return @{Slic3r::Geometry::Clipper::simplify_polygons([ $self->SUPER::simplify(@_) ])}; -} - # this method subdivides the polygon segments to that no one of them # is longer than the length provided sub subdivide { diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index fc368a692..185dee5dc 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -27,14 +27,6 @@ sub remove_acute_vertices { polyline_remove_acute_vertices($self); } -sub simplify { - my $self = shift; - my $tolerance = shift || 10; - - my $simplified = Boost::Geometry::Utils::linestring_simplify($self->pp, $tolerance); - return __PACKAGE__->new(@$simplified); -} - sub bounding_box { my $self = shift; return Slic3r::Geometry::BoundingBox->new_from_points($self); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index a0ea9fb07..b13b2a7a0 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -317,14 +317,8 @@ sub _simplify_slices { my ($distance) = @_; foreach my $layer (map @{$_->layers}, @{$self->objects}) { - my @new = map $_->simplify($distance), map $_->clone, @{$layer->slices}; - $layer->slices->clear; - $layer->slices->append(@new); - foreach my $layerm (@{$layer->regions}) { - my @new = map $_->simplify($distance), map $_->clone, @{$layerm->slices}; - $layerm->slices->clear; - $layerm->slices->append(@new); - } + $layer->slices->simplify($distance); + $_->slices->simplify($distance) for @{$layer->regions}; } } diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index cc9a29c88..e0b6394f1 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -38,11 +38,6 @@ sub offset { return [ map $self->clone(expolygon => $_), @{$self->expolygon->offset_ex(@_)} ]; } -sub simplify { - my $self = shift; - return map $self->clone(expolygon => $_), $self->expolygon->simplify(@_); -} - sub p { my $self = shift; return @{$self->polygons}; diff --git a/t/clean_polylines.t b/t/clean_polylines.t index acd72a288..4ad905f68 100644 --- a/t/clean_polylines.t +++ b/t/clean_polylines.t @@ -24,7 +24,7 @@ use Slic3r; my $polyline = Slic3r::Polyline->new( [0,0],[1,0],[2,0],[2,1],[2,2],[1,2],[0,2],[0,1],[0,0], ); - $polyline = $polyline->simplify(1); + $polyline->simplify(1); is_deeply $polyline->pp, [ [0, 0], [2, 0], [2, 2], [0, 2], [0, 0] ], 'Douglas-Peucker'; } @@ -32,7 +32,7 @@ use Slic3r; my $polyline = Slic3r::Polyline->new( [0,0], [50,50], [100,0], [125,-25], [150,50], ); - $polyline = $polyline->simplify(25); + $polyline->simplify(25); is_deeply $polyline->pp, [ [0, 0], [50, 50], [125, -25], [150, 50] ], 'Douglas-Peucker'; } diff --git a/xs/src/ExPolygon.cpp b/xs/src/ExPolygon.cpp index 2a60058d2..d98a86fc5 100644 --- a/xs/src/ExPolygon.cpp +++ b/xs/src/ExPolygon.cpp @@ -82,6 +82,32 @@ ExPolygon::contains_point(const Point* point) const return true; } +Polygons +ExPolygon::simplify(double tolerance) const +{ + Polygons p; + this->contour.simplify(tolerance, p); + for (Polygons::const_iterator it = this->holes.begin(); it != this->holes.end(); ++it) + it->simplify(tolerance, p); + simplify_polygons(p, p); + return p; +} + +ExPolygons +ExPolygon::simplify(double tolerance) const +{ + Polygons p = this->simplify(tolerance); + return union_(p); +} + +void +ExPolygon::simplify(double tolerance, ExPolygons &expolygons) const +{ + ExPolygons ep = this->simplify(tolerance); + expolygons.reserve(expolygons.size() + ep.size()); + expolygons.insert(expolygons.end(), ep.begin(), ep.end()); +} + #ifdef SLIC3RXS SV* ExPolygon::to_AV() { diff --git a/xs/src/ExPolygon.hpp b/xs/src/ExPolygon.hpp index ecb0012a8..8576c6b79 100644 --- a/xs/src/ExPolygon.hpp +++ b/xs/src/ExPolygon.hpp @@ -19,6 +19,9 @@ class ExPolygon bool is_valid() const; bool contains_line(const Line* line) const; bool contains_point(const Point* point) const; + Polygons simplify(double tolerance) const; + ExPolygons simplify(double tolerance) const; + void simplify(double tolerance, ExPolygons &expolygons) const; #ifdef SLIC3RXS void from_SV(SV* poly_sv); diff --git a/xs/src/ExPolygonCollection.cpp b/xs/src/ExPolygonCollection.cpp index da257ca39..d6beca4dc 100644 --- a/xs/src/ExPolygonCollection.cpp +++ b/xs/src/ExPolygonCollection.cpp @@ -47,4 +47,14 @@ ExPolygonCollection::contains_point(const Point* point) const return false; } +void +ExPolygonCollection::simplify(double tolerance) +{ + ExPolygons t; + for (ExPolygons::const_iterator it = this->expolygons.begin(); it != this->expolygons.end(); ++it) { + it->simplify_and_append_to(tolerance, t); + } + this->expolygons = t; +} + } diff --git a/xs/src/ExPolygonCollection.hpp b/xs/src/ExPolygonCollection.hpp index d4b7d8162..5a5c4d8d4 100644 --- a/xs/src/ExPolygonCollection.hpp +++ b/xs/src/ExPolygonCollection.hpp @@ -15,6 +15,7 @@ class ExPolygonCollection void translate(double x, double y); void rotate(double angle, Point* center); bool contains_point(const Point* point) const; + void simplify(double tolerance); }; } diff --git a/xs/src/ExtrusionEntity.cpp b/xs/src/ExtrusionEntity.cpp index 1c8231af7..9c5cd5d31 100644 --- a/xs/src/ExtrusionEntity.cpp +++ b/xs/src/ExtrusionEntity.cpp @@ -78,6 +78,12 @@ ExtrusionPath::clip_end(double distance) this->polyline.clip_end(distance); } +void +ExtrusionPath::simplify(double tolerance) +{ + this->polyline.simplify(tolerance); +} + double ExtrusionPath::length() const { diff --git a/xs/src/ExtrusionEntity.hpp b/xs/src/ExtrusionEntity.hpp index c97ceb2a2..c763ad77e 100644 --- a/xs/src/ExtrusionEntity.hpp +++ b/xs/src/ExtrusionEntity.hpp @@ -54,6 +54,7 @@ class ExtrusionPath : public ExtrusionEntity ExtrusionEntityCollection* intersect_expolygons(ExPolygonCollection* collection) const; ExtrusionEntityCollection* subtract_expolygons(ExPolygonCollection* collection) const; void clip_end(double distance); + void simplify(double tolerance); double length() const; private: ExtrusionEntityCollection* _inflate_collection(const Polylines &polylines) const; diff --git a/xs/src/MultiPoint.cpp b/xs/src/MultiPoint.cpp index dab41877b..0c0bcd33b 100644 --- a/xs/src/MultiPoint.cpp +++ b/xs/src/MultiPoint.cpp @@ -55,6 +55,47 @@ MultiPoint::is_valid() const return this->points.size() >= 2; } +void +MultiPoint::simplify(double tolerance) +{ + this->points = MultiPoint::_douglas_peucker(this->points, tolerance); +} + +Points +MultiPoint::_douglas_peucker(Points &points, double tolerance) +{ + Points results; + double dmax = 0; + int index = 0; + Line full(points.front(), points.back()); + for (Points::const_iterator it = points.begin() + 1; it != points.end(); ++it) { + double d = it->distance_to(full); + if (d > dmax) { + index = it - points.begin(); + dmax = d; + } + } + if (dmax >= tolerance) { + Points dp0; + dp0.reserve(index + 1); + dp0.insert(dp0.end(), points.begin(), points.begin() + index + 1); + Points dp1 = MultiPoint::_douglas_peucker(dp0, tolerance); + results.reserve(results.size() + dp1.size() - 1); + results.insert(results.end(), dp1.begin(), dp1.end() - 1); + + dp0.clear(); + dp0.reserve(points.size() - index + 1); + dp0.insert(dp0.end(), points.begin() + index, points.end()); + dp1 = MultiPoint::_douglas_peucker(dp0, tolerance); + results.reserve(results.size() + dp1.size()); + results.insert(results.end(), dp1.begin(), dp1.end()); + } else { + results.push_back(points.front()); + results.push_back(points.back()); + } + return results; +} + #ifdef SLIC3RXS void MultiPoint::from_SV(SV* poly_sv) diff --git a/xs/src/MultiPoint.hpp b/xs/src/MultiPoint.hpp index a1ad19c95..a13d6eba2 100644 --- a/xs/src/MultiPoint.hpp +++ b/xs/src/MultiPoint.hpp @@ -21,6 +21,7 @@ class MultiPoint virtual Lines lines() const = 0; double length() const; bool is_valid() const; + void simplify(double tolerance); #ifdef SLIC3RXS void from_SV(SV* poly_sv); @@ -28,6 +29,9 @@ class MultiPoint SV* to_AV(); SV* to_SV_pureperl() const; #endif + + private: + static Points _douglas_peucker(Points &points, double tolerance); }; } diff --git a/xs/src/Point.cpp b/xs/src/Point.cpp index b39a06c11..cef2bfd90 100644 --- a/xs/src/Point.cpp +++ b/xs/src/Point.cpp @@ -76,12 +76,18 @@ Point::distance_to(const Point* point) const double Point::distance_to(const Line* line) const { - if (line->a.coincides_with(&line->b)) return this->distance_to(&line->a); + return this->distance_to(*line); +} + +double +Point::distance_to(const Line &line) const +{ + if (line.a.coincides_with(&line.b)) return this->distance_to(&line.a); - double n = (line->b.x - line->a.x) * (line->a.y - this->y) - - (line->a.x - this->x) * (line->b.y - line->a.y); + double n = (line.b.x - line.a.x) * (line.a.y - this->y) + - (line.a.x - this->x) * (line.b.y - line.a.y); - return abs(n) / line->length(); + return abs(n) / line.length(); } #ifdef SLIC3RXS diff --git a/xs/src/Point.hpp b/xs/src/Point.hpp index 5023ad663..981b6f214 100644 --- a/xs/src/Point.hpp +++ b/xs/src/Point.hpp @@ -25,6 +25,7 @@ class Point Point* nearest_point(Points points) const; double distance_to(const Point* point) const; double distance_to(const Line* line) const; + double distance_to(const Line &line) const; #ifdef SLIC3RXS void from_SV(SV* point_sv); diff --git a/xs/src/Polygon.cpp b/xs/src/Polygon.cpp index a6e6afebf..f2e9b1540 100644 --- a/xs/src/Polygon.cpp +++ b/xs/src/Polygon.cpp @@ -125,6 +125,12 @@ Polygon::contains_point(const Point* point) const return result; } +Polygons +Polygon::simplify(double tolerance) const +{ + +} + #ifdef SLIC3RXS SV* Polygon::to_SV_ref() { diff --git a/xs/src/Polygon.hpp b/xs/src/Polygon.hpp index 4710e5333..370925d7c 100644 --- a/xs/src/Polygon.hpp +++ b/xs/src/Polygon.hpp @@ -24,6 +24,8 @@ class Polygon : public MultiPoint { bool make_clockwise(); bool is_valid() const; bool contains_point(const Point* point) const; + Polygons simplify(double tolerance) const; + void simplify(double tolerance, Polygons &polygons) const; #ifdef SLIC3RXS SV* to_SV_ref(); diff --git a/xs/xsp/ExPolygonCollection.xsp b/xs/xsp/ExPolygonCollection.xsp index 7a108235f..ec404528b 100644 --- a/xs/xsp/ExPolygonCollection.xsp +++ b/xs/xsp/ExPolygonCollection.xsp @@ -17,6 +17,7 @@ int count() %code{% RETVAL = THIS->expolygons.size(); %}; bool contains_point(Point* point); + void simplify(double tolerance); %{ ExPolygonCollection* diff --git a/xs/xsp/ExtrusionPath.xsp b/xs/xsp/ExtrusionPath.xsp index 3ba98c880..b4248214c 100644 --- a/xs/xsp/ExtrusionPath.xsp +++ b/xs/xsp/ExtrusionPath.xsp @@ -25,6 +25,7 @@ ExtrusionEntityCollection* subtract_expolygons(ExPolygonCollection* collection) %code{% const char* CLASS = "Slic3r::ExtrusionPath::Collection"; RETVAL = THIS->subtract_expolygons(collection); %}; void clip_end(double distance); + void simplify(double tolerance); double length(); bool is_perimeter(); bool is_fill(); diff --git a/xs/xsp/Polygon.xsp b/xs/xsp/Polygon.xsp index 1236c4f0c..363cac38b 100644 --- a/xs/xsp/Polygon.xsp +++ b/xs/xsp/Polygon.xsp @@ -34,6 +34,7 @@ Point* first_point() %code{% const char* CLASS = "Slic3r::Point"; RETVAL = THIS->first_point(); %}; bool contains_point(Point* point); + void simplify(double tolerance); %{ Polygon* diff --git a/xs/xsp/Polyline.xsp b/xs/xsp/Polyline.xsp index 40d88a1cd..ab7eb3307 100644 --- a/xs/xsp/Polyline.xsp +++ b/xs/xsp/Polyline.xsp @@ -29,6 +29,7 @@ bool is_valid(); void clip_end(double distance); void clip_start(double distance); + void simplify(double tolerance); %{ Polyline*