diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm
deleted file mode 100644
index 31f614ba92..0000000000
--- a/lib/Slic3r/GUI.pm
+++ /dev/null
@@ -1,337 +0,0 @@
-package Slic3r::GUI;
-use strict;
-use warnings;
-use utf8;
-
-use File::Basename qw(basename);
-use FindBin;
-use List::Util qw(first);
-use Slic3r::GUI::MainFrame;
-use Slic3r::GUI::Plater;
-use Slic3r::GUI::Plater::3D;
-use Slic3r::GUI::Plater::3DPreview;
-
-use Wx::Locale gettext => 'L';
-
-our $have_OpenGL = eval "use Slic3r::GUI::3DScene; 1";
-
-use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow :filedialog :font);
-use Wx::Event qw(EVT_IDLE EVT_COMMAND EVT_MENU);
-use base 'Wx::App';
-
-use constant FILE_WILDCARDS => {
- known => 'Known files (*.stl, *.obj, *.amf, *.xml, *.3mf, *.prusa)|*.stl;*.STL;*.obj;*.OBJ;*.zip.amf;*.amf;*.AMF;*.xml;*.XML;*.3mf;*.3MF;*.prusa;*.PRUSA',
- stl => 'STL files (*.stl)|*.stl;*.STL',
- obj => 'OBJ files (*.obj)|*.obj;*.OBJ',
- amf => 'AMF files (*.amf)|*.zip.amf;*.amf;*.AMF;*.xml;*.XML',
- threemf => '3MF files (*.3mf)|*.3mf;*.3MF',
- prusa => 'Prusa Control files (*.prusa)|*.prusa;*.PRUSA',
- ini => 'INI files *.ini|*.ini;*.INI',
- gcode => 'G-code files (*.gcode, *.gco, *.g, *.ngc)|*.gcode;*.GCODE;*.gco;*.GCO;*.g;*.G;*.ngc;*.NGC',
-};
-use constant MODEL_WILDCARD => join '|', @{&FILE_WILDCARDS}{qw(known stl obj amf threemf prusa)};
-
-# Datadir provided on the command line.
-our $datadir;
-our $no_plater;
-our @cb;
-
-our $small_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
-$small_font->SetPointSize(11) if &Wx::wxMAC;
-our $small_bold_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
-$small_bold_font->SetPointSize(11) if &Wx::wxMAC;
-$small_bold_font->SetWeight(wxFONTWEIGHT_BOLD);
-our $medium_font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
-$medium_font->SetPointSize(12);
-our $grey = Wx::Colour->new(200,200,200);
-
-# Events to be sent from a C++ menu implementation:
-# 1) To inform about a change of the application language.
-our $LANGUAGE_CHANGE_EVENT = Wx::NewEventType;
-# 2) To inform about a change of Preferences.
-our $PREFERENCES_EVENT = Wx::NewEventType;
-# To inform AppConfig about Slic3r version available online
-our $VERSION_ONLINE_EVENT = Wx::NewEventType;
-
-sub OnInit {
- my ($self) = @_;
-
- $self->SetAppName('Slic3rPE');
- $self->SetAppDisplayName('Slic3r Prusa Edition');
- Slic3r::debugf "wxWidgets version %s, Wx version %s\n", &Wx::wxVERSION_STRING, $Wx::VERSION;
-
- # Set the Slic3r data directory at the Slic3r XS module.
- # Unix: ~/.Slic3r
- # 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->{app_config} = Slic3r::GUI::AppConfig->new;
- Slic3r::GUI::set_app_config($self->{app_config});
- $self->{preset_bundle} = Slic3r::GUI::PresetBundle->new;
- Slic3r::GUI::set_preset_bundle($self->{preset_bundle});
-
- # just checking for existence of Slic3r::data_dir is not enough: it may be an empty directory
- # supplied as argument to --datadir; in that case we should still run the wizard
- eval { $self->{preset_bundle}->setup_directories() };
- if ($@) {
- warn $@ . "\n";
- fatal_error(undef, $@);
- }
- my $app_conf_exists = $self->{app_config}->exists;
- # load settings
- $self->{app_config}->load if $app_conf_exists;
- $self->{app_config}->set('version', $Slic3r::VERSION);
- $self->{app_config}->save;
-
- $self->{preset_updater} = Slic3r::PresetUpdater->new($VERSION_ONLINE_EVENT);
- Slic3r::GUI::set_preset_updater($self->{preset_updater});
-
- Slic3r::GUI::load_language();
-
- # Suppress the '- default -' presets.
- $self->{preset_bundle}->set_default_suppressed($self->{app_config}->get('no_defaults') ? 1 : 0);
- eval { $self->{preset_bundle}->load_presets($self->{app_config}); };
- if ($@) {
- warn $@ . "\n";
- show_error(undef, $@);
- }
-
- # application frame
- print STDERR "Creating main frame...\n";
- Wx::Image::FindHandlerType(wxBITMAP_TYPE_PNG) || Wx::Image::AddHandler(Wx::PNGHandler->new);
- $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
- no_plater => $no_plater,
- lang_ch_event => $LANGUAGE_CHANGE_EVENT,
- preferences_event => $PREFERENCES_EVENT,
- );
- $self->SetTopWindow($frame);
-
- # This makes CallAfter() work
- EVT_IDLE($self->{mainframe}, sub {
- while (my $cb = shift @cb) {
- $cb->();
- }
- $self->{app_config}->save if $self->{app_config}->dirty;
- });
-
- # On OS X the UI tends to freeze in weird ways if modal dialogs (config wizard, update notifications, ...)
- # are shown before or in the same event callback with the main frame creation.
- # Therefore we schedule them for later using CallAfter.
- $self->CallAfter(sub {
- eval {
- if (! $self->{preset_updater}->config_update()) {
- $self->{mainframe}->Close;
- }
- };
- if ($@) {
- show_error(undef, $@);
- $self->{mainframe}->Close;
- }
- });
-
- $self->CallAfter(sub {
- if (! Slic3r::GUI::config_wizard_startup($app_conf_exists)) {
- # Only notify if there was not wizard so as not to bother too much ...
- $self->{preset_updater}->slic3r_update_notify();
- }
- $self->{preset_updater}->sync($self->{preset_bundle});
- });
-
- # The following event is emited by the C++ menu implementation of application language change.
- EVT_COMMAND($self, -1, $LANGUAGE_CHANGE_EVENT, sub{
- print STDERR "LANGUAGE_CHANGE_EVENT\n";
- $self->recreate_GUI;
- });
-
- # The following event is emited by the C++ menu implementation of preferences change.
- EVT_COMMAND($self, -1, $PREFERENCES_EVENT, sub{
- $self->update_ui_from_settings;
- });
-
- # The following event is emited by PresetUpdater (C++) to inform about
- # the newer Slic3r application version avaiable online.
- EVT_COMMAND($self, -1, $VERSION_ONLINE_EVENT, sub {
- my ($self, $event) = @_;
- my $version = $event->GetString;
- $self->{app_config}->set('version_online', $version);
- $self->{app_config}->save;
- });
-
- return 1;
-}
-
-sub recreate_GUI{
- print STDERR "recreate_GUI\n";
- my ($self) = @_;
- my $topwindow = $self->GetTopWindow();
- $self->{mainframe} = my $frame = Slic3r::GUI::MainFrame->new(
- no_plater => $no_plater,
- lang_ch_event => $LANGUAGE_CHANGE_EVENT,
- preferences_event => $PREFERENCES_EVENT,
- );
-
- if($topwindow)
- {
- $self->SetTopWindow($frame);
- $topwindow->Destroy;
- }
-
- EVT_IDLE($self->{mainframe}, sub {
- while (my $cb = shift @cb) {
- $cb->();
- }
- $self->{app_config}->save if $self->{app_config}->dirty;
- });
-
- # 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.
- Slic3r::GUI::config_wizard_startup(1);
- });
-}
-
-sub system_info {
- my ($self) = @_;
- my $slic3r_info = Slic3r::slic3r_info(format => 'html');
- my $copyright_info = Slic3r::copyright_info(format => 'html');
- my $system_info = Slic3r::system_info(format => 'html');
- my $opengl_info;
- my $opengl_info_txt = '';
- if (defined($self->{mainframe}) && defined($self->{mainframe}->{plater}) &&
- defined($self->{mainframe}->{plater}->{canvas3D})) {
- $opengl_info = Slic3r::GUI::_3DScene::get_gl_info(1, 1);
- $opengl_info_txt = Slic3r::GUI::_3DScene::get_gl_info(0, 1);
- }
-# my $about = Slic3r::GUI::SystemInfo->new(
-# parent => undef,
-# slic3r_info => $slic3r_info,
-# system_info => $system_info,
-# opengl_info => $opengl_info,
-# text_info => Slic3r::slic3r_info . Slic3r::system_info . $opengl_info_txt,
-# );
-# $about->ShowModal;
-# $about->Destroy;
-}
-
-# static method accepting a wxWindow object as first parameter
-sub catch_error {
- my ($self, $cb, $message_dialog) = @_;
- if (my $err = $@) {
- $cb->() if $cb;
- $message_dialog
- ? $message_dialog->($err, 'Error', wxOK | wxICON_ERROR)
- : Slic3r::GUI::show_error($self, $err);
- return 1;
- }
- return 0;
-}
-
-# static method accepting a wxWindow object as first parameter
-sub show_error {
- my ($parent, $message) = @_;
- Slic3r::GUI::show_error_id($parent ? $parent->GetId() : 0, $message);
-}
-
-# static method accepting a wxWindow object as first parameter
-sub show_info {
- my ($parent, $message, $title) = @_;
- Wx::MessageDialog->new($parent, $message, $title || 'Notice', wxOK | wxICON_INFORMATION)->ShowModal;
-}
-
-# static method accepting a wxWindow object as first parameter
-sub fatal_error {
- show_error(@_);
- exit 1;
-}
-
-# static method accepting a wxWindow object as first parameter
-sub warning_catcher {
- my ($self, $message_dialog) = @_;
- return sub {
- my $message = shift;
- return if $message =~ /GLUquadricObjPtr|Attempt to free unreferenced scalar/;
- my @params = ($message, 'Warning', wxOK | wxICON_WARNING);
- $message_dialog
- ? $message_dialog->(@params)
- : Wx::MessageDialog->new($self, @params)->ShowModal;
- };
-}
-
-sub notify {
- my ($self, $message) = @_;
-
- my $frame = $self->GetTopWindow;
- # try harder to attract user attention on OS X
- $frame->RequestUserAttention(&Wx::wxMAC ? wxUSER_ATTENTION_ERROR : wxUSER_ATTENTION_INFO)
- unless ($frame->IsActive);
-
- # There used to be notifier using a Growl application for OSX, but Growl is dead.
- # The notifier also supported the Linux X D-bus notifications, but that support was broken.
- #TODO use wxNotificationMessage?
-}
-
-# Called after the Preferences dialog is closed and the program settings are saved.
-# Update the UI based on the current preferences.
-sub update_ui_from_settings {
- my ($self) = @_;
- $self->{mainframe}->update_ui_from_settings;
-}
-
-sub open_model {
- my ($self, $window) = @_;
-
- my $dlg_title = L('Choose one or more files (STL/OBJ/AMF/3MF/PRUSA):');
- my $dialog = Wx::FileDialog->new($window // $self->GetTopWindow, $dlg_title,
- $self->{app_config}->get_last_dir, "",
- MODEL_WILDCARD, wxFD_OPEN | wxFD_MULTIPLE | wxFD_FILE_MUST_EXIST);
- if ($dialog->ShowModal != wxID_OK) {
- $dialog->Destroy;
- return;
- }
- my @input_files = $dialog->GetPaths;
- $dialog->Destroy;
- return @input_files;
-}
-
-sub CallAfter {
- my ($self, $cb) = @_;
- push @cb, $cb;
-}
-
-sub append_menu_item {
- my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_;
-
- $id //= &Wx::NewId();
- my $item = Wx::MenuItem->new($menu, $id, $string, $description // '', $kind // 0);
- $self->set_menu_item_icon($item, $icon);
- $menu->Append($item);
-
- EVT_MENU($self, $id, $cb);
- return $item;
-}
-
-sub append_submenu {
- my ($self, $menu, $string, $description, $submenu, $id, $icon) = @_;
-
- $id //= &Wx::NewId();
- my $item = Wx::MenuItem->new($menu, $id, $string, $description // '');
- $self->set_menu_item_icon($item, $icon);
- $item->SetSubMenu($submenu);
- $menu->Append($item);
-
- return $item;
-}
-
-sub set_menu_item_icon {
- my ($self, $menuItem, $icon) = @_;
-
- # SetBitmap was not available on OS X before Wx 0.9927
- if ($icon && $menuItem->can('SetBitmap')) {
- $menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG));
- }
-}
-
-1;
diff --git a/lib/Slic3r/GUI/3DScene.pm b/lib/Slic3r/GUI/3DScene.pm
deleted file mode 100644
index 23decaa371..0000000000
--- a/lib/Slic3r/GUI/3DScene.pm
+++ /dev/null
@@ -1,70 +0,0 @@
-# Implements pure perl packages
-#
-# Slic3r::GUI::3DScene::Base;
-# Slic3r::GUI::3DScene;
-#
-# Slic3r::GUI::Plater::3D derives from Slic3r::GUI::3DScene,
-# Slic3r::GUI::Plater::3DPreview,
-# Slic3r::GUI::Plater::ObjectCutDialog and Slic3r::GUI::Plater::ObjectPartsPanel
-# own $self->{canvas} of the Slic3r::GUI::3DScene type.
-#
-# Therefore the 3DScene supports renderng of STLs, extrusions and cutting planes,
-# and camera manipulation.
-
-package Slic3r::GUI::3DScene::Base;
-use strict;
-use warnings;
-
-use Wx qw(wxTheApp :timer :bitmap :icon :dialog);
-# must load OpenGL *before* Wx::GLCanvas
-use OpenGL qw(:glconstants :glfunctions :glufunctions :gluconstants);
-use base qw(Wx::GLCanvas Class::Accessor);
-use Wx::GLCanvas qw(:all);
-
-sub new {
- my ($class, $parent) = @_;
-
- # 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');
- my $attrib = [WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 24];
- if ($can_multisample) {
- # Request a window with multi sampled anti aliasing. This is a new feature in Wx 3.0.3 (backported from 3.1.0).
- # Use eval to avoid compilation, if the subs WX_GL_SAMPLE_BUFFERS and WX_GL_SAMPLES are missing.
- eval 'push(@$attrib, (WX_GL_SAMPLE_BUFFERS, 1, WX_GL_SAMPLES, 4));';
- }
- # wxWidgets expect the attrib list to be ended by zero.
- push(@$attrib, 0);
-
- # we request a depth buffer explicitely because it looks like it's not created by
- # default on Linux, causing transparency issues
- my $self = $class->SUPER::new($parent, -1, Wx::wxDefaultPosition, Wx::wxDefaultSize, 0, "", $attrib);
-
- Slic3r::GUI::_3DScene::add_canvas($self);
- Slic3r::GUI::_3DScene::allow_multisample($self, $can_multisample);
-
- return $self;
-}
-
-sub Destroy {
- my ($self) = @_;
- Slic3r::GUI::_3DScene::remove_canvas($self);
- return $self->SUPER::Destroy;
-}
-
-# The 3D canvas to display objects and tool paths.
-package Slic3r::GUI::3DScene;
-use base qw(Slic3r::GUI::3DScene::Base);
-
-sub new {
- my $class = shift;
-
- my $self = $class->SUPER::new(@_);
- return $self;
-}
-
-1;
diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm
deleted file mode 100644
index c1975cd5d3..0000000000
--- a/lib/Slic3r/GUI/MainFrame.pm
+++ /dev/null
@@ -1,644 +0,0 @@
-# The main frame, the parent of all.
-
-package Slic3r::GUI::MainFrame;
-use strict;
-use warnings;
-use utf8;
-
-use File::Basename qw(basename dirname);
-use FindBin;
-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 :dirdialog
- :font :icon wxTheApp);
-use Wx::Event qw(EVT_CLOSE EVT_COMMAND EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED);
-use base 'Wx::Frame';
-
-use Wx::Locale gettext => 'L';
-
-our $qs_last_input_file;
-our $qs_last_output_file;
-our $last_config;
-our $appController;
-
-# Events to be sent from a C++ Tab implementation:
-# 1) To inform about a change of a configuration value.
-our $VALUE_CHANGE_EVENT = Wx::NewEventType;
-# 2) To inform about a preset selection change or a "modified" status change.
-our $PRESETS_CHANGED_EVENT = Wx::NewEventType;
-# 3) To update the status bar with the progress information.
-our $PROGRESS_BAR_EVENT = Wx::NewEventType;
-# 4) To display an error dialog box from a thread on the UI thread.
-our $ERROR_EVENT = Wx::NewEventType;
-# 5) To inform about a change of object selection
-our $OBJECT_SELECTION_CHANGED_EVENT = Wx::NewEventType;
-# 6) To inform about a change of object settings
-our $OBJECT_SETTINGS_CHANGED_EVENT = Wx::NewEventType;
-# 7) To inform about a remove of object
-our $OBJECT_REMOVE_EVENT = Wx::NewEventType;
-# 8) To inform about a update of the scene
-our $UPDATE_SCENE_EVENT = Wx::NewEventType;
-
-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);
-
- $appController = Slic3r::AppController->new();
-
- 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';
- $iconfile = Slic3r::var("Slic3r.ico") unless -f $iconfile;
- $self->SetIcon(Wx::Icon->new($iconfile, wxBITMAP_TYPE_ICO));
- } else {
- $self->SetIcon(Wx::Icon->new(Slic3r::var("Slic3r_128px.png"), wxBITMAP_TYPE_PNG));
- }
-
- # store input params
- $self->{no_plater} = $params{no_plater};
- $self->{loaded} = 0;
- $self->{lang_ch_event} = $params{lang_ch_event};
- $self->{preferences_event} = $params{preferences_event};
-
- # initialize tabpanel and menubar
- $self->_init_tabpanel;
- $self->_init_menubar;
-
- # set default tooltip timer in msec
- # SetAutoPop supposedly accepts long integers but some bug doesn't allow for larger values
- # (SetAutoPop is not available on GTK.)
- eval { Wx::ToolTip::SetAutoPop(32767) };
-
- # initialize status bar
- $self->{statusbar} = Slic3r::GUI::ProgressStatusBar->new();
- $self->{statusbar}->Embed;
- $self->{statusbar}->SetStatusText(L("Version ").$Slic3r::VERSION.L(" - Remember to check for updates at http://github.com/prusa3d/slic3r/releases"));
- # Make the global status bar and its progress indicator available in C++
- Slic3r::GUI::set_progress_status_bar($self->{statusbar});
- $appController->set_global_progress_indicator($self->{statusbar});
-
- $appController->set_model($self->{plater}->{model});
- $appController->set_print($self->{plater}->{print});
-
- $self->{plater}->{appController} = $appController;
-
- $self->{loaded} = 1;
-
- # initialize layout
- {
- my $sizer = Wx::BoxSizer->new(wxVERTICAL);
- $sizer->Add($self->{tabpanel}, 1, wxEXPAND);
- $sizer->SetSizeHints($self);
- $self->SetSizer($sizer);
- $self->Fit;
- $self->SetMinSize([760, 490]);
- $self->SetSize($self->GetMinSize);
- Slic3r::GUI::restore_window_size($self, "main_frame");
- $self->Show;
- $self->Layout;
- }
-
- # declare events
- EVT_CLOSE($self, sub {
- my (undef, $event) = @_;
- if ($event->CanVeto && !Slic3r::GUI::check_unsaved_changes) {
- $event->Veto;
- return;
- }
- # save window size
- Slic3r::GUI::save_window_size($self, "main_frame");
- # Save the slic3r.ini. Usually the ini file is saved from "on idle" callback,
- # but in rare cases it may not have been called yet.
- wxTheApp->{app_config}->save;
- $self->{statusbar}->ResetCancelCallback();
- $self->{plater}->{print} = undef if($self->{plater});
- Slic3r::GUI::_3DScene::remove_all_canvases();
- Slic3r::GUI::deregister_on_request_update_callback();
- # propagate event
- $event->Skip;
- });
-
- $self->update_ui_from_settings;
-
- Slic3r::GUI::update_mode();
-
- return $self;
-}
-
-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');
-
- for my $tab_name (qw(print filament printer)) {
- Slic3r::GUI::get_preset_tab("$tab_name")->OnActivate if ("$tab_name" eq $panel->GetName);
- }
- });
-
- if (!$self->{no_plater}) {
- $panel->AddPage($self->{plater} = Slic3r::GUI::Plater->new($panel,
- event_object_selection_changed => $OBJECT_SELECTION_CHANGED_EVENT,
- event_object_settings_changed => $OBJECT_SETTINGS_CHANGED_EVENT,
- event_remove_object => $OBJECT_REMOVE_EVENT,
- event_update_scene => $UPDATE_SCENE_EVENT,
- ), L("Plater"));
- }
-
- #TODO this is an example of a Slic3r XS interface call to add a new preset editor page to the main view.
- # The following event is emited by the C++ Tab implementation on config value change.
- EVT_COMMAND($self, -1, $VALUE_CHANGE_EVENT, sub {
- my ($self, $event) = @_;
- my $str = $event->GetString;
- my ($opt_key, $name) = ($str =~ /(.*) (.*)/);
- #print "VALUE_CHANGE_EVENT: ", $opt_key, "\n";
- my $tab = Slic3r::GUI::get_preset_tab($name);
- my $config = $tab->get_config;
- if ($self->{plater}) {
- $self->{plater}->on_config_change($config); # propagate config change events to the plater
- if ($opt_key eq 'extruders_count'){
- my $value = $event->GetInt();
- $self->{plater}->on_extruders_change($value);
- }
- if ($opt_key eq 'printer_technology'){
- my $value = $event->GetInt();# 0 ~ "ptFFF"; 1 ~ "ptSLA"
- $self->{plater}->show_preset_comboboxes($value);
- }
- }
- # don't save while loading for the first time
- $self->config->save($Slic3r::GUI::autosave) if $Slic3r::GUI::autosave && $self->{loaded};
- });
- # The following event is emited by the C++ Tab implementation on preset selection,
- # or when the preset's "modified" status changes.
- EVT_COMMAND($self, -1, $PRESETS_CHANGED_EVENT, sub {
- my ($self, $event) = @_;
- my $tab_name = $event->GetString;
-
- my $tab = Slic3r::GUI::get_preset_tab($tab_name);
- if ($self->{plater}) {
- # Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs.
- my $presets = $tab->get_presets;
- if (defined $presets){
- my $reload_dependent_tabs = $tab->get_dependent_tabs;
- $self->{plater}->update_presets($tab_name, $reload_dependent_tabs, $presets);
- $self->{plater}->{"selected_item_$tab_name"} = $tab->get_selected_preset_item;
- if ($tab_name eq 'printer') {
- # Printer selected at the Printer tab, update "compatible" marks at the print and filament selectors.
- for my $tab_name_other (qw(print filament sla_material)) {
- # 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;
- }
- }
- $self->{plater}->on_config_change($tab->get_config);
- }
- }
- });
-
- # The following event is emited by the C++ Tab implementation on object selection change.
- EVT_COMMAND($self, -1, $OBJECT_SELECTION_CHANGED_EVENT, sub {
- my ($self, $event) = @_;
- my $obj_idx = $event->GetId;
-# my $child = $event->GetInt == 1 ? 1 : undef;
-# $self->{plater}->select_object($obj_idx < 0 ? undef: $obj_idx, $child);
-# $self->{plater}->item_changed_selection($obj_idx);
-
- my $vol_idx = $event->GetInt;
- $self->{plater}->select_object_from_cpp($obj_idx < 0 ? undef: $obj_idx, $vol_idx<0 ? -1 : $vol_idx);
- });
-
- # The following event is emited by the C++ GUI implementation on object settings change.
- EVT_COMMAND($self, -1, $OBJECT_SETTINGS_CHANGED_EVENT, sub {
- my ($self, $event) = @_;
-
- my $line = $event->GetString;
- my ($obj_idx, $parts_changed, $part_settings_changed) = split('',$line);
-
- $self->{plater}->changed_object_settings($obj_idx, $parts_changed, $part_settings_changed);
- });
-
- # The following event is emited by the C++ GUI implementation on object remove.
- EVT_COMMAND($self, -1, $OBJECT_REMOVE_EVENT, sub {
- my ($self, $event) = @_;
- $self->{plater}->remove();
- });
-
- # The following event is emited by the C++ GUI implementation on extruder change for object.
- EVT_COMMAND($self, -1, $UPDATE_SCENE_EVENT, sub {
- my ($self, $event) = @_;
- $self->{plater}->update();
- });
-
- Slic3r::GUI::create_preset_tabs($VALUE_CHANGE_EVENT, $PRESETS_CHANGED_EVENT);
- $self->{options_tabs} = {};
- for my $tab_name (qw(print filament sla_material printer)) {
- $self->{options_tabs}{$tab_name} = Slic3r::GUI::get_preset_tab("$tab_name");
- }
-
- # Update progress bar with an event sent by the slicing core.
- EVT_COMMAND($self, -1, $PROGRESS_BAR_EVENT, sub {
- my ($self, $event) = @_;
- if (defined $self->{progress_dialog}) {
- # If a progress dialog is open, update it.
- $self->{progress_dialog}->Update($event->GetInt, $event->GetString . "…");
- } else {
- # Otherwise update the main window status bar.
- $self->{statusbar}->SetProgress($event->GetInt);
- $self->{statusbar}->SetStatusText($event->GetString . "…");
- }
- });
-
- EVT_COMMAND($self, -1, $ERROR_EVENT, sub {
- my ($self, $event) = @_;
- Slic3r::GUI::show_error($self, $event->GetString);
- });
-
- if ($self->{plater}) {
- $self->{plater}->on_select_preset(sub {
- my ($group, $name) = @_;
- $self->{options_tabs}{$group}->select_preset($name);
- });
- # load initial config
- my $full_config = wxTheApp->{preset_bundle}->full_config;
- $self->{plater}->on_config_change($full_config);
-
- # Show a correct number of filament fields.
- if (defined $full_config->nozzle_diameter){ # nozzle_diameter is undefined when SLA printer is selected
- $self->{plater}->on_extruders_change(int(@{$full_config->nozzle_diameter}));
- }
-
- # Show correct preset comboboxes according to the printer_technology
- $self->{plater}->show_preset_comboboxes(($full_config->printer_technology eq "FFF") ? 0 : 1);
- }
-}
-
-sub _init_menubar {
- my ($self) = @_;
-
- # File menu
- my $fileMenu = Wx::Menu->new;
- {
- wxTheApp->append_menu_item($fileMenu, L("Open STL/OBJ/AMF/3MF…\tCtrl+O"), L('Open a model'), sub {
- $self->{plater}->add if $self->{plater};
- }, undef, undef); #'brick_add.png');
- $self->_append_menu_item($fileMenu, L("&Load Config…\tCtrl+L"), L('Load exported configuration file'), sub {
- $self->load_config_file;
- }, undef, 'plugin_add.png');
- $self->_append_menu_item($fileMenu, L("&Export Config…\tCtrl+E"), L('Export current configuration to file'), sub {
- $self->export_config;
- }, undef, 'plugin_go.png');
- $self->_append_menu_item($fileMenu, L("&Load Config Bundle…"), L('Load presets from a bundle'), sub {
- $self->load_configbundle;
- }, undef, 'lorry_add.png');
- $self->_append_menu_item($fileMenu, L("&Export Config Bundle…"), L('Export all presets to file'), sub {
- $self->export_configbundle;
- }, undef, 'lorry_go.png');
- $fileMenu->AppendSeparator();
- $self->_append_menu_item($fileMenu, L("Slice to PNG…"), L('Slice file to a set of PNG files'), sub {
- $self->slice_to_png;
- }, undef, 'shape_handles.png');
- $self->{menu_item_reslice_now} = $self->_append_menu_item(
- $fileMenu, L("(&Re)Slice Now\tCtrl+S"), L('Start new slicing process'),
- sub { $self->reslice_now; }, undef, 'shape_handles.png');
- $fileMenu->AppendSeparator();
- $self->_append_menu_item($fileMenu, L("Repair STL file…"), L('Automatically repair an STL file'), sub {
- $self->repair_stl;
- }, undef, 'wrench.png');
- $fileMenu->AppendSeparator();
- $self->_append_menu_item($fileMenu, L("&Quit"), L('Quit Slic3r'), sub {
- $self->Close(0);
- }, wxID_EXIT);
- }
-
- # Plater menu
- unless ($self->{no_plater}) {
- my $plater = $self->{plater};
-
- $self->{plater_menu} = Wx::Menu->new;
- $self->_append_menu_item($self->{plater_menu}, L("Export G-code..."), L('Export current plate as G-code'), sub {
- $plater->export_gcode;
- }, undef, 'cog_go.png');
- $self->_append_menu_item($self->{plater_menu}, L("Export plate as STL..."), L('Export current plate as STL'), sub {
- $plater->export_stl;
- }, undef, 'brick_go.png');
- $self->_append_menu_item($self->{plater_menu}, L("Export plate as AMF..."), L('Export current plate as AMF'), sub {
- $plater->export_amf;
- }, undef, 'brick_go.png');
- $self->_append_menu_item($self->{plater_menu}, L("Export plate as 3MF..."), L('Export current plate as 3MF'), sub {
- $plater->export_3mf;
- }, undef, 'brick_go.png');
-
- $self->{object_menu} = $self->{plater}->object_menu;
- $self->on_plater_selection_changed(0);
- }
-
- # Window menu
- my $windowMenu = Wx::Menu->new;
- {
- my $tab_offset = 0;
- if (!$self->{no_plater}) {
- $self->_append_menu_item($windowMenu, L("Select &Plater Tab\tCtrl+1"), L('Show the plater'), sub {
- $self->select_tab(0);
- }, undef, 'application_view_tile.png');
- $tab_offset += 1;
- }
- if (!$self->{no_controller}) {
- $self->_append_menu_item($windowMenu, L("Select &Controller Tab\tCtrl+T"), L('Show the printer controller'), sub {
- $self->select_tab(1);
- }, undef, 'printer_empty.png');
- $tab_offset += 1;
- }
- if ($tab_offset > 0) {
- $windowMenu->AppendSeparator();
- }
- $self->_append_menu_item($windowMenu, L("Select P&rint Settings Tab\tCtrl+2"), L('Show the print settings'), sub {
- $self->select_tab($tab_offset+0);
- }, undef, 'cog.png');
- $self->_append_menu_item($windowMenu, L("Select &Filament Settings Tab\tCtrl+3"), L('Show the filament settings'), sub {
- $self->select_tab($tab_offset+1);
- }, undef, 'spool.png');
- $self->_append_menu_item($windowMenu, L("Select Print&er Settings Tab\tCtrl+4"), L('Show the printer settings'), sub {
- $self->select_tab($tab_offset+2);
- }, undef, 'printer_empty.png');
- }
-
- # View menu
- if (!$self->{no_plater}) {
- $self->{viewMenu} = Wx::Menu->new;
- # \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.
- my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] };
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Iso'), '0'), L('Iso View') , sub { $self->select_view('iso' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Top'), '1'), L('Top View') , sub { $self->select_view('top' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Bottom'), '2'), L('Bottom View') , sub { $self->select_view('bottom' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Front'), '3'), L('Front View') , sub { $self->select_view('front' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Rear'), '4'), L('Rear View') , sub { $self->select_view('rear' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Left'), '5'), L('Left View') , sub { $self->select_view('left' ); });
- $self->_append_menu_item($self->{viewMenu}, $accel->(L('Right'), '6'), L('Right View') , sub { $self->select_view('right' ); });
- }
-
- # Help menu
- my $helpMenu = Wx::Menu->new;
- {
- $self->_append_menu_item($helpMenu, L("Prusa 3D Drivers"), L('Open the Prusa3D drivers download page in your browser'), sub {
- Wx::LaunchDefaultBrowser('http://www.prusa3d.com/drivers/');
- });
- $self->_append_menu_item($helpMenu, L("Prusa Edition Releases"), L('Open the Prusa Edition releases page in your browser'), sub {
- Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/releases');
- });
-# my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
-# wxTheApp->check_version(1);
-# });
-# $versioncheck->Enable(wxTheApp->have_version_check);
- $self->_append_menu_item($helpMenu, L("Slic3r &Website"), L('Open the Slic3r website in your browser'), sub {
- Wx::LaunchDefaultBrowser('http://slic3r.org/');
- });
- $self->_append_menu_item($helpMenu, L("Slic3r &Manual"), L('Open the Slic3r manual in your browser'), sub {
- Wx::LaunchDefaultBrowser('http://manual.slic3r.org/');
- });
- $helpMenu->AppendSeparator();
- $self->_append_menu_item($helpMenu, L("System Info"), L('Show system information'), sub {
- wxTheApp->system_info;
- });
- $self->_append_menu_item($helpMenu, L("Show &Configuration Folder"), L('Show user configuration folder (datadir)'), sub {
- Slic3r::GUI::desktop_open_datadir_folder();
- });
- $self->_append_menu_item($helpMenu, L("Report an Issue"), L('Report an issue on the Slic3r Prusa Edition'), sub {
- Wx::LaunchDefaultBrowser('http://github.com/prusa3d/slic3r/issues/new');
- });
- $self->_append_menu_item($helpMenu, L("&About Slic3r"), L('Show about dialog'), sub {
- Slic3r::GUI::about;
- });
- }
-
- # menubar
- # assign menubar to frame after appending items, otherwise special items
- # will not be handled correctly
- {
- my $menubar = Wx::MenuBar->new;
- $menubar->Append($fileMenu, L("&File"));
- $menubar->Append($self->{plater_menu}, L("&Plater")) if $self->{plater_menu};
- $menubar->Append($self->{object_menu}, L("&Object")) if $self->{object_menu};
- $menubar->Append($windowMenu, L("&Window"));
- $menubar->Append($self->{viewMenu}, L("&View")) if $self->{viewMenu};
- # Add additional menus from C++
- Slic3r::GUI::add_menus($menubar, $self->{preferences_event}, $self->{lang_ch_event});
- $menubar->Append($helpMenu, L("&Help"));
- $self->SetMenuBar($menubar);
- }
-}
-
-sub is_loaded {
- my ($self) = @_;
- return $self->{loaded};
-}
-
-# Selection of a 3D object changed on the platter.
-sub on_plater_selection_changed {
- my ($self, $have_selection) = @_;
- return if !defined $self->{object_menu};
- $self->{object_menu}->Enable($_->GetId, $have_selection)
- for $self->{object_menu}->GetMenuItems;
-}
-
-sub slice_to_png {
- my $self = shift;
- $self->{plater}->stop_background_process;
- $self->{plater}->async_apply_config;
- $appController->print_ctl()->slice_to_png();
-}
-
-sub reslice_now {
- my ($self) = @_;
- $self->{plater}->reslice if $self->{plater};
-}
-
-sub repair_stl {
- my $self = shift;
-
- my $input_file;
- {
- my $dialog = Wx::FileDialog->new($self, L('Select the STL file to repair:'),
- wxTheApp->{app_config}->get_last_dir, "",
- &Slic3r::GUI::FILE_WILDCARDS->{stl}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
- if ($dialog->ShowModal != wxID_OK) {
- $dialog->Destroy;
- return;
- }
- $input_file = $dialog->GetPaths;
- $dialog->Destroy;
- }
-
- my $output_file = $input_file;
- {
- $output_file =~ s/\.[sS][tT][lL]$/_fixed.obj/;
- my $dlg = Wx::FileDialog->new($self, L("Save OBJ file (less prone to coordinate errors than STL) as:"), dirname($output_file),
- basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{obj}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- if ($dlg->ShowModal != wxID_OK) {
- $dlg->Destroy;
- return undef;
- }
- $output_file = $dlg->GetPath;
- $dlg->Destroy;
- }
-
- my $tmesh = Slic3r::TriangleMesh->new;
- $tmesh->ReadSTLFile($input_file);
- $tmesh->repair;
- $tmesh->WriteOBJFile($output_file);
- Slic3r::GUI::show_info($self, L("Your file was repaired."), L("Repair"));
-}
-
-sub export_config {
- my $self = shift;
- # Generate a cummulative configuration for the selected print, filaments and printer.
- my $config = wxTheApp->{preset_bundle}->full_config();
- # Validate the cummulative configuration.
- eval { $config->validate; };
- Slic3r::GUI::catch_error($self) and return;
- # Ask user for the file name for the config file.
- my $dlg = Wx::FileDialog->new($self, L('Save configuration as:'),
- $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
- $last_config ? basename($last_config) : "config.ini",
- &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
- $dlg->Destroy;
- if (defined $file) {
- wxTheApp->{app_config}->update_config_dir(dirname($file));
- $last_config = $file;
- $config->save($file);
- }
-}
-
-# Load a config file containing a Print, Filament & Printer preset.
-sub load_config_file {
- my ($self, $file) = @_;
- if (!$file) {
- return unless Slic3r::GUI::check_unsaved_changes;
- my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'),
- $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
- "config.ini",
- 'INI files (*.ini, *.gcode)|*.ini;*.INI;*.gcode;*.g', wxFD_OPEN | wxFD_FILE_MUST_EXIST);
- return unless $dlg->ShowModal == wxID_OK;
- $file = $dlg->GetPaths;
- $dlg->Destroy;
- }
- eval { wxTheApp->{preset_bundle}->load_config_file($file); };
- # Dont proceed further if the config file cannot be loaded.
- return if Slic3r::GUI::catch_error($self);
- $_->load_current_preset for (values %{$self->{options_tabs}});
- wxTheApp->{app_config}->update_config_dir(dirname($file));
- $last_config = $file;
-}
-
-sub export_configbundle {
- my ($self) = @_;
- return unless Slic3r::GUI::check_unsaved_changes;
- # validate current configuration in case it's dirty
- eval { wxTheApp->{preset_bundle}->full_config->validate; };
- Slic3r::GUI::catch_error($self) and return;
- # Ask user for a file name.
- my $dlg = Wx::FileDialog->new($self, L('Save presets bundle as:'),
- $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
- "Slic3r_config_bundle.ini",
- &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- my $file = ($dlg->ShowModal == wxID_OK) ? $dlg->GetPath : undef;
- $dlg->Destroy;
- if (defined $file) {
- # Export the config bundle.
- wxTheApp->{app_config}->update_config_dir(dirname($file));
- eval { wxTheApp->{preset_bundle}->export_configbundle($file); };
- Slic3r::GUI::catch_error($self) and return;
- }
-}
-
-# Loading a config bundle with an external file name used to be used
-# 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, $reset_user_profile) = @_;
- return unless Slic3r::GUI::check_unsaved_changes;
- if (!$file) {
- my $dlg = Wx::FileDialog->new($self, L('Select configuration to load:'),
- $last_config ? dirname($last_config) : wxTheApp->{app_config}->get_last_dir,
- "config.ini",
- &Slic3r::GUI::FILE_WILDCARDS->{ini}, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
- return unless $dlg->ShowModal == wxID_OK;
- $file = $dlg->GetPaths;
- $dlg->Destroy;
- }
-
- wxTheApp->{app_config}->update_config_dir(dirname($file));
-
- my $presets_imported = 0;
- eval { $presets_imported = wxTheApp->{preset_bundle}->load_configbundle($file); };
- 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;
- }
-
- my $message = sprintf L("%d presets successfully imported."), $presets_imported;
- Slic3r::GUI::show_info($self, $message);
-}
-
-# Load a provied DynamicConfig into the Print / Filament / Printer tabs, thus modifying the active preset.
-# Also update the platter with the new presets.
-sub load_config {
- my ($self, $config) = @_;
- $_->load_config($config) foreach values %{$self->{options_tabs}};
- $self->{plater}->on_config_change($config) if $self->{plater};
-}
-
-sub select_tab {
- my ($self, $tab) = @_;
- $self->{tabpanel}->SetSelection($tab);
-}
-
-# Set a camera direction, zoom to all objects.
-sub select_view {
- my ($self, $direction) = @_;
- if (! $self->{no_plater}) {
- $self->{plater}->select_view($direction);
- }
-}
-
-sub _append_menu_item {
- my ($self, $menu, $string, $description, $cb, $id, $icon) = @_;
- $id //= &Wx::NewId();
- my $item = $menu->Append($id, $string, $description);
- $self->_set_menu_item_icon($item, $icon);
- EVT_MENU($self, $id, $cb);
- return $item;
-}
-
-sub _set_menu_item_icon {
- my ($self, $menuItem, $icon) = @_;
- # SetBitmap was not available on OS X before Wx 0.9927
- if ($icon && $menuItem->can('SetBitmap')) {
- $menuItem->SetBitmap(Wx::Bitmap->new(Slic3r::var($icon), wxBITMAP_TYPE_PNG));
- }
-}
-
-# Called after the Preferences dialog is closed and the program settings are saved.
-# Update the UI based on the current preferences.
-sub update_ui_from_settings {
- my ($self) = @_;
- $self->{menu_item_reslice_now}->Enable(! wxTheApp->{app_config}->get("background_processing"));
- $self->{plater}->update_ui_from_settings if ($self->{plater});
- for my $tab_name (qw(print filament printer)) {
- $self->{options_tabs}{$tab_name}->update_ui_from_settings;
- }
-}
-
-1;
diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm
deleted file mode 100644
index db360c811b..0000000000
--- a/lib/Slic3r/GUI/Plater.pm
+++ /dev/null
@@ -1,2683 +0,0 @@
-# The "Plater" tab. It contains the "3D", "2D", "Preview" and "Layers" subtabs.
-
-package Slic3r::GUI::Plater;
-use strict;
-use warnings;
-use utf8;
-
-use File::Basename qw(basename dirname);
-use List::Util qw(sum first max);
-use Slic3r::Geometry qw(X Y Z scale unscale deg2rad rad2deg);
-use Wx qw(:button :colour :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
- :panel :sizer :toolbar :window wxTheApp :notebook :combobox wxNullBitmap);
-use Wx::Event qw(EVT_BUTTON EVT_TOGGLEBUTTON EVT_COMMAND EVT_KEY_DOWN EVT_LIST_ITEM_ACTIVATED
- EVT_LIST_ITEM_DESELECTED EVT_LIST_ITEM_SELECTED EVT_LEFT_DOWN EVT_MOUSE_EVENTS EVT_PAINT EVT_TOOL
- EVT_CHOICE EVT_COMBOBOX EVT_TIMER EVT_NOTEBOOK_PAGE_CHANGED);
-use Slic3r::Geometry qw(PI);
-use base 'Wx::Panel';
-
-use constant TB_ADD => &Wx::NewId;
-use constant TB_REMOVE => &Wx::NewId;
-use constant TB_RESET => &Wx::NewId;
-use constant TB_ARRANGE => &Wx::NewId;
-use constant TB_EXPORT_GCODE => &Wx::NewId;
-use constant TB_EXPORT_STL => &Wx::NewId;
-use constant TB_MORE => &Wx::NewId;
-use constant TB_FEWER => &Wx::NewId;
-use constant TB_45CW => &Wx::NewId;
-use constant TB_45CCW => &Wx::NewId;
-use constant TB_SCALE => &Wx::NewId;
-use constant TB_SPLIT => &Wx::NewId;
-use constant TB_CUT => &Wx::NewId;
-use constant TB_SETTINGS => &Wx::NewId;
-use constant TB_LAYER_EDITING => &Wx::NewId;
-
-use Wx::Locale gettext => 'L';
-
-# Emitted from the worker thread when the G-code export is finished.
-our $SLICING_COMPLETED_EVENT = Wx::NewEventType;
-our $PROCESS_COMPLETED_EVENT = Wx::NewEventType;
-
-my $PreventListEvents = 0;
-our $appController;
-
-# XXX: VK: done, except callback handling and timer
-sub new {
- my ($class, $parent, %params) = @_;
- my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
- Slic3r::GUI::set_plater($self);
- $self->{config} = Slic3r::Config::new_from_defaults_keys([qw(
- bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width variable_layer_height
- serial_port serial_speed host_type print_host printhost_apikey printhost_cafile
- nozzle_diameter single_extruder_multi_material wipe_tower wipe_tower_x wipe_tower_y wipe_tower_width
- wipe_tower_rotation_angle extruder_colour filament_colour max_print_height printer_model
- )]);
-
- # store input params
- $self->{event_object_selection_changed} = $params{event_object_selection_changed};
- $self->{event_object_settings_changed} = $params{event_object_settings_changed};
- $self->{event_remove_object} = $params{event_remove_object};
- $self->{event_update_scene} = $params{event_update_scene};
-
- # C++ Slic3r::Model with Perl extensions in Slic3r/Model.pm
- $self->{model} = Slic3r::Model->new;
- # C++ Slic3r::Print with Perl extensions in Slic3r/Print.pm
- $self->{print} = Slic3r::Print->new;
- # List of Perl objects Slic3r::GUI::Plater::Object, representing a 2D preview of the platter.
- $self->{objects} = [];
- $self->{gcode_preview_data} = Slic3r::GCode::PreviewData->new;
- $self->{background_slicing_process} = Slic3r::GUI::BackgroundSlicingProcess->new;
- $self->{background_slicing_process}->set_print($self->{print});
- $self->{background_slicing_process}->set_gcode_preview_data($self->{gcode_preview_data});
- $self->{background_slicing_process}->set_sliced_event($SLICING_COMPLETED_EVENT);
- $self->{background_slicing_process}->set_finished_event($PROCESS_COMPLETED_EVENT);
-
- # The C++ slicing core will post a wxCommand message to the main window.
- Slic3r::GUI::set_print_callback_event($self->{print}, $Slic3r::GUI::MainFrame::PROGRESS_BAR_EVENT);
-
- # Initialize preview notebook
- $self->{preview_notebook} = Wx::Notebook->new($self, -1, wxDefaultPosition, [-1,335], wxNB_BOTTOM);
-
- # Initialize handlers for canvases
- my $on_select_object = sub {
- my ($obj_idx, $vol_idx) = @_;
-
- if (($obj_idx != -1) && ($vol_idx == -1)) {
- # Ignore the special objects (the wipe tower proxy and such).
- $self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef);
- $self->item_changed_selection($obj_idx) if (defined($obj_idx));
- }
- };
- my $on_right_click = sub {
- my ($canvas, $click_pos_x, $click_pos_y) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $menu = $self->object_menu;
- $canvas->PopupMenu($menu, $click_pos_x, $click_pos_y);
- $menu->Destroy;
- };
- my $on_instances_moved = sub {
- $self->update;
- };
-
- # callback to enable/disable action buttons
- my $enable_action_buttons = sub {
- my ($enable) = @_;
- Slic3r::GUI::enable_action_buttons($enable);
-# $self->{btn_export_gcode}->Enable($enable);
-# $self->{btn_reslice}->Enable($enable);
-# $self->{btn_print}->Enable($enable);
-# $self->{btn_send_gcode}->Enable($enable);
- };
-
- # callback to react to gizmo scale
- my $on_gizmo_scale_uniformly = sub {
- my ($scale) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- $self->stop_background_process;
-
- my $variation = $scale / $model_instance->scaling_factor;
- #FIXME Scale the layer height profile?
- foreach my $range (@{ $model_object->layer_height_ranges }) {
- $range->[0] *= $variation;
- $range->[1] *= $variation;
- }
- $_->set_scaling_factor($scale) for @{ $model_object->instances };
-
- # Set object scale on c++ side
-# Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100);
-
-# $object->transform_thumbnail($self->{model}, $obj_idx);
-
- #update print and start background processing
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed(1); # refresh info (size, volume etc.)
- $self->update;
- $self->schedule_background_process;
- };
-
- # callback to react to gizmo scale
- my $on_gizmo_scale_3D = sub {
- my ($scale_x, $scale_y, $scale_z) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- $self->stop_background_process;
-
- #FIXME Scale the layer height profile?
-# my $variation = $scale / $model_instance->scaling_factor;
-# foreach my $range (@{ $model_object->layer_height_ranges }) {
-# $range->[0] *= $variation;
-# $range->[1] *= $variation;
-# }
-
- my $scale = Slic3r::Pointf3->new($scale_x, $scale_y, $scale_z);
- foreach my $inst (@{ $model_object->instances }) {
- $inst->set_scaling_factors($scale);
- }
- Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
-
- #update print and start background processing
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed(1); # refresh info (size, volume etc.)
- $self->update;
- $self->schedule_background_process;
-
- };
-
- # callback to react to gizmo rotate
- my $on_gizmo_rotate = sub {
- my ($angle) = @_;
- $self->rotate(rad2deg($angle), Z, 'absolute');
- };
-
- # callback to react to gizmo rotate
- my $on_gizmo_rotate_3D = sub {
- my ($angle_x, $angle_y, $angle_z) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- $self->stop_background_process;
-
- my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z);
- foreach my $inst (@{ $model_object->instances }) {
- $inst->set_rotations($rotation);
- }
- Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
-
- # update print and start background processing
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed; # refresh info (size etc.)
- $self->update;
- $self->schedule_background_process;
- };
-
- # callback to react to gizmo flatten
- my $on_gizmo_flatten = sub {
- my ($angle, $axis_x, $axis_y, $axis_z) = @_;
- $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0;
- };
-
- # callback to react to gizmo flatten
- my $on_gizmo_flatten_3D = sub {
- my ($angle_x, $angle_y, $angle_z) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- $self->stop_background_process;
-
- my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z);
- foreach my $inst (@{ $model_object->instances }) {
- $inst->set_rotations($rotation);
- }
- Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
-
- # update print and start background processing
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed; # refresh info (size etc.)
- $self->update;
- $self->schedule_background_process;
- };
-
- # callback to update object's geometry info while using gizmos
- my $on_update_geometry_info = sub {
- my ($size_x, $size_y, $size_z, $scale_factor) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
-
- if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane?
- $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z));
- my $model_object = $self->{model}->objects->[$obj_idx];
- if (my $stats = $model_object->mesh_stats) {
- $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_factor**3));
- }
- }
- };
-
- # callback to update object's geometry info while using gizmos
- my $on_update_geometry_3D_info = sub {
- my ($size_x, $size_y, $size_z, $scale_x, $scale_y, $scale_z) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
-
- if ((defined $obj_idx) && ($self->{object_info_size})) { # have we already loaded the info pane?
- $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", $size_x, $size_y, $size_z));
- my $model_object = $self->{model}->objects->[$obj_idx];
- if (my $stats = $model_object->mesh_stats) {
- $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * $scale_x * $scale_y * $scale_z));
- }
- }
- };
-
- # callbacks for toolbar
- my $on_action_add = sub {
- $self->add;
- };
-
- my $on_action_delete = sub {
- $self->remove();
- };
-
- my $on_action_deleteall = sub {
- $self->reset;
- };
-
- my $on_action_arrange = sub {
- $self->arrange;
- };
-
- my $on_action_more = sub {
- $self->increase;
- };
-
- my $on_action_fewer = sub {
- $self->decrease;
- };
-
- my $on_action_split = sub {
- $self->split_object;
- };
-
- my $on_action_cut = sub {
- $self->object_cut_dialog;
- };
-
- my $on_action_settings = sub {
- $self->object_settings_dialog;
- };
-
- my $on_action_layersediting = sub {
- my $state = Slic3r::GUI::_3DScene::is_toolbar_item_pressed($self->{canvas3D}, "layersediting");
- $self->on_layer_editing_toggled($state);
- };
-
- my $on_action_selectbyparts = sub {
- my $curr = Slic3r::GUI::_3DScene::get_select_by($self->{canvas3D});
- if ($curr eq 'volume') {
- Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object');
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
- }
- elsif ($curr eq 'object') {
- Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'volume');
- my $selections = [];
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D});
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
-
- my ($obj_idx, $object) = $self->selected_object;
- if (defined $obj_idx) {
- my $vol_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx);
- #Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx) if ($vol_idx != -1);
- my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count;
- for (0..$inst_cnt-1){
- Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $_ + $vol_idx) if ($vol_idx != -1);
- }
-
- my $volume_idx = Slic3r::GUI::_3DScene::get_in_object_volume_id($self->{canvas3D}, $vol_idx);
- Slic3r::GUI::select_current_volume($obj_idx, $volume_idx) if ($volume_idx != -1);
- }
- }
- };
-
- # Initialize 3D plater
- if ($Slic3r::GUI::have_OpenGL) {
- $self->{canvas3D} = Slic3r::GUI::Plater::3D->new($self->{preview_notebook}, $self->{objects}, $self->{model}, $self->{print}, $self->{config});
- $self->{preview_notebook}->AddPage($self->{canvas3D}, L('3D'));
- Slic3r::GUI::_3DScene::register_on_select_object_callback($self->{canvas3D}, $on_select_object);
-# Slic3r::GUI::_3DScene::register_on_double_click_callback($self->{canvas3D}, $on_double_click);
- Slic3r::GUI::_3DScene::register_on_right_click_callback($self->{canvas3D}, sub { $on_right_click->($self->{canvas3D}, @_); });
- Slic3r::GUI::_3DScene::register_on_arrange_callback($self->{canvas3D}, sub { $self->arrange });
- Slic3r::GUI::_3DScene::register_on_rotate_object_left_callback($self->{canvas3D}, sub { $self->rotate(-45, Z, 'relative') });
- Slic3r::GUI::_3DScene::register_on_rotate_object_right_callback($self->{canvas3D}, sub { $self->rotate( 45, Z, 'relative') });
- Slic3r::GUI::_3DScene::register_on_scale_object_uniformly_callback($self->{canvas3D}, sub { $self->changescale(undef) });
- Slic3r::GUI::_3DScene::register_on_increase_objects_callback($self->{canvas3D}, sub { $self->increase() });
- Slic3r::GUI::_3DScene::register_on_decrease_objects_callback($self->{canvas3D}, sub { $self->decrease() });
- Slic3r::GUI::_3DScene::register_on_remove_object_callback($self->{canvas3D}, sub { $self->remove() });
- Slic3r::GUI::_3DScene::register_on_instance_moved_callback($self->{canvas3D}, $on_instances_moved);
- Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons);
- Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly);
- Slic3r::GUI::_3DScene::register_on_gizmo_scale_3D_callback($self->{canvas3D}, $on_gizmo_scale_3D);
- Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate);
- Slic3r::GUI::_3DScene::register_on_gizmo_rotate_3D_callback($self->{canvas3D}, $on_gizmo_rotate_3D);
- Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten);
- Slic3r::GUI::_3DScene::register_on_gizmo_flatten_3D_callback($self->{canvas3D}, $on_gizmo_flatten_3D);
- Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info);
- Slic3r::GUI::_3DScene::register_on_update_geometry_3D_info_callback($self->{canvas3D}, $on_update_geometry_3D_info);
- Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add);
- Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete);
- Slic3r::GUI::_3DScene::register_action_deleteall_callback($self->{canvas3D}, $on_action_deleteall);
- Slic3r::GUI::_3DScene::register_action_arrange_callback($self->{canvas3D}, $on_action_arrange);
- Slic3r::GUI::_3DScene::register_action_more_callback($self->{canvas3D}, $on_action_more);
- Slic3r::GUI::_3DScene::register_action_fewer_callback($self->{canvas3D}, $on_action_fewer);
- Slic3r::GUI::_3DScene::register_action_split_callback($self->{canvas3D}, $on_action_split);
- Slic3r::GUI::_3DScene::register_action_cut_callback($self->{canvas3D}, $on_action_cut);
- Slic3r::GUI::_3DScene::register_action_settings_callback($self->{canvas3D}, $on_action_settings);
- Slic3r::GUI::_3DScene::register_action_layersediting_callback($self->{canvas3D}, $on_action_layersediting);
- Slic3r::GUI::_3DScene::register_action_selectbyparts_callback($self->{canvas3D}, $on_action_selectbyparts);
- Slic3r::GUI::_3DScene::enable_gizmos($self->{canvas3D}, 1);
- Slic3r::GUI::_3DScene::enable_toolbar($self->{canvas3D}, 1);
- Slic3r::GUI::_3DScene::enable_shader($self->{canvas3D}, 1);
- Slic3r::GUI::_3DScene::enable_force_zoom_to_bed($self->{canvas3D}, 1);
-
- Slic3r::GUI::_3DScene::register_on_wipe_tower_moved_callback($self->{canvas3D}, sub {
- my ($x, $y) = @_;
- my $cfg = Slic3r::Config->new;
- $cfg->set('wipe_tower_x', $x);
- $cfg->set('wipe_tower_y', $y);
- $self->GetFrame->{options_tabs}{print}->load_config($cfg);
- });
-
- Slic3r::GUI::_3DScene::register_on_model_update_callback($self->{canvas3D}, sub {
- if (wxTheApp->{app_config}->get("background_processing")) {
- $self->schedule_background_process;
- } else {
- # Hide the print info box, it is no more valid.
- $self->print_info_box_show(0);
- }
- });
-
- Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D},
- sub {
- $self->{preview_iface}->set_viewport_from_scene($self->{canvas3D});
- });
-# Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{canvas3D}, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D}); });
- }
-
- Slic3r::GUI::register_on_request_update_callback(sub { $self->schedule_background_process; });
-
- # Initialize 3D toolpaths preview
- if ($Slic3r::GUI::have_OpenGL) {
- $self->{preview_iface} = Slic3r::GUI::create_preview_iface($self->{preview_notebook}, $self->{config}, $self->{print}, $self->{gcode_preview_data});
- $self->{preview_page_idx} = $self->{preview_notebook}->GetPageCount-1;
- $self->{preview_iface}->register_on_viewport_changed_callback(sub { $self->{preview_iface}->set_viewport_into_scene($self->{canvas3D}); });
-# $self->{preview3D} = Slic3r::GUI::Plater::3DPreview->new($self->{preview_notebook}, $self->{print}, $self->{gcode_preview_data}, $self->{config});
-# Slic3r::GUI::_3DScene::enable_legend_texture($self->{preview3D}->canvas, 1);
-# Slic3r::GUI::_3DScene::enable_dynamic_background($self->{preview3D}->canvas, 1);
-# Slic3r::GUI::_3DScene::register_on_viewport_changed_callback($self->{preview3D}->canvas, sub { Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas); });
-# $self->{preview_notebook}->AddPage($self->{preview3D}, L('Preview'));
- $self->{preview3D_page_idx} = $self->{preview_notebook}->GetPageCount-1;
- }
-
- EVT_NOTEBOOK_PAGE_CHANGED($self, $self->{preview_notebook}, sub {
- my $preview = $self->{preview_notebook}->GetCurrentPage;
- my $page_id = $self->{preview_notebook}->GetSelection;
- if (($preview != $self->{canvas3D}) && ($page_id != $self->{preview_page_idx})) {
-# if (($preview != $self->{preview3D}) && ($preview != $self->{canvas3D})) {
- $preview->OnActivate if $preview->can('OnActivate');
- } elsif ($page_id == $self->{preview_page_idx}) {
- $self->{preview_iface}->reload_print;
- # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
- $self->{preview_iface}->set_canvas_as_dirty;
-# } elsif ($preview == $self->{preview3D}) {
-# $self->{preview3D}->reload_print;
-# # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
-# Slic3r::GUI::_3DScene::set_as_dirty($self->{preview3D}->canvas);
- } elsif ($preview == $self->{canvas3D}) {
- if (Slic3r::GUI::_3DScene::is_reload_delayed($self->{canvas3D})) {
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
- }
- # sets the canvas as dirty to force a render at the 1st idle event (wxWidgets IsShownOnScreen() is buggy and cannot be used reliably)
- Slic3r::GUI::_3DScene::set_as_dirty($self->{canvas3D});
- }
- });
-
-# # toolbar for object manipulation
-# if (!&Wx::wxMSW) {
-# Wx::ToolTip::Enable(1);
-# $self->{htoolbar} = Wx::ToolBar->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTB_HORIZONTAL | wxTB_TEXT | wxBORDER_SIMPLE | wxTAB_TRAVERSAL);
-# $self->{htoolbar}->AddTool(TB_ADD, L("Add…"), Wx::Bitmap->new(Slic3r::var("brick_add.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_REMOVE, L("Delete"), Wx::Bitmap->new(Slic3r::var("brick_delete.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_RESET, L("Delete All"), Wx::Bitmap->new(Slic3r::var("cross.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_ARRANGE, L("Arrange"), Wx::Bitmap->new(Slic3r::var("bricks.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddSeparator;
-# $self->{htoolbar}->AddTool(TB_MORE, L("More"), Wx::Bitmap->new(Slic3r::var("add.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_FEWER, L("Fewer"), Wx::Bitmap->new(Slic3r::var("delete.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddSeparator;
-# $self->{htoolbar}->AddTool(TB_45CCW, L("45° ccw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_anticlockwise.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_45CW, L("45° cw"), Wx::Bitmap->new(Slic3r::var("arrow_rotate_clockwise.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_SCALE, L("Scale…"), Wx::Bitmap->new(Slic3r::var("arrow_out.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_SPLIT, L("Split"), Wx::Bitmap->new(Slic3r::var("shape_ungroup.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_CUT, L("Cut…"), Wx::Bitmap->new(Slic3r::var("package.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddSeparator;
-# $self->{htoolbar}->AddTool(TB_SETTINGS, L("Settings…"), Wx::Bitmap->new(Slic3r::var("cog.png"), wxBITMAP_TYPE_PNG), '');
-# $self->{htoolbar}->AddTool(TB_LAYER_EDITING, L('Layer Editing'), Wx::Bitmap->new(Slic3r::var("variable_layer_height.png"), wxBITMAP_TYPE_PNG), wxNullBitmap, 1, 0, 'Layer Editing');
-# } else {
-# my %tbar_buttons = (
-# add => L("Add…"),
-# remove => L("Delete"),
-# reset => L("Delete All"),
-# arrange => L("Arrange"),
-# increase => "",
-# decrease => "",
-# rotate45ccw => "",
-# rotate45cw => "",
-# changescale => L("Scale…"),
-# split => L("Split"),
-# cut => L("Cut…"),
-# settings => L("Settings…"),
-# layer_editing => L("Layer editing"),
-# );
-# $self->{btoolbar} = Wx::BoxSizer->new(wxHORIZONTAL);
-# for (qw(add remove reset arrange increase decrease rotate45ccw rotate45cw changescale split cut settings)) {
-# $self->{"btn_$_"} = Wx::Button->new($self, -1, $tbar_buttons{$_}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-# $self->{btoolbar}->Add($self->{"btn_$_"});
-# }
-# $self->{"btn_layer_editing"} = Wx::ToggleButton->new($self, -1, $tbar_buttons{'layer_editing'}, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
-# $self->{btoolbar}->Add($self->{"btn_layer_editing"});
-# }
-
- ### Panel for right column
- $self->{right_panel} = Wx::Panel->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-# $self->{right_panel} = Wx::ScrolledWindow->new($self, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
-# $self->{right_panel}->SetScrollbars(0, 1, 1, 1);
-
- ### Scrolled Window for panel without "Export G-code" and "Slice now" buttons
- my $scrolled_window_sizer = $self->{scrolled_window_sizer} = Wx::BoxSizer->new(wxVERTICAL);
- $scrolled_window_sizer->SetMinSize([320, -1]);
- my $scrolled_window_panel = $self->{scrolled_window_panel} = Wx::ScrolledWindow->new($self->{right_panel}, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
- $scrolled_window_panel->SetSizer($scrolled_window_sizer);
- $scrolled_window_panel->SetScrollbars(0, 1, 1, 1);
-
- # right pane buttons
- $self->{btn_export_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Export G-code…"), wxDefaultPosition, [-1, 30],);# wxNO_BORDER);#, wxBU_LEFT);
- $self->{btn_reslice} = Wx::Button->new($self->{right_panel}, -1, L("Slice now"), wxDefaultPosition, [-1, 30]);#, wxNO_BORDER);#, wxBU_LEFT);
-# $self->{btn_print} = Wx::Button->new($self->{right_panel}, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
-# $self->{btn_send_gcode} = Wx::Button->new($self->{right_panel}, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
- $self->{btn_print} = Wx::Button->new($scrolled_window_panel, -1, L("Print…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
- $self->{btn_send_gcode} = Wx::Button->new($scrolled_window_panel, -1, L("Send to printer"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
- #$self->{btn_export_stl} = Wx::Button->new($self->{right_panel}, -1, L("Export STL…"), wxDefaultPosition, [-1, 30], wxBU_LEFT);
- #$self->{btn_export_gcode}->SetFont($Slic3r::GUI::small_font);
- #$self->{btn_export_stl}->SetFont($Slic3r::GUI::small_font);
- $self->{btn_print}->Hide;
- $self->{btn_send_gcode}->Hide;
-
-# export_gcode cog_go.png
-#! reslice reslice.png
- my %icons = qw(
- print arrow_up.png
- send_gcode arrow_up.png
- export_stl brick_go.png
- );
- for (grep $self->{"btn_$_"}, keys %icons) {
- $self->{"btn_$_"}->SetBitmap(Wx::Bitmap->new(Slic3r::var($icons{$_}), wxBITMAP_TYPE_PNG));
- }
- $self->selection_changed(0);
- $self->object_list_changed;
- EVT_BUTTON($self, $self->{btn_export_gcode}, sub {
- $self->export_gcode;
- });
- EVT_BUTTON($self, $self->{btn_print}, sub {
- $self->{print_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir());
- });
- EVT_BUTTON($self, $self->{btn_send_gcode}, sub {
- $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir());
- });
- EVT_BUTTON($self, $self->{btn_reslice}, \&reslice);
- EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl);
-
-# if ($self->{htoolbar}) {
-# EVT_TOOL($self, TB_ADD, sub { $self->add; });
-# EVT_TOOL($self, TB_REMOVE, sub { $self->remove() }); # explicitly pass no argument to remove
-# EVT_TOOL($self, TB_RESET, sub { $self->reset; });
-# EVT_TOOL($self, TB_ARRANGE, sub { $self->arrange; });
-# EVT_TOOL($self, TB_MORE, sub { $self->increase; });
-# EVT_TOOL($self, TB_FEWER, sub { $self->decrease; });
-# EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45, Z, 'relative') });
-# EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45, Z, 'relative') });
-# EVT_TOOL($self, TB_SCALE, sub { $self->changescale(undef); });
-# EVT_TOOL($self, TB_SPLIT, sub { $self->split_object; });
-# EVT_TOOL($self, TB_CUT, sub { $_[0]->object_cut_dialog });
-# EVT_TOOL($self, TB_SETTINGS, sub { $_[0]->object_settings_dialog });
-# EVT_TOOL($self, TB_LAYER_EDITING, sub {
-# my $state = Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
-# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, ! $state);
-# $self->on_layer_editing_toggled(! $state);
-# });
-# } else {
-# EVT_BUTTON($self, $self->{btn_add}, sub { $self->add; });
-# EVT_BUTTON($self, $self->{btn_remove}, sub { $self->remove() }); # explicitly pass no argument to remove
-# EVT_BUTTON($self, $self->{btn_remove}, sub { Slic3r::GUI::remove_obj() }); # explicitly pass no argument to remove
-# EVT_BUTTON($self, $self->{btn_reset}, sub { $self->reset; });
-# EVT_BUTTON($self, $self->{btn_arrange}, sub { $self->arrange; });
-# EVT_BUTTON($self, $self->{btn_increase}, sub { $self->increase; });
-# EVT_BUTTON($self, $self->{btn_decrease}, sub { $self->decrease; });
-# EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45, Z, 'relative') });
-# EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45, Z, 'relative') });
-# EVT_BUTTON($self, $self->{btn_changescale}, sub { $self->changescale(undef); });
-# EVT_BUTTON($self, $self->{btn_split}, sub { $self->split_object; });
-# EVT_BUTTON($self, $self->{btn_cut}, sub { $_[0]->object_cut_dialog });
-# EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog });
-# EVT_TOGGLEBUTTON($self, $self->{btn_layer_editing}, sub { $self->on_layer_editing_toggled($self->{btn_layer_editing}->GetValue); });
-# }
-
- $_->SetDropTarget(Slic3r::GUI::Plater::DropTarget->new($self))
- for grep defined($_),
- $self, $self->{canvas3D}, $self->{preview_iface}, $self->{list};
-# $self, $self->{canvas3D}, $self->{preview3D}, $self->{list};
-# $self, $self->{canvas}, $self->{canvas3D}, $self->{preview3D};
-
- EVT_COMMAND($self, -1, $SLICING_COMPLETED_EVENT, sub {
- my ($self, $event) = @_;
- $self->on_update_print_preview;
- });
-
- EVT_COMMAND($self, -1, $PROCESS_COMPLETED_EVENT, sub {
- my ($self, $event) = @_;
- $self->on_process_completed($event->GetInt ? undef : $event->GetString);
- });
-
-# XXX: not done
- {
- my $timer_id = Wx::NewId();
- $self->{apply_config_timer} = Wx::Timer->new($self, $timer_id);
- EVT_TIMER($self, $timer_id, sub {
- my ($self, $event) = @_;
- $self->async_apply_config;
- });
- }
-
-# $self->{canvas}->update_bed_size;
- if ($self->{canvas3D}) {
- Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape);
- Slic3r::GUI::_3DScene::zoom_to_bed($self->{canvas3D});
- }
- $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface});
-# if ($self->{preview3D}) {
-# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape);
-# }
- $self->update;
-
- {
- my $presets;
- {
- $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(4, 2, 1, 2);
- $presets->AddGrowableCol(1, 1);
- $presets->SetFlexibleDirection(wxHORIZONTAL);
- my %group_labels = (
- print => L('Print settings'),
- filament => L('Filament'),
- sla_material=> L('SLA material'),
- printer => L('Printer'),
- );
- # UI Combo boxes for a print, multiple filaments, SLA material and a printer.
- # Initially a single filament combo box is created, but the number of combo boxes for the filament selection may increase,
- # once a printer preset with multiple extruders is activated.
- # $self->{preset_choosers}{$group}[$idx]
- $self->{preset_choosers} = {};
- for my $group (qw(print filament sla_material printer)) {
-# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
- my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$group_labels{$group}:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
- $text->SetFont($Slic3r::GUI::small_font);
-# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
- my $choice = Wx::BitmapComboBox->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, [], wxCB_READONLY);
- if ($group eq 'filament') {
- EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down(0, @_); } );
- }
- $self->{preset_choosers}{$group} = [$choice];
- # setup the listener
- EVT_COMBOBOX($choice, $choice, sub {
- my ($choice) = @_;
- wxTheApp->CallAfter(sub {
- $self->_on_select_preset($group, $choice, 0);
- });
- });
- $presets->Add($text, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxRIGHT, 4);
- $presets->Add($choice, 1, wxALIGN_CENTER_VERTICAL | wxEXPAND | wxBOTTOM, 1);
- }
- $presets->Layout;
- }
-
- my $frequently_changed_parameters_sizer = $self->{frequently_changed_parameters_sizer} = Wx::BoxSizer->new(wxVERTICAL);
-#! Slic3r::GUI::add_frequently_changed_parameters($self->{right_panel}, $frequently_changed_parameters_sizer, $presets);
- Slic3r::GUI::add_frequently_changed_parameters($self->{scrolled_window_panel}, $frequently_changed_parameters_sizer, $presets);
-
- my $object_info_sizer;
- {
- my $box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Info"));
-# my $box = Wx::StaticBox->new($self->{right_panel}, -1, L("Info"));
- $box->SetFont($Slic3r::GUI::small_bold_font);
- $object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL);
- $object_info_sizer->SetMinSize([300,-1]);
- #!my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5);
- my $grid_sizer = Wx::FlexGridSizer->new(2, 4, 5, 5);
- $grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
- $grid_sizer->AddGrowableCol(1, 1);
- $grid_sizer->AddGrowableCol(3, 1);
- $object_info_sizer->Add($grid_sizer, 0, wxEXPAND);
-
- my @info = (
- size => L("Size"),
- volume => L("Volume"),
- facets => L("Facets"),
- materials => L("Materials"),
- manifold => L("Manifold"),
- );
- while (my $field = shift @info) {
- my $label = shift @info;
- my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
-# my $text = Wx::StaticText->new($self->{right_panel}, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
- $text->SetFont($Slic3r::GUI::small_font);
- #!$grid_sizer->Add($text, 0);
-
- $self->{"object_info_$field"} = Wx::StaticText->new($scrolled_window_panel, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
-# $self->{"object_info_$field"} = Wx::StaticText->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
- $self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font);
- if ($field eq 'manifold') {
- $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($scrolled_window_panel, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
-# $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self->{right_panel}, -1, Wx::Bitmap->new(Slic3r::var("error.png"), wxBITMAP_TYPE_PNG));
- #$self->{object_info_manifold_warning_icon}->Hide;
- $self->{"object_info_manifold_warning_icon_show"} = sub {
- if ($self->{object_info_manifold_warning_icon}->IsShown() != $_[0]) {
- # this fuction show/hide info_manifold_warning_icon on the c++ side now
- Slic3r::GUI::set_show_manifold_warning_icon($_[0]);
- #my $mode = wxTheApp->{app_config}->get("view_mode");
- #return if ($mode eq "" || $mode eq "simple");
- #$self->{object_info_manifold_warning_icon}->Show($_[0]);
- #$self->Layout
- }
- };
- $self->{"object_info_manifold_warning_icon_show"}->(0);
-
- my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $h_sizer->Add($text, 0);
- $h_sizer->Add($self->{object_info_manifold_warning_icon}, 0, wxLEFT, 2);
- $h_sizer->Add($self->{"object_info_$field"}, 0, wxLEFT, 2);
- #!$grid_sizer->Add($h_sizer, 0, wxEXPAND);
- $object_info_sizer->Add($h_sizer, 0, wxEXPAND|wxTOP, 4);
- } else {
- $grid_sizer->Add($text, 0);
- $grid_sizer->Add($self->{"object_info_$field"}, 0);
- }
- }
- }
-
- my $print_info_box = Wx::StaticBox->new($scrolled_window_panel, -1, L("Sliced Info"));
- $print_info_box->SetFont($Slic3r::GUI::small_bold_font);
- my $print_info_sizer = $self->{print_info_sizer} = Wx::StaticBoxSizer->new($print_info_box, wxVERTICAL);
-# Wx::StaticBox->new($self->{right_panel}, -1, L("Sliced Info")), wxVERTICAL);
- $print_info_sizer->SetMinSize([300,-1]);
-
- my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $self->{buttons_sizer} = $buttons_sizer;
- $buttons_sizer->AddStretchSpacer(1);
-# $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0);
-#! $buttons_sizer->Add($self->{btn_reslice}, 0, wxALIGN_RIGHT, 0);
- $buttons_sizer->Add($self->{btn_print}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5);
- $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT | wxBOTTOM | wxTOP, 5);
-
-# $scrolled_window_sizer->Add($self->{list}, 1, wxEXPAND, 5);
-# $scrolled_window_sizer->Add($object_info_sizer, 0, wxEXPAND, 0);
-# $scrolled_window_sizer->Add($print_info_sizer, 0, wxEXPAND, 0);
- #$buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0);
-
- ### Sizer for info boxes
- my $info_sizer = $self->{info_sizer} = Wx::BoxSizer->new(wxVERTICAL);
- $info_sizer->SetMinSize([318, -1]);
- $info_sizer->Add($object_info_sizer, 0, wxEXPAND | wxTOP, 20);
- $info_sizer->Add($print_info_sizer, 0, wxEXPAND | wxTOP, 20);
-
- $scrolled_window_sizer->Add($presets, 0, wxEXPAND | wxLEFT, 2) if defined $presets;
- $scrolled_window_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxLEFT, 0) if defined $frequently_changed_parameters_sizer;
- $scrolled_window_sizer->Add($buttons_sizer, 0, wxEXPAND, 0);
- $scrolled_window_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
- # Show the box initially, let it be shown after the slicing is finished.
- $self->print_info_box_show(0);
-
- ### Sizer for "Export G-code" & "Slice now" buttons
- my $btns_sizer = Wx::BoxSizer->new(wxVERTICAL);
- $btns_sizer->SetMinSize([318, -1]);
- $btns_sizer->Add($self->{btn_reslice}, 0, wxEXPAND, 0);
- $btns_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxTOP, 5);
-
- my $right_sizer = Wx::BoxSizer->new(wxVERTICAL);
- $self->{right_panel}->SetSizer($right_sizer);
- $right_sizer->SetMinSize([320, -1]);
-#! $right_sizer->Add($presets, 0, wxEXPAND | wxTOP, 10) if defined $presets;
-#! $right_sizer->Add($frequently_changed_parameters_sizer, 1, wxEXPAND | wxTOP, 0) if defined $frequently_changed_parameters_sizer;
-#! $right_sizer->Add($buttons_sizer, 0, wxEXPAND | wxBOTTOM | wxTOP, 10);
-#! $right_sizer->Add($info_sizer, 0, wxEXPAND | wxLEFT, 20);
- # Show the box initially, let it be shown after the slicing is finished.
-#! $self->print_info_box_show(0);
- $right_sizer->Add($scrolled_window_panel, 1, wxEXPAND | wxTOP, 5);
-# $right_sizer->Add($self->{btn_reslice}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
-# $right_sizer->Add($self->{btn_export_gcode}, 0, wxEXPAND | wxLEFT | wxTOP, 20);
- $right_sizer->Add($btns_sizer, 0, wxEXPAND | wxLEFT | wxTOP, 20);
-
- my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $hsizer->Add($self->{preview_notebook}, 1, wxEXPAND | wxTOP, 1);
- $hsizer->Add($self->{right_panel}, 0, wxEXPAND | wxLEFT | wxRIGHT, 0);#3);
-
- my $sizer = Wx::BoxSizer->new(wxVERTICAL);
-# $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar};
-# $sizer->Add($self->{btoolbar}, 0, wxEXPAND, 0) if $self->{btoolbar};
- $sizer->Add($hsizer, 1, wxEXPAND, 0);
-
- $sizer->SetSizeHints($self);
- $self->SetSizer($sizer);
-
- # Send sizers/buttons to C++
- Slic3r::GUI::set_objects_from_perl( $self->{scrolled_window_panel},
- $frequently_changed_parameters_sizer,
- $info_sizer,
- $self->{btn_export_gcode},
- # $self->{btn_export_stl},
- $self->{btn_reslice},
- $self->{btn_print},
- $self->{btn_send_gcode},
- $self->{object_info_manifold_warning_icon} );
-
- Slic3r::GUI::set_model_events_from_perl( $self->{model},
- $self->{event_object_selection_changed},
- $self->{event_object_settings_changed},
- $self->{event_remove_object},
- $self->{event_update_scene});
- }
-
- # Last correct selected item for each preset
- {
- $self->{selected_item_print} = 0;
- $self->{selected_item_filament} = 0;
- $self->{selected_item_printer} = 0;
- }
-
- $self->update_ui_from_settings();
- $self->Layout;
-
- return $self;
-}
-
-# XXX: VK: WIP
-# sets the callback
-sub on_select_preset {
- my ($self, $cb) = @_;
- $self->{on_select_preset} = $cb;
-}
-
-# XXX: merged with on_select_preset
-# Called from the platter combo boxes selecting the active print, filament or printer.
-sub _on_select_preset {
- my ($self, $group, $choice, $idx) = @_;
- # If user changed a filament preset and the selected machine is equipped with multiple extruders,
- # there are multiple filament selection combo boxes shown at the platter. In that case
- # don't propagate the filament selection changes to the tab.
- if ($group eq 'filament') {
- 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 {
- my $selected_item = $choice->GetSelection();
- return if ($selected_item == $self->{"selected_item_$group"} &&
- !Slic3r::GUI::get_preset_tab($group)->current_preset_is_dirty);
-
- my $selected_string = $choice->GetString($selected_item);
- if ($selected_string eq ("------- ".L("System presets")." -------") ||
- $selected_string eq ("------- ".L("User presets")." -------") ){
- $choice->SetSelection($self->{"selected_item_$group"});
- return;
- }
-
- # call GetSelection() in scalar context as it's context-aware
-# $self->{on_select_preset}->($group, $choice->GetStringSelection)
- $self->{on_select_preset}->($group, $selected_string)
- if $self->{on_select_preset};
- $self->{"selected_item_$group"} = $selected_item;
- }
- # Synchronize config.ini with the current selections.
- wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config});
- # get new config and generate on_config_change() event for updating plater and other things
- $self->on_config_change(wxTheApp->{preset_bundle}->full_config);
-}
-
-# XXX: VK: done
-sub on_layer_editing_toggled {
- my ($self, $new_state) = @_;
- Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, $new_state);
- if ($new_state && ! Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D})) {
- # Initialization of the OpenGL shaders failed. Disable the tool.
-# if ($self->{htoolbar}) {
-# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
-# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0);
-# } else {
-# $self->{"btn_layer_editing"}->Disable;
-# $self->{"btn_layer_editing"}->SetValue(0);
-# }
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0);
- }
- $self->{canvas3D}->Refresh;
- $self->{canvas3D}->Update;
-}
-
-# XXX: VK: done (Plater::priv::main_frame)
-sub GetFrame {
- my ($self) = @_;
- return &Wx::GetTopLevelParent($self);
-}
-
-# XXX: not done
-# Called after the Preferences dialog is closed and the program settings are saved.
-# Update the UI based on the current preferences.
-sub update_ui_from_settings
-{
- my ($self) = @_;
- if (defined($self->{btn_reslice}) && $self->{buttons_sizer}->IsShown($self->{btn_reslice}) != (! wxTheApp->{app_config}->get("background_processing"))) {
- $self->{buttons_sizer}->Show($self->{btn_reslice}, ! wxTheApp->{app_config}->get("background_processing"));
- $self->{buttons_sizer}->Layout;
- }
-}
-
-# XXX: VK: done
-# Update preset combo boxes (Print settings, Filament, Material, Printer) from their respective tabs.
-# Called by
-# Slic3r::GUI::Tab::Print::_on_presets_changed
-# Slic3r::GUI::Tab::Filament::_on_presets_changed
-# Slic3r::GUI::Tab::Material::_on_presets_changed
-# Slic3r::GUI::Tab::Printer::_on_presets_changed
-# when the presets are loaded or the user selects another preset.
-# For Print settings and Printer, synchronize the selection index with their tabs.
-# For Filament, synchronize the selection index for a single extruder printer only, otherwise keep the selection.
-sub update_presets {
- # $group: one of qw(print filament sla_material printer)
- # $presets: PresetCollection
- my ($self, $group, $presets) = @_;
- my @choosers = @{$self->{preset_choosers}{$group}};
- if ($group eq 'filament') {
- my $choice_idx = 0;
- if (int(@choosers) == 1) {
- # Single filament printer, synchronize the filament presets.
- wxTheApp->{preset_bundle}->set_filament_preset(0, wxTheApp->{preset_bundle}->filament->get_selected_preset->name);
- }
- foreach my $choice (@choosers) {
- wxTheApp->{preset_bundle}->update_platter_filament_ui($choice_idx, $choice);
- $choice_idx += 1;
- }
- } elsif ($group eq 'print') {
- wxTheApp->{preset_bundle}->print->update_platter_ui($choosers[0]);
- } elsif ($group eq 'sla_material') {
- wxTheApp->{preset_bundle}->sla_material->update_platter_ui($choosers[0]);
- } elsif ($group eq 'printer') {
- # Update the print choosers to only contain the compatible presets, update the dirty flags.
- wxTheApp->{preset_bundle}->print->update_platter_ui($self->{preset_choosers}{print}->[0]);
- # Update the printer choosers, update the dirty flags.
- wxTheApp->{preset_bundle}->printer->update_platter_ui($choosers[0]);
- # Update the filament choosers to only contain the compatible presets, update the color preview,
- # update the dirty flags.
- my $choice_idx = 0;
- foreach my $choice (@{$self->{preset_choosers}{filament}}) {
- wxTheApp->{preset_bundle}->update_platter_filament_ui($choice_idx, $choice);
- $choice_idx += 1;
- }
- }
- # Synchronize config.ini with the current selections.
- wxTheApp->{preset_bundle}->export_selections(wxTheApp->{app_config});
-}
-
-# XXX: VK: done, in on_action_add()
-sub add {
- my ($self) = @_;
- my @input_files = wxTheApp->open_model($self);
- $self->load_files(\@input_files);
-}
-
-# XXX: VK: done
-sub load_files {
- my ($self, $input_files) = @_;
-
- return if ! defined($input_files) || ! scalar(@$input_files);
-
- my $nozzle_dmrs = $self->{config}->get('nozzle_diameter');
- # One of the files is potentionally a bundle of files. Don't bundle them, but load them one by one.
- # Only bundle .stls or .objs if the printer has multiple extruders.
- my $one_by_one = (@$nozzle_dmrs <= 1) || (@$input_files == 1) ||
- defined(first { $_ =~ /.[aA][mM][fF]$/ || $_ =~ /.[aA][mM][fF].[xX][mM][lL]$/ || $_ =~ /.[zZ][iI][pP].[aA][mM][fF]$/ || $_ =~ /.3[mM][fF]$/ || $_ =~ /.[pP][rR][uI][sS][aA]$/ } @$input_files);
-
- my $process_dialog = Wx::ProgressDialog->new(L('Loading…'), L("Processing input file\n") . basename($input_files->[0]), 100, $self, 0);
- $process_dialog->Pulse;
- local $SIG{__WARN__} = Slic3r::GUI::warning_catcher($self);
-
- # new_model to collect volumes, if all of them come from .stl or .obj and there is a chance, that they will be
- # possibly merged into a single multi-part object.
- my $new_model = $one_by_one ? undef : Slic3r::Model->new;
- # Object indices for the UI.
- my @obj_idx = ();
- # Collected file names to display the final message on the status bar.
- my @loaded_files = (); # XXX: used???
- # For all input files.
- for (my $i = 0; $i < @$input_files; $i += 1) {
- my $input_file = $input_files->[$i];
- $process_dialog->Update(100. * $i / @$input_files, L("Processing input file\n") . basename($input_file));
-
- my $model;
- if (($input_file =~ /.3[mM][fF]$/) || ($input_file =~ /.[zZ][iI][pP].[aA][mM][fF]$/))
- {
- $model = eval { Slic3r::Model->read_from_archive($input_file, wxTheApp->{preset_bundle}, 0) };
- Slic3r::GUI::show_error($self, $@) if $@;
- $_->load_current_preset for (values %{$self->GetFrame->{options_tabs}});
- wxTheApp->{app_config}->update_config_dir(dirname($input_file));
- # forces the update of the config here, or it will invalidate the imported layer heights profile if done using the timer
- # and if the config contains a "layer_height" different from the current defined one
- $self->async_apply_config;
- }
- else
- {
- $model = eval { Slic3r::Model->read_from_file($input_file, 0) };
- Slic3r::GUI::show_error($self, $@) if $@;
- }
-
- next if ! defined $model;
-
- if ($model->looks_like_multipart_object) {
- my $dialog = Wx::MessageDialog->new($self,
- L("This file contains several objects positioned at multiple heights. "
- . "Instead of considering them as multiple objects, should I consider\n"
- . "this file as a single object having multiple parts?\n"),
- L('Multi-part object detected'), wxICON_WARNING | wxYES | wxNO);
- $model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES;
- }
-
- # objects imported from 3mf require a call to center_around_origin to have gizmos working properly and this call
- # need to be done after looks_like_multipart_object detection
- if ($input_file =~ /[.]3[mM][fF]$/)
- {
- foreach my $model_object (@{$model->objects}) {
- $model_object->center_around_origin; # also aligns object to Z = 0
- }
- }
-
- if ($one_by_one) {
- push @obj_idx, $self->load_model_objects(@{$model->objects});
- } else {
- # This must be an .stl or .obj file, which may contain a maximum of one volume.
- $new_model->add_object($_) for (@{$model->objects});
- }
- }
-
- if ($new_model) {
- my $dialog = Wx::MessageDialog->new($self,
- L("Multiple objects were loaded for a multi-material printer.\n"
- . "Instead of considering them as multiple objects, should I consider\n"
- . "these files to represent a single object having multiple parts?\n"),
- L('Multi-part object detected'), wxICON_WARNING | wxYES | wxNO);
- $new_model->convert_multipart_object(scalar(@$nozzle_dmrs)) if $dialog->ShowModal() == wxID_YES;
- push @obj_idx, $self->load_model_objects(@{$new_model->objects});
- }
-
- # Note the current directory for the file open dialog.
- wxTheApp->{app_config}->update_skein_dir(dirname($input_files->[-1]));
-
- $process_dialog->Destroy;
- $self->statusbar->SetStatusText(L("Loaded ") . join(',', @loaded_files));
- return @obj_idx;
-}
-
-# XXX: VK: done, except a few todos
-sub load_model_objects {
- my ($self, @model_objects) = @_;
-
- my $bed_centerf = $self->bed_centerf;
- my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape});
- my $bed_size = $bed_shape->bounding_box->size;
-
- my $need_arrange = 0;
- my $scaled_down = 0;
- my @obj_idx = ();
- foreach my $model_object (@model_objects) {
- my $o = $self->{model}->add_object($model_object);
- my $object_name = $model_object->name;
- $object_name = basename($model_object->input_file) if ($object_name eq '');
- push @{ $self->{objects} }, Slic3r::GUI::Plater::Object->new(name => $object_name);
- push @obj_idx, $#{ $self->{objects} };
-
- if ($model_object->instances_count == 0) {
- # if object has no defined position(s) we need to rearrange everything after loading
- $need_arrange = 1;
-
- # add a default instance and center object around origin
- $o->center_around_origin; # also aligns object to Z = 0
- $o->add_instance(offset => $bed_centerf);
- }
-
- {
- # if the object is too large (more than 5 times the bed), scale it down
- my $size = $o->bounding_box->size;
- my $ratio = max($size->x / unscale($bed_size->x), $size->y / unscale($bed_size->y));
- if ($ratio > 10000) {
- # the size of the object is too big -> this could lead to overflow when moving to clipper coordinates,
- # so scale down the mesh
- $o->scale_xyz(Slic3r::Pointf3->new(1/$ratio, 1/$ratio, 1/$ratio));
- $scaled_down = 1;
- }
- elsif ($ratio > 5) {
- $_->set_scaling_factor(1/$ratio) for @{$o->instances};
- $scaled_down = 1;
- }
- }
-
- $self->{print}->auto_assign_extruders($o);
- $self->{print}->add_model_object($o);
- }
-
- # if user turned autocentering off, automatic arranging would disappoint them
- if (! wxTheApp->{app_config}->get("autocenter")) {
- $need_arrange = 0;
- }
-
- if ($scaled_down) {
- Slic3r::GUI::show_info(
- $self,
- L('Your object appears to be too large, so it was automatically scaled down to fit your print bed.'),
- L('Object too large?'),
- );
- }
-
- foreach my $obj_idx (@obj_idx) {
- my $object = $self->{objects}[$obj_idx];
- my $model_object = $self->{model}->objects->[$obj_idx];
-
- # Add object to list on c++ side
- Slic3r::GUI::add_object_to_list($object->name, $model_object);
-
-
-# $self->reset_thumbnail($obj_idx);
- }
- $self->arrange if $need_arrange;
- $self->update;
-
- # zoom to objects
- Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
-
- $self->object_list_changed;
-
- $self->schedule_background_process;
-
- return @obj_idx;
-}
-
-# XXX: Removed, replaced with bed_shape_bb()
-sub bed_centerf {
- my ($self) = @_;
-
- my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape});
- my $bed_center = $bed_shape->bounding_box->center;
- return Slic3r::Pointf->new(unscale($bed_center->x), unscale($bed_center->y)); #)
-}
-
-# XXX: VK: done
-sub remove {
- my ($self, $obj_idx) = @_;
-
- $self->stop_background_process;
-
- # Prevent toolpaths preview from rendering while we modify the Print object
- $self->{preview_iface}->set_enabled(0) if $self->{preview_iface};
-# $self->{preview3D}->enabled(0) if $self->{preview3D};
-
- # If no object index is supplied, remove the selected one.
- if (! defined $obj_idx) {
- ($obj_idx, undef) = $self->selected_object;
- return if ! defined $obj_idx;
- }
-
- splice @{$self->{objects}}, $obj_idx, 1;
- $self->{model}->delete_object($obj_idx);
- $self->{print}->delete_object($obj_idx);
- # Delete object from list on c++ side
- Slic3r::GUI::delete_object_from_list();
- $self->object_list_changed;
-
- $self->select_object(undef);
- $self->update;
-}
-
-# XXX: VK: done
-sub reset {
- my ($self) = @_;
-
- $self->stop_background_process;
-
- # Prevent toolpaths preview from rendering while we modify the Print object
- $self->{preview_iface}->set_enabled(0) if $self->{preview_iface};
-# $self->{preview3D}->enabled(0) if $self->{preview3D};
-
- @{$self->{objects}} = ();
- $self->{model}->clear_objects;
- $self->{print}->clear_objects;
- # Delete all objects from list on c++ side
- Slic3r::GUI::delete_all_objects_from_list();
- $self->object_list_changed;
-
- $self->select_object(undef);
- $self->update;
-}
-
-# XXX: VK: done
-sub increase {
- my ($self, $copies) = @_;
- $copies //= 1;
- my ($obj_idx, $object) = $self->selected_object;
- return if ! defined $obj_idx;
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $instance = $model_object->instances->[-1];
- $self->stop_background_process;
- for my $i (1..$copies) {
- $instance = $model_object->add_instance(
- offset => Slic3r::Pointf->new(map 10+$_, @{$instance->offset}),
- scaling_factor => $instance->scaling_factor,
- rotation => $instance->rotation,
- );
- $self->{print}->objects->[$obj_idx]->add_copy($instance->offset);
- }
- # Set count of object on c++ side
- Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count);
-
- # only autoarrange if user has autocentering enabled
- $self->stop_background_process;
- if (wxTheApp->{app_config}->get("autocenter")) {
- $self->arrange;
- } else {
- $self->update;
- }
-
- $self->selection_changed; # refresh info (size, volume etc.)
- $self->schedule_background_process;
-}
-
-# XXX: VK: done
-sub decrease {
- my ($self, $copies_asked) = @_;
- my $copies = $copies_asked // 1;
- my ($obj_idx, $object) = $self->selected_object;
- return if ! defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- if ($model_object->instances_count > $copies) {
- $self->stop_background_process;
- for my $i (1..$copies) {
- $model_object->delete_last_instance;
- $self->{print}->objects->[$obj_idx]->delete_last_copy;
- }
- # Set conut of object on c++ side
- Slic3r::GUI::set_object_count($obj_idx, $model_object->instances_count);
- } elsif (defined $copies_asked) {
- # The "decrease" came from the "set number of copies" dialog.
- $self->stop_background_process;
- $self->remove;
- } else {
- # The "decrease" came from the "-" button. Don't allow the object to disappear.
- return;
- }
-
- $self->update;
-}
-
-# XXX: VK: done
-sub set_number_of_copies {
- my ($self) = @_;
- # get current number of copies
- my ($obj_idx, $object) = $self->selected_object;
- my $model_object = $self->{model}->objects->[$obj_idx];
- # prompt user
- my $copies = -1;
- $copies = Wx::GetNumberFromUser("", L("Enter the number of copies of the selected object:"), L("Copies"), $model_object->instances_count, 0, 1000, $self);
- my $diff = $copies - $model_object->instances_count;
- if ($diff == 0 || $copies == -1) {
- # no variation
- } elsif ($diff > 0) {
- $self->increase($diff);
- } elsif ($diff < 0) {
- $self->decrease(-$diff);
- }
-}
-
-# XXX: VK: removed
-sub _get_number_from_user {
- my ($self, $title, $prompt_message, $error_message, $default, $only_positive) = @_;
- for (;;) {
- my $value = Wx::GetTextFromUser($prompt_message, $title, $default, $self);
- # Accept both dashes and dots as a decimal separator.
- $value =~ s/,/./;
- # If scaling value is being entered, remove the trailing percent sign.
- $value =~ s/%$// if $only_positive;
- # User canceled the selection, return undef.
- return if $value eq '';
- # Validate a numeric value.
- return $value if ($value =~ /^-?\d*(?:\.\d*)?$/) && (! $only_positive || $value > 0);
- Wx::MessageBox(
- $error_message .
- (($only_positive && $value <= 0) ?
- ": ".$value.L("\nNon-positive value.") :
- ": ".$value.L("\nNot a numeric value.")),
- L("Slic3r Error"), wxOK | wxICON_EXCLAMATION, $self);
- $default = $value;
- }
-}
-
-# XXX: not done
-sub rotate {
- my ($self, $angle, $axis, $relative_key, $axis_x, $axis_y, $axis_z) = @_;
- $relative_key //= 'absolute'; # relative or absolute coordinates
- $axis_x //= 0;
- $axis_y //= 0;
- $axis_z //= 0;
- my $relative = $relative_key eq 'relative';
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- if (!defined $angle) {
- my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
- my $default = $axis == Z ? rad2deg($model_instance->rotation) : 0;
- $angle = $self->_get_number_from_user(L("Enter the rotation angle:"), L("Rotate around ").$axis_name.(" axis"), L("Invalid rotation angle entered"), $default);
- return if $angle eq '';
- }
-
- # Let's calculate vector of rotation axis (if we don't have it already)
- if (defined $axis) {
- if ($axis == X) {
- $axis_x = 1;
- }
- if ($axis == Y) {
- $axis_y = 1;
- }
- }
-
- $self->stop_background_process;
-
- if (defined $axis && $axis == Z) {
- my $new_angle = deg2rad($angle);
- foreach my $inst (@{ $model_object->instances }) {
- my $rotation = ($relative ? $inst->rotation : 0.) + $new_angle;
- while ($rotation > 2.0 * PI) {
- $rotation -= 2.0 * PI;
- }
- while ($rotation < 0.0) {
- $rotation += 2.0 * PI;
- }
- $inst->set_rotation($rotation);
- Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D});
- }
-# $object->transform_thumbnail($self->{model}, $obj_idx);
- } else {
- if (defined $axis) {
- # rotation around X and Y needs to be performed on mesh
- # so we first apply any Z rotation
- if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, -1));
- $_->set_rotation(0) for @{ $model_object->instances };
- }
- }
- $model_object->rotate(deg2rad($angle), Slic3r::Pointf3->new($axis_x, $axis_y, $axis_z));
-
-# # realign object to Z = 0
-# $model_object->center_around_origin;
-# $self->reset_thumbnail($obj_idx);
- }
-
- # update print and start background processing
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed; # refresh info (size etc.)
- $self->update;
-}
-
-# XXX: not done
-sub mirror {
- my ($self, $axis) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- # apply Z rotation before mirroring
- if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1));
- $_->set_rotation(0) for @{ $model_object->instances };
- }
-
- $model_object->mirror($axis);
-
-# # realign object to Z = 0
-# $model_object->center_around_origin;
-# $self->reset_thumbnail($obj_idx);
-
- # update print and start background processing
- $self->stop_background_process;
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed; # refresh info (size etc.)
- $self->update;
-}
-
-# XXX: not done, renamed as Plater::priv::scale()
-sub changescale {
- my ($self, $axis, $tosize) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
-
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_instance = $model_object->instances->[0];
-
- my $object_size = $model_object->instance_bounding_box(0)->size;
-
- if (defined $axis) {
- my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
- my $scale;
- if ($tosize) {
- my $cursize = $object_size->[$axis];
- my $newsize = $self->_get_number_from_user(
- L('Enter the new size for the selected object:'),
- L("Scale along ").$axis_name, L('Invalid scaling value entered'), $cursize, 1);
- return if $newsize eq '';
- $scale = $newsize / $cursize * 100;
- } else {
- $scale = $self->_get_number_from_user(L('Enter the scale % for the selected object:'), L("Scale along ").$axis_name, L('Invalid scaling value entered'), 100, 1);
- return if $scale eq '';
- }
-
- # apply Z rotation before scaling
- if ($model_instance->rotation != 0) {
- $model_object->rotate($model_instance->rotation, Slic3r::Pointf3->new(0, 0, 1));
- $_->set_rotation(0) for @{ $model_object->instances };
- }
-
- my $versor = [1,1,1];
- $versor->[$axis] = $scale/100;
- $model_object->scale_xyz(Slic3r::Pointf3->new(@$versor));
- #FIXME Scale the layer height profile when $axis == Z?
- #FIXME Scale the layer height ranges $axis == Z?
- # object was already aligned to Z = 0, so no need to realign it
-# $self->reset_thumbnail($obj_idx);
- } else {
- my $scale;
- if ($tosize) {
- my $cursize = max(@$object_size);
- my $newsize = $self->_get_number_from_user(L('Enter the new max size for the selected object:'), L('Scale'), L('Invalid scaling value entered'), $cursize, 1);
- return if ! defined($newsize) || $newsize eq '';
- $scale = $model_instance->scaling_factor * $newsize / $cursize * 100;
- } else {
- # max scale factor should be above 2540 to allow importing files exported in inches
- $scale = $self->_get_number_from_user(L('Enter the scale % for the selected object:'), L('Scale'), L('Invalid scaling value entered'), $model_instance->scaling_factor*100, 1);
- return if ! defined($scale) || $scale eq '';
- }
-
- # Set object scale on c++ side
-# Slic3r::GUI::set_object_scale($obj_idx, $scale);
- $scale /= 100; # turn percent into factor
-
- my $variation = $scale / $model_instance->scaling_factor;
- #FIXME Scale the layer height profile?
- foreach my $range (@{ $model_object->layer_height_ranges }) {
- $range->[0] *= $variation;
- $range->[1] *= $variation;
- }
- $_->set_scaling_factor($scale) for @{ $model_object->instances };
-# $object->transform_thumbnail($self->{model}, $obj_idx);
- }
-
- # update print and start background processing
- $self->stop_background_process;
- $self->{print}->add_model_object($model_object, $obj_idx);
-
- $self->selection_changed(1); # refresh info (size, volume etc.)
- $self->update;
-}
-
-# XXX: VK: WIP
-sub arrange {
- my ($self) = @_;
-
- $self->stop_background_process;
- # my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape);
- # my $success = $self->{model}->arrange_objects(wxTheApp->{preset_bundle}->full_config->min_object_distance, $bb);
-
- # Update is not implemented in C++ so we cannot call this for now
- $self->{appController}->arrange_model;
-
- # ignore arrange failures on purpose: user has visual feedback and we don't need to warn him
- # when parts don't fit in print bed
-
- # Force auto center of the aligned grid of of objects on the print bed.
- $self->update(0);
-}
-
-# XXX: not done
-sub split_object {
- my $self = shift;
-
- my ($obj_idx, $current_object) = $self->selected_object;
-
- # we clone model object because split_object() adds the split volumes
- # into the same model object, thus causing duplicates when we call load_model_objects()
- my $new_model = $self->{model}->clone; # store this before calling get_object()
- my $current_model_object = $new_model->get_object($obj_idx);
-
- if ($current_model_object->volumes_count > 1) {
- Slic3r::GUI::warning_catcher($self)->(L("The selected object can't be split because it contains more than one volume/material."));
- return;
- }
-
- $self->stop_background_process;
-
- my @model_objects = @{$current_model_object->split_object};
- if (@model_objects == 1) {
- Slic3r::GUI::warning_catcher($self)->(L("The selected object couldn't be split because it contains only one part."));
- $self->schedule_background_process;
- } else {
- $_->center_around_origin for (@model_objects);
- $self->remove($obj_idx);
- $current_object = $obj_idx = undef;
- # load all model objects at once, otherwise the plate would be rearranged after each one
- # causing original positions not to be kept
- $self->load_model_objects(@model_objects);
- }
-}
-
-# XXX: not done
-# Trigger $self->async_apply_config() after 500ms.
-# The call is delayed to avoid restarting the background processing during typing into an edit field.
-sub schedule_background_process {
- my ($self) = @_;
- $self->{apply_config_timer}->Start(0.5 * 1000, 1); # 1 = one shot, every half a second.
-}
-
-# XXX: not done
-# Executed asynchronously by a timer every PROCESS_DELAY (0.5 second).
-# The timer is started by schedule_background_process(),
-sub async_apply_config {
- my ($self) = @_;
- # Apply new config to the possibly running background task.
- my $was_running = $self->{background_slicing_process}->running;
- my $invalidated = $self->{background_slicing_process}->apply_config(wxTheApp->{preset_bundle}->full_config);
- # Just redraw the 3D canvas without reloading the scene to consume the update of the layer height profile.
- $self->{canvas3D}->Refresh if Slic3r::GUI::_3DScene::is_layers_editing_enabled($self->{canvas3D});
- # If the apply_config caused the calculation to stop, or it was not running yet:
- if ($invalidated) {
- if ($was_running) {
- # Hide the slicing results if the current slicing status is no more valid.
- $self->print_info_box_show(0)
- }
- if (wxTheApp->{app_config}->get("background_processing")) {
- $self->{background_slicing_process}->start;
- }
- if ($was_running) {
- # Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
- # Otherwise they will be just refreshed.
- $self->{gcode_preview_data}->reset;
- $self->{preview_iface}->reload_print if $self->{preview_iface};
-# $self->{preview3D}->reload_print if $self->{preview3D};
- # We also need to reload 3D scene because of the wipe tower preview box
- if ($self->{config}->wipe_tower) {
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1) if $self->{canvas3D}
- }
- }
- }
-}
-
-# XXX: not done
-# Background processing is started either by the "Slice now" button, by the "Export G-code button" or by async_apply_config().
-sub start_background_process {
- my ($self) = @_;
- return if ! @{$self->{objects}} || $self->{background_slicing_process}->running;
- # Don't start process thread if config is not valid.
- eval {
- # this will throw errors if config is not valid
- wxTheApp->{preset_bundle}->full_config->validate;
- $self->{print}->validate;
- };
- if ($@) {
- $self->statusbar->SetStatusText($@);
- return;
- }
- # Copy the names of active presets into the placeholder parser.
- wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser);
- # Start the background process.
- $self->{background_slicing_process}->start;
-}
-
-# XXX: not done
-# Stop the background processing
-sub stop_background_process {
- my ($self) = @_;
- $self->{background_slicing_process}->stop();
- $self->{preview_iface}->reload_print if $self->{preview_iface};
-# $self->{preview3D}->reload_print if $self->{preview3D};
-}
-
-# XXX: not done
-# Called by the "Slice now" button, which is visible only if the background processing is disabled.
-sub reslice {
- # explicitly cancel a previous thread and start a new one.
- my ($self) = @_;
- # Don't reslice if export of G-code or sending to OctoPrint is running.
- if (! defined($self->{export_gcode_output_file}) && ! defined($self->{send_gcode_file})) {
- # Stop the background processing threads, stop the async update timer.
- $self->stop_background_process;
- # Rather perform one additional unnecessary update of the print object instead of skipping a pending async update.
- $self->async_apply_config;
- $self->statusbar->SetCancelCallback(sub {
- $self->stop_background_process;
- $self->statusbar->SetStatusText(L("Slicing cancelled"));
- # this updates buttons status
- $self->object_list_changed;
- });
- $self->start_background_process;
- }
-}
-
-# XXX: VK: done
-sub export_gcode {
- my ($self, $output_file) = @_;
-
- return if !@{$self->{objects}};
-
- if ($self->{export_gcode_output_file}) {
- Wx::MessageDialog->new($self, L("Another export job is currently running."), L('Error'), wxOK | wxICON_ERROR)->ShowModal;
- return;
- }
-
- # if process is not running, validate config
- # (we assume that if it is running, config is valid)
- eval {
- # this will throw errors if config is not valid
- wxTheApp->{preset_bundle}->full_config->validate;
- $self->{print}->validate;
- };
- Slic3r::GUI::catch_error($self) and return;
-
-
- # apply config and validate print
- my $config = wxTheApp->{preset_bundle}->full_config;
- eval {
- # this will throw errors if config is not valid
- $config->validate;
- #FIXME it shall use the background processing!
- $self->{print}->apply_config($config);
- $self->{print}->validate;
- };
- Slic3r::GUI::catch_error($self) and return;
-
- # Copy the names of active presets into the placeholder parser.
- wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser);
- # select output file
- if ($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 = eval { $self->{print}->output_filepath($main::opt{output} // '') };
- Slic3r::GUI::catch_error($self) and return;
- # If possible, remove accents from accented latin characters.
- # This function is useful for generating file names to be processed by legacy firmwares.
- $default_output_file = Slic3r::GUI::fold_utf8_to_ascii($default_output_file);
- my $dlg = Wx::FileDialog->new($self, L('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);
- if ($dlg->ShowModal != wxID_OK) {
- $dlg->Destroy;
- return;
- }
- my $path = $dlg->GetPath;
- wxTheApp->{app_config}->update_last_output_dir(dirname($path));
- $self->{export_gcode_output_file} = $path;
- $dlg->Destroy;
- }
-
- $self->statusbar->StartBusy;
-
- $self->statusbar->SetCancelCallback(sub {
- $self->stop_background_process;
- $self->statusbar->SetStatusText(L("Export cancelled"));
- $self->{export_gcode_output_file} = undef;
- $self->{send_gcode_file} = undef;
-
- # this updates buttons status
- $self->object_list_changed;
- });
-
- $self->{background_slicing_process}->set_output_path($self->{export_gcode_output_file});
-
- # start background process, whose completion event handler
- # will detect $self->{export_gcode_output_file} and proceed with export
- $self->start_background_process;
-
- # this updates buttons status
- $self->object_list_changed;
-
- return $self->{export_gcode_output_file};
-}
-
-# XXX: not done
-# This message should be called by the background process synchronously.
-sub on_update_print_preview {
- my ($self) = @_;
- $self->{preview_iface}->reload_print if $self->{preview_iface};
-# $self->{preview3D}->reload_print if $self->{preview3D};
-
- # in case this was MM print, wipe tower bounding box on 3D tab might need redrawing with exact depth:
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
-}
-
-# XXX: not done
-# This gets called also if we have no threads.
-sub on_progress_event {
- my ($self, $percent, $message) = @_;
-
- $self->statusbar->SetProgress($percent);
- # TODO: three dot character is not properly translated into C++
- # $self->statusbar->SetStatusText("$message…");
- $self->statusbar->SetStatusText("$message...");
-}
-
-# XXX: not done
-# Called when the G-code export finishes, either successfully or with an error.
-# This gets called also if we don't have threads.
-sub on_process_completed {
- my ($self, $result) = @_;
-
- # Stop the background task, wait until the thread goes into the "Idle" state.
- # At this point of time the thread should be either finished or canceled,
- # so the following call just confirms, that the produced data were consumed.
- $self->{background_slicing_process}->stop;
- $self->statusbar->ResetCancelCallback();
- $self->statusbar->StopBusy;
- $self->statusbar->SetStatusText("");
-
- my $message;
- my $send_gcode = 0;
- my $do_print = 0;
-# print "Process completed, message: ", $message, "\n";
- if (defined($result)) {
- $message = L("Export failed");
- } else {
- # G-code file exported successfully.
- if ($self->{print_file}) {
- $message = L("File added to print queue");
- $do_print = 1;
- } elsif ($self->{send_gcode_file}) {
- $message = L("Sending G-code file to the Printer Host ...");
- $send_gcode = 1;
- } elsif (defined $self->{export_gcode_output_file}) {
- $message = L("G-code file exported to ") . $self->{export_gcode_output_file};
- } else {
- $message = L("Slicing complete");
- }
- }
- $self->{export_gcode_output_file} = undef;
- wxTheApp->notify($message);
-
- $self->do_print if $do_print;
-
- # Send $self->{send_gcode_file} to OctoPrint.
- if ($send_gcode) {
- my $host = Slic3r::PrintHost::get_print_host($self->{config});
- if ($host->send_gcode($self->{send_gcode_file})) {
- $message = L("Upload to host finished.");
- } else {
- $message = "";
- }
- }
-
- # As of now, the BackgroundProcessing thread posts status bar update messages to a queue on the MainFrame.pm,
- # but the "Processing finished" message is posted to this window.
- # Delay the following status bar update, so it will be called later than what is received by MainFrame.pm.
- wxTheApp->CallAfter(sub {
- $self->statusbar->SetStatusText($message);
- });
-
- $self->{print_file} = undef;
- $self->{send_gcode_file} = undef;
- $self->print_info_box_show(1);
-
- # this updates buttons status
- $self->object_list_changed;
-
- # refresh preview
- $self->{preview_iface}->reload_print if $self->{preview_iface};
-# $self->{preview3D}->reload_print if $self->{preview3D};
-}
-
-# XXX: partially done in the Sidebar
-# Fill in the "Sliced info" box with the result of the G-code generator.
-sub print_info_box_show {
- my ($self, $show) = @_;
-# my $scrolled_window_panel = $self->{scrolled_window_panel};
-# my $scrolled_window_sizer = $self->{scrolled_window_sizer};
-# return if (!$show && ($scrolled_window_sizer->IsShown(2) == $show));
- my $panel = $self->{scrolled_window_panel};#$self->{right_panel};
- my $sizer = $self->{info_sizer};
-# return if (!$sizer || !$show && ($sizer->IsShown(1) == $show));
- return if (!$sizer);
-
- Slic3r::GUI::set_show_print_info($show);
-# return if (wxTheApp->{app_config}->get("view_mode") eq "simple");
-
-# if ($show)
- {
- my $print_info_sizer = $self->{print_info_sizer};
- $print_info_sizer->Clear(1);
- my $grid_sizer = Wx::FlexGridSizer->new(2, 2, 5, 5);
- $grid_sizer->SetFlexibleDirection(wxHORIZONTAL);
- $grid_sizer->AddGrowableCol(1, 1);
- $grid_sizer->AddGrowableCol(3, 1);
- $print_info_sizer->Add($grid_sizer, 0, wxEXPAND);
- my $is_wipe_tower = $self->{print}->total_wipe_tower_filament > 0;
- my @info = (
- L("Used Filament (m)")
- => $is_wipe_tower ?
- sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_used_filament / 1000,
- ($self->{print}->total_used_filament - $self->{print}->total_wipe_tower_filament) / 1000,
- L("objects"),
- $self->{print}->total_wipe_tower_filament / 1000,
- L("wipe tower")) :
- sprintf("%.2f" , $self->{print}->total_used_filament / 1000),
-
- L("Used Filament (mm³)")
- => sprintf("%.2f" , $self->{print}->total_extruded_volume),
- L("Used Filament (g)"),
- => sprintf("%.2f" , $self->{print}->total_weight),
- L("Cost"),
- => $is_wipe_tower ?
- sprintf("%.2f (%.2f %s + %.2f %s)" , $self->{print}->total_cost,
- ($self->{print}->total_cost - $self->{print}->total_wipe_tower_cost),
- L("objects"),
- $self->{print}->total_wipe_tower_cost,
- L("wipe tower")) :
- sprintf("%.2f" , $self->{print}->total_cost),
- L("Estimated printing time (normal mode)")
- => $self->{print}->estimated_normal_print_time,
- L("Estimated printing time (silent mode)")
- => $self->{print}->estimated_silent_print_time
- );
- # if there is a wipe tower, insert number of toolchanges info into the array:
- splice (@info, 8, 0, L("Number of tool changes") => sprintf("%.d", $self->{print}->wipe_tower_number_of_toolchanges)) if ($is_wipe_tower);
-
- while ( my $label = shift @info) {
- my $value = shift @info;
- next if $value eq "N/A";
-# my $text = Wx::StaticText->new($scrolled_window_panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
- my $text = Wx::StaticText->new($panel, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_RIGHT);
- $text->SetFont($Slic3r::GUI::small_font);
- $grid_sizer->Add($text, 0);
-# my $field = Wx::StaticText->new($scrolled_window_panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
- my $field = Wx::StaticText->new($panel, -1, $value, wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT);
- $field->SetFont($Slic3r::GUI::small_font);
- $grid_sizer->Add($field, 0);
- }
- }
-
-# $scrolled_window_sizer->Show(2, $show);
-# $scrolled_window_panel->Layout;
- $sizer->Show(1, $show && wxTheApp->{app_config}->get("view_mode") ne "simple");
-
- $self->Layout;
- $panel->Refresh;
-}
-
-# XXX: not done - to be removed
-sub do_print {
- my ($self) = @_;
-
- my $controller = $self->GetFrame->{controller};
- my $printer_preset = wxTheApp->{preset_bundle}->printer->get_edited_preset;
- 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 };
- $printer_panel->load_print_job($self->{print_file}, $filament_stats);
-}
-
-# XXX: VK: done
-sub export_stl {
- my ($self) = @_;
- return if !@{$self->{objects}};
- # Ask user for a file name to write into.
- my $output_file = $self->_get_export_file('STL') or return;
- # Store a binary STL.
- $self->{model}->store_stl($output_file, 1);
- $self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
-}
-
-# XXX: VK: done
-sub reload_from_disk {
- my ($self) = @_;
-
- my ($obj_idx, $object) = $self->selected_object;
- 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 Slic3r::encode_path($model_object->input_file);
-
- my @new_obj_idx = $self->load_files([$model_object->input_file]);
- return if !@new_obj_idx;
-
- foreach my $new_obj_idx (@new_obj_idx) {
- 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);
-}
-
-# XXX: VK: integrated into Plater::export_stl()
-sub export_object_stl {
- my ($self) = @_;
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
- my $model_object = $self->{model}->objects->[$obj_idx];
- # Ask user for a file name to write into.
- my $output_file = $self->_get_export_file('STL') or return;
- $model_object->mesh->write_binary($output_file);
- $self->statusbar->SetStatusText(L("STL file exported to ").$output_file);
-}
-
-# XXX: not done
-sub fix_through_netfabb {
- my ($self) = @_;
- my ($obj_idx, $object) = $self->selected_object;
- return if !defined $obj_idx;
- my $model_object = $self->{model}->objects->[$obj_idx];
- my $model_fixed = Slic3r::Model->new;
- Slic3r::GUI::fix_model_by_win10_sdk_gui($model_object, $self->{print}, $model_fixed);
-
- my @new_obj_idx = $self->load_model_objects(@{$model_fixed->objects});
- return if !@new_obj_idx;
-
- foreach my $new_obj_idx (@new_obj_idx) {
- 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);
-}
-
-# XXX: VK: done
-sub export_amf {
- my ($self) = @_;
- return if !@{$self->{objects}};
- # Ask user for a file name to write into.
- my $output_file = $self->_get_export_file('AMF') or return;
- my $res = $self->{model}->store_amf($output_file, $self->{print}, $self->{export_option});
- if ($res)
- {
- $self->statusbar->SetStatusText(L("AMF file exported to ").$output_file);
- }
- else
- {
- $self->statusbar->SetStatusText(L("Error exporting AMF file ").$output_file);
- }
-}
-
-# XXX: VK: done
-sub export_3mf {
- my ($self) = @_;
- return if !@{$self->{objects}};
- # Ask user for a file name to write into.
- my $output_file = $self->_get_export_file('3MF') or return;
- my $res = $self->{model}->store_3mf($output_file, $self->{print}, $self->{export_option});
- if ($res)
- {
- $self->statusbar->SetStatusText(L("3MF file exported to ").$output_file);
- }
- else
- {
- $self->statusbar->SetStatusText(L("Error exporting 3MF file ").$output_file);
- }
-}
-
-# XXX: VK: done
-# Ask user to select an output file for a given file format (STl, AMF, 3MF).
-# Propose a default file name based on the 'output_filename_format' configuration value.
-sub _get_export_file {
- my ($self, $format) = @_;
- my $suffix = '';
- my $wildcard = 'known';
- if ($format eq 'STL')
- {
- $suffix = '.stl';
- $wildcard = 'stl';
- }
- elsif ($format eq 'AMF')
- {
- if (&Wx::wxMAC) {
- # It seems that MacOS does not like double extension
- $suffix = '.amf';
- } else {
- $suffix = '.zip.amf';
- }
- $wildcard = 'amf';
- }
- elsif ($format eq '3MF')
- {
- $suffix = '.3mf';
- $wildcard = 'threemf';
- }
- # Copy the names of active presets into the placeholder parser.
- wxTheApp->{preset_bundle}->export_selections_pp($self->{print}->placeholder_parser);
- 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, L("Save ").$format.L(" file as:"), dirname($output_file),
- basename($output_file), &Slic3r::GUI::FILE_WILDCARDS->{$wildcard}, wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
- Slic3r::GUI::add_export_option($dlg, $format);
- if ($dlg->ShowModal != wxID_OK) {
- $dlg->Destroy;
- return undef;
- }
- $output_file = $dlg->GetPath;
- $self->{export_option} = Slic3r::GUI::get_export_option($dlg);
- $dlg->Destroy;
- return $output_file;
-}
-
-#sub reset_thumbnail {
-# my ($self, $obj_idx) = @_;
-# $self->{objects}[$obj_idx]->thumbnail(undef);
-#}
-
-# XXX: VK: done
-# this method gets called whenever print center is changed or the objects' bounding box changes
-# (i.e. when an object is added/removed/moved/rotated/scaled)
-sub update {
- my ($self, $force_autocenter) = @_;
- $self->Freeze;
- if (wxTheApp->{app_config}->get("autocenter") || $force_autocenter) {
- $self->{model}->center_instances_around_point($self->bed_centerf);
- }
- $self->stop_background_process;
- $self->{print}->reload_model_instances();
- $self->{canvas}->reload_scene if $self->{canvas};
-# $self->{canvas}->reload_scene if $self->{canvas};
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
- $self->{preview_iface}->reset_gcode_preview_data if $self->{preview_iface};
- $self->{preview_iface}->reload_print if $self->{preview_iface};
-# $self->{preview3D}->reset_gcode_preview_data if $self->{preview3D};
-# $self->{preview3D}->reload_print if $self->{preview3D};
- $self->schedule_background_process;
- $self->Thaw;
-}
-
-# XXX: YS: done
-# When a printer technology is changed, the UI needs to be updated to show/hide needed preset combo boxes.
-sub show_preset_comboboxes{
- my ($self, $showSLA) = @_; #if showSLA is oposite value to "ptFFF"
-
- my $choices = $self->{preset_choosers}{filament};
- my $print_filament_ctrls_cnt = 2 + 2 * ($#$choices+1);
-
- foreach (0..$print_filament_ctrls_cnt-1){
- $self->{presets_sizer}->Show($_, !$showSLA);
- }
- $self->{presets_sizer}->Show($print_filament_ctrls_cnt , $showSLA);
- $self->{presets_sizer}->Show($print_filament_ctrls_cnt+1, $showSLA);
-
- $self->{frequently_changed_parameters_sizer}->Show(0,!$showSLA);
-
- $self->Layout;
-}
-
-# XXX: YS: done
-# When a number of extruders changes, the UI needs to be updated to show a single filament selection combo box per extruder.
-# Also the wxTheApp->{preset_bundle}->filament_presets needs to be resized accordingly
-# and some reasonable default has to be selected for the additional extruders.
-sub on_extruders_change {
- my ($self, $num_extruders) = @_;
- my $choices = $self->{preset_choosers}{filament};
-
- while (int(@$choices) < $num_extruders) {
- # copy strings from first choice
- my @presets = $choices->[0]->GetStrings;
-
- # initialize new choice
-# my $choice = Wx::BitmapComboBox->new($self->{right_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
- my $choice = Wx::BitmapComboBox->new($self->{scrolled_window_panel}, -1, "", wxDefaultPosition, wxDefaultSize, [@presets], wxCB_READONLY);
- my $extruder_idx = scalar @$choices;
- EVT_LEFT_DOWN($choice, sub { $self->filament_color_box_lmouse_down($extruder_idx, @_); } );
- push @$choices, $choice;
- # copy icons from first choice
- $choice->SetItemBitmap($_, $choices->[0]->GetItemBitmap($_)) for 0..$#presets;
- # insert new choice into sizer
- $self->{presets_sizer}->Insert(4 + ($#$choices-1)*2, 0, 0);
- $self->{presets_sizer}->Insert(5 + ($#$choices-1)*2, $choice, 0, wxEXPAND | wxBOTTOM, 0);
- # setup the listener
- EVT_COMBOBOX($choice, $choice, sub {
- my ($choice) = @_;
- wxTheApp->CallAfter(sub {
- $self->_on_select_preset('filament', $choice, $extruder_idx);
- });
- });
- # initialize selection
- wxTheApp->{preset_bundle}->update_platter_filament_ui($extruder_idx, $choice);
- }
-
- # remove unused choices if any
- while (@$choices > $num_extruders) {
- $self->{presets_sizer}->Remove(4 + ($#$choices-1)*2); # label
- $self->{presets_sizer}->Remove(4 + ($#$choices-1)*2); # wxChoice
- $choices->[-1]->Destroy;
- pop @$choices;
- }
- $self->{right_panel}->Layout;
- $self->Layout;
-}
-
-# XXX: not done
-sub on_config_change {
- my ($self, $config) = @_;
-
- my $update_scheduled;
- foreach my $opt_key (@{$self->{config}->diff($config)}) {
- $self->{config}->set($opt_key, $config->get($opt_key));
- if ($opt_key eq 'bed_shape') {
-# $self->{canvas}->update_bed_size;
- Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D};
- $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface});
-# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
- $update_scheduled = 1;
- } elsif ($opt_key =~ '^wipe_tower' || $opt_key eq 'single_extruder_multi_material') {
- $update_scheduled = 1;
- } elsif ($opt_key eq 'serial_port') {
- $self->{btn_print}->Show($config->get('serial_port'));
- $self->Layout;
- } elsif ($opt_key eq 'print_host') {
- $self->{btn_send_gcode}->Show($config->get('print_host'));
- $self->Layout;
- } elsif ($opt_key eq 'variable_layer_height') {
- if ($config->get('variable_layer_height') != 1) {
-# if ($self->{htoolbar}) {
-# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 0);
-# $self->{htoolbar}->ToggleTool(TB_LAYER_EDITING, 0);
-# } else {
-# $self->{"btn_layer_editing"}->Disable;
-# $self->{"btn_layer_editing"}->SetValue(0);
-# }
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 0);
- Slic3r::GUI::_3DScene::enable_layers_editing($self->{canvas3D}, 0);
- $self->{canvas3D}->Refresh;
- $self->{canvas3D}->Update;
- } elsif (Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D})) {
- # Want to allow the layer editing, but do it only if the OpenGL supports it.
-# if ($self->{htoolbar}) {
-# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, 1);
-# } else {
-# $self->{"btn_layer_editing"}->Enable;
-# }
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", 1);
- }
- } elsif ($opt_key eq 'extruder_colour') {
- $update_scheduled = 1;
- my $extruder_colors = $config->get('extruder_colour');
- $self->{preview_iface}->set_number_extruders(scalar(@{$extruder_colors}));
-# $self->{preview3D}->set_number_extruders(scalar(@{$extruder_colors}));
- } elsif ($opt_key eq 'max_print_height') {
- $update_scheduled = 1;
- } elsif ($opt_key eq 'printer_model') {
- # update to force bed selection (for texturing)
- Slic3r::GUI::_3DScene::set_bed_shape($self->{canvas3D}, $self->{config}->bed_shape) if $self->{canvas3D};
- $self->{preview_iface}->set_bed_shape($self->{config}->bed_shape) if ($self->{preview_iface});
-# Slic3r::GUI::_3DScene::set_bed_shape($self->{preview3D}->canvas, $self->{config}->bed_shape) if $self->{preview3D};
- $update_scheduled = 1;
- }
- }
-
- $self->update if $update_scheduled;
-
- return if !$self->GetFrame->is_loaded;
-
- # (re)start timer
- $self->schedule_background_process;
-}
-
-# XXX: YS: WIP
-sub item_changed_selection {
- my ($self, $obj_idx) = @_;
-
- if (($obj_idx >= 0) && ($obj_idx < 1000)) { # skip if wipe tower selected
- if ($self->{canvas3D}) {
- Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D});
- if ($obj_idx >= 0) {
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::update_volumes_selection($self->{canvas3D}, \@$selections);
- }
-# Slic3r::GUI::_3DScene::render($self->{canvas3D});
- }
- }
-}
-
-# XXX: VK: done
-sub collect_selections {
- my ($self) = @_;
- my $selections = [];
- foreach my $o (@{$self->{objects}}) {
- push(@$selections, $o->selected);
- }
- return $selections;
-}
-
-# XXX: YS: done, lambda on LEFT_DOWN
-# Called when clicked on the filament preset combo box.
-# When clicked on the icon, show the color picker.
-sub filament_color_box_lmouse_down
-{
- my ($self, $extruder_idx, $combobox, $event) = @_;
- my $pos = $event->GetLogicalPosition(Wx::ClientDC->new($combobox));
- my( $x, $y ) = ( $pos->x, $pos->y );
- if ($x > 24) {
- # Let the combo box process the mouse click.
- $event->Skip;
- } else {
- # Swallow the mouse click and open the color picker.
- my $data = Wx::ColourData->new;
- $data->SetChooseFull(1);
- my $dialog = Wx::ColourDialog->new($self->GetFrame, $data);
- if ($dialog->ShowModal == wxID_OK) {
- my $cfg = Slic3r::Config->new;
- my $colors = wxTheApp->{preset_bundle}->full_config->get('extruder_colour');
- $colors->[$extruder_idx] = $dialog->GetColourData->GetColour->GetAsString(wxC2S_HTML_SYNTAX);
- $cfg->set('extruder_colour', $colors);
- $self->GetFrame->{options_tabs}{printer}->load_config($cfg);
- wxTheApp->{preset_bundle}->update_platter_filament_ui($extruder_idx, $combobox);
- }
- $dialog->Destroy();
- }
-}
-
-#sub object_cut_dialog {
-# my ($self, $obj_idx) = @_;
-#
-# if (!defined $obj_idx) {
-# ($obj_idx, undef) = $self->selected_object;
-# }
-#
-# if (!$Slic3r::GUI::have_OpenGL) {
-# Slic3r::GUI::show_error($self, L("Please install the OpenGL modules to use this feature (see build instructions)."));
-# return;
-# }
-#
-# my $dlg = Slic3r::GUI::Plater::ObjectCutDialog->new($self,
-# object => $self->{objects}[$obj_idx],
-# model_object => $self->{model}->objects->[$obj_idx],
-# );
-# return unless $dlg->ShowModal == wxID_OK;
-#
-# if (my @new_objects = $dlg->NewModelObjects) {
-# $self->remove($obj_idx);
-# $self->load_model_objects(grep defined($_), @new_objects);
-# $self->arrange;
-# Slic3r::GUI::_3DScene::zoom_to_volumes($self->{canvas3D}) if $self->{canvas3D};
-# }
-#}
-
-# XXX: YS: done
-sub changed_object_settings {
- my ($self, $obj_idx, $parts_changed, $part_settings_changed) = @_;
-
- # update thumbnail since parts may have changed
- if ($parts_changed) {
- # recenter and re-align to Z = 0
- my $model_object = $self->{model}->objects->[$obj_idx];
- $model_object->center_around_origin;
-# $self->reset_thumbnail($obj_idx);
- }
-
- # update print
- if ($parts_changed || $part_settings_changed) {
- $self->stop_background_process;
- $self->{print}->reload_object($obj_idx);
- $self->schedule_background_process;
- $self->{canvas}->reload_scene if $self->{canvas};
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 0);
- } else {
- $self->schedule_background_process;
- }
-}
-
-# XXX: VK: done
-# Called to update various buttons depending on whether there are any objects or
-# whether background processing (export of a G-code, sending to Octoprint, forced background re-slicing) is active.
-sub object_list_changed {
- my $self = shift;
-
- # Enable/disable buttons depending on whether there are any objects on the platter.
- my $have_objects = @{$self->{objects}} ? 1 : 0;
-# if ($self->{htoolbar}) {
-# # On OSX or Linux
-# $self->{htoolbar}->EnableTool($_, $have_objects)
-# for (TB_RESET, TB_ARRANGE);
-# } else {
-# # On MSW
-# my $method = $have_objects ? 'Enable' : 'Disable';
-# $self->{"btn_$_"}->$method
-# for grep $self->{"btn_$_"}, qw(reset arrange reslice export_gcode export_stl print send_gcode);
-# }
-
- for my $toolbar_item (qw(deleteall arrange)) {
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_objects);
- }
-
- my $export_in_progress = $self->{export_gcode_output_file} || $self->{send_gcode_file};
- my $model_fits = $self->{canvas3D} ? Slic3r::GUI::_3DScene::check_volumes_outside_state($self->{canvas3D}, $self->{config}) : 1;
- # $model_fits == 1 -> ModelInstance::PVS_Partly_Outside
- my $method = ($have_objects && ! $export_in_progress && ($model_fits != 1)) ? 'Enable' : 'Disable';
- $self->{"btn_$_"}->$method
- for grep $self->{"btn_$_"}, qw(reslice export_gcode print send_gcode);
-}
-
-# XXX: VK: WIP
-# Selection of an active 3D object changed.
-sub selection_changed {
- my ($self) = @_;
- my ($obj_idx, $object) = $self->selected_object;
- my $have_sel = defined $obj_idx;
- my $layers_height_allowed = $self->{config}->variable_layer_height && Slic3r::GUI::_3DScene::is_layers_editing_allowed($self->{canvas3D}) && $have_sel;
-
- $self->{right_panel}->Freeze;
-# if ($self->{htoolbar}) {
-# # On OSX or Linux
-# $self->{htoolbar}->EnableTool($_, $have_sel)
-# for (TB_REMOVE, TB_MORE, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_CUT, TB_SETTINGS);
-#
-# $self->{htoolbar}->EnableTool(TB_LAYER_EDITING, $layers_height_allowed);
-#
-# if ($have_sel) {
-# my $model_object = $self->{model}->objects->[$obj_idx];
-# $self->{htoolbar}->EnableTool(TB_FEWER, $model_object->instances_count > 1);
-# } else {
-# $self->{htoolbar}->EnableTool(TB_FEWER, 0);
-# }
-#
-# } else {
-# # On MSW
-# my $method = $have_sel ? 'Enable' : 'Disable';
-# $self->{"btn_$_"}->$method
-# for grep $self->{"btn_$_"}, qw(remove increase rotate45cw rotate45ccw changescale split cut settings);
-#
-# if ($layers_height_allowed) {
-# $self->{"btn_layer_editing"}->Enable;
-# } else {
-# $self->{"btn_layer_editing"}->Disable;
-# }
-#
-# if ($have_sel) {
-# my $model_object = $self->{model}->objects->[$obj_idx];
-# if ($model_object->instances_count > 1) {
-# $self->{"btn_decrease"}->Enable;
-# } else {
-# $self->{"btn_decrease"}->Disable;
-# }
-# } else {
-# $self->{"btn_decrease"}->Disable;
-# }
-# }
-
- for my $toolbar_item (qw(delete more fewer split cut settings)) {
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, $toolbar_item, $have_sel);
- }
-
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "layersediting", $layers_height_allowed);
-
- my $can_select_by_parts = 0;
-
- if ($have_sel) {
- my $model_object = $self->{model}->objects->[$obj_idx];
- $can_select_by_parts = ($obj_idx >= 0) && ($obj_idx < 1000) && ($model_object->volumes_count > 1);
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "fewer", $model_object->instances_count > 1);
- }
-
- if ($can_select_by_parts) {
- # first disable to let the item in the toolbar to switch to the unpressed state
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 0);
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 1);
- } else {
- Slic3r::GUI::_3DScene::enable_toolbar_item($self->{canvas3D}, "selectbyparts", 0);
- Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object');
- }
-
- if ($self->{object_info_size}) { # have we already loaded the info pane?
- if ($have_sel) {
- my $model_object = $self->{model}->objects->[$obj_idx];
- #FIXME print_info runs model fixing in two rounds, it is very slow, it should not be performed here!
- # $model_object->print_info;
- my $model_instance = $model_object->instances->[0];
- $self->{object_info_size}->SetLabel(sprintf("%.2f x %.2f x %.2f", @{$model_object->instance_bounding_box(0)->size}));
- $self->{object_info_materials}->SetLabel($model_object->materials_count);
-
- if (my $stats = $model_object->mesh_stats) {
- $self->{object_info_volume}->SetLabel(sprintf('%.2f', $stats->{volume} * ($model_instance->scaling_factor**3)));
- $self->{object_info_facets}->SetLabel(sprintf(L('%d (%d shells)'), $model_object->facets_count, $stats->{number_of_parts}));
- if (my $errors = sum(@$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)})) {
- $self->{object_info_manifold}->SetLabel(sprintf(L("Auto-repaired (%d errors)"), $errors));
- #$self->{object_info_manifold_warning_icon}->Show;
- $self->{"object_info_manifold_warning_icon_show"}->(1);
-
- # we don't show normals_fixed because we never provide normals
- # to admesh, so it generates normals for all facets
- my $message = sprintf L('%d degenerate facets, %d edges fixed, %d facets removed, %d facets added, %d facets reversed, %d backwards edges'),
- @$stats{qw(degenerate_facets edges_fixed facets_removed facets_added facets_reversed backwards_edges)};
- $self->{object_info_manifold}->SetToolTipString($message);
- $self->{object_info_manifold_warning_icon}->SetToolTipString($message);
- } else {
- $self->{object_info_manifold}->SetLabel(L("Yes"));
- #$self->{object_info_manifold_warning_icon}->Hide;
- $self->{"object_info_manifold_warning_icon_show"}->(0);
- $self->{object_info_manifold}->SetToolTipString("");
- $self->{object_info_manifold_warning_icon}->SetToolTipString("");
- }
- } else {
- $self->{object_info_facets}->SetLabel($object->facets);
- }
- } else {
- $self->{"object_info_$_"}->SetLabel("") for qw(size volume facets materials manifold);
- #$self->{object_info_manifold_warning_icon}->Hide;
- $self->{"object_info_manifold_warning_icon_show"}->(0);
- $self->{object_info_manifold}->SetToolTipString("");
- $self->{object_info_manifold_warning_icon}->SetToolTipString("");
- }
- $self->Layout;
- }
-
- # prepagate the event to the frame (a custom Wx event would be cleaner)
- $self->GetFrame->on_plater_selection_changed($have_sel);
- $self->{right_panel}->Thaw;
-}
-
-# XXX: VK: done
-sub select_object {
- my ($self, $obj_idx, $child) = @_;
-
- # remove current selection
- foreach my $o (0..$#{$self->{objects}}) {
- $self->{objects}->[$o]->selected(0);
- }
-
- if (defined $obj_idx) {
- $self->{objects}->[$obj_idx]->selected(1);
- # Select current object in the list on c++ side, if item isn't child
-# if (!defined $child){
-# Slic3r::GUI::select_current_object($obj_idx);} # all selections in the object list is on c++ side
- } else {
- # Unselect all objects in the list on c++ side
-# Slic3r::GUI::unselect_objects(); # all selections in the object list is on c++ side
- }
- $self->selection_changed(1);
-}
-
-# XXX: YS: WIP
-sub select_object_from_cpp {
- my ($self, $obj_idx, $vol_idx) = @_;
-
- # remove current selection
- foreach my $o (0..$#{$self->{objects}}) {
- $self->{objects}->[$o]->selected(0);
- }
-
- my $curr = Slic3r::GUI::_3DScene::get_select_by($self->{canvas3D});
-
- if (defined $obj_idx) {
- if ($vol_idx == -1){
- if ($curr eq 'object') {
- $self->{objects}->[$obj_idx]->selected(1);
- }
- elsif ($curr eq 'volume') {
- Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'object');
- }
-
- my $selections = $self->collect_selections;
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
- }
- else {
- if ($curr eq 'object') {
- Slic3r::GUI::_3DScene::set_select_by($self->{canvas3D}, 'volume');
- }
-
- my $selections = [];
- Slic3r::GUI::_3DScene::set_objects_selections($self->{canvas3D}, \@$selections);
- Slic3r::GUI::_3DScene::deselect_volumes($self->{canvas3D});
- Slic3r::GUI::_3DScene::reload_scene($self->{canvas3D}, 1);
- my $volume_idx = Slic3r::GUI::_3DScene::get_first_volume_id($self->{canvas3D}, $obj_idx);
-
- my $inst_cnt = $self->{model}->objects->[$obj_idx]->instances_count;
- for (0..$inst_cnt-1){
- Slic3r::GUI::_3DScene::select_volume($self->{canvas3D}, $vol_idx*$inst_cnt + $_ + $volume_idx) if ($volume_idx != -1);
- }
- }
- }
-
- $self->selection_changed(1);
-}
-
-# XXX: VK: done
-sub selected_object {
- my ($self) = @_;
- my $obj_idx = first { $self->{objects}[$_]->selected } 0..$#{ $self->{objects} };
- return defined $obj_idx ? ($obj_idx, $self->{objects}[$obj_idx]) : undef;
-}
-
-# XXX: VK: done
-sub statusbar {
- return $_[0]->GetFrame->{statusbar};
-}
-
-# XXX: not done, to be removed (?)
-sub object_menu {
- my ($self) = @_;
-
- my $frame = $self->GetFrame;
- my $menu = Wx::Menu->new;
- my $accel = ($^O eq 'MSWin32') ? sub { $_[0] . "\t\xA0" . $_[1] } : sub { $_[0] };
- $frame->_append_menu_item($menu, $accel->(L('Delete'), 'Del'), L('Remove the selected object'), sub {
- $self->remove;
- }, undef, 'brick_delete.png');
- $frame->_append_menu_item($menu, $accel->(L('Increase copies'), '+'), L('Place one more copy of the selected object'), sub {
- $self->increase;
- }, undef, 'add.png');
- $frame->_append_menu_item($menu, $accel->(L('Decrease copies'), '-'), L('Remove one copy of the selected object'), sub {
- $self->decrease;
- }, undef, 'delete.png');
- $frame->_append_menu_item($menu, L("Set number of copies…"), L('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, $accel->(L('Rotate 45° clockwise'), 'l'), L('Rotate the selected object by 45° clockwise'), sub {
- $self->rotate(-45, Z, 'relative');
- }, undef, 'arrow_rotate_clockwise.png');
- $frame->_append_menu_item($menu, $accel->(L('Rotate 45° counter-clockwise'), 'r'), L('Rotate the selected object by 45° counter-clockwise'), sub {
- $self->rotate(+45, Z, 'relative');
- }, undef, 'arrow_rotate_anticlockwise.png');
-
- my $rotateMenu = Wx::Menu->new;
- my $rotateMenuItem = $menu->AppendSubMenu($rotateMenu, L("Rotate"), L('Rotate the selected object by an arbitrary angle'));
- $frame->_set_menu_item_icon($rotateMenuItem, 'textfield.png');
- $frame->_append_menu_item($rotateMenu, L("Around X axis…"), L('Rotate the selected object by an arbitrary angle around X axis'), sub {
- $self->rotate(undef, X);
- }, undef, 'bullet_red.png');
- $frame->_append_menu_item($rotateMenu, L("Around Y axis…"), L('Rotate the selected object by an arbitrary angle around Y axis'), sub {
- $self->rotate(undef, Y);
- }, undef, 'bullet_green.png');
- $frame->_append_menu_item($rotateMenu, L("Around Z axis…"), L('Rotate the selected object by an arbitrary angle around Z axis'), sub {
- $self->rotate(undef, Z);
- }, undef, 'bullet_blue.png');
-
- my $mirrorMenu = Wx::Menu->new;
- my $mirrorMenuItem = $menu->AppendSubMenu($mirrorMenu, L("Mirror"), L('Mirror the selected object'));
- $frame->_set_menu_item_icon($mirrorMenuItem, 'shape_flip_horizontal.png');
- $frame->_append_menu_item($mirrorMenu, L("Along X axis…"), L('Mirror the selected object along the X axis'), sub {
- $self->mirror(X);
- }, undef, 'bullet_red.png');
- $frame->_append_menu_item($mirrorMenu, L("Along Y axis…"), L('Mirror the selected object along the Y axis'), sub {
- $self->mirror(Y);
- }, undef, 'bullet_green.png');
- $frame->_append_menu_item($mirrorMenu, L("Along Z axis…"), L('Mirror the selected object along the Z axis'), sub {
- $self->mirror(Z);
- }, undef, 'bullet_blue.png');
-
- my $scaleMenu = Wx::Menu->new;
- my $scaleMenuItem = $menu->AppendSubMenu($scaleMenu, L("Scale"), L('Scale the selected object along a single axis'));
- $frame->_set_menu_item_icon($scaleMenuItem, 'arrow_out.png');
- $frame->_append_menu_item($scaleMenu, $accel->(L('Uniformly…'), 's'), L('Scale the selected object along the XYZ axes'), sub {
- $self->changescale(undef);
- });
- $frame->_append_menu_item($scaleMenu, L("Along X axis…"), L('Scale the selected object along the X axis'), sub {
- $self->changescale(X);
- }, undef, 'bullet_red.png');
- $frame->_append_menu_item($scaleMenu, L("Along Y axis…"), L('Scale the selected object along the Y axis'), sub {
- $self->changescale(Y);
- }, undef, 'bullet_green.png');
- $frame->_append_menu_item($scaleMenu, L("Along Z axis…"), L('Scale the selected object along the Z axis'), sub {
- $self->changescale(Z);
- }, undef, 'bullet_blue.png');
-
- my $scaleToSizeMenu = Wx::Menu->new;
- my $scaleToSizeMenuItem = $menu->AppendSubMenu($scaleToSizeMenu, L("Scale to size"), L('Scale the selected object along a single axis'));
- $frame->_set_menu_item_icon($scaleToSizeMenuItem, 'arrow_out.png');
- $frame->_append_menu_item($scaleToSizeMenu, L("Uniformly…"), L('Scale the selected object along the XYZ axes'), sub {
- $self->changescale(undef, 1);
- });
- $frame->_append_menu_item($scaleToSizeMenu, L("Along X axis…"), L('Scale the selected object along the X axis'), sub {
- $self->changescale(X, 1);
- }, undef, 'bullet_red.png');
- $frame->_append_menu_item($scaleToSizeMenu, L("Along Y axis…"), L('Scale the selected object along the Y axis'), sub {
- $self->changescale(Y, 1);
- }, undef, 'bullet_green.png');
- $frame->_append_menu_item($scaleToSizeMenu, L("Along Z axis…"), L('Scale the selected object along the Z axis'), sub {
- $self->changescale(Z, 1);
- }, undef, 'bullet_blue.png');
-
- $frame->_append_menu_item($menu, L("Split"), L('Split the selected object into individual parts'), sub {
- $self->split_object;
- }, undef, 'shape_ungroup.png');
- $frame->_append_menu_item($menu, L("Cut…"), L('Open the 3D cutting tool'), sub {
- $self->object_cut_dialog;
- }, undef, 'package.png');
- $menu->AppendSeparator();
- $frame->_append_menu_item($menu, L("Settings…"), L('Open the object editor dialog'), sub {
- $self->object_settings_dialog;
- }, undef, 'cog.png');
- $menu->AppendSeparator();
- $frame->_append_menu_item($menu, L("Reload from Disk"), L('Reload the selected file from Disk'), sub {
- $self->reload_from_disk;
- }, undef, 'arrow_refresh.png');
- $frame->_append_menu_item($menu, L("Export object as STL…"), L('Export this single object as STL file'), sub {
- $self->export_object_stl;
- }, undef, 'brick_go.png');
- if (Slic3r::GUI::is_windows10) {
- $frame->_append_menu_item($menu, L("Fix STL through Netfabb"), L('Fix the model by sending it to a Netfabb cloud service through Windows 10 API'), sub {
- $self->fix_through_netfabb;
- }, undef, 'brick_go.png');
- }
-
- return $menu;
-}
-
-# XXX: not done
-# Set a camera direction, zoom to all objects.
-sub select_view {
- my ($self, $direction) = @_;
- my $idx_page = $self->{preview_notebook}->GetSelection;
- my $page = ($idx_page == &Wx::wxNOT_FOUND) ? L('3D') : $self->{preview_notebook}->GetPageText($idx_page);
- if ($page eq L('Preview')) {
- $self->{preview_iface}->select_view($direction);
- $self->{preview_iface}->set_viewport_into_scene($self->{canvas3D});
-# Slic3r::GUI::_3DScene::select_view($self->{preview3D}->canvas, $direction);
-# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{canvas3D}, $self->{preview3D}->canvas);
- } else {
- Slic3r::GUI::_3DScene::select_view($self->{canvas3D}, $direction);
- $self->{preview_iface}->set_viewport_from_scene($self->{canvas3D});
-# Slic3r::GUI::_3DScene::set_viewport_from_scene($self->{preview3D}->canvas, $self->{canvas3D});
- }
-}
-
-
-# XXX: VK: done, in PlaterDropTarget
-package Slic3r::GUI::Plater::DropTarget;
-use Wx::DND;
-use base 'Wx::FileDropTarget';
-
-sub new {
- my ($class, $window) = @_;
- my $self = $class->SUPER::new;
- $self->{window} = $window;
- return $self;
-}
-
-sub OnDropFiles {
- my ($self, $x, $y, $filenames) = @_;
- # stop scalars leaking on older perl
- # https://rt.perl.org/rt3/Public/Bug/Display.html?id=70602
- @_ = ();
- # only accept STL, OBJ, AMF, 3MF and PRUSA files
- return 0 if grep !/\.(?:[sS][tT][lL]|[oO][bB][jJ]|[aA][mM][fF]|[3][mM][fF]|[aA][mM][fF].[xX][mM][lL]|[zZ][iI][pP].[aA][mM][lL]|[pP][rR][uU][sS][aA])$/, @$filenames;
- $self->{window}->load_files($filenames);
-}
-
-# 2D preview of an object. Each object is previewed by its convex hull.
-package Slic3r::GUI::Plater::Object;
-use Moo;
-
-has 'name' => (is => 'rw', required => 1);
-has 'selected' => (is => 'rw', default => sub { 0 });
-
-1;
diff --git a/lib/Slic3r/GUI/Plater/3D.pm b/lib/Slic3r/GUI/Plater/3D.pm
deleted file mode 100644
index 0b770b31cb..0000000000
--- a/lib/Slic3r/GUI/Plater/3D.pm
+++ /dev/null
@@ -1,26 +0,0 @@
-package Slic3r::GUI::Plater::3D;
-use strict;
-use warnings;
-use utf8;
-
-use List::Util qw();
-use Wx qw(:misc :pen :brush :sizer :font :cursor :keycode wxTAB_TRAVERSAL);
-use base qw(Slic3r::GUI::3DScene Class::Accessor);
-
-sub new {
- my $class = shift;
- my ($parent, $objects, $model, $print, $config) = @_;
-
- my $self = $class->SUPER::new($parent);
- Slic3r::GUI::_3DScene::enable_picking($self, 1);
- Slic3r::GUI::_3DScene::enable_moving($self, 1);
- Slic3r::GUI::_3DScene::set_select_by($self, 'object');
- Slic3r::GUI::_3DScene::set_drag_by($self, 'instance');
- Slic3r::GUI::_3DScene::set_model($self, $model);
- Slic3r::GUI::_3DScene::set_print($self, $print);
- Slic3r::GUI::_3DScene::set_config($self, $config);
-
- return $self;
-}
-
-1;
diff --git a/lib/Slic3r/GUI/Plater/3DPreview.pm b/lib/Slic3r/GUI/Plater/3DPreview.pm
deleted file mode 100644
index 06d1a798b5..0000000000
--- a/lib/Slic3r/GUI/Plater/3DPreview.pm
+++ /dev/null
@@ -1,555 +0,0 @@
-package Slic3r::GUI::Plater::3DPreview;
-use strict;
-use warnings;
-use utf8;
-
-use Slic3r::Print::State ':steps';
-use Wx qw(:misc :sizer :slider :statictext :keycode wxWHITE wxCB_READONLY);
-use Wx::Event qw(EVT_SLIDER EVT_KEY_DOWN EVT_CHECKBOX EVT_CHOICE EVT_CHECKLISTBOX EVT_SIZE);
-use base qw(Wx::Panel Class::Accessor);
-
-use Wx::Locale gettext => 'L';
-
-__PACKAGE__->mk_accessors(qw(print gcode_preview_data enabled _loaded canvas slider_low slider_high single_layer double_slider_sizer));
-
-sub new {
- my $class = shift;
- my ($parent, $print, $gcode_preview_data, $config) = @_;
-
- my $self = $class->SUPER::new($parent, -1, wxDefaultPosition);
- $self->{config} = $config;
- $self->{number_extruders} = 1;
- # Show by feature type by default.
- $self->{preferred_color_mode} = 'feature';
-
- # init GUI elements
- my $canvas = Slic3r::GUI::3DScene->new($self);
- Slic3r::GUI::_3DScene::enable_shader($canvas, 1);
- Slic3r::GUI::_3DScene::set_config($canvas, $config);
- $self->canvas($canvas);
-# my $slider_low = Wx::Slider->new(
-# $self, -1,
-# 0, # default
-# 0, # min
- # we set max to a bogus non-zero value because the MSW implementation of wxSlider
- # will skip drawing the slider if max <= min:
-# 1, # max
-# wxDefaultPosition,
-# wxDefaultSize,
-# wxVERTICAL | wxSL_INVERSE,
-# );
-# $self->slider_low($slider_low);
-# my $slider_high = Wx::Slider->new(
-# $self, -1,
-# 0, # default
-# 0, # min
- # we set max to a bogus non-zero value because the MSW implementation of wxSlider
- # will skip drawing the slider if max <= min:
-# 1, # max
-# wxDefaultPosition,
-# wxDefaultSize,
-# wxVERTICAL | wxSL_INVERSE,
-# );
-# $self->slider_high($slider_high);
-
-# my $z_label_low = $self->{z_label_low} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-# $z_label_low->SetFont($Slic3r::GUI::small_font);
-# my $z_label_high = $self->{z_label_high} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-# $z_label_high->SetFont($Slic3r::GUI::small_font);
-
-# my $z_label_low_idx = $self->{z_label_low_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-# $z_label_low_idx->SetFont($Slic3r::GUI::small_font);
-# my $z_label_high_idx = $self->{z_label_high_idx} = Wx::StaticText->new($self, -1, "", wxDefaultPosition,
-# [40,-1], wxALIGN_CENTRE_HORIZONTAL);
-# $z_label_high_idx->SetFont($Slic3r::GUI::small_font);
-
-# $self->single_layer(0);
-# my $checkbox_singlelayer = $self->{checkbox_singlelayer} = Wx::CheckBox->new($self, -1, L("1 Layer"));
-
- my $label_view_type = $self->{label_view_type} = Wx::StaticText->new($self, -1, L("View"));
-
- my $choice_view_type = $self->{choice_view_type} = Wx::Choice->new($self, -1);
- $choice_view_type->Append(L("Feature type"));
- $choice_view_type->Append(L("Height"));
- $choice_view_type->Append(L("Width"));
- $choice_view_type->Append(L("Speed"));
- $choice_view_type->Append(L("Volumetric flow rate"));
- $choice_view_type->Append(L("Tool"));
- $choice_view_type->SetSelection(0);
-
- # the following value needs to be changed if new items are added into $choice_view_type before "Tool"
- $self->{tool_idx} = 5;
-
- my $label_show_features = $self->{label_show_features} = Wx::StaticText->new($self, -1, L("Show"));
-
- my $combochecklist_features = $self->{combochecklist_features} = Wx::ComboCtrl->new();
- $combochecklist_features->Create($self, -1, L("Feature types"), wxDefaultPosition, [200, -1], wxCB_READONLY);
- my $feature_text = L("Feature types");
- my $feature_items = L("Perimeter")."|"
- .L("External perimeter")."|"
- .L("Overhang perimeter")."|"
- .L("Internal infill")."|"
- .L("Solid infill")."|"
- .L("Top solid infill")."|"
- .L("Bridge infill")."|"
- .L("Gap fill")."|"
- .L("Skirt")."|"
- .L("Support material")."|"
- .L("Support material interface")."|"
- .L("Wipe tower")."|"
- .L("Custom");
- Slic3r::GUI::create_combochecklist($combochecklist_features, $feature_text, $feature_items, 1);
-
- my $double_slider_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
- Slic3r::GUI::create_double_slider($self, $double_slider_sizer, $self->canvas);
- $self->double_slider_sizer($double_slider_sizer);
-
- my $checkbox_travel = $self->{checkbox_travel} = Wx::CheckBox->new($self, -1, L("Travel"));
- my $checkbox_retractions = $self->{checkbox_retractions} = Wx::CheckBox->new($self, -1, L("Retractions"));
- my $checkbox_unretractions = $self->{checkbox_unretractions} = Wx::CheckBox->new($self, -1, L("Unretractions"));
- my $checkbox_shells = $self->{checkbox_shells} = Wx::CheckBox->new($self, -1, L("Shells"));
-
-# my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL);
-# my $vsizer = Wx::BoxSizer->new(wxVERTICAL);
-# my $vsizer_outer = Wx::BoxSizer->new(wxVERTICAL);
-# $vsizer->Add($slider_low, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-# $vsizer->Add($z_label_low_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-# $vsizer->Add($z_label_low, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-# $hsizer->Add($vsizer, 0, wxEXPAND, 0);
-# $vsizer = Wx::BoxSizer->new(wxVERTICAL);
-# $vsizer->Add($slider_high, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-# $vsizer->Add($z_label_high_idx, 0, wxALIGN_CENTER_HORIZONTAL, 0);
-# $vsizer->Add($z_label_high, 0, 0, 0);
-# $hsizer->Add($vsizer, 0, wxEXPAND, 0);
-# $vsizer_outer->Add($hsizer, 3, wxALIGN_CENTER_HORIZONTAL, 0);
-# $vsizer_outer->Add($double_slider_sizer, 3, wxEXPAND, 0);
-# $vsizer_outer->Add($checkbox_singlelayer, 0, wxTOP | wxALIGN_CENTER_HORIZONTAL, 5);
-
- my $bottom_sizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $bottom_sizer->Add($label_view_type, 0, wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->Add($choice_view_type, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->AddSpacer(10);
- $bottom_sizer->Add($label_show_features, 0, wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->Add($combochecklist_features, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->AddSpacer(20);
- $bottom_sizer->Add($checkbox_travel, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->AddSpacer(10);
- $bottom_sizer->Add($checkbox_retractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->AddSpacer(10);
- $bottom_sizer->Add($checkbox_unretractions, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
- $bottom_sizer->AddSpacer(10);
- $bottom_sizer->Add($checkbox_shells, 0, wxEXPAND | wxALL | wxALIGN_CENTER_VERTICAL, 5);
-
- my $sizer = Wx::BoxSizer->new(wxHORIZONTAL);
- $sizer->Add($canvas, 1, wxALL | wxEXPAND, 0);
-# $sizer->Add($vsizer_outer, 0, wxTOP | wxBOTTOM | wxEXPAND, 5);
- $sizer->Add($double_slider_sizer, 0, wxEXPAND, 0);#wxTOP | wxBOTTOM | wxEXPAND, 5);
-
- my $main_sizer = Wx::BoxSizer->new(wxVERTICAL);
- $main_sizer->Add($sizer, 1, wxALL | wxEXPAND, 0);
- $main_sizer->Add($bottom_sizer, 0, wxALL | wxEXPAND, 0);
-
-# EVT_SLIDER($self, $slider_low, sub {
-# $slider_high->SetValue($slider_low->GetValue) if $self->single_layer;
-# $self->set_z_idx_low ($slider_low ->GetValue)
-# });
-# EVT_SLIDER($self, $slider_high, sub {
-# $slider_low->SetValue($slider_high->GetValue) if $self->single_layer;
-# $self->set_z_idx_high($slider_high->GetValue)
-# });
-# EVT_KEY_DOWN($canvas, sub {
-# my ($s, $event) = @_;
-# Slic3r::GUI::update_double_slider_from_canvas($event);
-# my $key = $event->GetKeyCode;
-# if ($event->HasModifiers) {
-# $event->Skip;
-# } else {
-# if ($key == ord('U')) {
-# $slider_high->SetValue($slider_high->GetValue + 1);
-# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
-# $self->set_z_idx_high($slider_high->GetValue);
-# } elsif ($key == ord('D')) {
-# $slider_high->SetValue($slider_high->GetValue - 1);
-# $slider_low->SetValue($slider_high->GetValue) if ($event->ShiftDown());
-# $self->set_z_idx_high($slider_high->GetValue);
-# } elsif ($key == ord('S')) {
-# $checkbox_singlelayer->SetValue(! $checkbox_singlelayer->GetValue());
-# $self->single_layer($checkbox_singlelayer->GetValue());
-# if ($self->single_layer) {
-# $slider_low->SetValue($slider_high->GetValue);
-# $self->set_z_idx_high($slider_high->GetValue);
-# }
-# } else {
-# $event->Skip;
-# }
-# }
-# });
-# EVT_KEY_DOWN($slider_low, sub {
-# my ($s, $event) = @_;
-# my $key = $event->GetKeyCode;
-# if ($event->HasModifiers) {
-# $event->Skip;
-# } else {
-# if ($key == WXK_LEFT) {
-# } elsif ($key == WXK_RIGHT) {
-# $slider_high->SetFocus;
-# } else {
-# $event->Skip;
-# }
-# }
-# });
-# EVT_KEY_DOWN($slider_high, sub {
-# my ($s, $event) = @_;
-# my $key = $event->GetKeyCode;
-# if ($event->HasModifiers) {
-# $event->Skip;
-# } else {
-# if ($key == WXK_LEFT) {
-# $slider_low->SetFocus;
-# } elsif ($key == WXK_RIGHT) {
-# } else {
-# $event->Skip;
-# }
-# }
-# });
-# EVT_CHECKBOX($self, $checkbox_singlelayer, sub {
-# $self->single_layer($checkbox_singlelayer->GetValue());
-# if ($self->single_layer) {
-# $slider_low->SetValue($slider_high->GetValue);
-# $self->set_z_idx_high($slider_high->GetValue);
-# }
-# });
- EVT_CHOICE($self, $choice_view_type, sub {
- my $selection = $choice_view_type->GetCurrentSelection();
- $self->{preferred_color_mode} = ($selection == $self->{tool_idx}) ? 'tool' : 'feature';
- $self->gcode_preview_data->set_type($selection);
- $self->reload_print;
- });
- EVT_CHECKLISTBOX($self, $combochecklist_features, sub {
- my $flags = Slic3r::GUI::combochecklist_get_flags($combochecklist_features);
-
- $self->gcode_preview_data->set_extrusion_flags($flags);
- $self->refresh_print;
- });
- EVT_CHECKBOX($self, $checkbox_travel, sub {
- $self->gcode_preview_data->set_travel_visible($checkbox_travel->IsChecked());
- $self->refresh_print;
- });
- EVT_CHECKBOX($self, $checkbox_retractions, sub {
- $self->gcode_preview_data->set_retractions_visible($checkbox_retractions->IsChecked());
- $self->refresh_print;
- });
- EVT_CHECKBOX($self, $checkbox_unretractions, sub {
- $self->gcode_preview_data->set_unretractions_visible($checkbox_unretractions->IsChecked());
- $self->refresh_print;
- });
- EVT_CHECKBOX($self, $checkbox_shells, sub {
- $self->gcode_preview_data->set_shells_visible($checkbox_shells->IsChecked());
- $self->refresh_print;
- });
-
- EVT_SIZE($self, sub {
- my ($s, $event) = @_;
- $event->Skip;
- $self->Refresh;
- });
-
- $self->SetSizer($main_sizer);
- $self->SetMinSize($self->GetSize);
- $sizer->SetSizeHints($self);
-
- # init canvas
- $self->print($print);
- $self->gcode_preview_data($gcode_preview_data);
-
- # sets colors for gcode preview extrusion roles
- my @extrusion_roles_colors = (
- 'Perimeter' => 'FFFF66',
- 'External perimeter' => 'FFA500',
- 'Overhang perimeter' => '0000FF',
- 'Internal infill' => 'B1302A',
- 'Solid infill' => 'D732D7',
- 'Top solid infill' => 'FF1A1A',
- 'Bridge infill' => '9999FF',
- 'Gap fill' => 'FFFFFF',
- 'Skirt' => '845321',
- 'Support material' => '00FF00',
- 'Support material interface' => '008000',
- 'Wipe tower' => 'B3E3AB',
- 'Custom' => '28CC94',
- );
- $self->gcode_preview_data->set_extrusion_paths_colors(\@extrusion_roles_colors);
-
- $self->show_hide_ui_elements('none');
- $self->reload_print;
-
- return $self;
-}
-
-sub reload_print {
- my ($self, $force) = @_;
-
- Slic3r::GUI::_3DScene::reset_volumes($self->canvas);
- $self->_loaded(0);
-
- if (! $self->IsShown && ! $force) {
-# $self->{reload_delayed} = 1;
- return;
- }
-
- $self->load_print;
-}
-
-sub refresh_print {
- my ($self) = @_;
-
- $self->_loaded(0);
-
- if (! $self->IsShown) {
- return;
- }
-
- $self->load_print;
-}
-
-sub reset_gcode_preview_data {
- my ($self) = @_;
- $self->gcode_preview_data->reset;
- Slic3r::GUI::_3DScene::reset_legend_texture();
-}
-
-sub load_print {
- my ($self) = @_;
-
- return if $self->_loaded;
-
- # we require that there's at least one object and the posSlice step
- # is performed on all of them (this ensures that _shifted_copies was
- # populated and we know the number of layers)
- my $n_layers = 0;
- if ($self->print->object_step_done(STEP_SLICE)) {
- my %z = (); # z => 1
- foreach my $object (@{$self->{print}->objects}) {
- foreach my $layer (@{$object->layers}, @{$object->support_layers}) {
- $z{$layer->print_z} = 1;
- }
- }
- $self->{layers_z} = [ sort { $a <=> $b } keys %z ];
- $n_layers = scalar(@{$self->{layers_z}});
- }
-
- if ($n_layers == 0) {
- $self->reset_sliders;
- Slic3r::GUI::_3DScene::reset_legend_texture();
- $self->canvas->Refresh; # clears canvas
- return;
- }
-
- if ($self->{preferred_color_mode} eq 'tool_or_feature') {
- # It is left to Slic3r to decide whether the print shall be colored by the tool or by the feature.
- # Color by feature if it is a single extruder print.
- my $extruders = $self->{print}->extruders;
- my $type = (scalar(@{$extruders}) > 1) ? $self->{tool_idx} : 0;
- $self->gcode_preview_data->set_type($type);
- $self->{choice_view_type}->SetSelection($type);
- # If the ->SetSelection changed the following line, revert it to "decide yourself".
- $self->{preferred_color_mode} = 'tool_or_feature';
- }
-
- # Collect colors per extruder.
- my @colors = ();
- if (! $self->gcode_preview_data->empty() || $self->gcode_preview_data->type == $self->{tool_idx}) {
- my @extruder_colors = @{$self->{config}->extruder_colour};
- my @filament_colors = @{$self->{config}->filament_colour};
- for (my $i = 0; $i <= $#extruder_colors; $i += 1) {
- my $color = $extruder_colors[$i];
- $color = $filament_colors[$i] if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/);
- $color = '#FFFFFF' if (! defined($color) || $color !~ m/^#[[:xdigit:]]{6}/);
- push @colors, $color;
- }
- }
-
- if ($self->IsShown) {
- # used to set the sliders to the extremes of the current zs range
- $self->{force_sliders_full_range} = 0;
-
- if ($self->gcode_preview_data->empty) {
- # load skirt and brim
- Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
- Slic3r::GUI::_3DScene::load_preview($self->canvas, \@colors);
- $self->show_hide_ui_elements('simple');
- } else {
- $self->{force_sliders_full_range} = (Slic3r::GUI::_3DScene::get_volumes_count($self->canvas) == 0);
- Slic3r::GUI::_3DScene::set_print($self->canvas, $self->print);
- Slic3r::GUI::_3DScene::load_gcode_preview($self->canvas, $self->gcode_preview_data, \@colors);
- $self->show_hide_ui_elements('full');
-
- # recalculates zs and update sliders accordingly
- $self->{layers_z} = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 1);
- $n_layers = scalar(@{$self->{layers_z}});
- if ($n_layers == 0) {
- # all layers filtered out
- $self->reset_sliders;
- $self->canvas->Refresh; # clears canvas
- }
- }
-
- $self->update_sliders($n_layers) if ($n_layers > 0);
- $self->_loaded(1);
- }
-}
-
-sub reset_sliders {
- my ($self) = @_;
- $self->enabled(0);
-# $self->set_z_range(0,0);
-# $self->slider_low->Hide;
-# $self->slider_high->Hide;
-# $self->{z_label_low}->SetLabel("");
-# $self->{z_label_high}->SetLabel("");
-# $self->{z_label_low_idx}->SetLabel("");
-# $self->{z_label_high_idx}->SetLabel("");
-
- Slic3r::GUI::reset_double_slider();
- $self->double_slider_sizer->Hide(0);
-}
-
-sub update_sliders
-{
- my ($self, $n_layers) = @_;
-
-# my $z_idx_low = $self->slider_low->GetValue;
-# my $z_idx_high = $self->slider_high->GetValue;
- $self->enabled(1);
-# $self->slider_low->SetRange(0, $n_layers - 1);
-# $self->slider_high->SetRange(0, $n_layers - 1);
-
-# if ($self->{force_sliders_full_range}) {
-# $z_idx_low = 0;
-# $z_idx_high = $n_layers - 1;
-# } elsif ($z_idx_high < $n_layers && ($self->single_layer || $z_idx_high != 0)) {
-# # search new indices for nearest z (size of $self->{layers_z} may change in dependence of what is shown)
-# if (defined($self->{z_low})) {
-# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
-# if ($self->{layers_z}[$i] <= $self->{z_low}) {
-# $z_idx_low = $i;
-# last;
-# }
-# }
-# }
-# if (defined($self->{z_high})) {
-# for (my $i = scalar(@{$self->{layers_z}}) - 1; $i >= 0; $i -= 1) {
-# if ($self->{layers_z}[$i] <= $self->{z_high}) {
-# $z_idx_high = $i;
-# last;
-# }
-# }
-# }
-# } elsif ($z_idx_high >= $n_layers) {
-# # Out of range. Disable 'single layer' view.
-# $self->single_layer(0);
-# $self->{checkbox_singlelayer}->SetValue(0);
-# $z_idx_low = 0;
-# $z_idx_high = $n_layers - 1;
-# } else {
-# $z_idx_low = 0;
-# $z_idx_high = $n_layers - 1;
-# }
-
-# $self->slider_low->SetValue($z_idx_low);
-# $self->slider_high->SetValue($z_idx_high);
-# $self->slider_low->Show;
-# $self->slider_high->Show;
-# $self->set_z_range($self->{layers_z}[$z_idx_low], $self->{layers_z}[$z_idx_high]);
-
- Slic3r::GUI::update_double_slider($self->{force_sliders_full_range});
- $self->double_slider_sizer->Show(0);
-
- $self->Layout;
-}
-
-sub set_z_range
-{
- my ($self, $z_low, $z_high) = @_;
-
- return if !$self->enabled;
- $self->{z_low} = $z_low;
- $self->{z_high} = $z_high;
- $self->{z_label_low}->SetLabel(sprintf '%.2f', $z_low);
- $self->{z_label_high}->SetLabel(sprintf '%.2f', $z_high);
-
- my $layers_z = Slic3r::GUI::_3DScene::get_current_print_zs($self->canvas, 0);
- for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
- if (($z_low - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_low + 1e-6)) {
- $self->{z_label_low_idx}->SetLabel(sprintf '%d', $i + 1);
- last;
- }
- }
- for (my $i = 0; $i < scalar(@{$layers_z}); $i += 1) {
- if (($z_high - 1e-6 < @{$layers_z}[$i]) && (@{$layers_z}[$i] < $z_high + 1e-6)) {
- $self->{z_label_high_idx}->SetLabel(sprintf '%d', $i + 1);
- last;
- }
- }
-
- Slic3r::GUI::_3DScene::set_toolpaths_range($self->canvas, $z_low - 1e-6, $z_high + 1e-6);
- $self->canvas->Refresh if $self->IsShown;
-}
-
-sub set_z_idx_low
-{
- my ($self, $idx_low) = @_;
- if ($self->enabled) {
- my $idx_high = $self->slider_high->GetValue;
- if ($idx_low >= $idx_high) {
- $idx_high = $idx_low;
- $self->slider_high->SetValue($idx_high);
- }
- $self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]);
- }
-}
-
-sub set_z_idx_high
-{
- my ($self, $idx_high) = @_;
- if ($self->enabled) {
- my $idx_low = $self->slider_low->GetValue;
- if ($idx_low > $idx_high) {
- $idx_low = $idx_high;
- $self->slider_low->SetValue($idx_low);
- }
- $self->set_z_range($self->{layers_z}[$idx_low], $self->{layers_z}[$idx_high]);
- }
-}
-
-sub set_number_extruders {
- my ($self, $number_extruders) = @_;
- if ($self->{number_extruders} != $number_extruders) {
- $self->{number_extruders} = $number_extruders;
- my $type = ($number_extruders > 1) ?
- $self->{tool_idx} # color by a tool number
- : 0; # color by a feature type
- $self->{choice_view_type}->SetSelection($type);
- $self->gcode_preview_data->set_type($type);
- $self->{preferred_color_mode} = ($type == $self->{tool_idx}) ? 'tool_or_feature' : 'feature';
- }
-}
-
-sub show_hide_ui_elements {
- my ($self, $what) = @_;
- my $method = ($what eq 'full') ? 'Enable' : 'Disable';
- $self->{$_}->$method for qw(label_show_features combochecklist_features checkbox_travel checkbox_retractions checkbox_unretractions checkbox_shells);
- $method = ($what eq 'none') ? 'Disable' : 'Enable';
- $self->{$_}->$method for qw(label_view_type choice_view_type);
-}
-
-# Called by the Platter wxNotebook when this page is activated.
-sub OnActivate {
-# my ($self) = @_;
-# $self->reload_print(1) if ($self->{reload_delayed});
-}
-
-1;
diff --git a/resources/fonts/NotoSans-hinted.zip b/resources/fonts/NotoSans-hinted.zip
deleted file mode 100644
index 861c1be8c4..0000000000
Binary files a/resources/fonts/NotoSans-hinted.zip and /dev/null differ
diff --git a/resources/icons/bed/mk2.svg b/resources/icons/bed/mk2.svg
new file mode 100644
index 0000000000..b8fa8d0cd7
--- /dev/null
+++ b/resources/icons/bed/mk2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/bed/mk3.svg b/resources/icons/bed/mk3.svg
new file mode 100644
index 0000000000..c8f53373b5
--- /dev/null
+++ b/resources/icons/bed/mk3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/icons/bed/sl1.svg b/resources/icons/bed/sl1.svg
new file mode 100644
index 0000000000..c1098b9df8
--- /dev/null
+++ b/resources/icons/bed/sl1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/resources/localization/uk/Slic3rPE.mo b/resources/localization/uk/Slic3rPE.mo
index 56af728d6e..08bf555b58 100644
Binary files a/resources/localization/uk/Slic3rPE.mo and b/resources/localization/uk/Slic3rPE.mo differ
diff --git a/resources/localization/uk/Slic3rPE_uk.po b/resources/localization/uk/Slic3rPE_uk.po
index 9db2b919af..7880453bba 100644
--- a/resources/localization/uk/Slic3rPE_uk.po
+++ b/resources/localization/uk/Slic3rPE_uk.po
@@ -3,7 +3,7 @@ msgstr ""
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-01-17 13:39+0100\n"
-"PO-Revision-Date: 2019-01-21 11:25+0100\n"
+"PO-Revision-Date: 2019-02-19 14:42+0100\n"
"Last-Translator: Oleksandra Iushchenko \n"
"Language-Team: \n"
"Language: uk\n"
@@ -624,48 +624,48 @@ msgstr ""
#: src/slic3r/GUI/GLGizmo.cpp:2207
msgid "Left mouse click - add point"
-msgstr ""
+msgstr "Ліва кнопка миші - додати точку"
#: src/slic3r/GUI/GLGizmo.cpp:2208
msgid "Right mouse click - remove point"
-msgstr ""
+msgstr "Права кнопка миші - видалити точку"
#: src/slic3r/GUI/GLGizmo.cpp:2211
msgid "Generate points automatically"
-msgstr ""
+msgstr "Генерувати точки автоматично"
#: src/slic3r/GUI/GLGizmo.cpp:2212
msgid "Remove all points"
-msgstr ""
+msgstr "Видалити всі точки"
#: src/slic3r/GUI/GLGizmo.cpp:2245
msgid "SLA Support Points"
-msgstr ""
+msgstr "Точки SLA підтримки"
#: src/slic3r/GUI/GLGizmo.cpp:2268 src/slic3r/GUI/GLGizmo.cpp:2468
msgid "Rotate lower part upwards"
-msgstr ""
+msgstr "Повернути нижню частину вгору"
#: src/slic3r/GUI/GLGizmo.cpp:2269 src/slic3r/GUI/GLGizmo.cpp:2470
msgid "Perform cut"
-msgstr ""
+msgstr "Виконати розріз"
#: src/slic3r/GUI/GLGizmo.cpp:2276
msgid "Cut object:"
-msgstr ""
+msgstr "Розрізати об'єкт:"
#: src/slic3r/GUI/GLGizmo.cpp:2356 src/slic3r/GUI/GLGizmo.cpp:2461
#: src/libslic3r/PrintConfig.cpp:3016
msgid "Cut"
-msgstr ""
+msgstr "Розрізати"
#: src/slic3r/GUI/GLGizmo.cpp:2466
msgid "Keep upper part"
-msgstr ""
+msgstr "Залишити верхню частину"
#: src/slic3r/GUI/GLGizmo.cpp:2467
msgid "Keep lower part"
-msgstr ""
+msgstr "Залишити нижню частину"
#: src/slic3r/GUI/GUI.cpp:242
msgid "Notice"
@@ -5636,7 +5636,7 @@ msgstr ""
#: src/libslic3r/PrintConfig.cpp:3017
msgid "Cut model at the given Z."
-msgstr ""
+msgstr "Розрізати модель за заданим Z."
#: src/libslic3r/PrintConfig.cpp:3022
msgid "Dont arrange"
diff --git a/resources/profiles/PrusaResearch.idx b/resources/profiles/PrusaResearch.idx
index a8d169c684..407883544a 100644
--- a/resources/profiles/PrusaResearch.idx
+++ b/resources/profiles/PrusaResearch.idx
@@ -1,8 +1,15 @@
+min_slic3r_version = 1.42.0-alpha6
+0.8.0-alpha7
+0.8.0-alpha6
min_slic3r_version = 1.42.0-alpha
+0.8.0-alpha
0.4.0-alpha4 Updated SLA profiles
0.4.0-alpha3 Update of SLA profiles
0.4.0-alpha2 First SLA profiles
+min_slic3r_version = 1.41.3-alpha
+0.4.0 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
min_slic3r_version = 1.41.1
+0.3.4 Changelog: https://github.com/prusa3d/Slic3r-settings/blob/master/live/PrusaResearch/changelog.txt
0.3.3 Prusament PETG released
0.3.2 New MK2.5 and MK3 FW versions
0.3.1 New MK2.5 and MK3 FW versions
@@ -34,6 +41,7 @@ min_slic3r_version = 1.41.0-alpha
0.2.0-alpha1 added initial profiles for the i3 MK3 Multi Material Upgrade 2.0
0.2.0-alpha moved machine limits from the start G-code to the new print profile parameters
min_slic3r_version = 1.40.0
+0.1.12 New MK2.5 and MK3 FW versions
0.1.11 fw version changed to 3.3.1
0.1.10 MK3 jerk and acceleration update
0.1.9 edited support extrusion width for 0.25 and 0.6 nozzles
diff --git a/resources/profiles/PrusaResearch.ini b/resources/profiles/PrusaResearch.ini
index 306867044b..a471700fb8 100644
--- a/resources/profiles/PrusaResearch.ini
+++ b/resources/profiles/PrusaResearch.ini
@@ -1,1694 +1,2034 @@
-# Print profiles for the Prusa Research printers.
-
-[vendor]
-# Vendor name will be shown by the Config Wizard.
-name = Prusa Research
-# Configuration version of this file. Config file will only be installed, if the config_version differs.
-# This means, the server may force the Slic3r configuration to be downgraded.
-config_version = 0.4.0-alpha4
-# Where to get the updates from?
-config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
-
-# The printer models will be shown by the Configuration Wizard in this order,
-# also the first model installed & the first nozzle installed will be activated after install.
-#TODO: One day we may differentiate variants of the nozzles / hot ends,
-#for example by the melt zone size, or whether the nozzle is hardened.
-# Printer model name will be shown by the installation wizard.
-
-[printer_model:MK3]
-name = Original Prusa i3 MK3
-variants = 0.4; 0.25; 0.6
-technology = FFF
-
-[printer_model:MK2.5]
-name = Original Prusa i3 MK2.5
-variants = 0.4; 0.25; 0.6
-technology = FFF
-
-[printer_model:MK2S]
-name = Original Prusa i3 MK2/S
-variants = 0.4; 0.25; 0.6
-technology = FFF
-
-[printer_model:MK3MMU2]
-name = Original Prusa i3 MK3 MMU 2.0
-variants = 0.4
-technology = FFF
-
-[printer_model:MK2SMM]
-name = Original Prusa i3 MK2/S MMU 1.0
-variants = 0.4; 0.6
-technology = FFF
-
-[printer_model:MK2.5MMU2]
-name = Original Prusa i3 MK2.5 MMU 2.0
-variants = 0.4
-technology = FFF
-
-[printer_model:SL1]
-name = Original Prusa SL1
-variants = default
-technology = SLA
-
-# All presets starting with asterisk, for example *common*, are intermediate and they will
-# not make it into the user interface.
-
-# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle.
-# All other print presets will derive from the *common* print preset.
-[print:*common*]
-avoid_crossing_perimeters = 0
-bridge_acceleration = 1000
-bridge_angle = 0
-bridge_flow_ratio = 0.8
-bridge_speed = 20
-brim_width = 0
-clip_multipart_objects = 1
-compatible_printers =
-complete_objects = 0
-default_acceleration = 1000
-dont_support_bridges = 1
-elefant_foot_compensation = 0
-ensure_vertical_shell_thickness = 1
-external_fill_pattern = rectilinear
-external_perimeters_first = 0
-external_perimeter_extrusion_width = 0.45
-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 = 20
-gap_fill_speed = 40
-gcode_comments = 0
-infill_every_layers = 1
-infill_extruder = 1
-infill_extrusion_width = 0.45
-infill_first = 0
-infill_only_where_needed = 0
-infill_overlap = 25%
-interface_shells = 0
-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 =
-overhangs = 0
-only_retract_when_crossing_perimeters = 0
-ooze_prevention = 0
-output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}.gcode
-perimeters = 2
-perimeter_extruder = 1
-perimeter_extrusion_width = 0.45
-post_process =
-print_settings_id =
-raft_layers = 0
-resolution = 0
-seam_position = nearest
-single_extruder_multi_material_priming = 1
-skirts = 1
-skirt_distance = 2
-skirt_height = 3
-small_perimeter_speed = 25
-solid_infill_below_area = 0
-solid_infill_every_layers = 0
-solid_infill_extruder = 1
-solid_infill_extrusion_width = 0.45
-spiral_vase = 0
-standby_temperature_delta = -5
-support_material = 0
-support_material_extruder = 0
-support_material_extrusion_width = 0.35
-support_material_interface_extruder = 0
-support_material_angle = 0
-support_material_buildplate_only = 0
-support_material_enforce_layers = 0
-support_material_contact_distance = 0.1
-support_material_interface_contact_loops = 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 = 55
-support_material_with_sheath = 0
-support_material_xy_spacing = 50%
-thin_walls = 0
-top_infill_extrusion_width = 0.45
-top_solid_infill_speed = 40
-travel_speed = 180
-wipe_tower = 1
-wipe_tower_bridging = 10
-wipe_tower_rotation_angle = 0
-wipe_tower_width = 60
-wipe_tower_x = 170
-wipe_tower_y = 140
-xy_size_compensation = 0
-
-[print:*MK3*]
-fill_pattern = grid
-single_extruder_multi_material_priming = 0
-travel_speed = 180
-wipe_tower_x = 170
-wipe_tower_y = 125
-
-# Print parameters common to a 0.25mm diameter nozzle.
-[print:*0.25nozzle*]
-external_perimeter_extrusion_width = 0.25
-extrusion_width = 0.25
-first_layer_extrusion_width = 0.25
-infill_extrusion_width = 0.25
-perimeter_extrusion_width = 0.25
-solid_infill_extrusion_width = 0.25
-top_infill_extrusion_width = 0.25
-support_material_extrusion_width = 0.2
-support_material_interface_layers = 0
-support_material_interface_spacing = 0.15
-support_material_spacing = 1
-support_material_xy_spacing = 150%
-
-# Print parameters common to a 0.6mm diameter nozzle.
-[print:*0.6nozzle*]
-external_perimeter_extrusion_width = 0.61
-extrusion_width = 0.67
-first_layer_extrusion_width = 0.65
-infill_extrusion_width = 0.7
-perimeter_extrusion_width = 0.65
-solid_infill_extrusion_width = 0.65
-top_infill_extrusion_width = 0.6
-support_material_extrusion_width = 0.55
-
-[print:*soluble_support*]
-overhangs = 1
-skirts = 0
-support_material = 1
-support_material_contact_distance = 0
-support_material_extruder = 4
-support_material_extrusion_width = 0.45
-support_material_interface_extruder = 4
-support_material_interface_spacing = 0.1
-support_material_synchronize_layers = 1
-support_material_threshold = 80
-support_material_with_sheath = 1
-
-# XXXXXXXXXXXXXXXXXXXX
-# XXX--- 0.05mm ---XXX
-# XXXXXXXXXXXXXXXXXXXX
-
-[print:*0.05mm*]
-inherits = *common*
-bottom_solid_layers = 10
-bridge_acceleration = 300
-bridge_flow_ratio = 0.7
-default_acceleration = 500
-external_perimeter_speed = 20
-fill_density = 20%
-first_layer_acceleration = 500
-gap_fill_speed = 20
-infill_acceleration = 800
-infill_speed = 30
-max_print_speed = 80
-small_perimeter_speed = 20
-solid_infill_speed = 30
-support_material_extrusion_width = 0.3
-support_material_spacing = 1.5
-layer_height = 0.05
-perimeter_acceleration = 300
-perimeter_speed = 30
-perimeters = 3
-support_material_speed = 30
-top_solid_infill_speed = 20
-top_solid_layers = 15
-
-[print:0.05mm ULTRADETAIL]
-inherits = *0.05mm*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
-infill_extrusion_width = 0.5
-
-[print:0.05mm ULTRADETAIL MK3]
-inherits = *0.05mm*; *MK3*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
-top_infill_extrusion_width = 0.4
-
-[print:0.05mm ULTRADETAIL 0.25 nozzle]
-inherits = *0.05mm*; *0.25nozzle*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
-fill_density = 20%
-infill_speed = 20
-max_print_speed = 100
-perimeter_speed = 20
-small_perimeter_speed = 15
-solid_infill_speed = 20
-support_material_speed = 20
-
-[print:0.05mm ULTRADETAIL 0.25 nozzle MK3]
-inherits = *0.05mm*; *0.25nozzle*; *MK3*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
-
-# XXXXXXXXXXXXXXXXXXXX
-# XXX--- 0.10mm ---XXX
-# XXXXXXXXXXXXXXXXXXXX
-
-[print:*0.10mm*]
-inherits = *common*
-bottom_solid_layers = 7
-bridge_flow_ratio = 0.7
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
-layer_height = 0.1
-perimeter_acceleration = 800
-top_solid_layers = 9
-
-[print:0.10mm DETAIL]
-inherits = *0.10mm*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
-external_perimeter_speed = 40
-infill_acceleration = 2000
-infill_speed = 60
-perimeter_speed = 50
-solid_infill_speed = 50
-
-[print:0.10mm DETAIL MK3]
-inherits = *0.10mm*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_infill_extrusion_width = 0.4
-top_solid_infill_speed = 50
-
-[print:0.10mm DETAIL 0.25 nozzle]
-inherits = *0.10mm*; *0.25nozzle*
-bridge_acceleration = 600
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25
-external_perimeter_speed = 20
-infill_acceleration = 1600
-infill_speed = 40
-perimeter_acceleration = 600
-perimeter_speed = 25
-small_perimeter_speed = 15
-solid_infill_speed = 40
-top_solid_infill_speed = 30
-
-[print:0.10mm DETAIL 0.25 nozzle MK3]
-inherits = *0.10mm*; *0.25nozzle*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-[print:0.10mm DETAIL 0.6 nozzle MK3]
-inherits = *0.10mm*; *0.6nozzle*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-# XXXXXXXXXXXXXXXXXXXX
-# XXX--- 0.15mm ---XXX
-# XXXXXXXXXXXXXXXXXXXX
-
-[print:*0.15mm*]
-inherits = *common*
-bottom_solid_layers = 5
-external_perimeter_speed = 40
-infill_acceleration = 2000
-infill_speed = 60
-layer_height = 0.15
-perimeter_acceleration = 800
-perimeter_speed = 50
-solid_infill_speed = 50
-top_infill_extrusion_width = 0.4
-top_solid_layers = 7
-
-[print:0.15mm 100mms Linear Advance]
-inherits = *0.15mm*
-bridge_flow_ratio = 0.95
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
-external_perimeter_speed = 50
-infill_speed = 100
-max_print_speed = 150
-perimeter_speed = 60
-small_perimeter_speed = 30
-solid_infill_speed = 100
-support_material_speed = 60
-top_solid_infill_speed = 70
-
-[print:0.15mm OPTIMAL]
-inherits = *0.15mm*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
-top_infill_extrusion_width = 0.45
-
-[print:0.15mm OPTIMAL 0.25 nozzle]
-inherits = *0.15mm*; *0.25nozzle*
-bridge_acceleration = 600
-bridge_flow_ratio = 0.7
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25
-external_perimeter_speed = 20
-infill_acceleration = 1600
-infill_speed = 40
-perimeter_acceleration = 600
-perimeter_speed = 25
-small_perimeter_speed = 15
-solid_infill_speed = 40
-top_solid_infill_speed = 30
-
-[print:0.15mm OPTIMAL 0.6 nozzle]
-inherits = *0.15mm*; *0.6nozzle*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
-
-[print:0.15mm OPTIMAL MK3]
-inherits = *0.15mm*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-[print:0.15mm OPTIMAL MK3 SOLUBLE FULL]
-inherits = 0.15mm OPTIMAL MK3; *soluble_support*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
-support_material_extruder = 5
-support_material_interface_extruder = 5
-perimeter_speed = 40
-solid_infill_speed = 40
-top_infill_extrusion_width = 0.45
-top_solid_infill_speed = 30
-
-[print:0.15mm OPTIMAL MK3 SOLUBLE INTERFACE]
-inherits = 0.15mm OPTIMAL MK3 SOLUBLE FULL
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
-support_material_extruder = 0
-support_material_interface_layers = 3
-support_material_with_sheath = 0
-
-[print:0.15mm OPTIMAL SOLUBLE FULL]
-inherits = *0.15mm*; *soluble_support*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-external_perimeter_speed = 25
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
-perimeter_speed = 40
-solid_infill_speed = 40
-top_infill_extrusion_width = 0.45
-top_solid_infill_speed = 30
-
-[print:0.15mm OPTIMAL SOLUBLE INTERFACE]
-inherits = 0.15mm OPTIMAL SOLUBLE FULL
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
-support_material_extruder = 0
-support_material_interface_layers = 3
-support_material_with_sheath = 0
-support_material_xy_spacing = 80%
-
-[print:0.15mm OPTIMAL 0.25 nozzle MK3]
-inherits = *0.15mm*; *0.25nozzle*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-[print:*0.20mm*]
-inherits = *common*
-bottom_solid_layers = 4
-bridge_flow_ratio = 0.95
-external_perimeter_speed = 40
-infill_acceleration = 2000
-infill_speed = 60
-layer_height = 0.2
-perimeter_acceleration = 800
-perimeter_speed = 50
-solid_infill_speed = 50
-top_infill_extrusion_width = 0.4
-top_solid_layers = 5
-
-[print:0.15mm OPTIMAL 0.6 nozzle MK3]
-inherits = *0.15mm*; *0.6nozzle*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-# XXXXXXXXXXXXXXXXXXXX
-# XXX--- 0.20mm ---XXX
-# XXXXXXXXXXXXXXXXXXXX
-
-[print:0.20mm 100mms Linear Advance]
-inherits = *0.20mm*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
-external_perimeter_speed = 50
-infill_speed = 100
-max_print_speed = 150
-perimeter_speed = 60
-small_perimeter_speed = 30
-solid_infill_speed = 100
-support_material_speed = 60
-top_solid_infill_speed = 70
-
-[print:0.20mm FAST MK3]
-inherits = *0.20mm*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-[print:0.20mm FAST MK3 SOLUBLE FULL]
-inherits = 0.20mm FAST MK3; *soluble_support*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
-support_material_extruder = 5
-support_material_interface_extruder = 5
-perimeter_speed = 40
-solid_infill_speed = 40
-top_infill_extrusion_width = 0.45
-top_solid_infill_speed = 30
-
-[print:0.20mm FAST MK3 SOLUBLE INTERFACE]
-inherits = 0.20mm FAST MK3 SOLUBLE FULL
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
-support_material_extruder = 0
-support_material_interface_layers = 3
-support_material_with_sheath = 0
-
-[print:0.20mm NORMAL]
-inherits = *0.20mm*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
-
-[print:0.20mm NORMAL 0.6 nozzle]
-inherits = *0.20mm*; *0.6nozzle*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
-
-[print:0.20mm NORMAL SOLUBLE FULL]
-inherits = *0.20mm*; *soluble_support*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-external_perimeter_speed = 30
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
-perimeter_speed = 40
-solid_infill_speed = 40
-top_solid_infill_speed = 30
-
-[print:0.20mm NORMAL SOLUBLE INTERFACE]
-inherits = 0.20mm NORMAL SOLUBLE FULL
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
-support_material_extruder = 0
-support_material_interface_layers = 3
-support_material_with_sheath = 0
-support_material_xy_spacing = 80%
-
-[print:0.20mm FAST 0.6 nozzle MK3]
-inherits = *0.20mm*; *0.6nozzle*; *MK3*
-bridge_speed = 30
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
-external_perimeter_speed = 35
-infill_acceleration = 1250
-infill_speed = 200
-max_print_speed = 200
-perimeter_speed = 45
-solid_infill_speed = 200
-top_solid_infill_speed = 50
-
-# XXXXXXXXXXXXXXXXXXXX
-# XXX--- 0.35mm ---XXX
-# XXXXXXXXXXXXXXXXXXXX
-
-[print:*0.35mm*]
-inherits = *common*
-bottom_solid_layers = 3
-external_perimeter_extrusion_width = 0.6
-external_perimeter_speed = 40
-first_layer_extrusion_width = 0.75
-infill_acceleration = 2000
-infill_speed = 60
-layer_height = 0.35
-perimeter_acceleration = 800
-perimeter_extrusion_width = 0.65
-perimeter_speed = 50
-solid_infill_extrusion_width = 0.65
-solid_infill_speed = 60
-top_solid_infill_speed = 50
-top_solid_layers = 4
-
-[print:0.35mm FAST]
-inherits = *0.35mm*
-bridge_flow_ratio = 0.95
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
-first_layer_extrusion_width = 0.42
-perimeter_extrusion_width = 0.43
-solid_infill_extrusion_width = 0.7
-top_infill_extrusion_width = 0.43
-
-[print:0.35mm FAST 0.6 nozzle]
-inherits = *0.35mm*; *0.6nozzle*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
-
-[print:0.35mm FAST sol full 0.6 nozzle]
-inherits = *0.35mm*; *0.6nozzle*; *soluble_support*
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1
-external_perimeter_extrusion_width = 0.6
-external_perimeter_speed = 30
-notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
-perimeter_speed = 40
-support_material_interface_layers = 3
-support_material_xy_spacing = 120%
-top_infill_extrusion_width = 0.57
-
-[print:0.35mm FAST sol int 0.6 nozzle]
-inherits = 0.35mm FAST sol full 0.6 nozzle
-support_material_extruder = 0
-support_material_interface_layers = 2
-support_material_with_sheath = 0
-support_material_xy_spacing = 150%
-
-# XXXXXXXXXXXXXXXXXXXXXX
-# XXX----- MK2.5 ----XXX
-# XXXXXXXXXXXXXXXXXXXXXX
-
-[print:0.15mm 100mms Linear Advance MK2.5]
-inherits = 0.15mm 100mms Linear Advance
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
-single_extruder_multi_material_priming = 0
-
-[print:0.15mm OPTIMAL MK2.5]
-inherits = 0.15mm OPTIMAL
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
-single_extruder_multi_material_priming = 0
-
-[print:0.15mm OPTIMAL SOLUBLE FULL MK2.5]
-inherits = 0.15mm OPTIMAL SOLUBLE FULL
-support_material_extruder = 5
-support_material_interface_extruder = 5
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-
-[print:0.15mm OPTIMAL SOLUBLE INTERFACE MK2.5]
-inherits = 0.15mm OPTIMAL SOLUBLE INTERFACE
-support_material_extruder = 0
-support_material_interface_extruder = 5
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-
-[print:0.20mm 100mms Linear Advance MK2.5]
-inherits = 0.20mm 100mms Linear Advance
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
-single_extruder_multi_material_priming = 0
-
-[print:0.20mm NORMAL MK2.5]
-inherits = 0.20mm NORMAL
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
-single_extruder_multi_material_priming = 0
-
-[print:0.20mm NORMAL SOLUBLE FULL MK2.5]
-inherits = 0.20mm NORMAL SOLUBLE FULL
-support_material_extruder = 5
-support_material_interface_extruder = 5
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-single_extruder_multi_material_priming = 0
-
-[print:0.20mm NORMAL SOLUBLE INTERFACE MK2.5]
-inherits = 0.20mm NORMAL SOLUBLE INTERFACE
-support_material_extruder = 0
-support_material_interface_extruder = 5
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
-single_extruder_multi_material_priming = 0
-
-[print:0.35mm FAST MK2.5]
-inherits = 0.35mm FAST
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
-single_extruder_multi_material_priming = 0
-
-# XXXXXXxxXXXXXXXXXXXXXX
-# XXX--- filament ---XXX
-# XXXXXXXXxxXXXXXXXXXXXX
-
-[filament:*common*]
-cooling = 1
-compatible_printers =
-# For now, all but selected filaments are disabled for the MMU 2.0
-compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
-end_filament_gcode = "; Filament-specific end gcode"
-extrusion_multiplier = 1
-filament_loading_speed = 28
-filament_loading_speed_start = 3
-filament_unloading_speed = 90
-filament_unloading_speed_start = 100
-filament_toolchange_delay = 0
-filament_cooling_moves = 4
-filament_cooling_initial_speed = 2.2
-filament_cooling_final_speed = 3.4
-filament_load_time = 0
-filament_unload_time = 0
-filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_minimal_purge_on_wipe_tower = 15
-filament_cost = 0
-filament_density = 0
-filament_diameter = 1.75
-filament_notes = ""
-filament_settings_id = ""
-filament_soluble = 0
-min_print_speed = 15
-slowdown_below_layer_time = 20
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
-
-[filament:*PLA*]
-inherits = *common*
-bed_temperature = 60
-bridge_fan_speed = 100
-disable_fan_first_layers = 1
-fan_always_on = 1
-fan_below_layer_time = 100
-filament_colour = #FF3232
-filament_max_volumetric_speed = 15
-filament_type = PLA
-first_layer_bed_temperature = 60
-first_layer_temperature = 215
-max_fan_speed = 100
-min_fan_speed = 100
-temperature = 210
-
-[filament:*PET*]
-inherits = *common*
-bed_temperature = 90
-bridge_fan_speed = 50
-disable_fan_first_layers = 3
-fan_always_on = 1
-fan_below_layer_time = 20
-filament_colour = #FF8000
-filament_max_volumetric_speed = 8
-filament_type = PET
-first_layer_bed_temperature = 85
-first_layer_temperature = 230
-max_fan_speed = 50
-min_fan_speed = 30
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
-temperature = 240
-
-[filament:*ABS*]
-inherits = *common*
-bed_temperature = 110
-bridge_fan_speed = 30
-cooling = 0
-disable_fan_first_layers = 3
-fan_always_on = 0
-fan_below_layer_time = 20
-filament_colour = #3A80CA
-filament_max_volumetric_speed = 11
-filament_ramming_parameters = "120 100 5.70968 6.03226 7 8.25806 9 9.19355 9.3871 9.77419 10.129 10.3226 10.4516 10.5161| 0.05 5.69677 0.45 6.15484 0.95 8.76774 1.45 9.20323 1.95 9.95806 2.45 10.3871 2.95 10.5677 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_type = ABS
-first_layer_bed_temperature = 100
-first_layer_temperature = 255
-max_fan_speed = 30
-min_fan_speed = 20
-temperature = 255
-
-[filament:*FLEX*]
-inherits = *common*
-bed_temperature = 50
-bridge_fan_speed = 100
-# For now, all but selected filaments are disabled for the MMU 2.0
-compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
-cooling = 0
-disable_fan_first_layers = 1
-extrusion_multiplier = 1.2
-fan_always_on = 0
-fan_below_layer_time = 100
-filament_colour = #00CA0A
-filament_max_volumetric_speed = 1.5
-filament_type = FLEX
-first_layer_bed_temperature = 50
-first_layer_temperature = 240
-max_fan_speed = 90
-min_fan_speed = 70
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 240
-
-[filament:ColorFabb Brass Bronze]
-inherits = *PLA*
-# For now, all but selected filaments are disabled for the MMU 2.0
-compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
-extrusion_multiplier = 1.2
-filament_cost = 80.65
-filament_density = 4
-filament_colour = #804040
-filament_max_volumetric_speed = 10
-
-[filament:ColorFabb HT]
-inherits = *PET*
-bed_temperature = 110
-bridge_fan_speed = 30
-cooling = 1
-disable_fan_first_layers = 3
-fan_always_on = 0
-fan_below_layer_time = 10
-filament_cost = 58.66
-filament_density = 1.18
-first_layer_bed_temperature = 105
-first_layer_temperature = 270
-max_fan_speed = 20
-min_fan_speed = 10
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
-temperature = 270
-
-[filament:ColorFabb PLA-PHA]
-inherits = *PLA*
-filament_cost = 55.5
-filament_density = 1.24
-
-[filament:ColorFabb Woodfil]
-inherits = *PLA*
-# For now, all but selected filaments are disabled for the MMU 2.0
-compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
-extrusion_multiplier = 1.2
-filament_cost = 62.9
-filament_density = 1.15
-filament_colour = #804040
-filament_max_volumetric_speed = 10
-first_layer_temperature = 200
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 200
-
-[filament:ColorFabb XT]
-inherits = *PET*
-filament_type = PET
-filament_cost = 62.9
-filament_density = 1.27
-first_layer_bed_temperature = 90
-first_layer_temperature = 260
-temperature = 270
-
-[filament:ColorFabb XT-CF20]
-inherits = *PET*
-compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
-extrusion_multiplier = 1.2
-filament_cost = 80.65
-filament_density = 1.35
-filament_colour = #804040
-filament_max_volumetric_speed = 1
-first_layer_bed_temperature = 90
-first_layer_temperature = 260
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
-temperature = 260
-
-[filament:ColorFabb nGen]
-inherits = *PET*
-filament_cost = 21.2
-filament_density = 1.2
-bridge_fan_speed = 40
-fan_always_on = 0
-fan_below_layer_time = 10
-filament_type = NGEN
-first_layer_temperature = 240
-max_fan_speed = 35
-min_fan_speed = 20
-
-[filament:ColorFabb nGen flex]
-inherits = *FLEX*
-filament_cost = 0
-filament_density = 1
-bed_temperature = 85
-bridge_fan_speed = 40
-cooling = 1
-disable_fan_first_layers = 3
-extrusion_multiplier = 1
-fan_below_layer_time = 10
-filament_max_volumetric_speed = 5
-first_layer_bed_temperature = 85
-first_layer_temperature = 260
-max_fan_speed = 35
-min_fan_speed = 20
-temperature = 260
-
-[filament:E3D Edge]
-inherits = *PET*
-filament_cost = 56.9
-filament_density = 1.26
-filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
-
-[filament:E3D PC-ABS]
-inherits = *ABS*
-filament_cost = 0
-filament_density = 1.05
-first_layer_temperature = 270
-temperature = 270
-
-[filament:Fillamentum ABS]
-inherits = *ABS*
-filament_cost = 32.4
-filament_density = 1.04
-first_layer_temperature = 240
-temperature = 240
-
-[filament:Fillamentum ASA]
-inherits = *ABS*
-filament_cost = 38.7
-filament_density = 1.04
-fan_always_on = 1
-first_layer_temperature = 265
-temperature = 265
-
-[filament:Fillamentum CPE HG100 HM100]
-inherits = *PET*
-filament_cost = 54.1
-filament_density = 1.25
-filament_notes = "CPE HG100 , CPE HM100"
-first_layer_bed_temperature = 90
-first_layer_temperature = 275
-max_fan_speed = 50
-min_fan_speed = 50
-temperature = 275
-
-[filament:Fillamentum Timberfil]
-inherits = *PLA*
-# For now, all but selected filaments are disabled for the MMU 2.0
-compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
-extrusion_multiplier = 1.2
-filament_cost = 68
-filament_density = 1.15
-filament_colour = #804040
-filament_max_volumetric_speed = 10
-first_layer_temperature = 190
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 190
-
-[filament:Generic ABS]
-inherits = *ABS*
-filament_cost = 27.82
-filament_density = 1.04
-filament_notes = "List of materials tested with standart ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS"
-
-[filament:Generic PET]
-inherits = *PET*
-filament_cost = 27.82
-filament_density = 1.27
-filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
-
-[filament:Generic PLA]
-inherits = *PLA*
-filament_cost = 25.4
-filament_density = 1.24
-filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
-
-[filament:Polymaker PC-Max]
-inherits = *ABS*
-filament_cost = 77.3
-filament_density = 1.20
-bed_temperature = 115
-filament_colour = #3A80CA
-first_layer_bed_temperature = 100
-first_layer_temperature = 270
-temperature = 270
-
-[filament:Primavalue PVA]
-inherits = *PLA*
-filament_cost = 108
-filament_density = 1.23
-cooling = 0
-fan_always_on = 0
-filament_colour = #FFFFD7
-filament_max_volumetric_speed = 10
-filament_notes = "List of materials tested with standart PVA print settings:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH"
-filament_ramming_parameters = "120 100 8.3871 8.6129 8.93548 9.22581 9.48387 9.70968 9.87097 10.0323 10.2258 10.4194 10.6452 10.8065| 0.05 8.34193 0.45 8.73548 0.95 9.34836 1.45 9.78385 1.95 10.0871 2.45 10.5161 2.95 10.8903 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_soluble = 1
-filament_type = PVA
-first_layer_temperature = 195
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 195
-
-[filament:Prusa ABS]
-inherits = *ABS*
-filament_cost = 27.82
-filament_density = 1.08
-filament_notes = "List of materials tested with standart ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS"
-
-[filament:*ABS MMU2*]
-inherits = Prusa ABS
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
-filament_cooling_final_speed = 50
-filament_cooling_initial_speed = 10
-filament_cooling_moves = 5
-filament_ramming_parameters = "120 110 5.32258 5.45161 5.67742 6 6.48387 7.12903 7.90323 8.70968 9.3871 9.83871 10.0968 10.2258| 0.05 5.30967 0.45 5.50967 0.95 6.1871 1.45 7.39677 1.95 9.05484 2.45 10 2.95 10.3098 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6";
-
-[filament:Generic ABS MMU2]
-inherits = *ABS MMU2*
-
-[filament:Prusa ABS MMU2]
-inherits = *ABS MMU2*
-
-[filament:Prusa HIPS]
-inherits = *ABS*
-filament_cost = 27.3
-filament_density = 1.04
-bridge_fan_speed = 50
-cooling = 1
-extrusion_multiplier = 0.9
-fan_always_on = 1
-fan_below_layer_time = 10
-filament_colour = #FFFFD7
-filament_soluble = 1
-filament_type = HIPS
-first_layer_temperature = 220
-max_fan_speed = 20
-min_fan_speed = 20
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 220
-
-[filament:Prusa PET]
-inherits = *PET*
-filament_cost = 27.82
-filament_density = 1.27
-filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
-
-[filament:Prusament PETG]
-inherits = *PET*
-first_layer_temperature = 240
-temperature = 250
-filament_cost = 24.99
-filament_density = 1.27
-
-[filament:*PET MMU2*]
-inherits = Prusa PET
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
-temperature = 230
-first_layer_temperature = 230
-filament_cooling_final_speed = 1
-filament_cooling_initial_speed = 2
-filament_cooling_moves = 1
-filament_load_time = 12
-filament_loading_speed = 14
-filament_notes = PET
-filament_ramming_parameters = "120 140 4.70968 4.74194 4.77419 4.80645 4.83871 4.87097 4.90323 5 5.25806 5.67742 6.29032 7.06452 7.83871 8.3871| 0.05 4.72901 0.45 4.73545 0.95 4.83226 1.45 4.88067 1.95 5.05483 2.45 5.93553 2.95 7.53556 3.45 8.6323 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_unload_time = 11
-filament_unloading_speed = 20
-filament_unloading_speed_start = 120
-
-[filament:Generic PET MMU2]
-inherits = *PET MMU2*
-
-[filament:Prusa PET MMU2]
-inherits = *PET MMU2*
-
-[filament:Prusament PET MMU2]
-inherits = *PET MMU2*
-
-[filament:Prusa PLA]
-inherits = *PLA*
-filament_cost = 25.4
-filament_density = 1.24
-filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
-
-[filament:Prusament PLA]
-inherits = *PLA*
-temperature = 215
-filament_cost = 24.99
-filament_density = 1.24
-filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa"
-
-[filament:*PLA MMU2*]
-inherits = Prusa PLA
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
-temperature = 205
-filament_cooling_final_speed = 1
-filament_cooling_initial_speed = 2
-filament_cooling_moves = 1
-filament_load_time = 12
-filament_loading_speed = 14
-filament_ramming_parameters = "120 110 2.70968 2.93548 3.32258 3.83871 4.58065 5.54839 6.51613 7.35484 7.93548 8.16129| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 5.97742 1.95 7.69999 2.45 8.1936 2.95 11.342 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_unload_time = 11
-filament_unloading_speed = 20
-
-[filament:Generic PLA MMU2]
-inherits = *PLA MMU2*
-
-[filament:Prusa PLA MMU2]
-inherits = *PLA MMU2*
-
-[filament:Prusament PLA MMU2]
-inherits = *PLA MMU2*
-
-[filament:SemiFlex or Flexfill 98A]
-inherits = *FLEX*
-filament_cost = 82
-filament_density = 1.22
-
-[filament:Taulman Bridge]
-inherits = *common*
-filament_cost = 40
-filament_density = 1.13
-bed_temperature = 90
-bridge_fan_speed = 40
-cooling = 0
-disable_fan_first_layers = 3
-fan_always_on = 0
-fan_below_layer_time = 20
-filament_colour = #DEE0E6
-filament_max_volumetric_speed = 10
-filament_soluble = 0
-filament_type = PET
-first_layer_bed_temperature = 60
-first_layer_temperature = 240
-max_fan_speed = 5
-min_fan_speed = 0
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 250
-
-[filament:Taulman T-Glase]
-inherits = *PET*
-filament_cost = 40
-filament_density = 1.27
-bridge_fan_speed = 40
-cooling = 0
-fan_always_on = 0
-first_layer_bed_temperature = 90
-first_layer_temperature = 240
-max_fan_speed = 5
-min_fan_speed = 0
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
-
-[filament:Verbatim BVOH]
-inherits = *common*
-filament_cost = 218
-filament_density = 1.23
-bed_temperature = 60
-bridge_fan_speed = 100
-cooling = 0
-disable_fan_first_layers = 1
-extrusion_multiplier = 1
-fan_always_on = 0
-fan_below_layer_time = 100
-filament_colour = #FFFFD7
-filament_max_volumetric_speed = 4
-filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
-filament_soluble = 1
-filament_type = PLA
-first_layer_bed_temperature = 60
-first_layer_temperature = 215
-max_fan_speed = 100
-min_fan_speed = 100
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 210
-
-[filament:Verbatim BVOH MMU2]
-inherits = Verbatim BVOH
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
-temperature = 195
-filament_notes = BVOH
-fan_always_on = 1
-first_layer_temperature = 200
-filament_cooling_final_speed = 1
-filament_cooling_initial_speed = 2
-filament_max_volumetric_speed = 4
-filament_type = PVA
-filament_cooling_moves = 1
-filament_load_time = 12
-filament_loading_speed = 14
-filament_ramming_parameters = "120 110 1.74194 1.90323 2.16129 2.48387 2.83871 3.25806 3.83871 4.6129 5.41935 5.96774| 0.05 1.69677 0.45 1.96128 0.95 2.63872 1.45 3.46129 1.95 4.99031 2.45 6.12908 2.95 8.30974 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6"
-filament_unload_time = 11
-filament_unloading_speed = 20
-filament_unloading_speed_start = 100
-
-[filament:Verbatim PP]
-inherits = *common*
-filament_cost = 72
-filament_density = 0.89
-bed_temperature = 100
-bridge_fan_speed = 100
-cooling = 1
-disable_fan_first_layers = 2
-extrusion_multiplier = 1
-fan_always_on = 1
-fan_below_layer_time = 100
-filament_colour = #DEE0E6
-filament_max_volumetric_speed = 5
-filament_notes = "List of materials tested with standart PLA print settings:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA"
-filament_type = PLA
-first_layer_bed_temperature = 100
-first_layer_temperature = 220
-max_fan_speed = 100
-min_fan_speed = 100
-start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
-temperature = 220
-
-[sla_print:*common*]
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
-layer_height = 0.05
-output_filename_format = [input_filename_base].dwz
-pad_edge_radius = 0.5
-pad_enable = 1
-pad_max_merge_distance = 50
-pad_wall_height = 3
-pad_wall_thickness = 1
-support_base_diameter = 3
-support_base_height = 0.5
-support_critical_angle = 45
-support_density_at_45 = 250
-support_density_at_horizontal = 500
-support_head_front_diameter = 0.4
-support_head_penetration = 0.4
-support_head_width = 3
-support_max_bridge_length = 10
-support_minimal_z = 0
-support_object_elevation = 5
-support_pillar_diameter = 1
-support_pillar_widening_factor = 0
-supports_enable = 1
-
-[sla_print:0.025 UltraDetail]
-inherits = *common*
-layer_height = 0.025
-support_head_width = 2
-
-[sla_print:0.035 Detail]
-inherits = *common*
-layer_height = 0.035
-
-[sla_print:0.05 Normal]
-inherits = *common*
-layer_height = 0.05
-
-[sla_print:0.1 Fast]
-inherits = *common*
-layer_height = 0.1
-
-########### Materials 0.025
-
-[sla_material:*common 0.05*]
-compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
-compatible_prints_condition = layer_height == 0.05
-exposure_time = 12
-initial_exposure_time = 45
-initial_layer_height = 0.05
-material_correction_curing = 1,1,1
-material_correction_printing = 1,1,1
-material_notes =
-
-[sla_material:*common 0.025*]
-inherits = *common 0.05*
-compatible_prints_condition = layer_height == 0.025
-exposure_time = 10
-initial_exposure_time = 35
-initial_layer_height = 0.025
-
-[sla_material:*common 0.035*]
-inherits = *common 0.05*
-compatible_prints_condition = layer_height == 0.035
-exposure_time = 13
-initial_exposure_time = 40
-initial_layer_height = 0.035
-
-[sla_material:*common 0.1*]
-inherits = *common 0.05*
-compatible_prints_condition = layer_height == 0.1
-exposure_time = 20
-initial_exposure_time = 90
-initial_layer_height = 0.1
-
-########### Materials 0.025
-
-[sla_material:Bluecast Phrozen Wax 0.025]
-inherits = *common 0.025*
-exposure_time = 8
-initial_exposure_time = 45
-
-[sla_material:Jamg He PJHC-30 Orange 0.025]
-inherits = *common 0.025*
-exposure_time = 5
-initial_exposure_time = 35
-
-########### Materials 0.05
-
-[sla_material:3DM-HTR140 (high temperature) 0.05]
-inherits = *common 0.05*
-exposure_time = 12
-initial_exposure_time = 45
-
-[sla_material:Bluecast Ecogray 0.05]
-inherits = *common 0.05*
-exposure_time = 8
-initial_exposure_time = 45
-
-[sla_material:Bluecast Keramaster 0.05]
-inherits = *common 0.05*
-exposure_time = 8
-initial_exposure_time = 45
-
-[sla_material:Bluecast Phrozen Wax 0.05]
-inherits = *common 0.05*
-exposure_time = 10
-initial_exposure_time = 55
-
-[sla_material:Jamg He PJHC-00 Yellow 0.05]
-inherits = *common 0.05*
-exposure_time = 7
-initial_exposure_time = 45
-
-[sla_material:Jamg He PJHC-19 Skin 0.05]
-inherits = *common 0.05*
-exposure_time = 6
-initial_exposure_time = 45
-
-[sla_material:Jamg He PJHC-30 Orange 0.05]
-inherits = *common 0.05*
-exposure_time = 7
-initial_exposure_time = 45
-
-[sla_material:Jamg He PJHC-60 Gray 0.05]
-inherits = *common 0.05*
-exposure_time = 6
-initial_exposure_time = 45
-
-[sla_material:Jamg He PJHC-70 Black 0.05]
-inherits = *common 0.05*
-exposure_time = 6
-initial_exposure_time = 45
-
-[sla_material:Monocure 3D Black Rapid Resin 0.05]
-inherits = *common 0.05*
-exposure_time = 6
-initial_exposure_time = 40
-
-[sla_material:Monocure 3D Blue Rapid Resin 0.05]
-inherits = *common 0.05*
-exposure_time = 7
-initial_exposure_time = 40
-
-[sla_material:Monocure 3D Clear Rapid Resin 0.05]
-inherits = *common 0.05*
-exposure_time = 8
-initial_exposure_time = 40
-
-[sla_material:Monocure 3D Gray Rapid Resin 0.05]
-inherits = *common 0.05*
-exposure_time = 7
-initial_exposure_time = 40
-
-[sla_material:Monocure 3D White Rapid Resin 0.05]
-inherits = *common 0.05*
-exposure_time = 7
-initial_exposure_time = 40
-
-########### Materials 0.035
-
-## [sla_material:Jamg He Transparent Clear 0.035]
-## inherits = *common 0.035*
-
-## [sla_material:Jamg He Transparent Green 0.035]
-## inherits = *common 0.035*
-
-## [sla_material:Jamg He Transparent Orange 0.035]
-## inherits = *common 0.035*
-
-## [sla_material:Jamg He Transparent Red 0.035]
-## inherits = *common 0.035*
-
-########### Materials 0.1
-
-## [sla_material:Jamg He Transparent Clear 0.1]
-## inherits = *common 0.1*
-
-## [sla_material:Jamg He Transparent Green 0.1]
-## inherits = *common 0.1*
-
-## [sla_material:Jamg He Transparent Orange 0.1]
-## inherits = *common 0.1*
-
-## [sla_material:Jamg He Transparent Red 0.1]
-## inherits = *common 0.1*
-
-[printer:*common*]
-printer_technology = FFF
-bed_shape = 0x0,250x0,250x210,0x210
-before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\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\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
-extruder_colour = #FFFF00
-extruder_offset = 0x0
-gcode_flavor = marlin
-silent_mode = 0
-remaining_times = 0
-machine_max_acceleration_e = 10000
-machine_max_acceleration_extruding = 2000
-machine_max_acceleration_retracting = 1500
-machine_max_acceleration_x = 9000
-machine_max_acceleration_y = 9000
-machine_max_acceleration_z = 500
-machine_max_feedrate_e = 120
-machine_max_feedrate_x = 500
-machine_max_feedrate_y = 500
-machine_max_feedrate_z = 12
-machine_max_jerk_e = 2.5
-machine_max_jerk_x = 10
-machine_max_jerk_y = 10
-machine_max_jerk_z = 0.2
-machine_min_extruding_rate = 0
-machine_min_travel_rate = 0
-layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
-max_layer_height = 0.25
-min_layer_height = 0.07
-max_print_height = 200
-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 = 4
-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\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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_model = MK2S
-printer_variant = 0.4
-default_print_profile = 0.15mm OPTIMAL
-default_filament_profile = Prusament PLA
-
-[printer:*multimaterial*]
-inherits = *common*
-deretract_speed = 50
-retract_before_travel = 3
-retract_before_wipe = 60%
-retract_layer_change = 0
-retract_length = 4
-retract_lift = 0.6
-retract_lift_above = 0
-retract_lift_below = 199
-retract_restart_extra = 0
-retract_restart_extra_toolchange = 0
-retract_speed = 80
-parking_pos_retraction = 92
-cooling_tube_length = 5
-cooling_tube_retraction = 91.5
-single_extruder_multi_material = 1
-variable_layer_height = 1
-printer_model = MK2SMM
-
-[printer:*mm-single*]
-inherits = *multimaterial*
-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 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n
-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
-start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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\nG92 E0.0
-default_print_profile = 0.15mm OPTIMAL
-
-[printer:*mm-multi*]
-inherits = *multimaterial*
-high_current_on_filament_swap = 1
-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 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors
-extruder_colour = #FFAA55;#E37BA0;#4ECDD3;#FB7259
-nozzle_diameter = 0.4,0.4,0.4,0.4
-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
-start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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_single_extruder_multi_material_priming}\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\n{endif}\nG92 E0.0
-default_print_profile = 0.15mm OPTIMAL
-
-# XXXXXXXXXXXXXXXXX
-# XXX--- MK2 ---XXX
-# XXXXXXXXXXXXXXXXX
-
-[printer:Original Prusa i3 MK2]
-inherits = *common*
-
-[printer:Original Prusa i3 MK2 0.25 nozzle]
-inherits = *common*
-max_layer_height = 0.15
-min_layer_height = 0.05
-nozzle_diameter = 0.25
-retract_length = 1
-retract_speed = 50
-variable_layer_height = 1
-printer_variant = 0.25
-default_print_profile = 0.10mm DETAIL 0.25 nozzle
-
-[printer:Original Prusa i3 MK2 0.6 nozzle]
-inherits = *common*
-max_layer_height = 0.35
-min_layer_height = 0.1
-nozzle_diameter = 0.6
-printer_variant = 0.6
-default_print_profile = 0.20mm NORMAL 0.6 nozzle
-
-# XXXXXXXXXXXXXXXXXXX
-# XXX--- MK2MM ---XXX
-# XXXXXXXXXXXXXXXXXXX
-
-[printer:Original Prusa i3 MK2 MMU1 Single]
-inherits = *mm-single*
-max_layer_height = 0.25
-min_layer_height = 0.07
-
-[printer:Original Prusa i3 MK2 MMU1 Single 0.6 nozzle]
-inherits = *mm-single*
-nozzle_diameter = 0.6
-printer_variant = 0.6
-default_print_profile = 0.20mm NORMAL 0.6 nozzle
-max_layer_height = 0.35
-min_layer_height = 0.1
-
-[printer:Original Prusa i3 MK2 MMU1]
-inherits = *mm-multi*
-nozzle_diameter = 0.4,0.4,0.4,0.4
-max_layer_height = 0.25
-min_layer_height = 0.07
-
-[printer:Original Prusa i3 MK2 MMU1 0.6 nozzle]
-inherits = *mm-multi*
-nozzle_diameter = 0.6,0.6,0.6,0.6
-printer_variant = 0.6
-default_print_profile = 0.20mm NORMAL 0.6 nozzle
-max_layer_height = 0.35
-min_layer_height = 0.1
-
-# XXXXXXXXXXXXXXXXXXX
-# XXX--- MK2.5 ---XXX
-# XXXXXXXXXXXXXXXXXXX
-
-[printer:Original Prusa i3 MK2.5]
-inherits = Original Prusa i3 MK2
-printer_model = MK2.5
-remaining_times = 1
-start_gcode = M115 U3.5.1 ; 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
-
-[printer:Original Prusa i3 MK2.5 MMU2 Single]
-inherits = Original Prusa i3 MK2.5; *mm2*
-printer_model = MK2.5MMU2
-single_extruder_multi_material = 0
-max_print_height = 200
-remaining_times = 1
-silent_mode = 0
-retract_lift_below = 199
-machine_max_acceleration_e = 10000
-machine_max_acceleration_extruding = 2000
-machine_max_acceleration_retracting = 1500
-machine_max_acceleration_x = 9000
-machine_max_acceleration_y = 9000
-machine_max_acceleration_z = 500
-machine_max_feedrate_e = 120
-machine_max_feedrate_x = 500
-machine_max_feedrate_y = 500
-machine_max_feedrate_z = 12
-machine_max_jerk_e = 2.5
-machine_max_jerk_x = 10
-machine_max_jerk_y = 10
-machine_max_jerk_z = 0.2
-machine_min_extruding_rate = 0
-machine_min_travel_rate = 0
-default_print_profile = 0.15mm OPTIMAL MK2.5
-default_filament_profile = Prusament PLA
-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.5\n
-start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
-end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
-
-[printer:Original Prusa i3 MK2.5 MMU2]
-inherits = Original Prusa i3 MK2.5; *mm2*
-printer_model = MK2.5MMU2
-max_print_height = 200
-remaining_times = 1
-silent_mode = 0
-retract_lift_below = 199
-machine_max_acceleration_e = 10000
-machine_max_acceleration_extruding = 2000
-machine_max_acceleration_retracting = 1500
-machine_max_acceleration_x = 9000
-machine_max_acceleration_y = 9000
-machine_max_acceleration_z = 500
-machine_max_feedrate_e = 120
-machine_max_feedrate_x = 500
-machine_max_feedrate_y = 500
-machine_max_feedrate_z = 12
-machine_max_jerk_e = 2.5
-machine_max_jerk_x = 10
-machine_max_jerk_y = 10
-machine_max_jerk_z = 0.2
-machine_min_extruding_rate = 0
-machine_min_travel_rate = 0
-default_print_profile = 0.15mm OPTIMAL MK2.5
-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.5\n
-single_extruder_multi_material = 1
-# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
-# (for example the retract values) are duplicaed from the first value, so they do not need
-# to be defined explicitely.
-nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
-extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
-start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
-end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
-
-[printer:Original Prusa i3 MK2.5 0.25 nozzle]
-inherits = Original Prusa i3 MK2 0.25 nozzle
-printer_model = MK2.5
-remaining_times = 1
-start_gcode = M115 U3.5.1 ; 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
-
-[printer:Original Prusa i3 MK2.5 0.6 nozzle]
-inherits = Original Prusa i3 MK2 0.6 nozzle
-printer_model = MK2.5
-remaining_times = 1
-start_gcode = M115 U3.5.1 ; 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
-
-# XXXXXXXXXXXXXXXXX
-# XXX--- MK3 ---XXX
-# XXXXXXXXXXXXXXXXX
-
-[printer:Original Prusa i3 MK3]
-inherits = *common*
-end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
-machine_max_acceleration_e = 5000,5000
-machine_max_acceleration_extruding = 1250,1250
-machine_max_acceleration_retracting = 1250,1250
-machine_max_acceleration_x = 1000,960
-machine_max_acceleration_y = 1000,960
-machine_max_acceleration_z = 1000,1000
-machine_max_feedrate_e = 120,120
-machine_max_feedrate_x = 200,100
-machine_max_feedrate_y = 200,100
-machine_max_feedrate_z = 12,12
-machine_max_jerk_e = 1.5,1.5
-machine_max_jerk_x = 8,8
-machine_max_jerk_y = 8,8
-machine_max_jerk_z = 0.4,0.4
-machine_min_extruding_rate = 0,0
-machine_min_travel_rate = 0,0
-silent_mode = 1
-remaining_times = 1
-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_lift_below = 209
-max_print_height = 210
-start_gcode = M115 U3.5.1 ; 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\nM221 S{if layer_height==0.05}100{else}95{endif}
-printer_model = MK3
-default_print_profile = 0.15mm OPTIMAL MK3
-
-[printer:Original Prusa i3 MK3 0.25 nozzle]
-inherits = Original Prusa i3 MK3
-nozzle_diameter = 0.25
-max_layer_height = 0.15
-min_layer_height = 0.05
-printer_variant = 0.25
-default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3
-
-[printer:Original Prusa i3 MK3 0.6 nozzle]
-inherits = Original Prusa i3 MK3
-nozzle_diameter = 0.6
-max_layer_height = 0.35
-min_layer_height = 0.1
-printer_variant = 0.6
-default_print_profile = 0.15mm OPTIMAL 0.6 nozzle MK3
-
-[printer:*mm2*]
-inherits = Original Prusa i3 MK3
-single_extruder_multi_material = 1
-cooling_tube_length = 10
-cooling_tube_retraction = 30
-parking_pos_retraction = 85
-retract_length_toolchange = 3
-extra_loading_move = -13
-printer_model = MK3MMU2
-default_print_profile = 0.15mm OPTIMAL MK3
-default_filament_profile = Prusament PLA MMU2
-
-[printer:Original Prusa i3 MK3 MMU2 Single]
-inherits = *mm2*
-single_extruder_multi_material = 0
-default_filament_profile = Prusament PLA
-start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
-end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
-
-[printer:Original Prusa i3 MK3 MMU2]
-inherits = *mm2*
-# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
-# (for example the retract values) are duplicaed from the first value, so they do not need
-# to be defined explicitely.
-machine_max_acceleration_e = 8000,8000
-nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
-extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
-start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
-end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
-
-[printer:Original Prusa SL1]
-printer_technology = SLA
-printer_model = SL1
-printer_variant = default
-default_sla_material_profile = Jamg He Transparent Green 0.05
-default_sla_print_profile = 0.05 Normal
-bed_shape = 0.98x1.02,119.98x1.02,119.98x68.02,0.98x68.02
-display_height = 68.04
-display_orientation = portrait
-display_pixels_x = 2560
-display_pixels_y = 1440
-display_width = 120.96
-max_print_height = 150
-printer_correction = 1,1,1
-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_SL1\n
-
-# The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer.
-[obsolete_presets]
-print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2"
-filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"
+# Print profiles for the Prusa Research printers.
+
+[vendor]
+# Vendor name will be shown by the Config Wizard.
+name = Prusa Research
+# Configuration version of this file. Config file will only be installed, if the config_version differs.
+# This means, the server may force the Slic3r configuration to be downgraded.
+config_version = 0.8.0-alpha7
+# Where to get the updates from?
+config_update_url = https://raw.githubusercontent.com/prusa3d/Slic3r-settings/master/live/PrusaResearch/
+
+# The printer models will be shown by the Configuration Wizard in this order,
+# also the first model installed & the first nozzle installed will be activated after install.
+#TODO: One day we may differentiate variants of the nozzles / hot ends,
+#for example by the melt zone size, or whether the nozzle is hardened.
+# Printer model name will be shown by the installation wizard.
+
+[printer_model:MK3S]
+name = Original Prusa i3 MK3S
+variants = 0.4; 0.25; 0.6
+technology = FFF
+family = MK3
+
+[printer_model:MK3]
+name = Original Prusa i3 MK3
+variants = 0.4; 0.25; 0.6
+technology = FFF
+family = MK3
+
+[printer_model:MK3SMMU2S]
+name = Original Prusa i3 MK3S MMU2S
+variants = 0.4
+technology = FFF
+family = MK3
+
+[printer_model:MK3MMU2]
+name = Original Prusa i3 MK3 MMU2
+variants = 0.4
+technology = FFF
+family = MK3
+
+[printer_model:MK2.5S]
+name = Original Prusa i3 MK2.5S
+variants = 0.4; 0.25; 0.6
+technology = FFF
+family = MK2.5
+
+[printer_model:MK2.5]
+name = Original Prusa i3 MK2.5
+variants = 0.4; 0.25; 0.6
+technology = FFF
+family = MK2.5
+
+[printer_model:MK2.5SMMU2S]
+name = Original Prusa i3 MK2.5S MMU2S
+variants = 0.4
+technology = FFF
+family = MK2.5
+
+[printer_model:MK2.5MMU2]
+name = Original Prusa i3 MK2.5 MMU2
+variants = 0.4
+technology = FFF
+family = MK2.5
+
+[printer_model:MK2S]
+name = Original Prusa i3 MK2S
+variants = 0.4; 0.25; 0.6
+technology = FFF
+family = MK2
+
+[printer_model:MK2SMM]
+name = Original Prusa i3 MK2S MMU1
+variants = 0.4; 0.6
+technology = FFF
+family = MK2
+
+[printer_model:SL1]
+name = Original Prusa SL1
+variants = default
+technology = SLA
+family = SL1
+
+# All presets starting with asterisk, for example *common*, are intermediate and they will
+# not make it into the user interface.
+
+# Common print preset, mostly derived from MK2 single material with a 0.4mm nozzle.
+# All other print presets will derive from the *common* print preset.
+[print:*common*]
+avoid_crossing_perimeters = 0
+bridge_acceleration = 1000
+bridge_angle = 0
+bridge_flow_ratio = 0.8
+bridge_speed = 20
+brim_width = 0
+clip_multipart_objects = 1
+compatible_printers =
+complete_objects = 0
+default_acceleration = 1000
+dont_support_bridges = 1
+elefant_foot_compensation = 0
+ensure_vertical_shell_thickness = 1
+external_fill_pattern = rectilinear
+external_perimeters_first = 0
+external_perimeter_extrusion_width = 0.45
+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 = 20
+gap_fill_speed = 40
+gcode_comments = 0
+infill_every_layers = 1
+infill_extruder = 1
+infill_extrusion_width = 0.45
+infill_first = 0
+infill_only_where_needed = 0
+infill_overlap = 25%
+interface_shells = 0
+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 =
+overhangs = 0
+only_retract_when_crossing_perimeters = 0
+ooze_prevention = 0
+output_filename_format = {input_filename_base}_{layer_height}mm_{filament_type[0]}_{printer_model}.gcode
+perimeters = 2
+perimeter_extruder = 1
+perimeter_extrusion_width = 0.45
+post_process =
+print_settings_id =
+raft_layers = 0
+resolution = 0
+seam_position = nearest
+single_extruder_multi_material_priming = 1
+skirts = 1
+skirt_distance = 2
+skirt_height = 3
+small_perimeter_speed = 25
+solid_infill_below_area = 0
+solid_infill_every_layers = 0
+solid_infill_extruder = 1
+solid_infill_extrusion_width = 0.45
+spiral_vase = 0
+standby_temperature_delta = -5
+support_material = 0
+support_material_extruder = 0
+support_material_extrusion_width = 0.35
+support_material_interface_extruder = 0
+support_material_angle = 0
+support_material_buildplate_only = 0
+support_material_enforce_layers = 0
+support_material_contact_distance = 0.1
+support_material_interface_contact_loops = 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 = 55
+support_material_with_sheath = 0
+support_material_xy_spacing = 50%
+thin_walls = 0
+top_infill_extrusion_width = 0.45
+top_solid_infill_speed = 40
+travel_speed = 180
+wipe_tower = 1
+wipe_tower_bridging = 10
+wipe_tower_rotation_angle = 0
+wipe_tower_width = 60
+wipe_tower_x = 170
+wipe_tower_y = 140
+xy_size_compensation = 0
+
+[print:*MK3*]
+fill_pattern = grid
+single_extruder_multi_material_priming = 0
+travel_speed = 180
+wipe_tower_x = 170
+wipe_tower_y = 125
+
+# Print parameters common to a 0.25mm diameter nozzle.
+[print:*0.25nozzle*]
+external_perimeter_extrusion_width = 0.25
+extrusion_width = 0.25
+first_layer_extrusion_width = 0.25
+infill_extrusion_width = 0.25
+perimeter_extrusion_width = 0.25
+solid_infill_extrusion_width = 0.25
+top_infill_extrusion_width = 0.25
+support_material_extrusion_width = 0.2
+support_material_interface_layers = 0
+support_material_interface_spacing = 0.15
+support_material_spacing = 1
+support_material_xy_spacing = 150%
+
+# Print parameters common to a 0.6mm diameter nozzle.
+[print:*0.6nozzle*]
+external_perimeter_extrusion_width = 0.61
+extrusion_width = 0.67
+first_layer_extrusion_width = 0.65
+infill_extrusion_width = 0.7
+perimeter_extrusion_width = 0.65
+solid_infill_extrusion_width = 0.65
+top_infill_extrusion_width = 0.6
+support_material_extrusion_width = 0.55
+
+[print:*soluble_support*]
+overhangs = 1
+skirts = 0
+support_material = 1
+support_material_contact_distance = 0
+support_material_extruder = 4
+support_material_extrusion_width = 0.45
+support_material_interface_extruder = 4
+support_material_interface_spacing = 0.1
+support_material_synchronize_layers = 1
+support_material_threshold = 80
+support_material_with_sheath = 1
+wipe_tower_bridging = 8
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.05mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+[print:*0.05mm*]
+inherits = *common*
+bottom_solid_layers = 10
+bridge_acceleration = 300
+bridge_flow_ratio = 0.7
+default_acceleration = 500
+external_perimeter_speed = 20
+fill_density = 20%
+first_layer_acceleration = 500
+gap_fill_speed = 20
+infill_acceleration = 800
+infill_speed = 30
+max_print_speed = 80
+small_perimeter_speed = 20
+solid_infill_speed = 30
+support_material_extrusion_width = 0.3
+support_material_spacing = 1.5
+layer_height = 0.05
+perimeter_acceleration = 300
+perimeter_speed = 30
+perimeters = 3
+support_material_speed = 30
+top_solid_infill_speed = 20
+top_solid_layers = 15
+
+[print:0.05mm ULTRADETAIL]
+inherits = *0.05mm*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
+infill_extrusion_width = 0.5
+
+# MK3 #
+[print:0.05mm ULTRADETAIL MK3]
+inherits = *0.05mm*; *MK3*
+fill_pattern = gyroid
+fill_density = 15%
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
+top_infill_extrusion_width = 0.4
+
+# MK2 #
+[print:0.05mm ULTRADETAIL 0.25 nozzle]
+inherits = *0.05mm*; *0.25nozzle*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
+fill_density = 20%
+infill_speed = 20
+max_print_speed = 100
+perimeter_speed = 20
+small_perimeter_speed = 15
+solid_infill_speed = 20
+support_material_speed = 20
+
+# MK3 #
+[print:0.05mm ULTRADETAIL 0.25 nozzle MK3]
+inherits = *0.05mm*; *0.25nozzle*; *MK3*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25 and num_extruders==1
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.07mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+[print:*0.07mm*]
+inherits = *common*
+bottom_solid_layers = 8
+bridge_acceleration = 300
+bridge_flow_ratio = 0.7
+bridge_speed = 20
+default_acceleration = 500
+external_perimeter_speed = 20
+fill_density = 15%
+first_layer_acceleration = 500
+gap_fill_speed = 20
+infill_acceleration = 800
+infill_speed = 40
+max_print_speed = 80
+small_perimeter_speed = 20
+solid_infill_speed = 40
+support_material_extrusion_width = 0.3
+support_material_spacing = 1.5
+layer_height = 0.07
+perimeter_acceleration = 300
+perimeter_speed = 30
+perimeters = 3
+support_material_speed = 40
+top_solid_infill_speed = 30
+top_solid_layers = 11
+
+# MK3 #
+[print:0.07mm ULTRADETAIL MK3]
+inherits = *0.07mm*; *MK3*
+fill_pattern = gyroid
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
+top_infill_extrusion_width = 0.4
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.10mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+# MK2 #
+[print:*0.10mm*]
+inherits = *common*
+bottom_solid_layers = 7
+bridge_flow_ratio = 0.7
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
+layer_height = 0.1
+perimeter_acceleration = 800
+top_solid_layers = 9
+
+# MK2 #
+[print:0.10mm DETAIL]
+inherits = *0.10mm*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.4 and num_extruders==1
+external_perimeter_speed = 40
+infill_acceleration = 2000
+infill_speed = 60
+perimeter_speed = 50
+solid_infill_speed = 50
+
+# MK3 #
+[print:0.10mm DETAIL MK3]
+inherits = *0.10mm*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and ! single_extruder_multi_material
+external_perimeter_speed = 25
+infill_acceleration = 1250
+infill_speed = 80
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 80
+top_infill_extrusion_width = 0.4
+top_solid_infill_speed = 40
+fill_pattern = gyroid
+fill_density = 15%
+
+# MK2 #
+[print:0.10mm DETAIL 0.25 nozzle]
+inherits = *0.10mm*; *0.25nozzle*
+bridge_acceleration = 600
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25
+external_perimeter_speed = 20
+infill_acceleration = 1600
+infill_speed = 40
+perimeter_acceleration = 600
+perimeter_speed = 25
+small_perimeter_speed = 15
+solid_infill_speed = 40
+top_solid_infill_speed = 30
+
+# MK3 #
+[print:0.10mm DETAIL 0.25 nozzle MK3]
+inherits = *0.10mm*; *0.25nozzle*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# MK3 #
+[print:0.10mm DETAIL 0.6 nozzle MK3]
+inherits = *0.10mm*; *0.6nozzle*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.15mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+[print:*0.15mm*]
+inherits = *common*
+bottom_solid_layers = 5
+external_perimeter_speed = 40
+infill_acceleration = 2000
+infill_speed = 60
+layer_height = 0.15
+perimeter_acceleration = 800
+perimeter_speed = 50
+solid_infill_speed = 50
+top_infill_extrusion_width = 0.4
+top_solid_layers = 7
+
+# MK2 #
+[print:0.15mm 100mms Linear Advance]
+inherits = *0.15mm*
+bridge_flow_ratio = 0.95
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 50
+infill_speed = 100
+max_print_speed = 150
+perimeter_speed = 60
+small_perimeter_speed = 30
+solid_infill_speed = 100
+support_material_speed = 60
+top_solid_infill_speed = 70
+
+# MK2 #
+[print:0.15mm OPTIMAL]
+inherits = *0.15mm*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
+top_infill_extrusion_width = 0.45
+
+# MK2 #
+[print:0.15mm OPTIMAL 0.25 nozzle]
+inherits = *0.15mm*; *0.25nozzle*
+bridge_acceleration = 600
+bridge_flow_ratio = 0.7
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.25
+external_perimeter_speed = 20
+infill_acceleration = 1600
+infill_speed = 40
+perimeter_acceleration = 600
+perimeter_speed = 25
+small_perimeter_speed = 15
+solid_infill_speed = 40
+top_solid_infill_speed = 30
+
+# MK2 #
+[print:0.15mm OPTIMAL 0.6 nozzle]
+inherits = *0.15mm*; *0.6nozzle*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
+
+# MK3 #
+[print:0.15mm QUALITY MK3]
+inherits = *0.15mm*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 25
+infill_acceleration = 1250
+infill_speed = 80
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 80
+top_solid_infill_speed = 40
+fill_pattern = gyroid
+fill_density = 15%
+
+[print:0.15mm SPEED MK3]
+inherits = *0.15mm*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 60
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# MK3 MMU #
+[print:0.15mm SOLUBLE FULL MK3]
+inherits = 0.15mm SPEED MK3; *soluble_support*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
+support_material_extruder = 5
+support_material_interface_extruder = 5
+perimeter_speed = 40
+solid_infill_speed = 40
+top_infill_extrusion_width = 0.45
+top_solid_infill_speed = 30
+
+# MK3 MMU #
+[print:0.15mm SOLUBLE INTERFACE MK3]
+inherits = 0.15mm SOLUBLE FULL MK3
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder
+support_material_extruder = 0
+support_material_interface_layers = 3
+support_material_with_sheath = 0
+
+# MK2 MMU #
+[print:0.15mm OPTIMAL SOLUBLE FULL]
+inherits = *0.15mm*; *soluble_support*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+external_perimeter_speed = 25
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
+perimeter_speed = 40
+solid_infill_speed = 40
+top_infill_extrusion_width = 0.45
+top_solid_infill_speed = 30
+
+# MK2 MMU #
+[print:0.15mm OPTIMAL SOLUBLE INTERFACE]
+inherits = 0.15mm OPTIMAL SOLUBLE FULL
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder
+support_material_extruder = 0
+support_material_interface_layers = 3
+support_material_with_sheath = 0
+support_material_xy_spacing = 80%
+
+# MK3 #
+[print:0.15mm OPTIMAL 0.25 nozzle MK3]
+inherits = *0.15mm*; *0.25nozzle*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.25
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+[print:*0.20mm*]
+inherits = *common*
+bottom_solid_layers = 4
+bridge_flow_ratio = 0.95
+external_perimeter_speed = 40
+infill_acceleration = 2000
+infill_speed = 60
+layer_height = 0.2
+perimeter_acceleration = 800
+perimeter_speed = 50
+solid_infill_speed = 50
+top_infill_extrusion_width = 0.4
+top_solid_layers = 5
+
+# MK3 #
+[print:0.15mm OPTIMAL 0.6 nozzle MK3]
+inherits = *0.15mm*; *0.6nozzle*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.20mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+# MK2 #
+[print:0.20mm 100mms Linear Advance]
+inherits = *0.20mm*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 50
+infill_speed = 100
+max_print_speed = 150
+perimeter_speed = 60
+small_perimeter_speed = 30
+solid_infill_speed = 100
+support_material_speed = 60
+top_solid_infill_speed = 70
+
+# MK3 #
+[print:0.20mm QUALITY MK3]
+inherits = *0.20mm*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 25
+infill_acceleration = 1250
+infill_speed = 80
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 80
+top_solid_infill_speed = 40
+fill_pattern = gyroid
+fill_density = 15%
+
+[print:0.20mm SPEED MK3]
+inherits = *0.20mm*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 60
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# MK3 MMU #
+[print:0.20mm SOLUBLE FULL MK3]
+inherits = 0.20mm SPEED MK3; *soluble_support*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
+support_material_extruder = 5
+support_material_interface_extruder = 5
+perimeter_speed = 40
+solid_infill_speed = 40
+top_infill_extrusion_width = 0.45
+top_solid_infill_speed = 30
+
+# MK3 MMU #
+[print:0.20mm SOLUBLE INTERFACE MK3]
+inherits = 0.20mm SOLUBLE FULL MK3
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder
+support_material_extruder = 0
+support_material_interface_layers = 3
+support_material_with_sheath = 0
+
+# MK2 #
+[print:0.20mm NORMAL]
+inherits = *0.20mm*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
+
+# MK2 #
+[print:0.20mm NORMAL 0.6 nozzle]
+inherits = *0.20mm*; *0.6nozzle*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
+
+# MK2 MMU #
+[print:0.20mm NORMAL SOLUBLE FULL]
+inherits = *0.20mm*; *soluble_support*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+external_perimeter_speed = 30
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft/skirt extruder & Support material/raft interface extruder
+perimeter_speed = 40
+solid_infill_speed = 40
+top_solid_infill_speed = 30
+
+# MK2 MMU #
+[print:0.20mm NORMAL SOLUBLE INTERFACE]
+inherits = 0.20mm NORMAL SOLUBLE FULL
+notes = Set your soluble extruder in Multiple Extruders > Support material/raft interface extruder
+support_material_extruder = 0
+support_material_interface_layers = 3
+support_material_with_sheath = 0
+support_material_xy_spacing = 80%
+
+# MK3 #
+[print:0.20mm FAST 0.6 nozzle MK3]
+inherits = *0.20mm*; *0.6nozzle*; *MK3*
+bridge_speed = 30
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and nozzle_diameter[0]==0.6
+external_perimeter_speed = 35
+infill_acceleration = 1250
+infill_speed = 200
+max_print_speed = 200
+perimeter_speed = 45
+solid_infill_speed = 200
+top_solid_infill_speed = 50
+
+# XXXXXXXXXXXXXXXXXXXX
+# XXX--- 0.35mm ---XXX
+# XXXXXXXXXXXXXXXXXXXX
+
+[print:*0.35mm*]
+inherits = *common*
+bottom_solid_layers = 3
+external_perimeter_extrusion_width = 0.6
+external_perimeter_speed = 40
+first_layer_extrusion_width = 0.75
+infill_acceleration = 2000
+infill_speed = 60
+layer_height = 0.35
+perimeter_acceleration = 800
+perimeter_extrusion_width = 0.65
+perimeter_speed = 50
+solid_infill_extrusion_width = 0.65
+solid_infill_speed = 60
+top_solid_infill_speed = 50
+top_solid_layers = 4
+
+# MK2 #
+[print:0.35mm FAST]
+inherits = *0.35mm*
+bridge_flow_ratio = 0.95
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2[^\.].*/ and nozzle_diameter[0]==0.4
+first_layer_extrusion_width = 0.42
+perimeter_extrusion_width = 0.43
+solid_infill_extrusion_width = 0.7
+top_infill_extrusion_width = 0.43
+
+# MK2 #
+[print:0.35mm FAST 0.6 nozzle]
+inherits = *0.35mm*; *0.6nozzle*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6
+
+# MK2 MMU #
+[print:0.35mm FAST sol full 0.6 nozzle]
+inherits = *0.35mm*; *0.6nozzle*; *soluble_support*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.*/ and nozzle_diameter[0]==0.6 and num_extruders>1
+external_perimeter_extrusion_width = 0.6
+external_perimeter_speed = 30
+notes = Set your solluble extruder in Multiple Extruders > Support material/raft interface extruder
+perimeter_speed = 40
+support_material_interface_layers = 3
+support_material_xy_spacing = 120%
+top_infill_extrusion_width = 0.57
+
+# MK2 MMU #
+[print:0.35mm FAST sol int 0.6 nozzle]
+inherits = 0.35mm FAST sol full 0.6 nozzle
+support_material_extruder = 0
+support_material_interface_layers = 2
+support_material_with_sheath = 0
+support_material_xy_spacing = 150%
+
+# XXXXXXXXXXXXXXXXXXXXXX
+# XXX----- MK2.5 ----XXX
+# XXXXXXXXXXXXXXXXXXXXXX
+
+# MK2.5 #
+[print:0.15mm 100mms Linear Advance MK2.5]
+inherits = 0.15mm 100mms Linear Advance
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
+single_extruder_multi_material_priming = 0
+
+# MK2.5 #
+[print:0.15mm OPTIMAL MK2.5]
+inherits = 0.15mm OPTIMAL
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
+single_extruder_multi_material_priming = 0
+
+# MK2.5 MMU2 #
+[print:0.15mm OPTIMAL SOLUBLE FULL MK2.5]
+inherits = 0.15mm OPTIMAL SOLUBLE FULL
+support_material_extruder = 5
+support_material_interface_extruder = 5
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+
+# MK2.5 MMU2 #
+[print:0.15mm OPTIMAL SOLUBLE INTERFACE MK2.5]
+inherits = 0.15mm OPTIMAL SOLUBLE INTERFACE
+support_material_extruder = 0
+support_material_interface_extruder = 5
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+
+# MK2.5 #
+[print:0.20mm 100mms Linear Advance MK2.5]
+inherits = 0.20mm 100mms Linear Advance
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
+single_extruder_multi_material_priming = 0
+
+# MK2.5 #
+[print:0.20mm NORMAL MK2.5]
+inherits = 0.20mm NORMAL
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
+single_extruder_multi_material_priming = 0
+
+# MK2.5 MMU2 #
+[print:0.20mm NORMAL SOLUBLE FULL MK2.5]
+inherits = 0.20mm NORMAL SOLUBLE FULL
+support_material_extruder = 5
+support_material_interface_extruder = 5
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+single_extruder_multi_material_priming = 0
+
+# MK2.5 MMU2 #
+[print:0.20mm NORMAL SOLUBLE INTERFACE MK2.5]
+inherits = 0.20mm NORMAL SOLUBLE INTERFACE
+support_material_extruder = 0
+support_material_interface_extruder = 5
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4 and num_extruders>1
+single_extruder_multi_material_priming = 0
+
+# MK2.5 #
+[print:0.35mm FAST MK2.5]
+inherits = 0.35mm FAST
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK2.5.*/ and nozzle_diameter[0]==0.4
+single_extruder_multi_material_priming = 0
+
+# XXXXXXxxXXXXXXXXXXXXXX
+# XXX--- filament ---XXX
+# XXXXXXXXxxXXXXXXXXXXXX
+
+[filament:*common*]
+cooling = 1
+compatible_printers =
+# For now, all but selected filaments are disabled for the MMU 2.0
+compatible_printers_condition = ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+end_filament_gcode = "; Filament-specific end gcode"
+extrusion_multiplier = 1
+filament_loading_speed = 28
+filament_loading_speed_start = 3
+filament_unloading_speed = 90
+filament_unloading_speed_start = 100
+filament_toolchange_delay = 0
+filament_cooling_moves = 4
+filament_cooling_initial_speed = 2.2
+filament_cooling_final_speed = 3.4
+filament_load_time = 0
+filament_unload_time = 0
+filament_ramming_parameters = "120 100 6.6 6.8 7.2 7.6 7.9 8.2 8.7 9.4 9.9 10.0| 0.05 6.6 0.45 6.8 0.95 7.8 1.45 8.3 1.95 9.7 2.45 10 2.95 7.6 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_minimal_purge_on_wipe_tower = 15
+filament_cost = 0
+filament_density = 0
+filament_diameter = 1.75
+filament_notes = ""
+filament_settings_id = ""
+filament_soluble = 0
+min_print_speed = 15
+slowdown_below_layer_time = 20
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
+
+[filament:*PLA*]
+inherits = *common*
+bed_temperature = 60
+bridge_fan_speed = 100
+disable_fan_first_layers = 1
+fan_always_on = 1
+fan_below_layer_time = 100
+filament_colour = #FF3232
+filament_max_volumetric_speed = 15
+filament_type = PLA
+first_layer_bed_temperature = 60
+first_layer_temperature = 215
+max_fan_speed = 100
+min_fan_speed = 100
+temperature = 210
+
+[filament:*PET*]
+inherits = *common*
+bed_temperature = 90
+bridge_fan_speed = 50
+disable_fan_first_layers = 3
+fan_always_on = 1
+fan_below_layer_time = 20
+filament_colour = #FF8000
+filament_max_volumetric_speed = 8
+filament_type = PET
+first_layer_bed_temperature = 85
+first_layer_temperature = 230
+max_fan_speed = 50
+min_fan_speed = 30
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
+temperature = 240
+
+[filament:*ABS*]
+inherits = *common*
+bed_temperature = 110
+bridge_fan_speed = 30
+cooling = 0
+disable_fan_first_layers = 3
+fan_always_on = 0
+fan_below_layer_time = 20
+filament_colour = #3A80CA
+filament_max_volumetric_speed = 11
+filament_ramming_parameters = "120 100 5.70968 6.03226 7 8.25806 9 9.19355 9.3871 9.77419 10.129 10.3226 10.4516 10.5161| 0.05 5.69677 0.45 6.15484 0.95 8.76774 1.45 9.20323 1.95 9.95806 2.45 10.3871 2.95 10.5677 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_type = ABS
+first_layer_bed_temperature = 100
+first_layer_temperature = 255
+max_fan_speed = 30
+min_fan_speed = 20
+temperature = 255
+
+[filament:*FLEX*]
+inherits = *common*
+bed_temperature = 50
+bridge_fan_speed = 100
+# For now, all but selected filaments are disabled for the MMU 2.0
+compatible_printers_condition = nozzle_diameter[0]>0.35 and num_extruders==1 && ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK3.*/ and single_extruder_multi_material)
+cooling = 0
+disable_fan_first_layers = 1
+extrusion_multiplier = 1.2
+fan_always_on = 0
+fan_below_layer_time = 100
+filament_colour = #00CA0A
+filament_max_volumetric_speed = 1.5
+filament_type = FLEX
+first_layer_bed_temperature = 50
+first_layer_temperature = 240
+max_fan_speed = 90
+min_fan_speed = 70
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 240
+
+[filament:ColorFabb Brass Bronze]
+inherits = *PLA*
+# For now, all but selected filaments are disabled for the MMU 2.0
+compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+extrusion_multiplier = 1.2
+filament_cost = 80.65
+filament_density = 4
+filament_colour = #804040
+filament_max_volumetric_speed = 10
+
+[filament:ColorFabb HT]
+inherits = *PET*
+bed_temperature = 110
+bridge_fan_speed = 30
+cooling = 1
+disable_fan_first_layers = 3
+fan_always_on = 0
+fan_below_layer_time = 10
+filament_cost = 58.66
+filament_density = 1.18
+first_layer_bed_temperature = 105
+first_layer_temperature = 270
+max_fan_speed = 20
+min_fan_speed = 10
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}45{endif}; Filament gcode"
+temperature = 270
+
+[filament:ColorFabb PLA-PHA]
+inherits = *PLA*
+filament_cost = 55.5
+filament_density = 1.24
+
+[filament:ColorFabb Woodfil]
+inherits = *PLA*
+# For now, all but selected filaments are disabled for the MMU 2.0
+compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+extrusion_multiplier = 1.2
+filament_cost = 62.9
+filament_density = 1.15
+filament_colour = #804040
+filament_max_volumetric_speed = 10
+first_layer_temperature = 200
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 200
+
+[filament:ColorFabb XT]
+inherits = *PET*
+filament_type = PET
+filament_cost = 62.9
+filament_density = 1.27
+first_layer_bed_temperature = 90
+first_layer_temperature = 260
+temperature = 270
+
+[filament:ColorFabb XT-CF20]
+inherits = *PET*
+compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+extrusion_multiplier = 1.2
+filament_cost = 80.65
+filament_density = 1.35
+filament_colour = #804040
+filament_max_volumetric_speed = 1
+first_layer_bed_temperature = 90
+first_layer_temperature = 260
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
+temperature = 260
+
+[filament:ColorFabb nGen]
+inherits = *PET*
+filament_cost = 21.2
+filament_density = 1.2
+bridge_fan_speed = 40
+fan_always_on = 0
+fan_below_layer_time = 10
+filament_type = NGEN
+first_layer_temperature = 240
+max_fan_speed = 35
+min_fan_speed = 20
+
+[filament:ColorFabb nGen flex]
+inherits = *FLEX*
+filament_cost = 0
+filament_density = 1
+bed_temperature = 85
+bridge_fan_speed = 40
+cooling = 1
+disable_fan_first_layers = 3
+extrusion_multiplier = 1
+fan_below_layer_time = 10
+filament_max_volumetric_speed = 5
+first_layer_bed_temperature = 85
+first_layer_temperature = 260
+max_fan_speed = 35
+min_fan_speed = 20
+temperature = 260
+
+[filament:E3D Edge]
+inherits = *PET*
+filament_cost = 56.9
+filament_density = 1.26
+filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
+
+[filament:E3D PC-ABS]
+inherits = *ABS*
+filament_cost = 0
+filament_density = 1.05
+first_layer_temperature = 270
+temperature = 270
+
+[filament:Fillamentum ABS]
+inherits = *ABS*
+filament_cost = 32.4
+filament_density = 1.04
+first_layer_temperature = 240
+temperature = 240
+
+[filament:Fillamentum ASA]
+inherits = *ABS*
+filament_cost = 38.7
+filament_density = 1.04
+fan_always_on = 1
+first_layer_temperature = 265
+temperature = 265
+
+[filament:Fillamentum CPE HG100 HM100]
+inherits = *PET*
+filament_cost = 54.1
+filament_density = 1.25
+filament_notes = "CPE HG100 , CPE HM100"
+first_layer_bed_temperature = 90
+first_layer_temperature = 275
+max_fan_speed = 50
+min_fan_speed = 50
+temperature = 275
+
+[filament:Fillamentum Timberfil]
+inherits = *PLA*
+# For now, all but selected filaments are disabled for the MMU 2.0
+compatible_printers_condition = nozzle_diameter[0]>0.35 and ! (printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material)
+extrusion_multiplier = 1.2
+filament_cost = 68
+filament_density = 1.15
+filament_colour = #804040
+filament_max_volumetric_speed = 10
+first_layer_temperature = 190
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 190
+
+[filament:Generic ABS]
+inherits = *ABS*
+filament_cost = 27.82
+filament_density = 1.04
+filament_notes = "List of materials tested with standart ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS"
+
+[filament:Generic PET]
+inherits = *PET*
+filament_cost = 27.82
+filament_density = 1.27
+filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
+
+[filament:Generic PLA]
+inherits = *PLA*
+filament_cost = 25.4
+filament_density = 1.24
+filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
+
+[filament:Polymaker PC-Max]
+inherits = *ABS*
+filament_cost = 77.3
+filament_density = 1.20
+bed_temperature = 115
+filament_colour = #3A80CA
+first_layer_bed_temperature = 100
+first_layer_temperature = 270
+temperature = 270
+
+[filament:PrimaSelect PVA+]
+inherits = *PLA*
+filament_cost = 108
+filament_density = 1.23
+cooling = 0
+fan_always_on = 0
+filament_colour = #FFFFD7
+filament_max_volumetric_speed = 10
+filament_notes = "List of materials tested with standart PVA print settings:\n\nPrimaSelect PVA+\nICE FILAMENTS PVA 'NAUGHTY NATURAL'\nVerbatim BVOH"
+filament_ramming_parameters = "120 100 8.3871 8.6129 8.93548 9.22581 9.48387 9.70968 9.87097 10.0323 10.2258 10.4194 10.6452 10.8065| 0.05 8.34193 0.45 8.73548 0.95 9.34836 1.45 9.78385 1.95 10.0871 2.45 10.5161 2.95 10.8903 3.45 7.6 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_soluble = 1
+filament_type = PVA
+first_layer_temperature = 195
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 195
+
+[filament:Prusa ABS]
+inherits = *ABS*
+filament_cost = 27.82
+filament_density = 1.08
+filament_notes = "List of materials tested with standart ABS print settings:\n\nEsun ABS\nFil-A-Gehr ABS\nHatchboxABS\nPlasty Mladec ABS"
+
+[filament:*ABS MMU2*]
+inherits = Prusa ABS
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
+filament_cooling_final_speed = 50
+filament_cooling_initial_speed = 10
+filament_cooling_moves = 5
+filament_ramming_parameters = "120 110 5.32258 5.45161 5.67742 6 6.48387 7.12903 7.90323 8.70968 9.3871 9.83871 10.0968 10.2258| 0.05 5.30967 0.45 5.50967 0.95 6.1871 1.45 7.39677 1.95 9.05484 2.45 10 2.95 10.3098 3.45 13.0839 3.95 7.6 4.45 7.6 4.95 7.6";
+filament_loading_speed_start = 19
+filament_load_time = 15
+filament_unload_time = 12
+filament_loading_speed = 14
+filament_unloading_speed = 20
+
+[filament:Generic ABS MMU2]
+inherits = *ABS MMU2*
+
+[filament:Prusa ABS MMU2]
+inherits = *ABS MMU2*
+
+[filament:Prusa HIPS]
+inherits = *ABS*
+filament_cost = 27.3
+filament_density = 1.04
+bridge_fan_speed = 50
+cooling = 1
+extrusion_multiplier = 0.9
+fan_always_on = 1
+fan_below_layer_time = 10
+filament_colour = #FFFFD7
+filament_soluble = 1
+filament_type = HIPS
+first_layer_temperature = 220
+max_fan_speed = 20
+min_fan_speed = 20
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 220
+
+[filament:Prusa PET]
+inherits = *PET*
+filament_cost = 27.82
+filament_density = 1.27
+filament_notes = "List of manufacturers tested with standart PET print settings:\n\nE3D Edge\nFillamentum CPE GH100\nPlasty Mladec PETG"
+
+[filament:Prusament PETG]
+inherits = *PET*
+first_layer_temperature = 240
+temperature = 250
+filament_cost = 24.99
+filament_density = 1.27
+
+[filament:*PET MMU2*]
+inherits = Prusa PET
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
+temperature = 230
+first_layer_temperature = 230
+filament_cooling_final_speed = 1
+filament_cooling_initial_speed = 2
+filament_cooling_moves = 1
+filament_load_time = 15
+filament_loading_speed = 14
+filament_notes = PET
+filament_ramming_parameters = "120 140 4.70968 4.74194 4.77419 4.80645 4.83871 4.87097 4.90323 5 5.25806 5.67742 6.29032 7.06452 7.83871 8.3871| 0.05 4.72901 0.45 4.73545 0.95 4.83226 1.45 4.88067 1.95 5.05483 2.45 5.93553 2.95 7.53556 3.45 8.6323 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_unload_time = 12
+filament_unloading_speed = 20
+filament_unloading_speed_start = 120
+filament_loading_speed_start = 19
+
+[filament:Generic PET MMU2]
+inherits = *PET MMU2*
+
+[filament:Prusa PET MMU2]
+inherits = *PET MMU2*
+
+[filament:Prusament PETG MMU2]
+inherits = *PET MMU2*
+
+[filament:Prusa PLA]
+inherits = *PLA*
+filament_cost = 25.4
+filament_density = 1.24
+filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
+
+[filament:Prusament PLA]
+inherits = *PLA*
+temperature = 215
+filament_cost = 24.99
+filament_density = 1.24
+filament_notes = "Affordable filament for everyday printing in premium quality manufactured in-house by Josef Prusa"
+
+[filament:*PLA MMU2*]
+inherits = Prusa PLA
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
+temperature = 205
+filament_cooling_final_speed = 2
+filament_cooling_initial_speed = 3
+filament_cooling_moves = 1
+filament_load_time = 15
+filament_loading_speed = 14
+filament_ramming_parameters = "130 120 2.70968 2.93548 3.32258 3.83871 4.58065 5.54839 6.51613 7.35484 7.93548 8.16129| 0.05 2.66451 0.45 3.05805 0.95 4.05807 1.45 5.97742 1.95 7.69999 2.45 8.1936 2.95 11.342 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_unload_time = 12
+filament_unloading_speed = 20
+filament_loading_speed_start = 19
+filament_minimal_purge_on_wipe_tower = 15
+filament_unloading_speed_start = 100
+
+[filament:Generic PLA MMU2]
+inherits = *PLA MMU2*
+
+[filament:Prusa PLA MMU2]
+inherits = *PLA MMU2*
+
+[filament:Prusament PLA MMU2]
+inherits = *PLA MMU2*
+
+[filament:SemiFlex or Flexfill 98A]
+inherits = *FLEX*
+filament_cost = 82
+filament_density = 1.22
+
+[filament:Taulman Bridge]
+inherits = *common*
+filament_cost = 40
+filament_density = 1.13
+bed_temperature = 90
+bridge_fan_speed = 40
+cooling = 0
+disable_fan_first_layers = 3
+fan_always_on = 0
+fan_below_layer_time = 20
+filament_colour = #DEE0E6
+filament_max_volumetric_speed = 10
+filament_soluble = 0
+filament_type = PET
+first_layer_bed_temperature = 60
+first_layer_temperature = 240
+max_fan_speed = 5
+min_fan_speed = 0
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 250
+
+[filament:Taulman T-Glase]
+inherits = *PET*
+filament_cost = 40
+filament_density = 1.27
+bridge_fan_speed = 40
+cooling = 0
+fan_always_on = 0
+first_layer_bed_temperature = 90
+first_layer_temperature = 240
+max_fan_speed = 5
+min_fan_speed = 0
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
+
+[filament:Verbatim BVOH]
+inherits = *common*
+filament_cost = 218
+filament_density = 1.23
+bed_temperature = 60
+bridge_fan_speed = 100
+cooling = 0
+disable_fan_first_layers = 1
+extrusion_multiplier = 1
+fan_always_on = 0
+fan_below_layer_time = 100
+filament_colour = #FFFFD7
+filament_max_volumetric_speed = 4
+filament_notes = "List of materials tested with standart PLA print settings:\n\nDas Filament\nEsun PLA\nEUMAKERS PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nVerbatim PLA\nVerbatim BVOH"
+filament_soluble = 1
+filament_type = PLA
+first_layer_bed_temperature = 60
+first_layer_temperature = 215
+max_fan_speed = 100
+min_fan_speed = 100
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 210
+
+[filament:Verbatim BVOH MMU2]
+inherits = Verbatim BVOH
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
+temperature = 195
+filament_notes = BVOH
+fan_always_on = 1
+first_layer_temperature = 200
+filament_cooling_final_speed = 1
+filament_cooling_initial_speed = 2
+filament_max_volumetric_speed = 4
+filament_type = PLA
+filament_cooling_moves = 1
+filament_load_time = 15
+filament_loading_speed = 14
+filament_ramming_parameters = "120 110 1.74194 1.90323 2.16129 2.48387 2.83871 3.25806 3.83871 4.6129 5.41935 5.96774| 0.05 1.69677 0.45 1.96128 0.95 2.63872 1.45 3.46129 1.95 4.99031 2.45 6.12908 2.95 8.30974 3.45 11.4065 3.95 7.6 4.45 7.6 4.95 7.6"
+filament_unload_time = 12
+filament_unloading_speed = 20
+filament_unloading_speed_start = 100
+filament_loading_speed_start = 19
+
+[filament:PrimaSelect PVA+ MMU2]
+inherits = *common*
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_MK(2.5|3).*/ and single_extruder_multi_material
+bed_temperature = 60
+bridge_fan_speed = 100
+cooling = 0
+disable_fan_first_layers = 1
+fan_always_on = 0
+fan_below_layer_time = 100
+filament_colour = #FFFFD7
+filament_cooling_final_speed = 2
+filament_cooling_initial_speed = 4
+filament_cooling_moves = 2
+filament_cost = 25.4
+filament_density = 1.24
+filament_diameter = 1.75
+filament_load_time = 15
+filament_loading_speed = 14
+filament_loading_speed_start = 19
+filament_max_volumetric_speed = 4
+filament_minimal_purge_on_wipe_tower = 5
+filament_notes = PVA
+filament_ramming_parameters = "120 110 3.83871 3.90323 3.96774 4.03226 4.09677 4.19355 4.3871 4.83871 5.67742 6.93548 8.54839 10.3226 11.9677 13.2581 14.129 14.5806| 0.05 3.8258 0.45 3.89676 0.95 4.05807 1.45 4.23548 1.95 5.18386 2.45 7.80651 2.95 11.5356 3.45 13.9872 3.95 14.7613 4.45 7.6 4.95 7.6"
+filament_soluble = 1
+filament_toolchange_delay = 0
+filament_type = PLA
+filament_unload_time = 12
+filament_unloading_speed = 20
+filament_unloading_speed_start = 100
+first_layer_bed_temperature = 60
+first_layer_temperature = 200
+max_fan_speed = 100
+min_fan_speed = 100
+min_print_speed = 15
+slowdown_below_layer_time = 20
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}30{endif}; Filament gcode"
+temperature = 195
+
+[filament:Verbatim PP]
+inherits = *common*
+filament_cost = 72
+filament_density = 0.89
+bed_temperature = 100
+bridge_fan_speed = 100
+cooling = 1
+disable_fan_first_layers = 2
+extrusion_multiplier = 1
+fan_always_on = 1
+fan_below_layer_time = 100
+filament_colour = #DEE0E6
+filament_max_volumetric_speed = 5
+filament_notes = "List of materials tested with standart PLA print settings:\n\nEsun PLA\nFiberlogy HD-PLA\nFillamentum PLA\nFloreon3D\nHatchbox PLA\nPlasty Mladec PLA\nPrimavalue PLA\nProto pasta Matte Fiber\nEUMAKERS PLA"
+filament_type = PLA
+first_layer_bed_temperature = 100
+first_layer_temperature = 220
+max_fan_speed = 100
+min_fan_speed = 100
+start_filament_gcode = "M900 K{if printer_notes=~/.*PRINTER_HAS_BOWDEN.*/}200{else}10{endif}; Filament gcode"
+temperature = 220
+
+[sla_print:*common*]
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
+layer_height = 0.05
+output_filename_format = [input_filename_base].dwz
+pad_edge_radius = 0.5
+pad_enable = 1
+pad_max_merge_distance = 50
+pad_wall_height = 3
+pad_wall_thickness = 1
+support_base_diameter = 3
+support_base_height = 0.5
+support_critical_angle = 45
+support_density_at_45 = 250
+support_density_at_horizontal = 500
+support_head_front_diameter = 0.4
+support_head_penetration = 0.4
+support_head_width = 3
+support_max_bridge_length = 10
+support_minimal_z = 0
+support_object_elevation = 5
+support_pillar_diameter = 1
+support_pillar_widening_factor = 0
+supports_enable = 1
+
+[sla_print:0.025 UltraDetail]
+inherits = *common*
+layer_height = 0.025
+support_head_width = 2
+
+[sla_print:0.035 Detail]
+inherits = *common*
+layer_height = 0.035
+
+[sla_print:0.05 Normal]
+inherits = *common*
+layer_height = 0.05
+
+[sla_print:0.1 Fast]
+inherits = *common*
+layer_height = 0.1
+
+########### Materials 0.025
+
+[sla_material:*common 0.05*]
+compatible_printers_condition = printer_notes=~/.*PRINTER_VENDOR_PRUSA3D.*/ and printer_notes=~/.*PRINTER_MODEL_SL1.*/
+compatible_prints_condition = layer_height == 0.05
+exposure_time = 12
+initial_exposure_time = 45
+initial_layer_height = 0.05
+material_correction_curing = 1,1,1
+material_correction_printing = 1,1,1
+material_notes =
+
+[sla_material:*common 0.025*]
+inherits = *common 0.05*
+compatible_prints_condition = layer_height == 0.025
+exposure_time = 10
+initial_exposure_time = 35
+initial_layer_height = 0.025
+
+[sla_material:*common 0.035*]
+inherits = *common 0.05*
+compatible_prints_condition = layer_height == 0.035
+exposure_time = 13
+initial_exposure_time = 40
+initial_layer_height = 0.035
+
+[sla_material:*common 0.1*]
+inherits = *common 0.05*
+compatible_prints_condition = layer_height == 0.1
+exposure_time = 20
+initial_exposure_time = 90
+initial_layer_height = 0.1
+
+########### Materials 0.025
+
+[sla_material:Bluecast Phrozen Wax 0.025]
+inherits = *common 0.025*
+exposure_time = 8
+initial_exposure_time = 45
+
+[sla_material:Jamg He PJHC-30 Orange 0.025]
+inherits = *common 0.025*
+exposure_time = 5
+initial_exposure_time = 35
+
+########### Materials 0.05
+
+[sla_material:3DM-HTR140 (high temperature) 0.05]
+inherits = *common 0.05*
+exposure_time = 12
+initial_exposure_time = 45
+
+[sla_material:Bluecast Ecogray 0.05]
+inherits = *common 0.05*
+exposure_time = 8
+initial_exposure_time = 45
+
+[sla_material:Bluecast Keramaster 0.05]
+inherits = *common 0.05*
+exposure_time = 8
+initial_exposure_time = 45
+
+[sla_material:Bluecast Phrozen Wax 0.05]
+inherits = *common 0.05*
+exposure_time = 10
+initial_exposure_time = 55
+
+[sla_material:Jamg He PJHC-00 Yellow 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 45
+
+[sla_material:Jamg He PJHC-19 Skin 0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 45
+
+[sla_material:Jamg He PJHC-30 Orange 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 45
+
+[sla_material:Jamg He PJHC-60 Gray 0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 45
+
+[sla_material:Jamg He PJHC-70 Black 0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 45
+
+[sla_material:Monocure 3D Black Rapid Resin 0.05]
+inherits = *common 0.05*
+exposure_time = 6
+initial_exposure_time = 40
+
+[sla_material:Monocure 3D Blue Rapid Resin 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 40
+
+[sla_material:Monocure 3D Clear Rapid Resin 0.05]
+inherits = *common 0.05*
+exposure_time = 8
+initial_exposure_time = 40
+
+[sla_material:Monocure 3D Gray Rapid Resin 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 40
+
+[sla_material:Monocure 3D White Rapid Resin 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 40
+
+# v2
+
+[sla_material:3DM-ABS 0.05]
+inherits = *common 0.05*
+exposure_time = 9
+initial_exposure_time = 35
+
+[sla_material:3DM-DENT 0.05]
+inherits = *common 0.05*
+exposure_time = 7
+initial_exposure_time = 45
+
+[sla_material:3DM-HR Green 0.05]
+inherits = *common 0.05*
+exposure_time = 15
+initial_exposure_time = 40
+
+[sla_material:3DM-HR Red Wine 0.05]
+inherits = *common 0.05*
+exposure_time = 9
+initial_exposure_time = 35
+
+[sla_material:3DM-XPRO White 0.05]
+inherits = *common 0.05*
+exposure_time = 9
+initial_exposure_time = 35
+
+[sla_material:FTD Ash Grey 0.05]
+inherits = *common 0.05*
+exposure_time = 9
+initial_exposure_time = 40
+
+[sla_material:Jamg He LOC-19 Super Low Odor Skin 0.05]
+inherits = *common 0.05*
+exposure_time = 7.5
+initial_exposure_time = 40
+
+[sla_material:Jamg He LOC-20 Super Low Odor White 0.05]
+inherits = *common 0.05*
+exposure_time = 6.5
+initial_exposure_time = 40
+
+[sla_material:Jamg He LOC-60 Super Low Odor Grey 0.05]
+inherits = *common 0.05*
+exposure_time = 6.5
+initial_exposure_time = 40
+
+########### Materials 0.035
+
+[sla_material:Jamg He PJHC-30 Orange 0.035]
+inherits = *common 0.035*
+exposure_time = 9
+initial_exposure_time = 35
+
+########### Materials 0.1
+
+[sla_material:Jamg He PJHC-30 Orange 0.1]
+inherits = *common 0.1*
+exposure_time = 10
+initial_exposure_time = 45
+
+[printer:*common*]
+printer_technology = FFF
+bed_shape = 0x0,250x0,250x210,0x210
+before_layer_gcode = ;BEFORE_LAYER_CHANGE\nG92 E0.0\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\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
+extruder_colour = #FFFF00
+extruder_offset = 0x0
+gcode_flavor = marlin
+silent_mode = 0
+remaining_times = 0
+machine_max_acceleration_e = 10000
+machine_max_acceleration_extruding = 2000
+machine_max_acceleration_retracting = 1500
+machine_max_acceleration_x = 9000
+machine_max_acceleration_y = 9000
+machine_max_acceleration_z = 500
+machine_max_feedrate_e = 120
+machine_max_feedrate_x = 500
+machine_max_feedrate_y = 500
+machine_max_feedrate_z = 12
+machine_max_jerk_e = 2.5
+machine_max_jerk_x = 10
+machine_max_jerk_y = 10
+machine_max_jerk_z = 0.2
+machine_min_extruding_rate = 0
+machine_min_travel_rate = 0
+layer_gcode = ;AFTER_LAYER_CHANGE\n;[layer_z]
+max_layer_height = 0.25
+min_layer_height = 0.07
+max_print_height = 200
+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 = 4
+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\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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_model = MK2S
+printer_variant = 0.4
+default_print_profile = 0.15mm OPTIMAL
+default_filament_profile = Prusament PLA
+
+[printer:*multimaterial*]
+inherits = *common*
+deretract_speed = 50
+retract_before_travel = 3
+retract_before_wipe = 60%
+retract_layer_change = 0
+retract_length = 4
+retract_lift = 0.6
+retract_lift_above = 0
+retract_lift_below = 199
+retract_restart_extra = 0
+retract_restart_extra_toolchange = 0
+retract_speed = 80
+parking_pos_retraction = 92
+cooling_tube_length = 5
+cooling_tube_retraction = 91.5
+single_extruder_multi_material = 1
+variable_layer_height = 1
+printer_model = MK2SMM
+
+[printer:*mm-single*]
+inherits = *multimaterial*
+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 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors\n\n
+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
+start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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\nG92 E0.0
+default_print_profile = 0.15mm OPTIMAL
+
+[printer:*mm-multi*]
+inherits = *multimaterial*
+high_current_on_filament_swap = 1
+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 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nG28 X0 ; home X axis\nM84 ; disable motors
+extruder_colour = #FFAA55;#E37BA0;#4ECDD3;#FB7259
+nozzle_diameter = 0.4,0.4,0.4,0.4
+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
+start_gcode = M115 U3.1.0 ; tell printer latest fw version\nM204 S[machine_max_acceleration_extruding] T[machine_max_acceleration_retracting] ; MK2 firmware only supports the old M204 format\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_single_extruder_multi_material_priming}\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\n{endif}\nG92 E0.0
+default_print_profile = 0.15mm OPTIMAL
+
+# XXXXXXXXXXXXXXXXX
+# XXX--- MK2 ---XXX
+# XXXXXXXXXXXXXXXXX
+
+[printer:Original Prusa i3 MK2S]
+inherits = *common*
+
+[printer:Original Prusa i3 MK2S 0.25 nozzle]
+inherits = *common*
+max_layer_height = 0.15
+min_layer_height = 0.05
+nozzle_diameter = 0.25
+retract_length = 1
+retract_speed = 50
+variable_layer_height = 1
+printer_variant = 0.25
+default_print_profile = 0.10mm DETAIL 0.25 nozzle
+
+[printer:Original Prusa i3 MK2S 0.6 nozzle]
+inherits = *common*
+max_layer_height = 0.35
+min_layer_height = 0.1
+nozzle_diameter = 0.6
+printer_variant = 0.6
+default_print_profile = 0.20mm NORMAL 0.6 nozzle
+
+# XXXXXXXXXXXXXXXXXXX
+# XXX--- MK2MM ---XXX
+# XXXXXXXXXXXXXXXXXXX
+
+[printer:Original Prusa i3 MK2S MMU1 Single]
+inherits = *mm-single*
+max_layer_height = 0.25
+min_layer_height = 0.07
+
+[printer:Original Prusa i3 MK2S MMU1 Single 0.6 nozzle]
+inherits = *mm-single*
+nozzle_diameter = 0.6
+printer_variant = 0.6
+default_print_profile = 0.20mm NORMAL 0.6 nozzle
+max_layer_height = 0.35
+min_layer_height = 0.1
+
+[printer:Original Prusa i3 MK2S MMU1]
+inherits = *mm-multi*
+nozzle_diameter = 0.4,0.4,0.4,0.4
+max_layer_height = 0.25
+min_layer_height = 0.07
+
+[printer:Original Prusa i3 MK2S MMU1 0.6 nozzle]
+inherits = *mm-multi*
+nozzle_diameter = 0.6,0.6,0.6,0.6
+printer_variant = 0.6
+default_print_profile = 0.20mm NORMAL 0.6 nozzle
+max_layer_height = 0.35
+min_layer_height = 0.1
+
+# XXXXXXXXXXXXXXXXXXX
+# XXX--- MK2.5 ---XXX
+# XXXXXXXXXXXXXXXXXXX
+
+[printer:Original Prusa i3 MK2.5]
+inherits = Original Prusa i3 MK2S
+printer_model = MK2.5
+remaining_times = 1
+start_gcode = M115 U3.5.1 ; 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
+
+[printer:Original Prusa i3 MK2.5 0.25 nozzle]
+inherits = Original Prusa i3 MK2S 0.25 nozzle
+printer_model = MK2.5
+remaining_times = 1
+start_gcode = M115 U3.5.1 ; 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
+
+[printer:Original Prusa i3 MK2.5 0.6 nozzle]
+inherits = Original Prusa i3 MK2S 0.6 nozzle
+printer_model = MK2.5
+remaining_times = 1
+start_gcode = M115 U3.5.1 ; 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
+
+[printer:Original Prusa i3 MK2.5 MMU2 Single]
+inherits = Original Prusa i3 MK2.5; *mm2*
+printer_model = MK2.5MMU2
+single_extruder_multi_material = 0
+max_print_height = 200
+remaining_times = 1
+silent_mode = 0
+retract_lift_below = 199
+machine_max_acceleration_e = 10000
+machine_max_acceleration_extruding = 2000
+machine_max_acceleration_retracting = 1500
+machine_max_acceleration_x = 9000
+machine_max_acceleration_y = 9000
+machine_max_acceleration_z = 500
+machine_max_feedrate_e = 120
+machine_max_feedrate_x = 500
+machine_max_feedrate_y = 500
+machine_max_feedrate_z = 12
+machine_max_jerk_e = 2.5
+machine_max_jerk_x = 10
+machine_max_jerk_y = 10
+machine_max_jerk_z = 0.2
+machine_min_extruding_rate = 0
+machine_min_travel_rate = 0
+default_print_profile = 0.15mm OPTIMAL MK2.5
+default_filament_profile = Prusament PLA
+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.5\n
+start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
+
+[printer:Original Prusa i3 MK2.5 MMU2]
+inherits = Original Prusa i3 MK2.5; *mm2*
+printer_model = MK2.5MMU2
+max_print_height = 200
+remaining_times = 1
+silent_mode = 0
+retract_lift_below = 199
+machine_max_acceleration_e = 10000
+machine_max_acceleration_extruding = 2000
+machine_max_acceleration_retracting = 1500
+machine_max_acceleration_x = 9000
+machine_max_acceleration_y = 9000
+machine_max_acceleration_z = 500
+machine_max_feedrate_e = 120
+machine_max_feedrate_x = 500
+machine_max_feedrate_y = 500
+machine_max_feedrate_z = 12
+machine_max_jerk_e = 2.5
+machine_max_jerk_x = 10
+machine_max_jerk_y = 10
+machine_max_jerk_z = 0.2
+machine_min_extruding_rate = 0
+machine_min_travel_rate = 0
+default_print_profile = 0.15mm OPTIMAL MK2.5
+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.5\n
+single_extruder_multi_material = 1
+# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
+# (for example the retract values) are duplicaed from the first value, so they do not need
+# to be defined explicitely.
+nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
+extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
+start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
+
+[printer:Original Prusa i3 MK2.5S]
+inherits = Original Prusa i3 MK2.5
+printer_model = MK2.5S
+
+[printer:Original Prusa i3 MK2.5S 0.25 nozzle]
+inherits = Original Prusa i3 MK2.5 0.25 nozzle
+printer_model = MK2.5S
+
+[printer:Original Prusa i3 MK2.5S 0.6 nozzle]
+inherits = Original Prusa i3 MK2.5 0.6 nozzle
+printer_model = MK2.5S
+
+[printer:Original Prusa i3 MK2.5S MMU2S Single]
+inherits = Original Prusa i3 MK2.5; *mm2s*
+printer_model = MK2.5SMMU2S
+single_extruder_multi_material = 0
+max_print_height = 200
+remaining_times = 1
+silent_mode = 0
+retract_lift_below = 199
+machine_max_acceleration_e = 10000
+machine_max_acceleration_extruding = 2000
+machine_max_acceleration_retracting = 1500
+machine_max_acceleration_x = 9000
+machine_max_acceleration_y = 9000
+machine_max_acceleration_z = 500
+machine_max_feedrate_e = 120
+machine_max_feedrate_x = 500
+machine_max_feedrate_y = 500
+machine_max_feedrate_z = 12
+machine_max_jerk_e = 2.5
+machine_max_jerk_x = 10
+machine_max_jerk_y = 10
+machine_max_jerk_z = 0.2
+machine_min_extruding_rate = 0
+machine_min_travel_rate = 0
+default_print_profile = 0.15mm OPTIMAL MK2.5
+default_filament_profile = Prusament PLA
+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.5\n
+start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
+
+[printer:Original Prusa i3 MK2.5S MMU2S]
+inherits = Original Prusa i3 MK2.5; *mm2s*
+printer_model = MK2.5SMMU2S
+max_print_height = 200
+remaining_times = 1
+silent_mode = 0
+retract_lift_below = 199
+machine_max_acceleration_e = 10000
+machine_max_acceleration_extruding = 2000
+machine_max_acceleration_retracting = 1500
+machine_max_acceleration_x = 9000
+machine_max_acceleration_y = 9000
+machine_max_acceleration_z = 500
+machine_max_feedrate_e = 120
+machine_max_feedrate_x = 500
+machine_max_feedrate_y = 500
+machine_max_feedrate_z = 12
+machine_max_jerk_e = 2.5
+machine_max_jerk_x = 10
+machine_max_jerk_y = 10
+machine_max_jerk_z = 0.2
+machine_min_extruding_rate = 0
+machine_min_travel_rate = 0
+default_print_profile = 0.15mm OPTIMAL MK2.5
+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.5\n
+single_extruder_multi_material = 1
+# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
+# (for example the retract values) are duplicaed from the first value, so they do not need
+# to be defined explicitely.
+nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
+extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
+start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
+
+
+# XXXXXXXXXXXXXXXXX
+# XXX--- MK3 ---XXX
+# XXXXXXXXXXXXXXXXX
+
+[printer:Original Prusa i3 MK3]
+inherits = *common*
+end_gcode = G4 ; wait\nM221 S100\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors
+machine_max_acceleration_e = 5000,5000
+machine_max_acceleration_extruding = 1250,1250
+machine_max_acceleration_retracting = 1250,1250
+machine_max_acceleration_x = 1000,960
+machine_max_acceleration_y = 1000,960
+machine_max_acceleration_z = 1000,1000
+machine_max_feedrate_e = 120,120
+machine_max_feedrate_x = 200,100
+machine_max_feedrate_y = 200,100
+machine_max_feedrate_z = 12,12
+machine_max_jerk_e = 1.5,1.5
+machine_max_jerk_x = 8,8
+machine_max_jerk_y = 8,8
+machine_max_jerk_z = 0.4,0.4
+machine_min_extruding_rate = 0,0
+machine_min_travel_rate = 0,0
+silent_mode = 1
+remaining_times = 1
+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_lift_below = 209
+max_print_height = 210
+start_gcode = M115 U3.5.1 ; 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\nM221 S{if layer_height<0.075}100{else}95{endif}
+printer_model = MK3
+default_print_profile = 0.15mm QUALITY MK3
+
+[printer:Original Prusa i3 MK3 0.25 nozzle]
+inherits = Original Prusa i3 MK3
+nozzle_diameter = 0.25
+max_layer_height = 0.15
+min_layer_height = 0.05
+printer_variant = 0.25
+default_print_profile = 0.10mm DETAIL 0.25 nozzle MK3
+
+[printer:Original Prusa i3 MK3 0.6 nozzle]
+inherits = Original Prusa i3 MK3
+nozzle_diameter = 0.6
+max_layer_height = 0.35
+min_layer_height = 0.1
+printer_variant = 0.6
+default_print_profile = 0.15mm OPTIMAL 0.6 nozzle MK3
+
+[printer:Original Prusa i3 MK3S]
+inherits = Original Prusa i3 MK3
+printer_model = MK3S
+
+[printer:Original Prusa i3 MK3S 0.25 nozzle]
+inherits = Original Prusa i3 MK3 0.25 nozzle
+printer_model = MK3S
+
+[printer:Original Prusa i3 MK3S 0.6 nozzle]
+inherits = Original Prusa i3 MK3 0.6 nozzle
+printer_model = MK3S
+
+[printer:*mm2*]
+inherits = Original Prusa i3 MK3
+single_extruder_multi_material = 1
+cooling_tube_length = 10
+cooling_tube_retraction = 30
+parking_pos_retraction = 85
+retract_length_toolchange = 3
+extra_loading_move = -13
+printer_model = MK3MMU2
+default_print_profile = 0.15mm QUALITY MK3
+default_filament_profile = Prusament PLA MMU2
+
+[printer:*mm2s*]
+inherits = Original Prusa i3 MK3
+single_extruder_multi_material = 1
+cooling_tube_length = 20
+cooling_tube_retraction = 40
+parking_pos_retraction = 85
+retract_length_toolchange = 3
+extra_loading_move = -25
+printer_model = MK3SMMU2S
+default_print_profile = 0.15mm QUALITY MK3
+default_filament_profile = Prusament PLA MMU2
+
+[printer:Original Prusa i3 MK3 MMU2 Single]
+inherits = *mm2*
+single_extruder_multi_material = 0
+default_filament_profile = Prusament PLA
+start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
+
+[printer:Original Prusa i3 MK3 MMU2]
+inherits = *mm2*
+# The 5x nozzle diameter defines the number of extruders. Other extruder parameters
+# (for example the retract values) are duplicaed from the first value, so they do not need
+# to be defined explicitely.
+machine_max_acceleration_e = 8000,8000
+nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
+extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
+start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E32.0 F1073.0\nG1 X5.0 E32.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
+
+[printer:Original Prusa i3 MK3S MMU2S Single]
+inherits = *mm2s*
+single_extruder_multi_material = 0
+default_filament_profile = Prusament PLA
+start_gcode = M107\nM115 U3.5.1 ; 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\nTx\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\n\nG21 ; set units to millimeters\n\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nTc\n; purge line\nG1 X55.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = G1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\nG1 X0 Y200; home X axis\nM84 ; disable motors
+
+[printer:Original Prusa i3 MK3S MMU2S]
+inherits = *mm2s*
+machine_max_acceleration_e = 8000,8000
+nozzle_diameter = 0.4,0.4,0.4,0.4,0.4
+extruder_colour = #FF8000;#DB5182;#00FFFF;#FF4F4F;#9FFF9F
+start_gcode = M107\nM115 U3.5.1 ; 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\nG21 ; set units to millimeters\n\n; Send the filament type to the MMU2.0 unit.\n; E stands for extruder number, F stands for filament type (0: default; 1:flex; 2: PVA)\nM403 E0 F{"" + ((filament_type[0]=="FLEX") ? 1 : ((filament_type[0]=="PVA") ? 2 : 0))}\nM403 E1 F{"" + ((filament_type[1]=="FLEX") ? 1 : ((filament_type[1]=="PVA") ? 2 : 0))}\nM403 E2 F{"" + ((filament_type[2]=="FLEX") ? 1 : ((filament_type[2]=="PVA") ? 2 : 0))}\nM403 E3 F{"" + ((filament_type[3]=="FLEX") ? 1 : ((filament_type[3]=="PVA") ? 2 : 0))}\nM403 E4 F{"" + ((filament_type[4]=="FLEX") ? 1 : ((filament_type[4]=="PVA") ? 2 : 0))}\n\n{if not has_single_extruder_multi_material_priming}\n;go outside print area\nG1 Y-3.0 F1000.0\nG1 Z0.4 F1000.0\n; select extruder\nT[initial_tool]\n; initial load\nG1 X55.0 E29.0 F1073.0\nG1 X5.0 E29.0 F1800.0\nG1 X55.0 E8.0 F2000.0\nG1 Z0.3 F1000.0\nG92 E0.0\nG1 X240.0 E25.0 F2200.0\nG1 Y-2.0 F1000.0\nG1 X55.0 E25 F1400.0\nG1 Z0.20 F1000.0\nG1 X5.0 E4.0 F1000.0\nG92 E0.0\n{endif}\n\nM221 S{if layer_height<0.075}100{else}95{endif}\nG90 ; use absolute coordinates\nM83 ; use relative distances for extrusion\nG92 E0.0\n
+end_gcode = {if has_wipe_tower}\nG1 E-15.0000 F3000\n{else}\nG1 X0 Y210 F7200\nG1 E2 F5000\nG1 E2 F5500\nG1 E2 F6000\nG1 E-15.0000 F5800\nG1 E-20.0000 F5500\nG1 E10.0000 F3000\nG1 E-10.0000 F3100\nG1 E10.0000 F3150\nG1 E-10.0000 F3250\nG1 E10.0000 F3300\n{endif}\n\n; Unload filament\nM702 C\n\nG4 ; wait\nM104 S0 ; turn off temperature\nM140 S0 ; turn off heatbed\nM107 ; turn off fan\n; Lift print head a bit\n{if layer_z < max_print_height}G1 Z{z_offset+min(layer_z+30, max_print_height)}{endif} ; Move print head up\nG1 X0 Y200; home X axis\nM84 ; disable motors\n
+
+[printer:Original Prusa SL1]
+printer_technology = SLA
+printer_model = SL1
+printer_variant = default
+default_sla_material_profile = Jamg He Transparent Green 0.05
+default_sla_print_profile = 0.05 Normal
+bed_shape = 0.98x1.02,119.98x1.02,119.98x68.02,0.98x68.02
+display_height = 68.04
+display_orientation = portrait
+display_pixels_x = 2560
+display_pixels_y = 1440
+display_width = 120.96
+max_print_height = 150
+printer_correction = 1,1,1
+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_SL1\n
+
+# The obsolete presets will be removed when upgrading from the legacy configuration structure (up to Slic3r 1.39.2) to 1.40.0 and newer.
+[obsolete_presets]
+print="0.05mm DETAIL 0.25 nozzle";"0.05mm DETAIL MK3";"0.05mm DETAIL";"0.20mm NORMAL MK3";"0.35mm FAST MK3";"print:0.15mm OPTIMAL MK3 MMU2";"print:0.20mm FAST MK3 MMU2"
+filament="ColorFabb Brass Bronze 1.75mm";"ColorFabb HT 1.75mm";"ColorFabb nGen 1.75mm";"ColorFabb Woodfil 1.75mm";"ColorFabb XT 1.75mm";"ColorFabb XT-CF20 1.75mm";"E3D PC-ABS 1.75mm";"Fillamentum ABS 1.75mm";"Fillamentum ASA 1.75mm";"Generic ABS 1.75mm";"Generic PET 1.75mm";"Generic PLA 1.75mm";"Prusa ABS 1.75mm";"Prusa HIPS 1.75mm";"Prusa PET 1.75mm";"Prusa PLA 1.75mm";"Taulman Bridge 1.75mm";"Taulman T-Glase 1.75mm"
diff --git a/resources/shaders/printbed.fs b/resources/shaders/printbed.fs
new file mode 100644
index 0000000000..be14347c21
--- /dev/null
+++ b/resources/shaders/printbed.fs
@@ -0,0 +1,20 @@
+#version 110
+
+const vec3 back_color_dark = vec3(0.235, 0.235, 0.235);
+const vec3 back_color_light = vec3(0.365, 0.365, 0.365);
+
+uniform sampler2D texture;
+uniform bool transparent_background;
+
+varying vec2 tex_coords;
+
+void main()
+{
+ // calculates radial gradient
+ vec3 back_color = vec3(mix(back_color_light, back_color_dark, smoothstep(0.0, 0.5, length(abs(tex_coords.xy) - vec2(0.5)))));
+
+ vec4 fore_color = texture2D(texture, tex_coords);
+
+ // blends foreground with background
+ gl_FragColor = vec4(mix(back_color, fore_color.rgb, fore_color.a), transparent_background ? fore_color.a : 1.0);
+}
\ No newline at end of file
diff --git a/resources/shaders/printbed.vs b/resources/shaders/printbed.vs
new file mode 100644
index 0000000000..968bcce16a
--- /dev/null
+++ b/resources/shaders/printbed.vs
@@ -0,0 +1,11 @@
+#version 110
+
+attribute vec2 v_tex_coords;
+
+varying vec2 tex_coords;
+
+void main()
+{
+ gl_Position = ftransform();
+ tex_coords = v_tex_coords;
+}
\ No newline at end of file
diff --git a/sandboxes/slabasebed/CMakeLists.txt b/sandboxes/slabasebed/CMakeLists.txt
index bff5ca5887..9d731a1333 100644
--- a/sandboxes/slabasebed/CMakeLists.txt
+++ b/sandboxes/slabasebed/CMakeLists.txt
@@ -1,2 +1,2 @@
add_executable(slabasebed EXCLUDE_FROM_ALL slabasebed.cpp)
-target_link_libraries(slabasebed libslic3r)
\ No newline at end of file
+target_link_libraries(slabasebed libslic3r ${Boost_LIBRARIES} ${TBB_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_DL_LIBS})
diff --git a/sandboxes/slabasebed/slabasebed.cpp b/sandboxes/slabasebed/slabasebed.cpp
index 9804ea3c94..3237416097 100644
--- a/sandboxes/slabasebed/slabasebed.cpp
+++ b/sandboxes/slabasebed/slabasebed.cpp
@@ -1,15 +1,29 @@
#include
+#include
#include
#include
#include
#include
+#include
#include
const std::string USAGE_STR = {
"Usage: slabasebed stlfilename.stl"
};
+namespace Slic3r { namespace sla {
+
+Contour3D convert(const Polygons& triangles, coord_t z, bool dir);
+Contour3D walls(const Polygon& floor_plate, const Polygon& ceiling,
+ double floor_z_mm, double ceiling_z_mm,
+ double offset_difference_mm, ThrowOnCancel thr);
+
+void offset(ExPolygon& sh, coord_t distance);
+
+}
+}
+
int main(const int argc, const char *argv[]) {
using namespace Slic3r;
using std::cout; using std::endl;
@@ -26,18 +40,43 @@ int main(const int argc, const char *argv[]) {
model.align_to_origin();
ExPolygons ground_slice;
- TriangleMesh basepool;
+ sla::Contour3D mesh;
+// TriangleMesh basepool;
sla::base_plate(model, ground_slice, 0.1f);
+ if(ground_slice.empty()) return EXIT_FAILURE;
+
+ ExPolygon bottom_plate = ground_slice.front();
+ ExPolygon top_plate = bottom_plate;
+ sla::offset(top_plate, coord_t(3.0/SCALING_FACTOR));
+ sla::offset(bottom_plate, coord_t(1.0/SCALING_FACTOR));
+
bench.start();
- sla::create_base_pool(ground_slice, basepool);
+
+ Polygons top_plate_triangles, bottom_plate_triangles;
+ top_plate.triangulate_p2t(&top_plate_triangles);
+ bottom_plate.triangulate_p2t(&bottom_plate_triangles);
+
+ auto top_plate_mesh = sla::convert(top_plate_triangles, coord_t(3.0/SCALING_FACTOR), false);
+ auto bottom_plate_mesh = sla::convert(bottom_plate_triangles, 0, true);
+
+ mesh.merge(bottom_plate_mesh);
+ mesh.merge(top_plate_mesh);
+
+ sla::Contour3D w = sla::walls(bottom_plate.contour, top_plate.contour, 0, 3, 2.0, [](){});
+
+ mesh.merge(w);
+// sla::create_base_pool(ground_slice, basepool);
bench.stop();
cout << "Base pool creation time: " << std::setprecision(10)
<< bench.getElapsedSec() << " seconds." << endl;
- basepool.write_ascii("out.stl");
+// basepool.write_ascii("out.stl");
+
+ std::fstream outstream("out.obj", std::fstream::out);
+ mesh.to_obj(outstream);
return EXIT_SUCCESS;
}
diff --git a/src/avrdude/ac_cfg.h b/src/avrdude/ac_cfg.h
index 2461bf3071..41d648bf12 100644
--- a/src/avrdude/ac_cfg.h
+++ b/src/avrdude/ac_cfg.h
@@ -169,22 +169,22 @@
#define LT_OBJDIR ".libs/"
/* Name of package */
-#define PACKAGE "avrdude"
+#define PACKAGE "avrdude-slic3r"
/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT "avrdude-dev@nongnu.org"
+#define PACKAGE_BUGREPORT "https://github.com/prusa3d/Slic3r/issues"
/* Define to the full name of this package. */
-#define PACKAGE_NAME "avrdude"
+#define PACKAGE_NAME "avrdude-slic3r"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "avrdude 6.3-20160220"
/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME "avrdude"
+#define PACKAGE_TARNAME "avrdude-slic3r"
/* Define to the home page for this package. */
-#define PACKAGE_URL ""
+#define PACKAGE_URL "https://github.com/prusa3d/Slic3r"
/* Define to the version of this package. */
#define PACKAGE_VERSION "6.3-20160220"
diff --git a/src/avrdude/avrdude-slic3r.cpp b/src/avrdude/avrdude-slic3r.cpp
index 3037f52848..debf204a80 100644
--- a/src/avrdude/avrdude-slic3r.cpp
+++ b/src/avrdude/avrdude-slic3r.cpp
@@ -96,13 +96,20 @@ void AvrDude::priv::unset_handlers()
int AvrDude::priv::run_one(const std::vector &args) {
- std::vector c_args {{ const_cast(PACKAGE_NAME) }};
+ std::vector c_args {{ const_cast(PACKAGE) }};
+ std::string command_line { PACKAGE };
+
for (const auto &arg : args) {
c_args.push_back(const_cast(arg.data()));
+ command_line.push_back(' ');
+ command_line.append(arg);
}
+ command_line.push_back('\n');
HandlerGuard guard(*this);
+ message_fn(command_line.c_str(), command_line.size());
+
const auto res = ::avrdude_main(static_cast(c_args.size()), c_args.data(), sys_config.c_str());
return res;
diff --git a/src/avrdude/main.c b/src/avrdude/main.c
index 9ada27be35..80a9b3737a 100644
--- a/src/avrdude/main.c
+++ b/src/avrdude/main.c
@@ -1082,6 +1082,7 @@ int avrdude_main(int argc, char * argv [], const char *sys_config)
if (rc < 0) {
exitrc = 1;
pgm->ppidata = 0; /* clear all bits at exit */
+ avrdude_message(MSG_INFO, "%s: Could not open port: %s\n", progname, port);
goto main_exit;
}
is_open = 1;
diff --git a/src/libslic3r/Fill/Fill.cpp b/src/libslic3r/Fill/Fill.cpp
index 016d162d84..75952e4c23 100644
--- a/src/libslic3r/Fill/Fill.cpp
+++ b/src/libslic3r/Fill/Fill.cpp
@@ -69,7 +69,9 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.is_solid() && (!surface.is_bridge() || layerm.layer()->id() == 0)) {
group_attrib[i].is_solid = true;
group_attrib[i].flow_width = (surface.surface_type == stTop) ? top_solid_infill_flow.width : solid_infill_flow.width;
- group_attrib[i].pattern = surface.is_external() ? layerm.region()->config().external_fill_pattern.value : ipRectilinear;
+ group_attrib[i].pattern = surface.is_external() ?
+ (surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
+ ipRectilinear;
}
}
// Loop through solid groups, find compatible groups and append them to this one.
@@ -161,7 +163,7 @@ void make_fill(LayerRegion &layerm, ExtrusionEntityCollection &out)
if (surface.is_solid()) {
density = 100.;
fill_pattern = (surface.is_external() && ! is_bridge) ?
- layerm.region()->config().external_fill_pattern.value :
+ (surface.is_top() ? layerm.region()->config().top_fill_pattern.value : layerm.region()->config().bottom_fill_pattern.value) :
ipRectilinear;
} else if (density <= 0)
continue;
diff --git a/src/libslic3r/Format/3mf.cpp b/src/libslic3r/Format/3mf.cpp
index 8b0c28cd6f..47f78b3606 100644
--- a/src/libslic3r/Format/3mf.cpp
+++ b/src/libslic3r/Format/3mf.cpp
@@ -323,7 +323,7 @@ namespace Slic3r {
typedef std::map IdToMetadataMap;
typedef std::map IdToGeometryMap;
typedef std::map> IdToLayerHeightsProfileMap;
- typedef std::map> IdToSlaSupportPointsMap;
+ typedef std::map> IdToSlaSupportPointsMap;
// Version of the 3mf file
unsigned int m_version;
@@ -776,10 +776,19 @@ namespace Slic3r {
std::vector objects;
boost::split(objects, buffer, boost::is_any_of("\n"), boost::token_compress_off);
+ // Info on format versioning - see 3mf.hpp
+ int version = 0;
+ if (!objects.empty() && objects[0].find("support_points_format_version=") != std::string::npos) {
+ objects[0].erase(objects[0].begin(), objects[0].begin() + 30); // removes the string
+ version = std::stoi(objects[0]);
+ objects.erase(objects.begin()); // pop the header
+ }
+
for (const std::string& object : objects)
{
std::vector object_data;
boost::split(object_data, object, boost::is_any_of("|"), boost::token_compress_off);
+
if (object_data.size() != 2)
{
add_error("Error while reading object data");
@@ -811,10 +820,24 @@ namespace Slic3r {
std::vector object_data_points;
boost::split(object_data_points, object_data[1], boost::is_any_of(" "), boost::token_compress_off);
- std::vector sla_support_points;
+ std::vector sla_support_points;
- for (unsigned int i=0; i());
+ if (version == 0) {
+ for (unsigned int i=0; iname = metadata.value;
else if ((metadata.key == MODIFIER_KEY) && (metadata.value == "1"))
- volume->set_type(ModelVolume::PARAMETER_MODIFIER);
+ volume->set_type(ModelVolumeType::PARAMETER_MODIFIER);
else if (metadata.key == VOLUME_TYPE_KEY)
volume->set_type(ModelVolume::type_from_string(metadata.value));
else
@@ -1961,7 +1984,7 @@ namespace Slic3r {
for (const ModelObject* object : model.objects)
{
++count;
- const std::vector& sla_support_points = object->sla_support_points;
+ const std::vector& sla_support_points = object->sla_support_points;
if (!sla_support_points.empty())
{
sprintf(buffer, "object_id=%d|", count);
@@ -1970,7 +1993,7 @@ namespace Slic3r {
// Store the layer height profile as a single space separated list.
for (size_t i = 0; i < sla_support_points.size(); ++i)
{
- sprintf(buffer, (i==0 ? "%f %f %f" : " %f %f %f"), sla_support_points[i](0), sla_support_points[i](1), sla_support_points[i](2));
+ sprintf(buffer, (i==0 ? "%f %f %f %f %f" : " %f %f %f %f %f"), sla_support_points[i].pos(0), sla_support_points[i].pos(1), sla_support_points[i].pos(2), sla_support_points[i].head_front_radius, (float)sla_support_points[i].is_new_island);
out += buffer;
}
out += "\n";
@@ -1979,6 +2002,9 @@ namespace Slic3r {
if (!out.empty())
{
+ // Adds version header at the beginning:
+ out = std::string("support_points_format_version=") + std::to_string(support_points_format_version) + std::string("\n") + out;
+
if (!mz_zip_writer_add_mem(&archive, SLA_SUPPORT_POINTS_FILE.c_str(), (const void*)out.data(), out.length(), MZ_DEFAULT_COMPRESSION))
{
add_error("Unable to add sla support points file to archive");
diff --git a/src/libslic3r/Format/3mf.hpp b/src/libslic3r/Format/3mf.hpp
index 44b37c1aee..b5927651ec 100644
--- a/src/libslic3r/Format/3mf.hpp
+++ b/src/libslic3r/Format/3mf.hpp
@@ -3,6 +3,23 @@
namespace Slic3r {
+ /* The format for saving the SLA points was changing in the past. This enum holds the latest version that is being currently used.
+ * Examples of the Slic3r_PE_sla_support_points.txt for historically used versions:
+
+ * version 0 : object_id=1|-12.055421 -2.658771 10.000000
+ object_id=2|-14.051745 -3.570338 5.000000
+ // no header and x,y,z positions of the points)
+
+ * version 1 : ThreeMF_support_points_version=1
+ object_id=1|-12.055421 -2.658771 10.000000 0.4 0.0
+ object_id=2|-14.051745 -3.570338 5.000000 0.6 1.0
+ // introduced header with version number; x,y,z,head_size,is_new_island)
+ */
+
+ enum {
+ support_points_format_version = 1
+ };
+
class Model;
class DynamicPrintConfig;
diff --git a/src/libslic3r/Format/AMF.cpp b/src/libslic3r/Format/AMF.cpp
index 9791b15022..2f5284db94 100644
--- a/src/libslic3r/Format/AMF.cpp
+++ b/src/libslic3r/Format/AMF.cpp
@@ -583,7 +583,7 @@ void AMFParserContext::endElement(const char * /* name */)
else if (m_path.size() == 3 && m_path[1] == NODE_TYPE_OBJECT && m_object && strcmp(opt_key, "sla_support_points") == 0) {
// Parse object's layer height profile, a semicolon separated list of floats.
unsigned char coord_idx = 0;
- Vec3f point(Vec3f::Zero());
+ Eigen::Matrix point(Eigen::Matrix::Zero());
char *p = const_cast(m_value[1].c_str());
for (;;) {
char *end = strchr(p, ';');
@@ -591,8 +591,8 @@ void AMFParserContext::endElement(const char * /* name */)
*end = 0;
point(coord_idx) = atof(p);
- if (++coord_idx == 3) {
- m_object->sla_support_points.push_back(point);
+ if (++coord_idx == 5) {
+ m_object->sla_support_points.push_back(sla::SupportPoint(point));
coord_idx = 0;
}
if (end == nullptr)
@@ -604,7 +604,7 @@ void AMFParserContext::endElement(const char * /* name */)
if (strcmp(opt_key, "modifier") == 0) {
// Is this volume a modifier volume?
// "modifier" flag comes first in the XML file, so it may be later overwritten by the "type" flag.
- m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolume::PARAMETER_MODIFIER : ModelVolume::MODEL_PART);
+ m_volume->set_type((atoi(m_value[1].c_str()) == 1) ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART);
} else if (strcmp(opt_key, "volume_type") == 0) {
m_volume->set_type(ModelVolume::type_from_string(m_value[1]));
}
@@ -900,14 +900,14 @@ bool store_amf(const char *path, Model *model, const DynamicPrintConfig *config)
}
//FIXME Store the layer height ranges (ModelObject::layer_height_ranges)
- const std::vector& sla_support_points = object->sla_support_points;
+ const std::vector& sla_support_points = object->sla_support_points;
if (!sla_support_points.empty()) {
// Store the SLA supports as a single semicolon separated list.
stream << " ";
for (size_t i = 0; i < sla_support_points.size(); ++i) {
if (i != 0)
stream << ";";
- stream << sla_support_points[i](0) << ";" << sla_support_points[i](1) << ";" << sla_support_points[i](2);
+ stream << sla_support_points[i].pos(0) << ";" << sla_support_points[i].pos(1) << ";" << sla_support_points[i].pos(2) << ";" << sla_support_points[i].head_front_radius << ";" << sla_support_points[i].is_new_island;
}
stream << "\n \n";
}
diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp
index 4227172796..6e291412c2 100644
--- a/src/libslic3r/Model.cpp
+++ b/src/libslic3r/Model.cpp
@@ -1480,32 +1480,32 @@ const TriangleMesh& ModelVolume::get_convex_hull() const
return m_convex_hull;
}
-ModelVolume::Type ModelVolume::type_from_string(const std::string &s)
+ModelVolumeType ModelVolume::type_from_string(const std::string &s)
{
// Legacy support
if (s == "1")
- return PARAMETER_MODIFIER;
+ return ModelVolumeType::PARAMETER_MODIFIER;
// New type (supporting the support enforcers & blockers)
if (s == "ModelPart")
- return MODEL_PART;
+ return ModelVolumeType::MODEL_PART;
if (s == "ParameterModifier")
- return PARAMETER_MODIFIER;
+ return ModelVolumeType::PARAMETER_MODIFIER;
if (s == "SupportEnforcer")
- return SUPPORT_ENFORCER;
+ return ModelVolumeType::SUPPORT_ENFORCER;
if (s == "SupportBlocker")
- return SUPPORT_BLOCKER;
+ return ModelVolumeType::SUPPORT_BLOCKER;
assert(s == "0");
// Default value if invalud type string received.
- return MODEL_PART;
+ return ModelVolumeType::MODEL_PART;
}
-std::string ModelVolume::type_to_string(const Type t)
+std::string ModelVolume::type_to_string(const ModelVolumeType t)
{
switch (t) {
- case MODEL_PART: return "ModelPart";
- case PARAMETER_MODIFIER: return "ParameterModifier";
- case SUPPORT_ENFORCER: return "SupportEnforcer";
- case SUPPORT_BLOCKER: return "SupportBlocker";
+ case ModelVolumeType::MODEL_PART: return "ModelPart";
+ case ModelVolumeType::PARAMETER_MODIFIER: return "ParameterModifier";
+ case ModelVolumeType::SUPPORT_ENFORCER: return "SupportEnforcer";
+ case ModelVolumeType::SUPPORT_BLOCKER: return "SupportBlocker";
default:
assert(false);
return "ModelPart";
@@ -1671,7 +1671,7 @@ bool model_object_list_extended(const Model &model_old, const Model &model_new)
return true;
}
-bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type)
+bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type)
{
bool modifiers_differ = false;
size_t i_old, i_new;
diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp
index b998fbb7db..a215f9b9f1 100644
--- a/src/libslic3r/Model.hpp
+++ b/src/libslic3r/Model.hpp
@@ -12,6 +12,7 @@
#include
#include
#include "Geometry.hpp"
+#include
namespace Slic3r {
@@ -48,6 +49,8 @@ struct ModelID
bool operator<=(const ModelID &rhs) const { return this->id <= rhs.id; }
bool operator>=(const ModelID &rhs) const { return this->id >= rhs.id; }
+ bool valid() const { return id != 0; }
+
size_t id;
};
@@ -175,7 +178,8 @@ public:
// This vector holds position of selected support points for SLA. The data are
// saved in mesh coordinates to allow using them for several instances.
- std::vector sla_support_points;
+ // The format is (x, y, z, point_size, supports_island)
+ std::vector sla_support_points;
/* This vector accumulates the total translation applied to the object by the
center_around_origin() method. Callers might want to apply the same translation
@@ -291,6 +295,15 @@ private:
mutable bool m_raw_mesh_bounding_box_valid;
};
+// Declared outside of ModelVolume, so it could be forward declared.
+enum class ModelVolumeType : int {
+ INVALID = -1,
+ MODEL_PART = 0,
+ PARAMETER_MODIFIER,
+ SUPPORT_ENFORCER,
+ SUPPORT_BLOCKER,
+};
+
// An object STL, or a modifier volume, over which a different set of parameters shall be applied.
// ModelVolume instances are owned by a ModelObject.
class ModelVolume : public ModelBase
@@ -303,23 +316,15 @@ public:
// overriding the global Slic3r settings and the ModelObject settings.
DynamicPrintConfig config;
- enum Type {
- MODEL_TYPE_INVALID = -1,
- MODEL_PART = 0,
- PARAMETER_MODIFIER,
- SUPPORT_ENFORCER,
- SUPPORT_BLOCKER,
- };
-
// A parent object owning this modifier volume.
ModelObject* get_object() const { return this->object; };
- Type type() const { return m_type; }
- void set_type(const Type t) { m_type = t; }
- bool is_model_part() const { return m_type == MODEL_PART; }
- bool is_modifier() const { return m_type == PARAMETER_MODIFIER; }
- bool is_support_enforcer() const { return m_type == SUPPORT_ENFORCER; }
- bool is_support_blocker() const { return m_type == SUPPORT_BLOCKER; }
- bool is_support_modifier() const { return m_type == SUPPORT_BLOCKER || m_type == SUPPORT_ENFORCER; }
+ ModelVolumeType type() const { return m_type; }
+ void set_type(const ModelVolumeType t) { m_type = t; }
+ bool is_model_part() const { return m_type == ModelVolumeType::MODEL_PART; }
+ bool is_modifier() const { return m_type == ModelVolumeType::PARAMETER_MODIFIER; }
+ bool is_support_enforcer() const { return m_type == ModelVolumeType::SUPPORT_ENFORCER; }
+ bool is_support_blocker() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER; }
+ bool is_support_modifier() const { return m_type == ModelVolumeType::SUPPORT_BLOCKER || m_type == ModelVolumeType::SUPPORT_ENFORCER; }
t_model_material_id material_id() const { return m_material_id; }
void set_material_id(t_model_material_id material_id);
ModelMaterial* material() const;
@@ -353,8 +358,8 @@ public:
const TriangleMesh& get_convex_hull() const;
// Helpers for loading / storing into AMF / 3MF files.
- static Type type_from_string(const std::string &s);
- static std::string type_to_string(const Type t);
+ static ModelVolumeType type_from_string(const std::string &s);
+ static std::string type_to_string(const ModelVolumeType t);
const Geometry::Transformation& get_transformation() const { return m_transformation; }
void set_transformation(const Geometry::Transformation& transformation) { m_transformation = transformation; }
@@ -399,7 +404,7 @@ private:
// Parent object owning this ModelVolume.
ModelObject* object;
// Is it an object to be printed, or a modifier volume?
- Type m_type;
+ ModelVolumeType m_type;
t_model_material_id m_material_id;
// The convex hull of this model's mesh.
TriangleMesh m_convex_hull;
@@ -411,13 +416,13 @@ private:
// 1 -> is splittable
int m_is_splittable {-1};
- ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(MODEL_PART), object(object)
+ ModelVolume(ModelObject *object, const TriangleMesh &mesh) : mesh(mesh), m_type(ModelVolumeType::MODEL_PART), object(object)
{
if (mesh.stl.stats.number_of_facets > 1)
calculate_convex_hull();
}
ModelVolume(ModelObject *object, TriangleMesh &&mesh, TriangleMesh &&convex_hull) :
- mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(MODEL_PART), object(object) {}
+ mesh(std::move(mesh)), m_convex_hull(std::move(convex_hull)), m_type(ModelVolumeType::MODEL_PART), object(object) {}
// Copying an existing volume, therefore this volume will get a copy of the ID assigned.
ModelVolume(ModelObject *object, const ModelVolume &other) :
@@ -629,7 +634,7 @@ extern bool model_object_list_extended(const Model &model_old, const Model &mode
// Test whether the new ModelObject contains a different set of volumes (or sorted in a different order)
// than the old ModelObject.
-extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolume::Type type);
+extern bool model_volume_list_changed(const ModelObject &model_object_old, const ModelObject &model_object_new, const ModelVolumeType type);
#ifndef NDEBUG
// Verify whether the IDs of Model / ModelObject / ModelVolume / ModelInstance / ModelMaterial are valid and unique.
diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp
index d456fb9c6c..a03e6f436a 100644
--- a/src/libslic3r/Point.hpp
+++ b/src/libslic3r/Point.hpp
@@ -22,6 +22,7 @@ typedef Point Vector;
// Vector types with a fixed point coordinate base type.
typedef Eigen::Matrix Vec2crd;
typedef Eigen::Matrix Vec3crd;
+typedef Eigen::Matrix Vec2i;
typedef Eigen::Matrix Vec3i;
typedef Eigen::Matrix Vec2i64;
typedef Eigen::Matrix Vec3i64;
diff --git a/src/libslic3r/Print.cpp b/src/libslic3r/Print.cpp
index 6416a709ad..87e78f11c1 100644
--- a/src/libslic3r/Print.cpp
+++ b/src/libslic3r/Print.cpp
@@ -280,7 +280,7 @@ bool Print::is_step_done(PrintObjectStep step) const
return false;
tbb::mutex::scoped_lock lock(this->state_mutex());
for (const PrintObject *object : m_objects)
- if (! object->m_state.is_done_unguarded(step))
+ if (! object->is_step_done_unguarded(step))
return false;
return true;
}
@@ -549,10 +549,14 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con
assert(! it->second); // not consumed yet
it->second = true;
ModelVolume *model_volume_dst = const_cast(it->first);
- assert(model_volume_dst->type() == model_volume_src->type());
+ // For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
+ assert((model_volume_dst->is_support_modifier() && model_volume_src->is_support_modifier()) || model_volume_dst->type() == model_volume_src->type());
model_object_dst.volumes.emplace_back(model_volume_dst);
- if (model_volume_dst->is_support_modifier())
- model_volume_dst->set_transformation(model_volume_src->get_transformation());
+ if (model_volume_dst->is_support_modifier()) {
+ // For support modifiers, the type may have been switched from blocker to enforcer and vice versa.
+ model_volume_dst->set_type(model_volume_src->type());
+ model_volume_dst->set_transformation(model_volume_src->get_transformation());
+ }
assert(model_volume_dst->get_matrix().isApprox(model_volume_src->get_matrix()));
} else {
// The volume was not found in the old list. Create a new copy.
@@ -567,7 +571,7 @@ void Print::model_volume_list_update_supports(ModelObject &model_object_dst, con
delete mv_with_status.first;
}
-static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolume::Type type)
+static inline void model_volume_list_copy_configs(ModelObject &model_object_dst, const ModelObject &model_object_src, const ModelVolumeType type)
{
size_t i_src, i_dst;
for (i_src = 0, i_dst = 0; i_src < model_object_src.volumes.size() && i_dst < model_object_dst.volumes.size();) {
@@ -713,7 +717,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
if (model.id() != m_model.id()) {
// Kill everything, initialize from scratch.
// Stop background processing.
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_all_steps());
for (PrintObject *object : m_objects) {
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
@@ -745,7 +749,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
} else {
// Reorder the objects, add new objects.
// First stop background processing before shuffling or deleting the PrintObjects in the object list.
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_step(psGCodeExport));
// Second create a new list of objects.
std::vector model_objects_old(std::move(m_model.objects));
@@ -837,10 +841,10 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved);
const ModelObject &model_object_new = *model.objects[idx_model_object];
// Check whether a model part volume was added or removed, their transformations or order changed.
- bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART);
- bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::PARAMETER_MODIFIER);
- bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_BLOCKER);
- bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::SUPPORT_ENFORCER);
+ bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
+ bool modifiers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::PARAMETER_MODIFIER);
+ bool support_blockers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_BLOCKER);
+ bool support_enforcers_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::SUPPORT_ENFORCER);
if (model_parts_differ || modifiers_differ ||
model_object.origin_translation != model_object_new.origin_translation ||
model_object.layer_height_ranges != model_object_new.layer_height_ranges ||
@@ -855,7 +859,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
model_object.assign_copy(model_object_new);
} else if (support_blockers_differ || support_enforcers_differ) {
// First stop background processing before shuffling or deleting the ModelVolumes in the ModelObject's list.
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(false);
// Invalidate just the supports step.
auto range = print_object_status.equal_range(PrintObjectStatus(model_object.id()));
@@ -882,8 +886,8 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
}
// Synchronize (just copy) the remaining data of ModelVolumes (name, config).
//FIXME What to do with m_material_id?
- model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolume::MODEL_PART);
- model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolume::PARAMETER_MODIFIER);
+ model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::MODEL_PART);
+ model_volume_list_copy_configs(model_object /* dst */, model_object_new /* src */, ModelVolumeType::PARAMETER_MODIFIER);
// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
model_object.name = model_object_new.name;
model_object.input_file = model_object_new.input_file;
@@ -956,7 +960,7 @@ Print::ApplyStatus Print::apply(const Model &model, const DynamicPrintConfig &co
}
}
if (m_objects != print_objects_new) {
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_all_steps());
m_objects = print_objects_new;
// Delete the PrintObjects marked as Unknown or Deleted.
@@ -1502,7 +1506,8 @@ void Print::export_gcode(const std::string &path_template, GCodePreviewData *pre
// The following call may die if the output_filename_format template substitution fails.
std::string path = this->output_filepath(path_template);
std::string message = "Exporting G-code";
- if (! path.empty()) {
+ if (! path.empty() && preview_data == nullptr) {
+ // Only show the path if preview_data is not set -> running from command line.
message += " to ";
message += path;
}
@@ -1863,7 +1868,7 @@ std::string Print::output_filename() const
DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
return this->PrintBase::output_filename(m_config.output_filename_format.value, "gcode", &config);
}
-
+/*
// Shorten the dhms time by removing the seconds, rounding the dhm to full minutes
// and removing spaces.
static std::string short_time(const std::string &time)
@@ -1903,7 +1908,7 @@ static std::string short_time(const std::string &time)
::sprintf(buffer, "%ds", seconds);
return buffer;
}
-
+*/
DynamicConfig PrintStatistics::config() const
{
DynamicConfig config;
diff --git a/src/libslic3r/PrintBase.hpp b/src/libslic3r/PrintBase.hpp
index 84d04d26fe..e01b678a53 100644
--- a/src/libslic3r/PrintBase.hpp
+++ b/src/libslic3r/PrintBase.hpp
@@ -62,6 +62,10 @@ public:
return state;
}
+ bool is_started(StepType step, tbb::mutex &mtx) const {
+ return this->state_with_timestamp(step, mtx).state == STARTED;
+ }
+
bool is_done(StepType step, tbb::mutex &mtx) const {
return this->state_with_timestamp(step, mtx).state == DONE;
}
@@ -70,6 +74,10 @@ public:
return m_state[step];
}
+ bool is_started_unguarded(StepType step) const {
+ return this->state_with_timestamp_unguarded(step).state == STARTED;
+ }
+
bool is_done_unguarded(StepType step) const {
return this->state_with_timestamp_unguarded(step).state == DONE;
}
@@ -235,7 +243,24 @@ public:
virtual ApplyStatus apply(const Model &model, const DynamicPrintConfig &config) = 0;
const Model& model() const { return m_model; }
+ struct TaskParams {
+ TaskParams() : single_model_object(0), single_model_instance_only(false), to_object_step(-1), to_print_step(-1) {}
+ // If non-empty, limit the processing to this ModelObject.
+ ModelID single_model_object;
+ // If set, only process single_model_object. Otherwise process everything, but single_model_object first.
+ bool single_model_instance_only;
+ // If non-negative, stop processing at the successive object step.
+ int to_object_step;
+ // If non-negative, stop processing at the successive print step.
+ int to_print_step;
+ };
+ // After calling the apply() function, call set_task() to limit the task to be processed by process().
+ virtual void set_task(const TaskParams ¶ms) {}
+ // Perform the calculation. This is the only method that is to be called at a worker thread.
virtual void process() = 0;
+ // Clean up after process() finished, either with success, error or if canceled.
+ // The adjustments on the Print / PrintObject data due to set_task() are to be reverted here.
+ virtual void finalize() {}
struct SlicingStatus {
SlicingStatus(int percent, const std::string &text, unsigned int flags = 0) : percent(percent), text(text), flags(flags) {}
@@ -244,8 +269,9 @@ public:
// Bitmap of flags.
enum FlagBits {
DEFAULT,
- NO_RELOAD_SCENE = 0,
- RELOAD_SCENE = 1,
+ NO_RELOAD_SCENE = 0,
+ RELOAD_SCENE = 1 << 1,
+ RELOAD_SLA_SUPPORT_POINTS = 1 << 2,
};
// Bitmap of FlagBits
unsigned int flags;
@@ -300,7 +326,7 @@ protected:
tbb::mutex& state_mutex() const { return m_state_mutex; }
std::function cancel_callback() { return m_cancel_callback; }
- void call_cancell_callback() { m_cancel_callback(); }
+ void call_cancel_callback() { m_cancel_callback(); }
// If the background processing stop was requested, throw CanceledException.
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
@@ -349,6 +375,9 @@ protected:
bool invalidate_all_steps()
{ return m_state.invalidate_all(this->cancel_callback()); }
+ bool is_step_started_unguarded(PrintStepEnum step) const { return m_state.is_started_unguarded(step); }
+ bool is_step_done_unguarded(PrintStepEnum step) const { return m_state.is_done_unguarded(step); }
+
private:
PrintState m_state;
};
@@ -382,6 +411,9 @@ protected:
bool invalidate_all_steps()
{ return m_state.invalidate_all(PrintObjectBase::cancel_callback(m_print)); }
+ bool is_step_started_unguarded(PrintObjectStepEnum step) const { return m_state.is_started_unguarded(step); }
+ bool is_step_done_unguarded(PrintObjectStepEnum step) const { return m_state.is_done_unguarded(step); }
+
protected:
// If the background processing stop was requested, throw CanceledException.
// To be called by the worker thread and its sub-threads (mostly launched on the TBB thread pool) regularly.
diff --git a/src/libslic3r/PrintConfig.cpp b/src/libslic3r/PrintConfig.cpp
index 3e1ee9f9f8..cc644fc748 100644
--- a/src/libslic3r/PrintConfig.cpp
+++ b/src/libslic3r/PrintConfig.cpp
@@ -362,12 +362,11 @@ void PrintConfigDef::init_fff_params()
def->mode = comAdvanced;
def->default_value = new ConfigOptionBool(false);
- def = this->add("external_fill_pattern", coEnum);
- def->label = L("Top/bottom fill pattern");
+ auto def_top_fill_pattern = def = this->add("top_fill_pattern", coEnum);
+ def->label = L("Top fill pattern");
def->category = L("Infill");
- def->tooltip = L("Fill pattern for top/bottom infill. This only affects the external visible layer, "
- "and not its adjacent solid shells.");
- def->cli = "external-fill-pattern|solid-fill-pattern=s";
+ def->tooltip = L("Fill pattern for top infill. This only affects the top visible layer, and not its adjacent solid shells.");
+ def->cli = "top-fill-pattern|external-fill-pattern|solid-fill-pattern=s";
def->enum_keys_map = &ConfigOptionEnum::get_enum_values();
def->enum_values.push_back("rectilinear");
def->enum_values.push_back("concentric");
@@ -379,8 +378,15 @@ void PrintConfigDef::init_fff_params()
def->enum_labels.push_back(L("Hilbert Curve"));
def->enum_labels.push_back(L("Archimedean Chords"));
def->enum_labels.push_back(L("Octagram Spiral"));
- // solid_fill_pattern is an obsolete equivalent to external_fill_pattern.
- def->aliases = { "solid_fill_pattern" };
+ // solid_fill_pattern is an obsolete equivalent to top_fill_pattern/bottom_fill_pattern.
+ def->aliases = { "solid_fill_pattern", "external_fill_pattern" };
+ def->default_value = new ConfigOptionEnum(ipRectilinear);
+
+ def = this->add("bottom_fill_pattern", coEnum);
+ *def = *def_top_fill_pattern;
+ def->label = L("Bottom Pattern");
+ def->tooltip = L("Fill pattern for bottom infill. This only affects the bottom external visible layer, and not its adjacent solid shells.");
+ def->cli = "bottom-fill-pattern|external-fill-pattern|solid-fill-pattern=s";
def->default_value = new ConfigOptionEnum(ipRectilinear);
def = this->add("external_perimeter_extrusion_width", coFloatOrPercent);
@@ -2435,6 +2441,32 @@ void PrintConfigDef::init_sla_params()
def->enum_labels.push_back(L("Portrait"));
def->default_value = new ConfigOptionEnum(sladoPortrait);
+ def = this->add("fast_tilt_time", coFloat);
+ def->label = L("Fast");
+ def->full_label = L("Fast tilt");
+ def->tooltip = L("Time of the fast tilt");
+ def->sidetext = L("s");
+ def->min = 0;
+ def->mode = comExpert;
+ def->default_value = new ConfigOptionFloat(5.);
+
+ def = this->add("slow_tilt_time", coFloat);
+ def->label = L("Slow");
+ def->full_label = L("Slow tilt");
+ def->tooltip = L("Time of the slow tilt");
+ def->sidetext = L("s");
+ def->min = 0;
+ def->mode = comExpert;
+ def->default_value = new ConfigOptionFloat(8.);
+
+ def = this->add("area_fill", coFloat);
+ def->label = L("Area fill");
+ def->tooltip = L("The percentage of the bed area. \nIf the print area exceeds the specified value, \nthen a slow tilt will be used, otherwise - a fast tilt");
+ def->sidetext = L("%");
+ def->min = 0;
+ def->mode = comExpert;
+ def->default_value = new ConfigOptionFloat(50.);
+
def = this->add("printer_correction", coFloats);
def->full_label = L("Printer scaling correction");
def->tooltip = L("Printer scaling correction");
@@ -2450,6 +2482,14 @@ void PrintConfigDef::init_sla_params()
def->min = 0;
def->default_value = new ConfigOptionFloat(0.3);
+ def = this->add("faded_layers", coInt);
+ def->label = L("Faded layers");
+ def->tooltip = L("Number of the layers needed for the exposure time fade from initial exposure time to the exposure time");
+ def->min = 3;
+ def->max = 20;
+ def->mode = comExpert;
+ def->default_value = new ConfigOptionInt(10);
+
def = this->add("exposure_time", coFloat);
def->label = L("Exposure time");
def->tooltip = L("Exposure time");
@@ -2630,28 +2670,19 @@ void PrintConfigDef::init_sla_params()
def->min = 0;
def->default_value = new ConfigOptionFloat(5.0);
- def = this->add("support_density_at_horizontal", coInt);
- def->label = L("Density on horizontal surfaces");
+ def = this->add("support_points_density_relative", coInt);
+ def->label = L("Support points density");
def->category = L("Supports");
- def->tooltip = L("How many support points (approximately) should be placed on horizontal surface.");
- def->sidetext = L("points per square dm");
+ def->tooltip = L("This is a relative measure of support points density.");
+ def->sidetext = L("%");
def->cli = "";
def->min = 0;
- def->default_value = new ConfigOptionInt(500);
+ def->default_value = new ConfigOptionInt(100);
- def = this->add("support_density_at_45", coInt);
- def->label = L("Density on surfaces at 45 degrees");
+ def = this->add("support_points_minimal_distance", coFloat);
+ def->label = L("Minimal distance of the support points");
def->category = L("Supports");
- def->tooltip = L("How many support points (approximately) should be placed on surface sloping at 45 degrees.");
- def->sidetext = L("points per square dm");
- def->cli = "";
- def->min = 0;
- def->default_value = new ConfigOptionInt(250);
-
- def = this->add("support_minimal_z", coFloat);
- def->label = L("Minimal support point height");
- def->category = L("Supports");
- def->tooltip = L("No support points will be placed lower than this value from the bottom.");
+ def->tooltip = L("No support points will be placed closer than this threshold.");
def->sidetext = L("mm");
def->cli = "";
def->min = 0;
@@ -2699,6 +2730,17 @@ void PrintConfigDef::init_sla_params()
def->cli = "";
def->min = 0;
def->default_value = new ConfigOptionFloat(1.0);
+
+ def = this->add("pad_wall_tilt", coFloat);
+ def->label = L("Pad wall tilt");
+ def->category = L("Pad");
+ def->tooltip = L("The tilt of the pad wall relative to the bed plane. "
+ "90 degrees means straight walls.");
+ def->sidetext = L("degrees");
+ def->cli = "";
+ def->min = 0.1; // What should be the minimum?
+ def->max = 90;
+ def->default_value = new ConfigOptionFloat(45.0);
}
void PrintConfigDef::handle_legacy(t_config_option_key &opt_key, std::string &value)
@@ -2914,13 +2956,17 @@ std::string FullPrintConfig::validate()
if (! print_config_def.get("fill_pattern")->has_enum_value(this->fill_pattern.serialize()))
return "Invalid value for --fill-pattern";
- // --external-fill-pattern
- if (! print_config_def.get("external_fill_pattern")->has_enum_value(this->external_fill_pattern.serialize()))
- return "Invalid value for --external-fill-pattern";
+ // --top-fill-pattern
+ if (! print_config_def.get("top_fill_pattern")->has_enum_value(this->top_fill_pattern.serialize()))
+ return "Invalid value for --top-fill-pattern";
+
+ // --bottom-fill-pattern
+ if (! print_config_def.get("bottom_fill_pattern")->has_enum_value(this->bottom_fill_pattern.serialize()))
+ return "Invalid value for --bottom-fill-pattern";
// --fill-density
if (fabs(this->fill_density.value - 100.) < EPSILON &&
- ! print_config_def.get("external_fill_pattern")->has_enum_value(this->fill_pattern.serialize()))
+ ! print_config_def.get("top_fill_pattern")->has_enum_value(this->fill_pattern.serialize()))
return "The selected fill pattern is not supposed to work at 100% density";
// --infill-every-layers
diff --git a/src/libslic3r/PrintConfig.hpp b/src/libslic3r/PrintConfig.hpp
index 20c089d1c0..21bc32ed95 100644
--- a/src/libslic3r/PrintConfig.hpp
+++ b/src/libslic3r/PrintConfig.hpp
@@ -462,7 +462,8 @@ public:
ConfigOptionFloat bridge_flow_ratio;
ConfigOptionFloat bridge_speed;
ConfigOptionBool ensure_vertical_shell_thickness;
- ConfigOptionEnum external_fill_pattern;
+ ConfigOptionEnum top_fill_pattern;
+ ConfigOptionEnum bottom_fill_pattern;
ConfigOptionFloatOrPercent external_perimeter_extrusion_width;
ConfigOptionFloatOrPercent external_perimeter_speed;
ConfigOptionBool external_perimeters_first;
@@ -504,7 +505,8 @@ protected:
OPT_PTR(bridge_flow_ratio);
OPT_PTR(bridge_speed);
OPT_PTR(ensure_vertical_shell_thickness);
- OPT_PTR(external_fill_pattern);
+ OPT_PTR(top_fill_pattern);
+ OPT_PTR(bottom_fill_pattern);
OPT_PTR(external_perimeter_extrusion_width);
OPT_PTR(external_perimeter_speed);
OPT_PTR(external_perimeters_first);
@@ -958,6 +960,9 @@ class SLAPrintObjectConfig : public StaticPrintConfig
public:
ConfigOptionFloat layer_height;
+ //Number of the layers needed for the exposure time fade [3;20]
+ ConfigOptionInt faded_layers /*= 10*/;
+
// Enabling or disabling support creation
ConfigOptionBool supports_enable;
@@ -1002,9 +1007,8 @@ public:
ConfigOptionFloat support_object_elevation /*= 5.0*/;
/////// Following options influence automatic support points placement:
- ConfigOptionInt support_density_at_horizontal;
- ConfigOptionInt support_density_at_45;
- ConfigOptionFloat support_minimal_z;
+ ConfigOptionInt support_points_density_relative;
+ ConfigOptionFloat support_points_minimal_distance;
// Now for the base pool (pad) /////////////////////////////////////////////
@@ -1024,10 +1028,14 @@ public:
// The smoothing radius of the pad edges
ConfigOptionFloat pad_edge_radius /*= 1*/;
+ // The tilt of the pad wall...
+ ConfigOptionFloat pad_wall_tilt;
+
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
OPT_PTR(layer_height);
+ OPT_PTR(faded_layers);
OPT_PTR(supports_enable);
OPT_PTR(support_head_front_diameter);
OPT_PTR(support_head_penetration);
@@ -1040,15 +1048,15 @@ protected:
OPT_PTR(support_base_height);
OPT_PTR(support_critical_angle);
OPT_PTR(support_max_bridge_length);
- OPT_PTR(support_density_at_horizontal);
- OPT_PTR(support_density_at_45);
- OPT_PTR(support_minimal_z);
+ OPT_PTR(support_points_density_relative);
+ OPT_PTR(support_points_minimal_distance);
OPT_PTR(support_object_elevation);
OPT_PTR(pad_enable);
OPT_PTR(pad_wall_thickness);
OPT_PTR(pad_wall_height);
OPT_PTR(pad_max_merge_distance);
OPT_PTR(pad_edge_radius);
+ OPT_PTR(pad_wall_tilt);
}
};
@@ -1085,6 +1093,9 @@ public:
ConfigOptionInt display_pixels_y;
ConfigOptionEnum display_orientation;
ConfigOptionFloats printer_correction;
+ ConfigOptionFloat fast_tilt_time;
+ ConfigOptionFloat slow_tilt_time;
+ ConfigOptionFloat area_fill;
protected:
void initialize(StaticCacheBase &cache, const char *base_ptr)
{
@@ -1097,6 +1108,9 @@ protected:
OPT_PTR(display_pixels_y);
OPT_PTR(display_orientation);
OPT_PTR(printer_correction);
+ OPT_PTR(fast_tilt_time);
+ OPT_PTR(slow_tilt_time);
+ OPT_PTR(area_fill);
}
};
diff --git a/src/libslic3r/PrintExport.hpp b/src/libslic3r/PrintExport.hpp
index 5cfb552176..0df4058468 100644
--- a/src/libslic3r/PrintExport.hpp
+++ b/src/libslic3r/PrintExport.hpp
@@ -14,6 +14,17 @@
namespace Slic3r {
+// Used for addressing parameters of FilePrinter::set_statistics()
+enum ePrintStatistics
+{
+ psUsedMaterial = 0,
+ psNumFade,
+ psNumSlow,
+ psNumFast,
+
+ psCnt
+};
+
enum class FilePrinterFormat {
SLA_PNGZIP,
SVG
@@ -118,32 +129,39 @@ template<> class FilePrinter
double m_layer_height = .0;
Raster::Origin m_o = Raster::Origin::TOP_LEFT;
+ double m_used_material = 0.0;
+ int m_cnt_fade_layers = 0;
+ int m_cnt_slow_layers = 0;
+ int m_cnt_fast_layers = 0;
+
std::string createIniContent(const std::string& projectname) {
- double layer_height = m_layer_height;
+// double layer_height = m_layer_height;
using std::string;
using std::to_string;
auto expt_str = to_string(m_exp_time_s);
auto expt_first_str = to_string(m_exp_time_first_s);
- auto stepnum_str = to_string(static_cast(800*layer_height));
- auto layerh_str = to_string(layer_height);
+// auto stepnum_str = to_string(static_cast(800*layer_height));
+ auto layerh_str = to_string(m_layer_height);
+
+ const std::string cnt_fade_layers = to_string(m_cnt_fade_layers);
+ const std::string cnt_slow_layers = to_string(m_cnt_slow_layers);
+ const std::string cnt_fast_layers = to_string(m_cnt_fast_layers);
+ const std::string used_material = to_string(m_used_material);
return string(
"action = print\n"
"jobDir = ") + projectname + "\n" +
"expTime = " + expt_str + "\n"
"expTimeFirst = " + expt_first_str + "\n"
- "stepNum = " + stepnum_str + "\n"
- "wifiOn = 1\n"
- "tiltSlow = 60\n"
- "tiltFast = 15\n"
- "numFade = 10\n"
- "startdelay = 0\n"
+ "numFade = " + cnt_fade_layers + "\n"
"layerHeight = " + layerh_str + "\n"
- "noteInfo = "
- "expTime="+expt_str+"+resinType=generic+layerHeight="
- +layerh_str+"+printer=DWARF3\n";
+ "expTime = "+expt_str+" + resinType = generic+layerHeight = "
+ +layerh_str+" + printer = DWARF3\n"
+ "usedMaterial = " + used_material + "\n"
+ "numSlow = " + cnt_slow_layers + "\n"
+ "numFast = " + cnt_fast_layers + "\n";
}
public:
@@ -277,6 +295,17 @@ public:
out.close();
m_layers_rst[i].first.reset();
}
+
+ void set_statistics(const std::vector statistics)
+ {
+ if (statistics.size() != psCnt)
+ return;
+
+ m_used_material = statistics[psUsedMaterial];
+ m_cnt_fade_layers = int(statistics[psNumFade]);
+ m_cnt_slow_layers = int(statistics[psNumSlow]);
+ m_cnt_fast_layers = int(statistics[psNumFast]);
+ }
};
}
diff --git a/src/libslic3r/PrintObject.cpp b/src/libslic3r/PrintObject.cpp
index d516153a92..8fa1436818 100644
--- a/src/libslic3r/PrintObject.cpp
+++ b/src/libslic3r/PrintObject.cpp
@@ -498,7 +498,8 @@ bool PrintObject::invalidate_state_by_config_options(const std::vector
+
#include "SLAAutoSupports.hpp"
#include "Model.hpp"
#include "ExPolygon.hpp"
#include "SVG.hpp"
#include "Point.hpp"
#include "ClipperUtils.hpp"
+#include "Tesselate.hpp"
+#include "libslic3r.h"
#include
#include
namespace Slic3r {
-SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights,
- const Config& config, std::function throw_on_cancel)
-: m_config(config), m_V(emesh.V()), m_F(emesh.F()), m_throw_on_cancel(throw_on_cancel)
-{
- // FIXME: It might be safer to get rid of the rand() calls altogether, because it is probably
- // not always thread-safe and can be slow if it is.
- srand(time(NULL)); // rand() is used by igl::random_point_on_mesh
-
- // Find all separate islands that will need support. The coord_t number denotes height
- // of a point just below the mesh (so that we can later project the point precisely
- // on the mesh by raycasting (done by igl) and not risking we will place the point inside).
- std::vector> islands = find_islands(slices, heights);
-
- // Uniformly cover each of the islands with support points.
- for (const auto& island : islands) {
- std::vector points = uniformly_cover(island);
- m_throw_on_cancel();
- project_upward_onto_mesh(points);
- m_output.insert(m_output.end(), points.begin(), points.end());
- m_throw_on_cancel();
- }
-
- // We are done with the islands. Let's sprinkle the rest of the mesh.
- // The function appends to m_output.
- sprinkle_mesh(mesh);
-}
-
-
-float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2)
+/*float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2)
{
n1.normalize();
n2.normalize();
@@ -59,115 +35,6 @@ float SLAAutoSupports::approximate_geodesic_distance(const Vec3d& p1, const Vec3
}
-void SLAAutoSupports::sprinkle_mesh(const TriangleMesh& mesh)
-{
- std::vector points;
- // Loads the ModelObject raw_mesh and transforms it by first instance's transformation matrix (disregarding translation).
- // Instances only differ in z-rotation, so it does not matter which of them will be used for the calculation.
- // The supports point will be calculated on this mesh (so scaling ang vertical direction is correctly accounted for).
- // Results will be inverse-transformed to raw_mesh coordinates.
- //TriangleMesh mesh = m_model_object.raw_mesh();
- //Transform3d transformation_matrix = m_model_object.instances[0]->get_matrix(true/*dont_translate*/);
- //mesh.transform(transformation_matrix);
-
- // Check that the object is thick enough to produce any support points
- BoundingBoxf3 bb = mesh.bounding_box();
- if (bb.size()(2) < m_config.minimal_z)
- return;
-
- // All points that we curretly have must be transformed too, so distance to them is correcly calculated.
- //for (Vec3f& point : m_model_object.sla_support_points)
- // point = transformation_matrix.cast() * point;
-
-
- // In order to calculate distance to already placed points, we must keep know which facet the point lies on.
- std::vector facets_normals;
-
- // Only points belonging to islands were added so far - they all lie on horizontal surfaces:
- for (unsigned int i=0; i aabb;
- aabb.init(V, F);
- for (unsigned int i=0; i dump;
- Eigen::MatrixXf query_point = m_model_object.sla_support_points[i];
- aabb.squared_distance(V, F, query_point, facet_idx, dump);
- Vec3f a1 = V.row(F(facet_idx,1)) - V.row(F(facet_idx,0));
- Vec3f a2 = V.row(F(facet_idx,2)) - V.row(F(facet_idx,0));
- Vec3f normal = a1.cross(a2);
- normal.normalize();
- facets_normals.push_back(normal);
- }*/
-
- // New potential support point is randomly generated on the mesh and distance to all already placed points is calculated.
- // In case it is never smaller than certain limit (depends on the new point's facet normal), the point is accepted.
- // The process stops after certain number of points is refused in a row.
- Vec3d point;
- Vec3d normal;
- int added_points = 0;
- int refused_points = 0;
- const int refused_limit = 30;
- // Angle at which the density reaches zero:
- const float threshold_angle = std::min(M_PI_2, M_PI_4 * acos(0.f/m_config.density_at_horizontal) / acos(m_config.density_at_45/m_config.density_at_horizontal));
-
- size_t cancel_test_cntr = 0;
- while (refused_points < refused_limit) {
- if (++ cancel_test_cntr == 500) {
- // Don't call the cancellation routine too often as the multi-core cache synchronization
- // may be pretty expensive.
- m_throw_on_cancel();
- cancel_test_cntr = 0;
- }
- // Place a random point on the mesh and calculate corresponding facet's normal:
- Eigen::VectorXi FI;
- Eigen::MatrixXd B;
- igl::random_points_on_mesh(1, m_V, m_F, B, FI);
- point = B(0,0)*m_V.row(m_F(FI(0),0)) +
- B(0,1)*m_V.row(m_F(FI(0),1)) +
- B(0,2)*m_V.row(m_F(FI(0),2));
- if (point(2) - bb.min(2) < m_config.minimal_z)
- continue;
-
- Vec3d a1 = m_V.row(m_F(FI(0),1)) - m_V.row(m_F(FI(0),0));
- Vec3d a2 = m_V.row(m_F(FI(0),2)) - m_V.row(m_F(FI(0),0));
- normal = a1.cross(a2);
- normal.normalize();
-
- // calculate angle between the normal and vertical:
- float angle = angle_from_normal(normal.cast());
- if (angle > threshold_angle)
- continue;
-
- const float limit = distance_limit(angle);
- bool add_it = true;
- for (unsigned int i=0; i());
- facets_normals.push_back(normal);
- ++added_points;
- refused_points = 0;
- }
- }
-
- m_output.insert(m_output.end(), points.begin(), points.end());
-
- // Now transform all support points to mesh coordinates:
- //for (Vec3f& point : m_model_object.sla_support_points)
- // point = transformation_matrix.inverse().cast() * point;
-}
-
-
-
float SLAAutoSupports::get_required_density(float angle) const
{
// calculation would be density_0 * cos(angle). To provide one more degree of freedom, we will scale the angle
@@ -179,10 +46,470 @@ float SLAAutoSupports::get_required_density(float angle) const
float SLAAutoSupports::distance_limit(float angle) const
{
return 1./(2.4*get_required_density(angle));
+}*/
+
+SLAAutoSupports::SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices, const std::vector& heights,
+ const Config& config, std::function throw_on_cancel)
+: m_config(config), m_emesh(emesh), m_throw_on_cancel(throw_on_cancel)
+{
+ process(slices, heights);
+ project_onto_mesh(m_output);
+}
+
+void SLAAutoSupports::project_onto_mesh(std::vector& points) const
+{
+ // The function makes sure that all the points are really exactly placed on the mesh.
+ igl::Hit hit_up{0, 0, 0.f, 0.f, 0.f};
+ igl::Hit hit_down{0, 0, 0.f, 0.f, 0.f};
+
+ // Use a reasonable granularity to account for the worker thread synchronization cost.
+ tbb::parallel_for(tbb::blocked_range(0, points.size(), 64),
+ [this, &points](const tbb::blocked_range& range) {
+ for (size_t point_id = range.begin(); point_id < range.end(); ++ point_id) {
+ if ((point_id % 16) == 0)
+ // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
+ m_throw_on_cancel();
+ Vec3f& p = points[point_id].pos;
+ // Project the point upward and downward and choose the closer intersection with the mesh.
+ //bool up = igl::ray_mesh_intersect(p.cast(), Vec3f(0., 0., 1.), m_V, m_F, hit_up);
+ //bool down = igl::ray_mesh_intersect(p.cast(), Vec3f(0., 0., -1.), m_V, m_F, hit_down);
+
+ sla::EigenMesh3D::hit_result hit_up = m_emesh.query_ray_hit(p.cast(), Vec3d(0., 0., 1.));
+ sla::EigenMesh3D::hit_result hit_down = m_emesh.query_ray_hit(p.cast(), Vec3d(0., 0., -1.));
+
+ bool up = hit_up.face() != -1;
+ bool down = hit_down.face() != -1;
+
+ if (!up && !down)
+ continue;
+
+ sla::EigenMesh3D::hit_result& hit = (!down || (hit_up.distance() < hit_down.distance())) ? hit_up : hit_down;
+ //int fid = hit.face();
+ //Vec3f bc(1-hit.u-hit.v, hit.u, hit.v);
+ //p = (bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2))).cast();
+
+ p = p + (hit.distance() * hit.direction()).cast();
+ }
+ });
+}
+
+static std::vector make_layers(
+ const std::vector& slices, const std::vector& heights,
+ std::function throw_on_cancel)
+{
+ assert(slices.size() == heights.size());
+
+ // Allocate empty layers.
+ std::vector layers;
+ layers.reserve(slices.size());
+ for (size_t i = 0; i < slices.size(); ++ i)
+ layers.emplace_back(i, heights[i]);
+
+ // FIXME: calculate actual pixel area from printer config:
+ //const float pixel_area = pow(wxGetApp().preset_bundle->project_config.option("display_width") / wxGetApp().preset_bundle->project_config.option("display_pixels_x"), 2.f); //
+ const float pixel_area = pow(0.047f, 2.f);
+
+ // Use a reasonable granularity to account for the worker thread synchronization cost.
+ tbb::parallel_for(tbb::blocked_range(0, layers.size(), 32),
+ [&layers, &slices, &heights, pixel_area, throw_on_cancel](const tbb::blocked_range& range) {
+ for (size_t layer_id = range.begin(); layer_id < range.end(); ++ layer_id) {
+ if ((layer_id % 8) == 0)
+ // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
+ throw_on_cancel();
+ SLAAutoSupports::MyLayer &layer = layers[layer_id];
+ const ExPolygons &islands = slices[layer_id];
+ //FIXME WTF?
+ const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0]));
+ layer.islands.reserve(islands.size());
+ for (const ExPolygon &island : islands) {
+ float area = float(island.area() * SCALING_FACTOR * SCALING_FACTOR);
+ if (area >= pixel_area)
+ //FIXME this is not a correct centroid of a polygon with holes.
+ layer.islands.emplace_back(layer, island, get_extents(island.contour), Slic3r::unscale(island.contour.centroid()).cast(), area, height);
+ }
+ }
+ });
+
+ // Calculate overlap of successive layers. Link overlapping islands.
+ tbb::parallel_for(tbb::blocked_range(1, layers.size(), 8),
+ [&layers, &heights, throw_on_cancel](const tbb::blocked_range& range) {
+ for (size_t layer_id = range.begin(); layer_id < range.end(); ++layer_id) {
+ if ((layer_id % 2) == 0)
+ // Don't call the following function too often as it flushes CPU write caches due to synchronization primitves.
+ throw_on_cancel();
+ SLAAutoSupports::MyLayer &layer_above = layers[layer_id];
+ SLAAutoSupports::MyLayer &layer_below = layers[layer_id - 1];
+ //FIXME WTF?
+ const float height = (layer_id>2 ? heights[layer_id-3] : heights[0]-(heights[1]-heights[0]));
+ const float layer_height = (layer_id!=0 ? heights[layer_id]-heights[layer_id-1] : heights[0]);
+ const float safe_angle = 5.f * (float(M_PI)/180.f); // smaller number - less supports
+ const float between_layers_offset = float(scale_(layer_height / std::tan(safe_angle)));
+ //FIXME This has a quadratic time complexity, it will be excessively slow for many tiny islands.
+ for (SLAAutoSupports::Structure &top : layer_above.islands) {
+ for (SLAAutoSupports::Structure &bottom : layer_below.islands) {
+ float overlap_area = top.overlap_area(bottom);
+ if (overlap_area > 0) {
+ top.islands_below.emplace_back(&bottom, overlap_area);
+ bottom.islands_above.emplace_back(&top, overlap_area);
+ }
+ }
+ if (! top.islands_below.empty()) {
+ Polygons top_polygons = to_polygons(*top.polygon);
+ Polygons bottom_polygons = top.polygons_below();
+ top.overhangs = diff_ex(top_polygons, bottom_polygons);
+ if (! top.overhangs.empty()) {
+ top.overhangs_area = 0.f;
+ std::vector> expolys_with_areas;
+ for (ExPolygon &ex : top.overhangs) {
+ float area = float(ex.area());
+ expolys_with_areas.emplace_back(&ex, area);
+ top.overhangs_area += area;
+ }
+ std::sort(expolys_with_areas.begin(), expolys_with_areas.end(),
+ [](const std::pair &p1, const std::pair &p2)
+ { return p1.second > p2.second; });
+ ExPolygons overhangs_sorted;
+ for (auto &p : expolys_with_areas)
+ overhangs_sorted.emplace_back(std::move(*p.first));
+ top.overhangs = std::move(overhangs_sorted);
+ top.overhangs_area *= float(SCALING_FACTOR * SCALING_FACTOR);
+ top.dangling_areas = diff_ex(top_polygons, offset(bottom_polygons, between_layers_offset));
+ }
+ }
+ }
+ }
+ });
+
+ return layers;
+}
+
+void SLAAutoSupports::process(const std::vector& slices, const std::vector& heights)
+{
+#ifdef SLA_AUTOSUPPORTS_DEBUG
+ std::vector> islands;
+#endif /* SLA_AUTOSUPPORTS_DEBUG */
+
+ std::vector layers = make_layers(slices, heights, m_throw_on_cancel);
+
+ PointGrid3D point_grid;
+ point_grid.cell_size = Vec3f(10.f, 10.f, 10.f);
+
+ for (unsigned int layer_id = 0; layer_id < layers.size(); ++ layer_id) {
+ SLAAutoSupports::MyLayer *layer_top = &layers[layer_id];
+ SLAAutoSupports::MyLayer *layer_bottom = (layer_id > 0) ? &layers[layer_id - 1] : nullptr;
+ std::vector support_force_bottom;
+ if (layer_bottom != nullptr) {
+ support_force_bottom.assign(layer_bottom->islands.size(), 0.f);
+ for (size_t i = 0; i < layer_bottom->islands.size(); ++ i)
+ support_force_bottom[i] = layer_bottom->islands[i].supports_force_total();
+ }
+ for (Structure &top : layer_top->islands)
+ for (Structure::Link &bottom_link : top.islands_below) {
+ Structure &bottom = *bottom_link.island;
+ float centroids_dist = (bottom.centroid - top.centroid).norm();
+ // Penalization resulting from centroid offset:
+// bottom.supports_force *= std::min(1.f, 1.f - std::min(1.f, (1600.f * layer_height) * centroids_dist * centroids_dist / bottom.area));
+ float &support_force = support_force_bottom[&bottom - layer_bottom->islands.data()];
+//FIXME this condition does not reflect a bifurcation into a one large island and one tiny island well, it incorrectly resets the support force to zero.
+// One should rather work with the overlap area vs overhang area.
+// support_force *= std::min(1.f, 1.f - std::min(1.f, 0.1f * centroids_dist * centroids_dist / bottom.area));
+ // Penalization resulting from increasing polygon area:
+ support_force *= std::min(1.f, 20.f * bottom.area / top.area);
+ }
+ // Let's assign proper support force to each of them:
+ if (layer_id > 0) {
+ for (Structure &below : layer_bottom->islands) {
+ float below_support_force = support_force_bottom[&below - layer_bottom->islands.data()];
+ float above_overlap_area = 0.f;
+ for (Structure::Link &above_link : below.islands_above)
+ above_overlap_area += above_link.overlap_area;
+ for (Structure::Link &above_link : below.islands_above)
+ above_link.island->supports_force_inherited += below_support_force * above_link.overlap_area / above_overlap_area;
+ }
+ }
+ // Now iterate over all polygons and append new points if needed.
+ for (Structure &s : layer_top->islands) {
+ // Penalization resulting from large diff from the last layer:
+// s.supports_force_inherited /= std::max(1.f, (layer_height / 0.3f) * e_area / s.area);
+ s.supports_force_inherited /= std::max(1.f, 0.17f * (s.overhangs_area) / s.area);
+
+ float force_deficit = s.support_force_deficit(m_config.tear_pressure());
+ if (s.islands_below.empty()) { // completely new island - needs support no doubt
+ uniformly_cover({ *s.polygon }, s, point_grid, true);
+ } else if (! s.dangling_areas.empty()) {
+ // Let's see if there's anything that overlaps enough to need supports:
+ // What we now have in polygons needs support, regardless of what the forces are, so we can add them.
+ //FIXME is it an island point or not? Vojtech thinks it is.
+ uniformly_cover(s.dangling_areas, s, point_grid);
+ } else if (! s.overhangs.empty()) {
+ //FIXME add the support force deficit as a parameter, only cover until the defficiency is covered.
+ uniformly_cover(s.overhangs, s, point_grid);
+ }
+ }
+
+ m_throw_on_cancel();
+
+#ifdef SLA_AUTOSUPPORTS_DEBUG
+ /*std::string layer_num_str = std::string((i<10 ? "0" : "")) + std::string((i<100 ? "0" : "")) + std::to_string(i);
+ output_expolygons(expolys_top, "top" + layer_num_str + ".svg");
+ output_expolygons(diff, "diff" + layer_num_str + ".svg");
+ if (!islands.empty())
+ output_expolygons(islands, "islands" + layer_num_str + ".svg");*/
+#endif /* SLA_AUTOSUPPORTS_DEBUG */
+ }
+}
+
+std::vector sample_expolygon(const ExPolygon &expoly, float samples_per_mm2, std::mt19937 &rng)
+{
+ // Triangulate the polygon with holes into triplets of 3D points.
+ std::vector triangles = Slic3r::triangulate_expolygon_2f(expoly);
+
+ std::vector out;
+ if (! triangles.empty())
+ {
+ // Calculate area of each triangle.
+ std::vector areas;
+ areas.reserve(triangles.size() / 3);
+ for (size_t i = 0; i < triangles.size(); ) {
+ const Vec2f &a = triangles[i ++];
+ const Vec2f v1 = triangles[i ++] - a;
+ const Vec2f v2 = triangles[i ++] - a;
+ areas.emplace_back(0.5f * std::abs(cross2(v1, v2)));
+ if (i != 3)
+ // Prefix sum of the areas.
+ areas.back() += areas[areas.size() - 2];
+ }
+
+ size_t num_samples = size_t(ceil(areas.back() * samples_per_mm2));
+ std::uniform_real_distribution<> random_triangle(0., double(areas.back()));
+ std::uniform_real_distribution<> random_float(0., 1.);
+ for (size_t i = 0; i < num_samples; ++ i) {
+ double r = random_triangle(rng);
+ size_t idx_triangle = std::min(std::upper_bound(areas.begin(), areas.end(), (float)r) - areas.begin(), areas.size() - 1) * 3;
+ // Select a random point on the triangle.
+ double u = float(sqrt(random_float(rng)));
+ double v = float(random_float(rng));
+ const Vec2f &a = triangles[idx_triangle ++];
+ const Vec2f &b = triangles[idx_triangle++];
+ const Vec2f &c = triangles[idx_triangle];
+ const Vec2f x = a * (1.f - u) + b * (u * (1.f - v)) + c * (v * u);
+ out.emplace_back(x);
+ }
+ }
+ return out;
+}
+
+std::vector sample_expolygon_with_boundary(const ExPolygon &expoly, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
+{
+ std::vector out = sample_expolygon(expoly, samples_per_mm2, rng);
+ double point_stepping_scaled = scale_(1.f) / samples_per_mm_boundary;
+ for (size_t i_contour = 0; i_contour <= expoly.holes.size(); ++ i_contour) {
+ const Polygon &contour = (i_contour == 0) ? expoly.contour : expoly.holes[i_contour - 1];
+ const Points pts = contour.equally_spaced_points(point_stepping_scaled);
+ for (size_t i = 0; i < pts.size(); ++ i)
+ out.emplace_back(unscale(pts[i].x()), unscale(pts[i].y()));
+ }
+ return out;
+}
+
+std::vector sample_expolygon_with_boundary(const ExPolygons &expolys, float samples_per_mm2, float samples_per_mm_boundary, std::mt19937 &rng)
+{
+ std::vector out;
+ for (const ExPolygon &expoly : expolys)
+ append(out, sample_expolygon_with_boundary(expoly, samples_per_mm2, samples_per_mm_boundary, rng));
+ return out;
+}
+
+template
+static inline std::vector poisson_disk_from_samples(const std::vector &raw_samples, float radius, REFUSE_FUNCTION refuse_function)
+{
+ Vec2f corner_min(std::numeric_limits::max(), std::numeric_limits::max());
+ for (const Vec2f &pt : raw_samples) {
+ corner_min.x() = std::min(corner_min.x(), pt.x());
+ corner_min.y() = std::min(corner_min.y(), pt.y());
+ }
+
+ // Assign the raw samples to grid cells, sort the grid cells lexicographically.
+ struct RawSample {
+ Vec2f coord;
+ Vec2i cell_id;
+ };
+ std::vector raw_samples_sorted;
+ RawSample sample;
+ for (const Vec2f &pt : raw_samples) {
+ sample.coord = pt;
+ sample.cell_id = ((pt - corner_min) / radius).cast();
+ raw_samples_sorted.emplace_back(sample);
+ }
+ std::sort(raw_samples_sorted.begin(), raw_samples_sorted.end(), [](const RawSample &lhs, const RawSample &rhs)
+ { return lhs.cell_id.x() < rhs.cell_id.x() || (lhs.cell_id.x() == rhs.cell_id.x() && lhs.cell_id.y() < rhs.cell_id.y()); });
+
+ struct PoissonDiskGridEntry {
+ // Resulting output sample points for this cell:
+ enum {
+ max_positions = 4
+ };
+ Vec2f poisson_samples[max_positions];
+ int num_poisson_samples = 0;
+
+ // Index into raw_samples:
+ int first_sample_idx;
+ int sample_cnt;
+ };
+
+ struct CellIDHash {
+ std::size_t operator()(const Vec2i &cell_id) const {
+ return std::hash()(cell_id.x()) ^ std::hash()(cell_id.y() * 593);
+ }
+ };
+
+ // Map from cell IDs to hash_data. Each hash_data points to the range in raw_samples corresponding to that cell.
+ // (We could just store the samples in hash_data. This implementation is an artifact of the reference paper, which
+ // is optimizing for GPU acceleration that we haven't implemented currently.)
+ typedef std::unordered_map Cells;
+ Cells cells;
+ {
+ typename Cells::iterator last_cell_id_it;
+ Vec2i last_cell_id(-1, -1);
+ for (int i = 0; i < raw_samples_sorted.size(); ++ i) {
+ const RawSample &sample = raw_samples_sorted[i];
+ if (sample.cell_id == last_cell_id) {
+ // This sample is in the same cell as the previous, so just increase the count. Cells are
+ // always contiguous, since we've sorted raw_samples_sorted by cell ID.
+ ++ last_cell_id_it->second.sample_cnt;
+ } else {
+ // This is a new cell.
+ PoissonDiskGridEntry data;
+ data.first_sample_idx = i;
+ data.sample_cnt = 1;
+ auto result = cells.insert({sample.cell_id, data});
+ last_cell_id = sample.cell_id;
+ last_cell_id_it = result.first;
+ }
+ }
+ }
+
+ const int max_trials = 5;
+ const float radius_squared = radius * radius;
+ for (int trial = 0; trial < max_trials; ++ trial) {
+ // Create sample points for each entry in cells.
+ for (auto &it : cells) {
+ const Vec2i &cell_id = it.first;
+ PoissonDiskGridEntry &cell_data = it.second;
+ // This cell's raw sample points start at first_sample_idx. On trial 0, try the first one. On trial 1, try first_sample_idx + 1.
+ int next_sample_idx = cell_data.first_sample_idx + trial;
+ if (trial >= cell_data.sample_cnt)
+ // There are no more points to try for this cell.
+ continue;
+ const RawSample &candidate = raw_samples_sorted[next_sample_idx];
+ // See if this point conflicts with any other points in this cell, or with any points in
+ // neighboring cells. Note that it's possible to have more than one point in the same cell.
+ bool conflict = refuse_function(candidate.coord);
+ for (int i = -1; i < 2 && ! conflict; ++ i) {
+ for (int j = -1; j < 2; ++ j) {
+ const auto &it_neighbor = cells.find(cell_id + Vec2i(i, j));
+ if (it_neighbor != cells.end()) {
+ const PoissonDiskGridEntry &neighbor = it_neighbor->second;
+ for (int i_sample = 0; i_sample < neighbor.num_poisson_samples; ++ i_sample)
+ if ((neighbor.poisson_samples[i_sample] - candidate.coord).squaredNorm() < radius_squared) {
+ conflict = true;
+ break;
+ }
+ }
+ }
+ }
+ if (! conflict) {
+ // Store the new sample.
+ assert(cell_data.num_poisson_samples < cell_data.max_positions);
+ if (cell_data.num_poisson_samples < cell_data.max_positions)
+ cell_data.poisson_samples[cell_data.num_poisson_samples ++] = candidate.coord;
+ }
+ }
+ }
+
+ // Copy the results to the output.
+ std::vector out;
+ for (const auto& it : cells)
+ for (int i = 0; i < it.second.num_poisson_samples; ++ i)
+ out.emplace_back(it.second.poisson_samples[i]);
+ return out;
+}
+
+void SLAAutoSupports::uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island, bool just_one)
+{
+ //int num_of_points = std::max(1, (int)((island.area()*pow(SCALING_FACTOR, 2) * m_config.tear_pressure)/m_config.support_force));
+
+ const float support_force_deficit = structure.support_force_deficit(m_config.tear_pressure());
+ if (support_force_deficit < 0)
+ return;
+
+ // Number of newly added points.
+ const size_t poisson_samples_target = size_t(ceil(support_force_deficit / m_config.support_force()));
+
+ const float density_horizontal = m_config.tear_pressure() / m_config.support_force();
+ //FIXME why?
+ float poisson_radius = std::max(m_config.minimal_distance, 1.f / (5.f * density_horizontal));
+// const float poisson_radius = 1.f / (15.f * density_horizontal);
+ const float samples_per_mm2 = 30.f / (float(M_PI) * poisson_radius * poisson_radius);
+ // Minimum distance between samples, in 3D space.
+// float min_spacing = poisson_radius / 3.f;
+ float min_spacing = poisson_radius;
+
+ //FIXME share the random generator. The random generator may be not so cheap to initialize, also we don't want the random generator to be restarted for each polygon.
+ std::random_device rd;
+ std::mt19937 rng(rd());
+ std::vector raw_samples = sample_expolygon_with_boundary(islands, samples_per_mm2, 5.f / poisson_radius, rng);
+ std::vector poisson_samples;
+ for (size_t iter = 0; iter < 4; ++ iter) {
+ poisson_samples = poisson_disk_from_samples(raw_samples, poisson_radius,
+ [&structure, &grid3d, min_spacing](const Vec2f &pos) {
+ return grid3d.collides_with(pos, &structure, min_spacing);
+ });
+ if (poisson_samples.size() >= poisson_samples_target || m_config.minimal_distance > poisson_radius-EPSILON)
+ break;
+ float coeff = 0.5f;
+ if (poisson_samples.size() * 2 > poisson_samples_target)
+ coeff = float(poisson_samples.size()) / float(poisson_samples_target);
+ poisson_radius = std::max(m_config.minimal_distance, poisson_radius * coeff);
+ min_spacing = std::max(m_config.minimal_distance, min_spacing * coeff);
+ }
+
+#ifdef SLA_AUTOSUPPORTS_DEBUG
+ {
+ static int irun = 0;
+ Slic3r::SVG svg(debug_out_path("SLA_supports-uniformly_cover-%d.svg", irun ++), get_extents(islands));
+ for (const ExPolygon &island : islands)
+ svg.draw(island);
+ for (const Vec2f &pt : raw_samples)
+ svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "red");
+ for (const Vec2f &pt : poisson_samples)
+ svg.draw(Point(scale_(pt.x()), scale_(pt.y())), "blue");
+ }
+#endif /* NDEBUG */
+
+// assert(! poisson_samples.empty());
+ if (poisson_samples_target < poisson_samples.size()) {
+ std::shuffle(poisson_samples.begin(), poisson_samples.end(), rng);
+ poisson_samples.erase(poisson_samples.begin() + poisson_samples_target, poisson_samples.end());
+ }
+ for (const Vec2f &pt : poisson_samples) {
+ m_output.emplace_back(float(pt(0)), float(pt(1)), structure.height, 0.2f, is_new_island);
+ structure.supports_force_this_layer += m_config.support_force();
+ grid3d.insert(pt, &structure);
+ }
}
#ifdef SLA_AUTOSUPPORTS_DEBUG
-void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, std::string filename) const
+void SLAAutoSupports::output_structures(const std::vector& structures)
+{
+ for (unsigned int i=0 ; i{*structures[i].polygon}, ss.str());
+ }
+}
+
+void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, const std::string &filename)
{
BoundingBox bb(Point(-30000000, -30000000), Point(30000000, 30000000));
Slic3r::SVG svg_cummulative(filename, bb);
@@ -198,138 +525,6 @@ void SLAAutoSupports::output_expolygons(const ExPolygons& expolys, std::string f
svg_cummulative.draw_outline(expolys[i].holes, "blue", scale_(0.05));
}
}
-#endif /* SLA_AUTOSUPPORTS_DEBUG */
-
-std::vector> SLAAutoSupports::find_islands(const std::vector& slices, const std::vector& heights) const
-{
- std::vector> islands;
-
- struct PointAccessor {
- const Point* operator()(const Point &pt) const { return &pt; }
- };
- typedef ClosestPointInRadiusLookup ClosestPointLookupType;
-
- for (unsigned int i = 0; i SLAAutoSupports::uniformly_cover(const std::pair& island)
-{
- int num_of_points = std::max(1, (int)(island.first.area()*pow(SCALING_FACTOR, 2) * get_required_density(0)));
-
- // In case there is just one point to place, we'll place it into the polygon's centroid (unless it lies in a hole).
- if (num_of_points == 1) {
- Point out(island.first.contour.centroid());
-
- for (const auto& hole : island.first.holes)
- if (hole.contains(out))
- goto HOLE_HIT;
- return std::vector{unscale(out(0), out(1), island.second)};
- }
-
-HOLE_HIT:
- // In this case either the centroid lies in a hole, or there are multiple points
- // to place. We will cover the island another way.
- // For now we'll just place the points randomly not too close to the others.
- std::random_device rd;
- std::mt19937 gen(rd());
- std::uniform_real_distribution<> dis(0., 1.);
-
- std::vector island_new_points;
- const BoundingBox& bb = get_extents(island.first);
- const int refused_limit = 30;
- int refused_points = 0;
- while (refused_points < refused_limit) {
- Point out(bb.min(0) + bb.size()(0) * dis(gen),
- bb.min(1) + bb.size()(1) * dis(gen)) ;
- Vec3d unscaled_out = unscale(out(0), out(1), island.second);
- bool add_it = true;
-
- if (!island.first.contour.contains(out))
- add_it = false;
- else
- for (const Polygon& hole : island.first.holes)
- if (hole.contains(out))
- add_it = false;
-
- if (add_it) {
- for (const Vec3d& p : island_new_points) {
- if ((p - unscaled_out).squaredNorm() < distance_limit(0)) {
- add_it = false;
- ++refused_points;
- break;
- }
- }
- }
- if (add_it)
- island_new_points.emplace_back(unscaled_out);
- }
- return island_new_points;
-}
-
-void SLAAutoSupports::project_upward_onto_mesh(std::vector& points) const
-{
- Vec3f dir(0., 0., 1.);
- igl::Hit hit{0, 0, 0.f, 0.f, 0.f};
- for (Vec3d& p : points) {
- igl::ray_mesh_intersect(p.cast(), dir, m_V, m_F, hit);
- int fid = hit.id;
- Vec3f bc(1-hit.u-hit.v, hit.u, hit.v);
- p = (bc(0) * m_V.row(m_F(fid, 0)) + bc(1) * m_V.row(m_F(fid, 1)) + bc(2)*m_V.row(m_F(fid, 2))).cast();
- }
-}
-
+#endif
} // namespace Slic3r
diff --git a/src/libslic3r/SLA/SLAAutoSupports.hpp b/src/libslic3r/SLA/SLAAutoSupports.hpp
index 311d7b0c73..0d5cc64f17 100644
--- a/src/libslic3r/SLA/SLAAutoSupports.hpp
+++ b/src/libslic3r/SLA/SLAAutoSupports.hpp
@@ -1,9 +1,12 @@
#ifndef SLAAUTOSUPPORTS_HPP_
#define SLAAUTOSUPPORTS_HPP_
+#include
#include
#include
-#include
+#include
+
+#include
// #define SLA_AUTOSUPPORTS_DEBUG
@@ -12,36 +15,184 @@ namespace Slic3r {
class SLAAutoSupports {
public:
struct Config {
- float density_at_horizontal;
- float density_at_45;
- float minimal_z;
+ float density_relative;
+ float minimal_distance;
+ ///////////////
+ inline float support_force() const { return 10.f / density_relative; } // a force one point can support (arbitrary force unit)
+ inline float tear_pressure() const { return 1.f; } // pressure that the display exerts (the force unit per mm2)
};
- SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices,
- const std::vector& heights, const Config& config, std::function throw_on_cancel);
- const std::vector& output() { return m_output; }
+ SLAAutoSupports(const TriangleMesh& mesh, const sla::EigenMesh3D& emesh, const std::vector& slices,
+ const std::vector& heights, const Config& config, std::function throw_on_cancel);
+ const std::vector& output() { return m_output; }
-private:
- std::vector m_output;
- std::vector m_normals;
- TriangleMesh mesh;
- static float angle_from_normal(const stl_normal& normal) { return acos((-normal.normalized())(2)); }
- float get_required_density(float angle) const;
- float distance_limit(float angle) const;
- static float approximate_geodesic_distance(const Vec3d& p1, const Vec3d& p2, Vec3d& n1, Vec3d& n2);
- std::vector> find_islands(const std::vector& slices, const std::vector& heights) const;
- void sprinkle_mesh(const TriangleMesh& mesh);
- std::vector uniformly_cover(const std::pair& island);
- void project_upward_onto_mesh(std::vector& points) const;
+ struct MyLayer;
+ struct Structure {
+ Structure(MyLayer &layer, const ExPolygon& poly, const BoundingBox &bbox, const Vec2f ¢roid, float area, float h) :
+ layer(&layer), polygon(&poly), bbox(bbox), centroid(centroid), area(area), height(h)
#ifdef SLA_AUTOSUPPORTS_DEBUG
- void output_expolygons(const ExPolygons& expolys, std::string filename) const;
+ , unique_id(std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()))
+#endif /* SLA_AUTOSUPPORTS_DEBUG */
+ {}
+ MyLayer *layer;
+ const ExPolygon* polygon = nullptr;
+ const BoundingBox bbox;
+ const Vec2f centroid = Vec2f::Zero();
+ const float area = 0.f;
+ float height = 0;
+ // How well is this ExPolygon held to the print base?
+ // Positive number, the higher the better.
+ float supports_force_this_layer = 0.f;
+ float supports_force_inherited = 0.f;
+ float supports_force_total() const { return this->supports_force_this_layer + this->supports_force_inherited; }
+#ifdef SLA_AUTOSUPPORTS_DEBUG
+ std::chrono::milliseconds unique_id;
#endif /* SLA_AUTOSUPPORTS_DEBUG */
+ struct Link {
+ Link(Structure *island, float overlap_area) : island(island), overlap_area(overlap_area) {}
+ Structure *island;
+ float overlap_area;
+ };
+
+#ifdef NDEBUG
+ // In release mode, use the optimized container.
+ boost::container::small_vector islands_above;
+ boost::container::small_vector islands_below;
+#else
+ // In debug mode, use the standard vector, which is well handled by debugger visualizer.
+ std::vector islands_above;
+ std::vector islands_below;
+#endif
+ ExPolygons dangling_areas;
+ ExPolygons overhangs;
+ float overhangs_area;
+
+ bool overlaps(const Structure &rhs) const {
+ return this->bbox.overlap(rhs.bbox) && (this->polygon->overlaps(*rhs.polygon) || rhs.polygon->overlaps(*this->polygon));
+ }
+ float overlap_area(const Structure &rhs) const {
+ double out = 0.;
+ if (this->bbox.overlap(rhs.bbox)) {
+ Polygons polys = intersection(to_polygons(*this->polygon), to_polygons(*rhs.polygon), false);
+ for (const Polygon &poly : polys)
+ out += poly.area();
+ }
+ return float(out);
+ }
+ float area_below() const {
+ float area = 0.f;
+ for (const Link &below : this->islands_below)
+ area += below.island->area;
+ return area;
+ }
+ Polygons polygons_below() const {
+ size_t cnt = 0;
+ for (const Link &below : this->islands_below)
+ cnt += 1 + below.island->polygon->holes.size();
+ Polygons out;
+ out.reserve(cnt);
+ for (const Link &below : this->islands_below) {
+ out.emplace_back(below.island->polygon->contour);
+ append(out, below.island->polygon->holes);
+ }
+ return out;
+ }
+ ExPolygons expolygons_below() const {
+ ExPolygons out;
+ out.reserve(this->islands_below.size());
+ for (const Link &below : this->islands_below)
+ out.emplace_back(*below.island->polygon);
+ return out;
+ }
+ // Positive deficit of the supports. If negative, this area is well supported. If positive, more supports need to be added.
+ float support_force_deficit(const float tear_pressure) const { return this->area * tear_pressure - this->supports_force_total(); }
+ };
+
+ struct MyLayer {
+ MyLayer(const size_t layer_id, coordf_t print_z) : layer_id(layer_id), print_z(print_z) {}
+ size_t layer_id;
+ coordf_t print_z;
+ std::vector islands;
+ };
+
+ struct RichSupportPoint {
+ Vec3f position;
+ Structure *island;
+ };
+
+ struct PointGrid3D {
+ struct GridHash {
+ std::size_t operator()(const Vec3i &cell_id) const {
+ return std::hash()(cell_id.x()) ^ std::hash()(cell_id.y() * 593) ^ std::hash()(cell_id.z() * 7919);
+ }
+ };
+ typedef std::unordered_multimap Grid;
+
+ Vec3f cell_size;
+ Grid grid;
+
+ Vec3i cell_id(const Vec3f &pos) {
+ return Vec3i(int(floor(pos.x() / cell_size.x())),
+ int(floor(pos.y() / cell_size.y())),
+ int(floor(pos.z() / cell_size.z())));
+ }
+
+ void insert(const Vec2f &pos, Structure *island) {
+ RichSupportPoint pt;
+ pt.position = Vec3f(pos.x(), pos.y(), float(island->layer->print_z));
+ pt.island = island;
+ grid.emplace(cell_id(pt.position), pt);
+ }
+
+ bool collides_with(const Vec2f &pos, Structure *island, float radius) {
+ Vec3f pos3d(pos.x(), pos.y(), float(island->layer->print_z));
+ Vec3i cell = cell_id(pos3d);
+ std::pair it_pair = grid.equal_range(cell);
+ if (collides_with(pos3d, radius, it_pair.first, it_pair.second))
+ return true;
+ for (int i = -1; i < 2; ++ i)
+ for (int j = -1; j < 2; ++ j)
+ for (int k = -1; k < 1; ++ k) {
+ if (i == 0 && j == 0 && k == 0)
+ continue;
+ it_pair = grid.equal_range(cell + Vec3i(i, j, k));
+ if (collides_with(pos3d, radius, it_pair.first, it_pair.second))
+ return true;
+ }
+ return false;
+ }
+
+ private:
+ bool collides_with(const Vec3f &pos, float radius, Grid::const_iterator it_begin, Grid::const_iterator it_end) {
+ for (Grid::const_iterator it = it_begin; it != it_end; ++ it) {
+ float dist2 = (it->second.position - pos).squaredNorm();
+ if (dist2 < radius * radius)
+ return true;
+ }
+ return false;
+ }
+ };
+
+private:
+ std::vector m_output;
+
SLAAutoSupports::Config m_config;
+
+ float m_supports_force_total = 0.f;
+
+ void process(const std::vector& slices, const std::vector& heights);
+ void uniformly_cover(const ExPolygons& islands, Structure& structure, PointGrid3D &grid3d, bool is_new_island = false, bool just_one = false);
+ void project_onto_mesh(std::vector& points) const;
+
+#ifdef SLA_AUTOSUPPORTS_DEBUG
+ static void output_expolygons(const ExPolygons& expolys, const std::string &filename);
+ static void output_structures(const std::vector &structures);
+#endif // SLA_AUTOSUPPORTS_DEBUG
+
std::function m_throw_on_cancel;
- const Eigen::MatrixXd& m_V;
- const Eigen::MatrixXi& m_F;
+ const sla::EigenMesh3D& m_emesh;
};
diff --git a/src/libslic3r/SLA/SLABasePool.cpp b/src/libslic3r/SLA/SLABasePool.cpp
index a235d52baf..42b22acb99 100644
--- a/src/libslic3r/SLA/SLABasePool.cpp
+++ b/src/libslic3r/SLA/SLABasePool.cpp
@@ -4,78 +4,177 @@
#include "boost/log/trivial.hpp"
#include "SLABoostAdapter.hpp"
#include "ClipperUtils.hpp"
+#include "Tesselate.hpp"
+// For debugging:
+//#include
+//#include
//#include "SVG.hpp"
-//#include "benchmark.h"
namespace Slic3r { namespace sla {
-/// Convert the triangulation output to an intermediate mesh.
-Contour3D convert(const Polygons& triangles, coord_t z, bool dir) {
-
- Pointf3s points;
- points.reserve(3*triangles.size());
- Indices indices;
- indices.reserve(points.size());
-
- for(auto& tr : triangles) {
- auto c = coord_t(points.size()), b = c++, a = c++;
- if(dir) indices.emplace_back(a, b, c);
- else indices.emplace_back(c, b, a);
- for(auto& p : tr.points) {
- points.emplace_back(unscale(x(p), y(p), z));
- }
- }
-
- return {points, indices};
-}
-
-Contour3D walls(const ExPolygon& floor_plate, const ExPolygon& ceiling,
- double floor_z_mm, double ceiling_z_mm,
- ThrowOnCancel thr)
+/// This function will return a triangulation of a sheet connecting an upper
+/// and a lower plate given as input polygons. It will not triangulate the
+/// plates themselves only the sheet. The caller has to specify the lower and
+/// upper z levels in world coordinates as well as the offset difference
+/// between the sheets. If the lower_z_mm is higher than upper_z_mm or the
+/// offset difference is negative, the resulting triangle orientation will be
+/// reversed.
+///
+/// IMPORTANT: This is not a universal triangulation algorithm. It assumes
+/// that the lower and upper polygons are offsetted versions of the same
+/// original polygon. In general, it assumes that one of the polygons is
+/// completely inside the other. The offset difference is the reference
+/// distance from the inner polygon's perimeter to the outer polygon's
+/// perimeter. The real distance will be variable as the clipper offset has
+/// different strategies (rounding, etc...). This algorithm should have
+/// O(2n + 3m) complexity where n is the number of upper vertices and m is the
+/// number of lower vertices.
+Contour3D walls(const Polygon& lower, const Polygon& upper,
+ double lower_z_mm, double upper_z_mm,
+ double offset_difference_mm, ThrowOnCancel thr)
{
- using std::transform; using std::back_inserter;
-
- ExPolygon poly;
- poly.contour.points = floor_plate.contour.points;
- poly.holes.emplace_back(ceiling.contour);
- auto& h = poly.holes.front();
- std::reverse(h.points.begin(), h.points.end());
- Polygons tri = triangulate(poly);
-
Contour3D ret;
- ret.points.reserve(tri.size() * 3);
- double fz = floor_z_mm;
- double cz = ceiling_z_mm;
- auto& rp = ret.points;
- auto& rpi = ret.indices;
- ret.indices.reserve(tri.size() * 3);
+ if(upper.points.size() < 3 || lower.size() < 3) return ret;
- coord_t idx = 0;
+ // The concept of the algorithm is relatively simple. It will try to find
+ // the closest vertices from the upper and the lower polygon and use those
+ // as starting points. Then it will create the triangles sequentially using
+ // an edge from the upper polygon and a vertex from the lower or vice versa,
+ // depending on the resulting triangle's quality.
+ // The quality is measured by a scalar value. So far it looks like it is
+ // enough to derive it from the slope of the triangle's two edges connecting
+ // the upper and the lower part. A reference slope is calculated from the
+ // height and the offset difference.
- auto hlines = h.lines();
- auto is_upper = [&hlines](const Point& p) {
- return std::any_of(hlines.begin(), hlines.end(),
- [&p](const Line& l) {
- return l.distance_to(p) < mm(1e-6);
- });
+ // Offset in the index array for the ceiling
+ const auto offs = upper.points.size();
+
+ // Shorthand for the vertex arrays
+ auto& upoints = upper.points, &lpoints = lower.points;
+ auto& rpts = ret.points; auto& rfaces = ret.indices;
+
+ // If the Z levels are flipped, or the offset difference is negative, we
+ // will interpret that as the triangles normals should be inverted.
+ bool inverted = upper_z_mm < lower_z_mm || offset_difference_mm < 0;
+
+ // Copy the points into the mesh, convert them from 2D to 3D
+ rpts.reserve(upoints.size() + lpoints.size());
+ rfaces.reserve(2*upoints.size() + 2*lpoints.size());
+ const double sf = SCALING_FACTOR;
+ for(auto& p : upoints) rpts.emplace_back(p.x()*sf, p.y()*sf, upper_z_mm);
+ for(auto& p : lpoints) rpts.emplace_back(p.x()*sf, p.y()*sf, lower_z_mm);
+
+ // Create pointing indices into vertex arrays. u-upper, l-lower
+ size_t uidx = 0, lidx = offs, unextidx = 1, lnextidx = offs + 1;
+
+ // Simple squared distance calculation.
+ auto distfn = [](const Vec3d& p1, const Vec3d& p2) {
+ auto p = p1 - p2; return p.transpose() * p;
};
- std::for_each(tri.begin(), tri.end(),
- [&rp, &rpi, thr, &idx, is_upper, fz, cz](const Polygon& pp)
- {
- thr(); // may throw if cancellation was requested
+ // We need to find the closest point on lower polygon to the first point on
+ // the upper polygon. These will be our starting points.
+ double distmin = std::numeric_limits::max();
+ for(size_t l = lidx; l < rpts.size(); ++l) {
+ thr();
+ double d = distfn(rpts[l], rpts[uidx]);
+ if(d < distmin) { lidx = l; distmin = d; }
+ }
- for(auto& p : pp.points)
- if(is_upper(p))
- rp.emplace_back(unscale(x(p), y(p), mm(cz)));
- else rp.emplace_back(unscale(x(p), y(p), mm(fz)));
+ // Set up lnextidx to be ahead of lidx in cyclic mode
+ lnextidx = lidx + 1;
+ if(lnextidx == rpts.size()) lnextidx = offs;
- coord_t a = idx++, b = idx++, c = idx++;
- if(fz > cz) rpi.emplace_back(c, b, a);
- else rpi.emplace_back(a, b, c);
- });
+ // This will be the flip switch to toggle between upper and lower triangle
+ // creation mode
+ enum class Proceed {
+ UPPER, // A segment from the upper polygon and one vertex from the lower
+ LOWER // A segment from the lower polygon and one vertex from the upper
+ } proceed = Proceed::UPPER;
+
+ // Flags to help evaluating loop termination.
+ bool ustarted = false, lstarted = false;
+
+ // The variables for the fitness values, one for the actual and one for the
+ // previous.
+ double current_fit = 0, prev_fit = 0;
+
+ // Every triangle of the wall has two edges connecting the upper plate with
+ // the lower plate. From the length of these two edges and the zdiff we
+ // can calculate the momentary squared offset distance at a particular
+ // position on the wall. The average of the differences from the reference
+ // (squared) offset distance will give us the driving fitness value.
+ const double offsdiff2 = std::pow(offset_difference_mm, 2);
+ const double zdiff2 = std::pow(upper_z_mm - lower_z_mm, 2);
+
+ // Mark the current vertex iterator positions. If the iterators return to
+ // the same position, the loop can be terminated.
+ size_t uendidx = uidx, lendidx = lidx;
+
+ do { thr(); // check throw if canceled
+
+ prev_fit = current_fit;
+
+ switch(proceed) { // proceed depending on the current state
+ case Proceed::UPPER:
+ if(!ustarted || uidx != uendidx) { // there are vertices remaining
+ // Get the 3D vertices in order
+ const Vec3d& p_up1 = rpts[size_t(uidx)];
+ const Vec3d& p_low = rpts[size_t(lidx)];
+ const Vec3d& p_up2 = rpts[size_t(unextidx)];
+
+ // Calculate fitness: the average of the two connecting edges
+ double a = offsdiff2 - (distfn(p_up1, p_low) - zdiff2);
+ double b = offsdiff2 - (distfn(p_up2, p_low) - zdiff2);
+ current_fit = (std::abs(a) + std::abs(b)) / 2;
+
+ if(current_fit > prev_fit) { // fit is worse than previously
+ proceed = Proceed::LOWER;
+ } else { // good to go, create the triangle
+ inverted? rfaces.emplace_back(unextidx, lidx, uidx) :
+ rfaces.emplace_back(uidx, lidx, unextidx) ;
+
+ // Increment the iterators, rotate if necessary
+ ++uidx; ++unextidx;
+ if(unextidx == offs) unextidx = 0;
+ if(uidx == offs) uidx = 0;
+
+ ustarted = true; // mark the movement of the iterators
+ // so that the comparison to uendidx can be made correctly
+ }
+ } else proceed = Proceed::LOWER;
+
+ break;
+ case Proceed::LOWER:
+ // Mode with lower segment, upper vertex. Same structure:
+ if(!lstarted || lidx != lendidx) {
+ const Vec3d& p_low1 = rpts[size_t(lidx)];
+ const Vec3d& p_low2 = rpts[size_t(lnextidx)];
+ const Vec3d& p_up = rpts[size_t(uidx)];
+
+ double a = offsdiff2 - (distfn(p_up, p_low1) - zdiff2);
+ double b = offsdiff2 - (distfn(p_up, p_low2) - zdiff2);
+ current_fit = (std::abs(a) + std::abs(b)) / 2;
+
+ if(current_fit > prev_fit) {
+ proceed = Proceed::UPPER;
+ } else {
+ inverted? rfaces.emplace_back(uidx, lnextidx, lidx) :
+ rfaces.emplace_back(lidx, lnextidx, uidx);
+
+ ++lidx; ++lnextidx;
+ if(lnextidx == rpts.size()) lnextidx = offs;
+ if(lidx == rpts.size()) lidx = offs;
+
+ lstarted = true;
+ }
+ } else proceed = Proceed::UPPER;
+
+ break;
+ } // end of switch
+ } while(!ustarted || !lstarted || uidx != uendidx || lidx != lendidx);
return ret;
}
@@ -207,20 +306,31 @@ ExPolygons unify(const ExPolygons& shapes) {
/// Only a debug function to generate top and bottom plates from a 2D shape.
/// It is not used in the algorithm directly.
inline Contour3D roofs(const ExPolygon& poly, coord_t z_distance) {
- Polygons triangles = triangulate(poly);
-
- auto lower = convert(triangles, 0, false);
- auto upper = convert(triangles, z_distance, true);
- lower.merge(upper);
- return lower;
+ auto lower = triangulate_expolygon_3d(poly);
+ auto upper = triangulate_expolygon_3d(poly, z_distance*SCALING_FACTOR, true);
+ Contour3D ret;
+ ret.merge(lower); ret.merge(upper);
+ return ret;
}
+/// This method will create a rounded edge around a flat polygon in 3d space.
+/// 'base_plate' parameter is the target plate.
+/// 'radius' is the radius of the edges.
+/// 'degrees' is tells how much of a circle should be created as the rounding.
+/// It should be in degrees, not radians.
+/// 'ceilheight_mm' is the Z coordinate of the flat polygon in 3D space.
+/// 'dir' Is the direction of the round edges: inward or outward
+/// 'thr' Throws if a cancel signal was received
+/// 'last_offset' An auxiliary output variable to save the last offsetted
+/// version of 'base_plate'
+/// 'last_height' An auxiliary output to save the last z coordinate of the
+/// offsetted base_plate. In other words, where the rounded edges end.
Contour3D round_edges(const ExPolygon& base_plate,
double radius_mm,
double degrees,
double ceilheight_mm,
bool dir,
- ThrowOnCancel throw_on_cancel,
+ ThrowOnCancel thr,
ExPolygon& last_offset, double& last_height)
{
auto ob = base_plate;
@@ -236,10 +346,10 @@ Contour3D round_edges(const ExPolygon& base_plate,
// we use sin for x distance because we interpret the angle starting from
// PI/2
int tos = degrees < 90?
- int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps;
+ int(radius_mm*std::cos(degrees * PI / 180 - PI/2) / stepx) : steps;
for(int i = 1; i <= tos; ++i) {
- throw_on_cancel();
+ thr();
ob = base_plate;
@@ -252,7 +362,8 @@ Contour3D round_edges(const ExPolygon& base_plate,
wh = ceilheight_mm - radius_mm + stepy;
Contour3D pwalls;
- pwalls = walls(ob, ob_prev, wh, wh_prev, throw_on_cancel);
+ double prev_x = xx - (i - 1) * stepx;
+ pwalls = walls(ob.contour, ob_prev.contour, wh, wh_prev, s*prev_x, thr);
curvedwalls.merge(pwalls);
ob_prev = ob;
@@ -264,7 +375,7 @@ Contour3D round_edges(const ExPolygon& base_plate,
int tos = int(tox / stepx);
for(int i = 1; i <= tos; ++i) {
- throw_on_cancel();
+ thr();
ob = base_plate;
double r2 = radius_mm * radius_mm;
@@ -275,7 +386,9 @@ Contour3D round_edges(const ExPolygon& base_plate,
wh = ceilheight_mm - radius_mm - stepy;
Contour3D pwalls;
- pwalls = walls(ob_prev, ob, wh_prev, wh, throw_on_cancel);
+ double prev_x = xx - radius_mm + (i - 1)*stepx;
+ pwalls =
+ walls(ob_prev.contour, ob.contour, wh_prev, wh, s*prev_x, thr);
curvedwalls.merge(pwalls);
ob_prev = ob;
@@ -291,15 +404,17 @@ Contour3D round_edges(const ExPolygon& base_plate,
/// Generating the concave part of the 3D pool with the bottom plate and the
/// side walls.
-Contour3D inner_bed(const ExPolygon& poly, double depth_mm,
- double begin_h_mm = 0) {
-
- Polygons triangles = triangulate(poly);
+Contour3D inner_bed(const ExPolygon& poly,
+ double depth_mm,
+ double begin_h_mm = 0)
+{
+ Contour3D bottom;
+ Pointf3s triangles = triangulate_expolygon_3d(poly, -depth_mm + begin_h_mm);
+ bottom.merge(triangles);
coord_t depth = mm(depth_mm);
coord_t begin_h = mm(begin_h_mm);
- auto bottom = convert(triangles, -depth + begin_h, false);
auto lines = poly.lines();
// Generate outer walls
@@ -469,6 +584,9 @@ void base_plate(const TriangleMesh &mesh, ExPolygons &output, float h,
void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
const PoolConfig& cfg)
{
+ // for debugging:
+ // Benchmark bench;
+ // bench.start();
double mergedist = 2*(1.8*cfg.min_wall_thickness_mm + 4*cfg.edge_radius_mm)+
cfg.max_merge_distance_mm;
@@ -478,27 +596,28 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
// serve as the bottom plate of the pad. We will offset this concave hull
// and then offset back the result with clipper with rounding edges ON. This
// trick will create a nice rounded pad shape.
- auto concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
+ ExPolygons concavehs = concave_hull(ground_layer, mergedist, cfg.throw_on_cancel);
const double thickness = cfg.min_wall_thickness_mm;
const double wingheight = cfg.min_wall_height_mm;
const double fullheight = wingheight + thickness;
- const double tilt = PI/4;
+ const double tilt = cfg.wall_tilt;
const double wingdist = wingheight / std::tan(tilt);
// scaled values
const coord_t s_thickness = mm(thickness);
const coord_t s_eradius = mm(cfg.edge_radius_mm);
const coord_t s_safety_dist = 2*s_eradius + coord_t(0.8*s_thickness);
- // const coord_t wheight = mm(cfg.min_wall_height_mm);
- coord_t s_wingdist = mm(wingdist);
+ const coord_t s_wingdist = mm(wingdist);
auto& thrcl = cfg.throw_on_cancel;
+ Contour3D pool;
+
for(ExPolygon& concaveh : concavehs) {
if(concaveh.contour.points.empty()) return;
- // Get rif of any holes in the concave hull output.
+ // Get rid of any holes in the concave hull output.
concaveh.holes.clear();
// Here lies the trick that does the smooting only with clipper offset
@@ -508,15 +627,22 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
auto outer_base = concaveh;
outer_base.holes.clear();
offset(outer_base, s_safety_dist + s_wingdist + s_thickness);
- auto inner_base = outer_base;
- offset(inner_base, -(s_thickness + s_wingdist));
+
+
+ ExPolygon bottom_poly = outer_base;
+ bottom_poly.holes.clear();
+ if(s_wingdist > 0) offset(bottom_poly, -s_wingdist);
// Punching a hole in the top plate for the cavity
ExPolygon top_poly;
ExPolygon middle_base;
+ ExPolygon inner_base;
top_poly.contour = outer_base.contour;
if(wingheight > 0) {
+ inner_base = outer_base;
+ offset(inner_base, -(s_thickness + s_wingdist + s_eradius));
+
middle_base = outer_base;
offset(middle_base, -s_thickness);
top_poly.holes.emplace_back(middle_base.contour);
@@ -524,8 +650,6 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
std::reverse(tph.begin(), tph.end());
}
- Contour3D pool;
-
ExPolygon ob = outer_base; double wh = 0;
// now we will calculate the angle or portion of the circle from
@@ -557,60 +681,53 @@ void create_base_pool(const ExPolygons &ground_layer, TriangleMesh& out,
// Generate the smoothed edge geometry
- auto walledges = round_edges(ob,
- r,
- phi,
- 0, // z position of the input plane
- true,
- thrcl,
- ob, wh);
- pool.merge(walledges);
+ pool.merge(round_edges(ob,
+ r,
+ phi,
+ 0, // z position of the input plane
+ true,
+ thrcl,
+ ob, wh));
- // Now that we have the rounded edge connencting the top plate with
+ // Now that we have the rounded edge connecting the top plate with
// the outer side walls, we can generate and merge the sidewall geometry
- auto pwalls = walls(ob, inner_base, wh, -fullheight, thrcl);
- pool.merge(pwalls);
+ pool.merge(walls(ob.contour, bottom_poly.contour, wh, -fullheight,
+ wingdist, thrcl));
if(wingheight > 0) {
// Generate the smoothed edge geometry
- auto cavityedges = round_edges(middle_base,
- r,
- phi - 90, // from tangent lines
- 0,
- false,
- thrcl,
- ob, wh);
- pool.merge(cavityedges);
+ pool.merge(round_edges(middle_base,
+ r,
+ phi - 90, // from tangent lines
+ 0, // z position of the input plane
+ false,
+ thrcl,
+ ob, wh));
// Next is the cavity walls connecting to the top plate's
// artificially created hole.
- auto cavitywalls = walls(inner_base, ob, -wingheight, wh, thrcl);
- pool.merge(cavitywalls);
+ pool.merge(walls(inner_base.contour, ob.contour, -wingheight,
+ wh, -wingdist, thrcl));
}
// Now we need to triangulate the top and bottom plates as well as the
// cavity bottom plate which is the same as the bottom plate but it is
- // eleveted by the thickness.
- Polygons top_triangles, bottom_triangles;
+ // elevated by the thickness.
+ pool.merge(triangulate_expolygon_3d(top_poly));
+ pool.merge(triangulate_expolygon_3d(bottom_poly, -fullheight, true));
- triangulate(top_poly, top_triangles);
- triangulate(inner_base, bottom_triangles);
+ if(wingheight > 0)
+ pool.merge(triangulate_expolygon_3d(inner_base, -wingheight));
- auto top_plate = convert(top_triangles, 0, false);
- auto bottom_plate = convert(bottom_triangles, -mm(fullheight), true);
-
- pool.merge(top_plate);
- pool.merge(bottom_plate);
-
- if(wingheight > 0) {
- Polygons middle_triangles;
- triangulate(inner_base, middle_triangles);
- auto middle_plate = convert(middle_triangles, -mm(wingheight), false);
- pool.merge(middle_plate);
- }
-
- out.merge(mesh(pool));
}
+
+ // For debugging:
+ // bench.stop();
+ // std::cout << "Pad creation time: " << bench.getElapsedSec() << std::endl;
+ // std::fstream fout("pad_debug.obj", std::fstream::out);
+ // if(fout.good()) pool.to_obj(fout);
+
+ out.merge(mesh(pool));
}
}
diff --git a/src/libslic3r/SLA/SLABasePool.hpp b/src/libslic3r/SLA/SLABasePool.hpp
index 3917d995b7..69b4561b15 100644
--- a/src/libslic3r/SLA/SLABasePool.hpp
+++ b/src/libslic3r/SLA/SLABasePool.hpp
@@ -3,6 +3,7 @@
#include
#include
+#include
namespace Slic3r {
@@ -27,15 +28,17 @@ struct PoolConfig {
double min_wall_height_mm = 5;
double max_merge_distance_mm = 50;
double edge_radius_mm = 1;
+ double wall_tilt = std::atan(1.0); // Universal constant for Pi/4
ThrowOnCancel throw_on_cancel = [](){};
inline PoolConfig() {}
- inline PoolConfig(double wt, double wh, double md, double er):
+ inline PoolConfig(double wt, double wh, double md, double er, double tilt):
min_wall_thickness_mm(wt),
min_wall_height_mm(wh),
max_merge_distance_mm(md),
- edge_radius_mm(er) {}
+ edge_radius_mm(er),
+ wall_tilt(tilt) {}
};
/// Calculate the pool for the mesh for SLA printing
diff --git a/src/libslic3r/SLA/SLABoilerPlate.hpp b/src/libslic3r/SLA/SLABoilerPlate.hpp
index c1096206a2..602121af9a 100644
--- a/src/libslic3r/SLA/SLABoilerPlate.hpp
+++ b/src/libslic3r/SLA/SLABoilerPlate.hpp
@@ -36,14 +36,6 @@ inline coord_t x(const Vec3crd& p) { return p(0); }
inline coord_t y(const Vec3crd& p) { return p(1); }
inline coord_t z(const Vec3crd& p) { return p(2); }
-inline void triangulate(const ExPolygon& expoly, Polygons& triangles) {
- expoly.triangulate_p2t(&triangles);
-}
-
-inline Polygons triangulate(const ExPolygon& expoly) {
- Polygons tri; triangulate(expoly, tri); return tri;
-}
-
using Indices = std::vector;
/// Intermediate struct for a 3D mesh
@@ -63,6 +55,15 @@ struct Contour3D {
}
}
+ void merge(const Pointf3s& triangles) {
+ const size_t offs = points.size();
+ points.insert(points.end(), triangles.begin(), triangles.end());
+ indices.reserve(indices.size() + points.size() / 3);
+
+ for(int i = (int)offs; i < (int)points.size(); i += 3)
+ indices.emplace_back(i, i + 1, i + 2);
+ }
+
// Write the index triangle structure to OBJ file for debugging purposes.
void to_obj(std::ostream& stream) {
for(auto& p : points) {
@@ -75,13 +76,9 @@ struct Contour3D {
}
};
-//using PointSet = Eigen::Matrix; //Eigen::MatrixXd;
using ClusterEl = std::vector;
using ClusteredPoints = std::vector;
-/// Convert the triangulation output to an intermediate mesh.
-Contour3D convert(const Polygons& triangles, coord_t z, bool dir);
-
/// Mesh from an existing contour.
inline TriangleMesh mesh(const Contour3D& ctour) {
return {ctour.points, ctour.indices};
diff --git a/src/libslic3r/SLA/SLACommon.hpp b/src/libslic3r/SLA/SLACommon.hpp
new file mode 100644
index 0000000000..f7c0acf332
--- /dev/null
+++ b/src/libslic3r/SLA/SLACommon.hpp
@@ -0,0 +1,137 @@
+#ifndef SLACOMMON_HPP
+#define SLACOMMON_HPP
+
+#include
+
+// #define SLIC3R_SLA_NEEDS_WINDTREE
+
+namespace Slic3r {
+
+// Typedefs from Point.hpp
+typedef Eigen::Matrix Vec3f;
+typedef Eigen::Matrix Vec3d;
+
+class TriangleMesh;
+
+namespace sla {
+
+struct SupportPoint {
+ Vec3f pos;
+ float head_front_radius;
+ bool is_new_island;
+
+ SupportPoint() :
+ pos(Vec3f::Zero()), head_front_radius(0.f), is_new_island(false) {}
+
+ SupportPoint(float pos_x, float pos_y, float pos_z, float head_radius, bool new_island) :
+ pos(pos_x, pos_y, pos_z), head_front_radius(head_radius), is_new_island(new_island) {}
+
+ SupportPoint(Vec3f position, float head_radius, bool new_island) :
+ pos(position), head_front_radius(head_radius), is_new_island(new_island) {}
+
+ SupportPoint(Eigen::Matrix data) :
+ pos(data(0), data(1), data(2)), head_front_radius(data(3)), is_new_island(data(4) != 0.f) {}
+
+ bool operator==(const SupportPoint& sp) const { return (pos==sp.pos) && head_front_radius==sp.head_front_radius && is_new_island==sp.is_new_island; }
+ bool operator!=(const SupportPoint& sp) const { return !(sp == (*this)); }
+};
+
+
+/// An index-triangle structure for libIGL functions. Also serves as an
+/// alternative (raw) input format for the SLASupportTree
+/*struct EigenMesh3D {
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi F;
+ double ground_level = 0;
+};*/
+
+/// An index-triangle structure for libIGL functions. Also serves as an
+/// alternative (raw) input format for the SLASupportTree
+class EigenMesh3D {
+ class AABBImpl;
+
+ Eigen::MatrixXd m_V;
+ Eigen::MatrixXi m_F;
+ double m_ground_level = 0;
+
+ std::unique_ptr m_aabb;
+public:
+
+ EigenMesh3D(const TriangleMesh&);
+ EigenMesh3D(const EigenMesh3D& other);
+ EigenMesh3D& operator=(const EigenMesh3D&);
+
+ ~EigenMesh3D();
+
+ inline double ground_level() const { return m_ground_level; }
+
+ inline const Eigen::MatrixXd& V() const { return m_V; }
+ inline const Eigen::MatrixXi& F() const { return m_F; }
+
+ // Result of a raycast
+ class hit_result {
+ double m_t = std::numeric_limits::infinity();
+ int m_face_id = -1;
+ const EigenMesh3D& m_mesh;
+ Vec3d m_dir;
+ inline hit_result(const EigenMesh3D& em): m_mesh(em) {}
+ friend class EigenMesh3D;
+ public:
+
+ inline double distance() const { return m_t; }
+ inline const Vec3d& direction() const { return m_dir; }
+ inline int face() const { return m_face_id; }
+
+ inline Vec3d normal() const {
+ if(m_face_id < 0) return {};
+ auto trindex = m_mesh.m_F.row(m_face_id);
+ const Vec3d& p1 = m_mesh.V().row(trindex(0));
+ const Vec3d& p2 = m_mesh.V().row(trindex(1));
+ const Vec3d& p3 = m_mesh.V().row(trindex(2));
+ Eigen::Vector3d U = p2 - p1;
+ Eigen::Vector3d V = p3 - p1;
+ return U.cross(V).normalized();
+ }
+
+ inline bool is_inside() {
+ return m_face_id >= 0 && normal().dot(m_dir) > 0;
+ }
+ };
+
+ // Casting a ray on the mesh, returns the distance where the hit occures.
+ hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const;
+
+ class si_result {
+ double m_value;
+ int m_fidx;
+ Vec3d m_p;
+ si_result(double val, int i, const Vec3d& c):
+ m_value(val), m_fidx(i), m_p(c) {}
+ friend class EigenMesh3D;
+ public:
+
+ si_result() = delete;
+
+ double value() const { return m_value; }
+ operator double() const { return m_value; }
+ const Vec3d& point_on_mesh() const { return m_p; }
+ int F_idx() const { return m_fidx; }
+ };
+
+#ifdef SLIC3R_SLA_NEEDS_WINDTREE
+ // The signed distance from a point to the mesh. Outputs the distance,
+ // the index of the triangle and the closest point in mesh coordinate space.
+ si_result signed_distance(const Vec3d& p) const;
+
+ bool inside(const Vec3d& p) const;
+#endif /* SLIC3R_SLA_NEEDS_WINDTREE */
+};
+
+
+
+
+} // namespace sla
+} // namespace Slic3r
+
+
+#endif // SLASUPPORTTREE_HPP
\ No newline at end of file
diff --git a/src/libslic3r/SLA/SLASupportTree.cpp b/src/libslic3r/SLA/SLASupportTree.cpp
index 7cf6015cb8..913e9bedab 100644
--- a/src/libslic3r/SLA/SLASupportTree.cpp
+++ b/src/libslic3r/SLA/SLASupportTree.cpp
@@ -551,10 +551,16 @@ enum { // For indexing Eigen vectors as v(X), v(Y), v(Z) instead of numbers
X, Y, Z
};
-PointSet to_point_set(const std::vector &v)
+PointSet to_point_set(const std::vector &v)
{
PointSet ret(v.size(), 3);
- { long i = 0; for(const Vec3d& p : v) ret.row(i++) = p; }
+ long i = 0;
+ for(const SupportPoint& support_point : v) {
+ ret.row(i)(0) = support_point.pos(0);
+ ret.row(i)(1) = support_point.pos(1);
+ ret.row(i)(2) = support_point.pos(2);
+ ++i;
+ }
return ret;
}
@@ -679,6 +685,7 @@ double pinhead_mesh_intersect(const Vec3d& s,
return *mit;
}
+
// Checking bridge (pillar and stick as well) intersection with the model. If
// the function is used for headless sticks, the ins_check parameter have to be
// true as the beginning of the stick might be inside the model geometry.
diff --git a/src/libslic3r/SLA/SLASupportTree.hpp b/src/libslic3r/SLA/SLASupportTree.hpp
index 7d23a981fb..c29b2a5712 100644
--- a/src/libslic3r/SLA/SLASupportTree.hpp
+++ b/src/libslic3r/SLA/SLASupportTree.hpp
@@ -7,6 +7,9 @@
#include
#include
+#include "SLACommon.hpp"
+
+
namespace Slic3r {
// Needed types from Point.hpp
@@ -105,86 +108,6 @@ struct Controller {
std::function cancelfn = [](){};
};
-/// An index-triangle structure for libIGL functions. Also serves as an
-/// alternative (raw) input format for the SLASupportTree
-class EigenMesh3D {
- class AABBImpl;
-
- Eigen::MatrixXd m_V;
- Eigen::MatrixXi m_F;
- double m_ground_level = 0;
-
- std::unique_ptr m_aabb;
-public:
-
- EigenMesh3D(const TriangleMesh&);
- EigenMesh3D(const EigenMesh3D& other);
- EigenMesh3D& operator=(const EigenMesh3D&);
-
- ~EigenMesh3D();
-
- inline double ground_level() const { return m_ground_level; }
-
- inline const Eigen::MatrixXd& V() const { return m_V; }
- inline const Eigen::MatrixXi& F() const { return m_F; }
-
- // Result of a raycast
- class hit_result {
- double m_t = std::numeric_limits::infinity();
- int m_face_id = -1;
- const EigenMesh3D& m_mesh;
- Vec3d m_dir;
- inline hit_result(const EigenMesh3D& em): m_mesh(em) {}
- friend class EigenMesh3D;
- public:
-
- inline double distance() const { return m_t; }
-
- inline int face() const { return m_face_id; }
-
- inline Vec3d normal() const {
- if(m_face_id < 0) return {};
- auto trindex = m_mesh.m_F.row(m_face_id);
- const Vec3d& p1 = m_mesh.V().row(trindex(0));
- const Vec3d& p2 = m_mesh.V().row(trindex(1));
- const Vec3d& p3 = m_mesh.V().row(trindex(2));
- Eigen::Vector3d U = p2 - p1;
- Eigen::Vector3d V = p3 - p1;
- return U.cross(V).normalized();
- }
-
- inline bool is_inside() {
- return m_face_id >= 0 && normal().dot(m_dir) > 0;
- }
- };
-
- // Casting a ray on the mesh, returns the distance where the hit occures.
- hit_result query_ray_hit(const Vec3d &s, const Vec3d &dir) const;
-
- class si_result {
- double m_value;
- int m_fidx;
- Vec3d m_p;
- si_result(double val, int i, const Vec3d& c):
- m_value(val), m_fidx(i), m_p(c) {}
- friend class EigenMesh3D;
- public:
-
- si_result() = delete;
-
- double value() const { return m_value; }
- operator double() const { return m_value; }
- const Vec3d& point_on_mesh() const { return m_p; }
- int F_idx() const { return m_fidx; }
- };
-
- // The signed distance from a point to the mesh. Outputs the distance,
- // the index of the triangle and the closest point in mesh coordinate space.
- si_result signed_distance(const Vec3d& p) const;
-
- bool inside(const Vec3d& p) const;
-};
-
using PointSet = Eigen::MatrixXd;
//EigenMesh3D to_eigenmesh(const TriangleMesh& m);
@@ -193,7 +116,7 @@ using PointSet = Eigen::MatrixXd;
//EigenMesh3D to_eigenmesh(const ModelObject& model);
// Simple conversion of 'vector of points' to an Eigen matrix
-PointSet to_point_set(const std::vector&);
+PointSet to_point_set(const std::vector&);
/* ************************************************************************** */
diff --git a/src/libslic3r/SLA/SLASupportTreeIGL.cpp b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
index d3af1eac89..25638fe692 100644
--- a/src/libslic3r/SLA/SLASupportTreeIGL.cpp
+++ b/src/libslic3r/SLA/SLASupportTreeIGL.cpp
@@ -95,7 +95,9 @@ size_t SpatIndex::size() const
class EigenMesh3D::AABBImpl: public igl::AABB {
public:
+#ifdef SLIC3R_SLA_NEEDS_WINDTREE
igl::WindingNumberAABB windtree;
+#endif /* SLIC3R_SLA_NEEDS_WINDTREE */
};
EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
@@ -136,7 +138,9 @@ EigenMesh3D::EigenMesh3D(const TriangleMesh& tmesh): m_aabb(new AABBImpl()) {
// Build the AABB accelaration tree
m_aabb->init(m_V, m_F);
+#ifdef SLIC3R_SLA_NEEDS_WINDTREE
m_aabb->windtree.set_mesh(m_V, m_F);
+#endif /* SLIC3R_SLA_NEEDS_WINDTREE */
}
EigenMesh3D::~EigenMesh3D() {}
@@ -168,6 +172,7 @@ EigenMesh3D::query_ray_hit(const Vec3d &s, const Vec3d &dir) const
return ret;
}
+#ifdef SLIC3R_SLA_NEEDS_WINDTREE
EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const {
double sign = 0; double sqdst = 0; int i = 0; Vec3d c;
igl::signed_distance_winding_number(*m_aabb, m_V, m_F, m_aabb->windtree,
@@ -179,6 +184,7 @@ EigenMesh3D::si_result EigenMesh3D::signed_distance(const Vec3d &p) const {
bool EigenMesh3D::inside(const Vec3d &p) const {
return m_aabb->windtree.inside(p);
}
+#endif /* SLIC3R_SLA_NEEDS_WINDTREE */
/* ****************************************************************************
* Misc functions
@@ -199,9 +205,11 @@ template double distance(const Vec& pp1, const Vec& pp2) {
return std::sqrt(p.transpose() * p);
}
-PointSet normals(const PointSet& points, const EigenMesh3D& mesh,
+PointSet normals(const PointSet& points,
+ const EigenMesh3D& mesh,
double eps,
- std::function throw_on_cancel) {
+ std::function throw_on_cancel)
+{
if(points.rows() == 0 || mesh.V().rows() == 0 || mesh.F().rows() == 0)
return {};
@@ -222,7 +230,7 @@ PointSet normals(const PointSet& points, const EigenMesh3D& mesh,
const Vec3d& p3 = mesh.V().row(trindex(2));
// We should check if the point lies on an edge of the hosting triangle.
- // If it does than all the other triangles using the same two points
+ // If it does then all the other triangles using the same two points
// have to be searched and the final normal should be some kind of
// aggregation of the participating triangle normals. We should also
// consider the cases where the support point lies right on a vertex
diff --git a/src/libslic3r/SLAPrint.cpp b/src/libslic3r/SLAPrint.cpp
index 142428f1db..d83e756e83 100644
--- a/src/libslic3r/SLAPrint.cpp
+++ b/src/libslic3r/SLAPrint.cpp
@@ -2,12 +2,14 @@
#include "SLA/SLASupportTree.hpp"
#include "SLA/SLABasePool.hpp"
#include "SLA/SLAAutoSupports.hpp"
+#include "ClipperUtils.hpp"
#include "MTUtils.hpp"
#include
#include
#include
+#include
#include
//#include //#include "tbb/mutex.h"
@@ -25,7 +27,7 @@ using SupportTreePtr = std::unique_ptr;
class SLAPrintObject::SupportData {
public:
sla::EigenMesh3D emesh; // index-triangle representation
- sla::PointSet support_points; // all the support points (manual/auto)
+ std::vector support_points; // all the support points (manual/auto)
SupportTreePtr support_tree_ptr; // the supports
SlicedSupports support_slices; // sliced supports
std::vector level_ids;
@@ -51,7 +53,7 @@ const std::array OBJ_STEP_LABELS =
L("Slicing model"), // slaposObjectSlice,
L("Generating support points"), // slaposSupportPoints,
L("Generating support tree"), // slaposSupportTree,
- L("Generating base pool"), // slaposBasePool,
+ L("Generating pad"), // slaposBasePool,
L("Slicing supports"), // slaposSliceSupports,
L("Slicing supports") // slaposIndexSlices,
};
@@ -182,7 +184,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
if (model.id() != m_model.id()) {
// Kill everything, initialize from scratch.
// Stop background processing.
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_all_steps());
for (SLAPrintObject *object : m_objects) {
model_object_status.emplace(object->model_object()->id(), ModelObjectStatus::Deleted);
@@ -211,7 +213,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
} else {
// Reorder the objects, add new objects.
// First stop background processing before shuffling or deleting the PrintObjects in the object list.
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_step(slapsRasterize));
// Second create a new list of objects.
std::vector model_objects_old(std::move(m_model.objects));
@@ -308,7 +310,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id())
it_print_object_status = print_object_status.end();
// Check whether a model part volume was added or removed, their transformations or order changed.
- bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolume::MODEL_PART);
+ bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART);
bool sla_trafo_differs = model_object.instances.empty() != model_object_new.instances.empty() ||
(! model_object.instances.empty() && ! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)));
if (model_parts_differ || sla_trafo_differs) {
@@ -354,14 +356,18 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
std::vector new_instances = sla_instances(model_object);
if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) {
// The SLAPrintObject is already there.
- if (new_instances != it_print_object_status->print_object->instances()) {
- // Instances changed.
- it_print_object_status->print_object->set_instances(new_instances);
- update_apply_status(this->invalidate_step(slapsRasterize));
- }
- print_objects_new.emplace_back(it_print_object_status->print_object);
- const_cast(*it_print_object_status).status = PrintObjectStatus::Reused;
- } else {
+ if (new_instances.empty()) {
+ const_cast(*it_print_object_status).status = PrintObjectStatus::Deleted;
+ } else {
+ if (new_instances != it_print_object_status->print_object->instances()) {
+ // Instances changed.
+ it_print_object_status->print_object->set_instances(new_instances);
+ update_apply_status(this->invalidate_step(slapsRasterize));
+ }
+ print_objects_new.emplace_back(it_print_object_status->print_object);
+ const_cast(*it_print_object_status).status = PrintObjectStatus::Reused;
+ }
+ } else if (! new_instances.empty()) {
auto print_object = new SLAPrintObject(this, &model_object);
// FIXME: this invalidates the transformed mesh in SLAPrintObject
@@ -376,7 +382,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
}
if (m_objects != print_objects_new) {
- this->call_cancell_callback();
+ this->call_cancel_callback();
update_apply_status(this->invalidate_all_steps());
m_objects = print_objects_new;
// Delete the PrintObjects marked as Unknown or Deleted.
@@ -398,6 +404,113 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf
return static_cast(apply_status);
}
+// After calling the apply() function, set_task() may be called to limit the task to be processed by process().
+void SLAPrint::set_task(const TaskParams ¶ms)
+{
+ // Grab the lock for the Print / PrintObject milestones.
+ tbb::mutex::scoped_lock lock(this->state_mutex());
+
+ int n_object_steps = int(params.to_object_step) + 1;
+ if (n_object_steps == 0)
+ n_object_steps = (int)slaposCount;
+
+ if (params.single_model_object.valid()) {
+ // Find the print object to be processed with priority.
+ SLAPrintObject *print_object = nullptr;
+ size_t idx_print_object = 0;
+ for (; idx_print_object < m_objects.size(); ++ idx_print_object)
+ if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) {
+ print_object = m_objects[idx_print_object];
+ break;
+ }
+ assert(print_object != nullptr);
+ // Find out whether the priority print object is being currently processed.
+ bool running = false;
+ for (int istep = 0; istep < n_object_steps; ++ istep) {
+ if (! print_object->m_stepmask[istep])
+ // Step was skipped, cancel.
+ break;
+ if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
+ // No step was skipped, and a wanted step is being processed. Don't cancel.
+ running = true;
+ break;
+ }
+ }
+ if (! running)
+ this->call_cancel_callback();
+
+ // Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
+ if (params.single_model_instance_only) {
+ // Suppress all the steps of other instances.
+ for (SLAPrintObject *po : m_objects)
+ for (int istep = 0; istep < (int)slaposCount; ++ istep)
+ po->m_stepmask[istep] = false;
+ } else if (! running) {
+ // Swap the print objects, so that the selected print_object is first in the row.
+ // At this point the background processing must be stopped, so it is safe to shuffle print objects.
+ if (idx_print_object != 0)
+ std::swap(m_objects.front(), m_objects[idx_print_object]);
+ }
+ // and set the steps for the current object.
+ for (int istep = 0; istep < n_object_steps; ++ istep)
+ print_object->m_stepmask[istep] = true;
+ for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
+ print_object->m_stepmask[istep] = false;
+ } else {
+ // Slicing all objects.
+ bool running = false;
+ for (SLAPrintObject *print_object : m_objects)
+ for (int istep = 0; istep < n_object_steps; ++ istep) {
+ if (! print_object->m_stepmask[istep]) {
+ // Step may have been skipped. Restart.
+ goto loop_end;
+ }
+ if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) {
+ // This step is running, and the state cannot be changed due to the this->state_mutex() being locked.
+ // It is safe to manipulate m_stepmask of other SLAPrintObjects and SLAPrint now.
+ running = true;
+ goto loop_end;
+ }
+ }
+ loop_end:
+ if (! running)
+ this->call_cancel_callback();
+ for (SLAPrintObject *po : m_objects) {
+ for (int istep = 0; istep < n_object_steps; ++ istep)
+ po->m_stepmask[istep] = true;
+ for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep)
+ po->m_stepmask[istep] = false;
+ }
+ }
+
+ if (params.to_object_step != -1 || params.to_print_step != -1) {
+ // Limit the print steps.
+ size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1;
+ for (; istep < m_stepmask.size(); ++ istep)
+ m_stepmask[istep] = false;
+ }
+}
+
+// Clean up after process() finished, either with success, error or if canceled.
+// The adjustments on the SLAPrint / SLAPrintObject data due to set_task() are to be reverted here.
+void SLAPrint::finalize()
+{
+ for (SLAPrintObject *po : m_objects)
+ for (int istep = 0; istep < (int)slaposCount; ++ istep)
+ po->m_stepmask[istep] = true;
+ for (int istep = 0; istep < (int)slapsCount; ++ istep)
+ m_stepmask[istep] = true;
+}
+
+// Generate a recommended output file name based on the format template, default extension, and template parameters
+// (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
+// Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before the output is finalized).
+std::string SLAPrint::output_filename() const
+{
+ DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders();
+ return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "zip", &config);
+}
+
namespace {
// Compile the argument for support creation from the static print config.
sla::SupportConfig make_support_cfg(const SLAPrintObjectConfig& c) {
@@ -472,7 +585,7 @@ void SLAPrint::process()
const size_t objcount = m_objects.size();
const unsigned min_objstatus = 0; // where the per object operations start
- const unsigned max_objstatus = 80; // where the per object operations end
+ const unsigned max_objstatus = PRINT_STEP_LEVELS[slapsRasterize]; // where the per object operations end
// the coefficient that multiplies the per object status values which
// are set up for <0, 100>. They need to be scaled into the whole process
@@ -532,9 +645,8 @@ void SLAPrint::process()
this->throw_if_canceled();
SLAAutoSupports::Config config;
const SLAPrintObjectConfig& cfg = po.config();
- config.minimal_z = float(cfg.support_minimal_z);
- config.density_at_45 = cfg.support_density_at_45 / 10000.f;
- config.density_at_horizontal = cfg.support_density_at_horizontal / 10000.f;
+ config.density_relative = float(cfg.support_points_density_relative / 100.f); // the config value is in percents
+ config.minimal_distance = float(cfg.support_points_minimal_distance);
// Construction of this object does the calculation.
this->throw_if_canceled();
@@ -546,17 +658,19 @@ void SLAPrint::process()
[this]() { throw_if_canceled(); });
// Now let's extract the result.
- const std::vector& points = auto_supports.output();
+ const std::vector& points = auto_supports.output();
this->throw_if_canceled();
- po.m_supportdata->support_points = sla::to_point_set(points);
+ po.m_supportdata->support_points = points;
BOOST_LOG_TRIVIAL(debug) << "Automatic support points: "
- << po.m_supportdata->support_points.rows();
+ << po.m_supportdata->support_points.size();
+
+ // Using RELOAD_SLA_SUPPORT_POINTS to tell the Plater to pass the update status to GLGizmoSlaSupports
+ report_status(*this, -1, L("Generating support points"), SlicingStatus::RELOAD_SLA_SUPPORT_POINTS);
}
else {
// There are some points on the front-end, no calculation will be done.
- po.m_supportdata->support_points =
- sla::to_point_set(po.transformed_support_points());
+ po.m_supportdata->support_points = po.transformed_support_points();
}
};
@@ -587,6 +701,8 @@ void SLAPrint::process()
ctl.statuscb = [this, init, d](unsigned st, const std::string& msg)
{
+ //FIXME this status line scaling does not seem to be correct.
+ // How does it account for an increasing object index?
report_status(*this, int(init + st*d), msg);
};
@@ -594,7 +710,7 @@ void SLAPrint::process()
ctl.cancelfn = [this]() { throw_if_canceled(); };
po.m_supportdata->support_tree_ptr.reset(
- new SLASupportTree(po.m_supportdata->support_points,
+ new SLASupportTree(sla::to_point_set(po.m_supportdata->support_points),
po.m_supportdata->emesh, scfg, ctl));
// Create the unified mesh
@@ -605,7 +721,7 @@ void SLAPrint::process()
po.m_supportdata->support_tree_ptr->merged_mesh();
BOOST_LOG_TRIVIAL(debug) << "Processed support point count "
- << po.m_supportdata->support_points.rows();
+ << po.m_supportdata->support_points.size();
// Check the mesh for later troubleshooting.
if(po.support_mesh().empty())
@@ -635,11 +751,13 @@ void SLAPrint::process()
double wt = po.m_config.pad_wall_thickness.getFloat();
double h = po.m_config.pad_wall_height.getFloat();
double md = po.m_config.pad_max_merge_distance.getFloat();
- double er = po.m_config.pad_edge_radius.getFloat();
+ // Radius is disabled for now...
+ double er = 0; // po.m_config.pad_edge_radius.getFloat();
+ double tilt = po.m_config.pad_wall_tilt.getFloat() * PI / 180.0;
double lh = po.m_config.layer_height.getFloat();
double elevation = po.m_config.support_object_elevation.getFloat();
if(!po.m_config.supports_enable.getBool()) elevation = 0;
- sla::PoolConfig pcfg(wt, h, md, er);
+ sla::PoolConfig pcfg(wt, h, md, er, tilt);
ExPolygons bp;
double pad_h = sla::get_pad_fullheight(pcfg);
@@ -650,8 +768,7 @@ void SLAPrint::process()
if(elevation < pad_h) {
// we have to count with the model geometry for the base plate
- sla::base_plate(trmesh, bp, float(pad_h), float(lh),
- thrfn);
+ sla::base_plate(trmesh, bp, float(pad_h), float(lh), thrfn);
}
pcfg.throw_on_cancel = thrfn;
@@ -878,21 +995,20 @@ void SLAPrint::process()
// Print all the layers in parallel
tbb::parallel_for(0, lvlcnt, lvlfn);
+
+ // Fill statistics
+ this->fill_statistics();
+ // Set statistics values to the printer
+ m_printer->set_statistics({(m_print_statistics.objects_used_material + m_print_statistics.support_used_material)/1000,
+ double(m_default_object_config.faded_layers.getInt()),
+ double(m_print_statistics.slow_layers_count),
+ double(m_print_statistics.fast_layers_count)
+ });
};
using slaposFn = std::function;
using slapsFn = std::function;
- // This is the actual order of steps done on each PrintObject
- std::array objectsteps = {
- slaposObjectSlice, // SupportPoints will need this step
- slaposSupportPoints,
- slaposSupportTree,
- slaposBasePool,
- slaposSliceSupports,
- slaposIndexSlices
- };
-
std::array pobj_program =
{
slice_model,
@@ -916,28 +1032,32 @@ void SLAPrint::process()
// TODO: this loop could run in parallel but should not exhaust all the CPU
// power available
- for(SLAPrintObject * po : m_objects) {
+ // Calculate the support structures first before slicing the supports, so that the preview will get displayed ASAP for all objects.
+ std::vector step_ranges = { slaposObjectSlice, slaposSliceSupports, slaposCount };
+ for (size_t idx_range = 0; idx_range + 1 < step_ranges.size(); ++ idx_range) {
+ for(SLAPrintObject * po : m_objects) {
- BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name;
+ BOOST_LOG_TRIVIAL(info) << "Slicing object " << po->model_object()->name;
- for(size_t s = 0; s < objectsteps.size(); ++s) {
- auto currentstep = objectsteps[s];
+ for (int s = (int)step_ranges[idx_range]; s < (int)step_ranges[idx_range + 1]; ++s) {
+ auto currentstep = (SLAPrintObjectStep)s;
- // Cancellation checking. Each step will check for cancellation
- // on its own and return earlier gracefully. Just after it returns
- // execution gets to this point and throws the canceled signal.
- throw_if_canceled();
-
- st += unsigned(incr * ostepd);
-
- if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
- report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
- pobj_program[currentstep](*po);
+ // Cancellation checking. Each step will check for cancellation
+ // on its own and return earlier gracefully. Just after it returns
+ // execution gets to this point and throws the canceled signal.
throw_if_canceled();
- po->set_done(currentstep);
- }
- incr = OBJ_STEP_LEVELS[currentstep];
+ st += unsigned(incr * ostepd);
+
+ if(po->m_stepmask[currentstep] && po->set_started(currentstep)) {
+ report_status(*this, int(st), OBJ_STEP_LABELS[currentstep]);
+ pobj_program[currentstep](*po);
+ throw_if_canceled();
+ po->set_done(currentstep);
+ }
+
+ incr = OBJ_STEP_LEVELS[currentstep];
+ }
}
}
@@ -994,7 +1114,10 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector steps;
@@ -1027,6 +1150,166 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector& instances) {
+ const size_t inst_cnt = instances.size();
+
+ size_t polygon_cnt = 0;
+ for (const ExPolygon& polygon : input_polygons)
+ polygon_cnt += polygon.holes.size() + 1;
+
+ Polygons polygons;
+ polygons.reserve(polygon_cnt * inst_cnt);
+ for (const ExPolygon& polygon : input_polygons) {
+ for (size_t i = 0; i < inst_cnt; ++i)
+ {
+ ExPolygon tmp = polygon;
+ tmp.rotate(Geometry::rad2deg(instances[i].rotation));
+ tmp.translate(instances[i].shift.x(), instances[i].shift.y());
+ polygons_append(polygons, to_polygons(std::move(tmp)));
+ }
+ }
+ return polygons;
+ };
+
+ double supports_volume = 0.0;
+ double models_volume = 0.0;
+
+ double estim_time = 0.0;
+
+ size_t slow_layers = 0;
+ size_t fast_layers = 0;
+
+ // find highest object
+ // Which is a better bet? To compare by max_z or by number of layers in the index?
+ double max_z = 0.;
+ size_t max_layers_cnt = 0;
+ size_t highest_obj_idx = 0;
+ for (SLAPrintObject *&po : m_objects) {
+ const SLAPrintObject::SliceIndex& slice_index = po->get_slice_index();
+ if (! slice_index.empty()) {
+ double z = (-- slice_index.end())->first;
+ size_t cnt = slice_index.size();
+ //if (z > max_z) {
+ if (cnt > max_layers_cnt) {
+ max_layers_cnt = cnt;
+ max_z = z;
+ highest_obj_idx = &po - &m_objects.front();
+ }
+ }
+ }
+
+ const SLAPrintObject * highest_obj = m_objects[highest_obj_idx];
+ const SLAPrintObject::SliceIndex& highest_obj_slice_index = highest_obj->get_slice_index();
+
+ const double delta_fade_time = (init_exp_time - exp_time) / (fade_layers_cnt + 1);
+ double fade_layer_time = init_exp_time;
+
+ int sliced_layer_cnt = 0;
+ for (const auto& layer : highest_obj_slice_index)
+ {
+ const double l_height = (layer.first == highest_obj_slice_index.begin()->first) ? init_layer_height : layer_height;
+
+ // Calculation of the consumed material
+
+ Polygons model_polygons;
+ Polygons supports_polygons;
+
+ for (SLAPrintObject * po : m_objects)
+ {
+ const SLAPrintObject::SliceRecord *record = nullptr;
+ {
+ const SLAPrintObject::SliceIndex& index = po->get_slice_index();
+ auto key = layer.first;
+ const SLAPrintObject::SliceIndex::const_iterator it_key = index.lower_bound(key - float(EPSILON));
+ if (it_key == index.end() || it_key->first > key + EPSILON)
+ continue;
+ record = &it_key->second;
+ }
+
+ if (record->model_slices_idx != SLAPrintObject::SliceRecord::NONE)
+ append(model_polygons, get_all_polygons(po->get_model_slices()[record->model_slices_idx], po->instances()));
+
+ if (record->support_slices_idx != SLAPrintObject::SliceRecord::NONE)
+ append(supports_polygons, get_all_polygons(po->get_support_slices()[record->support_slices_idx], po->instances()));
+ }
+
+ model_polygons = union_(model_polygons);
+ double layer_model_area = 0;
+ for (const Polygon& polygon : model_polygons)
+ layer_model_area += polygon.area();
+
+ if (layer_model_area != 0)
+ models_volume += layer_model_area * l_height;
+
+ if (!supports_polygons.empty() && !model_polygons.empty())
+ supports_polygons = diff(supports_polygons, model_polygons);
+ double layer_support_area = 0;
+ for (const Polygon& polygon : supports_polygons)
+ layer_support_area += polygon.area();
+
+ if (layer_support_area != 0)
+ supports_volume += layer_support_area * l_height;
+
+ // Calculation of the slow and fast layers to the future controlling those values on FW
+
+ const bool is_fast_layer = (layer_model_area + layer_support_area) <= display_area*area_fill;
+ const double tilt_time = is_fast_layer ? fast_tilt : slow_tilt;
+ if (is_fast_layer)
+ fast_layers++;
+ else
+ slow_layers++;
+
+
+ // Calculation of the printing time
+
+ if (sliced_layer_cnt < 3)
+ estim_time += init_exp_time;
+ else if (fade_layer_time > exp_time)
+ {
+ fade_layer_time -= delta_fade_time;
+ estim_time += fade_layer_time;
+ }
+ else
+ estim_time += exp_time;
+
+ estim_time += tilt_time;
+
+ sliced_layer_cnt++;
+ }
+
+ m_print_statistics.support_used_material = supports_volume * SCALING_FACTOR * SCALING_FACTOR;
+ m_print_statistics.objects_used_material = models_volume * SCALING_FACTOR * SCALING_FACTOR;
+
+ // Estimated printing time
+ // A layers count o the highest object
+ if (max_layers_cnt == 0)
+ m_print_statistics.estimated_print_time = "N/A";
+ else
+ m_print_statistics.estimated_print_time = get_time_dhms(float(estim_time));
+
+ m_print_statistics.fast_layers_count = fast_layers;
+ m_print_statistics.slow_layers_count = slow_layers;
+}
+
// Returns true if an object step is done on all objects and there's at least one object.
bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
{
@@ -1034,7 +1317,7 @@ bool SLAPrint::is_step_done(SLAPrintObjectStep step) const
return false;
tbb::mutex::scoped_lock lock(this->state_mutex());
for (const SLAPrintObject *object : m_objects)
- if (! object->m_state.is_done_unguarded(step))
+ if (! object->is_step_done_unguarded(step))
return false;
return true;
}
@@ -1060,9 +1343,13 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector steps;
bool invalidated = false;
for (const t_config_option_key &opt_key : opt_keys) {
- if (opt_key == "layer_height") {
+ if ( opt_key == "layer_height"
+ || opt_key == "faded_layers") {
steps.emplace_back(slaposObjectSlice);
- } else if (opt_key == "supports_enable") {
+ } else if (
+ opt_key == "supports_enable"
+ || opt_key == "support_points_density_relative"
+ || opt_key == "support_points_minimal_distance") {
steps.emplace_back(slaposSupportPoints);
} else if (
opt_key == "support_head_front_diameter"
@@ -1082,6 +1369,7 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector EMPTY_SLICES;
const TriangleMesh EMPTY_MESH;
}
-const Eigen::MatrixXd& SLAPrintObject::get_support_points() const
+const std::vector& SLAPrintObject::get_support_points() const
{
return m_supportdata->support_points;
}
@@ -1244,17 +1532,60 @@ const TriangleMesh &SLAPrintObject::transformed_mesh() const {
return m_transformed_rmesh.get();
}
-std::vector SLAPrintObject::transformed_support_points() const
+std::vector SLAPrintObject::transformed_support_points() const
{
assert(m_model_object != nullptr);
- auto& spts = m_model_object->sla_support_points;
+ std::vector& spts = m_model_object->sla_support_points;
// this could be cached as well
- std::vector ret; ret.reserve(spts.size());
+ std::vector ret;
+ ret.reserve(spts.size());
- for(auto& sp : spts) ret.emplace_back( trafo() * Vec3d(sp.cast()));
+ for(sla::SupportPoint& sp : spts) {
+ Vec3d transformed_pos = trafo() * Vec3d(sp.pos(0), sp.pos(1), sp.pos(2));
+ ret.emplace_back(transformed_pos(0), transformed_pos(1), transformed_pos(2), sp.head_front_radius, sp.is_new_island);
+ }
return ret;
}
+DynamicConfig SLAPrintStatistics::config() const
+{
+ DynamicConfig config;
+ const std::string print_time = Slic3r::short_time(this->estimated_print_time);
+ config.set_key_value("print_time", new ConfigOptionString(print_time));
+ config.set_key_value("objects_used_material", new ConfigOptionFloat(this->objects_used_material));
+ config.set_key_value("support_used_material", new ConfigOptionFloat(this->support_used_material));
+ config.set_key_value("total_cost", new ConfigOptionFloat(this->total_cost));
+ config.set_key_value("total_weight", new ConfigOptionFloat(this->total_weight));
+ return config;
+}
+
+DynamicConfig SLAPrintStatistics::placeholders()
+{
+ DynamicConfig config;
+ for (const std::string &key : {
+ "print_time", "total_cost", "total_weight",
+ "objects_used_material", "support_used_material" })
+ config.set_key_value(key, new ConfigOptionString(std::string("{") + key + "}"));
+ return config;
+}
+
+std::string SLAPrintStatistics::finalize_output_path(const std::string &path_in) const
+{
+ std::string final_path;
+ try {
+ boost::filesystem::path path(path_in);
+ DynamicConfig cfg = this->config();
+ PlaceholderParser pp;
+ std::string new_stem = pp.process(path.stem().string(), 0, &cfg);
+ final_path = (path.parent_path() / (new_stem + path.extension().string())).string();
+ }
+ catch (const std::exception &ex) {
+ BOOST_LOG_TRIVIAL(error) << "Failed to apply the print statistics to the export file name: " << ex.what();
+ final_path = path_in;
+ }
+ return final_path;
+}
+
} // namespace Slic3r
diff --git a/src/libslic3r/SLAPrint.hpp b/src/libslic3r/SLAPrint.hpp
index 21503c6f6a..4ac17f7b5c 100644
--- a/src/libslic3r/SLAPrint.hpp
+++ b/src/libslic3r/SLAPrint.hpp
@@ -2,7 +2,6 @@
#define slic3r_SLAPrint_hpp_
#include
-
#include "PrintBase.hpp"
#include "PrintExport.hpp"
#include "Point.hpp"
@@ -70,7 +69,7 @@ public:
// This will return the transformed mesh which is cached
const TriangleMesh& transformed_mesh() const;
- std::vector transformed_support_points() const;
+ std::vector transformed_support_points() const;
// Get the needed Z elevation for the model geometry if supports should be
// displayed. This Z offset should also be applied to the support
@@ -91,7 +90,7 @@ public:
const std::vector& get_support_slices() const;
// This method returns the support points of this SLAPrintObject.
- const Eigen::MatrixXd& get_support_points() const;
+ const std::vector& get_support_points() const;
// An index record referencing the slices
// (get_model_slices(), get_support_slices()) where the keys are the height
@@ -139,6 +138,10 @@ protected:
// Invalidate steps based on a set of parameters changed.
bool invalidate_state_by_config_options(const std::vector &opt_keys);
+ // Which steps have to be performed. Implicitly: all
+ // to be accessible from SLAPrint
+ std::vector