From 6ce651eb4ae0fab4d99ef73d176e2a614e0e710c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 7 Dec 2014 19:53:22 +0100 Subject: [PATCH] Fixed wrong implementation of concave_points() and convex_points() in C++. #2384 --- t/geometry.t | 28 +++++++++++++++++++++++++++- t/perimeters.t | 2 +- xs/src/libslic3r/MultiPoint.hpp | 2 ++ xs/src/libslic3r/Point.cpp | 7 +++++++ xs/src/libslic3r/Point.hpp | 1 + xs/src/libslic3r/Polygon.cpp | 28 ++++++++++++---------------- xs/src/libslic3r/Polygon.hpp | 3 +++ 7 files changed, 53 insertions(+), 18 deletions(-) diff --git a/t/geometry.t b/t/geometry.t index 24fbf52d9..d85c8bbcf 100644 --- a/t/geometry.t +++ b/t/geometry.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 33; +plan tests => 38; BEGIN { use FindBin; @@ -213,3 +213,29 @@ my $polygons = [ is scalar(@{$square->concave_points(PI*4/3)}), 0, 'no concave vertices detected in convex polygon'; is scalar(@{$square->convex_points(PI*2/3)}), 4, 'four convex vertices detected in square'; } + +{ + my $triangle = Slic3r::Polygon->new( + [16000170,26257364], [714223,461012], [31286371,461008], + ); + is scalar(@{$triangle->concave_points(PI*4/3)}), 0, 'no concave vertices detected in triangle'; + is scalar(@{$triangle->convex_points(PI*2/3)}), 3, 'three convex vertices detected in triangle'; +} + +{ + my $triangle = Slic3r::Polygon->new( + [16000170,26257364], [714223,461012], [20000000,461012], [31286371,461012], + ); + is scalar(@{$triangle->concave_points(PI*4/3)}), 0, 'no concave vertices detected in triangle having collinear point'; + is scalar(@{$triangle->convex_points(PI*2/3)}), 3, 'three convex vertices detected in triangle having collinear point'; +} + +{ + my $triangle = Slic3r::Polygon->new( + [16000170,26257364], [714223,461012], [31286371,461008], + ); + my $simplified = $triangle->simplify(250000)->[0]; + is scalar(@$simplified), 3, 'triangle is never simplified to less than 3 points'; +} + +__END__ diff --git a/t/perimeters.t b/t/perimeters.t index 17e1b31c7..49217fd82 100644 --- a/t/perimeters.t +++ b/t/perimeters.t @@ -266,7 +266,7 @@ use Slic3r::Test; my $was_extruding = 0; my @seam_points = (); my $print = Slic3r::Test::init_print($model_name, config => $config); - Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { + Slic3r::GCode::Reader->new->parse(my $gcode = Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($info->{extruding}) { diff --git a/xs/src/libslic3r/MultiPoint.hpp b/xs/src/libslic3r/MultiPoint.hpp index ba3c72e50..eaca9b8eb 100644 --- a/xs/src/libslic3r/MultiPoint.hpp +++ b/xs/src/libslic3r/MultiPoint.hpp @@ -17,6 +17,8 @@ class MultiPoint Points points; operator Points() const; + MultiPoint() {}; + explicit MultiPoint(const Points &_points): points(_points) {}; void scale(double factor); void translate(double x, double y); void translate(const Point &vector); diff --git a/xs/src/libslic3r/Point.cpp b/xs/src/libslic3r/Point.cpp index 9debe9e8e..76da85334 100644 --- a/xs/src/libslic3r/Point.cpp +++ b/xs/src/libslic3r/Point.cpp @@ -160,6 +160,13 @@ Point::ccw(const Line &line) const return this->ccw(line.a, line.b); } +// returns the CCW angle between this-p1 and this-p2 +double +Point::ccw_angle(const Point &p1, const Point &p2) const +{ + return Line(*this, p1).orientation() - Line(*this, p2).orientation(); +} + Point Point::projection_onto(const MultiPoint &poly) const { diff --git a/xs/src/libslic3r/Point.hpp b/xs/src/libslic3r/Point.hpp index 514eb51cd..60127b1b7 100644 --- a/xs/src/libslic3r/Point.hpp +++ b/xs/src/libslic3r/Point.hpp @@ -48,6 +48,7 @@ class Point double distance_to(const Line &line) const; double ccw(const Point &p1, const Point &p2) const; double ccw(const Line &line) const; + double ccw_angle(const Point &p1, const Point &p2) const; Point projection_onto(const MultiPoint &poly) const; Point projection_onto(const Line &line) const; Point negative() const; diff --git a/xs/src/libslic3r/Polygon.cpp b/xs/src/libslic3r/Polygon.cpp index 14206b189..36c644243 100644 --- a/xs/src/libslic3r/Polygon.cpp +++ b/xs/src/libslic3r/Polygon.cpp @@ -158,8 +158,12 @@ Polygon::contains(const Point &point) const Polygons Polygon::simplify(double tolerance) const { - Polygon p = *this; - p.points = MultiPoint::_douglas_peucker(p.points, tolerance); + // repeat first point at the end in order to apply Douglas-Peucker + // on the whole polygon + Points points = this->points; + points.push_back(points.front()); + Polygon p(MultiPoint::_douglas_peucker(points, tolerance)); + p.points.pop_back(); Polygons pp; pp.push_back(p); @@ -225,21 +229,17 @@ Polygon::wkt() const void Polygon::concave_points(double angle, Points* points) const { - /* input angle threshold is checked on the internal side of the polygon - but ccw() returns 0 for collinear, >0 for ccw and <0 for cw */ - double ccw_angle = angle - PI; - // check whether first point forms a concave angle - if (this->points.front().ccw(this->points.back(), *(this->points.begin()+1)) >= ccw_angle) + if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) >= angle) points->push_back(this->points.front()); // check whether points 1..(n-1) form concave angles for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) { - if (p->ccw(*(p-1), *(p+1)) >= ccw_angle) points->push_back(*p); + if (p->ccw_angle(*(p-1), *(p+1)) >= angle) points->push_back(*p); } // check whether last point forms a concave angle - if (this->points.back().ccw(*(this->points.end()-2), this->points.front()) >= ccw_angle) + if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) >= angle) points->push_back(this->points.back()); } @@ -252,21 +252,17 @@ Polygon::concave_points(Points* points) const void Polygon::convex_points(double angle, Points* points) const { - /* input angle threshold is checked on the internal side of the polygon - but ccw() returns 0 for collinear, >0 for ccw and <0 for cw */ - double ccw_angle = angle - PI; - // check whether first point forms a convex angle - if (this->points.front().ccw(this->points.back(), *(this->points.begin()+1)) <= ccw_angle) + if (this->points.front().ccw_angle(this->points.back(), *(this->points.begin()+1)) <= angle) points->push_back(this->points.front()); // check whether points 1..(n-1) form convex angles for (Points::const_iterator p = this->points.begin()+1; p != this->points.end()-1; ++p) { - if (p->ccw(*(p-1), *(p+1)) <= ccw_angle) points->push_back(*p); + if (p->ccw_angle(*(p-1), *(p+1)) <= angle) points->push_back(*p); } // check whether last point forms a convex angle - if (this->points.back().ccw(*(this->points.end()-2), this->points.front()) <= ccw_angle) + if (this->points.back().ccw_angle(*(this->points.end()-2), this->points.front()) <= angle) points->push_back(this->points.back()); } diff --git a/xs/src/libslic3r/Polygon.hpp b/xs/src/libslic3r/Polygon.hpp index 76e668024..778825f3e 100644 --- a/xs/src/libslic3r/Polygon.hpp +++ b/xs/src/libslic3r/Polygon.hpp @@ -19,6 +19,9 @@ class Polygon : public MultiPoint { operator Polyline() const; Point& operator[](Points::size_type idx); const Point& operator[](Points::size_type idx) const; + + Polygon() {}; + explicit Polygon(const Points &points): MultiPoint(points) {}; Point last_point() const; Lines lines() const; void lines(Lines* lines) const;