diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 366d037e..60a6db13 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -51,8 +51,8 @@ sub make_fill { # merge overlapping surfaces my @surfaces = (); { - my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->surfaces}; - foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->surfaces})) { + my @surfaces_with_bridge_angle = grep defined $_->bridge_angle, @{$layer->fill_surfaces}; + foreach my $group (Slic3r::Surface->group({merge_solid => 1}, @{$layer->fill_surfaces})) { my $union = union_ex([ map $_->p, @$group ]); # subtract surfaces having a defined bridge_angle from any other @@ -90,7 +90,7 @@ sub make_fill { my $is_solid = $surface->surface_type =~ /^(top|bottom)$/; # force 100% density and rectilinear fill for external surfaces - if (($surface->surface_type ne 'internal') && ($Slic3r::solid_layers >= 1)) { + if ($surface->surface_type ne 'internal') { $density = 1; $filler = $is_bridge ? 'rectilinear' : $Slic3r::solid_fill_pattern; $flow_width = $Slic3r::nozzle_diameter if $is_bridge; diff --git a/lib/Slic3r/Layer.pm b/lib/Slic3r/Layer.pm index 0c60a46d..9ae5d090 100644 --- a/lib/Slic3r/Layer.pm +++ b/lib/Slic3r/Layer.pm @@ -30,6 +30,13 @@ has 'surfaces' => ( default => sub { [] }, ); +# collection of surfaces for infill +has 'fill_surfaces' => ( + is => 'rw', + #isa => 'ArrayRef[Slic3r::Surface]', + default => sub { [] }, +); + # ordered collection of extrusion paths to build all perimeters has 'perimeters' => ( is => 'rw', @@ -77,24 +84,6 @@ sub print_z { + ($self->id * $Slic3r::layer_height)) / $Slic3r::resolution; } -sub add_surface { - my $self = shift; - my (@vertices) = @_; - - # convert arrayref points to Point objects - @vertices = map Slic3r::Point->new($_), @vertices; - - my $surface = Slic3r::Surface->new( - contour => Slic3r::Polyline::Closed->new(points => \@vertices), - ); - push @{ $self->surfaces }, $surface; - - # make sure our contour has its points in counter-clockwise order - $surface->contour->make_counter_clockwise; - - return $surface; -} - sub add_line { my $self = shift; my ($line) = @_; @@ -125,14 +114,52 @@ sub make_surfaces { #); } +sub prepare_fill_surfaces { + my $self = shift; + + my @surfaces = @{$self->surfaces}; + + # merge too small internal surfaces with their surrounding tops + # (if they're too small, they can be treated as solid) + { + my $min_area = ((7 * $Slic3r::flow_width / $Slic3r::resolution)**2) * PI; + my $small_internal = [ + grep { $_->expolygon->contour->area <= $min_area } + grep { $_->surface_type eq 'internal' } + @surfaces + ]; + foreach my $s (@$small_internal) { + @surfaces = grep $_ ne $s, @surfaces; + } + my $union = union_ex([ + (map $_->p, grep $_->surface_type eq 'top', @surfaces), + (map @$_, map $_->expolygon->safety_offset, @$small_internal), + ]); + my @top = map Slic3r::Surface->cast_from_expolygon($_, surface_type => 'top'), @$union; + @surfaces = (grep($_->surface_type ne 'top', @surfaces), @top); + } + + # remove top/bottom surfaces + if ($Slic3r::solid_layers == 0) { + @surfaces = grep $_->surface_type eq 'internal', @surfaces; + } + + # remove internal surfaces + if ($Slic3r::fill_density == 0) { + @surfaces = grep $_->surface_type ne 'internal', @surfaces; + } + + $self->fill_surfaces([@surfaces]); +} + sub remove_small_surfaces { my $self = shift; my @good_surfaces = (); my $distance = ($Slic3r::flow_width / 2 / $Slic3r::resolution); - my @surfaces = @{$self->surfaces}; - @{$self->surfaces} = (); + my @surfaces = @{$self->fill_surfaces}; + @{$self->fill_surfaces} = (); foreach my $surface (@surfaces) { # offset inwards my @offsets = $surface->expolygon->offset_ex(-$distance); @@ -144,13 +171,13 @@ sub remove_small_surfaces { # the difference between $surface->expolygon and @offsets # is what we can't print since it's too small - push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_, + push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, surface_type => $surface->surface_type), @offsets; } Slic3r::debugf "removed %d small surfaces at layer %d\n", - (@surfaces - @{$self->surfaces}), $self->id - if @{$self->surfaces} != @surfaces; + (@surfaces - @{$self->fill_surfaces}), $self->id + if @{$self->fill_surfaces} != @surfaces; } sub remove_small_perimeters { @@ -178,7 +205,7 @@ sub process_bridges { my @solid_surfaces = grep { ($_->surface_type eq 'bottom' && $self->id > 0) || $_->surface_type eq 'top' - } @{$self->surfaces} or return; + } @{$self->fill_surfaces} or return; my @internal_surfaces = grep $_->surface_type =~ /internal/, @{$self->surfaces}; @@ -197,11 +224,13 @@ sub process_bridges { } } - #use Slic3r::SVG; - #Slic3r::SVG::output(undef, "bridge.svg", - # green_polygons => [ map $_->p, @supporting_surfaces ], - # red_polygons => [ @$expolygon ], - #); + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output(undef, "bridge.svg", + green_polygons => [ map $_->p, @supporting_surfaces ], + red_polygons => [ @$expolygon ], + ); + } next SURFACE unless @supporting_surfaces; Slic3r::debugf " Found $description on layer %d with %d support(s)\n", @@ -215,7 +244,8 @@ sub process_bridges { my @edges = (); # edges are POLYLINES foreach my $supporting_surface (@supporting_surfaces) { my @surface_edges = $supporting_surface->contour->clip_with_polygon($contour_offset); - if (@surface_edges == 1 && @{$supporting_surface->contour->p} == @{$surface_edges[0]->p}) { + if (@supporting_surfaces == 1 && @surface_edges == 1 + && @{$supporting_surface->contour->p} == @{$surface_edges[0]->p}) { $bridge_over_hole = 1; } else { foreach my $edge (@surface_edges) { @@ -234,6 +264,7 @@ sub process_bridges { Slic3r::SVG::output(undef, "bridge.svg", polylines => [ map $_->p, @edges ], ); + exit if $self->id == 30; } if (@edges == 2) { @@ -288,8 +319,8 @@ sub process_bridges { # apply bridges to layer { - my @surfaces = @{$self->surfaces}; - @{$self->surfaces} = (); + my @surfaces = @{$self->fill_surfaces}; + @{$self->fill_surfaces} = (); # intersect layer surfaces with bridges to get actual bridges foreach my $bridge (@bridges) { @@ -298,7 +329,7 @@ sub process_bridges { [ $bridge->p ], ); - push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_, + push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, surface_type => $bridge->surface_type, bridge_angle => $bridge->bridge_angle, ), @$actual_bridge; @@ -310,7 +341,7 @@ sub process_bridges { [ map $_->p, @$group ], [ map $_->p, @bridges ], ); - push @{$self->surfaces}, map Slic3r::Surface->cast_from_expolygon($_, + push @{$self->fill_surfaces}, map Slic3r::Surface->cast_from_expolygon($_, surface_type => $group->[0]->surface_type), @$difference; } } diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index d2a54c54..9b7dcd07 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -205,14 +205,7 @@ sub detect_surfaces_type { # find top surfaces (difference between current surfaces # of current layer and upper one) if ($upper_layer) { - # only consider those upper surfaces that are not small - # (if they're too small, the interface with them can be treated - # like a continuous solid surface instead of cutting a little - # internal surface in it) - my $min_area = ((7 * $Slic3r::flow_width / $Slic3r::resolution)**2) * PI; - my $upper_surfaces = [ grep { $_->expolygon->contour->area > $min_area } @{$upper_layer->surfaces} ]; - - @top = $surface_difference->($layer->surfaces, $upper_surfaces, 'top'); + @top = $surface_difference->($layer->surfaces, $upper_layer->surfaces, 'top'); } else { # if no upper layer, all surfaces of this one are solid @@ -275,7 +268,7 @@ sub discover_horizontal_shells { my $layer = $self->layers->[$i]; foreach my $type (qw(top bottom)) { # find surfaces of current type for current layer - my @surfaces = grep $_->surface_type eq $type, @{$layer->surfaces} or next; + my @surfaces = grep $_->surface_type eq $type, @{$layer->fill_surfaces} or next; my $surfaces_p = [ map $_->p, @surfaces ]; Slic3r::debugf "Layer %d has %d surfaces of type '%s'\n", $i, scalar(@surfaces), $type; @@ -287,7 +280,7 @@ sub discover_horizontal_shells { next if $n < 0 || $n >= $self->layer_count; Slic3r::debugf " looking for neighbors on layer %d...\n", $n; - my $surfaces = $self->layers->[$n]->surfaces; + my $surfaces = $self->layers->[$n]->fill_surfaces; my @neighbor = @$surfaces; # find intersection between @surfaces and current layer's surfaces @@ -378,7 +371,7 @@ sub infill_every_layers { my $layer = $self->layer($i); # skip layer if no internal fill surfaces - next if !grep $_->surface_type eq 'internal', @{$layer->surfaces}; + next if !grep $_->surface_type eq 'internal', @{$layer->fill_surfaces}; # for each possible depth, look for intersections with the lower layer # we do this from the greater depth to the smaller @@ -388,13 +381,13 @@ sub infill_every_layers { # select surfaces of the lower layer having the depth we're looking for my @lower_surfaces = grep $_->depth_layers == $d && $_->surface_type eq 'internal', - @{$lower_layer->surfaces}; + @{$lower_layer->fill_surfaces}; next if !@lower_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 eq 'internal', @{$layer->surfaces} ], + [ map $_->p, grep $_->surface_type eq 'internal', @{$layer->fill_surfaces} ], ); next if !@$intersection; my $intersection_offsetted = safety_offset([ map @$_, @$intersection ]); @@ -405,7 +398,7 @@ sub infill_every_layers { # - any internal surface not belonging to the intersection (with its original depth) { my @new_surfaces = (); - push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->surfaces}; + push @new_surfaces, grep $_->surface_type ne 'internal', @{$layer->fill_surfaces}; push @new_surfaces, map Slic3r::Surface->cast_from_expolygon ($_, surface_type => 'internal', depth_layers => $d + 1), @$intersection; @@ -418,18 +411,18 @@ sub infill_every_layers { @{diff_ex( [ map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth, - @{$layer->surfaces}, + @{$layer->fill_surfaces}, ], $intersection_offsetted, )}; } - @{$layer->surfaces} = @new_surfaces; + @{$layer->fill_surfaces} = @new_surfaces; } # now we remove the intersections from lower layer { my @new_surfaces = (); - push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->surfaces}; + push @new_surfaces, grep $_->surface_type ne 'internal', @{$lower_layer->fill_surfaces}; foreach my $depth (1..$Slic3r::infill_every_layers) { push @new_surfaces, map Slic3r::Surface->cast_from_expolygon ($_, surface_type => 'internal', depth_layers => $depth), @@ -439,12 +432,12 @@ sub infill_every_layers { @{diff_ex( [ map $_->p, grep $_->surface_type eq 'internal' && $_->depth_layers == $depth, - @{$lower_layer->surfaces}, + @{$lower_layer->fill_surfaces}, ], $intersection_offsetted, )}; } - @{$lower_layer->surfaces} = @new_surfaces; + @{$lower_layer->fill_surfaces} = @new_surfaces; } } } diff --git a/lib/Slic3r/Skein.pm b/lib/Slic3r/Skein.pm index 7e0a8343..da5b08e7 100644 --- a/lib/Slic3r/Skein.pm +++ b/lib/Slic3r/Skein.pm @@ -45,6 +45,10 @@ sub go { $self->status_cb->(30, "Detecting solid surfaces..."); $print->detect_surfaces_type; + # prepare fill surfaces + $self->status_cb->(35, "Preparing infill surfaces..."); + $_->prepare_fill_surfaces for @{$print->layers}; + # this will remove unprintable surfaces # (those that are too tight for extrusion) $self->status_cb->(40, "Cleaning up..."); diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index b6e16f5a..abfa8a24 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -60,8 +60,8 @@ sub group { my $type = ($params->{merge_solid} && $surface->surface_type =~ /top|bottom|solid/) ? 'solid' : $surface->surface_type; - $type .= "_" . ($_[0]->bridge_angle || ''); - $type .= "_" . $_[0]->depth_layers; + $type .= "_" . ($surface->bridge_angle || ''); + $type .= "_" . $surface->depth_layers; $unique_types{$type} ||= []; push @{ $unique_types{$type} }, $surface; } diff --git a/lib/Slic3r/TriangleMesh.pm b/lib/Slic3r/TriangleMesh.pm index fd7c1c25..aef77ef5 100644 --- a/lib/Slic3r/TriangleMesh.pm +++ b/lib/Slic3r/TriangleMesh.pm @@ -68,7 +68,7 @@ sub make_loops { } } - my $sparse_lines = [ map $_->line, @lines ]; + my $sparse_lines = [ map $_->line, grep $_, @lines ]; # detect closed loops if (0) {