mirror of
https://git.mirrors.martin98.com/https://github.com/slic3r/Slic3r.git
synced 2025-08-12 13:49:02 +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 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;
|
@ -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}) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user