diff --git a/lib/Slic3r/ExPolygon.pm b/lib/Slic3r/ExPolygon.pm index ac1d0fb35..fe2759526 100644 --- a/lib/Slic3r/ExPolygon.pm +++ b/lib/Slic3r/ExPolygon.pm @@ -161,11 +161,6 @@ sub bounding_box_polygon { ]); } -sub bounding_box_center { - my $self = shift; - return Slic3r::Geometry::bounding_box_center($self->contour); -} - sub clip_line { my $self = shift; my ($line) = @_; # line must be a Slic3r::Line object diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index de1d52ef6..7db23412a 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -39,10 +39,9 @@ sub filler { return $FillTypes{$filler}->new; } - if (!$self->fillers->{$filler}) { - my $f = $self->fillers->{$filler} = $FillTypes{$filler}->new; - $f->bounding_box([ $self->print->bounding_box ]) if $f->can('bounding_box'); - } + $self->fillers->{$filler} ||= $FillTypes{$filler}->new( + bounding_box => [ $self->print->bounding_box ], + ); return $self->fillers->{$filler}; } diff --git a/lib/Slic3r/Fill/Base.pm b/lib/Slic3r/Fill/Base.pm index 9c6996be3..c9f801f59 100644 --- a/lib/Slic3r/Fill/Base.pm +++ b/lib/Slic3r/Fill/Base.pm @@ -5,6 +5,7 @@ use Slic3r::Geometry qw(PI); has 'layer_id' => (is => 'rw'); has 'angle' => (is => 'rw', default => sub { $Slic3r::Config->fill_angle }); +has 'bounding_box' => (is => 'ro', required => 1); sub angles () { [0, PI/2] } @@ -15,7 +16,7 @@ sub infill_direction { # set infill angle my (@rotate, @shift); $rotate[0] = Slic3r::Geometry::deg2rad($self->angle); - $rotate[1] = $surface->expolygon->bounding_box_center; + $rotate[1] = Slic3r::Geometry::bounding_box_center($self->bounding_box); @shift = @{$rotate[1]}; if (defined $self->layer_id) { @@ -41,11 +42,9 @@ sub rotate_points { my @rotate = @{$rotate_vector->[0]}; my @shift = @{$rotate_vector->[1]}; - # rotate points as needed - if ($rotate[0]) { - $expolygon->rotate(@rotate); - $expolygon->translate(@shift); - } + # rotate points + $expolygon->rotate(@rotate); + $expolygon->translate(@shift); } sub rotate_points_back { @@ -54,10 +53,8 @@ sub rotate_points_back { my @rotate = @{$rotate_vector->[0]}; my @shift = @{$rotate_vector->[1]}; - if ($rotate[0]) { - @$paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ], - map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @$paths; - } + @$paths = map [ Slic3r::Geometry::rotate_points(-$rotate[0], $rotate[1], @$_) ], + map [ Slic3r::Geometry::move_points([map -$_, @shift], @$_) ], @$paths; } sub adjust_solid_spacing { diff --git a/lib/Slic3r/Fill/Honeycomb.pm b/lib/Slic3r/Fill/Honeycomb.pm index 9e4ff8a27..1985ddb99 100644 --- a/lib/Slic3r/Fill/Honeycomb.pm +++ b/lib/Slic3r/Fill/Honeycomb.pm @@ -3,7 +3,6 @@ use Moo; extends 'Slic3r::Fill::Base'; -has 'bounding_box' => (is => 'rw'); has 'cache' => (is => 'rw', default => sub {{}}); use Slic3r::Geometry qw(PI X1 Y1 X2 Y2 X Y scale); @@ -25,7 +24,7 @@ sub fill_surface { my $cache_id = sprintf "d%s_s%s_a%s", $params{density}, $params{flow_spacing}, $rotate_vector->[0][0]; - if (!$self->cache->{$cache_id} || !defined $self->bounding_box) { + if (!$self->cache->{$cache_id}) { # hexagons math my $hex_side = $distance / (sqrt(3)/2); @@ -39,7 +38,7 @@ sub fill_surface { # adjust actual bounding box to the nearest multiple of our hex pattern # and align it so that it matches across layers - my $bounding_box = [ $self->bounding_box ? @{$self->bounding_box} : $expolygon->bounding_box ]; + my $bounding_box = [ @{$self->bounding_box} ]; # clone $bounding_box->[$_] = 0 for X1, Y1; { my $bb_polygon = Slic3r::Polygon->new_from_bounding_box($bounding_box); diff --git a/lib/Slic3r/Fill/Rectilinear.pm b/lib/Slic3r/Fill/Rectilinear.pm index e1dcab0e6..d5191a470 100644 --- a/lib/Slic3r/Fill/Rectilinear.pm +++ b/lib/Slic3r/Fill/Rectilinear.pm @@ -3,6 +3,8 @@ use Moo; extends 'Slic3r::Fill::Base'; +has 'cache' => (is => 'rw', default => sub {{}}); + use Slic3r::Geometry qw(X1 Y1 X2 Y2 A B X Y scale unscale scaled_epsilon); sub fill_surface { @@ -16,39 +18,55 @@ sub fill_surface { my ($expolygon_off) = $expolygon->offset_ex(scale $params{flow_spacing}/2); return {} if !$expolygon_off; # skip some very small polygons (which shouldn't arrive here) - my $bounding_box = [ $expolygon->bounding_box ]; + my $flow_spacing = $params{flow_spacing}; my $min_spacing = scale $params{flow_spacing}; my $distance_between_lines = $min_spacing / $params{density}; my $line_oscillation = $distance_between_lines - $min_spacing; - - my $flow_spacing = $params{flow_spacing}; - if ($params{density} == 1 && !$params{dont_adjust}) { - $distance_between_lines = $self->adjust_solid_spacing( - width => $bounding_box->[X2] - $bounding_box->[X1], - distance => $distance_between_lines, - ); - $flow_spacing = unscale $distance_between_lines; - } - - my $x = $bounding_box->[X1]; my $is_line_pattern = $self->isa('Slic3r::Fill::Line'); - my @vertical_lines = (); - for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) { - my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]); - if ($is_line_pattern && $i % 2) { - $vertical_line->[A][X] += $line_oscillation; - $vertical_line->[B][X] -= $line_oscillation; + + my $cache_id = sprintf "d%s_s%s_a%s", + $params{density}, $params{flow_spacing}, $rotate_vector->[0][0]; + + if (!$self->cache->{$cache_id}) { + # compute bounding box + my $bounding_box = $self->bounding_box; + { + my $bb_expolygon = Slic3r::ExPolygon->new(Slic3r::Polygon->new_from_bounding_box($bounding_box)); + $self->rotate_points($bb_expolygon, $rotate_vector); + $bounding_box = [ $bb_expolygon->bounding_box ]; } - push @vertical_lines, $vertical_line; - $x += $distance_between_lines; + + # define flow spacing according to requested density + if ($params{density} == 1 && !$params{dont_adjust}) { + $distance_between_lines = $self->adjust_solid_spacing( + width => $bounding_box->[X2] - $bounding_box->[X1], + distance => $distance_between_lines, + ); + $flow_spacing = unscale $distance_between_lines; + } + + # generate the basic pattern + my $x = $bounding_box->[X1]; + my @vertical_lines = (); + for (my $i = 0; $x <= $bounding_box->[X2] + scaled_epsilon; $i++) { + my $vertical_line = Slic3r::Line->new([$x, $bounding_box->[Y2]], [$x, $bounding_box->[Y1]]); + if ($is_line_pattern && $i % 2) { + $vertical_line->[A][X] += $line_oscillation; + $vertical_line->[B][X] -= $line_oscillation; + } + push @vertical_lines, $vertical_line; + $x += $distance_between_lines; + } + + $self->cache->{$cache_id} = [@vertical_lines]; } # clip paths against a slightly offsetted expolygon, so that the first and last paths # are kept even if the expolygon has vertical sides my @paths = @{ Boost::Geometry::Utils::polygon_multi_linestring_intersection( +($expolygon->offset_ex(scaled_epsilon))[0], # TODO: we should use all the resulting expolygons and clip the linestrings to a multipolygon object - [ @vertical_lines ], + [ @{ $self->cache->{$cache_id} } ], ) }; # connect lines diff --git a/lib/Slic3r/Geometry.pm b/lib/Slic3r/Geometry.pm index 9f0a631f4..4c1e23b9f 100644 --- a/lib/Slic3r/Geometry.pm +++ b/lib/Slic3r/Geometry.pm @@ -679,10 +679,10 @@ sub bounding_box { } sub bounding_box_center { - my @bounding_box = bounding_box(@_); + my ($bounding_box) = @_; return Slic3r::Point->new( - ($bounding_box[X2] + $bounding_box[X1]) / 2, - ($bounding_box[Y2] + $bounding_box[Y1]) / 2, + ($bounding_box->[X2] + $bounding_box->[X1]) / 2, + ($bounding_box->[Y2] + $bounding_box->[Y1]) / 2, ); } diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 7968ac61f..9fbe353e8 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -894,6 +894,7 @@ sub generate_support_material { # generate paths for the pattern that we're going to use Slic3r::debugf "Generating patterns\n"; + my $fill = Slic3r::Fill->new(print => $self->print); my $support_patterns = []; my $support_interface_patterns = []; { @@ -908,10 +909,7 @@ sub generate_support_material { push @angles, $angles[0] + 90; } - my $filler = Slic3r::Fill->filler($pattern); - $filler->bounding_box([ Slic3r::Geometry::bounding_box([ map @$_, map @$_, @areas ]) ]) - if $filler->can('bounding_box'); - + my $filler = $fill->filler($pattern); my $make_pattern = sub { my ($expolygon, $density) = @_; @@ -996,7 +994,7 @@ sub generate_support_material { # make a solid base on bottom layer if ($layer_id == 0) { - my $filler = Slic3r::Fill->filler('rectilinear'); + my $filler = $fill->filler('rectilinear'); $filler->angle($Slic3r::Config->support_material_angle + 90); foreach my $expolygon (@$islands) { my @paths = $filler->fill_surface(