implemented volumetric error approach to control the adaptive layer height

This commit is contained in:
Florens Wasserfall 2017-02-08 12:49:17 +01:00
parent 1bb827cbbd
commit 59dd5e4bca
7 changed files with 358 additions and 67 deletions

View File

@ -2,6 +2,7 @@ package Slic3r::AdaptiveSlicing;
use Moo;
use List::Util qw(min max);
use Math::Trig qw(asin acos deg2rad rad2deg);
use Slic3r::Geometry qw(X Y Z triangle_normal scale unscale);
# public
@ -57,6 +58,218 @@ sub BUILD {
}
# Combined layer height, weighing between cusp and Ra factor
sub next_layer_height_area {
my $self = shift;
my ($z, $factor, $min_height, $max_height) = @_;
# factor must be between 0-1, 0 is highest quality, 1 highest print speed
if($factor < 0 or $factor > 1) {
die "Speed / Quality factor must be in the interval [0:1]";
}
my $volume_factor = 0.12263;
my $delta_min = $volume_factor * $min_height * 2;
my $delta_max = $volume_factor * $max_height * 2 + 0.5*$max_height;
my $area_value = $factor * ($delta_max-$delta_min) + $delta_min;
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 $area_h = $self->_facet_area_height($ordered_id, $area_value);
$area_h = max($min_height, min($max_height, $area_h));
$height = $area_h if($area_h < $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 $area_h = $self->_facet_area_height($ordered_id, $area_value);
$area_h = max($min_height, min($max_height, $area_h));
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( $area_h > $z_diff) {
if($area_h < $height) {
Slic3r::debugf "cusp computation, height is reduced from %f", $height;
$height = $area_h;
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, $area_value, $height;
return $height;
}
# Combined layer height, weighing between cusp and Ra factor
sub next_layer_height {
my $self = shift;
my ($z, $factor, $min_height, $max_height) = @_;
# factor must be between 0-1, 0 is highest quality, 1 highest print speed
if($factor < 0 or $factor > 1) {
die "Speed / Quality factor must be in the interval [0:1]";
}
my $cusp_value = $factor * ($max_height-$min_height) + $min_height;
my $ra_value = 2 * $factor * ($max_height-$min_height) + $min_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);
my $ra = $self->_facet_ra_height($ordered_id, $cusp_value);
my $mixed_height = $self->_mixed_layer_height($ordered_id, $cusp_value, $ra_value, $min_height, $max_height, $factor);
$height = $mixed_height if($mixed_height < $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 $mixed_height = $self->_mixed_layer_height($ordered_id, $cusp_value, $ra_value, $min_height, $max_height, $factor);
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( $mixed_height > $z_diff) {
if($mixed_height < $height) {
Slic3r::debugf "cusp computation, height is reduced from %f", $height;
$height = $mixed_height;
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;
}
sub cusp_height {
my $self = shift;
my ($z, $cusp_value, $min_height, $max_height) = @_;
@ -120,24 +333,24 @@ sub cusp_height {
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) {
# # 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 %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;
}
Slic3r::debugf "to z-diff: %f\n", $height;
}
# }
$ordered_id++;
}
@ -150,6 +363,20 @@ sub cusp_height {
return $height;
}
sub _mixed_layer_height {
my ($self, $ordered_id, $cusp_value, $ra_value, $min_height, $max_height, $factor) = @_;
my $cusp = max($min_height, min($max_height, $self->_facet_cusp_height($ordered_id, $cusp_value)));
my $ra = max($min_height, min($max_height, $self->_facet_ra_height($ordered_id, $ra_value)));
my $normal_z = abs($self->normal_z->[$self->ordered_facets->[$ordered_id]->[0]]);
my $phi = asin($normal_z);
print "facet phi: " . rad2deg($phi) . " cusp_value: $cusp_value, ra_value: $ra_value\n";
print "ra: $ra, cusp: $cusp\n\n";
return $factor * $cusp + (1-$factor) * $ra;
}
# computes the cusp height from a given facets normal and the cusp_value
sub _facet_cusp_height {
my $self = shift;
@ -160,6 +387,27 @@ sub _facet_cusp_height {
return $cusp;
}
sub _facet_ra_height {
my $self = shift;
my ($ordered_id, $ra_value) = @_;
my $normal_z = abs($self->normal_z->[$self->ordered_facets->[$ordered_id]->[0]]);
#print "ra_value: $ra_value, facet normal: $normal_z\n";
my $phi = asin($normal_z);
#print "phi: $phi\n";
my $ra = $ra_value * cos($phi);
#print "ra: $ra\n\n";
return $ra;
}
sub _facet_area_height {
my ($self, $ordered_id, $area_value) = @_;
my $normal_z = abs($self->normal_z->[$self->ordered_facets->[$ordered_id]->[0]]);
my $area_h = 1/(2*0.12263/$area_value + ($normal_z/2)/$area_value);
return $area_h;
}
# Returns the distance to the next horizontal facet in Z-dir
# to consider horizontal object features in slice thickness
sub horizontal_facet_distance {

View File

@ -19,6 +19,8 @@ sub new {
my $obj_idx = $self->{obj_idx} = $params{obj_idx};
my $plater = $self->{plater} = $parent;
my $object = $self->{object} = $self->{plater}->{print}->get_object($self->{obj_idx});
$self->{update_spline_control} = 0;
# Initialize 3D toolpaths preview
if ($Slic3r::GUI::have_OpenGL) {
@ -32,26 +34,26 @@ sub new {
$self->{splineControl} = Slic3r::GUI::Plater::SplineControl->new($self, Wx::Size->new(150, 200), $object);
# my $cusp_slider = $self->{cusp_slider} = Wx::Slider->new(
# $self, -1,
# 0, # default
# 0, # min
# # we set max to a bogus non-zero value because the MSW implementation of wxSlider
# # will skip drawing the slider if max <= min:
# 1, # max
# wxDefaultPosition,
# wxDefaultSize,
# wxHORIZONTAL,
# );
my $cusp_slider = $self->{cusp_slider} = Wx::Slider->new(
$self, -1,
0, # default
0, # min
# we set max to a bogus non-zero value because the MSW implementation of wxSlider
# will skip drawing the slider if max <= min:
1, # max
wxDefaultPosition,
wxDefaultSize,
wxHORIZONTAL,
);
#my $cusp_label = $self->{cusp_label} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
# [150,-1], wxALIGN_CENTRE_HORIZONTAL);
#$cusp_label->SetFont($Slic3r::GUI::small_font);
my $cusp_label = $self->{cusp_label} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
[150,-1], wxALIGN_CENTRE_HORIZONTAL);
$cusp_label->SetFont($Slic3r::GUI::small_font);
my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
$right_sizer->Add($self->{splineControl}, 1, wxEXPAND | wxALL, 0);
#$right_sizer->Add($cusp_slider, 0, wxEXPAND | wxALL, 0);
#$right_sizer->Add($cusp_label, 0, wxEXPAND | wxALL, 0);
$right_sizer->Add($cusp_slider, 0, wxEXPAND | wxALL, 0);
$right_sizer->Add($cusp_label, 0, wxEXPAND | wxALL, 0);
$self->{sizer} = Wx::BoxSizer->new(wxHORIZONTAL);
$self->{sizer}->Add($self->{preview3D}, 3, wxEXPAND | wxTOP | wxBOTTOM, 0) if $self->{preview3D};
@ -91,36 +93,41 @@ sub new {
});
# init cusp slider
# if($object->config->adaptive_slicing) {
# my $cusp_value = $object->config->get('cusp_value');
# $cusp_label->SetLabel(sprintf 'Cusp value: %.2f mm', $cusp_value);
# $cusp_slider->SetRange(0, $max_height*100);
# $cusp_slider->SetValue($cusp_value*100);
# }else{
# # disable slider
# $cusp_label->SetLabel("Cusp value: ");
# $cusp_label->Enable(0);
# $cusp_slider->Enable(0);
# }
if($object->config->adaptive_slicing) {
my $cusp_value = $object->config->get('cusp_value');
$cusp_label->SetLabel(sprintf 'Cusp value: %.2f mm', $cusp_value);
$cusp_slider->SetRange(0, 100);
$cusp_slider->SetValue($cusp_value*100);
}else{
# disable slider
$cusp_label->SetLabel("Cusp value: ");
$cusp_label->Enable(0);
$cusp_slider->Enable(0);
}
# EVT_SLIDER($self, $cusp_slider, sub {
# $self->{plater}->pause_background_process;
# my $cusp_value = $cusp_slider->GetValue/100;
# $cusp_label->SetLabel(sprintf 'Cusp value: %.2f mm', $cusp_value);
# my $success = $object->config->set('cusp_value', $cusp_value);
# # trigger re-slicing
# $self->{plater}->stop_background_process;
# $self->{object}->invalidate_step(STEP_SLICE);
# $self->{plater}->schedule_background_process;
# });
EVT_SLIDER($self, $cusp_slider, sub {
$self->{plater}->pause_background_process;
my $cusp_value = $cusp_slider->GetValue/100;
$cusp_label->SetLabel(sprintf 'Cusp value: %.2f mm', $cusp_value);
my $success = $object->config->set('cusp_value', $cusp_value);
$object->layer_height_spline->setCuspValue($cusp_value);
# trigger re-slicing
$self->{plater}->stop_background_process;
$self->{object}->invalidate_step(STEP_SLICE);
$self->{plater}->schedule_background_process;
});
return $self;
}
sub reload_preview {
my ($self) = @_;
#$self->{splineControl}->update;
$self->{splineControl}->update;
$self->{preview3D}->reload_print;
if($self->{object}->layer_count-1 > 0) {
my $top_layer = $self->{object}->get_layer($self->{object}->layer_count-1);
$self->{preview3D}->set_z($top_layer->print_z);
}
}
1;

View File

@ -161,7 +161,9 @@ sub mouse_event {
$self->{heights} = $self->{interactive_heights};
$self->{interactive_heights} = ();
# update spline database
$self->{object}->layer_height_spline->updateLayerHeights($self->{heights});
unless($self->{object}->layer_height_spline->updateLayerHeights($self->{heights})) {
die "Unable to update interpolated layers!\n";
}
$self->{interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers;
}
$self->Refresh;
@ -175,7 +177,9 @@ sub mouse_event {
$self->{heights} = $self->{interactive_heights};
$self->{interactive_heights} = ();
# update spline database
$self->{object}->layer_height_spline->updateLayerHeights($self->{heights});
unless($self->{object}->layer_height_spline->updateLayerHeights($self->{heights})) {
die "Unable to update interpolated layers!\n";
}
$self->{interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers;
}
$self->Refresh;
@ -229,17 +233,19 @@ sub set_size_parameters {
sub update {
my $self = shift;
$self->{original_layers} = $self->{object}->layer_height_spline->getOriginalLayers;
$self->{original_interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers;
$self->{interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers; # Initialize to current values
# initialize height vector
$self->{heights} = ();
$self->{interactive_heights} = ();
my $last_z = 0;
foreach my $z (@{$self->{original_layers}}) {
push (@{$self->{heights}}, $z - $last_z);
$last_z = $z;
if($self->{object}->layer_height_spline->layersUpdated) {
$self->{original_layers} = $self->{object}->layer_height_spline->getOriginalLayers;
$self->{original_interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers;
$self->{interpolated_layers} = $self->{object}->layer_height_spline->getInterpolatedLayers; # Initialize to current values
# initialize height vector
$self->{heights} = ();
$self->{interactive_heights} = ();
my $last_z = 0;
foreach my $z (@{$self->{original_layers}}) {
push (@{$self->{heights}}, $z - $last_z);
$last_z = $z;
}
}
$self->Refresh;
}

View File

@ -152,6 +152,10 @@ sub slice {
if ($self->config->adaptive_slicing) {
$height = 999;
my $cusp_value = $self->config->get_value('cusp_value');
if($self->layer_height_spline->getCuspValue >= 0) {
$self->config->set('cusp_value', $self->layer_height_spline->getCuspValue);
$cusp_value = $self->layer_height_spline->getCuspValue;
}
Slic3r::debugf "\n Slice layer: %d\n", $id;
@ -159,7 +163,7 @@ sub slice {
for my $region_id (0 .. ($self->region_count - 1)) {
# get cusp height
next if(!defined $adaptive_slicing[$region_id]);
my $cusp_height = $adaptive_slicing[$region_id]->cusp_height(scale $slice_z, $cusp_value, $min_height, $max_height);
my $cusp_height = $adaptive_slicing[$region_id]->next_layer_height_area(scale $slice_z, $cusp_value, $min_height, $max_height);
# check for horizontal features and object size
if($self->config->get_value('match_horizontal_surfaces')) {

View File

@ -16,6 +16,9 @@ LayerHeightSpline::LayerHeightSpline(coordf_t object_height)
{
this->_is_valid = false;
this->_update_required = true;
this->_layers_updated = false;
this->_layer_heights_updated = false;
this->_cusp_value = -1;
}
LayerHeightSpline::~LayerHeightSpline()
@ -81,6 +84,9 @@ bool LayerHeightSpline::setLayers(std::vector<coordf_t> layers)
this->_internal_layer_heights.insert(this->_internal_layer_heights.begin(), 0);
this->_internal_layer_heights.push_back(0);
this->_layers_updated = true;
this->_layer_heights_updated = false;
return this->_updateBSpline();
}
@ -104,6 +110,9 @@ bool LayerHeightSpline::updateLayerHeights(std::vector<coordf_t> heights)
result = this->_updateBSpline();
}
this->_layers_updated = false;
this->_layer_heights_updated = true;
return result;
}
@ -118,6 +127,8 @@ void LayerHeightSpline::clear()
delete this->_layer_height_spline;
this->_layer_height_spline = NULL;
this->_is_valid = false;
this->_layers_updated = false;
this->_layer_heights_updated = false;
}

View File

@ -18,17 +18,27 @@ class LayerHeightSpline
void suppressUpdate();
bool setLayers(std::vector<coordf_t> layers);
bool updateLayerHeights(std::vector<coordf_t> heights);
bool layersUpdated() const { return this->_layers_updated; }; // true if the basis set of layers was updated (by the slicing algorithm)
bool layerHeightsUpdated() const { return this->_layer_heights_updated; }; // true if the heights where updated (by the spline control user interface)
void clear();
std::vector<coordf_t> getOriginalLayers() const { return this->_original_layers; };
std::vector<coordf_t> getInterpolatedLayers() const;
const coordf_t getLayerHeightAt(coordf_t height);
void setCuspValue(coordf_t cusp_value) {this->_cusp_value = cusp_value;};
coordf_t getCuspValue() {return this->_cusp_value;};
private:
bool _updateBSpline();
coordf_t _cusp_value;
coordf_t _object_height;
bool _is_valid;
bool _update_required; // this should be always true except if we want to generate new layers from this spline
bool _layers_updated;
bool _layer_heights_updated;
std::vector<coordf_t> _original_layers;
std::vector<coordf_t> _internal_layers;
std::vector<coordf_t> _internal_layer_heights;

View File

@ -15,9 +15,14 @@
%code%{ RETVAL = THIS->setLayers(layers); %};
bool updateLayerHeights(std::vector<double> heights)
%code%{ RETVAL = THIS->updateLayerHeights(heights); %};
bool layersUpdated();
bool layerHeightsUpdated();
void clear();
std::vector<double> getOriginalLayers();
std::vector<double> getInterpolatedLayers();
coordf_t getLayerHeightAt(coordf_t height);
//%code%{ RETVAL = THIS->upper_layer; %};
void setCuspValue(coordf_t cusp_value);
coordf_t getCuspValue();
};