diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 709bc65e4f..18768b8282 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -45,223 +45,7 @@ sub slice { $self->set_step_started(STEP_SLICE); $self->print->status_cb->(10, "Processing triangulated mesh"); - # init layers - { - $self->clear_layers; - - # make layers taking custom heights into account - my $id = 0; - my $print_z = 0; - my $first_object_layer_height = -1; - my $first_object_layer_distance = -1; - - # add raft layers - if ($self->config->raft_layers > 0) { - # Reserve object layers for the raft. Last layer of the raft is the contact layer. - $id += $self->config->raft_layers; - - # Raise first object layer Z by the thickness of the raft itself - # plus the extra distance required by the support material logic. - #FIXME The last raft layer is the contact layer, which shall be printed with a bridging flow for ease of separation. Currently it is not the case. - my $first_layer_height = $self->config->get_value('first_layer_height'); - $print_z += $first_layer_height; - - # Use as large as possible layer height for the intermediate raft layers. - my $support_material_layer_height; - { - my @nozzle_diameters = ( - map $self->print->config->get_at('nozzle_diameter', $_), - $self->config->support_material_extruder-1, - $self->config->support_material_interface_extruder-1, - ); - $support_material_layer_height = 0.75 * min(@nozzle_diameters); - } - $print_z += $support_material_layer_height * ($self->config->raft_layers - 1); - - # compute the average of all nozzles used for printing the object - #FIXME It is expected, that the 1st layer of the object is printed with a bridging flow over a full raft. Shall it not be vice versa? - my $nozzle_diameter; - { - my @nozzle_diameters = ( - map $self->print->config->get_at('nozzle_diameter', $_), @{$self->print->object_extruders} - ); - $nozzle_diameter = sum(@nozzle_diameters)/@nozzle_diameters; - } - $first_object_layer_distance = $self->_support_material->contact_distance($self->config->layer_height, $nozzle_diameter); - - # force first layer print_z according to the contact distance - # (the loop below will raise print_z by such height) - $first_object_layer_height = $first_object_layer_distance - $self->config->support_material_contact_distance; - } - - # loop until we have at least one layer and the max slice_z reaches the object height - my $slice_z = 0; - my $height = 0; - my $max_z = unscale($self->size->z); - while (($slice_z - $height) <= $max_z) { - # assign the default height to the layer according to the general settings - $height = ($id == 0) - ? $self->config->get_value('first_layer_height') - : $self->config->layer_height; - - # look for an applicable custom range - if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) { - $height = $range->[2]; - - # if user set custom height to zero we should just skip the range and resume slicing over it - if ($height == 0) { - $slice_z += $range->[1] - $range->[0]; - next; - } - } - - if ($first_object_layer_height != -1 && !@{$self->layers}) { - $height = $first_object_layer_height; - $print_z += ($first_object_layer_distance - $height); - } - - $print_z += $height; - $slice_z += $height/2; - - ### Slic3r::debugf "Layer %d: height = %s; slice_z = %s; print_z = %s\n", $id, $height, $slice_z, $print_z; - - $self->add_layer($id, $height, $print_z, $slice_z); - if ($self->layer_count >= 2) { - my $lc = $self->layer_count; - $self->get_layer($lc - 2)->set_upper_layer($self->get_layer($lc - 1)); - $self->get_layer($lc - 1)->set_lower_layer($self->get_layer($lc - 2)); - } - $id++; - - $slice_z += $height/2; # add the other half layer - } - } - - # make sure all layers contain layer region objects for all regions - my $regions_count = $self->print->region_count; - foreach my $layer (@{ $self->layers }) { - $layer->region($_) for 0 .. ($regions_count-1); - } - - # get array of Z coordinates for slicing - my @z = map $_->slice_z, @{$self->layers}; - - # slice all non-modifier volumes - for my $region_id (0..($self->region_count - 1)) { - my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 0); - for my $layer_id (0..$#$expolygons_by_layer) { - my $layerm = $self->get_layer($layer_id)->regions->[$region_id]; - $layerm->slices->clear; - foreach my $expolygon (@{ $expolygons_by_layer->[$layer_id] }) { - $layerm->slices->append(Slic3r::Surface->new( - expolygon => $expolygon, - surface_type => S_TYPE_INTERNAL, - )); - } - } - } - - # then slice all modifier volumes - if ($self->region_count > 1) { - for my $region_id (0..$self->region_count) { - my $expolygons_by_layer = $self->_slice_region($region_id, \@z, 1); - - # loop through the other regions and 'steal' the slices belonging to this one - for my $other_region_id (0..$self->region_count) { - next if $other_region_id == $region_id; - - for my $layer_id (0..$#$expolygons_by_layer) { - my $layerm = $self->get_layer($layer_id)->regions->[$region_id]; - my $other_layerm = $self->get_layer($layer_id)->regions->[$other_region_id]; - next if !defined $other_layerm; - - my $other_slices = [ map $_->p, @{$other_layerm->slices} ]; # Polygons - my $my_parts = intersection_ex( - $other_slices, - [ map @$_, @{ $expolygons_by_layer->[$layer_id] } ], - ); - next if !@$my_parts; - - # append new parts to our region - foreach my $expolygon (@$my_parts) { - $layerm->slices->append(Slic3r::Surface->new( - expolygon => $expolygon, - surface_type => S_TYPE_INTERNAL, - )); - } - - # remove such parts from original region - $other_layerm->slices->clear; - $other_layerm->slices->append(Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNAL, - )) for @{ diff_ex($other_slices, [ map @$_, @$my_parts ]) }; - } - } - } - } - - # remove last layer(s) if empty - $self->delete_layer($self->layer_count - 1) - while $self->layer_count && (!map @{$_->slices}, @{$self->get_layer($self->layer_count - 1)->regions}); - - foreach my $layer (@{ $self->layers }) { - # apply size compensation - if ($self->config->xy_size_compensation != 0) { - my $delta = scale($self->config->xy_size_compensation); - if (@{$layer->regions} == 1) { - # single region - my $layerm = $layer->regions->[0]; - my $slices = [ map $_->p, @{$layerm->slices} ]; - $layerm->slices->clear; - $layerm->slices->append(Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNAL, - )) for @{offset_ex($slices, $delta)}; - } else { - if ($delta < 0) { - # multiple regions, shrinking - # we apply the offset to the combined shape, then intersect it - # with the original slices for each region - my $slices = union([ map $_->p, map @{$_->slices}, @{$layer->regions} ]); - $slices = offset($slices, $delta); - foreach my $layerm (@{$layer->regions}) { - my $this_slices = intersection_ex( - $slices, - [ map $_->p, @{$layerm->slices} ], - ); - $layerm->slices->clear; - $layerm->slices->append(Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNAL, - )) for @$this_slices; - } - } else { - # multiple regions, growing - # this is an ambiguous case, since it's not clear how to grow regions where they are going to overlap - # so we give priority to the first one and so on - for my $i (0..$#{$layer->regions}) { - my $layerm = $layer->regions->[$i]; - my $slices = offset_ex([ map $_->p, @{$layerm->slices} ], $delta); - if ($i > 0) { - $slices = diff_ex( - [ map @$_, @$slices ], - [ map $_->p, map @{$_->slices}, map $layer->regions->[$_], 0..($i-1) ], # slices of already processed regions - ); - } - $layerm->slices->clear; - $layerm->slices->append(Slic3r::Surface->new( - expolygon => $_, - surface_type => S_TYPE_INTERNAL, - )) for @$slices; - } - } - } - } - - # Merge all regions' slices to get islands, chain them by a shortest path. - $layer->make_slices; - } + $self->_slice; # detect slicing errors my $warning_thrown = 0; @@ -334,39 +118,6 @@ sub slice { $self->set_step_done(STEP_SLICE); } -# called from slice() -sub _slice_region { - my ($self, $region_id, $z, $modifier) = @_; - - return [] if !@{$self->get_region_volumes($region_id)}; - - # compose mesh - my $mesh; - foreach my $volume_id (@{ $self->get_region_volumes($region_id) }) { - my $volume = $self->model_object->volumes->[$volume_id]; - next if $volume->modifier && !$modifier; - next if !$volume->modifier && $modifier; - - if (defined $mesh) { - $mesh->merge($volume->mesh); - } else { - $mesh = $volume->mesh->clone; - } - } - return if !defined $mesh; - - # transform mesh - # we ignore the per-instance transformations currently and only - # consider the first one - $self->model_object->instances->[0]->transform_mesh($mesh, 1); - - # align mesh to Z = 0 (it should be already aligned actually) and apply XY shift - $mesh->translate((map unscale(-$_), @{$self->_copies_shift}), -$self->model_object->bounding_box->z_min); - - # perform actual slicing - return $mesh->slice($z); -} - # 1) Merges typed region slices into stInternal type. # 2) Increases an "extra perimeters" counter at region slices where needed. # 3) Generates perimeters, gap fills and fill regions (fill regions of type stInternal).