diff --git a/README.md b/README.md index 4d9f90b01..40c22b98a 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,8 @@ The author of the Silk icon set is Mark James. --gui Forces the GUI launch instead of command line slicing (if you supply a model file, it will be loaded into the plater) --no-plater Disable the plater tab + --no-gui Forces the command line slicing instead of gui. + This takes precedence over --gui if both are present. --autosave Automatically export current configuration to the specified file Output options: diff --git a/doc/How_to_build_Slic3r.txt b/doc/How_to_build_Slic3r.txt index 0c5c709b0..a1d112981 100644 --- a/doc/How_to_build_Slic3r.txt +++ b/doc/How_to_build_Slic3r.txt @@ -1,6 +1,6 @@ -How to build Slic3r on Mac OS X 10.7 Lion 64bit +How to build Slic3r on Mac OS X 10.9 Maveric --------------------------------------------- -Vojtech Bubnik, 2016-04-26 +Vojtech Bubnik, 2017-12-12 1) Install Mac OS X 10.7 Lion 64 bit with X Code @@ -55,6 +55,9 @@ brew install boost --universal Install dylibbundler tool. The dylibbundler tool serves to collect dependent dynamic libraries and fix their linkage. Execute brew install dylibbundler +Install cmake +brew install cmake + 3) Install perl --------------- @@ -62,18 +65,31 @@ We don't want to distribute perl pre-installed on the Mac OS box. First, the sys http://perlbrew.pl/ First install perlbrew -\curl -L http://install.perlbrew.pl | bash +curl -L http://install.perlbrew.pl | bash Then compile the newest perl with the rellocatable @INC path and with multithreading enabled, execute following line: -perlbrew install --threads -Duserelocatableinc --switch perl-5.22.0 +perlbrew install --threads -Duserelocatableinc --switch perl-5.26.1 The --switch parameter switches the active perl to the currently compiled one. Available perl versions could be listed by calling perlbrew available +Switch to the newly compiled perl +perl5/perlbrew/bin/perlbrew switch perl-5.26.1 +Install cpanm +perlbrew install-cpanm Initialize CPAN, install PAR and PAR::Packer modules execute cpan command, from the cpan prompt, run install App::cpanminus +install ExtUtils::CppGuess +install ExtUtils::Typemaps +install ExtUtils::Typemaps::Basic install PAR install PAR::Packer +install Module::Build +install Module::Pluggable +install Module::Runtime +install Moo +install Test::Pod +install Test::Pod::Coverage quit 4) Download and install Slic3r @@ -92,6 +108,21 @@ to have the model sliced. 5) Download and compile the GUI libraries needed to execute Slic3r in GUI mode ------------------------------------------------------------------------------ +Building the Perl Alien-Wx containing a wxWidgets library: +We use wxWidgets-3.0.3. +patch wxWidgets-3.0.3//src/osx/cocoa/textctrl.mm , see https://github.com/prusa3d/Slic3r/issues/600 +perl -I. Build.PL --wxWidgets-extraflags="--with-osx_cocoa --with-macosx-version-min=10.9 --with-macosx-sdk=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.9.sdk --with-libjpeg=builtin --with-libpng=builtin --with-regex=builtin --with-libtiff=builtin --with-zlib=builtin --with-expat=builtin --with-opengl" +perl -I. Build +perl -I. Build test +perl -I. Build + +Building the Perl Wx package: +cpan install Wx + +Building the Perl OpenGL package: +OpenGL needs to be patched to support MSAA, see the Windows patch. + + For the current Slic3r 1.2.30 code base, set the environment variable SLIC3R_STATIC to link a static version of the boost library: export SLIC3R_STATIC=1 @@ -271,3 +302,14 @@ Debugging the C++ code works fine using the latest Eclipse for C++ and the gdb o It is yet a bit more complicated. The Strawberry MINGW is compiled for a different C++ exception passing model (SJLJ) than the other MINGWs, so one cannot simply combine MINGWs on Windows. For an unknown reason the nice debugger of the QT Creator hangs when debugging the C++ compiled by the Strawberry MINGW. Mabe it is because of the different exception passing models. And to disable optimization of the C/C++ code, one has to manually modify Config_heavy.pl in the Perl central installation. The SLIC3R_DEBUG environment variable did not override all the -O2 and -O3 flags that the perl build adds the gcc execution line. + +---------------------------------------------------------------------- + +Building boost. + +One may save compilation time by compiling just what Slic3r needs. +./bootstrap.sh --with-libraries=system,filesystem,thread,log,locale,regex +The -fPIC flag is required on Linux to make the static libraries rellocatable, +so they could be embedded into a shared library. +./bjam -a link=static variant=release threading=multi cxxflags=-fPIC cflags=-fPIC +To install on Linux to /usr/local/..., run the line above with the additional install keyword and with sudo. diff --git a/lib/Slic3r.pm b/lib/Slic3r.pm index 53b2e3663..66039ddf0 100644 --- a/lib/Slic3r.pm +++ b/lib/Slic3r.pm @@ -41,7 +41,8 @@ warn "Running Slic3r under Perl 5.16 is neither supported nor recommended\n" use FindBin; # Let the XS module know where the GUI resources reside. -set_var_dir(decode_path($FindBin::Bin) . "/var"); +set_resources_dir(decode_path($FindBin::Bin) . (($^O eq 'darwin') ? '/../Resources' : '/resources')); +set_var_dir(resources_dir() . "/icons"); use Moo 1.003001; @@ -79,6 +80,10 @@ my $paused = 0; $Slic3r::loglevel = (defined($ENV{'SLIC3R_LOGLEVEL'}) && $ENV{'SLIC3R_LOGLEVEL'} =~ /^[1-9]/) ? $ENV{'SLIC3R_LOGLEVEL'} : 0; set_logging_level($Slic3r::loglevel); +# Let the palceholder parser evaluate one expression to initialize its local static macro_processor +# class instance in a thread safe manner. +Slic3r::GCode::PlaceholderParser->new->evaluate_boolean_expression('1==1'); + sub spawn_thread { my ($cb) = @_; @_ = (); diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 2dc560cad..5d6d8e4a6 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -70,7 +70,7 @@ our $grey = Wx::Colour->new(200,200,200); sub OnInit { my ($self) = @_; - $self->SetAppName('Slic3r'); + $self->SetAppName('Slic3rPE'); $self->SetAppDisplayName('Slic3r Prusa Edition'); Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION; @@ -79,6 +79,7 @@ sub OnInit { # Windows: "C:\Users\username\AppData\Roaming\Slic3r" or "C:\Documents and Settings\username\Application Data\Slic3r" # Mac: "~/Library/Application Support/Slic3r" Slic3r::set_data_dir($datadir || Wx::StandardPaths::Get->GetUserDataDir); + Slic3r::GUI::set_wxapp($self); $self->{notifier} = Slic3r::GUI::Notifier->new; $self->{app_config} = Slic3r::GUI::AppConfig->new; @@ -99,29 +100,22 @@ sub OnInit { # Suppress the '- default -' presets. $self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0); - eval { - $self->{preset_bundle}->load_presets(Slic3r::data_dir); - }; + eval { $self->{preset_bundle}->load_presets }; if ($@) { warn $@ . "\n"; show_error(undef, $@); } - eval { - $self->{preset_bundle}->load_selections($self->{app_config}); - }; + eval { $self->{preset_bundle}->load_selections($self->{app_config}) }; $run_wizard = 1 if $self->{preset_bundle}->has_defauls_only; # application frame - Wx::Image::AddHandler(Wx::PNGHandler->new); + Wx::Image::FindHandlerType(wxBITMAP_TYPE_PNG) || Wx::Image::AddHandler(Wx::PNGHandler->new); $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new( # If set, the "Controller" tab for the control of the printer over serial line and the serial port settings are hidden. no_controller => $self->{app_config}->get('no_controller'), no_plater => $no_plater, ); $self->SetTopWindow($frame); - if ($run_wizard) { - $self->{mainframe}->config_wizard; - } EVT_IDLE($frame, sub { while (my $cb = shift @cb) { @@ -129,6 +123,15 @@ sub OnInit { } $self->{app_config}->save if $self->{app_config}->dirty; }); + + if ($run_wizard) { + # On OSX the UI was not initialized correctly if the wizard was called + # before the UI was up and running. + $self->CallAfter(sub { + # Run the config wizard, don't offer the "reset user profile" checkbox. + $self->{mainframe}->config_wizard(1); + }); + } return 1; } diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm index 51c822590..730216a8b 100644 --- a/lib/Slic3r/GUI/3DScene.pm +++ b/lib/Slic3r/GUI/3DScene.pm @@ -15,7 +15,7 @@ package Slic3r::GUI::3DScene::Base; use strict; use warnings; -use Wx qw(:timer :bitmap :icon :dialog); +use Wx qw(wxTheApp :timer :bitmap :icon :dialog); use Wx::Event qw(EVT_PAINT EVT_SIZE EVT_ERASE_BACKGROUND EVT_IDLE EVT_MOUSEWHEEL EVT_MOUSE_EVENTS EVT_CHAR EVT_TIMER); # must load OpenGL *before* Wx::GLCanvas use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants); @@ -108,6 +108,7 @@ sub new { # We can only enable multi sample anti aliasing wih wxWidgets 3.0.3 and with a hacked Wx::GLCanvas, # which exports some new WX_GL_XXX constants, namely WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES. my $can_multisample = + ! wxTheApp->{app_config}->get('use_legacy_opengl') && Wx::wxVERSION >= 3.000003 && defined Wx::GLCanvas->can('WX_GL_SAMPLE_BUFFERS') && defined Wx::GLCanvas->can('WX_GL_SAMPLES'); @@ -956,6 +957,16 @@ sub UseVBOs { my ($self) = @_; if (! defined ($self->{use_VBOs})) { + my $use_legacy = wxTheApp->{app_config}->get('use_legacy_opengl'); + if ($use_legacy eq '1') { + # Disable OpenGL 2.0 rendering. + $self->{use_VBOs} = 0; + # Don't enable the layer editing tool. + $self->{layer_editing_enabled} = 0; + # 2 means failed + $self->{layer_editing_initialized} = 2; + return 0; + } # This is a special path for wxWidgets on GTK, where an OpenGL context is initialized # first when an OpenGL widget is shown for the first time. How ugly. return 0 if (! $self->init && $^O eq 'linux'); diff --git a/lib/Slic3r/GUI/ConfigWizard.pm b/lib/Slic3r/GUI/ConfigWizard.pm index e540f9ea7..a32d345ed 100644 --- a/lib/Slic3r/GUI/ConfigWizard.pm +++ b/lib/Slic3r/GUI/ConfigWizard.pm @@ -14,14 +14,14 @@ our $wizard = 'Wizard'; $wizard = 'Assistant' if &Wx::wxMAC || &Wx::wxGTK; sub new { - my $class = shift; - my ($parent) = @_; + my ($class, $parent, $presets, $fresh_start) = @_; my $self = $class->SUPER::new($parent, -1, "Configuration $wizard"); # initialize an empty repository $self->{config} = Slic3r::Config->new; - $self->add_page(Slic3r::GUI::ConfigWizard::Page::Welcome->new($self)); + my $welcome_page = Slic3r::GUI::ConfigWizard::Page::Welcome->new($self, $fresh_start); + $self->add_page($welcome_page); $self->add_page(Slic3r::GUI::ConfigWizard::Page::Firmware->new($self)); $self->add_page(Slic3r::GUI::ConfigWizard::Page::Bed->new($self)); $self->add_page(Slic3r::GUI::ConfigWizard::Page::Nozzle->new($self)); @@ -32,12 +32,13 @@ sub new { $_->build_index for @{$self->{pages}}; + $welcome_page->set_selection_presets([@{$presets}, 'Other']); + return $self; } sub add_page { - my $self = shift; - my ($page) = @_; + my ($self, $page) = @_; my $n = push @{$self->{pages}}, $page; # add first page to the page area sizer @@ -48,13 +49,17 @@ sub add_page { } sub run { - my $self = shift; - + my ($self) = @_; + my $result; if (Wx::Wizard::RunWizard($self, $self->{pages}[0])) { - - # it would be cleaner to have these defined inside each page class, - # in some event getting called before leaving the page - { + my $preset_name = $self->{pages}[0]->{preset_name}; + $result = { + preset_name => $preset_name, + reset_user_profile => $self->{pages}[0]->{reset_user_profile} + }; + if ($preset_name eq 'Other') { + # it would be cleaner to have these defined inside each page class, + # in some event getting called before leaving the page # set first_layer_height + layer_height based on nozzle_diameter my $nozzle = $self->{config}->nozzle_diameter; $self->{config}->set('first_layer_height', $nozzle->[0]); @@ -66,14 +71,11 @@ sub run { # set first_layer_bed_temperature to temperature + 5 $self->{config}->set('first_layer_bed_temperature', [ ($self->{config}->bed_temperature->[0] > 0) ? ($self->{config}->bed_temperature->[0] + 5) : 0 ]); + $result->{config} = $self->{config}; } - - $self->Destroy; - return $self->{config}; - } else { - $self->Destroy; - return undef; } + $self->Destroy; + return $result; } package Slic3r::GUI::ConfigWizard::Index; @@ -127,6 +129,8 @@ sub repaint { $dc->SetTextForeground(Wx::Colour->new(128, 128, 128)) if $i > $self->{own_index}; $dc->DrawLabel($_, $bullet, Wx::Rect->new(0, $i * ($label_h + $gap), $label_w, $label_h)); + # Only show the first bullet if this is the only wizard page to be displayed. + last if $i == 0 && $self->{just_welcome}; $i++; } @@ -263,19 +267,87 @@ sub config { package Slic3r::GUI::ConfigWizard::Page::Welcome; use base 'Slic3r::GUI::ConfigWizard::Page'; +use Wx qw(:misc :sizer wxID_FORWARD); +use Wx::Event qw(EVT_ACTIVATE EVT_CHOICE EVT_CHECKBOX); sub new { - my $class = shift; - my ($parent) = @_; + my ($class, $parent, $fresh_start) = @_; my $self = $class->SUPER::new($parent, "Welcome to the Slic3r Configuration $wizard", 'Welcome'); + $self->{full_wizard_workflow} = 1; + $self->{reset_user_profile} = 0; - $self->append_text('Hello, welcome to Slic3r! This '.lc($wizard).' helps you with the initial configuration; just a few settings and you will be ready to print.'); - $self->append_text('To import an existing configuration instead, cancel this '.lc($wizard).' and use the Open Config menu item found in the File menu.'); - $self->append_text('To continue, click Next.'); + # Test for the existence of the old config path. + my $message_has_legacy; + { + my $datadir = Slic3r::data_dir; + if ($datadir =~ /Slic3rPE/) { + # Check for existence of the legacy Slic3r directory. + my $datadir_legacy = substr $datadir, 0, -2; + my $dir_enc = Slic3r::encode_path($datadir_legacy); + if (-e $dir_enc && -d $dir_enc && + -e ($dir_enc . '/print') && -d ($dir_enc . '/print') && + -e ($dir_enc . '/filament') && -d ($dir_enc . '/filament') && + -e ($dir_enc . '/printer') && -d ($dir_enc . '/printer') && + -e ($dir_enc . '/slic3r.ini')) { + $message_has_legacy = "Starting with Slic3r 1.38.4, the user profile directory has been renamed to $datadir. You may consider closing Slic3r and renaming $datadir_legacy to $datadir."; + } + } + } + + $self->append_text('Hello, welcome to Slic3r Prusa Edition! This '.lc($wizard).' helps you with the initial configuration; just a few settings and you will be ready to print.'); + $self->append_text('Please select your printer vendor and printer type. If your printer is not listed, you may try your luck and select a similar one. If you select "Other", this ' . lc($wizard) . ' will let you set the basic 3D printer parameters.'); + $self->append_text($message_has_legacy) if defined $message_has_legacy; + # To import an existing configuration instead, cancel this '.lc($wizard).' and use the Open Config menu item found in the File menu.'); + $self->append_text('If you received a configuration file or a config bundle from your 3D printer vendor, cancel this '.lc($wizard).' and use the "File->Load Config" or "File->Load Config Bundle" menu.'); + + $self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, []); + $self->{vsizer}->Add($choice, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); + if (! $fresh_start) { + $self->{reset_checkbox} = Wx::CheckBox->new($self, -1, "Reset user profile, install from scratch"); + $self->{vsizer}->Add($self->{reset_checkbox}, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); + } + + EVT_CHOICE($parent, $choice, sub { + my $sel = $self->{choice}->GetStringSelection; + $self->{preset_name} = $sel; + $self->set_full_wizard_workflow(($sel eq 'Other') || ($sel eq '')); + }); + + if (! $fresh_start) { + EVT_CHECKBOX($self, $self->{reset_checkbox}, sub { + $self->{reset_user_profile} = $self->{reset_checkbox}->GetValue(); + }); + } + + EVT_ACTIVATE($parent, sub { + $self->set_full_wizard_workflow($self->{preset_name} eq 'Other'); + }); return $self; } +sub set_full_wizard_workflow { + my ($self, $full_workflow) = @_; + $self->{full_wizard_workflow} = $full_workflow; + $self->{index}->{just_welcome} = !$full_workflow; + $self->{index}->Refresh; + my $next_button = $self->GetParent->FindWindow(wxID_FORWARD); + $next_button->SetLabel($full_workflow ? "&Next >" : "&Finish"); +} + +# Set the preset names, select the first item. +sub set_selection_presets { + my ($self, $names) = @_; + $self->{choice}->Append($names); + $self->{choice}->SetSelection(0); + $self->{preset_name} = $names->[0]; +} + +sub GetNext { + my $self = shift; + return $self->{full_wizard_workflow} ? $self->{next_page} : undef; +} + package Slic3r::GUI::ConfigWizard::Page::Firmware; use base 'Slic3r::GUI::ConfigWizard::Page'; diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 09a64ca4b..6b07d761d 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -7,7 +7,7 @@ use utf8; use File::Basename qw(basename dirname); use FindBin; -use List::Util qw(min); +use List::Util qw(min first); use Slic3r::Geometry qw(X Y); use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog :font :icon wxTheApp); @@ -22,6 +22,7 @@ sub new { my ($class, %params) = @_; my $self = $class->SUPER::new(undef, -1, $Slic3r::FORK_NAME . ' - ' . $Slic3r::VERSION, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE); + Slic3r::GUI::set_main_frame($self); if ($^O eq 'MSWin32') { # Load the icon either from the exe, or from the ico file. my $iconfile = Slic3r::decode_path($FindBin::Bin) . '\slic3r.exe'; @@ -92,6 +93,8 @@ sub _init_tabpanel { my ($self) = @_; $self->{tabpanel} = my $panel = Wx::Notebook->new($self, -1, wxDefaultPosition, wxDefaultSize, wxNB_TOP | wxTAB_TRAVERSAL); + Slic3r::GUI::set_tab_panel($panel); + EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{tabpanel}, sub { my $panel = $self->{tabpanel}->GetCurrentPage; $panel->OnActivate if $panel->can('OnActivate'); @@ -129,12 +132,14 @@ sub _init_tabpanel { $self->{plater}->update_presets($tab_name, @_); if ($tab_name eq 'printer') { # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors. - wxTheApp->{preset_bundle}->print->update_tab_ui( - $self->{options_tabs}{'print'}->{presets_choice}, - $self->{options_tabs}{'print'}->{show_incompatible_presets}); - wxTheApp->{preset_bundle}->filament->update_tab_ui( - $self->{options_tabs}{'filament'}->{presets_choice}, - $self->{options_tabs}{'filament'}->{show_incompatible_presets}); + my ($presets, $reload_dependent_tabs) = @_; + for my $tab_name_other (qw(print filament)) { + # If the printer tells us that the print or filament preset has been switched or invalidated, + # refresh the print or filament tab page. Otherwise just refresh the combo box. + my $update_action = ($reload_dependent_tabs && (first { $_ eq $tab_name_other } (@{$reload_dependent_tabs}))) + ? 'load_current_preset' : 'update_tab_ui'; + $self->{options_tabs}{$tab_name_other}->$update_action; + } # Update the controller printers. $self->{controller}->update_presets(@_) if $self->{controller}; } @@ -145,6 +150,9 @@ sub _init_tabpanel { $tab->load_current_preset; $panel->AddPage($tab, $tab->title); } + +#TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view. +# Slic3r::GUI::create_preset_tab("print"); if ($self->{plater}) { $self->{plater}->on_select_preset(sub { @@ -165,6 +173,9 @@ sub _init_menubar { # File menu my $fileMenu = Wx::Menu->new; { + wxTheApp->append_menu_item($fileMenu, "Open STL/OBJ/AMF…\tCtrl+O", 'Open a model', sub { + $self->{plater}->add if $self->{plater}; + }, undef, undef); #'brick_add.png'); $self->_append_menu_item($fileMenu, "&Load Config…\tCtrl+L", 'Load exported configuration file', sub { $self->load_config_file; }, undef, 'plugin_add.png'); @@ -274,20 +285,22 @@ sub _init_menubar { # \xA0 is a non-breaing space. It is entered here to spoil the automatic accelerators, # as the simple numeric accelerators spoil all numeric data entry. # The camera control accelerators are captured by 3DScene Perl module instead. - $self->_append_menu_item($self->{viewMenu}, "Iso\t\xA00" , 'Iso View' , sub { $self->select_view('iso' ); }); - $self->_append_menu_item($self->{viewMenu}, "Top\t\xA01" , 'Top View' , sub { $self->select_view('top' ); }); - $self->_append_menu_item($self->{viewMenu}, "Bottom\t\xA02" , 'Bottom View' , sub { $self->select_view('bottom' ); }); - $self->_append_menu_item($self->{viewMenu}, "Front\t\xA03" , 'Front View' , sub { $self->select_view('front' ); }); - $self->_append_menu_item($self->{viewMenu}, "Rear\t\xA04" , 'Rear View' , sub { $self->select_view('rear' ); }); - $self->_append_menu_item($self->{viewMenu}, "Left\t\xA05" , 'Left View' , sub { $self->select_view('left' ); }); - $self->_append_menu_item($self->{viewMenu}, "Right\t\xA06" , 'Right View' , sub { $self->select_view('right' ); }); + my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] }; + $self->_append_menu_item($self->{viewMenu}, $accel->('Iso', '0'), 'Iso View' , sub { $self->select_view('iso' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Top', '1'), 'Top View' , sub { $self->select_view('top' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Bottom', '2'), 'Bottom View' , sub { $self->select_view('bottom' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Front', '3'), 'Front View' , sub { $self->select_view('front' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Rear', '4'), 'Rear View' , sub { $self->select_view('rear' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Left', '5'), 'Left View' , sub { $self->select_view('left' ); }); + $self->_append_menu_item($self->{viewMenu}, $accel->('Right', '6'), 'Right View' , sub { $self->select_view('right' ); }); } # Help menu my $helpMenu = Wx::Menu->new; { $self->_append_menu_item($helpMenu, "&Configuration $Slic3r::GUI::ConfigWizard::wizard…", "Run Configuration $Slic3r::GUI::ConfigWizard::wizard", sub { - $self->config_wizard; + # Run the config wizard, offer the "reset user profile" checkbox. + $self->config_wizard(0); }); $helpMenu->AppendSeparator(); $self->_append_menu_item($helpMenu, "Prusa 3D Drivers", 'Open the Prusa3D drivers download page in your browser', sub { @@ -329,6 +342,8 @@ sub _init_menubar { $menubar->Append($windowMenu, "&Window"); $menubar->Append($self->{viewMenu}, "&View") if $self->{viewMenu}; $menubar->Append($helpMenu, "&Help"); + # Add an optional debug menu. In production code, the add_debug_menu() call should do nothing. + Slic3r::GUI::add_debug_menu($menubar); $self->SetMenuBar($menubar); } } @@ -413,6 +428,7 @@ sub quick_slice { if ($params{reslice}) { $output_file = $qs_last_output_file if defined $qs_last_output_file; } elsif ($params{save_as}) { + # The following line may die if the output_filename_format template substitution fails. $output_file = $sprint->output_filepath; $output_file =~ s/\.[gG][cC][oO][dD][eE]$/.svg/ if $params{export_svg}; my $dlg = Wx::FileDialog->new($self, 'Save ' . ($params{export_svg} ? 'SVG' : 'G-code') . ' file as:', @@ -565,7 +581,7 @@ sub export_configbundle { # to auto-install a config bundle on a fresh user account, # but that behavior was not documented and likely buggy. sub load_configbundle { - my ($self, $file) = @_; + my ($self, $file, $reset_user_profile) = @_; return unless $self->check_unsaved_changes; if (!$file) { my $dlg = Wx::FileDialog->new($self, 'Select configuration to load:', @@ -580,7 +596,7 @@ sub load_configbundle { wxTheApp->{app_config}->update_config_dir(dirname($file)); my $presets_imported = 0; - eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); }; + eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file, $reset_user_profile ? 1 : 0); }; Slic3r::GUI::catch_error($self) and return; # Load the currently selected preset into the GUI, update the preset selection box. @@ -601,19 +617,39 @@ sub load_config { } sub config_wizard { - my ($self) = @_; + my ($self, $fresh_start) = @_; # Exit wizard if there are unsaved changes and the user cancels the action. return unless $self->check_unsaved_changes; - if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) { - for my $tab (values %{$self->{options_tabs}}) { - # Select the first visible preset, force. - $tab->select_preset(undef, 1); + # Enumerate the profiles bundled with the Slic3r installation under resources/profiles. + my $directory = Slic3r::resources_dir() . "/profiles"; + my @profiles = (); + if (opendir(DIR, Slic3r::encode_path($directory))) { + while (my $file = readdir(DIR)) { + if ($file =~ /\.ini$/) { + $file =~ s/\.ini$//; + push @profiles, Slic3r::decode_path($file); + } } - # Load the config over the previously selected defaults. - $self->load_config($config); - for my $tab (values %{$self->{options_tabs}}) { - # Save the settings under a new name, select the name. - $tab->save_preset('My Settings'); + closedir(DIR); + } + # Open the wizard. + if (my $result = Slic3r::GUI::ConfigWizard->new($self, \@profiles, $fresh_start)->run) { + eval { + if ($result->{reset_user_profile}) { + wxTheApp->{preset_bundle}->reset(1); + } + if (defined $result->{config}) { + # Load and save the settings into print, filament and printer presets. + wxTheApp->{preset_bundle}->load_config('My Settings', $result->{config}); + } else { + # Wizard returned a name of a preset bundle bundled with the installation. Unpack it. + wxTheApp->{preset_bundle}->load_configbundle($directory . '/' . $result->{preset_name} . '.ini'); + } + }; + Slic3r::GUI::catch_error($self) and return; + # Load the currently selected preset into the GUI, update the preset selection box. + foreach my $tab (values %{$self->{options_tabs}}) { + $tab->load_current_preset; } } } diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index cdb03e791..da2d12aa0 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -99,6 +99,7 @@ sub new { $self->{canvas3D}->set_on_select_object($on_select_object); $self->{canvas3D}->set_on_double_click($on_double_click); $self->{canvas3D}->set_on_right_click(sub { $on_right_click->($self->{canvas3D}, @_); }); + $self->{canvas3D}->set_on_arrange(sub { $self->arrange }); $self->{canvas3D}->set_on_rotate_object_left(sub { $self->rotate(-45, Z, 'relative') }); $self->{canvas3D}->set_on_rotate_object_right(sub { $self->rotate( 45, Z, 'relative') }); $self->{canvas3D}->set_on_scale_object_uniformly(sub { $self->changescale(undef) }); @@ -429,6 +430,7 @@ sub new { $grid_sizer->AddGrowableCol(3, 1); $print_info_sizer->Add($grid_sizer, 0, wxEXPAND); my @info = ( + fil_m => "Used Filament (m)", fil_mm3 => "Used Filament (mm^3)", fil_g => "Used Filament (g)", cost => "Cost", @@ -504,6 +506,7 @@ sub _on_select_preset { wxTheApp->{preset_bundle}->set_filament_preset($idx, $choice->GetStringSelection); } if ($group eq 'filament' && @{$self->{preset_choosers}{filament}} > 1) { + # Only update the platter UI for the 2nd and other filaments. wxTheApp->{preset_bundle}->update_platter_filament_ui($idx, $choice); } else { # call GetSelection() in scalar context as it's context-aware @@ -1290,9 +1293,11 @@ sub export_gcode { # select output file if ($output_file) { - $self->{export_gcode_output_file} = $self->{print}->output_filepath($output_file); + $self->{export_gcode_output_file} = eval { $self->{print}->output_filepath($output_file) }; + Slic3r::GUI::catch_error($self) and return; } else { - my $default_output_file = $self->{print}->output_filepath($main::opt{output} // ''); + my $default_output_file = eval { $self->{print}->output_filepath($main::opt{output} // '') }; + Slic3r::GUI::catch_error($self) and return; my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->{app_config}->get_last_output_dir(dirname($default_output_file)), basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT); @@ -1423,6 +1428,7 @@ sub on_export_completed { $self->{"print_info_cost"}->SetLabel(sprintf("%.2f" , $self->{print}->total_cost)); $self->{"print_info_fil_g"}->SetLabel(sprintf("%.2f" , $self->{print}->total_weight)); $self->{"print_info_fil_mm3"}->SetLabel(sprintf("%.2f" , $self->{print}->total_extruded_volume)); + $self->{"print_info_fil_m"}->SetLabel(sprintf("%.2f" , $self->{print}->total_used_filament / 1000)); $self->{"print_info_box_show"}->(1); # this updates buttons status @@ -1437,8 +1443,8 @@ sub do_print { my $printer_panel = $controller->add_printer($printer_preset->name, $printer_preset->config); my $filament_stats = $self->{print}->filament_stats; - my @filament_names = wxTheApp->{preset_bundle}->filament_presets; - $filament_stats = { map { $filament_names[$_] => $filament_stats->{$_} } keys %$filament_stats }; + my $filament_names = wxTheApp->{preset_bundle}->filament_presets; + $filament_stats = { map { $filament_names->[$_] => $filament_stats->{$_} } keys %$filament_stats }; $printer_panel->load_print_job($self->{print_file}, $filament_stats); $self->GetFrame->select_tab(1); @@ -1494,6 +1500,7 @@ sub reload_from_disk { return if !defined $obj_idx; my $model_object = $self->{model}->objects->[$obj_idx]; + #FIXME convert to local file encoding return if !$model_object->input_file || !-e $model_object->input_file; @@ -1504,12 +1511,14 @@ sub reload_from_disk { my $o = $self->{model}->objects->[$new_obj_idx]; $o->clear_instances; $o->add_instance($_) for @{$model_object->instances}; + #$o->invalidate_bounding_box; if ($o->volumes_count == $model_object->volumes_count) { for my $i (0..($o->volumes_count-1)) { $o->get_volume($i)->config->apply($model_object->get_volume($i)->config); } } + #FIXME restore volumes and their configs, layer_height_ranges, layer_height_profile, layer_height_profile_valid, } $self->remove($obj_idx); @@ -1540,7 +1549,8 @@ sub export_amf { sub _get_export_file { my ($self, $format) = @_; my $suffix = $format eq 'STL' ? '.stl' : '.amf.xml'; - my $output_file = $self->{print}->output_filepath($main::opt{output} // ''); + my $output_file = eval { $self->{print}->output_filepath($main::opt{output} // '') }; + Slic3r::GUI::catch_error($self) and return undef; $output_file =~ s/\.[gG][cC][oO][dD][eE]$/$suffix/; 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); @@ -1917,23 +1927,24 @@ sub object_menu { my $frame = $self->GetFrame; my $menu = Wx::Menu->new; - $frame->_append_menu_item($menu, "Delete\t\xA0Del", 'Remove the selected object', sub { + my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] }; + $frame->_append_menu_item($menu, $accel->('Delete', 'Del'), 'Remove the selected object', sub { $self->remove; }, undef, 'brick_delete.png'); - $frame->_append_menu_item($menu, "Increase copies\t\xA0+", 'Place one more copy of the selected object', sub { + $frame->_append_menu_item($menu, $accel->('Increase copies', '+'), 'Place one more copy of the selected object', sub { $self->increase; }, undef, 'add.png'); - $frame->_append_menu_item($menu, "Decrease copies\t\xA0-", 'Remove one copy of the selected object', sub { + $frame->_append_menu_item($menu, $accel->('Decrease copies', '-'), 'Remove one copy of the selected object', sub { $self->decrease; }, undef, 'delete.png'); $frame->_append_menu_item($menu, "Set number of copies…", 'Change the number of copies of the selected object', sub { $self->set_number_of_copies; }, undef, 'textfield.png'); $menu->AppendSeparator(); - $frame->_append_menu_item($menu, "Rotate 45° clockwise\t\xA0l", 'Rotate the selected object by 45° clockwise', sub { + $frame->_append_menu_item($menu, $accel->('Rotate 45° clockwise', 'l'), 'Rotate the selected object by 45° clockwise', sub { $self->rotate(-45, Z, 'relative'); }, undef, 'arrow_rotate_clockwise.png'); - $frame->_append_menu_item($menu, "Rotate 45° counter-clockwise\t\xA0r", 'Rotate the selected object by 45° counter-clockwise', sub { + $frame->_append_menu_item($menu, $accel->('Rotate 45° counter-clockwise', 'r'), 'Rotate the selected object by 45° counter-clockwise', sub { $self->rotate(+45, Z, 'relative'); }, undef, 'arrow_rotate_anticlockwise.png'); @@ -1966,7 +1977,7 @@ sub object_menu { my $scaleMenu = Wx::Menu->new; my $scaleMenuItem = $menu->AppendSubMenu($scaleMenu, "Scale", 'Scale the selected object along a single axis'); $frame->_set_menu_item_icon($scaleMenuItem, 'arrow_out.png'); - $frame->_append_menu_item($scaleMenu, "Uniformly…\t\xA0s", 'Scale the selected object along the XYZ axes', sub { + $frame->_append_menu_item($scaleMenu, $accel->('Uniformly…', 's'), 'Scale the selected object along the XYZ axes', sub { $self->changescale(undef); }); $frame->_append_menu_item($scaleMenu, "Along X axis…", 'Scale the selected object along the X axis', sub { diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm index 2bc7dd90f..a97aa0776 100644 --- a/lib/Slic3r/GUI/Plater/3D.pm +++ b/lib/Slic3r/GUI/Plater/3D.pm @@ -9,7 +9,7 @@ use Wx::Event qw(EVT_KEY_DOWN EVT_CHAR); use base qw(Slic3r::GUI::3DScene Class::Accessor); __PACKAGE__->mk_accessors(qw( - on_rotate_object_left on_rotate_object_right on_scale_object_uniformly + on_arrange on_rotate_object_left on_rotate_object_right on_scale_object_uniformly on_remove_object on_increase_objects on_decrease_objects)); sub new { @@ -88,7 +88,9 @@ sub new { $event->Skip; } else { my $key = $event->GetKeyCode; - if ($key == ord('l')) { + if ($key == ord('a')) { + $self->on_arrange->() if $self->on_arrange; + } elsif ($key == ord('l')) { $self->on_rotate_object_left->() if $self->on_rotate_object_left; } elsif ($key == ord('r')) { $self->on_rotate_object_right->() if $self->on_rotate_object_right; @@ -122,6 +124,11 @@ sub set_on_right_click { $self->on_right_click($cb); } +sub set_on_arrange { + my ($self, $cb) = @_; + $self->on_arrange($cb); +} + sub set_on_rotate_object_left { my ($self, $cb) = @_; $self->on_rotate_object_left($cb); diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm index d20ccb53f..703a7a762 100644 --- a/lib/Slic3r/GUI/Preferences.pm +++ b/lib/Slic3r/GUI/Preferences.pm @@ -72,6 +72,13 @@ sub new { 'if they are marked as incompatible with the active printer', default => $app_config->get("show_incompatible_presets"), )); + $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( + opt_id => 'use_legacy_opengl', + type => 'bool', + label => 'Use legacy OpenGL 1.1 rendering', + tooltip => 'If you have rendering issues caused by a buggy OpenGL 2.0 driver, you may try to check this checkbox. This will disable the layer height editing and anti aliasing, so it is likely better to upgrade your graphics driver.', + default => $app_config->get("use_legacy_opengl"), + )); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($optgroup->sizer, 0, wxEXPAND | wxBOTTOM | wxLEFT | wxRIGHT, 10); @@ -90,7 +97,8 @@ sub _accept { my ($self) = @_; if (defined($self->{values}{no_controller}) || - defined($self->{values}{no_defaults})) { + defined($self->{values}{no_defaults}) || + defined($self->{values}{use_legacy_opengl})) { Slic3r::GUI::warning_catcher($self)->("You need to restart Slic3r to make the changes effective."); } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index d43c33ff1..7050cfa11 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -147,11 +147,13 @@ sub save_preset { return unless $dlg->ShowModal == wxID_OK; $name = $dlg->get_name; } - # Save the preset into Slic3r::data_dir/section_name/preset_name.ini + # Save the preset into Slic3r::data_dir/presets/section_name/preset_name.ini eval { $self->{presets}->save_current_preset($name); }; Slic3r::GUI::catch_error($self) and return; + # Mark the print & filament enabled if they are compatible with the currently selected preset. + wxTheApp->{preset_bundle}->update_compatible_with_printer(0); # Add the new item into the UI component, remove dirty flags and activate the saved item. - $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); + $self->update_tab_ui; # Update the selection boxes at the platter. $self->_on_presets_changed; } @@ -177,7 +179,7 @@ sub _toggle_show_hide_incompatible { my ($self) = @_; $self->{show_incompatible_presets} = ! $self->{show_incompatible_presets}; $self->_update_show_hide_incompatible_button; - $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); + $self->update_tab_ui; } sub _update_show_hide_incompatible_button { @@ -223,8 +225,9 @@ sub _update {} # to update the "dirty" flags of the selection boxes, # to uddate number of "filament" selection boxes when the number of extruders change. sub _on_presets_changed { - my ($self) = @_; - $self->{on_presets_changed}->($self->{presets}) if $self->{on_presets_changed}; + my ($self, $reload_dependent_tabs) = @_; + $self->{on_presets_changed}->($self->{presets}, $reload_dependent_tabs) + if $self->{on_presets_changed}; } # For the printer profile, generate the extruder pages after a preset is loaded. @@ -237,11 +240,12 @@ sub may_discard_current_dirty_preset my ($self, $presets, $new_printer_name) = @_; $presets //= $self->{presets}; # Display a dialog showing the dirty options in a human readable form. - my $old_preset = $presets->get_current_preset; - my $type_name = $presets->name; - my $name = $old_preset->default ? + my $old_preset = $presets->get_current_preset; + my $type_name = $presets->name; + my $tab = ' '; + my $name = $old_preset->default ? ('Default ' . $type_name . ' preset') : - ($type_name . " preset \"" . $old_preset->name . "\""); + ($type_name . " preset\n$tab" . $old_preset->name); # Collect descriptions of the dirty options. my @option_names = (); foreach my $opt_key (@{$presets->current_dirty_options}) { @@ -251,10 +255,10 @@ sub may_discard_current_dirty_preset push @option_names, $name; } # Show a confirmation dialog with the list of dirty options. - my $changes = join "\n", map "- $_", @option_names; + my $changes = join "\n", map "$tab$_", @option_names; my $message = (defined $new_printer_name) ? - "$name is not compatible with printer \"$new_printer_name\"\n and it has unsaved changes:" : - "$name has unsaved changes:"; + "$name\n\nis not compatible with printer\n$tab$new_printer_name\n\nand it has the following unsaved changes:" : + "$name\n\nhas the following unsaved changes:"; my $confirm = Wx::MessageDialog->new($self, $message . "\n$changes\n\nDiscard changes and continue anyway?", 'Unsaved Changes', wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); @@ -267,9 +271,13 @@ sub may_discard_current_dirty_preset sub select_preset { my ($self, $name, $force) = @_; $force //= 0; - my $current_dirty = $self->{presets}->current_is_dirty; - my $canceled = 0; - my $printer_tab = $self->{presets}->name eq 'printer'; + my $presets = $self->{presets}; + # If no name is provided, select the "-- default --" preset. + $name //= $presets->default_preset->name; + my $current_dirty = $presets->current_is_dirty; + my $canceled = 0; + my $printer_tab = $presets->name eq 'printer'; + my @reload_dependent_tabs = (); if (! $force && $current_dirty && ! $self->may_discard_current_dirty_preset) { $canceled = 1; } elsif ($printer_tab) { @@ -277,50 +285,53 @@ sub select_preset { # are compatible with the new printer. # If they are not compatible and the the current print or filament are dirty, let user decide # whether to discard the changes or keep the current printer selection. - my $new_printer_name = $name // ''; - my $new_printer_preset = $self->{presets}->find_preset($new_printer_name, 1); - # my $new_nozzle_dmrs = $new_printer_preset->config->get('nozzle_diameter'); - my $print_presets = wxTheApp->{preset_bundle}->print; - if ($print_presets->current_is_dirty && - ! $print_presets->get_edited_preset->is_compatible_with_printer($new_printer_name)) { - if ($self->may_discard_current_dirty_preset($print_presets, $new_printer_name)) { - $canceled = 1; - } else { - $print_presets->discard_current_changes; - } + my $new_printer_preset = $presets->find_preset($name, 1); + my $print_presets = wxTheApp->{preset_bundle}->print; + my $print_preset_dirty = $print_presets->current_is_dirty; + my $print_preset_compatible = $print_presets->get_edited_preset->is_compatible_with_printer($new_printer_preset); + $canceled = ! $force && $print_preset_dirty && ! $print_preset_compatible && + ! $self->may_discard_current_dirty_preset($print_presets, $name); + my $filament_presets = wxTheApp->{preset_bundle}->filament; + my $filament_preset_dirty = $filament_presets->current_is_dirty; + my $filament_preset_compatible = $filament_presets->get_edited_preset->is_compatible_with_printer($new_printer_preset); + if (! $canceled && ! $force) { + $canceled = $filament_preset_dirty && ! $filament_preset_compatible && + ! $self->may_discard_current_dirty_preset($filament_presets, $name); } - my $filament_presets = wxTheApp->{preset_bundle}->filament; - # if ((@$new_nozzle_dmrs <= 1) && - if (! $canceled && $filament_presets->current_is_dirty && - ! $filament_presets->get_edited_preset->is_compatible_with_printer($new_printer_name)) { - if ($self->may_discard_current_dirty_preset($filament_presets, $new_printer_name)) { - $canceled = 1; - } else { - $filament_presets->discard_current_changes; + if (! $canceled) { + if (! $print_preset_compatible) { + # The preset will be switched to a different, compatible preset, or the '-- default --'. + push @reload_dependent_tabs, 'print'; + $print_presets->discard_current_changes if $print_preset_dirty; + } + if (! $filament_preset_compatible) { + # The preset will be switched to a different, compatible preset, or the '-- default --'. + push @reload_dependent_tabs, 'filament'; + $filament_presets->discard_current_changes if $filament_preset_dirty; } } } if ($canceled) { - $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); - # Trigger the on_presets_changed event so that we also restore the previous value in the plater selector. + $self->update_tab_ui; + # Trigger the on_presets_changed event so that we also restore the previous value in the plater selector, + # if this action was initiated from the platter. $self->_on_presets_changed; } else { - if (defined $name) { - $self->{presets}->select_preset_by_name($name); - } else { - $self->{presets}->select_preset(0); - } + $presets->discard_current_changes if $current_dirty; + $presets->select_preset_by_name($name); # Mark the print & filament enabled if they are compatible with the currently selected preset. + # The following method should not discard changes of current print or filament presets on change of a printer profile, + # if they are compatible with the current printer. wxTheApp->{preset_bundle}->update_compatible_with_printer(1) if $current_dirty || $printer_tab; # Initialize the UI from the current preset. - $self->load_current_preset; + $self->load_current_preset(\@reload_dependent_tabs); } } # Initialize the UI from the current preset. sub load_current_preset { - my ($self) = @_; + my ($self, $dependent_tab_names) = @_; my $preset = $self->{presets}->get_current_preset; eval { local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self); @@ -337,8 +348,8 @@ sub load_current_preset { # preset dirty again # (not sure this is true anymore now that update_dirty is idempotent) wxTheApp->CallAfter(sub { - $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); - $self->_on_presets_changed; + $self->update_tab_ui; + $self->_on_presets_changed($dependent_tab_names); }); } @@ -430,11 +441,10 @@ sub _load_key_value { $self->{config}->set($opt_key, $value); # Mark the print & filament enabled if they are compatible with the currently selected preset. if ($opt_key eq 'compatible_printers') { +# $opt_key eq 'compatible_printers_condition') { wxTheApp->{preset_bundle}->update_compatible_with_printer(0); - $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}); - } else { - $self->{presets}->update_dirty_ui($self->{presets_choice}); } + $self->{presets}->update_dirty_ui($self->{presets_choice}); $self->_on_presets_changed; $self->_update; } @@ -485,6 +495,7 @@ sub _compatible_printers_widget { $btn->$method; # All printers have been made compatible with this preset. $self->_load_key_value('compatible_printers', []) if $checkbox->GetValue; + $self->get_field('compatible_printers_condition')->toggle($checkbox->GetValue); }); EVT_BUTTON($self, $btn, sub { @@ -506,6 +517,7 @@ sub _compatible_printers_widget { my $value = [ @presets[$dlg->GetSelections] ]; if (!@$value) { $checkbox->SetValue(1); + $self->get_field('compatible_printers_condition')->toggle(1); $btn->Disable; } # All printers have been made compatible with this preset. @@ -523,6 +535,7 @@ sub _reload_compatible_printers_widget { my $method = $has_any ? 'Enable' : 'Disable'; $self->{compatible_printers_checkbox}->SetValue(! $has_any); $self->{compatible_printers_btn}->$method; + $self->get_field('compatible_printers_condition')->toggle(! $has_any); } sub update_ui_from_settings { @@ -538,10 +551,14 @@ sub update_ui_from_settings { } else { if ($self->{show_incompatible_presets}) { $self->{show_incompatible_presets} = 0; - $self->{presets}->update_tab_ui($self->{presets_choice}, 0); + $self->update_tab_ui; } } } +sub update_tab_ui { + my ($self) = @_; + $self->{presets}->update_tab_ui($self->{presets_choice}, $self->{show_incompatible_presets}) +} package Slic3r::GUI::Tab::Print; use base 'Slic3r::GUI::Tab'; @@ -825,6 +842,10 @@ sub build { widget => $self->_compatible_printers_widget, ); $optgroup->append_line($line); + + my $option = $optgroup->get_option('compatible_printers_condition'); + $option->full_width(1); + $optgroup->append_single_option_line($option); } } } @@ -1194,6 +1215,10 @@ sub build { widget => $self->_compatible_printers_widget, ); $optgroup->append_line($line); + + my $option = $optgroup->get_option('compatible_printers_condition'); + $option->full_width(1); + $optgroup->append_single_option_line($option); } } } @@ -1223,6 +1248,12 @@ sub _update { for qw(min_fan_speed disable_fan_first_layers); } +sub OnActivate { + my ($self) = @_; + $self->{volumetric_speed_description_line}->SetText( + Slic3r::GUI::PresetHints::maximum_volumetric_flow_description(wxTheApp->{preset_bundle})); +} + package Slic3r::GUI::Tab::Printer; use base 'Slic3r::GUI::Tab'; use Wx qw(wxTheApp :sizer :button :bitmap :misc :id :icon :dialog); diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 1613b7e45..12ad2f12f 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -65,6 +65,9 @@ sub process { } # G-code export process, running at a background thread. +# The export_gcode may die for various reasons (fails to process output_filename_format, +# write error into the G-code, cannot execute post-processing scripts). +# It is up to the caller to show an error message. sub export_gcode { my $self = shift; my %params = @_; @@ -73,11 +76,12 @@ sub export_gcode { $self->process; # output everything to a G-code file + # The following call may die if the output_filename_format template substitution fails. my $output_file = $self->output_filepath($params{output_file} // ''); $self->status_cb->(90, "Exporting G-code" . ($output_file ? " to $output_file" : "")); - die "G-code export to " . $output_file . " failed\n" - if ! Slic3r::GCode->new->do_export($self, $output_file); + # The following line may die for multiple reasons. + Slic3r::GCode->new->do_export($self, $output_file); # run post-processing scripts if (@{$self->config->post_process}) { @@ -99,6 +103,7 @@ sub export_gcode { } # Export SVG slices for the offline SLA printing. +# The export_svg is expected to be executed inside an eval block. sub export_svg { my $self = shift; my %params = @_; @@ -107,6 +112,7 @@ sub export_svg { my $fh = $params{output_fh}; if (!$fh) { + # The following line may die if the output_filename_format template substitution fails. my $output_file = $self->output_filepath($params{output_file}); $output_file =~ s/\.[gG][cC][oO][dD][eE]$/.svg/; Slic3r::open(\$fh, ">", $output_file) or die "Failed to open $output_file for writing\n"; diff --git a/var/Slic3r-console.ico b/resources/icons/Slic3r-console.ico similarity index 100% rename from var/Slic3r-console.ico rename to resources/icons/Slic3r-console.ico diff --git a/var/Slic3r.icns b/resources/icons/Slic3r.icns similarity index 100% rename from var/Slic3r.icns rename to resources/icons/Slic3r.icns diff --git a/var/Slic3r.ico b/resources/icons/Slic3r.ico similarity index 100% rename from var/Slic3r.ico rename to resources/icons/Slic3r.ico diff --git a/var/Slic3r.png b/resources/icons/Slic3r.png similarity index 100% rename from var/Slic3r.png rename to resources/icons/Slic3r.png diff --git a/var/Slic3r_128px.png b/resources/icons/Slic3r_128px.png similarity index 100% rename from var/Slic3r_128px.png rename to resources/icons/Slic3r_128px.png diff --git a/var/Slic3r_192px.png b/resources/icons/Slic3r_192px.png similarity index 100% rename from var/Slic3r_192px.png rename to resources/icons/Slic3r_192px.png diff --git a/var/Slic3r_192px_transparent.png b/resources/icons/Slic3r_192px_transparent.png similarity index 100% rename from var/Slic3r_192px_transparent.png rename to resources/icons/Slic3r_192px_transparent.png diff --git a/var/add.png b/resources/icons/add.png old mode 100755 new mode 100644 similarity index 100% rename from var/add.png rename to resources/icons/add.png diff --git a/var/application_view_tile.png b/resources/icons/application_view_tile.png old mode 100755 new mode 100644 similarity index 100% rename from var/application_view_tile.png rename to resources/icons/application_view_tile.png diff --git a/var/arrow_down.png b/resources/icons/arrow_down.png similarity index 100% rename from var/arrow_down.png rename to resources/icons/arrow_down.png diff --git a/var/arrow_left.png b/resources/icons/arrow_left.png similarity index 100% rename from var/arrow_left.png rename to resources/icons/arrow_left.png diff --git a/var/arrow_out.png b/resources/icons/arrow_out.png old mode 100755 new mode 100644 similarity index 100% rename from var/arrow_out.png rename to resources/icons/arrow_out.png diff --git a/var/arrow_refresh.png b/resources/icons/arrow_refresh.png old mode 100755 new mode 100644 similarity index 100% rename from var/arrow_refresh.png rename to resources/icons/arrow_refresh.png diff --git a/var/arrow_right.png b/resources/icons/arrow_right.png similarity index 100% rename from var/arrow_right.png rename to resources/icons/arrow_right.png diff --git a/var/arrow_rotate_anticlockwise.png b/resources/icons/arrow_rotate_anticlockwise.png old mode 100755 new mode 100644 similarity index 100% rename from var/arrow_rotate_anticlockwise.png rename to resources/icons/arrow_rotate_anticlockwise.png diff --git a/var/arrow_rotate_clockwise.png b/resources/icons/arrow_rotate_clockwise.png old mode 100755 new mode 100644 similarity index 100% rename from var/arrow_rotate_clockwise.png rename to resources/icons/arrow_rotate_clockwise.png diff --git a/var/arrow_up.png b/resources/icons/arrow_up.png old mode 100755 new mode 100644 similarity index 100% rename from var/arrow_up.png rename to resources/icons/arrow_up.png diff --git a/var/box.png b/resources/icons/box.png old mode 100755 new mode 100644 similarity index 100% rename from var/box.png rename to resources/icons/box.png diff --git a/var/brick.png b/resources/icons/brick.png old mode 100755 new mode 100644 similarity index 100% rename from var/brick.png rename to resources/icons/brick.png diff --git a/var/brick_add.png b/resources/icons/brick_add.png old mode 100755 new mode 100644 similarity index 100% rename from var/brick_add.png rename to resources/icons/brick_add.png diff --git a/var/brick_delete.png b/resources/icons/brick_delete.png old mode 100755 new mode 100644 similarity index 100% rename from var/brick_delete.png rename to resources/icons/brick_delete.png diff --git a/var/brick_go.png b/resources/icons/brick_go.png old mode 100755 new mode 100644 similarity index 100% rename from var/brick_go.png rename to resources/icons/brick_go.png diff --git a/var/bricks.png b/resources/icons/bricks.png old mode 100755 new mode 100644 similarity index 100% rename from var/bricks.png rename to resources/icons/bricks.png diff --git a/var/building.png b/resources/icons/building.png old mode 100755 new mode 100644 similarity index 100% rename from var/building.png rename to resources/icons/building.png diff --git a/var/bullet_arrow_down.png b/resources/icons/bullet_arrow_down.png similarity index 100% rename from var/bullet_arrow_down.png rename to resources/icons/bullet_arrow_down.png diff --git a/var/bullet_arrow_up.png b/resources/icons/bullet_arrow_up.png similarity index 100% rename from var/bullet_arrow_up.png rename to resources/icons/bullet_arrow_up.png diff --git a/var/bullet_black.png b/resources/icons/bullet_black.png old mode 100755 new mode 100644 similarity index 100% rename from var/bullet_black.png rename to resources/icons/bullet_black.png diff --git a/var/bullet_blue.png b/resources/icons/bullet_blue.png old mode 100755 new mode 100644 similarity index 100% rename from var/bullet_blue.png rename to resources/icons/bullet_blue.png diff --git a/var/bullet_green.png b/resources/icons/bullet_green.png old mode 100755 new mode 100644 similarity index 100% rename from var/bullet_green.png rename to resources/icons/bullet_green.png diff --git a/var/bullet_red.png b/resources/icons/bullet_red.png old mode 100755 new mode 100644 similarity index 100% rename from var/bullet_red.png rename to resources/icons/bullet_red.png diff --git a/var/bullet_white.png b/resources/icons/bullet_white.png old mode 100755 new mode 100644 similarity index 100% rename from var/bullet_white.png rename to resources/icons/bullet_white.png diff --git a/var/cog.png b/resources/icons/cog.png old mode 100755 new mode 100644 similarity index 100% rename from var/cog.png rename to resources/icons/cog.png diff --git a/var/cog_go.png b/resources/icons/cog_go.png old mode 100755 new mode 100644 similarity index 100% rename from var/cog_go.png rename to resources/icons/cog_go.png diff --git a/var/control_pause.png b/resources/icons/control_pause.png similarity index 100% rename from var/control_pause.png rename to resources/icons/control_pause.png diff --git a/var/control_pause_blue.png b/resources/icons/control_pause_blue.png similarity index 100% rename from var/control_pause_blue.png rename to resources/icons/control_pause_blue.png diff --git a/var/control_play.png b/resources/icons/control_play.png similarity index 100% rename from var/control_play.png rename to resources/icons/control_play.png diff --git a/var/control_play_blue.png b/resources/icons/control_play_blue.png similarity index 100% rename from var/control_play_blue.png rename to resources/icons/control_play_blue.png diff --git a/var/control_stop.png b/resources/icons/control_stop.png similarity index 100% rename from var/control_stop.png rename to resources/icons/control_stop.png diff --git a/var/control_stop_blue.png b/resources/icons/control_stop_blue.png similarity index 100% rename from var/control_stop_blue.png rename to resources/icons/control_stop_blue.png diff --git a/var/cross.png b/resources/icons/cross.png old mode 100755 new mode 100644 similarity index 100% rename from var/cross.png rename to resources/icons/cross.png diff --git a/var/delete.png b/resources/icons/delete.png old mode 100755 new mode 100644 similarity index 100% rename from var/delete.png rename to resources/icons/delete.png diff --git a/var/disk.png b/resources/icons/disk.png old mode 100755 new mode 100644 similarity index 100% rename from var/disk.png rename to resources/icons/disk.png diff --git a/var/error.png b/resources/icons/error.png old mode 100755 new mode 100644 similarity index 100% rename from var/error.png rename to resources/icons/error.png diff --git a/var/flag-green-icon.png b/resources/icons/flag-green-icon.png similarity index 100% rename from var/flag-green-icon.png rename to resources/icons/flag-green-icon.png diff --git a/var/flag-red-icon.png b/resources/icons/flag-red-icon.png similarity index 100% rename from var/flag-red-icon.png rename to resources/icons/flag-red-icon.png diff --git a/var/funnel.png b/resources/icons/funnel.png similarity index 100% rename from var/funnel.png rename to resources/icons/funnel.png diff --git a/var/hourglass.png b/resources/icons/hourglass.png old mode 100755 new mode 100644 similarity index 100% rename from var/hourglass.png rename to resources/icons/hourglass.png diff --git a/var/house.png b/resources/icons/house.png similarity index 100% rename from var/house.png rename to resources/icons/house.png diff --git a/var/infill.png b/resources/icons/infill.png similarity index 100% rename from var/infill.png rename to resources/icons/infill.png diff --git a/var/joystick.png b/resources/icons/joystick.png old mode 100755 new mode 100644 similarity index 100% rename from var/joystick.png rename to resources/icons/joystick.png diff --git a/var/layers.png b/resources/icons/layers.png old mode 100755 new mode 100644 similarity index 100% rename from var/layers.png rename to resources/icons/layers.png diff --git a/var/lorry_add.png b/resources/icons/lorry_add.png old mode 100755 new mode 100644 similarity index 100% rename from var/lorry_add.png rename to resources/icons/lorry_add.png diff --git a/var/lorry_go.png b/resources/icons/lorry_go.png old mode 100755 new mode 100644 similarity index 100% rename from var/lorry_go.png rename to resources/icons/lorry_go.png diff --git a/var/note.png b/resources/icons/note.png old mode 100755 new mode 100644 similarity index 100% rename from var/note.png rename to resources/icons/note.png diff --git a/var/package.png b/resources/icons/package.png old mode 100755 new mode 100644 similarity index 100% rename from var/package.png rename to resources/icons/package.png diff --git a/var/package_green.png b/resources/icons/package_green.png old mode 100755 new mode 100644 similarity index 100% rename from var/package_green.png rename to resources/icons/package_green.png diff --git a/var/page_white_go.png b/resources/icons/page_white_go.png old mode 100755 new mode 100644 similarity index 100% rename from var/page_white_go.png rename to resources/icons/page_white_go.png diff --git a/var/plugin.png b/resources/icons/plugin.png old mode 100755 new mode 100644 similarity index 100% rename from var/plugin.png rename to resources/icons/plugin.png diff --git a/var/plugin_add.png b/resources/icons/plugin_add.png old mode 100755 new mode 100644 similarity index 100% rename from var/plugin_add.png rename to resources/icons/plugin_add.png diff --git a/var/plugin_go.png b/resources/icons/plugin_go.png old mode 100755 new mode 100644 similarity index 100% rename from var/plugin_go.png rename to resources/icons/plugin_go.png diff --git a/var/printer_empty.png b/resources/icons/printer_empty.png old mode 100755 new mode 100644 similarity index 100% rename from var/printer_empty.png rename to resources/icons/printer_empty.png diff --git a/var/reslice.png b/resources/icons/reslice.png similarity index 100% rename from var/reslice.png rename to resources/icons/reslice.png diff --git a/var/shape_flip_horizontal.png b/resources/icons/shape_flip_horizontal.png old mode 100755 new mode 100644 similarity index 100% rename from var/shape_flip_horizontal.png rename to resources/icons/shape_flip_horizontal.png diff --git a/var/shape_handles.png b/resources/icons/shape_handles.png old mode 100755 new mode 100644 similarity index 100% rename from var/shape_handles.png rename to resources/icons/shape_handles.png diff --git a/var/shape_ungroup.png b/resources/icons/shape_ungroup.png old mode 100755 new mode 100644 similarity index 100% rename from var/shape_ungroup.png rename to resources/icons/shape_ungroup.png diff --git a/var/spool.png b/resources/icons/spool.png similarity index 100% rename from var/spool.png rename to resources/icons/spool.png diff --git a/var/tag_blue.png b/resources/icons/tag_blue.png old mode 100755 new mode 100644 similarity index 100% rename from var/tag_blue.png rename to resources/icons/tag_blue.png diff --git a/var/textfield.png b/resources/icons/textfield.png old mode 100755 new mode 100644 similarity index 100% rename from var/textfield.png rename to resources/icons/textfield.png diff --git a/var/time.png b/resources/icons/time.png old mode 100755 new mode 100644 similarity index 100% rename from var/time.png rename to resources/icons/time.png diff --git a/var/variable_layer_height.png b/resources/icons/variable_layer_height.png similarity index 100% rename from var/variable_layer_height.png rename to resources/icons/variable_layer_height.png diff --git a/var/variable_layer_height_reset.png b/resources/icons/variable_layer_height_reset.png similarity index 100% rename from var/variable_layer_height_reset.png rename to resources/icons/variable_layer_height_reset.png diff --git a/var/variable_layer_height_tooltip.png b/resources/icons/variable_layer_height_tooltip.png similarity index 100% rename from var/variable_layer_height_tooltip.png rename to resources/icons/variable_layer_height_tooltip.png diff --git a/var/wand.png b/resources/icons/wand.png similarity index 100% rename from var/wand.png rename to resources/icons/wand.png diff --git a/var/wrench.png b/resources/icons/wrench.png old mode 100755 new mode 100644 similarity index 100% rename from var/wrench.png rename to resources/icons/wrench.png diff --git a/var/zoom.png b/resources/icons/zoom.png old mode 100755 new mode 100644 similarity index 100% rename from var/zoom.png rename to resources/icons/zoom.png diff --git a/resources/profiles/Original Prusa i3 MK3, MK2S, MK2 and MK2S-MMU.ini b/resources/profiles/Original Prusa i3 MK3, MK2S, MK2 and MK2S-MMU.ini new file mode 100644 index 000000000..cb076ac35 --- /dev/null +++ b/resources/profiles/Original Prusa i3 MK3, MK2S, MK2 and MK2S-MMU.ini @@ -0,0 +1,3681 @@ +# generated by Slic3r Prusa Edition 1.38.4 on 2017-12-19 at 17:08:04 + +[print:0.05mm DETAIL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 10 +bridge_acceleration = 300 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 +complete_objects = 0 +default_acceleration = 500 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 20 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 25% +fill_pattern = cubic +first_layer_acceleration = 500 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 20 +gcode_comments = 0 +infill_acceleration = 800 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.5 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 30 +interface_shells = 0 +layer_height = 0.05 +max_print_speed = 80 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 300 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 30 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 15 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 30 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.3 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1.5 +support_material_speed = 30 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 20 +top_solid_layers = 15 +travel_speed = 180 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.05mm DETAIL 0.25 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 10 +bridge_acceleration = 300 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1 +complete_objects = 0 +default_acceleration = 500 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0 +external_perimeter_speed = 20 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.28 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 500 +first_layer_extrusion_width = 0.3 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 20 +gcode_comments = 0 +infill_acceleration = 800 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 20 +interface_shells = 0 +layer_height = 0.05 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 300 +perimeter_extruder = 1 +perimeter_extrusion_width = 0 +perimeter_speed = 20 +perimeters = 4 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 10 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0 +solid_infill_speed = 20 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.18 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1 +support_material_speed = 20 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0 +top_solid_infill_speed = 20 +top_solid_layers = 15 +travel_speed = 200 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.05mm DETAIL MK3] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 10 +bridge_acceleration = 300 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ +complete_objects = 0 +default_acceleration = 500 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 20 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 25% +fill_pattern = cubic +first_layer_acceleration = 500 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 20 +gcode_comments = 0 +infill_acceleration = 800 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.5 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 30 +interface_shells = 0 +layer_height = 0.05 +max_print_speed = 80 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 300 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 30 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 15 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 30 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.3 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1.5 +support_material_speed = 30 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 20 +top_solid_layers = 15 +travel_speed = 180 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.10mm DETAIL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 7 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.1 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 50 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 50 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 40 +top_solid_layers = 9 +travel_speed = 120 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.10mm DETAIL 0.25 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 7 +bridge_acceleration = 600 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.25 +external_perimeter_speed = 20 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.25 +fill_angle = 45 +fill_density = 15% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.25 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 1600 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.25 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 40 +interface_shells = 0 +layer_height = 0.1 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 600 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.25 +perimeter_speed = 25 +perimeters = 4 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 10 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.25 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.18 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.25 +top_solid_infill_speed = 30 +top_solid_layers = 9 +travel_speed = 120 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.10mm DETAIL MK3] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 30 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 3500 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 35% +infill_speed = 200 +interface_shells = 0 +layer_height = 0.1 +max_print_speed = 250 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 200 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 +top_solid_layers = 5 +travel_speed = 250 +wipe_tower = 0 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm 100mms Linear Advance] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 50 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 100 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 150 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 30 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 100 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 60 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 70 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 5 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 50 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 50 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 40 +top_solid_layers = 7 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL 0.25 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 5 +bridge_acceleration = 600 +bridge_angle = 0 +bridge_flow_ratio = 0.7 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.25 +external_perimeter_speed = 20 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.25 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.25 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 1600 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.25 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 40 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 600 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.25 +perimeter_speed = 25 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 10 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.25 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.2 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 0 +support_material_interface_spacing = 0.15 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 1 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 35 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.25 +top_solid_infill_speed = 30 +top_solid_layers = 7 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL 0.6 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 5 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.61 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.67 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.65 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.75 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.65 +perimeter_speed = 50 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 50 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.6 +top_solid_infill_speed = 40 +top_solid_layers = 7 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL MK3] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 30 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 3500 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 35% +infill_speed = 200 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 250 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 200 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 +top_solid_layers = 5 +travel_speed = 250 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL SOLUBLE FULL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 5 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 25 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 40 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 4 +support_material_extrusion_width = 0.45 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.1 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 1 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 +top_solid_layers = 7 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.15mm OPTIMAL SOLUBLE INTERFACE] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 5 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 25 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.15 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 40 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.45 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 3 +support_material_interface_spacing = 0.1 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 0 +support_material_xy_spacing = 120% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 30 +top_solid_layers = 7 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm 100mms Linear Advance] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 50 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 100 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 150 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 30 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 100 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 60 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 70 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm NORMAL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 50 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 50 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 40 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm NORMAL 0.6 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.61 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.67 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.65 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.75 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.65 +perimeter_speed = 50 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 50 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.6 +top_solid_infill_speed = 40 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm NORMAL MK3] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 30 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 3500 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 35% +infill_speed = 200 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 250 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 200 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 50 +top_solid_layers = 5 +travel_speed = 250 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm NORMAL SOLUBLE FULL] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 30 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 40 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 4 +support_material_extrusion_width = 0.45 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.1 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 1 +support_material_xy_spacing = 120% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 30 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.20mm NORMAL SOLUBLE INTERFACE] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.45 +external_perimeter_speed = 30 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.45 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.2 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 40 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.45 +solid_infill_speed = 40 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.45 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 3 +support_material_interface_spacing = 0.1 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 0 +support_material_xy_spacing = 120% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.4 +top_solid_infill_speed = 30 +top_solid_layers = 5 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.35mm FAST] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 3 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.95 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.7 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.35 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.43 +perimeter_speed = 50 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.7 +solid_infill_speed = 60 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 1 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.43 +top_solid_infill_speed = 50 +top_solid_layers = 4 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.35mm FAST 0.6 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 7 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.61 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.67 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.65 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.75 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.35 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.65 +perimeter_speed = 50 +perimeters = 3 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 60 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 1 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.6 +top_solid_infill_speed = 50 +top_solid_layers = 9 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.35mm FAST MK3] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 4 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 30 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 40 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.45 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.42 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 3500 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.7 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 35% +infill_speed = 200 +interface_shells = 0 +layer_height = 0.35 +max_print_speed = 250 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 0 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.45 +perimeter_speed = 60 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 1 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.7 +solid_infill_speed = 200 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 0 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0.15 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.35 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 0 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 0 +support_material_threshold = 45 +support_material_with_sheath = 0 +support_material_xy_spacing = 60% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.45 +top_solid_infill_speed = 50 +top_solid_layers = 4 +travel_speed = 250 +wipe_tower = 1 +wipe_tower_per_color_wipe = 15 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.35mm FAST sol full 0.6 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 3 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 30 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.67 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.65 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.75 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.35 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.65 +perimeter_speed = 40 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 60 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 4 +support_material_extrusion_width = 0.55 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 3 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 0 +support_material_xy_spacing = 120% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.57 +top_solid_infill_speed = 50 +top_solid_layers = 4 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[print:0.35mm FAST sol int 0.6 nozzle] +avoid_crossing_perimeters = 0 +bottom_solid_layers = 3 +bridge_acceleration = 1000 +bridge_angle = 0 +bridge_flow_ratio = 0.8 +bridge_speed = 20 +brim_width = 0 +clip_multipart_objects = 1 +compatible_printers = +compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1 +complete_objects = 0 +default_acceleration = 1000 +dont_support_bridges = 1 +elefant_foot_compensation = 0 +ensure_vertical_shell_thickness = 1 +external_fill_pattern = rectilinear +external_perimeter_extrusion_width = 0.6 +external_perimeter_speed = 30 +external_perimeters_first = 0 +extra_perimeters = 0 +extruder_clearance_height = 20 +extruder_clearance_radius = 20 +extrusion_width = 0.67 +fill_angle = 45 +fill_density = 20% +fill_pattern = cubic +first_layer_acceleration = 1000 +first_layer_extrusion_width = 0.65 +first_layer_height = 0.2 +first_layer_speed = 30 +gap_fill_speed = 40 +gcode_comments = 0 +infill_acceleration = 2000 +infill_every_layers = 1 +infill_extruder = 1 +infill_extrusion_width = 0.75 +infill_first = 0 +infill_only_where_needed = 0 +infill_overlap = 25% +infill_speed = 60 +interface_shells = 0 +layer_height = 0.35 +max_print_speed = 100 +max_volumetric_extrusion_rate_slope_negative = 0 +max_volumetric_extrusion_rate_slope_positive = 0 +max_volumetric_speed = 0 +min_skirt_length = 4 +notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder +only_retract_when_crossing_perimeters = 0 +ooze_prevention = 0 +output_filename_format = [input_filename_base].gcode +overhangs = 1 +perimeter_acceleration = 800 +perimeter_extruder = 1 +perimeter_extrusion_width = 0.65 +perimeter_speed = 40 +perimeters = 2 +post_process = +print_settings_id = +raft_layers = 0 +resolution = 0 +seam_position = nearest +skirt_distance = 2 +skirt_height = 3 +skirts = 0 +small_perimeter_speed = 20 +solid_infill_below_area = 0 +solid_infill_every_layers = 0 +solid_infill_extruder = 1 +solid_infill_extrusion_width = 0.65 +solid_infill_speed = 60 +spiral_vase = 0 +standby_temperature_delta = -5 +support_material = 1 +support_material_angle = 0 +support_material_buildplate_only = 0 +support_material_contact_distance = 0 +support_material_enforce_layers = 0 +support_material_extruder = 0 +support_material_extrusion_width = 0.55 +support_material_interface_contact_loops = 0 +support_material_interface_extruder = 4 +support_material_interface_layers = 2 +support_material_interface_spacing = 0.2 +support_material_interface_speed = 100% +support_material_pattern = rectilinear +support_material_spacing = 2 +support_material_speed = 50 +support_material_synchronize_layers = 1 +support_material_threshold = 80 +support_material_with_sheath = 0 +support_material_xy_spacing = 150% +thin_walls = 0 +threads = 4 +top_infill_extrusion_width = 0.57 +top_solid_infill_speed = 50 +top_solid_layers = 4 +travel_speed = 120 +wipe_tower = 1 +wipe_tower_per_color_wipe = 20 +wipe_tower_width = 60 +wipe_tower_x = 180 +wipe_tower_y = 140 +xy_size_compensation = 0 + +[filament:ColorFabb Brass Bronze 1.75mm] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = nozzle_diameter[0]>0.35 +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1.3 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #804040 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 210 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 210 + +[filament:ColorFabb HT 1.75mm] +bed_temperature = 105 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 105 +first_layer_temperature = 270 +max_fan_speed = 20 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 270 + +[filament:ColorFabb PLA-PHA] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF3232 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 15 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 210 + +[filament:ColorFabb Woodfil 1.75mm] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = nozzle_diameter[0]>0.35 +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1.2 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #804040 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 200 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 200 + +[filament:ColorFabb XT 1.75mm] +bed_temperature = 65 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 50 +min_fan_speed = 30 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:ColorFabb XT-CF20 1.75mm] +bed_temperature = 90 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1.2 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #804040 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 1 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +max_fan_speed = 50 +min_fan_speed = 30 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 260 + +[filament:ColorFabb nGen 1.75mm] +bed_temperature = 85 +bridge_fan_speed = 40 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = NGEN +first_layer_bed_temperature = 85 +first_layer_temperature = 240 +max_fan_speed = 35 +min_fan_speed = 20 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:ColorFabb nGen flex] +bed_temperature = 85 +bridge_fan_speed = 40 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 10 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 5 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = FLEX +first_layer_bed_temperature = 85 +first_layer_temperature = 260 +max_fan_speed = 35 +min_fan_speed = 20 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 260 + +[filament:E3D Edge] +bed_temperature = 90 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 85 +first_layer_temperature = 230 +max_fan_speed = 50 +min_fan_speed = 30 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:E3D PC-ABS 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 100 +first_layer_temperature = 270 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 270 + +[filament:Fillamentum ABS 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = ABS +first_layer_bed_temperature = 100 +first_layer_temperature = 240 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 240 + +[filament:Fillamentum ASA 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 100 +first_layer_temperature = 265 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 265 + +[filament:Fillamentum CPE HG100 HM100] +bed_temperature = 90 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "CPE HG100 , CPE HM100" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 90 +first_layer_temperature = 260 +max_fan_speed = 80 +min_fan_speed = 80 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 260 + +[filament:Fillamentum Timberfil] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = nozzle_diameter[0]>0.35 +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1.2 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #804040 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 190 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 190 + +[filament:Generic ABS 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" +filament_settings_id = +filament_soluble = 0 +filament_type = ABS +first_layer_bed_temperature = 100 +first_layer_temperature = 255 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 255 + +[filament:Generic PET 1.75mm] +bed_temperature = 90 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 85 +first_layer_temperature = 230 +max_fan_speed = 50 +min_fan_speed = 30 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:Generic PLA 1.75mm] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF3232 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 15 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 210 + +[filament:Polymaker PC-Max] +bed_temperature = 120 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" +filament_settings_id = +filament_soluble = 0 +filament_type = ABS +first_layer_bed_temperature = 120 +first_layer_temperature = 270 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 270 + +[filament:Primavalue PVA] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #FFFFD7 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PVA print settings for MK2:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH" +filament_settings_id = +filament_soluble = 1 +filament_type = PVA +first_layer_bed_temperature = 60 +first_layer_temperature = 195 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 195 + +[filament:Prusa ABS 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 30 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #3A80CA +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "List of materials tested with standart ABS print settings for MK2:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladeč ABS" +filament_settings_id = +filament_soluble = 0 +filament_type = ABS +first_layer_bed_temperature = 100 +first_layer_temperature = 255 +max_fan_speed = 30 +min_fan_speed = 10 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 255 + +[filament:Prusa HIPS 1.75mm] +bed_temperature = 100 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 0.9 +fan_always_on = 1 +fan_below_layer_time = 10 +filament_colour = #FFFFD7 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 13 +filament_notes = "" +filament_settings_id = +filament_soluble = 1 +filament_type = HIPS +first_layer_bed_temperature = 100 +first_layer_temperature = 220 +max_fan_speed = 20 +min_fan_speed = 20 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[filament:Prusa PET 1.75mm] +bed_temperature = 90 +bridge_fan_speed = 50 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "List of manufacturers tested with standart PET print settings for MK2:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladeč PETG" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 85 +first_layer_temperature = 230 +max_fan_speed = 50 +min_fan_speed = 30 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode" +temperature = 240 + +[filament:Prusa PLA 1.75mm] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #FF3232 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 15 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 210 + +[filament:SemiFlex or Flexfill 98A] +bed_temperature = 50 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 +cooling = 0 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1.2 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #00CA0A +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 2.5 +filament_notes = "List of materials tested with FLEX print settings & FLEX material settings for MK2:\n\nFillamentum Flex 98A\nFillamentum Flex 92A\nPlasty Mladeč PP\nPlasty Mladeč TPE32 \nPlasty Mladeč TPE88" +filament_settings_id = +filament_soluble = 0 +filament_type = FLEX +first_layer_bed_temperature = 50 +first_layer_temperature = 220 +max_fan_speed = 90 +min_fan_speed = 70 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 230 + +[filament:Taulman Bridge 1.75mm] +bed_temperature = 50 +bridge_fan_speed = 40 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #DEE0E6 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 250 + +[filament:Taulman T-Glase 1.75mm] +bed_temperature = 90 +bridge_fan_speed = 40 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 3 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 20 +filament_colour = #FF8000 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "" +filament_settings_id = +filament_soluble = 0 +filament_type = PET +first_layer_bed_temperature = 90 +first_layer_temperature = 240 +max_fan_speed = 5 +min_fan_speed = 0 +min_print_speed = 5 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode" +temperature = 240 + +[filament:Verbatim BVOH] +bed_temperature = 60 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 0 +disable_fan_first_layers = 1 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 0 +fan_below_layer_time = 100 +filament_colour = #FFFFD7 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 10 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH" +filament_settings_id = +filament_soluble = 1 +filament_type = PLA +first_layer_bed_temperature = 60 +first_layer_temperature = 215 +max_fan_speed = 100 +min_fan_speed = 85 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 210 + +[filament:Verbatim PP] +bed_temperature = 100 +bridge_fan_speed = 100 +compatible_printers = +compatible_printers_condition = +cooling = 1 +disable_fan_first_layers = 2 +end_filament_gcode = "; Filament-specific end gcode" +extrusion_multiplier = 1 +fan_always_on = 1 +fan_below_layer_time = 100 +filament_colour = #DEE0E6 +filament_cost = 0 +filament_density = 0 +filament_diameter = 1.75 +filament_max_volumetric_speed = 5 +filament_notes = "List of materials tested with standart PLA print settings for MK2:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladeč PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA" +filament_settings_id = +filament_soluble = 0 +filament_type = PLA +first_layer_bed_temperature = 100 +first_layer_temperature = 220 +max_fan_speed = 100 +min_fan_speed = 100 +min_print_speed = 15 +slowdown_below_layer_time = 10 +start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode" +temperature = 220 + +[printer:Original Prusa i3 MK2] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n +printer_settings_id = +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 0.8 +retract_length_toolchange = 3 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 35 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 0.25 nozzle] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.1 +min_layer_height = 0.05 +nozzle_diameter = 0.25 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n +printer_settings_id = +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 1 +retract_length_toolchange = 3 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 50 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 0 +wipe = 1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 0.6 nozzle] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.35 +min_layer_height = 0.1 +nozzle_diameter = 0.6 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\n +printer_settings_id = +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 0.8 +retract_length_toolchange = 3 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 35 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 MM Single Mode] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 50 +end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n +extruder_colour = #FFAA55 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +printer_settings_id = +retract_before_travel = 3 +retract_before_wipe = 0% +retract_layer_change = 0 +retract_length = 4 +retract_length_toolchange = 6 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 80 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 1 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 MM Single Mode 0.6 nozzle] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 50 +end_gcode = G1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n +extruder_colour = #FFAA55 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.6 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +printer_settings_id = +retract_before_travel = 3 +retract_before_wipe = 0% +retract_layer_change = 0 +retract_length = 4 +retract_length_toolchange = 6 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 199 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 80 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 1 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT?\nM104 S[first_layer_temperature]\nM140 S[first_layer_bed_temperature]\nM109 S[first_layer_temperature]\nM190 S[first_layer_bed_temperature]\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 MultiMaterial] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 50,50,50,50 +end_gcode = {if not has_wipe_tower}\n; Pull the filament into the cooling tubes.\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors +extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259 +extruder_offset = 0x0,0x0,0x0,0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25,0.25,0.25,0.25 +min_layer_height = 0.07,0.07,0.07,0.07 +nozzle_diameter = 0.4,0.4,0.4,0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +printer_settings_id = +retract_before_travel = 3,3,3,3 +retract_before_wipe = 60%,60%,60%,60% +retract_layer_change = 0,0,0,0 +retract_length = 4,4,4,4 +retract_length_toolchange = 4,4,4,4 +retract_lift = 0.6,0.6,0.6,0.6 +retract_lift_above = 0,0,0,0 +retract_lift_below = 199,199,199,199 +retract_restart_extra = 0,0,0,0 +retract_restart_extra_toolchange = 0,0,0,0 +retract_speed = 80,80,80,80 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 1 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100 ; set max feedrate\nM92 E140 ; E-steps per filament milimeter\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 0 +wipe = 1,1,1,1 +z_offset = 0 + +[printer:Original Prusa i3 MK2 MultiMaterial 0.6 nozzle] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 50,50,50,50 +end_gcode = {if not has_wipe_tower}\nG1 E-4 F2100.00000\nG91\nG1 Z1 F7200.000\nG90\nG1 X245 Y1\nG1 X240 E4\nG1 F4000\nG1 X190 E2.7 \nG1 F4600\nG1 X110 E2.8\nG1 F5200\nG1 X40 E3 \nG1 E-15.0000 F5000\nG1 E-50.0000 F5400\nG1 E-15.0000 F3000\nG1 E-12.0000 F2000\nG1 F1600\nG1 X0 Y1 E3.0000\nG1 X50 Y1 E-5.0000\nG1 F2000\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-5.0000\nG1 F2400\nG1 X0 Y1 E5.0000\nG1 X50 Y1 E-3.0000\nG4 S0\n{endif}\nM107 ; fan off\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n +extruder_colour = #FFAA55;#5182DB;#4ECDD3;#FB7259 +extruder_offset = 0x0,0x0,0x0,0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25,0.25,0.25,0.25 +min_layer_height = 0.07,0.07,0.07,0.07 +nozzle_diameter = 0.6,0.6,0.6,0.6 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK2\nPRINTER_HAS_BOWDEN +printer_settings_id = +retract_before_travel = 3,3,3,3 +retract_before_wipe = 60%,60%,60%,60% +retract_layer_change = 0,0,0,0 +retract_length = 4,4,4,4 +retract_length_toolchange = 4,4,4,4 +retract_lift = 0.6,0.6,0.6,0.6 +retract_lift_above = 0,0,0,0 +retract_lift_below = 199,199,199,199 +retract_restart_extra = 0,0,0,0 +retract_restart_extra_toolchange = 0,0,0,0 +retract_speed = 80,80,80,80 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 1 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\n; Start G-Code sequence START\nT[initial_tool]\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG21 ; set units to millimeters\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG28 W\nG80\nG92 E0.0\nM203 E100\nM92 E140\n{if not has_wipe_tower}\nG1 Z0.250 F7200.000\nG1 X50.0 E80.0 F1000.0\nG1 X160.0 E20.0 F1000.0\nG1 Z0.200 F7200.000\nG1 X220.0 E13 F1000.0\nG1 X240.0 E0 F1000.0\nG1 E-4 F1000.0\n{endif}\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 0 +wipe = 1,1,1,1 +z_offset = 0 + +[printer:Original Prusa i3 MK3] +bed_shape = 0x0,250x0,250x210,0x210 +before_layer_gcode = ;BEFORE_LAYER_CHANGE\n;[layer_z]\n\n +between_objects_gcode = +deretract_speed = 0 +end_gcode = G4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors +extruder_colour = #FFFF00 +extruder_offset = 0x0 +gcode_flavor = reprap +layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z] +max_layer_height = 0.25 +min_layer_height = 0.07 +nozzle_diameter = 0.4 +octoprint_apikey = +octoprint_host = +printer_notes = Don't remove the following keywords! These keywords are used in the "compatible printer" condition of the print and filament profiles to link the particular print and filament profiles to this printer profile.\nPRINTER_VENDOR_PRUSA3D\nPRINTER_MODEL_MK3\n +retract_before_travel = 1 +retract_before_wipe = 0% +retract_layer_change = 1 +retract_length = 0.8 +retract_length_toolchange = 3 +retract_lift = 0.6 +retract_lift_above = 0 +retract_lift_below = 209 +retract_restart_extra = 0 +retract_restart_extra_toolchange = 0 +retract_speed = 35 +serial_port = +serial_speed = 250000 +single_extruder_multi_material = 0 +start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM83 ; extruder relative mode\nM104 S[first_layer_temperature] ; set extruder temp\nM140 S[first_layer_bed_temperature] ; set bed temp\nM190 S[first_layer_bed_temperature] ; wait for bed temp\nM109 S[first_layer_temperature] ; wait for extruder temp\nG28 W ; home all without mesh bed level\nG80 ; mesh bed leveling\nG1 Y-3.0 F1000.0 ; go outside print area\nG92 E0.0\nG1 X60.0 E9.0 F1000.0 ; intro line\nG1 X100.0 E12.5 F1000.0 ; intro line\nG92 E0.0 +toolchange_gcode = +use_firmware_retraction = 0 +use_relative_e_distances = 1 +use_volumetric_e = 0 +variable_layer_height = 1 +wipe = 1 +z_offset = 0 + +[presets] +print = 0.15mm 100mms Linear Advance +printer = Original Prusa i3 MK2 +filament = Prusa PLA 1.75mm diff --git a/slic3r.pl b/slic3r.pl index e49457c20..a3cc3cfc2 100755 --- a/slic3r.pl +++ b/slic3r.pl @@ -31,6 +31,7 @@ my %cli_options = (); 'debug' => \$Slic3r::debug, 'gui' => \$opt{gui}, + 'no-gui' => \$opt{no_gui}, 'o|output=s' => \$opt{output}, 'save=s' => \$opt{save}, @@ -70,10 +71,10 @@ my @external_configs = (); if ($opt{load}) { foreach my $configfile (@{$opt{load}}) { if (-e $configfile) { - push @external_configs, Slic3r::Config->load($configfile); + push @external_configs, Slic3r::Config::load($configfile); } elsif (-e "$FindBin::Bin/$configfile") { printf STDERR "Loading $FindBin::Bin/$configfile\n"; - push @external_configs, Slic3r::Config->load("$FindBin::Bin/$configfile"); + push @external_configs, Slic3r::Config::load("$FindBin::Bin/$configfile"); } else { $opt{ignore_nonexistent_config} or die "Cannot find specified configuration file ($configfile).\n"; } @@ -102,7 +103,7 @@ $config->apply($cli_config); # launch GUI my $gui; -if ((!@ARGV || $opt{gui}) && !$opt{save} && eval "require Slic3r::GUI; 1") { +if ((!@ARGV || $opt{gui}) && !$opt{no_gui} && !$opt{save} && eval "require Slic3r::GUI; 1") { { no warnings 'once'; $Slic3r::GUI::datadir = Slic3r::decode_path($opt{datadir} // ''); @@ -218,6 +219,8 @@ if (@ARGV) { # slicing from command line $sprint->export_svg; } else { my $t0 = [gettimeofday]; + # The following call may die if the output_filename_format template substitution fails, + # if the file cannot be written into, or if the post processing scripts cannot be executed. $sprint->export_gcode; # output some statistics @@ -267,6 +270,8 @@ Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ... --gui Forces the GUI launch instead of command line slicing (if you supply a model file, it will be loaded into the plater) --no-plater Disable the plater tab + --no-gui Forces the command line slicing instead of gui. + This takes precedence over --gui if both are present. --autosave Automatically export current configuration to the specified file Output options: diff --git a/t/custom_gcode.t b/t/custom_gcode.t index 1ccf738aa..5d3602483 100644 --- a/t/custom_gcode.t +++ b/t/custom_gcode.t @@ -1,4 +1,4 @@ -use Test::More tests => 49; +use Test::More tests => 71; use strict; use warnings; @@ -47,9 +47,13 @@ use Slic3r::Test; { my $parser = Slic3r::GCode::PlaceholderParser->new; - $parser->apply_config(my $config = Slic3r::Config::new_from_defaults); + my $config = Slic3r::Config::new_from_defaults; + $config->set('printer_notes', ' PRINTER_VENDOR_PRUSA3D PRINTER_MODEL_MK2 '); + $config->set('nozzle_diameter', [0.6, 0.6, 0.6, 0.6]); + $parser->apply_config($config); $parser->set('foo' => 0); $parser->set('bar' => 2); + $parser->set('num_extruders' => 4); is $parser->process('[temperature_[foo]]'), $config->temperature->[0], "nested config options (legacy syntax)"; @@ -67,6 +71,32 @@ use Slic3r::Test; is $parser->process('{2*foo*(3-12)}'), '0', 'math: 2*foo*(3-12)'; is $parser->process('{2*bar*(3-12)}'), '-36', 'math: 2*bar*(3-12)'; ok abs($parser->process('{2.5*bar*(3-12)}') - -45) < 1e-7, 'math: 2.5*bar*(3-12)'; + + # Test the boolean expression parser. + is $parser->evaluate_boolean_expression('12 == 12'), 1, 'boolean expression parser: 12 == 12'; + is $parser->evaluate_boolean_expression('12 != 12'), 0, 'boolean expression parser: 12 != 12'; + is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PATTERN.*/'), 1, 'boolean expression parser: regex matches'; + is $parser->evaluate_boolean_expression('"has some PATTERN embedded" =~ /.*PTRN.*/'), 0, 'boolean expression parser: regex does not match'; + is $parser->evaluate_boolean_expression('foo + 2 == bar'), 1, 'boolean expression parser: accessing variables, equal'; + is $parser->evaluate_boolean_expression('foo + 3 == bar'), 0, 'boolean expression parser: accessing variables, not equal'; + + is $parser->evaluate_boolean_expression('(12 == 12) and (13 != 14)'), 1, 'boolean expression parser: (12 == 12) and (13 != 14)'; + is $parser->evaluate_boolean_expression('(12 == 12) && (13 != 14)'), 1, 'boolean expression parser: (12 == 12) && (13 != 14)'; + is $parser->evaluate_boolean_expression('(12 == 12) or (13 == 14)'), 1, 'boolean expression parser: (12 == 12) or (13 == 14)'; + is $parser->evaluate_boolean_expression('(12 == 12) || (13 == 14)'), 1, 'boolean expression parser: (12 == 12) || (13 == 14)'; + is $parser->evaluate_boolean_expression('(12 == 12) and not (13 == 14)'), 1, 'boolean expression parser: (12 == 12) and not (13 == 14)'; + is $parser->evaluate_boolean_expression('(12 == 12) ? (1 - 1 == 0) : (2 * 2 == 3)'), 1, 'boolean expression parser: ternary true'; + is $parser->evaluate_boolean_expression('(12 == 21/2) ? (1 - 1 == 0) : (2 * 2 == 3)'), 0, 'boolean expression parser: ternary false'; + is $parser->evaluate_boolean_expression('(12 == 13) ? (1 - 1 == 3) : (2 * 2 == 4)"'), 1, 'boolean expression parser: ternary false'; + is $parser->evaluate_boolean_expression('(12 == 2 * 6) ? (1 - 1 == 3) : (2 * 2 == 4)"'), 0, 'boolean expression parser: ternary true'; + is $parser->evaluate_boolean_expression('12 < 3'), 0, 'boolean expression parser: lower than - false'; + is $parser->evaluate_boolean_expression('12 < 22'), 1, 'boolean expression parser: lower than - true'; + is $parser->evaluate_boolean_expression('12 > 3'), 1, 'boolean expression parser: lower than - true'; + is $parser->evaluate_boolean_expression('12 > 22'), 0, 'boolean expression parser: lower than - false'; + + is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1'), 1, 'complex expression'; + is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.6 and num_extruders>1)'), 1, 'complex expression2'; + is $parser->evaluate_boolean_expression('printer_notes=~/.*PRINTER_VEwerfNDOR_PRUSA3D.*/ or printer_notes=~/.*PRINTertER_MODEL_MK2.*/ or (nozzle_diameter[0]==0.3 and num_extruders>1)'), 0, 'complex expression3'; } { diff --git a/utils/view-toolpaths.pl b/utils/view-toolpaths.pl index 234a8123d..e064885ca 100755 --- a/utils/view-toolpaths.pl +++ b/utils/view-toolpaths.pl @@ -35,7 +35,7 @@ my %opt = (); # load config my $config = Slic3r::Config::new_from_defaults; if ($opt{load}) { - $config->apply(Slic3r::Config->load($opt{load})); + $config->apply(Slic3r::Config::load($opt{load})); } # init print diff --git a/xs/CMakeLists.txt b/xs/CMakeLists.txt index 07442f248..2f8eb14c5 100644 --- a/xs/CMakeLists.txt +++ b/xs/CMakeLists.txt @@ -440,7 +440,7 @@ if(SLIC3R_STATIC) # Use boost libraries linked statically to the C++ runtime. # set(Boost_USE_STATIC_RUNTIME ON) endif() -find_package(Boost REQUIRED COMPONENTS system filesystem thread log locale) +find_package(Boost REQUIRED COMPONENTS system filesystem thread log locale regex) if(Boost_FOUND) include_directories(${Boost_INCLUDE_DIRS}) target_link_libraries(XS ${Boost_LIBRARIES}) diff --git a/xs/src/libslic3r/Config.cpp b/xs/src/libslic3r/Config.cpp index d7671c82f..728ed608b 100644 --- a/xs/src/libslic3r/Config.cpp +++ b/xs/src/libslic3r/Config.cpp @@ -243,7 +243,7 @@ bool ConfigBase::set_deserialize_raw(const t_config_option_key &opt_key_src, con for (const auto &opt : def->options) { for (const t_config_option_key &opt_key2 : opt.second.aliases) { if (opt_key2 == opt_key) { - opt_key = opt_key2; + opt_key = opt.first; optdef = &opt.second; break; } diff --git a/xs/src/libslic3r/GCode.cpp b/xs/src/libslic3r/GCode.cpp index ff144610e..47695a230 100644 --- a/xs/src/libslic3r/GCode.cpp +++ b/xs/src/libslic3r/GCode.cpp @@ -30,6 +30,13 @@ #include namespace Slic3r { + +// Only add a newline in case the current G-code does not end with a newline. +static inline void check_add_eol(std::string &gcode) +{ + if (! gcode.empty() && gcode.back() != '\n') + gcode += '\n'; +} // Plan a travel move while minimizing the number of perimeter crossings. // point is in unscaled coordinates, in the coordinate system of the current active object @@ -157,6 +164,8 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T { std::string gcode; + // Disable linear advance for the wipe tower operations. + gcode += "M900 K0\n"; // Move over the wipe tower. // Retract for a tool change, using the toolchange retract value and setting the priming extra length. gcode += gcodegen.retract(true); @@ -173,6 +182,15 @@ std::string WipeTowerIntegration::append_tcr(GCode &gcodegen, const WipeTower::T // Let the m_writer know the current extruder_id, but ignore the generated G-code. if (new_extruder_id >= 0 && gcodegen.writer().need_toolchange(new_extruder_id)) gcodegen.writer().toolchange(new_extruder_id); + // Always append the filament start G-code even if the extruder did not switch, + // because the wipe tower resets the linear advance and we want it to be re-enabled. + const std::string &start_filament_gcode = gcodegen.config().start_filament_gcode.get_at(new_extruder_id); + if (! start_filament_gcode.empty()) { + // Process the start_filament_gcode for the active filament only. + gcodegen.placeholder_parser().set("current_extruder", new_extruder_id); + gcode += gcodegen.placeholder_parser_process("start_filament_gcode", start_filament_gcode, new_extruder_id); + check_add_eol(gcode); + } // A phony move to the end position at the wipe tower. gcodegen.writer().travel_to_xy(Pointf(tcr.end_pos.x, tcr.end_pos.y)); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, tcr.end_pos)); @@ -199,15 +217,18 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen) std::string gcode; if (&m_priming != nullptr && ! m_priming.extrusions.empty()) { + // Disable linear advance for the wipe tower operations. + gcode += "M900 K0\n"; // Let the tool change be executed by the wipe tower class. // Inform the G-code writer about the changes done behind its back. gcode += m_priming.gcode; // Let the m_writer know the current extruder_id, but ignore the generated G-code. - gcodegen.writer().toolchange(m_priming.extrusions.back().tool); + unsigned int current_extruder_id = m_priming.extrusions.back().tool; + gcodegen.writer().toolchange(current_extruder_id); + gcodegen.placeholder_parser().set("current_extruder", current_extruder_id); // A phony move to the end position at the wipe tower. gcodegen.writer().travel_to_xy(Pointf(m_priming.end_pos.x, m_priming.end_pos.y)); gcodegen.set_last_pos(wipe_tower_point_to_object_point(gcodegen, m_priming.end_pos)); - // Prepare a future wipe. gcodegen.m_wipe.path.points.clear(); // Start the wipe at the current position. @@ -220,19 +241,6 @@ std::string WipeTowerIntegration::prime(GCode &gcodegen) return gcode; } -std::string WipeTowerIntegration::prime_single_color_print(const Print & /* print */, unsigned int initial_tool, GCode & /* gcodegen */) -{ - std::string gcode = "\ -G1 Z0.250 F7200.000\n\ -G1 X50.0 E80.0 F1000.0\n\ -G1 X160.0 E20.0 F1000.0\n\ -G1 Z0.200 F7200.000\n\ -G1 X220.0 E13 F1000.0\n\ -G1 X240.0 E0 F1000.0\n\ -G1 E-4 F1000.0\n"; - return gcode; -} - std::string WipeTowerIntegration::tool_change(GCode &gcodegen, int extruder_id, bool finish_layer) { std::string gcode; @@ -354,7 +362,7 @@ std::vector>> GCode::collec return layers_to_print; } -bool GCode::do_export(Print *print, const char *path) +void GCode::do_export(Print *print, const char *path) { // Remove the old g-code if it exists. boost::nowide::remove(path); @@ -364,23 +372,36 @@ bool GCode::do_export(Print *print, const char *path) FILE *file = boost::nowide::fopen(path_tmp.c_str(), "wb"); if (file == nullptr) - return false; + throw std::runtime_error(std::string("G-code export to ") + path + " failed.\nCannot open the file for writing.\n"); - bool result = this->_do_export(*print, file); - fclose(file); - - if (result && boost::nowide::rename(path_tmp.c_str(), path) != 0) { - boost::nowide::cerr << "Failed to remove the output G-code file from " << path_tmp << " to " << path - << ". Is " << path_tmp << " locked?" << std::endl; - result = false; - } - - if (! result) + this->m_placeholder_parser_failed_templates.clear(); + this->_do_export(*print, file); + fflush(file); + if (ferror(file)) { + fclose(file); boost::nowide::remove(path_tmp.c_str()); - return result; + throw std::runtime_error(std::string("G-code export to ") + path + " failed\nIs the disk full?\n"); + } + fclose(file); + if (! this->m_placeholder_parser_failed_templates.empty()) { + // G-code export proceeded, but some of the PlaceholderParser substitutions failed. + std::string msg = std::string("G-code export to ") + path + " failed due to invalid custom G-code sections:\n\n"; + for (const std::string &name : this->m_placeholder_parser_failed_templates) + msg += std::string("\t") + name + "\n"; + msg += "\nPlease inspect the file "; + msg += path_tmp + " for error messages enclosed between\n"; + msg += " !!!!! Failed to process the custom G-code template ...\n"; + msg += "and\n"; + msg += " !!!!! End of an error report for the custom G-code template ...\n"; + throw std::runtime_error(msg); + } + if (boost::nowide::rename(path_tmp.c_str(), path) != 0) + throw std::runtime_error( + std::string("Failed to rename the output G-code file from ") + path_tmp + " to " + path + '\n' + + "Is " + path_tmp + " locked?" + '\n'); } -bool GCode::_do_export(Print &print, FILE *file) +void GCode::_do_export(Print &print, FILE *file) { // How many times will be change_layer() called? // change_layer() in turn increments the progress bar status. @@ -480,23 +501,21 @@ bool GCode::_do_export(Print &print, FILE *file) fprintf(file, "\n"); } // Write some terse information on the slicing parameters. - { - const PrintObject *first_object = print.objects.front(); - const double layer_height = first_object->config.layer_height.value; - const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height); - for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { - auto region = print.regions[region_id]; - fprintf(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width); - fprintf(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width); - fprintf(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width); - fprintf(file, "; solid infill extrusion width = %.2fmm\n", region->flow(frSolidInfill, layer_height, false, false, -1., *first_object).width); - fprintf(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width); - if (print.has_support_material()) - fprintf(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width); - if (print.config.first_layer_extrusion_width.value > 0) - fprintf(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width); - fprintf(file, "\n"); - } + const PrintObject *first_object = print.objects.front(); + const double layer_height = first_object->config.layer_height.value; + const double first_layer_height = first_object->config.first_layer_height.get_abs_value(layer_height); + for (size_t region_id = 0; region_id < print.regions.size(); ++ region_id) { + auto region = print.regions[region_id]; + fprintf(file, "; external perimeters extrusion width = %.2fmm\n", region->flow(frExternalPerimeter, layer_height, false, false, -1., *first_object).width); + fprintf(file, "; perimeters extrusion width = %.2fmm\n", region->flow(frPerimeter, layer_height, false, false, -1., *first_object).width); + fprintf(file, "; infill extrusion width = %.2fmm\n", region->flow(frInfill, layer_height, false, false, -1., *first_object).width); + fprintf(file, "; solid infill extrusion width = %.2fmm\n", region->flow(frSolidInfill, layer_height, false, false, -1., *first_object).width); + fprintf(file, "; top infill extrusion width = %.2fmm\n", region->flow(frTopSolidInfill, layer_height, false, false, -1., *first_object).width); + if (print.has_support_material()) + fprintf(file, "; support material extrusion width = %.2fmm\n", support_material_flow(first_object).width); + if (print.config.first_layer_extrusion_width.value > 0) + fprintf(file, "; first layer extrusion width = %.2fmm\n", region->flow(frPerimeter, first_layer_height, false, true, -1., *first_object).width); + fprintf(file, "\n"); } // Prepare the helper object for replacing placeholders in custom G-code and output filename. @@ -509,6 +528,7 @@ bool GCode::_do_export(Print &print, FILE *file) unsigned int initial_extruder_id = (unsigned int)-1; unsigned int final_extruder_id = (unsigned int)-1; size_t initial_print_object_id = 0; + bool has_wipe_tower = false; if (print.config.complete_objects.value) { // Find the 1st printing object, find its tool ordering and the initial extruder ID. for (; initial_print_object_id < print.objects.size(); ++initial_print_object_id) { @@ -523,6 +543,7 @@ bool GCode::_do_export(Print &print, FILE *file) ToolOrdering(print, initial_extruder_id) : print.m_tool_ordering; initial_extruder_id = tool_ordering.first_extruder(); + has_wipe_tower = print.has_wipe_tower() && tool_ordering.has_wipe_tower(); } if (initial_extruder_id == (unsigned int)-1) { // Nothing to print! @@ -545,7 +566,9 @@ bool GCode::_do_export(Print &print, FILE *file) m_placeholder_parser.set("current_extruder", initial_extruder_id); // Useful for sequential prints. m_placeholder_parser.set("current_object_idx", 0); - std::string start_gcode = m_placeholder_parser.process(print.config.start_gcode.value, initial_extruder_id); + // For the start / end G-code to do the priming and final filament pull in case there is no wipe tower provided. + m_placeholder_parser.set("has_wipe_tower", has_wipe_tower); + std::string start_gcode = this->placeholder_parser_process("start_gcode", print.config.start_gcode.value, initial_extruder_id); // Set bed temperature if the start G-code does not contain any bed temp control G-codes. this->_print_first_layer_bed_temperature(file, print, start_gcode, initial_extruder_id, true); @@ -554,8 +577,17 @@ bool GCode::_do_export(Print &print, FILE *file) // Write the custom start G-code writeln(file, start_gcode); // Process filament-specific gcode in extruder order. - for (const std::string &start_gcode : print.config.start_filament_gcode.values) - writeln(file, m_placeholder_parser.process(start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front()))); + if (print.config.single_extruder_multi_material) { + if (has_wipe_tower) { + // Wipe tower will control the extruder switching, it will call the start_filament_gcode. + } else { + // Only initialize the initial extruder. + writeln(file, this->placeholder_parser_process("start_filament_gcode", print.config.start_filament_gcode.values[initial_extruder_id], initial_extruder_id)); + } + } else { + for (const std::string &start_gcode : print.config.start_filament_gcode.values) + writeln(file, this->placeholder_parser_process("start_gcode", start_gcode, (unsigned int)(&start_gcode - &print.config.start_filament_gcode.values.front()))); + } this->_print_first_layer_extruder_temperatures(file, print, start_gcode, initial_extruder_id, true); // Set other general things. @@ -647,7 +679,7 @@ bool GCode::_do_export(Print &print, FILE *file) // another one, set first layer temperatures. This happens before the Z move // is triggered, so machine has more time to reach such temperatures. m_placeholder_parser.set("current_object_idx", int(finished_objects)); - std::string between_objects_gcode = m_placeholder_parser.process(print.config.between_objects_gcode.value, initial_extruder_id); + std::string between_objects_gcode = this->placeholder_parser_process("between_objects_gcode", print.config.between_objects_gcode.value, initial_extruder_id); // Set first layer bed and extruder temperatures, don't wait for it to reach the temperature. this->_print_first_layer_bed_temperature(file, print, between_objects_gcode, initial_extruder_id, false); this->_print_first_layer_extruder_temperatures(file, print, between_objects_gcode, initial_extruder_id, false); @@ -682,32 +714,30 @@ bool GCode::_do_export(Print &print, FILE *file) // All extrusion moves with the same top layer height are extruded uninterrupted. std::vector>> layers_to_print = collect_layers_to_print(print); // Prusa Multi-Material wipe tower. - if (print.has_wipe_tower() && ! layers_to_print.empty()) { - if (tool_ordering.has_wipe_tower()) { - m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); - write(file, m_wipe_tower->prime(*this)); - // Verify, whether the print overaps the priming extrusions. - BoundingBoxf bbox_print(get_print_extrusions_extents(print)); - coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; - for (const PrintObject *print_object : print.objects) - bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); - bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); - BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); - bbox_prime.offset(0.5f); - // Beep for 500ms, tone 800Hz. Yet better, play some Morse. - write(file, this->retract()); - fprintf(file, "M300 S800 P500\n"); - if (bbox_prime.overlap(bbox_print)) { - // Wait for the user to remove the priming extrusions, otherwise they would - // get covered by the print. - fprintf(file, "M1 Remove priming towers and click button.\n"); - } else { - // Just wait for a bit to let the user check, that the priming succeeded. - //TODO Add a message explaining what the printer is waiting for. This needs a firmware fix. - fprintf(file, "M1 S10\n"); - } - } else - write(file, WipeTowerIntegration::prime_single_color_print(print, initial_extruder_id, *this)); + if (has_wipe_tower && ! layers_to_print.empty()) { + m_wipe_tower.reset(new WipeTowerIntegration(print.config, *print.m_wipe_tower_priming.get(), print.m_wipe_tower_tool_changes, *print.m_wipe_tower_final_purge.get())); + write(file, m_writer.travel_to_z(first_layer_height + m_config.z_offset.value, "Move to the first layer height")); + write(file, m_wipe_tower->prime(*this)); + // Verify, whether the print overaps the priming extrusions. + BoundingBoxf bbox_print(get_print_extrusions_extents(print)); + coordf_t twolayers_printz = ((layers_to_print.size() == 1) ? layers_to_print.front() : layers_to_print[1]).first + EPSILON; + for (const PrintObject *print_object : print.objects) + bbox_print.merge(get_print_object_extrusions_extents(*print_object, twolayers_printz)); + bbox_print.merge(get_wipe_tower_extrusions_extents(print, twolayers_printz)); + BoundingBoxf bbox_prime(get_wipe_tower_priming_extrusions_extents(print)); + bbox_prime.offset(0.5f); + // Beep for 500ms, tone 800Hz. Yet better, play some Morse. + write(file, this->retract()); + fprintf(file, "M300 S800 P500\n"); + if (bbox_prime.overlap(bbox_print)) { + // Wait for the user to remove the priming extrusions, otherwise they would + // get covered by the print. + fprintf(file, "M1 Remove priming towers and click button.\n"); + } else { + // Just wait for a bit to let the user check, that the priming succeeded. + //TODO Add a message explaining what the printer is waiting for. This needs a firmware fix. + fprintf(file, "M1 S10\n"); + } } // Extrude the layers. for (auto &layer : layers_to_print) { @@ -727,9 +757,14 @@ bool GCode::_do_export(Print &print, FILE *file) write(file, this->retract()); write(file, m_writer.set_fan(false)); // Process filament-specific gcode in extruder order. - for (const std::string &end_gcode : print.config.end_filament_gcode.values) - writeln(file, m_placeholder_parser.process(end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); - writeln(file, m_placeholder_parser.process(print.config.end_gcode, m_writer.extruder()->id())); + if (print.config.single_extruder_multi_material) { + // Process the end_filament_gcode for the active filament only. + writeln(file, this->placeholder_parser_process("end_filament_gcode", print.config.end_filament_gcode.get_at(m_writer.extruder()->id()), m_writer.extruder()->id())); + } else { + for (const std::string &end_gcode : print.config.end_filament_gcode.values) + writeln(file, this->placeholder_parser_process("end_gcode", end_gcode, (unsigned int)(&end_gcode - &print.config.end_filament_gcode.values.front()))); + } + writeln(file, this->placeholder_parser_process("end_gcode", print.config.end_gcode, m_writer.extruder()->id())); write(file, m_writer.update_progress(m_layer_count, m_layer_count, true)); // 100% write(file, m_writer.postamble()); @@ -766,11 +801,25 @@ bool GCode::_do_export(Print &print, FILE *file) for (size_t i = 0; i < sizeof(configs) / sizeof(configs[0]); ++ i) { StaticPrintConfig *cfg = configs[i]; for (const std::string &key : cfg->keys()) - fprintf(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str()); + if (key != "compatible_printers") + fprintf(file, "; %s = %s\n", key.c_str(), cfg->serialize(key).c_str()); } } +} - return true; +std::string GCode::placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) +{ + try { + return m_placeholder_parser.process(templ, current_extruder_id, config_override); + } catch (std::runtime_error &err) { + // Collect the names of failed template substitutions for error reporting. + this->m_placeholder_parser_failed_templates.insert(name); + // Insert the macro error message into the G-code. + return + std::string("\n!!!!! Failed to process the custom G-code template ") + name + "\n" + + err.what() + + "!!!!! End of an error report for the custom G-code template " + name + "\n\n"; + } } // Parse the custom G-code, try to find mcode_set_temp_dont_wait and mcode_set_temp_and_wait inside the custom G-code. @@ -838,12 +887,12 @@ void GCode::_print_first_layer_bed_temperature(FILE *file, Print &print, const s // Is the bed temperature set by the provided custom G-code? int temp_by_gcode = -1; bool temp_set_by_gcode = custom_gcode_sets_temperature(gcode, 140, 190, temp_by_gcode); - if (temp_by_gcode >= 0 && temp_by_gcode < 1000) + if (temp_set_by_gcode && temp_by_gcode >= 0 && temp_by_gcode < 1000) temp = temp_by_gcode; // Always call m_writer.set_bed_temperature() so it will set the internal "current" state of the bed temp as if // the custom start G-code emited these. std::string set_temp_gcode = m_writer.set_bed_temperature(temp, wait); - if (! temp_by_gcode) + if (! temp_set_by_gcode) write(file, set_temp_gcode); } @@ -973,7 +1022,7 @@ void GCode::process_layer( DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index + 1)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); - gcode += m_placeholder_parser.process( + gcode += this->placeholder_parser_process("before_layer_gcode", print.config.before_layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } @@ -983,7 +1032,7 @@ void GCode::process_layer( DynamicConfig config; config.set_key_value("layer_num", new ConfigOptionInt(m_layer_index)); config.set_key_value("layer_z", new ConfigOptionFloat(print_z)); - gcode += m_placeholder_parser.process( + gcode += this->placeholder_parser_process("layer_gcode", print.config.layer_gcode.value, m_writer.extruder()->id(), &config) + "\n"; } @@ -2162,13 +2211,14 @@ GCode::retract(bool toolchange) std::string GCode::set_extruder(unsigned int extruder_id) { - m_placeholder_parser.set("current_extruder", extruder_id); if (!m_writer.need_toolchange(extruder_id)) return ""; // if we are running a single-extruder setup, just set the extruder and return nothing - if (!m_writer.multiple_extruders) + if (!m_writer.multiple_extruders) { + m_placeholder_parser.set("current_extruder", extruder_id); return m_writer.toolchange(extruder_id); + } // prepend retraction on the current extruder std::string gcode = this->retract(true); @@ -2176,23 +2226,41 @@ std::string GCode::set_extruder(unsigned int extruder_id) // Always reset the extrusion path, even if the tool change retract is set to zero. m_wipe.reset_path(); - // append custom toolchange G-code - if (m_writer.extruder() != nullptr && !m_config.toolchange_gcode.value.empty()) { + if (m_writer.extruder() != nullptr) { + // Process the custom end_filament_gcode in case of single_extruder_multi_material. + unsigned int old_extruder_id = m_writer.extruder()->id(); + const std::string &end_filament_gcode = m_config.end_filament_gcode.get_at(old_extruder_id); + if (m_config.single_extruder_multi_material && ! end_filament_gcode.empty()) { + gcode += placeholder_parser_process("end_filament_gcode", end_filament_gcode, old_extruder_id); + check_add_eol(gcode); + } + } + + m_placeholder_parser.set("current_extruder", extruder_id); + + if (m_writer.extruder() != nullptr && ! m_config.toolchange_gcode.value.empty()) { + // Process the custom toolchange_gcode. DynamicConfig config; config.set_key_value("previous_extruder", new ConfigOptionInt((int)m_writer.extruder()->id())); config.set_key_value("next_extruder", new ConfigOptionInt((int)extruder_id)); - gcode += m_placeholder_parser.process( - m_config.toolchange_gcode.value, extruder_id, &config) - + '\n'; + gcode += placeholder_parser_process("toolchange_gcode", m_config.toolchange_gcode.value, extruder_id, &config); + check_add_eol(gcode); } - // if ooze prevention is enabled, park current extruder in the nearest - // standby point and set it to the standby temperature + // If ooze prevention is enabled, park current extruder in the nearest + // standby point and set it to the standby temperature. if (m_ooze_prevention.enable && m_writer.extruder() != nullptr) gcode += m_ooze_prevention.pre_toolchange(*this); - // append the toolchange command + // Append the toolchange command. gcode += m_writer.toolchange(extruder_id); - // set the new extruder to the operating temperature + // Append the filament start G-code for single_extruder_multi_material. + const std::string &start_filament_gcode = m_config.start_filament_gcode.get_at(extruder_id); + if (m_config.single_extruder_multi_material && ! start_filament_gcode.empty()) { + // Process the start_filament_gcode for the active filament only. + gcode += this->placeholder_parser_process("start_filament_gcode", start_filament_gcode, extruder_id); + check_add_eol(gcode); + } + // Set the new extruder to the operating temperature. if (m_ooze_prevention.enable) gcode += m_ooze_prevention.post_toolchange(*this); diff --git a/xs/src/libslic3r/GCode.hpp b/xs/src/libslic3r/GCode.hpp index aa90ac968..2fd3b39d3 100644 --- a/xs/src/libslic3r/GCode.hpp +++ b/xs/src/libslic3r/GCode.hpp @@ -90,7 +90,6 @@ public: m_brim_done(false) {} std::string prime(GCode &gcodegen); - static std::string prime_single_color_print(const Print & /* print */, unsigned int initial_tool, GCode & /* gcodegen */); void next_layer() { ++ m_layer_idx; m_tool_change_idx = 0; } std::string tool_change(GCode &gcodegen, int extruder_id, bool finish_layer); std::string finalize(GCode &gcodegen); @@ -131,7 +130,8 @@ public: {} ~GCode() {} - bool do_export(Print *print, const char *path); + // throws std::runtime_exception + void do_export(Print *print, const char *path); // Exported for the helper classes (OozePrevention, Wipe) and for the Perl binding for unit tests. const Pointf& origin() const { return m_origin; } @@ -143,6 +143,10 @@ public: const FullPrintConfig &config() const { return m_config; } const Layer* layer() const { return m_layer; } GCodeWriter& writer() { return m_writer; } + PlaceholderParser& placeholder_parser() { return m_placeholder_parser; } + // Process a template through the placeholder parser, collect error messages to be reported + // inside the generated string and after the G-code export finishes. + std::string placeholder_parser_process(const std::string &name, const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr); bool enable_cooling_markers() const { return m_enable_cooling_markers; } // For Perl bindings, to be used exclusively by unit tests. @@ -151,7 +155,7 @@ public: void apply_print_config(const PrintConfig &print_config); protected: - bool _do_export(Print &print, FILE *file); + void _do_export(Print &print, FILE *file); // Object and support extrusions of the same PrintObject at the same print_z. struct LayerToPrint @@ -223,6 +227,8 @@ protected: FullPrintConfig m_config; GCodeWriter m_writer; PlaceholderParser m_placeholder_parser; + // Collection of templates, on which the placeholder substitution failed. + std::set m_placeholder_parser_failed_templates; OozePrevention m_ooze_prevention; Wipe m_wipe; AvoidCrossingPerimeters m_avoid_crossing_perimeters; diff --git a/xs/src/libslic3r/GCode/ToolOrdering.cpp b/xs/src/libslic3r/GCode/ToolOrdering.cpp index 0ffdbcc43..271b75ef3 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.cpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.cpp @@ -1,7 +1,16 @@ #include "Print.hpp" #include "ToolOrdering.hpp" -#include +// #define SLIC3R_DEBUG + +// Make assert active if SLIC3R_DEBUG +#ifdef SLIC3R_DEBUG + #define DEBUG + #define _DEBUG + #undef NDEBUG +#endif + +#include #include namespace Slic3r { @@ -256,12 +265,19 @@ void ToolOrdering::fill_wipe_tower_partitions(const PrintConfig &config, coordf_ // Insert one additional wipe tower layer between lh.print_z and lt_object.print_z. LayerTools lt_new(0.5f * (lt.print_z + lt_object.print_z)); // Find the 1st layer above lt_new. - for (j = i + 1; j < m_layer_tools.size() && m_layer_tools[j].print_z < lt_new.print_z; ++ j); - LayerTools <_extra = (m_layer_tools[j].print_z == lt_new.print_z) ? - m_layer_tools[j] : - *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); - lt_extra.has_wipe_tower = true; - lt_extra.wipe_tower_partitions = lt_object.wipe_tower_partitions; + for (j = i + 1; j < m_layer_tools.size() && m_layer_tools[j].print_z < lt_new.print_z - EPSILON; ++ j); + if (std::abs(m_layer_tools[j].print_z - lt_new.print_z) < EPSILON) { + m_layer_tools[j].has_wipe_tower = true; + } else { + LayerTools <_extra = *m_layer_tools.insert(m_layer_tools.begin() + j, lt_new); + LayerTools <_prev = m_layer_tools[j - 1]; + LayerTools <_next = m_layer_tools[j + 1]; + assert(! lt_prev.extruders.empty() && ! lt_next.extruders.empty()); + assert(lt_prev.extruders.back() == lt_next.extruders.front()); + lt_extra.has_wipe_tower = true; + lt_extra.extruders.push_back(lt_next.extruders.front()); + lt_extra.wipe_tower_partitions = lt_next.wipe_tower_partitions; + } } } break; diff --git a/xs/src/libslic3r/GCode/ToolOrdering.hpp b/xs/src/libslic3r/GCode/ToolOrdering.hpp index fe2c394c5..c92806b19 100644 --- a/xs/src/libslic3r/GCode/ToolOrdering.hpp +++ b/xs/src/libslic3r/GCode/ToolOrdering.hpp @@ -53,14 +53,14 @@ public: void clear() { m_layer_tools.clear(); } - // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. + // Get the first extruder printing, including the extruder priming areas, returns -1 if there is no layer printed. unsigned int first_extruder() const { return m_first_printing_extruder; } // Get the first extruder printing the layer_tools, returns -1 if there is no layer printed. unsigned int last_extruder() const { return m_last_printing_extruder; } // For a multi-material print, the printing extruders are ordered in the order they shall be primed. - std::vector all_extruders() const { return m_all_printing_extruders; } + const std::vector& all_extruders() const { return m_all_printing_extruders; } // Find LayerTools with the closest print_z. LayerTools& tools_for_layer(coordf_t print_z); @@ -69,6 +69,8 @@ public: const LayerTools& front() const { return m_layer_tools.front(); } const LayerTools& back() const { return m_layer_tools.back(); } + std::vector::const_iterator begin() const { return m_layer_tools.begin(); } + std::vector::const_iterator end() const { return m_layer_tools.end(); } bool empty() const { return m_layer_tools.empty(); } const std::vector& layer_tools() const { return m_layer_tools; } bool has_wipe_tower() const { return ! m_layer_tools.empty() && m_first_printing_extruder != (unsigned int)-1 && m_layer_tools.front().wipe_tower_partitions > 0; } diff --git a/xs/src/libslic3r/GCode/WipeTower.hpp b/xs/src/libslic3r/GCode/WipeTower.hpp index c5ce9b727..28549ae64 100644 --- a/xs/src/libslic3r/GCode/WipeTower.hpp +++ b/xs/src/libslic3r/GCode/WipeTower.hpp @@ -122,7 +122,7 @@ public: // print_z of the first layer. float first_layer_height, // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. - std::vector tools, + const std::vector &tools, // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. // If false, the last priming are will be large enough to wipe the last extruder sufficiently. bool last_wipe_inside_wipe_tower, diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp index 3890a3626..0b3a023a4 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.cpp @@ -389,7 +389,7 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::prime( // print_z of the first layer. float first_layer_height, // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. - std::vector tools, + const std::vector &tools, // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. // If false, the last priming are will be large enough to wipe the last extruder sufficiently. bool last_wipe_inside_wipe_tower, @@ -615,7 +615,8 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::tool_change(unsigned int tool, boo .extrude(box.ld, 3200).extrude(box.rd) .extrude(box.ru).extrude(box.lu); // Wipe the nozzle. - if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) + //if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) + // Always wipe the nozzle with a long wipe to reduce stringing when moving away from the wipe tower. writer.travel(box.ru, 7200) .travel(box.lu); } else @@ -723,8 +724,9 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::toolchange_Brim(Purpose purpose, b // Move to the front left corner. writer.travel(wipeTower_box.ld, 7000); - if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) + //if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) // Wipe along the front edge. + // Always wipe the nozzle with a long wipe to reduce stringing when moving away from the wipe tower. writer.travel(wipeTower_box.rd) .travel(wipeTower_box.ld); @@ -1083,8 +1085,10 @@ WipeTower::ToolChangeResult WipeTowerPrusaMM::finish_layer(Purpose purpose) .extrude(fill_box.ru + xy(-m_perimeter_width, -m_perimeter_width)); } - if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) + // if (purpose == PURPOSE_MOVE_TO_TOWER_AND_EXTRUDE) + if (true) // Wipe along the front side of the current wiping box. + // Always wipe the nozzle with a long wipe to reduce stringing when moving away from the wipe tower. writer.travel(fill_box.ld + xy( m_perimeter_width, m_perimeter_width / 2), 7200) .travel(fill_box.rd + xy(- m_perimeter_width, m_perimeter_width / 2)); else diff --git a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp index 275b2f237..574accd75 100644 --- a/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp +++ b/xs/src/libslic3r/GCode/WipeTowerPrusaMM.hpp @@ -151,7 +151,7 @@ public: // print_z of the first layer. float first_layer_height, // Extruder indices, in the order to be primed. The last extruder will later print the wipe tower brim, print brim and the object. - std::vector tools, + const std::vector &tools, // If true, the last priming are will be the same as the other priming areas, and the rest of the wipe will be performed inside the wipe tower. // If false, the last priming are will be large enough to wipe the last extruder sufficiently. bool last_wipe_inside_wipe_tower, diff --git a/xs/src/libslic3r/Layer.hpp b/xs/src/libslic3r/Layer.hpp index f8fdcdd4d..f3b460443 100644 --- a/xs/src/libslic3r/Layer.hpp +++ b/xs/src/libslic3r/Layer.hpp @@ -161,7 +161,9 @@ public: // Is there any valid extrusion assigned to this LayerRegion? virtual bool has_extrusions() const { return ! support_fills.empty(); } -protected: +//protected: + // The constructor has been made public to be able to insert additional support layers for the skirt or a wipe tower + // between the raft and the object first layer. SupportLayer(size_t id, PrintObject *object, coordf_t height, coordf_t print_z, coordf_t slice_z) : Layer(id, object, height, print_z, slice_z) {} virtual ~SupportLayer() {} diff --git a/xs/src/libslic3r/PlaceholderParser.cpp b/xs/src/libslic3r/PlaceholderParser.cpp index 060252387..bcd011da2 100644 --- a/xs/src/libslic3r/PlaceholderParser.cpp +++ b/xs/src/libslic3r/PlaceholderParser.cpp @@ -50,11 +50,20 @@ #include #include +// #define USE_CPP11_REGEX +#ifdef USE_CPP11_REGEX + #include + #define SLIC3R_REGEX_NAMESPACE std +#else /* USE_CPP11_REGEX */ + #include + #define SLIC3R_REGEX_NAMESPACE boost +#endif /* USE_CPP11_REGEX */ + namespace Slic3r { PlaceholderParser::PlaceholderParser() { - this->set("version", SLIC3R_VERSION); + this->set("version", std::string(SLIC3R_VERSION)); this->apply_env_variables(); this->update_timestamp(); } @@ -278,22 +287,31 @@ namespace client expr &operator+=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; - this->throw_if_not_numeric(err_msg); - rhs.throw_if_not_numeric(err_msg); - if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { - double d = this->as_d() + rhs.as_d(); - this->data.d = d; - this->type = TYPE_DOUBLE; - } else - this->data.i += rhs.i(); + if (this->type == TYPE_STRING) { + // Convert the right hand side to string and append. + *this->data.s += rhs.to_string(); + } else if (rhs.type == TYPE_STRING) { + // Conver the left hand side to string, append rhs. + this->data.s = new std::string(this->to_string() + rhs.s()); + this->type = TYPE_STRING; + } else { + const char *err_msg = "Cannot add non-numeric types."; + this->throw_if_not_numeric(err_msg); + rhs.throw_if_not_numeric(err_msg); + if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { + double d = this->as_d() + rhs.as_d(); + this->data.d = d; + this->type = TYPE_DOUBLE; + } else + this->data.i += rhs.i(); + } this->it_range = boost::iterator_range(this->it_range.begin(), rhs.it_range.end()); return *this; } expr &operator-=(const expr &rhs) { - const char *err_msg = "Cannot multiply with non-numeric type."; + const char *err_msg = "Cannot subtract non-numeric types."; this->throw_if_not_numeric(err_msg); rhs.throw_if_not_numeric(err_msg); if (this->type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) { @@ -349,30 +367,112 @@ namespace client out = self.b(); } + static void evaluate_boolean_to_string(expr &self, std::string &out) + { + if (self.type != TYPE_BOOL) + self.throw_exception("Not a boolean expression"); + out = self.b() ? "true" : "false"; + } + // Is lhs==rhs? Store the result into lhs. - static void compare_op(expr &lhs, expr &rhs, char op) + static void compare_op(expr &lhs, expr &rhs, char op, bool invert) { bool value = false; if ((lhs.type == TYPE_INT || lhs.type == TYPE_DOUBLE) && (rhs.type == TYPE_INT || rhs.type == TYPE_DOUBLE)) { // Both types are numeric. - value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ? - (lhs.as_d() == rhs.as_d()) : (lhs.i() == rhs.i()); + switch (op) { + case '=': + value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ? + (std::abs(lhs.as_d() - rhs.as_d()) < 1e-8) : (lhs.i() == rhs.i()); + break; + case '<': + value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ? + (lhs.as_d() < rhs.as_d()) : (lhs.i() < rhs.i()); + break; + case '>': + default: + value = (lhs.type == TYPE_DOUBLE || rhs.type == TYPE_DOUBLE) ? + (lhs.as_d() > rhs.as_d()) : (lhs.i() > rhs.i()); + break; + } } else if (lhs.type == TYPE_BOOL && rhs.type == TYPE_BOOL) { // Both type are bool. + if (op != '=') + boost::throw_exception(qi::expectation_failure( + lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types."))); value = lhs.b() == rhs.b(); } else if (lhs.type == TYPE_STRING || rhs.type == TYPE_STRING) { // One type is string, the other could be converted to string. - value = lhs.to_string() == rhs.to_string(); + value = (op == '=') ? (lhs.to_string() == rhs.to_string()) : + (op == '<') ? (lhs.to_string() < rhs.to_string()) : (lhs.to_string() > rhs.to_string()); } else { boost::throw_exception(qi::expectation_failure( - lhs.it_range.begin(), rhs.it_range.end(), spirit::info("Cannot compare the types."))); + lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot compare the types."))); } lhs.type = TYPE_BOOL; - lhs.data.b = (op == '=') ? value : !value; + lhs.data.b = invert ? ! value : value; + } + static void equal (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '=', false); } + static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '=', true ); } + static void lower (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', false); } + static void greater (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', false); } + static void leq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '>', true ); } + static void geq (expr &lhs, expr &rhs) { compare_op(lhs, rhs, '<', true ); } + + static void regex_op(expr &lhs, boost::iterator_range &rhs, char op) + { + const std::string *subject = nullptr; + const std::string *mask = nullptr; + if (lhs.type == TYPE_STRING) { + // One type is string, the other could be converted to string. + subject = &lhs.s(); + } else { + lhs.throw_exception("Left hand side of a regex match must be a string."); + } + try { + std::string pattern(++ rhs.begin(), -- rhs.end()); + bool result = SLIC3R_REGEX_NAMESPACE::regex_match(*subject, SLIC3R_REGEX_NAMESPACE::regex(pattern)); + if (op == '!') + result = ! result; + lhs.reset(); + lhs.type = TYPE_BOOL; + lhs.data.b = result; + } catch (SLIC3R_REGEX_NAMESPACE::regex_error &ex) { + // Syntax error in the regular expression + boost::throw_exception(qi::expectation_failure( + rhs.begin(), rhs.end(), spirit::info(std::string("*Regular expression compilation failed: ") + ex.what()))); + } + } + + static void regex_matches (expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '='); } + static void regex_doesnt_match(expr &lhs, boost::iterator_range &rhs) { return regex_op(lhs, rhs, '!'); } + + static void logical_op(expr &lhs, expr &rhs, char op) + { + bool value = false; + if (lhs.type == TYPE_BOOL && rhs.type == TYPE_BOOL) { + value = (op == '|') ? (lhs.b() || rhs.b()) : (lhs.b() && rhs.b()); + } else { + boost::throw_exception(qi::expectation_failure( + lhs.it_range.begin(), rhs.it_range.end(), spirit::info("*Cannot apply logical operation to non-boolean operators."))); + } + lhs.type = TYPE_BOOL; + lhs.data.b = value; + } + static void logical_or (expr &lhs, expr &rhs) { logical_op(lhs, rhs, '|'); } + static void logical_and(expr &lhs, expr &rhs) { logical_op(lhs, rhs, '&'); } + + static void ternary_op(expr &lhs, expr &rhs1, expr &rhs2) + { + bool value = false; + if (lhs.type != TYPE_BOOL) + lhs.throw_exception("Not a boolean expression"); + if (lhs.b()) + lhs = std::move(rhs1); + else + lhs = std::move(rhs2); } - static void equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '='); } - static void not_equal(expr &lhs, expr &rhs) { compare_op(lhs, rhs, '!'); } static void set_if(bool &cond, bool ¬_yet_consumed, std::string &str_in, std::string &str_out) { @@ -385,7 +485,7 @@ namespace client void throw_exception(const char *message) const { boost::throw_exception(qi::expectation_failure( - this->it_range.begin(), this->it_range.end(), spirit::info(message))); + this->it_range.begin(), this->it_range.end(), spirit::info(std::string("*") + message))); } void throw_if_not_numeric(const char *message) const @@ -412,9 +512,15 @@ namespace client } struct MyContext { - const PlaceholderParser *pp = nullptr; - const DynamicConfig *config_override = nullptr; - const size_t current_extruder_id = 0; + const DynamicConfig *config = nullptr; + const DynamicConfig *config_override = nullptr; + size_t current_extruder_id = 0; + // If false, the macro_processor will evaluate a full macro. + // If true, the macro processor will evaluate just a boolean condition using the full expressive power of the macro processor. + bool just_boolean_expression = false; + std::string error_message; + + static void evaluate_full_macro(const MyContext *ctx, bool &result) { result = ! ctx->just_boolean_expression; } const ConfigOption* resolve_symbol(const std::string &opt_key) const { @@ -422,7 +528,7 @@ namespace client if (config_override != nullptr) opt = config_override->option(opt_key); if (opt == nullptr) - opt = pp->option(opt_key); + opt = config->option(opt_key); return opt; } @@ -442,26 +548,22 @@ namespace client opt = ctx->resolve_symbol(opt_key_str.substr(0, idx)); if (opt != nullptr) { if (! opt->is_vector()) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Trying to index a scalar variable"))); + ctx->throw_exception("Trying to index a scalar variable", opt_key); char *endptr = nullptr; idx = strtol(opt_key_str.c_str() + idx + 1, &endptr, 10); if (endptr == nullptr || *endptr != 0) - boost::throw_exception(qi::expectation_failure( - opt_key.begin() + idx + 1, opt_key.end(), spirit::info("Invalid vector index"))); + ctx->throw_exception("Invalid vector index", boost::iterator_range(opt_key.begin() + idx + 1, opt_key.end())); } } } if (opt == nullptr) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Variable does not exist"))); + ctx->throw_exception("Variable does not exist", boost::iterator_range(opt_key.begin(), opt_key.end())); if (opt->is_scalar()) output = opt->serialize(); else { const ConfigOptionVectorBase *vec = static_cast(opt); if (vec->empty()) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Indexing an empty vector variable"))); + ctx->throw_exception("Indexing an empty vector variable", opt_key); output = vec->vserialize()[(idx >= vec->size()) ? 0 : idx]; } } @@ -482,23 +584,18 @@ namespace client opt = ctx->resolve_symbol(opt_key_str); } if (! opt->is_vector()) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Trying to index a scalar variable"))); + ctx->throw_exception("Trying to index a scalar variable", opt_key); const ConfigOptionVectorBase *vec = static_cast(opt); if (vec->empty()) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Indexing an empty vector variable"))); + ctx->throw_exception("Indexing an empty vector variable", boost::iterator_range(opt_key.begin(), opt_key.end())); const ConfigOption *opt_index = ctx->resolve_symbol(std::string(opt_vector_index.begin(), opt_vector_index.end())); if (opt_index == nullptr) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Variable does not exist"))); + ctx->throw_exception("Variable does not exist", opt_key); if (opt_index->type() != coInt) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Indexing variable has to be integer"))); + ctx->throw_exception("Indexing variable has to be integer", opt_key); int idx = opt_index->getInt(); if (idx < 0) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Negative vector index"))); + ctx->throw_exception("Negative vector index", opt_key); output = vec->vserialize()[(idx >= (int)vec->size()) ? 0 : idx]; } @@ -510,8 +607,7 @@ namespace client { const ConfigOption *opt = ctx->resolve_symbol(std::string(opt_key.begin(), opt_key.end())); if (opt == nullptr) - boost::throw_exception(qi::expectation_failure( - opt_key.begin(), opt_key.end(), spirit::info("Not a variable name"))); + ctx->throw_exception("Not a variable name", opt_key); output.opt = opt; output.it_range = opt_key; } @@ -523,8 +619,7 @@ namespace client expr &output) { if (opt.opt->is_vector()) - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("Referencing a scalar variable in a vector context"))); + ctx->throw_exception("Referencing a scalar variable in a vector context", opt.it_range); switch (opt.opt->type()) { case coFloat: output.set_d(opt.opt->getFloat()); break; case coInt: output.set_i(opt.opt->getInt()); break; @@ -533,11 +628,9 @@ namespace client case coPoint: output.set_s(opt.opt->serialize()); break; case coBool: output.set_b(opt.opt->getBool()); break; case coFloatOrPercent: - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("FloatOrPercent variables are not supported"))); + ctx->throw_exception("FloatOrPercent variables are not supported", opt.it_range); default: - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("Unknown scalar variable type"))); + ctx->throw_exception("Unknown scalar variable type", opt.it_range); } output.it_range = opt.it_range; } @@ -551,12 +644,10 @@ namespace client expr &output) { if (opt.opt->is_scalar()) - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("Referencing a vector variable in a scalar context"))); + ctx->throw_exception("Referencing a vector variable in a scalar context", opt.it_range); const ConfigOptionVectorBase *vec = static_cast(opt.opt); if (vec->empty()) - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("Indexing an empty vector variable"))); + ctx->throw_exception("Indexing an empty vector variable", opt.it_range); size_t idx = (index < 0) ? 0 : (index >= int(vec->size())) ? 0 : size_t(index); switch (opt.opt->type()) { case coFloats: output.set_d(static_cast(opt.opt)->values[idx]); break; @@ -566,8 +657,7 @@ namespace client case coPoints: output.set_s(static_cast(opt.opt)->values[idx].dump_perl()); break; case coBools: output.set_b(static_cast(opt.opt)->values[idx] != 0); break; default: - boost::throw_exception(qi::expectation_failure( - opt.it_range.begin(), opt.it_range.end(), spirit::info("Unknown vector variable type"))); + ctx->throw_exception("Unknown vector variable type", opt.it_range); } output.it_range = boost::iterator_range(opt.it_range.begin(), it_end); } @@ -577,10 +667,57 @@ namespace client template static void evaluate_index(expr &expr_index, int &output) { - if (expr_index.type != expr::TYPE_INT) + if (expr_index.type != expr::TYPE_INT) expr_index.throw_exception("Non-integer index is not allowed to address a vector variable."); output = expr_index.i(); } + + template + static void throw_exception(const std::string &msg, const boost::iterator_range &it_range) + { + // An asterix is added to the start of the string to differentiate the boost::spirit::info::tag content + // between the grammer terminal / non-terminal symbol name and a free-form error message. + boost::throw_exception(qi::expectation_failure(it_range.begin(), it_range.end(), spirit::info(std::string("*") + msg))); + } + + template + static void process_error_message(const MyContext *context, const boost::spirit::info &info, const Iterator &it_begin, const Iterator &it_end, const Iterator &it_error) + { + std::string &msg = const_cast(context)->error_message; + std::string first(it_begin, it_error); + std::string last(it_error, it_end); + auto first_pos = first.rfind('\n'); + auto last_pos = last.find('\n'); + int line_nr = 1; + if (first_pos == std::string::npos) + first_pos = 0; + else { + // Calculate the current line number. + for (size_t i = 0; i <= first_pos; ++ i) + if (first[i] == '\n') + ++ line_nr; + ++ first_pos; + } + auto error_line = std::string(first, first_pos) + std::string(last, 0, last_pos); + // Position of the it_error from the start of its line. + auto error_pos = (it_error - it_begin) - first_pos; + msg += "Parsing error at line " + std::to_string(line_nr); + if (! info.tag.empty() && info.tag.front() == '*') { + // The gat contains an explanatory string. + msg += ": "; + msg += info.tag.substr(1); + } else { + // A generic error report based on the nonterminal or terminal symbol name. + msg += ". Expecting tag "; + msg += info.tag; + } + msg += '\n'; + msg += error_line; + msg += '\n'; + for (size_t i = 0; i < error_pos; ++ i) + msg += ' '; + msg += "^\n"; + } }; // For debugging the boost::spirit parsers. Print out the string enclosed in it_range. @@ -598,14 +735,77 @@ namespace client template static bool parse_inf(It&, It const&, Attr&) { return false; } }; + // This parser is to be used inside a raw[] directive to accept a single valid UTF-8 character. + // If an invalid UTF-8 sequence is encountered, a qi::expectation_failure is thrown. + struct utf8_char_skipper_parser : qi::primitive_parser + { + // Define the attribute type exposed by this parser component + template + struct attribute + { + typedef wchar_t type; + }; + + // This function is called during the actual parsing process + template + bool parse(Iterator& first, Iterator const& last, Context& context, Skipper const& skipper, Attribute& attr) const + { + // The skipper shall always be empty, any white space will be accepted. + // skip_over(first, last, skipper); + if (first == last) + return false; + // Iterator over the UTF-8 sequence. + auto it = first; + // Read the first byte of the UTF-8 sequence. + unsigned char c = static_cast(*it ++); + unsigned int cnt = 0; + // UTF-8 sequence must not start with a continuation character: + if ((c & 0xC0) == 0x80) + goto err; + // Skip high surrogate first if there is one. + // If the most significant bit with a zero in it is in position + // 8-N then there are N bytes in this UTF-8 sequence: + { + unsigned char mask = 0x80u; + unsigned int result = 0; + while (c & mask) { + ++ result; + mask >>= 1; + } + cnt = (result == 0) ? 1 : ((result > 4) ? 4 : result); + } + // Since we haven't read in a value, we need to validate the code points: + for (-- cnt; cnt > 0; -- cnt) { + if (it == last) + goto err; + c = static_cast(*it ++); + // We must have a continuation byte: + if (cnt > 1 && (c & 0xC0) != 0x80) + goto err; + } + first = it; + return true; + err: + MyContext::throw_exception("Invalid utf8 sequence", boost::iterator_range(first, last)); + return false; + } + + // This function is called during error handling to create a human readable string for the error context. + template + spirit::info what(Context&) const + { + return spirit::info("unicode_char"); + } + }; + /////////////////////////////////////////////////////////////////////////// - // Our calculator grammar + // Our macro_processor grammar /////////////////////////////////////////////////////////////////////////// // Inspired by the C grammar rules https://www.lysator.liu.se/c/ANSI-C-grammar-y.html template - struct calculator : qi::grammar + struct macro_processor : qi::grammar, spirit::ascii::space_type> { - calculator() : calculator::base_type(start) + macro_processor() : macro_processor::base_type(start) { using namespace qi::labels; qi::alpha_type alpha; @@ -617,6 +817,7 @@ namespace client qi::no_skip_type no_skip; qi::real_parser strict_double; spirit::ascii::char_type char_; + utf8_char_skipper_parser utf8char; spirit::bool_type bool_; spirit::int_type int_; spirit::double_type double_; @@ -627,6 +828,8 @@ namespace client qi::_val_type _val; qi::_1_type _1; qi::_2_type _2; + qi::_3_type _3; + qi::_4_type _4; qi::_a_type _a; qi::_b_type _b; qi::_r1_type _r1; @@ -634,8 +837,15 @@ namespace client // Starting symbol of the grammer. // The leading eps is required by the "expectation point" operator ">". // Without it, some of the errors would not trigger the error handler. - start = eps > text_block(_r1); + // Also the start symbol switches between the "full macro syntax" and a "boolean expression only", + // depending on the context->just_boolean_expression flag. This way a single static expression parser + // could serve both purposes. + start = eps[px::bind(&MyContext::evaluate_full_macro, _r1, _a)] > + ( eps(_a==true) > text_block(_r1) [_val=_1] + | conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean_to_string, _1, _val) ] + ); start.name("start"); + qi::on_error(start, px::bind(&MyContext::process_error_message, _r1, _4, _1, _2, _3)); text_block = *( text [_val+=_1] @@ -649,7 +859,7 @@ namespace client // Free-form text up to a first brace, including spaces and newlines. // The free-form text will be inserted into the processed text without a modification. - text = no_skip[raw[+(char_ - '[' - '{')]]; + text = no_skip[raw[+(utf8char - char_('[') - char_('{'))]]; text.name("text"); // New style of macro expansion. @@ -695,32 +905,54 @@ namespace client raw[lexeme[(alpha | '_') >> *(alnum | '_')]]; identifier.name("identifier"); - bool_expr = - additive_expression(_r1) [_val = _1] - >> *( ("==" > additive_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] - | ("!=" > additive_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] - | ("<>" > additive_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + conditional_expression = + logical_or_expression(_r1) [_val = _1] + >> -('?' > conditional_expression(_r1) > ':' > conditional_expression(_r1)) [px::bind(&expr::ternary_op, _val, _1, _2)]; + + logical_or_expression = + logical_and_expression(_r1) [_val = _1] + >> *( ((kw["or"] | "||") > logical_and_expression(_r1) ) [px::bind(&expr::logical_or, _val, _1)] ); + + logical_and_expression = + equality_expression(_r1) [_val = _1] + >> *( ((kw["and"] | "&&") > equality_expression(_r1) ) [px::bind(&expr::logical_and, _val, _1)] ); + + equality_expression = + relational_expression(_r1) [_val = _1] + >> *( ("==" > relational_expression(_r1) ) [px::bind(&expr::equal, _val, _1)] + | ("!=" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("<>" > relational_expression(_r1) ) [px::bind(&expr::not_equal, _val, _1)] + | ("=~" > regular_expression ) [px::bind(&expr::regex_matches, _val, _1)] + | ("!~" > regular_expression ) [px::bind(&expr::regex_doesnt_match, _val, _1)] ); - bool_expr.name("bool expression"); + equality_expression.name("bool expression"); // Evaluate a boolean expression stored as expr into a boolean value. - // Throw if the bool_expr does not produce a expr of boolean type. - bool_expr_eval = bool_expr(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; + // Throw if the equality_expression does not produce a expr of boolean type. + bool_expr_eval = conditional_expression(_r1) [ px::bind(&expr::evaluate_boolean, _1, _val) ]; bool_expr_eval.name("bool_expr_eval"); + relational_expression = + additive_expression(_r1) [_val = _1] + >> *( (lit('<') > additive_expression(_r1) ) [px::bind(&expr::lower, _val, _1)] + | (lit('>') > additive_expression(_r1) ) [px::bind(&expr::greater, _val, _1)] + | ("<=" > additive_expression(_r1) ) [px::bind(&expr::leq, _val, _1)] + | (">=" > additive_expression(_r1) ) [px::bind(&expr::geq, _val, _1)] + ); + additive_expression = - term(_r1) [_val = _1] - >> *( (lit('+') > term(_r1) ) [_val += _1] - | (lit('-') > term(_r1) ) [_val -= _1] + multiplicative_expression(_r1) [_val = _1] + >> *( (lit('+') > multiplicative_expression(_r1) ) [_val += _1] + | (lit('-') > multiplicative_expression(_r1) ) [_val -= _1] ); additive_expression.name("additive_expression"); - term = - factor(_r1) [_val = _1] - >> *( (lit('*') > factor(_r1) ) [_val *= _1] - | (lit('/') > factor(_r1) ) [_val /= _1] + multiplicative_expression = + unary_expression(_r1) [_val = _1] + >> *( (lit('*') > unary_expression(_r1) ) [_val *= _1] + | (lit('/') > unary_expression(_r1) ) [_val /= _1] ); - term.name("term"); + multiplicative_expression.name("multiplicative_expression"); struct FactorActions { static void set_start_pos(Iterator &start_pos, expr &out) @@ -740,19 +972,19 @@ namespace client static void not_(expr &value, expr &out) { out = value.unary_not(out.it_range.begin()); } }; - factor = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( - scalar_variable_reference(_r1) [ _val = _1 ] - | (lit('(') > additive_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | (lit('-') > factor(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] - | (lit('+') > factor(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] - | ((kw["not"] | '!') > factor(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] - | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] - | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] - | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] - | raw[lexeme['"' > *((char_ - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] - [ px::bind(&FactorActions::string_, _1, _val) ] + unary_expression = iter_pos[px::bind(&FactorActions::set_start_pos, _1, _val)] >> ( + scalar_variable_reference(_r1) [ _val = _1 ] + | (lit('(') > conditional_expression(_r1) > ')' > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | (lit('-') > unary_expression(_r1) ) [ px::bind(&FactorActions::minus_, _1, _val) ] + | (lit('+') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::expr_, _1, _2, _val) ] + | ((kw["not"] | '!') > unary_expression(_r1) > iter_pos) [ px::bind(&FactorActions::not_, _1, _val) ] + | (strict_double > iter_pos) [ px::bind(&FactorActions::double_, _1, _2, _val) ] + | (int_ > iter_pos) [ px::bind(&FactorActions::int_, _1, _2, _val) ] + | (kw[bool_] > iter_pos) [ px::bind(&FactorActions::bool_, _1, _2, _val) ] + | raw[lexeme['"' > *((utf8char - char_('\\') - char_('"')) | ('\\' > char_)) > '"']] + [ px::bind(&FactorActions::string_, _1, _val) ] ); - factor.name("factor"); + unary_expression.name("unary_expression"); scalar_variable_reference = variable_reference(_r1)[_a=_1] >> @@ -766,16 +998,9 @@ namespace client variable_reference = identifier [ px::bind(&MyContext::resolve_variable, _r1, _1, _val) ]; variable_reference.name("variable reference"); -/* - qi::on_error(start, - phx::ref(std::cout) - << "Error! Expecting " - << qi::_4 - << " here: '" - << px::construct(qi::_3, qi::_2) - << "'\n" - ); -*/ + + regular_expression = raw[lexeme['/' > *((utf8char - char_('\\') - char_('/')) | ('\\' > char_)) > '/']]; + regular_expression.name("regular_expression"); keywords.add ("and") @@ -798,18 +1023,26 @@ namespace client debug(switch_output); debug(legacy_variable_expansion); debug(identifier); - debug(bool_expr); + debug(conditional_expression); + debug(logical_or_expression); + debug(logical_and_expression); + debug(equality_expression); debug(bool_expr_eval); + debug(relational_expression); debug(additive_expression); - debug(term); - debug(factor); + debug(multiplicative_expression); + debug(unary_expression); debug(scalar_variable_reference); debug(variable_reference); + debug(regular_expression); } } + // Generic expression over expr. + typedef qi::rule(const MyContext*), spirit::ascii::space_type> RuleExpression; + // The start of the grammar. - qi::rule start; + qi::rule, spirit::ascii::space_type> start; // A free-form text. qi::rule text; // A free-form text, possibly empty, possibly containing macro expansions. @@ -819,17 +1052,27 @@ namespace client // Legacy variable expansion of the original Slic3r, in the form of [scalar_variable] or [vector_variable_index]. qi::rule legacy_variable_expansion; // Parsed identifier name. - qi::rule(), spirit::ascii::space_type> identifier; - // Math expression consisting of +- operators over terms. - qi::rule(const MyContext*), spirit::ascii::space_type> additive_expression; + qi::rule(), spirit::ascii::space_type> identifier; + // Ternary operator (?:) over logical_or_expression. + RuleExpression conditional_expression; + // Logical or over logical_and_expressions. + RuleExpression logical_or_expression; + // Logical and over relational_expressions. + RuleExpression logical_and_expression; + // <, >, <=, >= + RuleExpression relational_expression; + // Math expression consisting of +- operators over multiplicative_expressions. + RuleExpression additive_expression; // Boolean expressions over expressions. - qi::rule(const MyContext*), spirit::ascii::space_type> bool_expr; + RuleExpression equality_expression; + // Math expression consisting of */ operators over factors. + RuleExpression multiplicative_expression; + // Number literals, functions, braced expressions, variable references, variable indexing references. + RuleExpression unary_expression; + // Rule to capture a regular expression enclosed in //. + qi::rule(), spirit::ascii::space_type> regular_expression; // Evaluate boolean expression into bool. qi::rule bool_expr_eval; - // Math expression consisting of */ operators over factors. - qi::rule(const MyContext*), spirit::ascii::space_type> term; - // Number literals, functions, braced expressions, variable references, variable indexing references. - qi::rule(const MyContext*), spirit::ascii::space_type> factor; // Reference of a scalar variable, or reference to a field of a vector variable. qi::rule(const MyContext*), qi::locals, int>, spirit::ascii::space_type> scalar_variable_reference; // Rule to translate an identifier to a ConfigOption, or to fail. @@ -842,69 +1085,50 @@ namespace client }; } -struct printer +static std::string process_macro(const std::string &templ, client::MyContext &context) { - typedef spirit::utf8_string string; + typedef std::string::const_iterator iterator_type; + typedef client::macro_processor macro_processor; - void element(string const& tag, string const& value, int depth) const - { - for (int i = 0; i < (depth*4); ++i) // indent to depth - std::cout << ' '; - std::cout << "tag: " << tag; - if (value != "") - std::cout << ", value: " << value; - std::cout << std::endl; + // Our whitespace skipper. + spirit::ascii::space_type space; + // Our grammar, statically allocated inside the method, meaning it will be allocated the first time + // PlaceholderParser::process() runs. + //FIXME this kind of initialization is not thread safe! + static macro_processor macro_processor_instance; + // Iterators over the source template. + std::string::const_iterator iter = templ.begin(); + std::string::const_iterator end = templ.end(); + // Accumulator for the processed template. + std::string output; + bool res = phrase_parse(iter, end, macro_processor_instance(&context), space, output); + if (! context.error_message.empty()) { + if (context.error_message.back() != '\n' && context.error_message.back() != '\r') + context.error_message += '\n'; + throw std::runtime_error(context.error_message); } -}; - -void print_info(spirit::info const& what) -{ - using spirit::basic_info_walker; - printer pr; - basic_info_walker walker(pr, what.tag, 0); - boost::apply_visitor(walker, what.value); + return output; } std::string PlaceholderParser::process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override) const { - typedef std::string::const_iterator iterator_type; - typedef client::calculator calculator; + client::MyContext context; + context.config = &this->config(); + context.config_override = config_override; + context.current_extruder_id = current_extruder_id; + return process_macro(templ, context); +} - spirit::ascii::space_type space; // Our skipper - calculator calc; // Our grammar - - std::string::const_iterator iter = templ.begin(); - std::string::const_iterator end = templ.end(); - //std::string result; - std::string result; - bool r = false; - try { - client::MyContext context; - context.pp = this; - context.config_override = config_override; - r = phrase_parse(iter, end, calc(&context), space, result); - } catch (qi::expectation_failure const& x) { - std::cout << "expected: "; print_info(x.what_); - std::cout << "got: \"" << std::string(x.first, x.last) << '"' << std::endl; - } - - if (r && iter == end) - { -// std::cout << "-------------------------\n"; -// std::cout << "Parsing succeeded\n"; -// std::cout << "result = " << result << std::endl; -// std::cout << "-------------------------\n"; - } - else - { - std::string rest(iter, end); - std::cout << "-------------------------\n"; - std::cout << "Parsing failed\n"; - std::cout << "stopped at: \" " << rest << "\"\n"; - std::cout << "source: \n" << templ; - std::cout << "-------------------------\n"; - } - return result; +// Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. +// Throws std::runtime_error on syntax or runtime error. +bool PlaceholderParser::evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override) +{ + client::MyContext context; + context.config = &config; + context.config_override = config_override; + // Let the macro processor parse just a boolean expression, not the full macro language. + context.just_boolean_expression = true; + return process_macro(templ, context) == "true"; } } diff --git a/xs/src/libslic3r/PlaceholderParser.hpp b/xs/src/libslic3r/PlaceholderParser.hpp index 9ec2eedea..4e0aa9ee2 100644 --- a/xs/src/libslic3r/PlaceholderParser.hpp +++ b/xs/src/libslic3r/PlaceholderParser.hpp @@ -22,14 +22,21 @@ public: void set(const std::string &key, const std::string &value) { this->set(key, new ConfigOptionString(value)); } void set(const std::string &key, int value) { this->set(key, new ConfigOptionInt(value)); } void set(const std::string &key, unsigned int value) { this->set(key, int(value)); } + void set(const std::string &key, bool value) { this->set(key, new ConfigOptionBool(value)); } void set(const std::string &key, double value) { this->set(key, new ConfigOptionFloat(value)); } void set(const std::string &key, const std::vector &values) { this->set(key, new ConfigOptionStrings(values)); } void set(const std::string &key, ConfigOption *opt) { m_config.set_key_value(key, opt); } - const ConfigOption* option(const std::string &key) const { return m_config.option(key); } + const DynamicConfig& config() const { return m_config; } + const ConfigOption* option(const std::string &key) const { return m_config.option(key); } - // Fill in the template. + // Fill in the template using a macro processing language. + // Throws std::runtime_error on syntax or runtime error. std::string process(const std::string &templ, unsigned int current_extruder_id, const DynamicConfig *config_override = nullptr) const; + // Evaluate a boolean expression using the full expressive power of the PlaceholderParser boolean expression syntax. + // Throws std::runtime_error on syntax or runtime error. + static bool evaluate_boolean_expression(const std::string &templ, const DynamicConfig &config, const DynamicConfig *config_override = nullptr); + private: DynamicConfig m_config; }; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index cfc26eeac..3cb2e481b 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -975,16 +975,52 @@ void Print::_make_wipe_tower() // Let the ToolOrdering class know there will be initial priming extrusions at the start of the print. m_tool_ordering = ToolOrdering(*this, (unsigned int)-1, true); - unsigned int initial_extruder_id = m_tool_ordering.first_extruder(); if (! m_tool_ordering.has_wipe_tower()) // Don't generate any wipe tower. return; + // Check whether there are any layers in m_tool_ordering, which are marked with has_wipe_tower, + // they print neither object, nor support. These layers are above the raft and below the object, and they + // shall be added to the support layers to be printed. + // see https://github.com/prusa3d/Slic3r/issues/607 + { + size_t idx_begin = size_t(-1); + size_t idx_end = m_tool_ordering.layer_tools().size(); + // Find the first wipe tower layer, which does not have a counterpart in an object or a support layer. + for (size_t i = 0; i < idx_end; ++ i) { + const ToolOrdering::LayerTools < = m_tool_ordering.layer_tools()[i]; + if (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support) { + idx_begin = i; + break; + } + } + if (idx_begin != size_t(-1)) { + // Find the position in this->objects.first()->support_layers to insert these new support layers. + double wipe_tower_new_layer_print_z_first = m_tool_ordering.layer_tools()[idx_begin].print_z; + SupportLayerPtrs::iterator it_layer = this->objects.front()->support_layers.begin(); + for (; (*it_layer)->print_z - EPSILON < wipe_tower_new_layer_print_z_first; ++ it_layer) ; + // Find the stopper of the sequence of wipe tower layers, which do not have a counterpart in an object or a support layer. + for (size_t i = idx_begin; i < idx_end; ++ i) { + ToolOrdering::LayerTools < = const_cast(m_tool_ordering.layer_tools()[i]); + if (! (lt.has_wipe_tower && ! lt.has_object && ! lt.has_support)) + break; + lt.has_support = true; + // Insert the new support layer. + //FIXME the support layer ID is duplicated, but Vojtech hopes it is not being used anywhere anyway. + double height = lt.print_z - m_tool_ordering.layer_tools()[i-1].print_z; + auto *new_layer = new SupportLayer((*it_layer)->id(), this->objects.front(), + height, lt.print_z, lt.print_z - 0.5 * height); + it_layer = this->objects.front()->support_layers.insert(it_layer, new_layer); + ++ it_layer; + } + } + } + // Initialize the wipe tower. WipeTowerPrusaMM wipe_tower( float(this->config.wipe_tower_x.value), float(this->config.wipe_tower_y.value), float(this->config.wipe_tower_width.value), float(this->config.wipe_tower_per_color_wipe.value), - float(this->config.wipe_tower_rotation_angle.value), initial_extruder_id); + float(this->config.wipe_tower_rotation_angle.value), m_tool_ordering.first_extruder()); //wipe_tower.set_retract(); //wipe_tower.set_zhop(); @@ -1029,9 +1065,12 @@ void Print::_make_wipe_tower() // Generate the wipe tower layers. m_wipe_tower_tool_changes.reserve(m_tool_ordering.layer_tools().size()); + wipe_tower.generate(m_wipe_tower_tool_changes); - /*unsigned int current_extruder_id = initial_extruder_id; + // Set current_extruder_id to the last extruder primed. + unsigned int current_extruder_id = m_tool_ordering.all_extruders().back(); + for (const ToolOrdering::LayerTools &layer_tools : m_tool_ordering.layer_tools()) { if (! layer_tools.has_wipe_tower) // This is a support only layer, or the wipe tower does not reach to this height. @@ -1046,7 +1085,11 @@ void Print::_make_wipe_tower() last_layer); std::vector tool_changes; for (unsigned int extruder_id : layer_tools.extruders) - if ((first_layer && extruder_id == initial_extruder_id) || extruder_id != current_extruder_id) { + // Call the wipe_tower.tool_change() at the first layer for the initial extruder + // to extrude the wipe tower brim, + if ((first_layer && extruder_id == m_tool_ordering.all_extruders().back()) || + // or when an extruder shall be switched. + extruder_id != current_extruder_id) { tool_changes.emplace_back(wipe_tower.tool_change(extruder_id, extruder_id == layer_tools.extruders.back(), WipeTower::PURPOSE_EXTRUDE)); current_extruder_id = extruder_id; } @@ -1096,7 +1139,11 @@ void Print::_make_wipe_tower() std::string Print::output_filename() { this->placeholder_parser.update_timestamp(); - return this->placeholder_parser.process(this->config.output_filename_format.value, 0); + try { + return this->placeholder_parser.process(this->config.output_filename_format.value, 0); + } catch (std::runtime_error &err) { + throw std::runtime_error(std::string("Failed processing of the output_filename_format template.\n") + err.what()); + } } std::string Print::output_filepath(const std::string &path) diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index b561388fd..e44c3608a 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -14,6 +14,9 @@ PrintConfigDef::PrintConfigDef() t_optiondef_map &Options = this->options; ConfigOptionDef* def; + + // Maximum extruder temperature, bumped to 1500 to support printing of glass. + const int max_temp = 1500; def = this->add("avoid_crossing_perimeters", coBool); def->label = "Avoid crossing perimeters"; @@ -136,6 +139,13 @@ PrintConfigDef::PrintConfigDef() def->label = "Compatible printers"; def->default_value = new ConfigOptionStrings(); + def = this->add("compatible_printers_condition", coString); + def->label = "Compatible printers condition"; + def->tooltip = "A boolean expression using the configuration values of an active printer profile. " + "If this expression evaluates to true, this profile is considered compatible " + "with the active printer profile."; + def->default_value = new ConfigOptionString(); + def = this->add("complete_objects", coBool); def->label = "Complete individual objects"; def->tooltip = "When printing multiple objects or copies, this feature will complete " @@ -245,6 +255,7 @@ PrintConfigDef::PrintConfigDef() def->enum_labels.push_back("Hilbert Curve"); def->enum_labels.push_back("Archimedean Chords"); def->enum_labels.push_back("Octagram Spiral"); + // solid_fill_pattern is an obsolete equivalent to external_fill_pattern. def->aliases.push_back("solid_fill_pattern"); def->default_value = new ConfigOptionEnum(ipRectilinear); @@ -610,7 +621,7 @@ PrintConfigDef::PrintConfigDef() "during print, set this to zero to disable temperature control commands in the output file."; def->cli = "first-layer-temperature=i@"; def->min = 0; - def->max = 500; + def->max = max_temp; def->default_value = new ConfigOptionInts { 200 }; def = this->add("gap_fill_speed", coFloat); @@ -1314,8 +1325,8 @@ PrintConfigDef::PrintConfigDef() "Enables a full-height \"sacrificial\" skirt on which the nozzles are periodically wiped."; def->sidetext = "∆°C"; def->cli = "standby-temperature-delta=i"; - def->min = -500; - def->max = 500; + def->min = -max_temp; + def->max = max_temp; def->default_value = new ConfigOptionInt(-5); def = this->add("start_gcode", coString); @@ -1555,7 +1566,7 @@ PrintConfigDef::PrintConfigDef() def->cli = "temperature=i@"; def->full_label = "Temperature"; def->max = 0; - def->max = 500; + def->max = max_temp; def->default_value = new ConfigOptionInts { 200 }; def = this->add("thin_walls", coBool); diff --git a/xs/src/libslic3r/PrintObject.cpp b/xs/src/libslic3r/PrintObject.cpp index fc2979c20..c61fc102b 100644 --- a/xs/src/libslic3r/PrintObject.cpp +++ b/xs/src/libslic3r/PrintObject.cpp @@ -447,7 +447,8 @@ void PrintObject::detect_surfaces_type() to_polygons(upper_layer->get_region(idx_region)->slices.surfaces) : to_polygons(upper_layer->slices); surfaces_append(top, - offset2_ex(diff(layerm_slices_surfaces, upper_slices, true), -offset, offset), + //FIXME implement offset2_ex working over ExPolygons, that should be a bit more efficient than calling offset_ex twice. + offset_ex(offset_ex(diff_ex(layerm_slices_surfaces, upper_slices, true), -offset), offset), stTop); } else { // if no upper layer, all surfaces of this one are solid diff --git a/xs/src/libslic3r/Slicing.hpp b/xs/src/libslic3r/Slicing.hpp index 1534e19f5..b4a074bb5 100644 --- a/xs/src/libslic3r/Slicing.hpp +++ b/xs/src/libslic3r/Slicing.hpp @@ -103,7 +103,7 @@ inline bool equal_layering(const SlicingParameters &sp1, const SlicingParameters sp1.layer_height == sp2.layer_height && sp1.min_layer_height == sp2.min_layer_height && sp1.max_layer_height == sp2.max_layer_height && - sp1.max_suport_layer_height == sp2.max_suport_layer_height && +// sp1.max_suport_layer_height == sp2.max_suport_layer_height && sp1.first_print_layer_height == sp2.first_print_layer_height && sp1.first_object_layer_height == sp2.first_object_layer_height && sp1.first_object_layer_bridging == sp2.first_object_layer_bridging && diff --git a/xs/src/libslic3r/SupportMaterial.cpp b/xs/src/libslic3r/SupportMaterial.cpp index 7a05cf998..b8df67ba6 100644 --- a/xs/src/libslic3r/SupportMaterial.cpp +++ b/xs/src/libslic3r/SupportMaterial.cpp @@ -373,15 +373,9 @@ void PrintObjectSupportMaterial::generate(PrintObject &object) height_min = std::min(height_min, layer.height); } if (! empty) { - object.add_support_layer(layer_id, height_min, zavg); - if (layer_id > 0) { - // Inter-link the support layers into a linked list. - SupportLayer *sl1 = object.support_layers[object.support_layer_count() - 2]; - SupportLayer *sl2 = object.support_layers.back(); - sl1->upper_layer = sl2; - sl2->lower_layer = sl1; - } - ++layer_id; + // Here the upper_layer and lower_layer pointers are left to null at the support layers, + // as they are never used. These pointers are candidates for removal. + object.add_support_layer(layer_id ++, height_min, zavg); } i = j; } @@ -2569,7 +2563,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // TODO: use brim ordering algorithm to_infill_polygons = to_polygons(to_infill); // TODO: use offset2_ex() - to_infill = offset_ex(to_infill, float(- flow.scaled_spacing())); + to_infill = offset_ex(to_infill, float(- 0.4 * flow.scaled_spacing())); extrusion_entities_append_paths( support_layer.support_fills.entities, to_polylines(STDMOVE(to_infill_polygons)), @@ -2602,7 +2596,8 @@ void PrintObjectSupportMaterial::generate_toolpaths( // Base flange. filler->angle = raft_angle_1st_layer; filler->spacing = m_first_layer_flow.spacing(); - density = 0.5f; + // 70% of density on the 1st layer. + density = 0.7f; } else if (support_layer_id >= m_slicing_params.base_raft_layers) { filler->angle = raft_angle_interface; // We don't use $base_flow->spacing because we need a constant spacing @@ -2776,7 +2771,7 @@ void PrintObjectSupportMaterial::generate_toolpaths( // TODO: use brim ordering algorithm Polygons to_infill_polygons = to_polygons(to_infill); // TODO: use offset2_ex() - to_infill = offset_ex(to_infill, - float(flow.scaled_spacing())); + to_infill = offset_ex(to_infill, - 0.4 * float(flow.scaled_spacing())); extrusion_entities_append_paths( base_layer.extrusions, to_polylines(STDMOVE(to_infill_polygons)), diff --git a/xs/src/libslic3r/Utils.hpp b/xs/src/libslic3r/Utils.hpp index 308a2a118..3afbc912f 100644 --- a/xs/src/libslic3r/Utils.hpp +++ b/xs/src/libslic3r/Utils.hpp @@ -15,15 +15,15 @@ const std::string& var_dir(); // Return a full resource path for a file_name. std::string var(const std::string &file_name); +// Set a path with various static definition data (for example the initial config bundles). +void set_resources_dir(const std::string &path); +// Return a full path to the resources directory. +const std::string& resources_dir(); + // Set a path with preset files. void set_data_dir(const std::string &path); // Return a full path to the GUI resource files. const std::string& data_dir(); -// Return a full path to a configuration file given its file name.. -std::string config_path(const std::string &file_name); -// Return a full path to a configuration file given the section and name. -// The suffix ".ini" will be added if it is missing in the name. -std::string config_path(const std::string §ion, const std::string &name); extern std::string encode_path(const char *src); extern std::string decode_path(const char *src); diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 644190d6a..f71311e7f 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -14,7 +14,7 @@ #include #define SLIC3R_FORK_NAME "Slic3r Prusa Edition" -#define SLIC3R_VERSION "1.38.2" +#define SLIC3R_VERSION "1.38.4" #define SLIC3R_BUILD "UNKNOWN" typedef long coord_t; diff --git a/xs/src/libslic3r/utils.cpp b/xs/src/libslic3r/utils.cpp index f4c03ef50..ef05dcae7 100644 --- a/xs/src/libslic3r/utils.cpp +++ b/xs/src/libslic3r/utils.cpp @@ -89,6 +89,18 @@ std::string var(const std::string &file_name) return file.string(); } +static std::string g_resources_dir; + +void set_resources_dir(const std::string &dir) +{ + g_resources_dir = dir; +} + +const std::string& resources_dir() +{ + return g_resources_dir; +} + static std::string g_data_dir; void set_data_dir(const std::string &dir) @@ -101,19 +113,6 @@ const std::string& data_dir() return g_data_dir; } -std::string config_path(const std::string &file_name) -{ - auto file = (boost::filesystem::path(g_data_dir) / file_name).make_preferred(); - return file.string(); -} - -std::string config_path(const std::string §ion, const std::string &name) -{ - auto file_name = boost::algorithm::iends_with(name, ".ini") ? name : name + ".ini"; - auto file = (boost::filesystem::path(g_data_dir) / section / file_name).make_preferred(); - return file.string(); -} - } // namespace Slic3r #ifdef SLIC3R_HAS_BROKEN_CROAK @@ -194,6 +193,7 @@ confess_at(const char *file, int line, const char *func, namespace Slic3r { +// Encode an UTF-8 string to the local code page. std::string encode_path(const char *src) { #ifdef WIN32 @@ -211,6 +211,7 @@ std::string encode_path(const char *src) #endif /* WIN32 */ } +// Encode an 8-bit string from a local code page to UTF-8. std::string decode_path(const char *src) { #ifdef WIN32 diff --git a/xs/src/slic3r/GUI/AppConfig.cpp b/xs/src/slic3r/GUI/AppConfig.cpp index 3161c5b78..9378a2094 100644 --- a/xs/src/slic3r/GUI/AppConfig.cpp +++ b/xs/src/slic3r/GUI/AppConfig.cpp @@ -45,6 +45,10 @@ void AppConfig::set_defaults() // Version check is enabled by default in the config, but it is not implemented yet. if (get("version_check").empty()) set("version_check", "1"); + // Use OpenGL 1.1 even if OpenGL 2.0 is available. This is mainly to support some buggy Intel HD Graphics drivers. + // https://github.com/prusa3d/Slic3r/issues/233 + if (get("use_legacy_opengl").empty()) + set("use_legacy_opengl", "0"); } void AppConfig::load() diff --git a/xs/src/slic3r/GUI/GUI.cpp b/xs/src/slic3r/GUI/GUI.cpp index 63cc7749d..8db0508f1 100644 --- a/xs/src/slic3r/GUI/GUI.cpp +++ b/xs/src/slic3r/GUI/GUI.cpp @@ -13,6 +13,14 @@ #pragma comment(lib, "user32.lib") #endif +#include +#include +#include +#include +#include +#include +#include + namespace Slic3r { namespace GUI { #if __APPLE__ @@ -134,4 +142,45 @@ void break_to_debugger() #endif /* _WIN32 */ } +// Passing the wxWidgets GUI classes instantiated by the Perl part to C++. +wxApp *g_wxApp = nullptr; +wxFrame *g_wxMainFrame = nullptr; +wxNotebook *g_wxTabPanel = nullptr; + +void set_wxapp(wxApp *app) +{ + g_wxApp = app; +} + +void set_main_frame(wxFrame *main_frame) +{ + g_wxMainFrame = main_frame; +} + +void set_tab_panel(wxNotebook *tab_panel) +{ + g_wxTabPanel = tab_panel; +} + +void add_debug_menu(wxMenuBar *menu) +{ +#if 0 + auto debug_menu = new wxMenu(); + debug_menu->Append(wxWindow::NewControlId(1), "Some debug"); + menu->Append(debug_menu, _T("&Debug")); +#endif +} + +void create_preset_tab(const char *name) +{ + auto *panel = new wxPanel(g_wxTabPanel, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBK_LEFT | wxTAB_TRAVERSAL); + // Vertical sizer to hold the choice menu and the rest of the page. + auto *sizer = new wxBoxSizer(wxVERTICAL); + sizer->SetSizeHints(panel); + panel->SetSizer(sizer); + auto *button = new wxButton(panel, wxID_ANY, "Hello World", wxDefaultPosition, wxDefaultSize, 0); + sizer->Add(button, 0, 0, 0); + g_wxTabPanel->AddPage(panel, name); +} + } } diff --git a/xs/src/slic3r/GUI/GUI.hpp b/xs/src/slic3r/GUI/GUI.hpp index 955a1cd8d..3634e0bc8 100644 --- a/xs/src/slic3r/GUI/GUI.hpp +++ b/xs/src/slic3r/GUI/GUI.hpp @@ -4,6 +4,11 @@ #include #include +class wxApp; +class wxFrame; +class wxMenuBar; +class wxNotebook; + namespace Slic3r { namespace GUI { void disable_screensaver(); @@ -12,6 +17,16 @@ std::vector scan_serial_ports(); bool debugged(); void break_to_debugger(); +// Passing the wxWidgets GUI classes instantiated by the Perl part to C++. +void set_wxapp(wxApp *app); +void set_main_frame(wxFrame *main_frame); +void set_tab_panel(wxNotebook *tab_panel); + +void add_debug_menu(wxMenuBar *menu); +// Create a new preset tab (print, filament or printer), +// add it at the end of the tab panel. +void create_preset_tab(const char *name); + } } #endif diff --git a/xs/src/slic3r/GUI/Preset.cpp b/xs/src/slic3r/GUI/Preset.cpp index 2d6ff59b0..4d55f347a 100644 --- a/xs/src/slic3r/GUI/Preset.cpp +++ b/xs/src/slic3r/GUI/Preset.cpp @@ -21,6 +21,7 @@ #include "../../libslic3r/libslic3r.h" #include "../../libslic3r/Utils.hpp" +#include "../../libslic3r/PlaceholderParser.hpp" namespace Slic3r { @@ -79,7 +80,8 @@ void Preset::set_num_extruders(DynamicPrintConfig &config, unsigned int num_extr auto *opt = config.option(key, false); assert(opt != nullptr); assert(opt->is_vector()); - static_cast(opt)->resize(num_extruders, defaults.option(key)); + if (opt != nullptr && opt->is_vector()) + static_cast(opt)->resize(num_extruders, defaults.option(key)); } } @@ -140,18 +142,37 @@ std::string Preset::label() const return this->name + (this->is_dirty ? g_suffix_modified : ""); } -bool Preset::is_compatible_with_printer(const std::string &active_printer) const +bool Preset::is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const { - auto *compatible_printers = dynamic_cast(this->config.option("compatible_printers")); - return this->is_default || active_printer.empty() || - compatible_printers == nullptr || compatible_printers->values.empty() || - std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer) != + auto *condition = dynamic_cast(this->config.option("compatible_printers_condition")); + auto *compatible_printers = dynamic_cast(this->config.option("compatible_printers")); + bool has_compatible_printers = compatible_printers != nullptr && ! compatible_printers->values.empty(); + if (! has_compatible_printers && condition != nullptr && ! condition->value.empty()) { + try { + return PlaceholderParser::evaluate_boolean_expression(condition->value, active_printer.config, extra_config); + } catch (const std::runtime_error &err) { + //FIXME in case of an error, return "compatible with everything". + printf("Preset::is_compatible_with_printer - parsing error of compatible_printers_condition %s:\n%s\n", active_printer.name.c_str(), err.what()); + return true; + } + } + return this->is_default || active_printer.name.empty() || ! has_compatible_printers || + std::find(compatible_printers->values.begin(), compatible_printers->values.end(), active_printer.name) != compatible_printers->values.end(); } -bool Preset::update_compatible_with_printer(const std::string &active_printer) +bool Preset::is_compatible_with_printer(const Preset &active_printer) const { - return this->is_compatible = is_compatible_with_printer(active_printer); + DynamicPrintConfig config; + config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name)); + config.set_key_value("num_extruders", new ConfigOptionInt( + (int)static_cast(active_printer.config.option("nozzle_diameter"))->values.size())); + return this->is_compatible_with_printer(active_printer, &config); +} + +bool Preset::update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) +{ + return this->is_compatible = is_compatible_with_printer(active_printer, extra_config); } const std::vector& Preset::print_options() @@ -179,7 +200,8 @@ const std::vector& Preset::print_options() "top_infill_extrusion_width", "support_material_extrusion_width", "infill_overlap", "bridge_flow_ratio", "clip_multipart_objects", "elefant_foot_compensation", "xy_size_compensation", "threads", "resolution", "wipe_tower", "wipe_tower_x", "wipe_tower_y", "wipe_tower_width", "wipe_tower_per_color_wipe", "wipe_tower_rotation_angle", - "compatible_printers" + "compatible_printers", "compatible_printers_condition" + }; return s_opts; } @@ -192,7 +214,7 @@ const std::vector& Preset::filament_options() "first_layer_bed_temperature", "fan_always_on", "cooling", "min_fan_speed", "max_fan_speed", "bridge_fan_speed", "disable_fan_first_layers", "fan_below_layer_time", "slowdown_below_layer_time", "min_print_speed", "start_filament_gcode", "end_filament_gcode", - "compatible_printers" + "compatible_printers", "compatible_printers_condition" }; return s_opts; } @@ -242,6 +264,21 @@ PresetCollection::~PresetCollection() m_bitmap_main_frame = nullptr; } +void PresetCollection::reset(bool delete_files) +{ + if (m_presets.size() > 1) { + if (delete_files) { + // Erase the preset files. + for (Preset &preset : m_presets) + if (! preset.is_default && ! preset.is_external) + boost::nowide::remove(preset.file.c_str()); + } + // Don't use m_presets.resize() here as it requires a default constructor for Preset. + m_presets.erase(m_presets.begin() + 1, m_presets.end()); + this->select_preset(0); + } +} + // Load all presets found in dir_path. // Throws an exception on error. void PresetCollection::load_presets(const std::string &dir_path, const std::string &subdir) @@ -283,10 +320,11 @@ Preset& PresetCollection::load_preset(const std::string &path, const std::string Preset& PresetCollection::load_preset(const std::string &path, const std::string &name, DynamicPrintConfig &&config, bool select) { - Preset key(m_type, name); - auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key); - if (it == m_presets.end() || it->name != name) + auto it = this->find_preset_internal(name); + if (it == m_presets.end() || it->name != name) { + // The preset was not found. Create a new preset. it = m_presets.emplace(it, Preset(m_type, name, false)); + } Preset &preset = *it; preset.file = path; preset.config = std::move(config); @@ -301,9 +339,8 @@ void PresetCollection::save_current_preset(const std::string &new_name) { // 1) Find the preset with a new_name or create a new one, // initialize it with the edited config. - Preset key(m_type, new_name, false); - auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key); - if (it != m_presets.end() && it->name == key.name) { + auto it = this->find_preset_internal(new_name); + if (it != m_presets.end() && it->name == new_name) { // Preset with the same name found. Preset &preset = *it; if (preset.is_default) @@ -314,11 +351,8 @@ void PresetCollection::save_current_preset(const std::string &new_name) } else { // Creating a new preset. Preset &preset = *m_presets.insert(it, m_edited_preset); - std::string file_name = new_name; - if (! boost::iends_with(file_name, ".ini")) - file_name += ".ini"; preset.name = new_name; - preset.file = (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); + preset.file = this->path_from_name(new_name); } // 2) Activate the saved preset. this->select_preset_by_name(new_name, true); @@ -356,7 +390,7 @@ bool PresetCollection::load_bitmap_default(const std::string &file_name) Preset* PresetCollection::find_preset(const std::string &name, bool first_visible_if_not_found) { Preset key(m_type, name, false); - auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key); + auto it = this->find_preset_internal(name); // Ensure that a temporary copy is returned if the preset found is currently selected. return (it != m_presets.end() && it->name == key.name) ? &this->preset(it - m_presets.begin()) : first_visible_if_not_found ? &this->first_visible() : nullptr; @@ -394,31 +428,25 @@ void PresetCollection::set_default_suppressed(bool default_suppressed) } } -void PresetCollection::update_compatible_with_printer(const std::string &active_printer, bool select_other_if_incompatible) +void PresetCollection::update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible) { - size_t num_visible = 0; + DynamicPrintConfig config; + config.set_key_value("printer_preset", new ConfigOptionString(active_printer.name)); + config.set_key_value("num_extruders", new ConfigOptionInt( + (int)static_cast(active_printer.config.option("nozzle_diameter"))->values.size())); for (size_t idx_preset = 1; idx_preset < m_presets.size(); ++ idx_preset) { bool selected = idx_preset == m_idx_selected; Preset &preset_selected = m_presets[idx_preset]; Preset &preset_edited = selected ? m_edited_preset : preset_selected; - if (preset_edited.update_compatible_with_printer(active_printer)) - // Mark compatible presets as visible. - preset_selected.is_visible = true; - else if (selected && select_other_if_incompatible) { - preset_selected.is_visible = false; + if (! preset_edited.update_compatible_with_printer(active_printer, &config) && + selected && select_other_if_incompatible) m_idx_selected = (size_t)-1; - } if (selected) preset_selected.is_compatible = preset_edited.is_compatible; - if (preset_selected.is_visible) - ++ num_visible; } if (m_idx_selected == (size_t)-1) - // Find some other visible preset. - this->select_preset(first_visible_idx()); - else if (num_visible == 0) - // Show the "-- default --" preset. - m_presets.front().is_visible = true; + // Find some other compatible preset, or the "-- default --" preset. + this->select_preset(first_compatible_idx()); } // Save the preset under a new name. If the name is different from the old one, @@ -459,7 +487,7 @@ void PresetCollection::update_tab_ui(wxBitmapComboBox *ui, bool show_incompatibl ui->Clear(); for (size_t i = this->m_presets.front().is_visible ? 0 : 1; i < this->m_presets.size(); ++ i) { const Preset &preset = this->m_presets[i]; - if (! show_incompatible && ! preset.is_compatible && i != m_idx_selected) + if (! preset.is_visible || (! show_incompatible && ! preset.is_compatible && i != m_idx_selected)) continue; const wxBitmap *bmp = preset.is_compatible ? m_bitmap_compatible : m_bitmap_incompatible; ui->Append(wxString::FromUTF8((preset.name + (preset.is_dirty ? g_suffix_modified : "")).c_str()), @@ -486,13 +514,36 @@ bool PresetCollection::update_dirty_ui(wxBitmapComboBox *ui) std::string preset_name = Preset::remove_suffix_modified(old_label); const Preset *preset = this->find_preset(preset_name, false); assert(preset != nullptr); - std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name; - if (old_label != new_label) - ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str())); + if (preset != nullptr) { + std::string new_label = preset->is_dirty ? preset->name + g_suffix_modified : preset->name; + if (old_label != new_label) + ui->SetString(ui_id, wxString::FromUTF8(new_label.c_str())); + } } +#ifdef __APPLE__ + // wxWidgets on OSX do not upload the text of the combo box line automatically. + // Force it to update by re-selecting. + ui->SetSelection(ui->GetSelection()); +#endif /* __APPLE __ */ return was_dirty != is_dirty; } +std::vector PresetCollection::current_dirty_options() const +{ + std::vector changed = this->get_selected_preset().config.diff(this->get_edited_preset().config); + // The "compatible_printers" option key is handled differently from the others: + // It is not mandatory. If the key is missing, it means it is compatible with any printer. + // If the key exists and it is empty, it means it is compatible with no printer. + std::initializer_list optional_keys { "compatible_printers", "compatible_printers_condition" }; + for (auto &opt_key : optional_keys) { + if (this->get_selected_preset().config.has(opt_key) != this->get_edited_preset().config.has(opt_key)) + changed.emplace_back(opt_key); + } + return changed; +} + +// Select a new preset. This resets all the edits done to the currently selected preset. +// If the preset with index idx does not exist, a first visible preset is selected. Preset& PresetCollection::select_preset(size_t idx) { for (Preset &preset : m_presets) @@ -509,10 +560,9 @@ bool PresetCollection::select_preset_by_name(const std::string &name_w_suffix, b { std::string name = Preset::remove_suffix_modified(name_w_suffix); // 1) Try to find the preset by its name. - Preset key(m_type, name, false); - auto it = std::lower_bound(m_presets.begin(), m_presets.end(), key); + auto it = this->find_preset_internal(name); size_t idx = 0; - if (it != m_presets.end() && it->name == key.name) + if (it != m_presets.end() && it->name == name) // Preset found by its name. idx = it - m_presets.begin(); else { @@ -544,4 +594,11 @@ std::string PresetCollection::name() const } } +// Generate a file path from a profile name. Add the ".ini" suffix if it is missing. +std::string PresetCollection::path_from_name(const std::string &new_name) const +{ + std::string file_name = boost::iends_with(new_name, ".ini") ? new_name : (new_name + ".ini"); + return (boost::filesystem::path(m_dir_path) / file_name).make_preferred().string(); +} + } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/Preset.hpp b/xs/src/slic3r/GUI/Preset.hpp index f44fd1590..1f6a90595 100644 --- a/xs/src/slic3r/GUI/Preset.hpp +++ b/xs/src/slic3r/GUI/Preset.hpp @@ -79,9 +79,11 @@ public: void set_dirty(bool dirty = true) { this->is_dirty = dirty; } void reset_dirty() { this->is_dirty = false; } - bool is_compatible_with_printer(const std::string &active_printer) const; + bool is_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config) const; + bool is_compatible_with_printer(const Preset &active_printer) const; + // Mark this preset as compatible if it is compatible with active_printer. - bool update_compatible_with_printer(const std::string &active_printer); + bool update_compatible_with_printer(const Preset &active_printer, const DynamicPrintConfig *extra_config); // Resize the extruder specific fields, initialize them with the content of the 1st extruder. void set_num_extruders(unsigned int n) { set_num_extruders(this->config, n); } @@ -114,6 +116,8 @@ public: PresetCollection(Preset::Type type, const std::vector &keys); ~PresetCollection(); + void reset(bool delete_files); + Preset::Type type() const { return m_type; } std::string name() const; const std::deque& operator()() const { return m_presets; } @@ -159,7 +163,7 @@ public: // Return a preset by an index. If the preset is active, a temporary copy is returned. Preset& preset(size_t idx) { return (int(idx) == m_idx_selected) ? m_edited_preset : m_presets[idx]; } const Preset& preset(size_t idx) const { return const_cast(this)->preset(idx); } - void discard_current_changes() { m_edited_preset = m_presets[m_idx_selected]; } + void discard_current_changes() { m_presets[m_idx_selected].reset_dirty(); m_edited_preset = m_presets[m_idx_selected]; } // Return a preset by its name. If the preset is active, a temporary copy is returned. // If a preset is not found by its name, null is returned. @@ -180,14 +184,14 @@ public: size_t size() const { return this->m_presets.size(); } // For Print / Filament presets, disable those, which are not compatible with the printer. - void update_compatible_with_printer(const std::string &active_printer, bool select_other_if_incompatible); + void update_compatible_with_printer(const Preset &active_printer, bool select_other_if_incompatible); size_t num_visible() const { return std::count_if(m_presets.begin(), m_presets.end(), [](const Preset &preset){return preset.is_visible;}); } // Compare the content of get_selected_preset() with get_edited_preset() configs, return true if they differ. - bool current_is_dirty() { return ! this->current_dirty_options().empty(); } + bool current_is_dirty() const { return ! this->current_dirty_options().empty(); } // Compare the content of get_selected_preset() with get_edited_preset() configs, return the list of keys where they differ. - std::vector current_dirty_options() { return this->get_selected_preset().config.diff(this->get_edited_preset().config); } + std::vector current_dirty_options() const; // Update the choice UI from the list of presets. // If show_incompatible, all presets are shown, otherwise only the compatible presets are shown. @@ -207,11 +211,26 @@ public: // With force, the changes are reverted if the new index is the same as the old index. bool select_preset_by_name(const std::string &name, bool force); + // Generate a file path from a profile name. Add the ".ini" suffix if it is missing. + std::string path_from_name(const std::string &new_name) const; + private: PresetCollection(); PresetCollection(const PresetCollection &other); PresetCollection& operator=(const PresetCollection &other); + // Find a preset in the sorted list of presets. + // The "-- default -- " preset is always the first, so it needs + // to be handled differently. + std::deque::iterator find_preset_internal(const std::string &name) + { + Preset key(m_type, name); + auto it = std::lower_bound(m_presets.begin() + 1, m_presets.end(), key); + return (it == m_presets.end() && m_presets.front().name == name) ? m_presets.begin() : it; + } + std::deque::const_iterator find_preset_internal(const std::string &name) const + { return const_cast(this)->find_preset_internal(name); } + // Type of this PresetCollection: TYPE_PRINT, TYPE_FILAMENT or TYPE_PRINTER. Preset::Type m_type; // List of presets, starting with the "- default -" preset. diff --git a/xs/src/slic3r/GUI/PresetBundle.cpp b/xs/src/slic3r/GUI/PresetBundle.cpp index 3855760c2..decc5d00b 100644 --- a/xs/src/slic3r/GUI/PresetBundle.cpp +++ b/xs/src/slic3r/GUI/PresetBundle.cpp @@ -1,4 +1,4 @@ -//#undef NDEBUGc +//#undef NDEBUG #include #include "PresetBundle.hpp" @@ -25,6 +25,10 @@ #include "../../libslic3r/PlaceholderParser.hpp" #include "../../libslic3r/Utils.hpp" +// Store the print/filament/printer presets into a "presets" subdirectory of the Slic3rPE config dir. +// This breaks compatibility with the upstream Slic3r if the --datadir is used to switch between the two versions. +// #define SLIC3R_PROFILE_USE_PRESETS_SUBDIR + namespace Slic3r { PresetBundle::PresetBundle() : @@ -34,7 +38,8 @@ PresetBundle::PresetBundle() : m_bitmapCompatible(new wxBitmap), m_bitmapIncompatible(new wxBitmap) { - ::wxInitAllImageHandlers(); + if (wxImage::FindHandler(wxBITMAP_TYPE_PNG) == nullptr) + wxImage::AddHandler(new wxPNGHandler); // Create the ID config keys, as they are not part of the Static print config classes. this->prints.preset(0).config.opt_string("print_settings_id", true); @@ -42,7 +47,9 @@ PresetBundle::PresetBundle() : this->printers.preset(0).config.opt_string("print_settings_id", true); // Create the "compatible printers" keys, as they are not part of the Static print config classes. this->filaments.preset(0).config.optptr("compatible_printers", true); + this->filaments.preset(0).config.optptr("compatible_printers_condition", true); this->prints.preset(0).config.optptr("compatible_printers", true); + this->prints.preset(0).config.optptr("compatible_printers_condition", true); this->prints .load_bitmap_default("cog.png"); this->filaments.load_bitmap_default("spool.png"); @@ -62,23 +69,54 @@ PresetBundle::~PresetBundle() delete bitmap.second; } +void PresetBundle::reset(bool delete_files) +{ + // Clear the existing presets, delete their respective files. + this->prints .reset(delete_files); + this->filaments.reset(delete_files); + this->printers .reset(delete_files); + this->filament_presets.clear(); + this->filament_presets.emplace_back(this->filaments.get_selected_preset().name); +} + void PresetBundle::setup_directories() { - boost::filesystem::path dir = boost::filesystem::canonical(Slic3r::data_dir()); - if (! boost::filesystem::is_directory(dir)) - throw std::runtime_error(std::string("datadir does not exist: ") + Slic3r::data_dir()); - std::initializer_list names = { "print", "filament", "printer" }; - for (const char *name : names) { - boost::filesystem::path subdir = (dir / name).make_preferred(); + boost::filesystem::path data_dir = boost::filesystem::path(Slic3r::data_dir()); + std::initializer_list paths = { + data_dir, +#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR + // Store the print/filament/printer presets into a "presets" directory. + data_dir / "presets", + data_dir / "presets" / "print", + data_dir / "presets" / "filament", + data_dir / "presets" / "printer" +#else + // Store the print/filament/printer presets at the same location as the upstream Slic3r. + data_dir / "print", + data_dir / "filament", + data_dir / "printer" +#endif + }; + for (const boost::filesystem::path &path : paths) { + boost::filesystem::path subdir = path; + subdir.make_preferred(); if (! boost::filesystem::is_directory(subdir) && ! boost::filesystem::create_directory(subdir)) throw std::runtime_error(std::string("Slic3r was unable to create its data directory at ") + subdir.string()); } } -void PresetBundle::load_presets(const std::string &dir_path) +void PresetBundle::load_presets() { std::string errors_cummulative; + const std::string dir_path = data_dir() +#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR + // Store the print/filament/printer presets into a "presets" directory. + + "/presets" +#else + // Store the print/filament/printer presets at the same location as the upstream Slic3r. +#endif + ; try { this->prints.load_presets(dir_path, "print"); } catch (const std::runtime_error &err) { @@ -95,6 +133,7 @@ void PresetBundle::load_presets(const std::string &dir_path) errors_cummulative += err.what(); } this->update_multi_material_filament_presets(); + this->update_compatible_with_printer(false); if (! errors_cummulative.empty()) throw std::runtime_error(errors_cummulative); } @@ -125,8 +164,10 @@ void PresetBundle::load_selections(const AppConfig &config) this->set_filament_preset(i, remove_ini_suffix(config.get("presets", name))); } // Update visibility of presets based on their compatibility with the active printer. - // This will switch the print or filament presets to compatible if the active presets are incompatible. - this->update_compatible_with_printer(false); + // Always try to select a compatible print and filament preset to the current printer preset, + // as the application may have been closed with an active "external" preset, which does not + // exist. + this->update_compatible_with_printer(true); } // Export selections (current print, current filaments, current printer) into config.ini @@ -216,6 +257,8 @@ DynamicPrintConfig PresetBundle::full_config() const } } } + + out.erase("compatible_printers"); static const char *keys[] = { "perimeter", "infill", "solid_infill", "support_material", "support_material_interface" }; for (size_t i = 0; i < sizeof(keys) / sizeof(keys[0]); ++ i) { @@ -239,7 +282,7 @@ void PresetBundle::load_config_file(const std::string &path) config.apply(FullPrintConfig::defaults()); config.load_from_gcode(path); Preset::normalize(config); - load_config_file_config(path, std::move(config)); + load_config_file_config(path, true, std::move(config)); return; } @@ -268,7 +311,7 @@ void PresetBundle::load_config_file(const std::string &path) config.apply(FullPrintConfig::defaults()); config.load(tree); Preset::normalize(config); - load_config_file_config(path, std::move(config)); + load_config_file_config(path, true, std::move(config)); break; } case CONFIG_FILE_TYPE_CONFIG_BUNDLE: @@ -278,17 +321,32 @@ void PresetBundle::load_config_file(const std::string &path) } // Load a config file from a boost property_tree. This is a private method called from load_config_file. -void PresetBundle::load_config_file_config(const std::string &path, const DynamicPrintConfig &config) +void PresetBundle::load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config) { + // The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway, + // but some of the alpha versions of Slic3r did. + { + ConfigOption *opt_compatible = config.optptr("compatible_printers"); + if (opt_compatible != nullptr) { + assert(opt_compatible->type() == coStrings); + if (opt_compatible->type() == coStrings) + static_cast(opt_compatible)->values.clear(); + } + } + // 1) Create a name from the file name. // Keep the suffix (.ini, .gcode, .amf, .3mf etc) to differentiate it from the normal profiles. - std::string name = boost::filesystem::path(path).filename().string(); + std::string name = is_external ? boost::filesystem::path(name_or_path).filename().string() : name_or_path; // 2) If the loading succeeded, split and load the config into print / filament / printer settings. // First load the print and printer presets. for (size_t i_group = 0; i_group < 2; ++ i_group) { PresetCollection &presets = (i_group == 0) ? this->prints : this->printers; - presets.load_preset(path, name, config).is_external = true; + Preset &preset = presets.load_preset(is_external ? name_or_path : presets.path_from_name(name), name, config); + if (is_external) + preset.is_external = true; + else + preset.save(); } // 3) Now load the filaments. If there are multiple filament presets, split them and load them. @@ -296,7 +354,12 @@ void PresetBundle::load_config_file_config(const std::string &path, const Dynami auto *filament_diameter = dynamic_cast(config.option("filament_diameter")); size_t num_extruders = std::min(nozzle_diameter->values.size(), filament_diameter->values.size()); if (num_extruders <= 1) { - this->filaments.load_preset(path, name, config).is_external = true; + Preset &preset = this->filaments.load_preset( + is_external ? name_or_path : this->filaments.path_from_name(name), name, config); + if (is_external) + preset.is_external = true; + else + preset.save(); this->filament_presets.clear(); this->filament_presets.emplace_back(name); } else { @@ -310,7 +373,7 @@ void PresetBundle::load_config_file_config(const std::string &path, const Dynami if (other_opt->is_scalar()) { for (size_t i = 0; i < configs.size(); ++ i) configs[i].option(key, false)->set(other_opt); - } else { + } else if (key != "compatible_printers") { for (size_t i = 0; i < configs.size(); ++ i) static_cast(configs[i].option(key, false))->set_at(other_opt, 0, i); } @@ -323,11 +386,20 @@ void PresetBundle::load_config_file_config(const std::string &path, const Dynami suffix[0] = 0; else sprintf(suffix, " (%d)", i); + std::string new_name = name + suffix; // Load all filament presets, but only select the first one in the preset dialog. - this->filaments.load_preset(path, name + suffix, std::move(configs[i]), i == 0).is_external = true; - this->filament_presets.emplace_back(name + suffix); + Preset &preset = this->filaments.load_preset( + is_external ? name_or_path : this->filaments.path_from_name(new_name), + new_name, std::move(configs[i]), i == 0); + if (is_external) + preset.is_external = true; + else + preset.save(); + this->filament_presets.emplace_back(new_name); } } + + this->update_compatible_with_printer(false); } // Load the active configuration of a config bundle from a boost property_tree. This is a private method called from load_config_file. @@ -335,7 +407,8 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const { // 1) Load the config bundle into a temp data. PresetBundle tmp_bundle; - tmp_bundle.load_configbundle(path); + // Load the config bundle, don't save the loaded presets to user profile directory. + tmp_bundle.load_configbundle(path, 0); std::string bundle_name = std::string(" - ") + boost::filesystem::path(path).filename().string(); // 2) Extract active configs from the config bundle, copy them and activate them in this bundle. @@ -368,6 +441,14 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const } assert(! preset_name_dst.empty()); // Save preset_src->config into collection_dst under preset_name_dst. + // The "compatible_printers" field should not have been exported into a config.ini or a G-code anyway, + // but some of the alpha versions of Slic3r did. + ConfigOption *opt_compatible = preset_src->config.optptr("compatible_printers"); + if (opt_compatible != nullptr) { + assert(opt_compatible->type() == coStrings); + if (opt_compatible->type() == coStrings) + static_cast(opt_compatible)->values.clear(); + } collection_dst.load_preset(path, preset_name_dst, std::move(preset_src->config), activate).is_external = true; return preset_name_dst; }; @@ -377,12 +458,17 @@ void PresetBundle::load_config_file_config_bundle(const std::string &path, const this->update_multi_material_filament_presets(); for (size_t i = 1; i < std::min(tmp_bundle.filament_presets.size(), this->filament_presets.size()); ++ i) this->filament_presets[i] = load_one(this->filaments, tmp_bundle.filaments, tmp_bundle.filament_presets[i], false); + + this->update_compatible_with_printer(false); } // Load a config bundle file, into presets and store the loaded presets into separate files // of the local configuration directory. -size_t PresetBundle::load_configbundle(const std::string &path) +size_t PresetBundle::load_configbundle(const std::string &path, unsigned int flags) { + if (flags & LOAD_CFGBNDLE_RESET_USER_PROFILE) + this->reset(flags & LOAD_CFGBNDLE_SAVE); + // 1) Read the complete config file into a boost::property_tree. namespace pt = boost::property_tree; pt::ptree tree; @@ -444,8 +530,20 @@ size_t PresetBundle::load_configbundle(const std::string &path) for (auto &kvp : section.second) config.set_deserialize(kvp.first, kvp.second.data()); Preset::normalize(config); + // Decide a full path to this .ini file. + auto file_name = boost::algorithm::iends_with(preset_name, ".ini") ? preset_name : preset_name + ".ini"; + auto file_path = (boost::filesystem::path(data_dir()) +#ifdef SLIC3R_PROFILE_USE_PRESETS_SUBDIR + // Store the print/filament/printer presets into a "presets" directory. + / "presets" +#else + // Store the print/filament/printer presets at the same location as the upstream Slic3r. +#endif + / presets->name() / file_name).make_preferred(); // Load the preset into the list of presets, save it to disk. - presets->load_preset(Slic3r::config_path(presets->name(), preset_name), preset_name, std::move(config), false).save(); + Preset &loaded = presets->load_preset(file_path.string(), preset_name, std::move(config), false); + if (flags & LOAD_CFGBNDLE_SAVE) + loaded.save(); ++ presets_loaded; } } @@ -462,6 +560,8 @@ size_t PresetBundle::load_configbundle(const std::string &path) this->update_multi_material_filament_presets(); for (size_t i = 0; i < std::min(this->filament_presets.size(), active_filaments.size()); ++ i) this->filament_presets[i] = filaments.find_preset(active_filaments[i], true)->name; + + this->update_compatible_with_printer(false); return presets_loaded; } @@ -480,8 +580,8 @@ void PresetBundle::update_multi_material_filament_presets() void PresetBundle::update_compatible_with_printer(bool select_other_if_incompatible) { - this->prints.update_compatible_with_printer(this->printers.get_selected_preset().name, select_other_if_incompatible); - this->filaments.update_compatible_with_printer(this->printers.get_selected_preset().name, select_other_if_incompatible); + this->prints.update_compatible_with_printer(this->printers.get_edited_preset(), select_other_if_incompatible); + this->filaments.update_compatible_with_printer(this->printers.get_edited_preset(), select_other_if_incompatible); if (select_other_if_incompatible) { // Verify validity of the current filament presets. for (std::string &filament_name : this->filament_presets) { @@ -557,9 +657,9 @@ static inline int hex_digit_to_int(const char c) static inline bool parse_color(const std::string &scolor, unsigned char *rgb_out) { rgb_out[0] = rgb_out[1] = rgb_out[2] = 0; - const char *c = scolor.data() + 1; if (scolor.size() != 7 || scolor.front() != '#') return false; + const char *c = scolor.data() + 1; for (size_t i = 0; i < 3; ++ i) { int digit1 = hex_digit_to_int(*c ++); int digit2 = hex_digit_to_int(*c ++); diff --git a/xs/src/slic3r/GUI/PresetBundle.hpp b/xs/src/slic3r/GUI/PresetBundle.hpp index 571dea0be..df04efd73 100644 --- a/xs/src/slic3r/GUI/PresetBundle.hpp +++ b/xs/src/slic3r/GUI/PresetBundle.hpp @@ -15,10 +15,14 @@ public: PresetBundle(); ~PresetBundle(); + // Remove all the presets but the "-- default --". + // Optionally remove all the files referenced by the presets from the user profile directory. + void reset(bool delete_files); + void setup_directories(); - // Load ini files of all types (print, filament, printer) from the provided directory path. - void load_presets(const std::string &dir_path); + // Load ini files of all types (print, filament, printer) from Slic3r::data_dir() / presets. + void load_presets(); // Load selections (current print, current filaments, current printer) from config.ini // This is done just once on application start up. @@ -40,6 +44,11 @@ public: DynamicPrintConfig full_config() const; + // Load user configuration and store it into the user profiles. + // This method is called by the configuration wizard. + void load_config(const std::string &name, DynamicPrintConfig config) + { this->load_config_file_config(name, false, std::move(config)); } + // Load an external config file containing the print, filament and printer presets. // Instead of a config file, a G-code may be loaded containing the full set of parameters. // In the future the configuration will likely be read from an AMF file as well. @@ -51,7 +60,14 @@ public: // Load settings into the provided settings instance. // Activate the presets stored in the config bundle. // Returns the number of presets loaded successfully. - size_t load_configbundle(const std::string &path); + enum { + // Save the profiles, which have been loaded. + LOAD_CFGBNDLE_SAVE = 1, + // Delete all old config profiles before loading. + LOAD_CFGBNDLE_RESET_USER_PROFILE = 2 + }; + // Load the config bundle, store it to the user profile directory by default. + size_t load_configbundle(const std::string &path, unsigned int flags = LOAD_CFGBNDLE_SAVE); // Export a config bundle file containing all the presets and the names of the active presets. void export_configbundle(const std::string &path); // , const DynamicPrintConfig &settings); @@ -78,7 +94,10 @@ public: void update_compatible_with_printer(bool select_other_if_incompatible); private: - void load_config_file_config(const std::string &path, const DynamicPrintConfig &config); + // Load print, filament & printer presets from a config. If it is an external config, then the name is extracted from the external path. + // and the external config is just referenced, not stored into user profile directory. + // If it is not an external config, then the config will be stored into the user profile directory. + void load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config); void load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree); bool load_compatible_bitmaps(); diff --git a/xs/src/slic3r/GUI/PresetHints.cpp b/xs/src/slic3r/GUI/PresetHints.cpp index 13478f980..8e23a5c49 100644 --- a/xs/src/slic3r/GUI/PresetHints.cpp +++ b/xs/src/slic3r/GUI/PresetHints.cpp @@ -55,11 +55,6 @@ static const ConfigOptionFloatOrPercent& first_positive(const ConfigOptionFloatO return (v1 != nullptr && v1->value > 0) ? *v1 : ((v2.value > 0) ? v2 : v3); } -static double first_positive(double v1, double v2) -{ - return (v1 > 0.) ? v1 : v2; -} - std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle &preset_bundle) { // Find out, to which nozzle index is the current filament profile assigned. @@ -106,6 +101,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle const auto &solid_infill_extrusion_width = *print_config.option("solid_infill_extrusion_width"); const auto &support_material_extrusion_width = *print_config.option("support_material_extrusion_width"); const auto &top_infill_extrusion_width = *print_config.option("top_infill_extrusion_width"); + const auto &first_layer_speed = *print_config.option("first_layer_speed"); // Index of an extruder assigned to a feature. If set to 0, an active extruder will be used for a multi-material print. // If different from idx_extruder, it will not be taken into account for this hint. @@ -136,12 +132,18 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle const float bfr = bridging ? bridge_flow_ratio : 0.f; double max_flow = 0.; std::string max_flow_extrusion_type; + auto limit_by_first_layer_speed = [&first_layer_speed, first_layer](double speed_normal, double speed_max) { + if (first_layer && first_layer_speed.value > 0) + // Apply the first layer limit. + speed_normal = first_layer_speed.get_abs_value(speed_normal); + return (speed_normal > 0.) ? speed_normal : speed_max; + }; if (perimeter_extruder_active) { double external_perimeter_rate = Flow::new_from_config_width(frExternalPerimeter, first_positive(first_layer_extrusion_width_ptr, external_perimeter_extrusion_width, extrusion_width), nozzle_diameter, lh, bfr).mm3_per_mm() * (bridging ? bridge_speed : - first_positive(std::max(external_perimeter_speed, small_perimeter_speed), max_print_speed)); + limit_by_first_layer_speed(std::max(external_perimeter_speed, small_perimeter_speed), max_print_speed)); if (max_flow < external_perimeter_rate) { max_flow = external_perimeter_rate; max_flow_extrusion_type = "external perimeters"; @@ -150,7 +152,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle first_positive(first_layer_extrusion_width_ptr, perimeter_extrusion_width, extrusion_width), nozzle_diameter, lh, bfr).mm3_per_mm() * (bridging ? bridge_speed : - first_positive(std::max(perimeter_speed, small_perimeter_speed), max_print_speed)); + limit_by_first_layer_speed(std::max(perimeter_speed, small_perimeter_speed), max_print_speed)); if (max_flow < perimeter_rate) { max_flow = perimeter_rate; max_flow_extrusion_type = "perimeters"; @@ -159,7 +161,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle if (! bridging && infill_extruder_active) { double infill_rate = Flow::new_from_config_width(frInfill, first_positive(first_layer_extrusion_width_ptr, infill_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * first_positive(infill_speed, max_print_speed); + nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(infill_speed, max_print_speed); if (max_flow < infill_rate) { max_flow = infill_rate; max_flow_extrusion_type = "infill"; @@ -169,7 +171,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle double solid_infill_rate = Flow::new_from_config_width(frInfill, first_positive(first_layer_extrusion_width_ptr, solid_infill_extrusion_width, extrusion_width), nozzle_diameter, lh, 0).mm3_per_mm() * - (bridging ? bridge_speed : first_positive(solid_infill_speed, max_print_speed)); + (bridging ? bridge_speed : limit_by_first_layer_speed(solid_infill_speed, max_print_speed)); if (max_flow < solid_infill_rate) { max_flow = solid_infill_rate; max_flow_extrusion_type = "solid infill"; @@ -177,7 +179,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle if (! bridging) { double top_solid_infill_rate = Flow::new_from_config_width(frInfill, first_positive(first_layer_extrusion_width_ptr, top_infill_extrusion_width, extrusion_width), - nozzle_diameter, lh, bfr).mm3_per_mm() * first_positive(top_solid_infill_speed, max_print_speed); + nozzle_diameter, lh, bfr).mm3_per_mm() * limit_by_first_layer_speed(top_solid_infill_speed, max_print_speed); if (max_flow < top_solid_infill_rate) { max_flow = top_solid_infill_rate; max_flow_extrusion_type = "top solid infill"; @@ -188,7 +190,7 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle double support_material_rate = Flow::new_from_config_width(frSupportMaterial, first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width), nozzle_diameter, lh, bfr).mm3_per_mm() * - (bridging ? bridge_speed : first_positive(support_material_speed, max_print_speed)); + (bridging ? bridge_speed : limit_by_first_layer_speed(support_material_speed, max_print_speed)); if (max_flow < support_material_rate) { max_flow = support_material_rate; max_flow_extrusion_type = "support"; @@ -198,23 +200,23 @@ std::string PresetHints::maximum_volumetric_flow_description(const PresetBundle double support_material_interface_rate = Flow::new_from_config_width(frSupportMaterialInterface, first_positive(first_layer_extrusion_width_ptr, support_material_extrusion_width, extrusion_width), nozzle_diameter, lh, bfr).mm3_per_mm() * - (bridging ? bridge_speed : first_positive(support_material_interface_speed, max_print_speed)); + (bridging ? bridge_speed : limit_by_first_layer_speed(support_material_interface_speed, max_print_speed)); if (max_flow < support_material_interface_rate) { max_flow = support_material_interface_rate; max_flow_extrusion_type = "support interface"; } } - //FIXME handle gap_fill_speed if (! out.empty()) out += "\n"; out += (first_layer ? "First layer volumetric" : (bridging ? "Bridging volumetric" : "Volumetric")); out += " flow rate is maximized "; - out += ((max_volumetric_speed > 0 && max_volumetric_speed < max_flow) ? + bool limited_by_max_volumetric_speed = max_volumetric_speed > 0 && max_volumetric_speed < max_flow; + out += (limited_by_max_volumetric_speed ? "by the print profile maximum" : - ("when printing " + max_flow_extrusion_type)) + ("when printing " + max_flow_extrusion_type)) + " with a volumetric rate "; - if (max_volumetric_speed > 0 && max_volumetric_speed < max_flow) + if (limited_by_max_volumetric_speed) max_flow = max_volumetric_speed; char buf[2048]; sprintf(buf, "%3.2f mm³/s", max_flow); diff --git a/xs/xsp/GCode.xsp b/xs/xsp/GCode.xsp index 92341394f..9e6df85dc 100644 --- a/xs/xsp/GCode.xsp +++ b/xs/xsp/GCode.xsp @@ -17,7 +17,14 @@ %name{Slic3r::GCode} class GCode { GCode(); ~GCode(); - std::string do_export(Print *print, const char *path); + void do_export(Print *print, const char *path) + %code%{ + try { + THIS->do_export(print, path); + } catch (std::exception& e) { + croak(e.what()); + } + %}; Ref origin() %code{% RETVAL = &(THIS->origin()); %}; diff --git a/xs/xsp/GUI.xsp b/xs/xsp/GUI.xsp index ce3c178a1..d6b55dbf1 100644 --- a/xs/xsp/GUI.xsp +++ b/xs/xsp/GUI.xsp @@ -22,3 +22,18 @@ bool debugged() void break_to_debugger() %code{% Slic3r::GUI::break_to_debugger(); %}; + +void set_wxapp(SV *ui) + %code%{ Slic3r::GUI::set_wxapp((wxApp*)wxPli_sv_2_object(aTHX_ ui, "Wx::App")); %}; + +void set_main_frame(SV *ui) + %code%{ Slic3r::GUI::set_main_frame((wxFrame*)wxPli_sv_2_object(aTHX_ ui, "Wx::Frame")); %}; + +void set_tab_panel(SV *ui) + %code%{ Slic3r::GUI::set_tab_panel((wxNotebook*)wxPli_sv_2_object(aTHX_ ui, "Wx::Notebook")); %}; + +void add_debug_menu(SV *ui) + %code%{ Slic3r::GUI::add_debug_menu((wxMenuBar*)wxPli_sv_2_object(aTHX_ ui, "Wx::MenuBar")); %}; + +void create_preset_tab(const char *name) + %code%{ Slic3r::GUI::create_preset_tab(name); %}; diff --git a/xs/xsp/GUI_Preset.xsp b/xs/xsp/GUI_Preset.xsp index a7fbdd07f..0e6b1504b 100644 --- a/xs/xsp/GUI_Preset.xsp +++ b/xs/xsp/GUI_Preset.xsp @@ -14,7 +14,9 @@ bool external() %code%{ RETVAL = THIS->is_external; %}; bool visible() %code%{ RETVAL = THIS->is_visible; %}; bool dirty() %code%{ RETVAL = THIS->is_dirty; %}; - bool is_compatible_with_printer(char *active_printer) const; + bool compatible() %code%{ RETVAL = THIS->is_compatible; %}; + bool is_compatible_with_printer(Preset *active_printer) + %code%{ RETVAL = THIS->is_compatible_with_printer(*active_printer); %}; const char* name() %code%{ RETVAL = THIS->name.c_str(); %}; const char* file() %code%{ RETVAL = THIS->file.c_str(); %}; @@ -98,6 +100,8 @@ PresetCollection::arrayref() PresetBundle(); ~PresetBundle(); + void reset(bool delete_files); + void setup_directories() %code%{ try { @@ -106,12 +110,21 @@ PresetCollection::arrayref() croak("Cannot create configuration directories:\n%s\n", e.what()); } %}; - void load_presets(const char *dir_path) + void load_presets() %code%{ try { - THIS->load_presets(dir_path); + THIS->load_presets(); } catch (std::exception& e) { - croak("Loading of Slic3r presets from %s failed.\n\n%s\n", dir_path, e.what()); + croak("Loading of Slic3r presets from %s failed.\n\n%s\n", + Slic3r::data_dir().c_str(), e.what()); + } + %}; + void load_config(const char *name, DynamicPrintConfig *config) + %code%{ + try { + THIS->load_config(name, *config); + } catch (std::exception& e) { + croak("Loading a configuration %s failed:\n%s\n", name, e.what()); } %}; void load_config_file(const char *path) @@ -125,7 +138,7 @@ PresetCollection::arrayref() size_t load_configbundle(const char *path) %code%{ try { - RETVAL = THIS->load_configbundle(path); + RETVAL = THIS->load_configbundle(path, PresetBundle::LOAD_CFGBNDLE_SAVE); } catch (std::exception& e) { croak("Loading of a config bundle %s failed:\n%s\n", path, e.what()); } diff --git a/xs/xsp/Layer.xsp b/xs/xsp/Layer.xsp index 71fc540dc..4f09fb521 100644 --- a/xs/xsp/Layer.xsp +++ b/xs/xsp/Layer.xsp @@ -50,10 +50,6 @@ int id(); void set_id(int id); Ref object(); - Ref upper_layer() - %code%{ RETVAL = THIS->upper_layer; %}; - Ref lower_layer() - %code%{ RETVAL = THIS->lower_layer; %}; bool slicing_errors() %code%{ RETVAL = THIS->slicing_errors; %}; coordf_t slice_z() @@ -63,15 +59,6 @@ coordf_t height() %code%{ RETVAL = THIS->height; %}; - void set_upper_layer(Layer *layer) - %code%{ THIS->upper_layer = layer; %}; - void set_lower_layer(Layer *layer) - %code%{ THIS->lower_layer = layer; %}; - bool has_upper_layer() - %code%{ RETVAL = (THIS->upper_layer != NULL); %}; - bool has_lower_layer() - %code%{ RETVAL = (THIS->lower_layer != NULL); %}; - size_t region_count(); Ref get_region(int idx); Ref add_region(PrintRegion* print_region); @@ -112,10 +99,6 @@ int id(); void set_id(int id); Ref object(); - Ref upper_layer() - %code%{ RETVAL = (SupportLayer*)THIS->upper_layer; %}; - Ref lower_layer() - %code%{ RETVAL = (SupportLayer*)THIS->lower_layer; %}; bool slicing_errors() %code%{ RETVAL = THIS->slicing_errors; %}; coordf_t slice_z() @@ -125,15 +108,6 @@ coordf_t height() %code%{ RETVAL = THIS->height; %}; - void set_upper_layer(SupportLayer *layer) - %code%{ THIS->upper_layer = layer; %}; - void set_lower_layer(SupportLayer *layer) - %code%{ THIS->lower_layer = layer; %}; - bool has_upper_layer() - %code%{ RETVAL = (THIS->upper_layer != NULL); %}; - bool has_lower_layer() - %code%{ RETVAL = (THIS->lower_layer != NULL); %}; - size_t region_count(); Ref get_region(int idx); Ref add_region(PrintRegion* print_region); diff --git a/xs/xsp/PlaceholderParser.xsp b/xs/xsp/PlaceholderParser.xsp index 08630f9d5..244f89cf8 100644 --- a/xs/xsp/PlaceholderParser.xsp +++ b/xs/xsp/PlaceholderParser.xsp @@ -14,5 +14,20 @@ %code%{ THIS->apply_config(*config); %}; void set(std::string key, int value); std::string process(std::string str) const - %code%{ RETVAL = THIS->process(str, 0); %}; + %code%{ + try { + RETVAL = THIS->process(str, 0); + } catch (std::exception& e) { + croak(e.what()); + } + %}; + + bool evaluate_boolean_expression(const char *str) const + %code%{ + try { + RETVAL = THIS->evaluate_boolean_expression(str, THIS->config()); + } catch (std::exception& e) { + croak(e.what()); + } + %}; }; diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index 852f0dde0..2e418253b 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -91,7 +91,6 @@ _constant() size_t support_layer_count(); void clear_support_layers(); Ref get_support_layer(int idx); - Ref add_support_layer(int id, coordf_t height, coordf_t print_z); bool step_done(PrintObjectStep step) %code%{ RETVAL = THIS->state.is_done(step); %}; @@ -206,8 +205,14 @@ _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 = ""); + std::string output_filepath(std::string path = "") + %code%{ + try { + RETVAL = THIS->output_filepath(path); + } catch (std::exception& e) { + croak(e.what()); + } + %}; void add_model_object(ModelObject* model_object, int idx = -1); bool apply_config(DynamicPrintConfig* config) @@ -215,10 +220,11 @@ _constant() bool has_infinite_skirt(); bool has_skirt(); std::vector extruders() const; - void validate() %code%{ + int validate() %code%{ std::string err = THIS->validate(); - if (! err.empty()) - throw std::invalid_argument(err.c_str()); + if (! err.empty()) + croak("Configuration is not valid: %s\n", err.c_str()); + RETVAL = 1; %}; Clone bounding_box(); Clone total_bounding_box(); diff --git a/xs/xsp/XS.xsp b/xs/xsp/XS.xsp index 2be42d383..b2f772834 100644 --- a/xs/xsp/XS.xsp +++ b/xs/xsp/XS.xsp @@ -60,6 +60,18 @@ var_dir() RETVAL = const_cast(Slic3r::var_dir().c_str()); OUTPUT: RETVAL +void +set_resources_dir(dir) + char *dir; + CODE: + Slic3r::set_resources_dir(dir); + +char* +resources_dir() + CODE: + RETVAL = const_cast(Slic3r::resources_dir().c_str()); + OUTPUT: RETVAL + std::string var(file_name) const char *file_name; @@ -79,14 +91,6 @@ data_dir() RETVAL = const_cast(Slic3r::data_dir().c_str()); OUTPUT: RETVAL -std::string -config_path(section, name) - const char *section; - const char *name; - CODE: - RETVAL = Slic3r::config_path(section, name); - OUTPUT: RETVAL - std::string encode_path(src) const char *src;