diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 2c3882499..1031b6e86 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -126,8 +126,8 @@ sub make_fill { my $filler = $Slic3r::Config->fill_pattern; my $density = $Slic3r::Config->fill_density; my $flow_spacing = $layer->infill_flow->spacing; - my $is_bridge = $layer->id > 0 && $surface->surface_type == S_TYPE_BOTTOM; - my $is_solid = (grep { $surface->surface_type == $_ } S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_INTERNALSOLID) ? 1 : 0; + my $is_bridge = $layer->id > 0 && $surface->is_bridge; + my $is_solid = $surface->is_solid; # force 100% density and rectilinear fill for external surfaces if ($surface->surface_type != S_TYPE_INTERNAL) { diff --git a/lib/Slic3r/Layer/Region.pm b/lib/Slic3r/Layer/Region.pm index c9792c60b..cb23f719a 100644 --- a/lib/Slic3r/Layer/Region.pm +++ b/lib/Slic3r/Layer/Region.pm @@ -458,7 +458,7 @@ sub process_bridges { ($_->surface_type == S_TYPE_BOTTOM && $self->id > 0) || $_->surface_type == S_TYPE_TOP } @{$self->fill_surfaces} or return; - my @internal_surfaces = grep { $_->surface_type == S_TYPE_INTERNAL || $_->surface_type == S_TYPE_INTERNALSOLID } @{$self->slices}; + my @internal_surfaces = grep $_->is_internal, @{$self->slices}; SURFACE: foreach my $surface (@solid_surfaces) { my $expolygon = $surface->expolygon->safety_offset; diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 4263c68b0..322b8fa48 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -356,6 +356,9 @@ sub export_gcode { $status_cb->(60, "Generating horizontal shells"); $_->discover_horizontal_shells for @{$self->objects}; $_->clip_fill_surfaces for @{$self->objects}; + # the following step needs to be done before combination because it may need + # to remove only half of the combined infill + $_->bridge_over_infill for @{$self->objects}; # combine fill surfaces to honor the "infill every N layers" option $status_cb->(70, "Combining infill"); diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 5dae0482e..5f0e51ee0 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -426,6 +426,72 @@ sub clip_fill_surfaces { } } +sub bridge_over_infill { + my $self = shift; + + # calculate the number of layers to remove below each bridged one + my $skip = int(); + + for my $layer_id (1..$#{$self->layers}) { + my $layer = $self->layers->[$layer_id]; + my $lower_layer = $self->layers->[$layer_id-1]; + + foreach my $layerm (@{$layer->regions}) { + # compute the areas needing bridge math + my @internal_solid = grep $_->surface_type == S_TYPE_INTERNALSOLID, @{$layerm->fill_surfaces}; + my @lower_internal = grep $_->surface_type == S_TYPE_INTERNAL, map @{$_->fill_surfaces}, @{$lower_layer->regions}; + my $to_bridge = intersection_ex( + [ map $_->p, @internal_solid ], + [ map $_->p, @lower_internal ], + ); + next unless @$to_bridge; + Slic3r::debugf "Bridging %d internal areas at layer %d\n", scalar(@$to_bridge), $layer_id; + + # build the new collection of fill_surfaces + { + my @new_surfaces = grep $_->surface_type != S_TYPE_INTERNALSOLID, @{$layerm->fill_surfaces}; + push @new_surfaces, map Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNALBRIDGE, + ), @$to_bridge; + push @new_surfaces, map Slic3r::Surface->new( + expolygon => $_, + surface_type => S_TYPE_INTERNALSOLID, + ), @{diff_ex( + [ map $_->p, @internal_solid ], + [ map @$_, @$to_bridge ], + )}; + @{$layerm->fill_surfaces} = @new_surfaces; + } + + # exclude infill from the layers below if needed + # see discussion at https://github.com/alexrj/Slic3r/issues/240 + { + my $excess = $layerm->infill_flow->bridge_width - $layerm->height; + for (my $i = $layer_id-1; $excess >= $self->layers->[$i]->height; $i--) { + Slic3r::debugf " skipping infill below those areas at layer %d\n", $i; + foreach my $lower_layerm (@{$self->layers->[$i]->regions}) { + my @new_surfaces = (); + # subtract the area from all types of surfaces + foreach my $group (Slic3r::Surface->group(@{$lower_layerm->fill_surfaces})) { + push @new_surfaces, map Slic3r::Surface->new( + expolygon => $_, + surface_type => $group->[0]->surface_type, + ), @{diff_ex( + [ map $_->p, @$group ], + [ map @$_, @$to_bridge ], + )}; + } + @{$lower_layerm->fill_surfaces} = @new_surfaces; + } + + $excess -= $self->layers->[$i]->height; + } + } + } + } +} + sub discover_horizontal_shells { my $self = shift; diff --git a/lib/Slic3r/Surface.pm b/lib/Slic3r/Surface.pm index 6912a15af..8ebddaa14 100644 --- a/lib/Slic3r/Surface.pm +++ b/lib/Slic3r/Surface.pm @@ -4,7 +4,7 @@ use warnings; require Exporter; our @ISA = qw(Exporter); -our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_INTERNALSOLID); +our @EXPORT_OK = qw(S_TYPE_TOP S_TYPE_BOTTOM S_TYPE_INTERNAL S_TYPE_INTERNALSOLID S_TYPE_INTERNALBRIDGE); our %EXPORT_TAGS = (types => \@EXPORT_OK); use constant S_EXPOLYGON => 0; @@ -17,6 +17,7 @@ use constant S_TYPE_TOP => 0; use constant S_TYPE_BOTTOM => 1; use constant S_TYPE_INTERNAL => 2; use constant S_TYPE_INTERNALSOLID => 3; +use constant S_TYPE_INTERNALBRIDGE => 4; sub new { my $class = shift; @@ -51,7 +52,7 @@ sub group { my %unique_types = (); foreach my $surface (@surfaces) { - my $type = ($params->{merge_solid} && grep { $surface->surface_type == $_ } S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_INTERNALSOLID) + my $type = ($params->{merge_solid} && $surface->is_solid) ? 'solid' : $surface->surface_type; $type .= "_" . ($surface->bridge_angle // ''); #/ @@ -89,4 +90,28 @@ sub p { return @{$self->expolygon}; } +sub is_solid { + my $self = shift; + my $type = $self->surface_type; + return $type == S_TYPE_TOP + || $type == S_TYPE_BOTTOM + || $type == S_TYPE_INTERNALSOLID + || $type == S_TYPE_INTERNALBRIDGE; +} + +sub is_internal { + my $self = shift; + my $type = $self->surface_type; + return $type == S_TYPE_INTERNAL + || $type == S_TYPE_INTERNALSOLID + || $type == S_TYPE_INTERNALBRIDGE; +} + +sub is_bridge { + my $self = shift; + my $type = $self->surface_type; + return $type == S_TYPE_BOTTOM + || $type == S_TYPE_INTERNALBRIDGE; +} + 1;