diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index d647f2a85..18c05dfa5 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -20,7 +20,7 @@ our @EXPORT_OK = qw( rad2deg_dir bounding_box_center line_intersects_any douglas_peucker polyline_remove_short_segments normal triangle_normal polygon_is_convex scaled_epsilon bounding_box_3D size_3D size_2D - convex_hull + convex_hull directions_parallel directions_parallel_within ); diff --git a/lib/Slic3r/Layer/BridgeDetector.pm b/lib/Slic3r/Layer/BridgeDetector.pm index f27cda3b2..795f5a624 100644 --- a/lib/Slic3r/Layer/BridgeDetector.pm +++ b/lib/Slic3r/Layer/BridgeDetector.pm @@ -2,7 +2,7 @@ package Slic3r::Layer::BridgeDetector; use Moo; use List::Util qw(first sum max min); -use Slic3r::Geometry qw(PI unscale scaled_epsilon rad2deg epsilon); +use Slic3r::Geometry qw(PI unscale scaled_epsilon rad2deg epsilon directions_parallel_within); use Slic3r::Geometry::Clipper qw(intersection_pl intersection_ex union offset diff_pl union_ex); has 'expolygon' => (is => 'ro', required => 1); @@ -84,10 +84,11 @@ sub detect_angle { # remove duplicates my $min_resolution = PI/180; # 1 degree - @angles = map { ($_ >= &PI-&epsilon) ? ($_-&PI) : $_ } @angles; - @angles = sort @angles; - for (my $i = 1; $i <= $#angles; ++$i) { - if (abs($angles[$i] - $angles[$i-1]) < $min_resolution) { + # proceed in reverse order so that when we compare first value with last one (-1) + # we remove the greatest one (PI) in case they are parallel (PI, 0) + @angles = reverse sort @angles; + for (my $i = 0; $i <= $#angles; ++$i) { + if (directions_parallel_within($angles[$i], $angles[$i-1], $min_resolution)) { splice @angles, $i, 1; --$i; } @@ -246,8 +247,13 @@ sub unsupported_edges { ); # split into individual segments and filter out edges parallel to the bridging angle + # TODO: angle tolerance should probably be based on segment length and flow width, + # so that we build supports whenever there's a chance that at least one or two bridge + # extrusions would be anchored within such length (i.e. a slightly non-parallel bridging + # direction might still benefit from anchors if long enough) + my $angle_tolerance = PI/180*5; @$unsupported = map $_->as_polyline, - grep !$_->parallel_to($angle), + grep !directions_parallel_within($_->direction, $angle, $angle_tolerance), map @{$_->lines}, @$unsupported; diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index d4517895c..eeda93047 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -34,7 +34,7 @@ sub is_straight { # first point and last point. (Checking each line against the previous # one would have caused the error to accumulate.) my $dir = Slic3r::Line->new($self->first_point, $self->last_point)->direction; - return !defined first { abs($_->direction - $dir) > epsilon } @{$self->lines}; + return !defined first { !$_->parallel_to($dir) } @{$self->lines}; } 1; diff --git a/xs/src/Geometry.cpp b/xs/src/Geometry.cpp index bb673813b..c0d9e66cd 100644 --- a/xs/src/Geometry.cpp +++ b/xs/src/Geometry.cpp @@ -93,6 +93,14 @@ chained_path_items(Points &points, T &items, T &retval) } template void chained_path_items(Points &points, ClipperLib::PolyNodes &items, ClipperLib::PolyNodes &retval); +bool +directions_parallel(double angle1, double angle2, double max_diff) +{ + double diff = fabs(angle1 - angle2); + max_diff += EPSILON; + return diff < max_diff || fabs(diff - PI) < max_diff; +} + Line MedialAxis::edge_to_line(const VD::edge_type &edge) const { diff --git a/xs/src/Geometry.hpp b/xs/src/Geometry.hpp index 9c758c616..2dc183f82 100644 --- a/xs/src/Geometry.hpp +++ b/xs/src/Geometry.hpp @@ -15,6 +15,7 @@ void convex_hull(Points &points, Polygon* hull); void chained_path(Points &points, std::vector<Points::size_type> &retval, Point start_near); void chained_path(Points &points, std::vector<Points::size_type> &retval); template<class T> void chained_path_items(Points &points, T &items, T &retval); +bool directions_parallel(double angle1, double angle2, double max_diff = 0); class MedialAxis { public: diff --git a/xs/src/Line.cpp b/xs/src/Line.cpp index 8efa4442a..fb66629d6 100644 --- a/xs/src/Line.cpp +++ b/xs/src/Line.cpp @@ -1,3 +1,4 @@ +#include "Geometry.hpp" #include "Line.hpp" #include "Polyline.hpp" #include <algorithm> @@ -113,8 +114,7 @@ Line::direction() const bool Line::parallel_to(double angle) const { - double diff = abs(this->direction() - angle); - return (diff < EPSILON) || (abs(diff - PI) < EPSILON); + return Slic3r::Geometry::directions_parallel(this->direction(), angle); } bool diff --git a/xs/t/10_line.t b/xs/t/10_line.t index dc1ad7dc7..b6ec3c316 100644 --- a/xs/t/10_line.t +++ b/xs/t/10_line.t @@ -54,12 +54,12 @@ foreach my $base_angle (0, PI/4, PI/2, PI) { } { my $line2 = $line->clone; - $line2->rotate(+EPSILON/2, [0,0]); + $line2->rotate(+(EPSILON)/2, [0,0]); ok $line->parallel_to_line($line2), 'line is parallel within epsilon'; } { my $line2 = $line->clone; - $line2->rotate(-EPSILON/2, [0,0]); + $line2->rotate(-(EPSILON)/2, [0,0]); ok $line->parallel_to_line($line2), 'line is parallel within epsilon'; } } diff --git a/xs/t/14_geometry.t b/xs/t/14_geometry.t index 4324da818..8dfdecb78 100644 --- a/xs/t/14_geometry.t +++ b/xs/t/14_geometry.t @@ -4,7 +4,9 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 2; +use Test::More tests => 8; + +use constant PI => 4 * atan2(1, 1); { my @points = ( @@ -19,4 +21,14 @@ use Test::More tests => 2; is scalar(@$hull), 4, 'convex_hull returns the correct number of points'; } +# directions_parallel() and directions_parallel_within() are tested +# also with Slic3r::Line::parallel_to() tests in 10_line.t +{ + ok Slic3r::Geometry::directions_parallel_within(0, 0, 0), 'directions_parallel_within'; + ok Slic3r::Geometry::directions_parallel_within(0, PI, 0), 'directions_parallel_within'; + ok Slic3r::Geometry::directions_parallel_within(0, 0, PI/180), 'directions_parallel_within'; + ok Slic3r::Geometry::directions_parallel_within(0, PI, PI/180), 'directions_parallel_within'; + ok !Slic3r::Geometry::directions_parallel_within(PI/2, PI, 0), 'directions_parallel_within'; + ok !Slic3r::Geometry::directions_parallel_within(PI/2, PI, PI/180), 'directions_parallel_within'; +} __END__ diff --git a/xs/xsp/Geometry.xsp b/xs/xsp/Geometry.xsp index b0497e356..85d2d359b 100644 --- a/xs/xsp/Geometry.xsp +++ b/xs/xsp/Geometry.xsp @@ -11,6 +11,25 @@ %{ +bool +directions_parallel(angle1, angle2) + double angle1 + double angle2 + CODE: + RETVAL = Slic3r::Geometry::directions_parallel(angle1, angle2); + OUTPUT: + RETVAL + +bool +directions_parallel_within(angle1, angle2, max_diff) + double angle1 + double angle2 + double max_diff + CODE: + RETVAL = Slic3r::Geometry::directions_parallel(angle1, angle2, max_diff); + OUTPUT: + RETVAL + Polygon* convex_hull(points) Points points