From 0aff5fab24d2cf2c09388de0e3457c9264bb6085 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 4 Dec 2011 16:24:46 +0100 Subject: [PATCH] Connect infill segments and adjust spacing and flow rate to fill the area completely without leaving gaps. #89 --- lib/Slic3r/Extruder.pm | 1 + lib/Slic3r/ExtrusionPath.pm | 3 ++ lib/Slic3r/ExtrusionPath/Collection.pm | 4 +- lib/Slic3r/Fill.pm | 6 ++- lib/Slic3r/Fill/PlanePath.pm | 2 +- lib/Slic3r/Fill/Rectilinear.pm | 53 +++++++++++++++++++++----- lib/Slic3r/Print.pm | 1 + 7 files changed, 56 insertions(+), 14 deletions(-) diff --git a/lib/Slic3r/Extruder.pm b/lib/Slic3r/Extruder.pm index a550a83b7..d4910dd48 100644 --- a/lib/Slic3r/Extruder.pm +++ b/lib/Slic3r/Extruder.pm @@ -117,6 +117,7 @@ sub extrude { * (($Slic3r::nozzle_diameter**2) / ($Slic3r::filament_diameter ** 2)) * $Slic3r::flow_speed_ratio * $self->flow_ratio + * ($path->flow_ratio || 1) * $Slic3r::extrusion_multiplier * $path->depth_layers; diff --git a/lib/Slic3r/ExtrusionPath.pm b/lib/Slic3r/ExtrusionPath.pm index 68de0d835..7cfbd73c0 100644 --- a/lib/Slic3r/ExtrusionPath.pm +++ b/lib/Slic3r/ExtrusionPath.pm @@ -7,6 +7,9 @@ extends 'Slic3r::Polyline'; # expressed in layers has 'depth_layers' => (is => 'ro', default => sub {1}); +# multiplier for the flow rate +has 'flow_ratio' => (is => 'rw'); + # perimeter/fill/solid-fill/bridge/skirt has 'role' => (is => 'ro', required => 1); diff --git a/lib/Slic3r/ExtrusionPath/Collection.pm b/lib/Slic3r/ExtrusionPath/Collection.pm index 943a8419e..69fb584b4 100644 --- a/lib/Slic3r/ExtrusionPath/Collection.pm +++ b/lib/Slic3r/ExtrusionPath/Collection.pm @@ -18,7 +18,7 @@ sub add { sub endpoints { my $self = shift; - return map $_->endpoints, @{$self->paths}; + return [ map $_->endpoints, @{$self->paths} ]; } sub shortest_path { @@ -30,7 +30,7 @@ sub shortest_path { CYCLE: while (@{$self->paths}) { # find nearest point $start_at = $start_near - ? Slic3r::Point->new(Slic3r::Geometry::nearest_point($start_near, [ $self->endpoints ])) + ? Slic3r::Point->new(Slic3r::Geometry::nearest_point($start_near, $self->endpoints)) : $self->endpoints->[0]; # loop through paths to find the one that starts or ends at the point found diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 90e1187ca..d90af89a9 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -60,6 +60,7 @@ sub make_fill { $union = diff_ex( [ map @$_, @$union ], [ map $_->p, @surfaces_with_bridge_angle ], + 1, ); } @@ -67,6 +68,7 @@ sub make_fill { $union = diff_ex( [ map @$_, @$union ], [ map $_->p, @surfaces ], + 1, ); push @surfaces, map Slic3r::Surface->cast_from_expolygon($_, @@ -103,6 +105,7 @@ sub make_fill { density => $density, flow_width => $flow_width, ); + my $params = shift @paths; # save into layer push @{ $layer->fills }, Slic3r::ExtrusionPath::Collection->new( @@ -111,10 +114,11 @@ sub make_fill { [ @$_ ], role => ($is_bridge ? 'bridge' : $is_solid ? 'solid-fill' : 'fill'), depth_layers => $surface->depth_layers, + flow_ratio => $params->{flow_ratio}, ), @paths, ], ); - $layer->fills->[-1]->cleanup; + ###$layer->fills->[-1]->cleanup; } } diff --git a/lib/Slic3r/Fill/PlanePath.pm b/lib/Slic3r/Fill/PlanePath.pm index 43ad82398..55561436d 100644 --- a/lib/Slic3r/Fill/PlanePath.pm +++ b/lib/Slic3r/Fill/PlanePath.pm @@ -63,7 +63,7 @@ sub fill_surface { # paths must be rotated back $self->rotate_points_back(\@paths, $rotate_vector); - return @paths; + return {}, @paths; } 1; diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index d1f23b392..639e67be0 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -3,7 +3,7 @@ use Moo; extends 'Slic3r::Fill::Base'; -use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X); +use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale epsilon); use XXX; sub fill_surface { @@ -16,28 +16,61 @@ sub fill_surface { $self->rotate_points($expolygon, $rotate_vector); my $bounding_box = [ $expolygon->bounding_box ]; - my $flow_width_res = $params{flow_width} / $Slic3r::resolution; - my $distance_between_lines = $flow_width_res / $params{density}; + $bounding_box->[X1] += scale 0.1; + $bounding_box->[X2] -= scale 0.1; + + my $min_spacing = scale $params{flow_width}; + my $distance_between_lines = $min_spacing / $params{density}; + my $line_oscillation = $distance_between_lines - $min_spacing; + + my $number_of_lines = int(($bounding_box->[X2] - $bounding_box->[X1]) / $distance_between_lines) + 1; + my $extra_space = ($bounding_box->[X2] - $bounding_box->[X1]) % $distance_between_lines; + $distance_between_lines += $extra_space / ($number_of_lines - 1) if $number_of_lines > 1; + my $flow_ratio = $distance_between_lines / ($min_spacing / $params{density}); my @paths = (); my $x = $bounding_box->[X1]; my $is_line_pattern = $self->isa('Slic3r::Fill::Line'); - my $i = 0; - while ($x < $bounding_box->[X2]) { + for (my $i = 0; $i < $number_of_lines; $i++) { my $vertical_line = [ [$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]] ]; if ($is_line_pattern && $i % 2) { - $vertical_line->[A][X] -= ($distance_between_lines - $flow_width_res); - $vertical_line->[B][X] += ($distance_between_lines - $flow_width_res); + $vertical_line->[A][X] -= $line_oscillation; + $vertical_line->[B][X] += $line_oscillation; } push @paths, @{ $expolygon->clip_line($vertical_line) }; - $x += int($distance_between_lines); - $i++; + $x += $distance_between_lines; + } + + # connect lines + { + my $collection = Slic3r::ExtrusionPath::Collection->new( + paths => [ map Slic3r::ExtrusionPath->cast([ @$_ ], role => 'bogus'), @paths ], + ); + @paths = (); + + my $can_connect = $is_line_pattern + ? sub { $_[X] <= (abs((($_[2][Y] - $bounding_box->[Y1])*(2 * $line_oscillation)/($bounding_box->[Y2] - $bounding_box->[Y1])) - $line_oscillation) + $distance_between_lines) && $_[Y] <= $distance_between_lines * 5 } + : sub { ($_[X] <= $distance_between_lines) && ($_[Y] <= $distance_between_lines * 5) }; + + foreach my $path ($collection->shortest_path) { + if (@paths) { + my @distance = map abs($paths[-1][-1][$_] - $path->points->[0][$_]), (X,Y); + + # TODO: we should also check that both points are on a fill_boundary to avoid + # connecting paths on the boundaries of internal regions + if ($can_connect->(@distance, $paths[-1][-1])) { + push @{$paths[-1]}, @{$path->points}; + next; + } + } + push @paths, [@{$path->points}]; + } } # paths must be rotated back $self->rotate_points_back(\@paths, $rotate_vector); - return @paths; + return { flow_ratio => $flow_ratio }, @paths; } 1; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 927598e8e..0c9bc4fc9 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -272,6 +272,7 @@ sub discover_horizontal_shells { my $new_internal_solid = intersection_ex( $surfaces_p, [ map $_->p, grep $_->surface_type =~ /internal/, @neighbor_surfaces ], + undef, 1, ); next if !@$new_internal_solid;