diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index ff82b57b0..ec74a4f7f 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -44,6 +44,7 @@ our $notes = ''; # output options our $output_filename_format = '[input_filename_base].gcode'; +our $post_process = []; # printer options our $nozzle_diameter = 0.5; diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index b169af3af..8ec3c0def 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -254,6 +254,16 @@ our $Options = { serialize => sub { join '\n', split /\R+/, $_[0] }, deserialize => sub { join "\n", split /\\n/, $_[0] }, }, + 'post_process' => { + label => 'Post-processing scripts', + cli => 'post-process=s@', + type => 's@', + multiline => 1, + width => 350, + height => 60, + serialize => sub { join '; ', @{$_[0]} }, + deserialize => sub { [ split /\s*;\s*/, $_[0] ] }, + }, # retraction options 'retract_length' => { @@ -352,6 +362,14 @@ sub serialize { : get($opt_key); } +sub deserialize { + my $class = @_ == 3 ? shift : undef; + my ($opt_key, $value) = @_; + return $Options->{$opt_key}{deserialize} + ? set($opt_key, $Options->{$opt_key}{deserialize}->($value)) + : set($opt_key, $value); +} + sub save { my $class = shift; my ($file) = @_; diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index e03a50538..f141d6cdc 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -45,7 +45,7 @@ sub make_fill { $_->layer($layer) for values %{$self->fillers}; - printf "Filling layer %d:\n", $layer->id; + Slic3r::debugf "Filling layer %d:\n", $layer->id; # merge overlapping surfaces my @surfaces = (); diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 1fec31136..0f529b772 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -33,7 +33,7 @@ sub new { $bold_font->SetPointSize($label->GetFont()->GetPointSize()); $label->SetFont($bold_font) if $opt->{important}; my $field; - if ($opt->{type} =~ /^(i|f|s)$/) { + if ($opt->{type} =~ /^(i|f|s|s@)$/) { my $style = 0; my $size = Wx::wxDefaultSize; @@ -42,10 +42,12 @@ sub new { $size = Wx::Size->new($opt->{width} || -1, $opt->{height} || -1); } - $field = Wx::TextCtrl->new($parent, -1, Slic3r::Config->get($opt_key), + my ($get, $set) = $opt->{type} eq 's@' ? qw(serialize deserialize) : qw(get set); + + $field = Wx::TextCtrl->new($parent, -1, Slic3r::Config->$get($opt_key), Wx::wxDefaultPosition, $size, $style); - EVT_TEXT($parent, $field, sub { Slic3r::Config->set($opt_key, $field->GetValue) }); - push @reload_callbacks, sub { $field->SetValue(Slic3r::Config->get($opt_key)) }; + EVT_TEXT($parent, $field, sub { Slic3r::Config->$set($opt_key, $field->GetValue) }); + push @reload_callbacks, sub { $field->SetValue(Slic3r::Config->$get($opt_key)) }; } elsif ($opt->{type} eq 'bool') { $field = Wx::CheckBox->new($parent, -1, ""); $field->SetValue(Slic3r::Config->get($opt_key)); diff --git a/lib/Slic3r/GUI/SkeinPanel.pm b/lib/Slic3r/GUI/SkeinPanel.pm index 2ad87521b..2308cba66 100644 --- a/lib/Slic3r/GUI/SkeinPanel.pm +++ b/lib/Slic3r/GUI/SkeinPanel.pm @@ -57,7 +57,7 @@ sub new { }, gcode => { title => 'Custom GCODE', - options => [qw(start_gcode end_gcode gcode_comments)], + options => [qw(start_gcode end_gcode gcode_comments post_process)], }, extrusion => { title => 'Extrusion', @@ -181,7 +181,7 @@ sub do_slice { status_cb => sub { my ($percent, $message) = @_; if (&Wx::wxVERSION_STRING =~ / 2\.(8\.|9\.[2-9])/) { - $process_dialog->Update($percent, $message); + $process_dialog->Update($percent, "$message..."); } }, ); diff --git a/lib/Slic3r/Perimeter.pm b/lib/Slic3r/Perimeter.pm index b88177f5a..b5e1d4379 100644 --- a/lib/Slic3r/Perimeter.pm +++ b/lib/Slic3r/Perimeter.pm @@ -9,7 +9,7 @@ use XXX; sub make_perimeter { my $self = shift; my ($layer) = @_; - printf "Making perimeter for layer %d\n", $layer->id; + Slic3r::debugf "Making perimeters for layer %d\n", $layer->id; # at least one perimeter is required die "Can't slice object with no perimeters!\n" diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 21d2c1532..03da5dd2f 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -45,9 +45,8 @@ sub new_from_mesh { # (we might have created it because of the $max_layer = ... + 1 code below) pop @{$print->layers} if !@{$print->layers->[-1]->surfaces} && !@{$print->layers->[-1]->lines}; - print "\n==> PROCESSING SLICES:\n"; foreach my $layer (@{ $print->layers }) { - printf "Making surfaces for layer %d:\n", $layer->id; + Slic3r::debugf "Making surfaces for layer %d:\n", $layer->id; # layer currently has many lines representing intersections of # model facets with the layer plane. there may also be lines @@ -517,8 +516,6 @@ sub export_gcode { my $self = shift; my ($file) = @_; - printf "Exporting GCODE file...\n"; - # open output gcode file open my $fh, ">", $file or die "Failed to open $file for writing\n"; diff --git a/lib/Slic3r/Skein.pm b/lib/Slic3r/Skein.pm index ee5b61cba..331190c8b 100644 --- a/lib/Slic3r/Skein.pm +++ b/lib/Slic3r/Skein.pm @@ -23,7 +23,7 @@ sub go { # skein the STL into layers # each layer has surfaces with holes - $self->status_cb->(10, "Processing triangulated mesh..."); + $self->status_cb->(10, "Processing triangulated mesh"); my $print; { my $mesh = $self->input_file =~ /\.stl$/i @@ -38,7 +38,7 @@ sub go { # make perimeters # this will add a set of extrusion loops to each layer # as well as generate infill boundaries - $self->status_cb->(20, "Generating perimeters..."); + $self->status_cb->(20, "Generating perimeters"); { my $perimeter_maker = Slic3r::Perimeter->new; $perimeter_maker->make_perimeter($_) for @{$print->layers}; @@ -46,42 +46,42 @@ sub go { # this will clip $layer->surfaces to the infill boundaries # and split them in top/bottom/internal surfaces; - $self->status_cb->(30, "Detecting solid surfaces..."); + $self->status_cb->(30, "Detecting solid surfaces"); $print->detect_surfaces_type; # decide what surfaces are to be filled - $self->status_cb->(35, "Preparing infill surfaces..."); + $self->status_cb->(35, "Preparing infill surfaces"); $_->prepare_fill_surfaces for @{$print->layers}; # this will remove unprintable surfaces # (those that are too tight for extrusion) - $self->status_cb->(40, "Cleaning up..."); + $self->status_cb->(40, "Cleaning up"); $_->remove_small_surfaces for @{$print->layers}; # this will detect bridges and reverse bridges # and rearrange top/bottom/internal surfaces - $self->status_cb->(45, "Detect bridges..."); + $self->status_cb->(45, "Detect bridges"); $_->process_bridges for @{$print->layers}; # this will remove unprintable perimeter loops # (those that are too tight for extrusion) - $self->status_cb->(50, "Cleaning up the perimeters..."); + $self->status_cb->(50, "Cleaning up the perimeters"); $_->remove_small_perimeters for @{$print->layers}; # detect which fill surfaces are near external layers # they will be split in internal and internal-solid surfaces - $self->status_cb->(60, "Generating horizontal shells..."); + $self->status_cb->(60, "Generating horizontal shells"); $print->discover_horizontal_shells; # free memory @{$_->surfaces} = () for @{$print->layers}; # combine fill surfaces to honor the "infill every N layers" option - $self->status_cb->(70, "Combining infill..."); + $self->status_cb->(70, "Combining infill"); $print->infill_every_layers; # this will generate extrusion paths for each layer - $self->status_cb->(80, "Infilling layers..."); + $self->status_cb->(80, "Infilling layers"); { my $fill_maker = Slic3r::Fill->new('print' => $print); @@ -116,17 +116,27 @@ sub go { # generate support material if ($Slic3r::support_material) { - $self->status_cb->(85, "Generating support material..."); + $self->status_cb->(85, "Generating support material"); $print->generate_support_material; } # make skirt - $self->status_cb->(88, "Generating skirt..."); + $self->status_cb->(88, "Generating skirt"); $print->extrude_skirt; # output everything to a GCODE file - $self->status_cb->(90, "Exporting GCODE..."); - $print->export_gcode($self->expanded_output_filepath); + $self->status_cb->(90, "Exporting GCODE"); + my $output_file = $self->expanded_output_filepath; + $print->export_gcode($output_file); + + # run post-processing scripts + if (@$Slic3r::post_process) { + $self->status_cb->(95, "Running post-processing scripts"); + for (@$Slic3r::post_process) { + Slic3r::debugf " '%s' '%s'\n", $_, $output_file; + system($_, $output_file); + } + } # output some statistics $self->processing_time(tv_interval($t0)); diff --git a/slic3r.pl b/slic3r.pl index fd1a9fdbc..b4e6fed4f 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -79,6 +79,10 @@ if ($ARGV[0]) { my $skein = Slic3r::Skein->new( input_file => $input_file, output_file => $opt{output}, + status_cb => sub { + my ($percent, $message) = @_; + printf "=> $message\n"; + }, ); $skein->go; @@ -108,6 +112,8 @@ Usage: slic3r.pl [ OPTIONS ] file.stl Output file name format; all config options enclosed in brackets will be replaced by their values, as well as [input_filename_base] and [input_filename] (default: $Slic3r::output_filename_format) + --post-process Generated G-code will be processed with the supplied script; + call this more than once to process through multiple scripts. Printer options: --nozzle-diameter Diameter of nozzle in mm (default: $Slic3r::nozzle_diameter) diff --git a/utils/post-processing/z-every-line.pl b/utils/post-processing/z-every-line.pl index 5f9d311b6..49d5f4502 100755 --- a/utils/post-processing/z-every-line.pl +++ b/utils/post-processing/z-every-line.pl @@ -1,11 +1,12 @@ -#!/usr/bin/perl +#!/usr/bin/perl -i use strict; +use warnings; my $z = 0; # read stdin and any/all files passed as parameters one line at a time -for (<>) { +while (<>) { # if we find a Z word, save it $z = $1 if /Z(\d+(\.\d+)?)/;