From c9b506fa02bf037126e8e47e69b476c554ad2b70 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci <aar@cpan.org> Date: Sun, 10 Feb 2013 12:40:43 +0100 Subject: [PATCH] New simpler and more robust implementation of infill every 'n' layers --- lib/Slic3r/Print/Object.pm | 122 +++++++++++++------------------------ 1 file changed, 44 insertions(+), 78 deletions(-) diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 6a2ad1537..800290a6d 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -530,93 +530,59 @@ sub combine_infill { my $self = shift; return unless $Slic3r::Config->infill_every_layers > 1 && $Slic3r::Config->fill_density > 0; + my $every = $Slic3r::Config->infill_every_layers; my $area_threshold = $Slic3r::flow->scaled_spacing ** 2; + my $layer_count = $self->layer_count; for my $region_id (0 .. ($self->print->regions_count-1)) { - # start from top, skip lowest layer - for (my $i = $self->layer_count - 1; $i > 0; $i--) { - my $layerm = $self->layers->[$i]->regions->[$region_id]; + # skip bottom layer + for (my $layer_id = $every; $layer_id <= $layer_count-1; $layer_id += $every) { + # get the layers whose infill we want to combine (bottom-up) + my @layerms = map $self->layers->[$_]->regions->[$region_id], + ($layer_id - ($every-1)) .. $layer_id; - # skip layer if no internal fill surfaces - next if !grep $_->surface_type == S_TYPE_INTERNAL, @{$layerm->fill_surfaces}; - - # for each possible depth, look for intersections with the lower layer - # we do this from the greater depth to the smaller - for (my $d = $Slic3r::Config->infill_every_layers - 1; $d >= 1; $d--) { - next if ($i - $d) <= 0; # do not combine infill for bottom layer - my $lower_layerm = $self->layers->[$i - 1]->regions->[$region_id]; + # process internal and internal-solid infill separately + for my $type (S_TYPE_INTERNAL, S_TYPE_INTERNALSOLID) { + # we need to perform a multi-layer intersection, so let's split it in pairs - # select surfaces of the lower layer having the depth we're looking for - my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type == S_TYPE_INTERNAL, - @{$lower_layerm->fill_surfaces}; - next if !@lower_surfaces; + # initialize the intersection with the candidates of the lowest layer + my $intersection = [ map $_->expolygon, grep $_->surface_type == $type, @{$layerms[0]->fill_surfaces} ]; - # calculate intersection between our surfaces and theirs - my $intersection = intersection_ex( - [ map $_->p, grep $_->depth_layers <= $d, @lower_surfaces ], - [ map $_->p, grep $_->surface_type == S_TYPE_INTERNAL, @{$layerm->fill_surfaces} ], - undef, 1, - ); - - # purge intersections, skip tiny regions - @$intersection = grep $_->area > $area_threshold, @$intersection; - next if !@$intersection; - - # new fill surfaces of the current layer are: - # - any non-internal surface - # - intersections found (with a $d + 1 depth) - # - any internal surface not belonging to the intersection (with its original depth) - { - my @new_surfaces = (); - push @new_surfaces, grep $_->surface_type != S_TYPE_INTERNAL, @{$layerm->fill_surfaces}; - push @new_surfaces, map Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNAL, depth_layers => $d + 1), @$intersection; - - foreach my $depth (reverse $d..$Slic3r::Config->infill_every_layers) { - push @new_surfaces, map Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNAL, depth_layers => $depth), - - # difference between our internal layers with depth == $depth - # and the intersection found - @{diff_ex( - [ - map $_->p, grep $_->surface_type == S_TYPE_INTERNAL && $_->depth_layers == $depth, - @{$layerm->fill_surfaces}, - ], - [ map @$_, @$intersection ], - 1, - )}; - } - @{$layerm->fill_surfaces} = @new_surfaces; + # start looping from the second layer and intersect the current intersection with it + for my $layerm (@layerms[1 .. $#layerms]) { + $intersection = intersection_ex( + [ map @$_, @$intersection ], + [ map @{$_->expolygon}, grep $_->surface_type == $type, @{$layerm->fill_surfaces} ], + ); } - # now we remove the intersections from lower layer - { - my @new_surfaces = (); - push @new_surfaces, grep $_->surface_type != S_TYPE_INTERNAL, @{$lower_layerm->fill_surfaces}; - - # offset for the two different flow spacings - $intersection = [ map $_->offset_ex( - $lower_layerm->infill_flow->scaled_spacing / 2 - + $layerm->infill_flow->scaled_spacing / 2 - ), @$intersection]; - - foreach my $depth (1..$Slic3r::Config->infill_every_layers) { - push @new_surfaces, map Slic3r::Surface->new - (expolygon => $_, surface_type => S_TYPE_INTERNAL, depth_layers => $depth), - - # difference between internal layers with depth == $depth - # and the intersection found - @{diff_ex( - [ - map $_->p, grep $_->surface_type == S_TYPE_INTERNAL && $_->depth_layers == $depth, - @{$lower_layerm->fill_surfaces}, - ], - [ map @$_, @$intersection ], - 1, - )}; + @$intersection = grep $_->area > $area_threshold, @$intersection; + next if !@$intersection; + Slic3r::debugf " combining %d %s regions from layers %d-%d\n", + scalar(@$intersection), + ($type == S_TYPE_INTERNAL ? 'internal' : 'internal-solid'), + $layer_id-($every-1), $layer_id; + + # $intersection now contains the regions that can be combined across the full amount of layers + # so let's remove those areas from all layers + foreach my $layerm (@layerms) { + my @this_type = grep $_->surface_type == $type, @{$layerm->fill_surfaces}; + my @other_types = grep $_->surface_type != $type, @{$layerm->fill_surfaces}; + + @this_type = map Slic3r::Surface->new(expolygon => $_, surface_type => $type), + @{diff_ex( + [ map @{$_->expolygon}, @this_type ], + [ map @$_, @$intersection ], + )}; + + # apply surfaces back with adjusted depth to the uppermost layer + if ($layerm->id == $layer_id) { + push @this_type, + map Slic3r::Surface->new(expolygon => $_, surface_type => $type, depth_layers => $every), + @$intersection; } - @{$lower_layerm->fill_surfaces} = @new_surfaces; + + @{$layerm->fill_surfaces} = (@this_type, @other_types); } } }