mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-13 14:08:58 +08:00
implemented core adaptive slicing algorithm
This commit is contained in:
parent
078f3af9c2
commit
197e071b32
@ -4,8 +4,11 @@ use Moo;
|
|||||||
use List::Util qw(min max);
|
use List::Util qw(min max);
|
||||||
use Slic3r::Geometry qw(X Y Z triangle_normal scale unscale);
|
use Slic3r::Geometry qw(X Y Z triangle_normal scale unscale);
|
||||||
|
|
||||||
|
# public
|
||||||
|
has 'mesh' => (is => 'ro', required => 1);
|
||||||
|
|
||||||
#private
|
#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 'ordered_facets' => (is => 'ro', default => sub { [] }); # id => [facet_id, min_z, max_z];
|
||||||
has 'current_facet' => (is => 'rw');
|
has 'current_facet' => (is => 'rw');
|
||||||
|
|
||||||
@ -15,21 +18,23 @@ sub BUILD {
|
|||||||
my $facet_id = 0;
|
my $facet_id = 0;
|
||||||
my $facets = $self->mesh->facets;
|
my $facets = $self->mesh->facets;
|
||||||
my $vertices = $self->mesh->vertices;
|
my $vertices = $self->mesh->vertices;
|
||||||
|
my $normals = $self->mesh->normals;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# generate facet normals
|
# generate facet normals
|
||||||
foreach my $facet (@{$facets}) {
|
for ($facet_id = 0; $facet_id <= $#{$facets}; $facet_id++) {
|
||||||
my $normal = triangle_normal(map $vertices->[$_], @$facet[-3..-1]);
|
my $normal = $normals->[$facet_id];
|
||||||
# normalize length
|
|
||||||
my $normal_length = sqrt($normal->[0]**2 + $normal->[1]**2 + $normal->[2]**2);
|
my $normal_length = sqrt($normal->[0]**2 + $normal->[1]**2 + $normal->[2]**2);
|
||||||
|
|
||||||
if($normal_length > 0) {
|
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
|
}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
|
# generate a list of facet_ids, containing maximum and minimum Z-Value of the facet, ordered by minimum Z
|
||||||
my @sort_facets;
|
my @sort_facets;
|
||||||
|
|
||||||
@ -39,7 +44,7 @@ sub BUILD {
|
|||||||
my $c = $vertices->[$facets->[$facet_id]->[2]]->[Z];
|
my $c = $vertices->[$facets->[$facet_id]->[2]]->[Z];
|
||||||
my $min_z = min($a, $b, $c);
|
my $min_z = min($a, $b, $c);
|
||||||
my $max_z = max($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;
|
@sort_facets = sort {$a->[1] <=> $b->[1]} @sort_facets;
|
||||||
for (my $i = 0; $i <= $#sort_facets; $i++) {
|
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;
|
1;
|
@ -131,18 +131,64 @@ sub slice {
|
|||||||
$first_object_layer_distance = $distance;
|
$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
|
# loop until we have at least one layer and the max slice_z reaches the object height
|
||||||
my $max_z = unscale($self->size->z);
|
my $max_z = unscale($self->size->z);
|
||||||
while (($slice_z - $height) <= $max_z) {
|
while (($slice_z - $height) <= $max_z) {
|
||||||
|
|
||||||
if ($self->config->adaptive_slicing) {
|
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
|
# assign the default height to the layer according to the general settings
|
||||||
$height = ($id == 0)
|
$height = ($id == 0)
|
||||||
? $self->config->get_value('first_layer_height')
|
? $self->config->get_value('first_layer_height')
|
||||||
: $self->config->layer_height;
|
: $self->config->layer_height;
|
||||||
|
}
|
||||||
|
|
||||||
# look for an applicable custom range
|
# look for an applicable custom range
|
||||||
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
|
if (my $range = first { $_->[0] <= $slice_z && $_->[1] > $slice_z } @{$self->layer_height_ranges}) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user