diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 49909a7a5..d399cedaf 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -55,7 +55,7 @@ our $flow_width; # print options our $perimeter_offsets = 3; our $solid_layers = 3; -our $bridge_overlap = 2; # mm +our $bridge_overlap = 3; # mm our $fill_type = 'rectilinear'; our $fill_density = 0.4; # 1 = 100% our $fill_angle = 0; diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 30104e109..d53193677 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -15,6 +15,8 @@ our @EXPORT_OK = qw( sum_vectors multiply_vector subtract_vectors dot perp polygon_points_visibility line_intersection bounding_box bounding_box_intersect clip_segment_complex_polygon longest_segment angle3points + polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices + polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges ); use Slic3r::Geometry::DouglasPeucker qw(Douglas_Peucker); @@ -575,4 +577,39 @@ sub angle3points { return $angle <= 0 ? $angle + 2*PI() : $angle; } +sub polyline_remove_parallel_continuous_edges { + my ($points, $isPolygon) = @_; + + for (my $i = $isPolygon ? 0 : 2; $i <= $#$points; $i++) { + if (Slic3r::Geometry::lines_parallel([$points->[$i-2], $points->[$i-1]], [$points->[$i-1], $points->[$i]])) { + # we can remove $points->[$i-1] + splice @$points, $i-1, 1; + $i--; + } + } +} + +sub polygon_remove_parallel_continuous_edges { + my ($points) = @_; + return polyline_remove_parallel_continuous_edges($points, 1); +} + +sub polyline_remove_acute_vertices { + my ($points, $isPolygon) = @_; + + for (my $i = $isPolygon ? -1 : 1; $i < $#$points; $i++) { + my $angle = angle3points($points->[$i], $points->[$i-1], $points->[$i+1]); + if ($angle < 0.01 || $angle >= 2*PI - 0.01) { + # we can remove $points->[$i] + splice @$points, $i, 1; + $i--; + } + } +} + +sub polygon_remove_acute_vertices { + my ($points) = @_; + return polyline_remove_acute_vertices($points, 1); +} + 1; diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 3c250ca2c..267424f39 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -157,8 +157,21 @@ sub make_surfaces { my %seen_points = map { $get_point_id->($points[$_]) => $_ } 0..1; CYCLE: while (1) { - my $next_lines = $pointmap{ $get_point_id->($points[-1]) } - or die sprintf "No lines start at point %d,%d. This shouldn't happen", @{$points[-1]}; + my $next_lines = $pointmap{ $get_point_id->($points[-1]) }; + + # shouldn't we find the point, let's try with a slower algorithm + # as approximation may make the coordinates differ + if (!$next_lines) { + local $Slic3r::Geometry::epsilon = 1; + for (keys %pointmap) { + $next_lines = $pointmap{$_} if points_coincide($points[-1], [ split /,/, $_ ]); + last if $next_lines; + } + } + + $next_lines + or die sprintf "No lines start at point %s. This shouldn't happen", + $get_point_id->($points[-1]); last CYCLE if !@$next_lines; my @ordered_next_lines = sort @@ -256,6 +269,12 @@ sub process_bridges { # in a convex polygon; this will print thin membranes eventually my $surface_p = convex_hull($surface->contour->p); + #use Slic3r::SVG; + #Slic3r::SVG::output(undef, "bridge.svg", + # green_polygons => [ map $_->p, @supporting_surfaces ], + # red_polygons => [ $surface_p ], + #); + # find all supported edges (as polylines, thus keeping notion of # consecutive supported edges) my @supported_polylines = (); diff --git a/lib/Slic3r/Polyline.pm b/lib/Slic3r/Polyline.pm index 3f321cc63..51846e8db 100644 --- a/lib/Slic3r/Polyline.pm +++ b/lib/Slic3r/Polyline.pm @@ -2,6 +2,8 @@ package Slic3r::Polyline; use Moo; use Math::Clipper qw(); +use Slic3r::Geometry qw(polyline_remove_parallel_continuous_edges polyline_remove_acute_vertices + polygon_remove_acute_vertices polygon_remove_parallel_continuous_edges); use Sub::Quote; use XXX; @@ -46,18 +48,24 @@ sub p { sub merge_continuous_lines { my $self = shift; - - my @points = map $_->p, @{$self->points}; - for (my $i = 2; $i <= $#points; $i++) { - if (Slic3r::Geometry::lines_parallel([$points[$i-2], $points[$i-1]], [$points[$i-1], $points[$i]])) { - # we can remove $points[$i-1] - splice @points, $i-1, 1; - - $i--; - } + my $points = $self->p; + if ($self->isa('Slic3r::Polyline::Closed')) { + polygon_remove_parallel_continuous_edges($points); + } else { + polyline_remove_parallel_continuous_edges($points); } - - @{$self->points} = map Slic3r::Point->cast($_), @points; + @{$self->points} = map Slic3r::Point->cast($_), @$points; +} + +sub remove_acute_vertices { + my $self = shift; + my $points = $self->p; + if ($self->isa('Slic3r::Polyline::Closed')) { + polygon_remove_acute_vertices($points); + } else { + polyline_remove_acute_vertices($points); + } + @{$self->points} = map Slic3r::Point->cast($_), @$points; } sub cleanup { diff --git a/lib/Slic3r/Polyline/Closed.pm b/lib/Slic3r/Polyline/Closed.pm index 5ad6d97ca..986d915fb 100644 --- a/lib/Slic3r/Polyline/Closed.pm +++ b/lib/Slic3r/Polyline/Closed.pm @@ -15,18 +15,6 @@ sub lines { return @lines; } -# superclass doesn't check whether last line of our closed polyline -# is parallel to first one, so let's do it here -sub merge_continuous_lines { - my $self = shift; - $self->SUPER::merge_continuous_lines(@_); - - my @lines = $self->lines; - if ($lines[-1]->parallel_to($lines[0])) { - shift @{$self->points}; - } -} - sub encloses_point { my $self = shift; my ($point) = @_; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 783b126b8..8cff162da 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -120,6 +120,15 @@ sub detect_surfaces_type { # of current layer and lower one) if ($lower_layer) { @bottom = $surface_difference->($layer->surfaces, $lower_layer->surfaces, 'bottom'); + for (@bottom) { + $_->contour->merge_continuous_lines; + $_->contour->remove_acute_vertices; + + # okay, this is an Ugly Hack(tm) to avoid floating point math problems + # with diagonal bridges. will find a nicer solution, promised. + my $offset = offset([$_->contour->p], 100, 100, JT_MITER, 2); + @{$_->contour->points} = map Slic3r::Point->cast($_), @{ $offset->[0] }; + } #Slic3r::SVG::output(undef, "layer_" . $layer->id . "_diff.svg", # green_polygons => [ map $_->p, @{$layer->surfaces} ], diff --git a/lib/Slic3r/SVG.pm b/lib/Slic3r/SVG.pm index ff3faa66b..68b0321b2 100644 --- a/lib/Slic3r/SVG.pm +++ b/lib/Slic3r/SVG.pm @@ -65,7 +65,7 @@ sub output { foreach my $type (qw(points red_points)) { if ($things{$type}) { - my ($colour, $r) = $type eq 'points' ? ('black', 2) : ('red', 3); + my ($colour, $r) = $type eq 'points' ? ('black', 5) : ('red', 3); my $g = $svg->group( style => { 'stroke-width' => 2, diff --git a/t/geometry.t b/t/geometry.t index 4c65d6ae5..24746e451 100644 --- a/t/geometry.t +++ b/t/geometry.t @@ -2,7 +2,7 @@ use Test::More; use strict; use warnings; -plan tests => 15; +plan tests => 17; BEGIN { use FindBin; @@ -10,7 +10,9 @@ BEGIN { } use Slic3r; -use Slic3r::Geometry qw(PI); +use Slic3r::Geometry qw(PI polyline_remove_parallel_continuous_edges + polyline_remove_acute_vertices polygon_remove_acute_vertices + polygon_remove_parallel_continuous_edges); #========================================================== @@ -114,3 +116,40 @@ is Slic3r::Geometry::can_connect_points(@$points, $polygons), 0, 'can_connect_po } #========================================================== + +{ + my $polygon = [ + [2265447881, 7013509857], [2271869937, 7009802077], [2606221146, 6816764300], [1132221146, 4263721402], + [1098721150, 4205697705], [1228411320, 4130821051], [1557501031, 3940821051], [1737340080, 3836990933], + [1736886253, 3837252951], [1494771522, 3977037948], [2959638603, 6514262167], [3002271522, 6588104548], + [3083252364, 6541350240], [2854283608, 6673545411], [2525193897, 6863545411], + ]; + polygon_remove_parallel_continuous_edges($polygon); + polygon_remove_acute_vertices($polygon); + is scalar(@$polygon), 4, 'polygon_remove_acute_vertices'; + + use Slic3r::SVG; + #pop @$polygon; + Slic3r::SVG::output(undef, "vert.svg", + polylines => [$polygon], + ); +} + +#========================================================== + +{ + my $polygon = [ + [226.5447881,701.3509857], [260.6221146,681.67643], [109.872115,420.5697705], [149.4771522,397.7037948], + [300.2271522,658.8104548], [308.3252364,654.135024], + ]; + polyline_remove_acute_vertices($polygon); + is scalar(@$polygon), 6, 'polyline_remove_acute_vertices'; + use Slic3r::SVG; + local $Slic3r::resolution = 0.1; + pop @$polygon; + Slic3r::SVG::output(undef, "vert2.svg", + polylines => [$polygon], + ); +} + +#========================================================== \ No newline at end of file diff --git a/t/stl.t b/t/stl.t index d891bc270..b06f2189c 100644 --- a/t/stl.t +++ b/t/stl.t @@ -25,8 +25,8 @@ is_deeply lines(22, 20, 20), [ [ $points[2], $points[1] ] ], 'lower edge on laye is_deeply lines(20, 20, 10), [ [ $points[0], $points[1] ] ], 'upper edge on layer'; is_deeply lines(20, 15, 10), [ ], 'upper vertex on layer'; is_deeply lines(28, 20, 30), [ ], 'lower vertex on layer'; -is_deeply lines(24, 10, 16), [ [ [2, 6], [4, 4] ] ], 'two edges intersect'; -is_deeply lines(24, 10, 20), [ [ [1, 9], [4, 4] ] ], 'one vertex on plane and one edge intersects'; +is_deeply lines(24, 10, 16), [ [ [4, 4], [2, 6] ] ], 'two edges intersect'; +is_deeply lines(24, 10, 20), [ [ [4, 4], [1, 9] ] ], 'one vertex on plane and one edge intersects'; my @lower = $stl->intersect_facet(vertices(22, 20, 20), $z, $dz); my @upper = $stl->intersect_facet(vertices(20, 20, 10), $z, $dz);