diff options
author | bubnikv <bubnikv@gmail.com> | 2016-11-10 21:23:01 +0300 |
---|---|---|
committer | bubnikv <bubnikv@gmail.com> | 2016-11-10 21:23:01 +0300 |
commit | 4460b5ce50c7160cd922972a190c27bf4381ffbd (patch) | |
tree | c9030404b1edebaf3501f107960697cc84f76e02 /lib | |
parent | 317e9131e89782c98201849a21c0e2e91c8fc142 (diff) |
re-wrote PrintObject::detect_surfaces_type() to C++,
Fixed some cracks in the fill surfaces created by rounding all surfaces inside detect_surface_type().
Fixed https://github.com/prusa3d/Slic3r/issues/12
Bridging-Angle not optimal
Extended the "Ensure veritcal wall thickness" mode (merged with the original discover_horizontal_shells function), but this a work in progress. Already Slic3r with "ensure vertical wall thickness" produces less spurious infills inside solids.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Slic3r/Print/Object.pm | 164 |
1 files changed, 3 insertions, 161 deletions
diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 438c4b1ef..ab390fd3a 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -669,167 +669,6 @@ sub _support_material { } } -# This function analyzes slices of a region (SurfaceCollection slices). -# Each slice (instance of Surface) is analyzed, whether it is supported or whether it is the top surface. -# Initially all slices are of type S_TYPE_INTERNAL. -# Slices are compared against the top / bottom slices and regions and classified to the following groups: -# S_TYPE_TOP - Part of a region, which is not covered by any upper layer. This surface will be filled with a top solid infill. -# S_TYPE_BOTTOMBRIDGE - Part of a region, which is not fully supported, but it hangs in the air, or it hangs losely on a support or a raft. -# S_TYPE_BOTTOM - Part of a region, which is not supported by the same region, but it is supported either by another region, or by a soluble interface layer. -# S_TYPE_INTERNAL - Part of a region, which is supported by the same region type. -# If a part of a region is of S_TYPE_BOTTOM and S_TYPE_TOP, the S_TYPE_BOTTOM wins. -sub detect_surfaces_type { - my $self = shift; - Slic3r::debugf "Detecting solid surfaces...\n"; - - for my $region_id (0 .. ($self->print->region_count-1)) { - for my $i (0 .. ($self->layer_count - 1)) { - my $layerm = $self->get_layer($i)->regions->[$region_id]; - - # prepare a reusable subroutine to make surface differences - my $difference = sub { - my ($subject, $clip, $result_type) = @_; - my $diff = diff( - [ map @$_, @$subject ], - [ map @$_, @$clip ], - 1, - ); - - # collapse very narrow parts (using the safety offset in the diff is not enough) - my $offset = $layerm->flow(FLOW_ROLE_EXTERNAL_PERIMETER)->scaled_width / 10; - return map Slic3r::Surface->new(expolygon => $_, surface_type => $result_type), - @{ offset2_ex($diff, -$offset, +$offset) }; - }; - - # comparison happens against the *full* slices (considering all regions) - # unless internal shells are requested - my $upper_layer = $i < $self->layer_count - 1 ? $self->get_layer($i+1) : undef; - my $lower_layer = $i > 0 ? $self->get_layer($i-1) : undef; - - # find top surfaces (difference between current surfaces - # of current layer and upper one) - my @top = (); - if ($upper_layer) { - # Config value $self->config->interface_shells is true, if a support is separated from the object - # by a soluble material (for example a PVA plastic). - my $upper_slices = $self->config->interface_shells - ? [ map $_->expolygon, @{$upper_layer->regions->[$region_id]->slices} ] - : $upper_layer->slices; - - @top = $difference->( - [ map $_->expolygon, @{$layerm->slices} ], - $upper_slices, - S_TYPE_TOP, - ); - } else { - # if no upper layer, all surfaces of this one are solid - # we clone surfaces because we're going to clear the slices collection - @top = map $_->clone, @{$layerm->slices}; - $_->surface_type(S_TYPE_TOP) for @top; - } - - # find bottom surfaces (difference between current surfaces - # of current layer and lower one) - my @bottom = (); - if ($lower_layer) { - # Any surface lying on the void is a true bottom bridge (an overhang) - push @bottom, $difference->( - [ map $_->expolygon, @{$layerm->slices} ], - $lower_layer->slices, - S_TYPE_BOTTOMBRIDGE, - ); - - # If we have soluble support material, don't bridge. The overhang will be squished against a soluble layer separating - # the support from the print. - if ($self->config->support_material && $self->config->support_material_contact_distance == 0) { - $_->surface_type(S_TYPE_BOTTOM) for @bottom; - } - - # if user requested internal shells, we need to identify surfaces - # lying on other slices not belonging to this region - if ($self->config->interface_shells) { - # non-bridging bottom surfaces: any part of this layer lying - # on something else, excluding those lying on our own region - my $supported = intersection_ex( - [ map @{$_->expolygon}, @{$layerm->slices} ], - [ map @$_, @{$lower_layer->slices} ], - ); - push @bottom, $difference->( - $supported, - [ map $_->expolygon, @{$lower_layer->regions->[$region_id]->slices} ], - S_TYPE_BOTTOM, - ); - } - } else { - # if no lower layer, all surfaces of this one are solid - # we clone surfaces because we're going to clear the slices collection - @bottom = map $_->clone, @{$layerm->slices}; - - # if we have raft layers, consider bottom layer as a bridge - # just like any other bottom surface lying on the void - if ($self->config->raft_layers > 0 && $self->config->support_material_contact_distance > 0) { - $_->surface_type(S_TYPE_BOTTOMBRIDGE) for @bottom; - } else { - $_->surface_type(S_TYPE_BOTTOM) for @bottom; - } - } - - # now, if the object contained a thin membrane, we could have overlapping bottom - # and top surfaces; let's do an intersection to discover them and consider them - # as bottom surfaces (to allow for bridge detection) - if (@top && @bottom) { - my $overlapping = intersection_ex([ map $_->p, @top ], [ map $_->p, @bottom ]); - Slic3r::debugf " layer %d contains %d membrane(s)\n", $layerm->layer->id, scalar(@$overlapping) - if $Slic3r::debug; - @top = $difference->([map $_->expolygon, @top], $overlapping, S_TYPE_TOP); - } - - # find internal surfaces (difference between top/bottom surfaces and others) - my @internal = $difference->( - [ map $_->expolygon, @{$layerm->slices} ], - [ map $_->expolygon, @top, @bottom ], - S_TYPE_INTERNAL, - ); - - # save surfaces to layer - $layerm->slices->clear; - $layerm->slices->append($_) for (@bottom, @top, @internal); - - Slic3r::debugf " layer %d has %d bottom, %d top and %d internal surfaces\n", - $layerm->layer->id, scalar(@bottom), scalar(@top), scalar(@internal) if $Slic3r::debug; - - if ($SLIC3R_DEBUG_SLICE_PROCESSING) { - $layerm->export_region_slices_to_svg_debug("detect_surfaces_type-final"); - } - } # for each layer of a region - - # clip surfaces to the fill boundaries - foreach my $layer (@{$self->layers}) { - my $layerm = $layer->regions->[$region_id]; - - # Note: this method should be idempotent, but fill_surfaces gets modified - # in place. However we're now only using its boundaries (which are invariant) - # so we're safe. This guarantees idempotence of prepare_infill() also in case - # that combine_infill() turns some fill_surface into VOID surfaces. - my $fill_boundaries = [ map $_->clone->p, @{$layerm->fill_surfaces} ]; - $layerm->fill_surfaces->clear; - foreach my $surface (@{$layerm->slices}) { - my $intersection = intersection_ex( - [ $surface->p ], - $fill_boundaries, - ); - $layerm->fill_surfaces->append($_) - for map Slic3r::Surface->new(expolygon => $_, surface_type => $surface->surface_type), - @$intersection; - } - - if ($SLIC3R_DEBUG_SLICE_PROCESSING) { - $layerm->export_region_fill_surfaces_to_svg_debug("1_detect_surfaces_type-final"); - } - } # for each layer of a region - } # for each $self->print->region_count -} - # Idempotence of this method is guaranteed by the fact that we don't remove things from # fill_surfaces but we only turn them into VOID surfaces, thus preserving the boundaries. sub clip_fill_surfaces { @@ -953,6 +792,9 @@ sub discover_horizontal_shells { my $type = $layerm->region->config->fill_density == 100 ? S_TYPE_INTERNALSOLID : S_TYPE_INTERNALBRIDGE; $_->surface_type($type) for @{$layerm->fill_surfaces->filter_by_type(S_TYPE_INTERNAL)}; } + + # If ensure_vertical_shell_thickness, then the rest has already been performed by discover_vertical_shells(). + next if ($layerm->region->config->ensure_vertical_shell_thickness); EXTERNAL: foreach my $type (S_TYPE_TOP, S_TYPE_BOTTOM, S_TYPE_BOTTOMBRIDGE) { # find slices of current type for current layer |