implemented core adaptive slicing algorithm

This commit is contained in:
florens 2014-08-15 18:21:28 +02:00
parent 078f3af9c2
commit 197e071b32
2 changed files with 170 additions and 15 deletions

View File

@ -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,21 +18,23 @@ 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;

View File

@ -131,18 +131,64 @@ sub slice {
$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;
}
# look for an applicable custom range
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {