From 2720000a17f2dd1c32d1af2f0d93ca9d433b7317 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 28 Apr 2014 20:14:20 +0200 Subject: [PATCH] New get_trapezoids() implementation. Maybe heavier but it doesn't fail with some versions of GCC like the one provided by Boost.Polygon. #1965 --- lib/Slic3r/Layer/BridgeDetector.pm | 2 +- xs/src/ExPolygon.cpp | 57 ++++++++++++++++++++++++++++++ xs/src/ExPolygon.hpp | 2 ++ xs/src/Polygon.cpp | 12 +++++++ xs/src/Polygon.hpp | 2 ++ xs/t/04_expolygon.t | 6 ++-- xs/xsp/ExPolygon.xsp | 2 ++ 7 files changed, 79 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/Layer/BridgeDetector.pm b/lib/Slic3r/Layer/BridgeDetector.pm index 4aba4d1ff..5b2098e5e 100644 --- a/lib/Slic3r/Layer/BridgeDetector.pm +++ b/lib/Slic3r/Layer/BridgeDetector.pm @@ -170,7 +170,7 @@ sub coverage { my $grown = $expolygon->offset_ex(+$self->extrusion_width/2); # Compute trapezoids according to a vertical orientation - my $trapezoids = [ map @{$_->get_trapezoids(PI/2)}, @$grown ]; + my $trapezoids = [ map @{$_->get_trapezoids2(PI/2)}, @$grown ]; # get anchors and rotate them too my $anchors = [ map $_->clone, @{$self->_anchors} ]; diff --git a/xs/src/ExPolygon.cpp b/xs/src/ExPolygon.cpp index 12f595ac7..8795d9b33 100644 --- a/xs/src/ExPolygon.cpp +++ b/xs/src/ExPolygon.cpp @@ -1,3 +1,4 @@ +#include "BoundingBox.hpp" #include "ExPolygon.hpp" #include "Geometry.hpp" #include "Polygon.hpp" @@ -8,6 +9,7 @@ #include "perlglue.hpp" #endif +#include #include namespace Slic3r { @@ -182,6 +184,61 @@ ExPolygon::get_trapezoids(Polygons* polygons, double angle) const polygon->rotate(-(PI/2 - angle), Point(0,0)); } +// This algorithm may return more trapezoids than necessary +// (i.e. it may break a single trapezoid in several because +// other parts of the object have x coordinates in the middle) +void +ExPolygon::get_trapezoids2(Polygons* polygons) const +{ + // get all points of this ExPolygon + Points pp = *this; + + // build our bounding box + BoundingBox bb(pp); + + // get all x coordinates + std::vector xx; + xx.reserve(pp.size()); + for (Points::const_iterator p = pp.begin(); p != pp.end(); ++p) + xx.push_back(p->x); + std::sort(xx.begin(), xx.end()); + + // find trapezoids by looping from first to next-to-last coordinate + for (std::vector::const_iterator x = xx.begin(); x != xx.end()-1; ++x) { + coord_t next_x = *(x + 1); + if (*x == next_x) continue; + + // build rectangle + Polygon poly; + poly.points.resize(4); + poly[0].x = *x; + poly[0].y = bb.min.y; + poly[1].x = next_x; + poly[1].y = bb.min.y; + poly[2].x = next_x; + poly[2].y = bb.max.y; + poly[3].x = *x; + poly[3].y = bb.max.y; + + // intersect with this expolygon + Polygons trapezoids; + intersection(poly, *this, trapezoids); + + // append results to return value + polygons->insert(polygons->end(), trapezoids.begin(), trapezoids.end()); + } +} + +void +ExPolygon::get_trapezoids2(Polygons* polygons, double angle) const +{ + ExPolygon clone = *this; + clone.rotate(PI/2 - angle, Point(0,0)); + clone.get_trapezoids2(polygons); + for (Polygons::iterator polygon = polygons->begin(); polygon != polygons->end(); ++polygon) + polygon->rotate(-(PI/2 - angle), Point(0,0)); +} + void ExPolygon::triangulate(Polygons* polygons) const { diff --git a/xs/src/ExPolygon.hpp b/xs/src/ExPolygon.hpp index 23ad82911..07ab7c9b8 100644 --- a/xs/src/ExPolygon.hpp +++ b/xs/src/ExPolygon.hpp @@ -29,6 +29,8 @@ class ExPolygon void medial_axis(double max_width, double min_width, Polylines* polylines) const; void get_trapezoids(Polygons* polygons) const; void get_trapezoids(Polygons* polygons, double angle) const; + void get_trapezoids2(Polygons* polygons) const; + void get_trapezoids2(Polygons* polygons, double angle) const; void triangulate(Polygons* polygons) const; void triangulate2(Polygons* polygons) const; diff --git a/xs/src/Polygon.cpp b/xs/src/Polygon.cpp index 0544b80e9..314febbf1 100644 --- a/xs/src/Polygon.cpp +++ b/xs/src/Polygon.cpp @@ -15,6 +15,18 @@ Polygon::operator Polygons() const return pp; } +Point& +Polygon::operator[](Points::size_type idx) +{ + return this->points[idx]; +} + +const Point& +Polygon::operator[](Points::size_type idx) const +{ + return this->points[idx]; +} + Point Polygon::last_point() const { diff --git a/xs/src/Polygon.hpp b/xs/src/Polygon.hpp index e96fb9736..2dfe0ed09 100644 --- a/xs/src/Polygon.hpp +++ b/xs/src/Polygon.hpp @@ -15,6 +15,8 @@ typedef std::vector Polygons; class Polygon : public MultiPoint { public: operator Polygons() const; + Point& operator[](Points::size_type idx); + const Point& operator[](Points::size_type idx) const; Point last_point() const; Lines lines() const; void lines(Lines* lines) const; diff --git a/xs/t/04_expolygon.t b/xs/t/04_expolygon.t index 4c9e89ee5..feba0a766 100644 --- a/xs/t/04_expolygon.t +++ b/xs/t/04_expolygon.t @@ -107,14 +107,14 @@ is $expolygon->area, 100*100-20*20, 'area'; { my $expolygon = Slic3r::ExPolygon->new($square); - my $polygons = $expolygon->get_trapezoids(PI/2); + my $polygons = $expolygon->get_trapezoids2(PI/2); is scalar(@$polygons), 1, 'correct number of trapezoids returned'; is scalar(@{$polygons->[0]}), 4, 'trapezoid has 4 points'; is $polygons->[0]->area, $expolygon->area, 'trapezoid has correct area'; } { - my $polygons = $expolygon->get_trapezoids(PI/2); + my $polygons = $expolygon->get_trapezoids2(PI/2); is scalar(@$polygons), 4, 'correct number of trapezoids returned'; # trapezoid polygons might have more than 4 points in case of collinear segments @@ -127,7 +127,7 @@ is $expolygon->area, 100*100-20*20, 'area'; { my $expolygon = Slic3r::ExPolygon->new([ [0,100],[100,0],[200,0],[300,100],[200,200],[100,200] ]); - my $polygons = $expolygon->get_trapezoids(PI/2); + my $polygons = $expolygon->get_trapezoids2(PI/2); is scalar(@$polygons), 3, 'correct number of trapezoids returned'; is scalar(grep { $_->area == 100*200/2 } @$polygons), 2, 'trapezoids have expected area'; is scalar(grep { $_->area == 100*200 } @$polygons), 1, 'trapezoids have expected area'; diff --git a/xs/xsp/ExPolygon.xsp b/xs/xsp/ExPolygon.xsp index 8ad97c250..9d6eff536 100644 --- a/xs/xsp/ExPolygon.xsp +++ b/xs/xsp/ExPolygon.xsp @@ -32,6 +32,8 @@ %code{% THIS->medial_axis(max_width, min_width, &RETVAL); %}; Polygons get_trapezoids(double angle) %code{% THIS->get_trapezoids(&RETVAL, angle); %}; + Polygons get_trapezoids2(double angle) + %code{% THIS->get_trapezoids2(&RETVAL, angle); %}; Polygons triangulate() %code{% THIS->triangulate(&RETVAL); %}; Polygons triangulate2()