diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 970c754f7e..c1df8b30ed 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -426,7 +426,7 @@ sub quick_slice { if ($params{reslice}) { $output_file = $qs_last_output_file if defined $qs_last_output_file; } elsif ($params{save_as}) { - $output_file = $sprint->expanded_output_filepath; + $output_file = $sprint->output_filepath; $output_file =~ s/\.gcode$/.svg/i if $params{export_svg}; my $dlg = Wx::FileDialog->new($self, 'Save ' . ($params{export_svg} ? 'SVG' : 'G-code') . ' file as:', wxTheApp->output_path(dirname($output_file)), diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 3243f9e706..427b89f615 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -251,7 +251,7 @@ sub new { $self->{print_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir()); }); EVT_BUTTON($self, $self->{btn_send_gcode}, sub { - my $filename = basename($self->{print}->expanded_output_filepath($main::opt{output})); + my $filename = basename($self->{print}->output_filepath($main::opt{output})); $filename = Wx::GetTextFromUser("Save to printer with the following name:", "OctoPrint", $filename, $self); @@ -1218,9 +1218,9 @@ sub export_gcode { # select output file if ($output_file) { - $self->{export_gcode_output_file} = $self->{print}->expanded_output_filepath($output_file); + $self->{export_gcode_output_file} = $self->{print}->output_filepath($output_file); } else { - my $default_output_file = $self->{print}->expanded_output_filepath($main::opt{output}); + my $default_output_file = $self->{print}->output_filepath($main::opt{output}); my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)), basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); if ($dlg->ShowModal != wxID_OK) { @@ -1477,7 +1477,7 @@ sub _get_export_file { my $output_file = $main::opt{output}; { - $output_file = $self->{print}->expanded_output_filepath($output_file); + $output_file = $self->{print}->output_filepath($output_file); $output_file =~ s/\.gcode$/$suffix/i; my $dlg = Wx::FileDialog->new($self, "Save $format file as:", dirname($output_file), basename($output_file), &Slic3r::GUI::MODEL_WILDCARD, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 2bb298c192..6be0b058bd 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -77,7 +77,7 @@ sub export_gcode { $self->process; # output everything to a G-code file - my $output_file = $self->expanded_output_filepath($params{output_file}); + my $output_file = $self->output_filepath($params{output_file} // ''); $self->status_cb->(90, "Exporting G-code" . ($output_file ? " to $output_file" : "")); { @@ -128,7 +128,7 @@ sub export_svg { my $fh = $params{output_fh}; if (!$fh) { - my $output_file = $self->expanded_output_filepath($params{output_file}); + my $output_file = $self->output_filepath($params{output_file}); $output_file =~ s/\.gcode$/.svg/i; Slic3r::open(\$fh, ">", $output_file) or die "Failed to open $output_file for writing\n"; print "Exporting to $output_file..." unless $params{quiet}; @@ -354,45 +354,6 @@ sub make_brim { $self->_make_brim; } -# this method will return the supplied input file path after expanding its -# format variables with their values -sub expanded_output_filepath { - my $self = shift; - my ($path) = @_; - - return undef if !@{$self->objects}; - my $input_file = first { defined $_ } map $_->model_object->input_file, @{$self->objects}; - return undef if !defined $input_file; - - my $filename = my $filename_base = basename($input_file); - $filename_base =~ s/\.[^.]+$//; # without suffix - - # set filename in placeholder parser so that it's available also in custom G-code - $self->placeholder_parser->set(input_filename => $filename); - $self->placeholder_parser->set(input_filename_base => $filename_base); - - # set other variables from model object - $self->placeholder_parser->set_multiple( - scale => [ map $_->model_object->instances->[0]->scaling_factor * 100 . "%", @{$self->objects} ], - ); - - if ($path && -d $path) { - # if output path is an existing directory, we take that and append - # the specified filename format - $path = File::Spec->join($path, $self->config->output_filename_format); - } elsif (!$path) { - # if no explicit output file was defined, we take the input - # file directory and append the specified filename format - $path = (fileparse($input_file))[1] . $self->config->output_filename_format; - } else { - # path is a full path to a file so we use it as it is - } - - # make sure we use an up-to-date timestamp - $self->placeholder_parser->update_timestamp; - return $self->placeholder_parser->process($path); -} - # Wrapper around the C++ Slic3r::Print::validate() # to produce a Perl exception without a hang-up on some Strawberry perls. sub validate diff --git a/lib/Slic3r/Print/Simple.pm b/lib/Slic3r/Print/Simple.pm index 3771bfe4a2..4fe3eb820b 100644 --- a/lib/Slic3r/Print/Simple.pm +++ b/lib/Slic3r/Print/Simple.pm @@ -13,7 +13,7 @@ use Slic3r::Geometry qw(X Y); has '_print' => ( is => 'ro', default => sub { Slic3r::Print->new }, - handles => [qw(apply_config extruders expanded_output_filepath + handles => [qw(apply_config extruders output_filepath total_used_filament total_extruded_volume placeholder_parser process)], ); diff --git a/t/custom_gcode.t b/t/custom_gcode.t index d99b6785f3..653bb26aea 100644 --- a/t/custom_gcode.t +++ b/t/custom_gcode.t @@ -60,7 +60,7 @@ use Slic3r::Test; $config->set('start_gcode', "TRAVEL:[travel_speed] HEIGHT:[layer_height]\n"); my $print = Slic3r::Test::init_print('20mm_cube', config => $config); - my $output_file = $print->print->expanded_output_filepath; + my $output_file = $print->print->output_filepath; my ($t, $h) = map $config->$_, qw(travel_speed layer_height); ok $output_file =~ /ts_${t}_/, 'print config options are replaced in output filename'; ok $output_file =~ /lh_$h\./, 'region config options are replaced in output filename'; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index 6fc7e4569d..8cff8dc417 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -6,6 +6,8 @@ #include "Geometry.hpp" #include "SupportMaterial.hpp" #include +#include +#include namespace Slic3r { @@ -973,4 +975,57 @@ Print::auto_assign_extruders(ModelObject* model_object) const } } +std::string +Print::output_filename() const +{ + PlaceholderParser pp = this->placeholder_parser; + + // get input file name + std::string input_file; + FOREACH_OBJECT(this, object) { + input_file = (*object)->model_object()->input_file; + if (!input_file.empty()) break; + } + + // get basename with and without suffix and set placeholders + const std::string input_basename = boost::filesystem::path(input_file).filename().string(); + pp.set("input_filename", input_basename); + const std::string input_basename_base = input_basename.substr(0, input_basename.find_last_of(".")); + pp.set("input_filename_base", input_basename_base); + + // set other variables from model object + { + std::vector v_scale; + FOREACH_OBJECT(this, object) + v_scale.push_back( boost::lexical_cast((*object)->model_object()->instances[0]->scaling_factor*100) + "%" ); + pp.set("scale", v_scale); + } + + pp.update_timestamp(); + return pp.process(this->config.output_filename_format.value); +} + +std::string +Print::output_filepath(const std::string &path) const +{ + // if we were supplied no path, generate an automatic one based on our first object's input file + if (path.empty()) { + // get the first input file name + std::string input_file; + FOREACH_OBJECT(this, object) { + input_file = (*object)->model_object()->input_file; + if (!input_file.empty()) break; + } + return (boost::filesystem::path(input_file).parent_path() / this->output_filename()).string(); + } + + // if we were supplied a directory, use it and append our automatically generated filename + boost::filesystem::path p(path); + if (boost::filesystem::is_directory(p)) + return (p / this->output_filename()).string(); + + // if we were supplied a file which is not a directory, use it + return path; +} + } diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 6cd24ef794..a147723793 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -212,6 +212,8 @@ class Print double max_allowed_layer_height() const; bool has_support_material() const; void auto_assign_extruders(ModelObject* model_object) const; + std::string output_filename() const; + std::string output_filepath(const std::string &path) const; private: void clear_regions(); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 3992a0aff5..9da32d6749 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -215,6 +215,8 @@ _constant() double max_allowed_layer_height() const; bool has_support_material() const; void auto_assign_extruders(ModelObject* model_object); + std::string output_filename(); + std::string output_filepath(std::string path = ""); void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig* config)