diff --git a/lib/Slic3r/AdaptiveSlicing.pm b/lib/Slic3r/AdaptiveSlicing.pm index eab981dd1..1537edf76 100644 --- a/lib/Slic3r/AdaptiveSlicing.pm +++ b/lib/Slic3r/AdaptiveSlicing.pm @@ -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 { diff --git a/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm b/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm index 9962309c9..f35d45fff 100644 --- a/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm +++ b/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm @@ -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; diff --git a/lib/Slic3r/GUI/Plater/SplineControl.pm b/lib/Slic3r/GUI/Plater/SplineControl.pm index 7bc7cf91f..e46030907 100644 --- a/lib/Slic3r/GUI/Plater/SplineControl.pm +++ b/lib/Slic3r/GUI/Plater/SplineControl.pm @@ -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; } diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 0a1a709e6..5f050af9b 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -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')) { diff --git a/xs/src/libslic3r/LayerHeightSpline.cpp b/xs/src/libslic3r/LayerHeightSpline.cpp index 5b3e59885..c04cf2ce7 100644 --- a/xs/src/libslic3r/LayerHeightSpline.cpp +++ b/xs/src/libslic3r/LayerHeightSpline.cpp @@ -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 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 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; } diff --git a/xs/src/libslic3r/LayerHeightSpline.hpp b/xs/src/libslic3r/LayerHeightSpline.hpp index ea02b93ae..0b618a5ac 100644 --- a/xs/src/libslic3r/LayerHeightSpline.hpp +++ b/xs/src/libslic3r/LayerHeightSpline.hpp @@ -18,17 +18,27 @@ class LayerHeightSpline void suppressUpdate(); bool setLayers(std::vector layers); bool updateLayerHeights(std::vector 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 getOriginalLayers() const { return this->_original_layers; }; std::vector 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 _original_layers; std::vector _internal_layers; std::vector _internal_layer_heights; diff --git a/xs/xsp/LayerHeightSpline.xsp b/xs/xsp/LayerHeightSpline.xsp index ad5c5e58e..3f915230e 100644 --- a/xs/xsp/LayerHeightSpline.xsp +++ b/xs/xsp/LayerHeightSpline.xsp @@ -15,9 +15,14 @@ %code%{ RETVAL = THIS->setLayers(layers); %}; bool updateLayerHeights(std::vector heights) %code%{ RETVAL = THIS->updateLayerHeights(heights); %}; + bool layersUpdated(); + bool layerHeightsUpdated(); void clear(); std::vector getOriginalLayers(); std::vector getInterpolatedLayers(); coordf_t getLayerHeightAt(coordf_t height); //%code%{ RETVAL = THIS->upper_layer; %}; + + void setCuspValue(coordf_t cusp_value); + coordf_t getCuspValue(); };