diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 580ed3bd5..6bacc1119 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -3,6 +3,8 @@ use Moo; extends 'Slic3r::Polyline'; +use constant PI => 4 * atan2(1, 1); + sub clip_end { my $self = shift; my ($distance) = @_; @@ -34,4 +36,36 @@ sub reverse { @{$self->points} = reverse @{$self->points}; } +sub split_at_acute_angles { + my $self = shift; + + # calculate angle limit + my $angle_limit = abs(Slic3r::Geometry::deg2rad(40)); + my @points = @{$self->p}; + + my @paths = (); + + # take first two points + my @p = splice @points, 0, 2; + + # loop until we have one spare point + while (my $p3 = shift @points) { + my $angle = abs(Slic3r::Geometry::angle3points($p[-1], $p[-2], $p3)); + $angle = 2*PI - $angle if $angle > PI; + + if ($angle < $angle_limit) { + # if the angle between $p[-2], $p[-1], $p3 is too acute + # then consider $p3 only as a starting point of a new + # path and stop the current one as it is + push @paths, __PACKAGE__->cast([@p]); + @p = ($p3); + push @p, grep $_, shift @points or last; + } else { + push @p, $p3; + } + } + push @paths, __PACKAGE__->cast([@p]) if @p > 1; + return @paths; +} + 1; diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index dda6e1d37..0179d991f 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -52,4 +52,11 @@ sub shortest_path { return @paths; } +sub cleanup { + my $self = shift; + + # split paths at angles that are too acute to be printed as they will cause blobs + @{$self->paths} = map $_->split_at_acute_angles, @{$self->paths}; +} + 1; diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index a1bee3e80..53ef2b9d9 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -170,9 +170,10 @@ sub make_fill { } # save into layer - FINISH: push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new( + push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new( paths => [ map Slic3r::ExtrusionPath->cast([ @$_ ]), @path_collection ], ); + $layer->fills->[-1]->cleanup; } } diff --git a/lib/Slic3r/SVG.pm b/lib/Slic3r/SVG.pm index 40ea5ab14..d66dca3ff 100644 --- a/lib/Slic3r/SVG.pm +++ b/lib/Slic3r/SVG.pm @@ -8,12 +8,12 @@ use constant X => 0; use constant Y => 1; sub factor { - return $Slic3r::resolution * 10; + return $Slic3r::resolution * 100; } sub svg { my ($print) = @_; - + $print ||= Slic3r::Print->new(x_length => 200 / $Slic3r::resolution, y_length => 200 / $Slic3r::resolution); return SVG->new(width => $print->max_length * factor(), height => $print->max_length * factor()); } @@ -56,7 +56,8 @@ sub output_points { } sub output_polygons { - my ($print, $filename, $polygons) = @_; + my ($print, $filename, $polygons, $type) = @_; + $type ||= 'polygon'; my $svg = svg($print); my $g = $svg->group( @@ -72,7 +73,7 @@ sub output_polygons { 'y' => [ map($_->[Y] * factor(), @$polygon) ], -type => 'polygon', ); - $g->polygon( + $g->$type( %$path, ); } @@ -80,6 +81,10 @@ sub output_polygons { write_svg($svg, $filename); } +sub output_polylines { + return output_polygons(@_, 'polyline'); +} + sub output_lines { my ($print, $filename, $lines) = @_;