From a3867b0be810838298c5177d1bdc143f72b91010 Mon Sep 17 00:00:00 2001 From: Florens Wasserfall Date: Thu, 26 Jan 2017 09:22:04 +0100 Subject: [PATCH] Integration of spline based layer height postprocessing --- lib/Slic3r/GUI/Plater.pm | 2 +- lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm | 22 +- lib/Slic3r/Print/Object.pm | 222 +++++++++++--------- xs/src/libslic3r/Print.hpp | 4 +- xs/src/libslic3r/PrintObject.cpp | 3 +- xs/xsp/Print.xsp | 2 + 6 files changed, 143 insertions(+), 112 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index b4fa04762..b28304bab 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -149,9 +149,9 @@ sub new { $self->{htoolbar}->AddTool(TB_SCALE, "Scale…", Wx::Bitmap->new($Slic3r::var->("arrow_out.png"), wxBITMAP_TYPE_PNG), ''); $self->{htoolbar}->AddTool(TB_SPLIT, "Split", Wx::Bitmap->new($Slic3r::var->("shape_ungroup.png"), wxBITMAP_TYPE_PNG), ''); $self->{htoolbar}->AddTool(TB_CUT, "Cut…", Wx::Bitmap->new($Slic3r::var->("package.png"), wxBITMAP_TYPE_PNG), ''); - $self->{htoolbar}->AddTool(TB_LAYERS, "Layers…", Wx::Bitmap->new($Slic3r::var->("cog.png"), wxBITMAP_TYPE_PNG), ''); $self->{htoolbar}->AddSeparator; $self->{htoolbar}->AddTool(TB_SETTINGS, "Settings…", Wx::Bitmap->new($Slic3r::var->("cog.png"), wxBITMAP_TYPE_PNG), ''); + $self->{htoolbar}->AddTool(TB_LAYERS, "Layers…", Wx::Bitmap->new($Slic3r::var->("layers.png"), wxBITMAP_TYPE_PNG), ''); } else { my %tbar_buttons = ( add => "Add…", diff --git a/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm b/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm index 6e8652aae..295508e3f 100644 --- a/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm +++ b/lib/Slic3r/GUI/Plater/ObjectLayersDialog.pm @@ -4,6 +4,7 @@ use warnings; use utf8; use Slic3r::Geometry qw(PI X scale unscale); +use Slic3r::Print::State ':steps'; use List::Util qw(min max sum first); use Wx qw(wxTheApp :dialog :id :misc :sizer wxTAB_TRAVERSAL); use Wx::Event qw(EVT_CLOSE EVT_BUTTON); @@ -14,12 +15,11 @@ sub new { my ($parent, %params) = @_; my $self = $class->SUPER::new($parent, -1, $params{object}->name, wxDefaultPosition, [500,500], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); $self->{model_object} = $params{model_object}; - - my $model_object = $self->{model_object} = $params{model_object}; 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}); + # Initialize 3D toolpaths preview if ($Slic3r::GUI::have_OpenGL) { $self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self, $plater->{print}); @@ -32,8 +32,8 @@ sub new { $self->{preview3D}->load_print; $self->{preview3D}->canvas->zoom_to_volumes; } - - $self->{splineControl} = Slic3r::GUI::Plater::SplineControl->new($self, Wx::Size->new(100, 200)); + + $self->{splineControl} = Slic3r::GUI::Plater::SplineControl->new($self, Wx::Size->new(200, 200), $object); my $right_sizer = Wx::BoxSizer->new(wxVERTICAL); $right_sizer->Add($self->{splineControl}, 1, wxEXPAND | wxALL, 0); @@ -46,9 +46,7 @@ sub new { $self->SetSize([800, 600]); $self->SetMinSize($self->GetSize); - # init spline control values - my $object = $self->{plater}->{print}->get_object($self->{obj_idx}); - + # init spline control values # determine min and max layer height from perimeter extruder capabilities. my %extruders; for my $region_id (0 .. ($object->region_count - 1)) { @@ -62,10 +60,12 @@ sub new { $self->{splineControl}->set_size_parameters($min_height, $max_height, unscale($object->size->z)); - # get array of current Z coordinates for selected object - my @layer_heights = map $_->print_z, @{$object->layers}; - $self->{splineControl}->set_layer_points(@layer_heights); + $self->{splineControl}->on_layer_update(sub { + # trigger re-slicing + $self->{object}->invalidate_step(STEP_SLICE); + $self->{plater}->start_background_process; + }); return $self; } diff --git a/lib/Slic3r/Print/Object.pm b/lib/Slic3r/Print/Object.pm index 66e156ddc..bef7dbf84 100644 --- a/lib/Slic3r/Print/Object.pm +++ b/lib/Slic3r/Print/Object.pm @@ -89,118 +89,144 @@ sub slice { my $slice_z = 0; my $height = 0; my $cusp_height = 0; + my @layers = (); - # 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; - } - } - - if (defined $mesh) { - $adaptive_slicing[$region_id] = Slic3r::AdaptiveSlicing->new( - mesh => $mesh, - size => $self->size->z - ); - } - } - - # 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) { - $height = 999; - 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 - 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); - - # check for horizontal features and object size - if($self->config->get_value('match_horizontal_surfaces')) { - my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height); - if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) { - Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist; - # can we shrink the current layer a bit? - if($cusp_height-($min_height-$horizontal_dist) > $min_height) { - # yes we can - $cusp_height = $cusp_height-($min_height-$horizontal_dist); - Slic3r::debugf "Shrink layer height to %f\n", $cusp_height; - }else{ - # no, current layer would become too thin - $cusp_height = $cusp_height+$horizontal_dist; - Slic3r::debugf "Widen layer height to %f\n", $cusp_height; - } - } - } + if(!$self->layer_height_spline->updateRequired) { # layer heights are already generated, just update layers from spline + @layers = @{$self->layer_height_spline->getInterpolatedLayers}; + }else{ # create new set of layers + # 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; + } + } - $height = ($id == 0) - ? $self->config->get_value('first_layer_height') - : min($cusp_height, $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}) { - $height = $range->[2]; - - # if user set custom height to zero we should just skip the range and resume slicing over it - if ($height == 0) { - $slice_z += $range->[1] - $range->[0]; - next; + if (defined $mesh) { + $adaptive_slicing[$region_id] = Slic3r::AdaptiveSlicing->new( + mesh => $mesh, + size => $self->size->z + ); + } } - } + + # 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) < $max_z) { + + if ($self->config->adaptive_slicing) { + $height = 999; + 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 + 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); + + # check for horizontal features and object size + if($self->config->get_value('match_horizontal_surfaces')) { + my $horizontal_dist = $adaptive_slicing[$region_id]->horizontal_facet_distance(scale $slice_z+$cusp_height, $min_height); + if(($horizontal_dist < $min_height) && ($horizontal_dist > 0)) { + Slic3r::debugf "Horizontal feature ahead, distance: %f\n", $horizontal_dist; + # can we shrink the current layer a bit? + if($cusp_height-($min_height-$horizontal_dist) > $min_height) { + # yes we can + $cusp_height = $cusp_height-($min_height-$horizontal_dist); + Slic3r::debugf "Shrink layer height to %f\n", $cusp_height; + }else{ + # no, current layer would become too thin + $cusp_height = $cusp_height+$horizontal_dist; + Slic3r::debugf "Widen layer height to %f\n", $cusp_height; + } + } + } + + $height = ($id == 0) + ? $self->config->get_value('first_layer_height') + : min($cusp_height, $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}) { + $height = $range->[2]; - if ($first_object_layer_height != -1 && !@{$self->layers}) { - $height = $first_object_layer_height; - $print_z += ($first_object_layer_distance - $height); + # if user set custom height to zero we should just skip the range and resume slicing over it + if ($height == 0) { + $slice_z += $range->[1] - $range->[0]; + next; + } + } + + # set first layer height if raft is active + if ($first_object_layer_height != -1 && !@layers) { + $height = $first_object_layer_height; + #$print_z += ($first_object_layer_distance - $height); + } + + $slice_z += $height; + $id++; + + # collect layers for spline smoothing + push (@layers, $slice_z); } - + $self->layer_height_spline->setLayers(\@layers); + if ($self->config->adaptive_slicing) { # smoothing after adaptive algorithm + $self->layer_height_spline->setLayers($self->layer_height_spline->getInterpolatedLayers); + } + } + + $id = 0; + if ($self->config->raft_layers > 0) { + $id = $self->config->raft_layers; + } + + # generate layer objects + $slice_z = 0; + foreach my $z (@layers) { + $height = $z - $slice_z; $print_z += $height; $slice_z += $height/2; - - ### Slic3r::debugf "Layer %d: height = %s; slice_z = %s; print_z = %s\n", $id, $height, $slice_z, $print_z; - + + Slic3r::debugf "Layer %d: height = %s; slice_z = %s; print_z = %s\n", $id, $height, $slice_z, $print_z; + $self->add_layer($id, $height, $print_z, $slice_z); if ($self->layer_count >= 2) { my $lc = $self->layer_count; $self->get_layer($lc - 2)->set_upper_layer($self->get_layer($lc - 1)); $self->get_layer($lc - 1)->set_lower_layer($self->get_layer($lc - 2)); } + $id++; - $slice_z += $height/2; # add the other half layer } } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index fcf6d0a79..69b927b1b 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -12,7 +12,7 @@ #include "Layer.hpp" #include "Model.hpp" #include "PlaceholderParser.hpp" - +#include "LayerHeightSpline.hpp" namespace Slic3r { @@ -83,6 +83,8 @@ class PrintObject PrintObjectConfig config; t_layer_height_ranges layer_height_ranges; + LayerHeightSpline layer_height_spline; + // this is set to true when LayerRegion->slices is split in top/internal/bottom // so that next call to make_perimeters() performs a union() before computing loops bool typed_slices; diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index eb744985e..5fedcabf3 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -8,7 +8,8 @@ namespace Slic3r { PrintObject::PrintObject(Print* print, ModelObject* model_object, const BoundingBoxf3 &modobj_bbox) : typed_slices(false), _print(print), - _model_object(model_object) + _model_object(model_object), + layer_height_spline(modobj_bbox.size().z) { // Compute the translation to be applied to our meshes so that we work with smaller coordinates { diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 27d970a5b..a5369cf54 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -58,6 +58,8 @@ _constant() Points copies(); t_layer_height_ranges layer_height_ranges() %code%{ RETVAL = THIS->layer_height_ranges; %}; + Ref layer_height_spline() + %code%{ RETVAL = &THIS->layer_height_spline; %}; Ref size() %code%{ RETVAL = &THIS->size; %}; Clone bounding_box();