diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index f30e09091..9609f4cda 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -25,60 +25,36 @@ has 'infill_flow' => (is => 'lazy'); # collection of spare segments generated by slicing the original geometry; # these need to be merged in continuos (closed) polylines -has 'lines' => ( - is => 'rw', - #isa => 'ArrayRef[ArrayRef]', - default => sub { [] }, -); +has 'lines' => (is => 'rw', default => sub { [] }); # collection of surfaces generated by slicing the original geometry -has 'slices' => (is => 'ro', default => sub { [] }); +has 'slices' => (is => 'rw'); # collection of polygons or polylines representing thin walls contained # in the original geometry -has 'thin_walls' => (is => 'ro', default => sub { [] }); - -# collection of expolygons generated by offsetting the innermost perimeter(s) -# they represent boundaries of areas to fill -has 'fill_boundaries' => (is => 'ro', default => sub { [] }); +has 'thin_walls' => (is => 'rw'); # collection of polygons or polylines representing thin infill regions that # need to be filled with a medial axis -has 'thin_fills' => (is => 'ro', default => sub { [] }); +has 'thin_fills' => (is => 'rw'); -# collection of surfaces generated by clipping the slices to the fill boundaries -has 'surfaces' => ( - is => 'rw', - #isa => 'ArrayRef[Slic3r::Surface]', - default => sub { [] }, -); +# collection of expolygons generated by offsetting the innermost perimeter(s) +# they represent boundaries of areas to fill, typed (top/bottom/internal) +has 'surfaces' => (is => 'rw'); -# collection of surfaces for infill -has 'fill_surfaces' => ( - is => 'rw', - #isa => 'ArrayRef[Slic3r::Surface]', - default => sub { [] }, -); +# collection of surfaces for infill generation. the difference between surfaces +# fill_surfaces is that this one honors fill_density == 0 and turns small internal +# surfaces into solid ones +has 'fill_surfaces' => (is => 'rw'); -# ordered collection of extrusion paths to build all perimeters -has 'perimeters' => ( - is => 'rw', - #isa => 'ArrayRef[Slic3r::ExtrusionLoop]', - default => sub { [] }, -); +# ordered collection of extrusion paths/loops to build all perimeters +has 'perimeters' => (is => 'rw'); # ordered collection of extrusion paths to fill surfaces for support material -has 'support_fills' => ( - is => 'rw', - #isa => 'Slic3r::ExtrusionPath::Collection', -); +has 'support_fills' => (is => 'rw'); # ordered collection of extrusion paths to fill surfaces -has 'fills' => ( - is => 'rw', - #isa => 'ArrayRef[Slic3r::ExtrusionPath::Collection]', - default => sub { [] }, -); +has 'fills' => (is => 'rw'); # Z used for slicing sub _build_slice_z { @@ -123,14 +99,6 @@ sub _build_infill_flow { : $Slic3r::infill_flow; } -sub add_line { - my $self = shift; - my ($line) = @_; - - push @{ $self->lines }, $line; - return $line; -} - # build polylines from lines sub make_surfaces { my $self = shift; @@ -144,9 +112,10 @@ sub make_surfaces { Slic3r::debugf " %d surface(s) having %d holes detected from %d polylines\n", scalar(@$expolygons), scalar(map $_->holes, @$expolygons), scalar(@$loops); - push @{$self->slices}, + $self->slices([ map Slic3r::Surface->new(expolygon => $_, surface_type => S_TYPE_INTERNAL), - @$expolygons; + @$expolygons + ]); } # the contours must be offsetted by half extrusion width inwards @@ -170,13 +139,12 @@ sub make_surfaces { 1, ); + $self->thin_walls([]); if (@$diff) { my $area_threshold = scale($self->perimeters_flow->spacing) ** 2; @$diff = grep $_->area > ($area_threshold), @$diff; - push @{$self->thin_walls}, - map $_->medial_axis(scale $self->perimeters_flow->width), - @$diff; + @{$self->thin_walls} = map $_->medial_axis(scale $self->perimeters_flow->width), @$diff; Slic3r::debugf " %d thin walls detected\n", scalar(@{$self->thin_walls}) if @{$self->thin_walls}; } @@ -216,6 +184,10 @@ sub make_perimeters { map [ $_->contour->[0], $_ ], @{$self->slices}, ])}; + $self->perimeters([]); + $self->surfaces([]); + $self->thin_fills([]); + # for each island: foreach my $surface (@surfaces) { my @last_offsets = ($surface->expolygon); @@ -276,7 +248,7 @@ sub make_perimeters { { my @fill_boundaries = map $_->offset_ex(-$distance), @last_offsets; $_->simplify(scale $Slic3r::resolution) for @fill_boundaries; - push @{ $self->fill_boundaries }, @fill_boundaries; + push @{ $self->surfaces }, @fill_boundaries; # detect the small gaps that we need to treat like thin polygons, # thus generating the skeleton and using it to fill them @@ -336,13 +308,13 @@ sub make_perimeters { } # do holes, then contours starting from innermost one - $self->add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef) + $self->_add_perimeter($holes[$_], $is_external{$_} ? EXTR_ROLE_EXTERNAL_PERIMETER : undef) for reverse 0 .. $#holes; for my $depth (reverse 0 .. $#$island) { my $role = $depth == $#$island ? EXTR_ROLE_CONTOUR_INTERNAL_PERIMETER : $depth == 0 ? EXTR_ROLE_EXTERNAL_PERIMETER : EXTR_ROLE_PERIMETER; - $self->add_perimeter($_, $role) for map $_->contour, @{$island->[$depth]}; + $self->_add_perimeter($_, $role) for map $_->contour, @{$island->[$depth]}; } } @@ -363,7 +335,7 @@ sub make_perimeters { } } -sub add_perimeter { +sub _add_perimeter { my $self = shift; my ($polygon, $role) = @_; @@ -381,6 +353,7 @@ sub prepare_fill_surfaces { my @surfaces = @{$self->surfaces}; # if no solid layers are requested, turn top/bottom surfaces to internal + # note that this modifies $self->surfaces in place if ($Slic3r::solid_layers == 0) { $_->surface_type(S_TYPE_INTERNAL) for grep $_->surface_type != S_TYPE_INTERNAL, @surfaces; } @@ -414,6 +387,7 @@ sub prepare_fill_surfaces { # (those that are too tight for extrusion) { my $distance = scale $self->infill_flow->spacing / 2; + my @fill_surfaces = (); foreach my $surface (@surfaces) { # offset inwards @@ -423,25 +397,26 @@ sub prepare_fill_surfaces { @offsets = map $_->offset_ex($distance), @offsets; @offsets = @{ union_ex([ map @$_, @offsets ], undef, 1) }; - push @{$self->fill_surfaces}, map Slic3r::Surface->new( + push @fill_surfaces, map Slic3r::Surface->new( expolygon => $_, surface_type => $surface->surface_type), @offsets; } Slic3r::debugf "identified %d small surfaces at layer %d\n", - (@surfaces - @{$self->fill_surfaces}), $self->id - if @{$self->fill_surfaces} != @surfaces; + (@surfaces - @fill_surfaces), $self->id + if @fill_surfaces != @surfaces; # the difference between @surfaces and $self->fill_surfaces # is what's too small; we add it back as solid infill if ($Slic3r::fill_density > 0) { my $diff = diff_ex( [ map $_->p, @surfaces ], - [ map $_->p, @{$self->fill_surfaces} ], + [ map $_->p, @fill_surfaces ], ); - push @{$self->fill_surfaces}, map Slic3r::Surface->new( + push @surfaces, map Slic3r::Surface->new( expolygon => $_, - surface_type => S_TYPE_INTERNALSOLID), @$diff; + surface_type => S_TYPE_INTERNALSOLID + ), @$diff; } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 77f671091..639e3b454 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -252,11 +252,11 @@ sub export_gcode { $_->discover_horizontal_shells for @{$self->objects}; # free memory - @{$_->surfaces} = () for map @{$_->layers}, @{$self->objects}; + $_->surfaces(undef) for map @{$_->layers}, @{$self->objects}; # combine fill surfaces to honor the "infill every N layers" option $status_cb->(70, "Combining infill"); - $_->infill_every_layers for @{$self->objects}; + $_->combine_infill for @{$self->objects}; # this will generate extrusion paths for each layer $status_cb->(80, "Infilling layers"); @@ -284,13 +284,13 @@ sub export_gcode { my $fills = shift; foreach my $obj_idx (keys %$fills) { foreach my $layer_id (keys %{$fills->{$obj_idx}}) { - @{$self->objects->[$obj_idx]->layers->[$layer_id]->fills} = @{$fills->{$obj_idx}{$layer_id}}; + $self->objects->[$obj_idx]->layers->[$layer_id]->fills($fills->{$obj_idx}{$layer_id}); } } }, no_threads_cb => sub { foreach my $layer (map @{$_->layers}, @{$self->objects}) { - @{$layer->fills} = $fill_maker->make_fill($layer); + $layer->fills([ $fill_maker->make_fill($layer) ]); } }, ); @@ -303,7 +303,7 @@ sub export_gcode { } # free memory (note that support material needs fill_surfaces) - @{$_->fill_surfaces} = () for map @{$_->layers}, @{$self->objects}; + $_->fill_surfaces(undef) for map @{$_->layers}, @{$self->objects}; # make skirt $status_cb->(88, "Generating skirt"); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index f94e4867d..6d276d479 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -48,7 +48,7 @@ sub slice { my $lines = shift; foreach my $layer_id (keys %$lines) { my $layer = $self->layer($layer_id); - $layer->add_line($_) for @{ $lines->{$layer_id} }; + push @{$layer->lines}, @{$lines->{$layer_id}}; } }; Slic3r::parallelize( @@ -84,7 +84,7 @@ sub slice { # remove last layer if empty # (we might have created it because of the $max_layer = ... + 1 code below) - pop @{$self->layers} if !@{$self->layers->[-1]->surfaces} && !@{$self->layers->[-1]->lines}; + pop @{$self->layers} if !@{$self->layers->[-1]->lines}; foreach my $layer (@{ $self->layers }) { Slic3r::debugf "Making surfaces for layer %d (slice z = %f):\n", @@ -291,19 +291,17 @@ sub detect_surfaces_type { # clip surfaces to the fill boundaries foreach my $layer (@{$self->layers}) { + my $fill_boundaries = [ map @$_, @{$layer->surfaces} ]; @{$layer->surfaces} = (); foreach my $surface (@{$layer->slices}) { my $intersection = intersection_ex( [ $surface->p ], - [ map @$_, @{$layer->fill_boundaries} ], + $fill_boundaries, ); push @{$layer->surfaces}, map Slic3r::Surface->new (expolygon => $_, surface_type => $surface->surface_type), @$intersection; } - - # free memory - @{$layer->fill_boundaries} = (); } } @@ -394,7 +392,7 @@ sub discover_horizontal_shells { } # combine fill surfaces across layers -sub infill_every_layers { +sub combine_infill { my $self = shift; return unless $Slic3r::infill_every_layers > 1 && $Slic3r::fill_density > 0;