diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 6d732971b..094ae0b2c 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -4,7 +4,7 @@ use warnings; use List::Util qw(first); use Slic3r::Geometry qw(scale chained_path); -use Slic3r::Geometry::Clipper qw(union_ex); +use Slic3r::Geometry::Clipper qw(union_ex intersection_ex); # the following two were previously generated by Moo sub print { @@ -60,7 +60,77 @@ sub make_slices { sub make_perimeters { my $self = shift; Slic3r::debugf "Making perimeters for layer %d\n", $self->id; - $_->make_perimeters for @{$self->regions}; + + # keep track of regions whose perimeters we have already generated + my %done = (); # region_id => 1 + + for my $region_id (0..$#{$self->regions}) { + next if $done{$region_id}; + my $layerm = $self->regions->[$region_id]; + $done{$region_id} = 1; + + # find compatible regions + my @layerms = ($layerm); + for my $i (($region_id+1)..$#{$self->regions}) { + my $config = $self->regions->[$i]->config; + my $layerm_config = $layerm->config; + + if ($config->perimeter_extruder == $layerm_config->perimeter_extruder + && $config->perimeters == $layerm_config->perimeters + && $config->perimeter_speed == $layerm_config->perimeter_speed + && $config->gap_fill_speed == $layerm_config->gap_fill_speed + && $config->overhangs == $layerm_config->overhangs + && $config->perimeter_extrusion_width == $layerm_config->perimeter_extrusion_width + && $config->thin_walls == $layerm_config->thin_walls + && $config->external_perimeters_first == $layerm_config->external_perimeters_first) { + push @layerms, $self->regions->[$i]; + $done{$i} = 1; + } + } + + if (@layerms == 1) { # optimization + $layerm->fill_surfaces->clear; + $layerm->make_perimeters($layerm->slices, $layerm->fill_surfaces); + } else { + # group slices (surfaces) according to number of extra perimeters + my %slices = (); # extra_perimeters => [ surface, surface... ] + foreach my $surface (map @{$_->slices}, @layerms) { + my $extra = $surface->extra_perimeters; + $slices{$extra} ||= []; + push @{$slices{$extra}}, $surface; + } + + # merge the surfaces assigned to each group + my $new_slices = Slic3r::Surface::Collection->new; + foreach my $surfaces (values %slices) { + $new_slices->append(Slic3r::Surface->new( + surface_type => $surfaces->[0]->surface_type, + extra_perimeters => $surfaces->[0]->extra_perimeters, + expolygon => $_, + )) for @{union_ex([ map $_->p, @$surfaces ], 1)}; + } + + # make perimeters + my $fill_surfaces = Slic3r::Surface::Collection->new; + $layerm->make_perimeters($new_slices, $fill_surfaces); + + # assign fill_surfaces to each layer + if ($fill_surfaces->count > 0) { + foreach my $lm (@layerms) { + my $expolygons = intersection_ex( + [ map $_->p, @$fill_surfaces ], + [ map $_->p, @{$lm->slices} ], + ); + $lm->fill_surfaces->clear; + $lm->fill_surfaces->append(Slic3r::Surface->new( + surface_type => $fill_surfaces->[0]->surface_type, + extra_perimeters => $fill_surfaces->[0]->extra_perimeters, + expolygon => $_, + )) for @$expolygons; + } + } + } + } } package Slic3r::Layer::Support; diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index ae2a7c2c4..25c840490 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -41,7 +41,7 @@ sub flow { } sub make_perimeters { - my $self = shift; + my ($self, $slices, $fill_surfaces) = @_; # other perimeters my $perimeter_flow = $self->flow(FLOW_ROLE_PERIMETER); @@ -73,7 +73,6 @@ sub make_perimeters { my $ext_min_spacing = $ext_pspacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE); $self->perimeters->clear; - $self->fill_surfaces->clear; $self->thin_fills->clear; my @contours = (); # array of Polygons with ccw orientation @@ -82,7 +81,7 @@ sub make_perimeters { # we need to process each island separately because we might have different # extra perimeters for each one - foreach my $surface (@{$self->slices}) { + foreach my $surface (@$slices) { # detect how many perimeters must be generated for this island my $loop_number = $self->config->perimeters + ($surface->extra_perimeters || 0); @@ -187,7 +186,7 @@ sub make_perimeters { # and then we offset back and forth by half the infill spacing to only consider the # non-collapsing regions my $min_perimeter_infill_spacing = $ispacing * (1 - &Slic3r::INSET_OVERLAP_TOLERANCE); - $self->fill_surfaces->append( + $fill_surfaces->append( map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), # use a bogus surface type @{offset2_ex( [ map @{$_->simplify_p(&Slic3r::SCALED_RESOLUTION)}, @{union_ex(\@last)} ],