diff --git a/lib/Slic3r/AdaptiveSlicing.pm b/lib/Slic3r/AdaptiveSlicing.pm index 037754777..bc18a9ed6 100644 --- a/lib/Slic3r/AdaptiveSlicing.pm +++ b/lib/Slic3r/AdaptiveSlicing.pm @@ -4,8 +4,11 @@ use Moo; use List::Util qw(min max); use Slic3r::Geometry qw(X Y Z triangle_normal scale unscale); +# public +has 'mesh' => (is => 'ro', required => 1); + #private -has 'normal' => (is => 'ro', default => sub { [] }); # facet_id => [normal]; +has 'normal_z' => (is => 'ro', default => sub { [] }); # facet_id => [normal]; has 'ordered_facets' => (is => 'ro', default => sub { [] }); # id => [facet_id, min_z, max_z]; has 'current_facet' => (is => 'rw'); @@ -15,20 +18,22 @@ sub BUILD { my $facet_id = 0; my $facets = $self->mesh->facets; my $vertices = $self->mesh->vertices; + my $normals = $self->mesh->normals; + + # generate facet normals - foreach my $facet (@{$facets}) { - my $normal = triangle_normal(map $vertices->[$_], @$facet[-3..-1]); - # normalize length + for ($facet_id = 0; $facet_id <= $#{$facets}; $facet_id++) { + my $normal = $normals->[$facet_id]; my $normal_length = sqrt($normal->[0]**2 + $normal->[1]**2 + $normal->[2]**2); if($normal_length > 0) { - $self->normal->[$facet_id] = [ map $normal->[$_]/$normal_length, (X,Y,Z) ]; + $self->normal_z->[$facet_id] = $normal->[Z]/$normal_length; }else{ # facet with area = 0 - $self->normal->[$facet_id] = [0 ,0 ,0]; + $self->normal_z->[$facet_id] = [0 ,0 ,0]; } - $facet_id++; - } + } + # generate a list of facet_ids, containing maximum and minimum Z-Value of the facet, ordered by minimum Z my @sort_facets; @@ -39,7 +44,7 @@ sub BUILD { my $c = $vertices->[$facets->[$facet_id]->[2]]->[Z]; my $min_z = min($a, $b, $c); my $max_z = max($a, $b, $c); - push @sort_facets, [$facet_id, $min_z, $max_z]; + push @sort_facets, [$facet_id, scale $min_z, scale $max_z]; } @sort_facets = sort {$a->[1] <=> $b->[1]} @sort_facets; for (my $i = 0; $i <= $#sort_facets; $i++) { @@ -50,4 +55,108 @@ sub BUILD { } +sub cusp_height { + my $self = shift; + my ($z, $cusp_value, $min_height, $max_height) = @_; + + my $height = $max_height; + my $first_hit = 0; + + # find all facets intersecting the slice-layer + my $ordered_id = $self->current_facet; + while ($ordered_id <= $#{$self->ordered_facets}) { + + # facet's minimum is higher than slice_z -> end loop + if($self->ordered_facets->[$ordered_id]->[1] >= $z) { + last; + } + + # facet's maximum is higher than slice_z -> store the first event for next cusp_height call to begin at this point + if($self->ordered_facets->[$ordered_id]->[2] > $z) { + # first event? + if(!$first_hit) { + $first_hit = 1; + $self->current_facet($ordered_id); + } + + #skip touching facets which could otherwise cause small cusp values + if($self->ordered_facets->[$ordered_id]->[2] <= $z+1) + { + $ordered_id++; + next; + } + + # compute cusp-height for this facet and store minimum of all heights + my $cusp = $self->_facet_cusp_height($ordered_id, $cusp_value); + $height = $cusp if($cusp < $height); + } + $ordered_id++; + } + # lower height limit due to printer capabilities + $height = $min_height if($height < $min_height); + + + # check for sloped facets inside the determined layer and correct height if necessary + if($height > $min_height){ + while ($ordered_id <= $#{$self->ordered_facets}) { + + # facet's minimum is higher than slice_z + height -> end loop + if($self->ordered_facets->[$ordered_id]->[1] >= ($z + scale $height)) { + last; + } + + #skip touching facets which could otherwise cause small cusp values + if($self->ordered_facets->[$ordered_id]->[2] <= $z+1) + { + $ordered_id++; + next; + } + + # Compute cusp-height for this facet and check against height. + my $cusp = $self->_facet_cusp_height($ordered_id, $cusp_value); + + my $z_diff = unscale ($self->ordered_facets->[$ordered_id]->[1] - $z); + + + # handle horizontal facets + if ($self->normal_z->[$self->ordered_facets->[$ordered_id]->[0]] > 0.999) { + Slic3r::debugf "cusp computation, height is reduced from %f", $height; + $height = $z_diff; + Slic3r::debugf "to %f due to near horizontal facet\n", $height; + }else{ + if( $cusp > $z_diff) { + if($cusp < $height) { + Slic3r::debugf "cusp computation, height is reduced from %f", $height; + $height = $cusp; + Slic3r::debugf "to %f due to new cusp height\n", $height; + } + }else{ + Slic3r::debugf "cusp computation, height is reduced from %f", $height; + $height = $z_diff; + Slic3r::debugf "to z-diff: %f\n", $height; + } + } + + $ordered_id++; + } + # lower height limit due to printer capabilities again + $height = $min_height if($height < $min_height); + } + + Slic3r::debugf "cusp computation, layer-bottom at z:%f, cusp_value:%f, resulting layer height:%f\n", unscale $z, $cusp_value, $height; + + return $height; +} + +# computes the cusp height from a given facets normal and the cusp_value +sub _facet_cusp_height { + my $self = shift; + my ($ordered_id, $cusp_value) = @_; + + my $normal_z = $self->normal_z->[$self->ordered_facets->[$ordered_id]->[0]]; + my $cusp = ($normal_z == 0) ? 9999 : abs($cusp_value/$normal_z); + return $cusp; +} + + 1; \ No newline at end of file diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 8cd5440af..d0000e872 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -130,19 +130,65 @@ sub slice { $first_object_layer_height = $nozzle_diameter; $first_object_layer_distance = $distance; } + + # create stateful objects and variables for the adaptive slicing process + my @adaptive_slicing; + my $min_height = 0; + my $max_height = 0; + if ($self->config->adaptive_slicing) { + for my $region_id (0 .. ($self->region_count - 1)) { + my $mesh; + foreach my $volume_id (@{ $self->get_region_volumes($region_id) }) { + my $volume = $self->model_object->volumes->[$volume_id]; + next if $volume->modifier; + if (defined $mesh) { + $mesh->merge($volume->mesh); + } else { + $mesh = $volume->mesh->clone; + } + } + + $adaptive_slicing[$region_id] = Slic3r::AdaptiveSlicing->new( + mesh => $mesh + ); + } + + # determine min and max layer height from perimeter extruder capabilities. + if($self->region_count > 1) { # multimaterial object + $min_height = max(map {$self->print->config->get_at('min_layer_height', $_)} (0..($self->region_count-1))); + $max_height = min(map {$self->print->config->get_at('max_layer_height', $_)} (0..($self->region_count-1))); + }else{ #single material object + my $perimeter_extruder = $self->print->get_region(0)->config->get('perimeter_extruder')-1; + $min_height = $self->print->config->get_at('min_layer_height', $perimeter_extruder); + $max_height = $self->print->config->get_at('max_layer_height', $perimeter_extruder); + } + } # loop until we have at least one layer and the max slice_z reaches the object height my $max_z = unscale($self->size->z); while (($slice_z - $height) <= $max_z) { if ($self->config->adaptive_slicing) { - #dummy + my $cusp_value = $self->config->get_value('cusp_value'); + + Slic3r::debugf "\n Slice layer: %d\n", $id; + + # determine next layer height + for my $region_id (0 .. ($self->region_count - 1)) { + # get cusp height + my $cusp_height = $adaptive_slicing[$region_id]->cusp_height(scale $slice_z, $cusp_value, $min_height, $max_height); + + $height = ($id == 0) + ? $self->config->get_value('first_layer_height') + : $cusp_height; + } + + }else{ + # 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; } - - # 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}) {