Merge branch 'master' into gui3-shortcuts

This commit is contained in:
Alessandro Ranellucci 2017-04-29 19:57:53 +02:00
commit 202a00c270
28 changed files with 504 additions and 214 deletions

2
.gitignore vendored
View File

@ -14,3 +14,5 @@ xs/assertlib*
local-lib local-lib
package/osx/Slic3r*.app package/osx/Slic3r*.app
*.dmg *.dmg
*.swp
*.swo

View File

@ -7,7 +7,6 @@ install:
- export SLIC3R_STATIC=1 - export SLIC3R_STATIC=1
- export CXX=g++-4.9 - export CXX=g++-4.9
- export CC=g++-4.9 - export CC=g++-4.9
- export WXDIR=$HOME/wx302
- source $HOME/perl5/perlbrew/etc/bashrc - source $HOME/perl5/perlbrew/etc/bashrc
script: script:
- bash package/linux/travis-setup.sh - bash package/linux/travis-setup.sh
@ -32,6 +31,8 @@ addons:
packages: packages:
- g++-4.9 - g++-4.9
- gcc-4.9 - gcc-4.9
- libgtk2.0-0
- libgtk2.0-dev
ssh_known_hosts: dl.slic3r.org ssh_known_hosts: dl.slic3r.org
notifications: notifications:
irc: irc:

View File

@ -5,6 +5,7 @@ use utf8;
use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow
:filedialog :font); :filedialog :font);
use Wx::Event qw(EVT_MENU);
BEGIN { BEGIN {
# Wrap the Wx::_load_plugin() function which doesn't work with non-ASCII paths # Wrap the Wx::_load_plugin() function which doesn't work with non-ASCII paths
@ -436,6 +437,30 @@ sub scan_serial_ports {
return grep !/Bluetooth|FireFly/, @ports; return grep !/Bluetooth|FireFly/, @ports;
} }
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 { sub set_menu_item_icon {
my ($self, $menuItem, $icon) = @_; my ($self, $menuItem, $icon) = @_;

View File

@ -10,7 +10,7 @@ use List::Util qw(min);
use Slic3r::Geometry qw(X Y Z); use Slic3r::Geometry qw(X Y Z);
use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog
:font :icon wxTheApp); :font :icon wxTheApp);
use Wx::Event qw(EVT_CLOSE EVT_MENU EVT_NOTEBOOK_PAGE_CHANGED); use Wx::Event qw(EVT_CLOSE EVT_NOTEBOOK_PAGE_CHANGED);
use base 'Wx::Frame'; use base 'Wx::Frame';
our $qs_last_input_file; our $qs_last_input_file;
@ -109,60 +109,60 @@ sub _init_menubar {
# File menu # File menu
my $fileMenu = Wx::Menu->new; my $fileMenu = Wx::Menu->new;
{ {
$self->_append_menu_item($fileMenu, "Open STL/OBJ/AMF…\tCtrl+O", 'Open a model', sub { wxTheApp->append_menu_item($fileMenu, "Open STL/OBJ/AMF…\tCtrl+O", 'Open a model', sub {
$self->{plater}->add if $self->{plater}; $self->{plater}->add if $self->{plater};
}, undef, 'brick_add.png'); }, undef, 'brick_add.png');
$self->_append_menu_item($fileMenu, "Open 2.5D TIN mesh…", 'Import a 2.5D TIN mesh', sub { wxTheApp->append_menu_item($fileMenu, "Open 2.5D TIN mesh…", 'Import a 2.5D TIN mesh', sub {
$self->{plater}->add_tin if $self->{plater}; $self->{plater}->add_tin if $self->{plater};
}, undef, 'map_add.png'); }, undef, 'map_add.png');
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, "&Load Config…\tCtrl+L", 'Load exported configuration file', sub { wxTheApp->append_menu_item($fileMenu, "&Load Config…\tCtrl+L", 'Load exported configuration file', sub {
$self->load_config_file; $self->load_config_file;
}, undef, 'plugin_add.png'); }, undef, 'plugin_add.png');
$self->_append_menu_item($fileMenu, "&Export Config…\tCtrl+E", 'Export current configuration to file', sub { wxTheApp->append_menu_item($fileMenu, "&Export Config…\tCtrl+E", 'Export current configuration to file', sub {
$self->export_config; $self->export_config;
}, undef, 'plugin_go.png'); }, undef, 'plugin_go.png');
$self->_append_menu_item($fileMenu, "&Load Config Bundle…", 'Load presets from a bundle', sub { wxTheApp->append_menu_item($fileMenu, "&Load Config Bundle…", 'Load presets from a bundle', sub {
$self->load_configbundle; $self->load_configbundle;
}, undef, 'lorry_add.png'); }, undef, 'lorry_add.png');
$self->_append_menu_item($fileMenu, "&Export Config Bundle…", 'Export all presets to file', sub { wxTheApp->append_menu_item($fileMenu, "&Export Config Bundle…", 'Export all presets to file', sub {
$self->export_configbundle; $self->export_configbundle;
}, undef, 'lorry_go.png'); }, undef, 'lorry_go.png');
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
my $repeat; my $repeat;
$self->_append_menu_item($fileMenu, "Q&uick Slice…\tCtrl+U", 'Slice file', sub { wxTheApp->append_menu_item($fileMenu, "Q&uick Slice…\tCtrl+U", 'Slice file', sub {
wxTheApp->CallAfter(sub { wxTheApp->CallAfter(sub {
$self->quick_slice; $self->quick_slice;
$repeat->Enable(defined $Slic3r::GUI::MainFrame::last_input_file); $repeat->Enable(defined $Slic3r::GUI::MainFrame::last_input_file);
}); });
}, undef, 'cog_go.png'); }, undef, 'cog_go.png');
$self->_append_menu_item($fileMenu, "Quick Slice and Save &As…\tCtrl+Alt+U", 'Slice file and save as', sub { wxTheApp->append_menu_item($fileMenu, "Quick Slice and Save &As…\tCtrl+Alt+U", 'Slice file and save as', sub {
wxTheApp->CallAfter(sub { wxTheApp->CallAfter(sub {
$self->quick_slice(save_as => 1); $self->quick_slice(save_as => 1);
$repeat->Enable(defined $Slic3r::GUI::MainFrame::last_input_file); $repeat->Enable(defined $Slic3r::GUI::MainFrame::last_input_file);
}); });
}, undef, 'cog_go.png'); }, undef, 'cog_go.png');
$repeat = $self->_append_menu_item($fileMenu, "&Repeat Last Quick Slice\tCtrl+Shift+U", 'Repeat last quick slice', sub { $repeat = wxTheApp->append_menu_item($fileMenu, "&Repeat Last Quick Slice\tCtrl+Shift+U", 'Repeat last quick slice', sub {
wxTheApp->CallAfter(sub { wxTheApp->CallAfter(sub {
$self->quick_slice(reslice => 1); $self->quick_slice(reslice => 1);
}); });
}, undef, 'cog_go.png'); }, undef, 'cog_go.png');
$repeat->Enable(0); $repeat->Enable(0);
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, "Slice to SV&G…\tCtrl+G", 'Slice file to SVG', sub { wxTheApp->append_menu_item($fileMenu, "Slice to SV&G…\tCtrl+G", 'Slice file to SVG', sub {
$self->quick_slice(save_as => 1, export_svg => 1); $self->quick_slice(save_as => 1, export_svg => 1);
}, undef, 'shape_handles.png'); }, undef, 'shape_handles.png');
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, "Repair STL file…", 'Automatically repair an STL file', sub { wxTheApp->append_menu_item($fileMenu, "Repair STL file…", 'Automatically repair an STL file', sub {
$self->repair_stl; $self->repair_stl;
}, undef, 'wrench.png'); }, undef, 'wrench.png');
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
# Cmd+, is standard on OS X - what about other operating systems? # Cmd+, is standard on OS X - what about other operating systems?
$self->_append_menu_item($fileMenu, "Preferences…\tCtrl+,", 'Application preferences', sub { wxTheApp->append_menu_item($fileMenu, "Preferences…\tCtrl+,", 'Application preferences', sub {
Slic3r::GUI::Preferences->new($self)->ShowModal; Slic3r::GUI::Preferences->new($self)->ShowModal;
}, wxID_PREFERENCES); }, wxID_PREFERENCES);
$fileMenu->AppendSeparator(); $fileMenu->AppendSeparator();
$self->_append_menu_item($fileMenu, "&Quit", 'Quit Slic3r', sub { wxTheApp->append_menu_item($fileMenu, "&Quit", 'Quit Slic3r', sub {
$self->Close(0); $self->Close(0);
}, wxID_EXIT); }, wxID_EXIT);
} }
@ -174,23 +174,22 @@ sub _init_menubar {
$self->{plater_menu} = Wx::Menu->new; $self->{plater_menu} = Wx::Menu->new;
{ {
my $selectMenu = $self->{plater_select_menu} = Wx::Menu->new; my $selectMenu = $self->{plater_select_menu} = Wx::Menu->new;
my $selectMenuItem = $self->{plater_menu}->AppendSubMenu($selectMenu, "Select", 'Select an object in the plater'); wxTheApp->append_submenu($self->{plater_menu}, "Select", 'Select an object in the plater', $selectMenu, undef, 'brick.png');
wxTheApp->set_menu_item_icon($selectMenuItem, 'brick.png');
} }
$self->_append_menu_item($self->{plater_menu}, "Select Next Object\tCtrl+Right", 'Select Next Object in the plater', sub { wxTheApp->append_menu_item($self->{plater_menu}, "Select Next Object\tCtrl+Right", 'Select Next Object in the plater', sub {
$plater->select_next; $plater->select_next;
}, undef, 'arrow_right.png'); }, undef, 'arrow_right.png');
$self->_append_menu_item($self->{plater_menu}, "Select Prev Object\tCtrl+Left", 'Select Previous Object in the plater', sub { wxTheApp->append_menu_item($self->{plater_menu}, "Select Prev Object\tCtrl+Left", 'Select Previous Object in the plater', sub {
$plater->select_prev; $plater->select_prev;
}, undef, 'arrow_left.png'); }, undef, 'arrow_left.png');
$self->{plater_menu}->AppendSeparator(); $self->{plater_menu}->AppendSeparator();
$self->_append_menu_item($self->{plater_menu}, "Export G-code...", 'Export current plate as G-code', sub { wxTheApp->append_menu_item($self->{plater_menu}, "Export G-code...", 'Export current plate as G-code', sub {
$plater->export_gcode; $plater->export_gcode;
}, undef, 'cog_go.png'); }, undef, 'cog_go.png');
$self->_append_menu_item($self->{plater_menu}, "Export plate as STL...", 'Export current plate as STL', sub { wxTheApp->append_menu_item($self->{plater_menu}, "Export plate as STL...", 'Export current plate as STL', sub {
$plater->export_stl; $plater->export_stl;
}, undef, 'brick_go.png'); }, undef, 'brick_go.png');
$self->_append_menu_item($self->{plater_menu}, "Export plate with modifiers as AMF...", 'Export current plate as AMF, including all modifier meshes', sub { wxTheApp->append_menu_item($self->{plater_menu}, "Export plate with modifiers as AMF...", 'Export current plate as AMF, including all modifier meshes', sub {
$plater->export_amf; $plater->export_amf;
}, undef, 'brick_go.png'); }, undef, 'brick_go.png');
@ -201,13 +200,13 @@ sub _init_menubar {
# Settings menu # Settings menu
my $settingsMenu = Wx::Menu->new; my $settingsMenu = Wx::Menu->new;
{ {
$self->_append_menu_item($settingsMenu, "P&rint Settings…\tCtrl+1", 'Show the print settings editor', sub { wxTheApp->append_menu_item($settingsMenu, "P&rint Settings…\tCtrl+1", 'Show the print settings editor', sub {
$self->{plater}->show_preset_editor('print'); $self->{plater}->show_preset_editor('print');
}, undef, 'cog.png'); }, undef, 'cog.png');
$self->_append_menu_item($settingsMenu, "&Filament Settings…\tCtrl+2", 'Show the filament settings editor', sub { wxTheApp->append_menu_item($settingsMenu, "&Filament Settings…\tCtrl+2", 'Show the filament settings editor', sub {
$self->{plater}->show_preset_editor('filament'); $self->{plater}->show_preset_editor('filament');
}, undef, 'spool.png'); }, undef, 'spool.png');
$self->_append_menu_item($settingsMenu, "Print&er Settings…\tCtrl+3", 'Show the printer settings editor', sub { wxTheApp->append_menu_item($settingsMenu, "Print&er Settings…\tCtrl+3", 'Show the printer settings editor', sub {
$self->{plater}->show_preset_editor('printer'); $self->{plater}->show_preset_editor('printer');
}, undef, 'printer_empty.png'); }, undef, 'printer_empty.png');
} }
@ -215,15 +214,15 @@ sub _init_menubar {
# View menu # View menu
{ {
$self->{viewMenu} = Wx::Menu->new; $self->{viewMenu} = Wx::Menu->new;
$self->_append_menu_item($self->{viewMenu}, "Top\tCtrl+4" , 'Top View' , sub { $self->select_view('top' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Top\tCtrl+4" , 'Top View' , sub { $self->select_view('top' ); });
$self->_append_menu_item($self->{viewMenu}, "Bottom\tCtrl+5" , 'Bottom View' , sub { $self->select_view('bottom' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Bottom\tCtrl+5" , 'Bottom View' , sub { $self->select_view('bottom' ); });
$self->_append_menu_item($self->{viewMenu}, "Left\tCtrl+6" , 'Left View' , sub { $self->select_view('left' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Left\tCtrl+6" , 'Left View' , sub { $self->select_view('left' ); });
$self->_append_menu_item($self->{viewMenu}, "Right\tCtrl+7" , 'Right View' , sub { $self->select_view('right' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Right\tCtrl+7" , 'Right View' , sub { $self->select_view('right' ); });
$self->_append_menu_item($self->{viewMenu}, "Front\tCtrl+8" , 'Front View' , sub { $self->select_view('front' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Front\tCtrl+8" , 'Front View' , sub { $self->select_view('front' ); });
$self->_append_menu_item($self->{viewMenu}, "Back\tCtrl+9" , 'Back View' , sub { $self->select_view('back' ); }); wxTheApp->append_menu_item($self->{viewMenu}, "Back\tCtrl+9" , 'Back View' , sub { $self->select_view('back' ); });
$self->_append_menu_item($self->{viewMenu}, "Diagonal\tCtrl+0", 'Diagonal View', sub { $self->select_view('diagonal'); }); wxTheApp->append_menu_item($self->{viewMenu}, "Diagonal\tCtrl+0", 'Diagonal View', sub { $self->select_view('diagonal'); });
$self->{viewMenu}->AppendSeparator(); $self->{viewMenu}->AppendSeparator();
$self->{color_toolpaths_by_role} = $self->_append_menu_item($self->{viewMenu}, $self->{color_toolpaths_by_role} = wxTheApp->append_menu_item($self->{viewMenu},
"Color Toolpaths by Role", "Color Toolpaths by Role",
'Color toolpaths according to perimeter/infill/support material', 'Color toolpaths according to perimeter/infill/support material',
sub { sub {
@ -233,7 +232,7 @@ sub _init_menubar {
}, },
undef, undef, wxITEM_RADIO undef, undef, wxITEM_RADIO
); );
$self->{color_toolpaths_by_extruder} = $self->_append_menu_item($self->{viewMenu}, $self->{color_toolpaths_by_extruder} = wxTheApp->append_menu_item($self->{viewMenu},
"Color Toolpaths by Filament", "Color Toolpaths by Filament",
'Color toolpaths using the configured extruder/filament color', 'Color toolpaths using the configured extruder/filament color',
sub { sub {
@ -253,13 +252,13 @@ sub _init_menubar {
# Window menu # Window menu
my $windowMenu = Wx::Menu->new; my $windowMenu = Wx::Menu->new;
{ {
$self->_append_menu_item($windowMenu, "&Plater\tCtrl+T", 'Show the plater', sub { wxTheApp->append_menu_item($windowMenu, "&Plater\tCtrl+T", 'Show the plater', sub {
$self->select_tab(0); $self->select_tab(0);
}, undef, 'application_view_tile.png'); }, undef, 'application_view_tile.png');
$self->_append_menu_item($windowMenu, "&Controller\tCtrl+Y", 'Show the printer controller', sub { wxTheApp->append_menu_item($windowMenu, "&Controller\tCtrl+Y", 'Show the printer controller', sub {
$self->select_tab(1); $self->select_tab(1);
}, undef, 'printer_empty.png') unless ($Slic3r::GUI::Settings->{_}{no_controller}); }, undef, 'printer_empty.png') unless ($Slic3r::GUI::Settings->{_}{no_controller});
$self->_append_menu_item($windowMenu, "DLP Projector…\tCtrl+P", 'Open projector window for DLP printing', sub { wxTheApp->append_menu_item($windowMenu, "DLP Projector…\tCtrl+P", 'Open projector window for DLP printing', sub {
$self->{plater}->pause_background_process; $self->{plater}->pause_background_process;
Slic3r::GUI::SLAPrintOptions->new($self)->ShowModal; Slic3r::GUI::SLAPrintOptions->new($self)->ShowModal;
$self->{plater}->resume_background_process; $self->{plater}->resume_background_process;
@ -269,22 +268,22 @@ sub _init_menubar {
# Help menu # Help menu
my $helpMenu = Wx::Menu->new; my $helpMenu = Wx::Menu->new;
{ {
$self->_append_menu_item($helpMenu, "&Configuration $Slic3r::GUI::ConfigWizard::wizard…", "Run Configuration $Slic3r::GUI::ConfigWizard::wizard", sub { wxTheApp->append_menu_item($helpMenu, "&Configuration $Slic3r::GUI::ConfigWizard::wizard…", "Run Configuration $Slic3r::GUI::ConfigWizard::wizard", sub {
$self->config_wizard; $self->config_wizard;
}); });
$helpMenu->AppendSeparator(); $helpMenu->AppendSeparator();
$self->_append_menu_item($helpMenu, "Slic3r &Website", 'Open the Slic3r website in your browser', sub { wxTheApp->append_menu_item($helpMenu, "Slic3r &Website", 'Open the Slic3r website in your browser', sub {
Wx::LaunchDefaultBrowser('http://slic3r.org/'); Wx::LaunchDefaultBrowser('http://slic3r.org/');
}); });
my $versioncheck = $self->_append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub { my $versioncheck = wxTheApp->append_menu_item($helpMenu, "Check for &Updates...", 'Check for new Slic3r versions', sub {
wxTheApp->check_version(1); wxTheApp->check_version(1);
}); });
$versioncheck->Enable(wxTheApp->have_version_check); $versioncheck->Enable(wxTheApp->have_version_check);
$self->_append_menu_item($helpMenu, "Slic3r &Manual", 'Open the Slic3r manual in your browser', sub { wxTheApp->append_menu_item($helpMenu, "Slic3r &Manual", 'Open the Slic3r manual in your browser', sub {
Wx::LaunchDefaultBrowser('http://manual.slic3r.org/'); Wx::LaunchDefaultBrowser('http://manual.slic3r.org/');
}); });
$helpMenu->AppendSeparator(); $helpMenu->AppendSeparator();
$self->_append_menu_item($helpMenu, "&About Slic3r", 'Show about dialog', sub { wxTheApp->append_menu_item($helpMenu, "&About Slic3r", 'Show about dialog', sub {
wxTheApp->about; wxTheApp->about;
}); });
} }
@ -631,15 +630,4 @@ sub select_view {
$self->{plater}->select_view($direction); $self->{plater}->select_view($direction);
} }
sub _append_menu_item {
my ($self, $menu, $string, $description, $cb, $id, $icon, $kind) = @_;
$id //= &Wx::NewId();
my $item = $menu->Append($id, $string, $description, $kind);
wxTheApp->set_menu_item_icon($item, $icon);
EVT_MENU($self, $id, $cb);
return $item;
}
1; 1;

View File

@ -323,7 +323,6 @@ sub new {
if ($self->{preview3D}) { if ($self->{preview3D}) {
$self->{preview3D}->set_bed_shape($self->{config}->bed_shape); $self->{preview3D}->set_bed_shape($self->{config}->bed_shape);
} }
$self->on_model_change;
{ {
my $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(3, 3, 1, 2); my $presets = $self->{presets_sizer} = Wx::FlexGridSizer->new(3, 3, 1, 2);
@ -894,6 +893,11 @@ sub load_file {
sub load_model_objects { sub load_model_objects {
my ($self, @model_objects) = @_; my ($self, @model_objects) = @_;
# Always restart background process when adding new objects.
# This prevents lack of processing in some circumstances when background process is
# running but adding a new object does not invalidate anything.
$self->stop_background_process;
my $bed_centerf = $self->bed_centerf; my $bed_centerf = $self->bed_centerf;
my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape}); my $bed_shape = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape});
my $bed_size = $bed_shape->bounding_box->size; my $bed_size = $bed_shape->bounding_box->size;
@ -1969,7 +1973,7 @@ sub on_model_change {
if ($count > 1) { if ($count > 1) {
$name .= " (${count}x)"; $name .= " (${count}x)";
} }
my $item = $self->GetFrame->_append_menu_item($menu, $name, 'Select object', sub { my $item = wxTheApp->append_menu_item($menu, $name, 'Select object', sub {
$self->select_object($i); $self->select_object($i);
$self->refresh_canvases; $self->refresh_canvases;
}, undef, undef, wxITEM_CHECK); }, undef, undef, wxITEM_CHECK);
@ -2320,105 +2324,109 @@ sub object_menu {
my $frame = $self->GetFrame; my $frame = $self->GetFrame;
my $menu = Wx::Menu->new; my $menu = Wx::Menu->new;
$frame->_append_menu_item($menu, "Delete\tCtrl+Del", 'Remove the selected object', sub { wxTheApp->append_menu_item($menu, "Delete\tCtrl+Del", 'Remove the selected object', sub {
$self->remove; $self->remove;
}, undef, 'brick_delete.png'); }, undef, 'brick_delete.png');
$frame->_append_menu_item($menu, "Increase copies\tCtrl++", 'Place one more copy of the selected object', sub { wxTheApp->append_menu_item($menu, "Increase copies\tCtrl++", 'Place one more copy of the selected object', sub {
$self->increase; $self->increase;
}, undef, 'add.png'); }, undef, 'add.png');
$frame->_append_menu_item($menu, "Decrease copies\tCtrl+-", 'Remove one copy of the selected object', sub { wxTheApp->append_menu_item($menu, "Decrease copies\tCtrl+-", 'Remove one copy of the selected object', sub {
$self->decrease; $self->decrease;
}, undef, 'delete.png'); }, undef, 'delete.png');
$frame->_append_menu_item($menu, "Set number of copies…", 'Change the number of copies of the selected object', sub { wxTheApp->append_menu_item($menu, "Set number of copies…", 'Change the number of copies of the selected object', sub {
$self->set_number_of_copies; $self->set_number_of_copies;
}, undef, 'textfield.png'); }, undef, 'textfield.png');
$menu->AppendSeparator(); $menu->AppendSeparator();
$frame->_append_menu_item($menu, "Move to bed center", 'Center object around bed center', sub { wxTheApp->append_menu_item($menu, "Move to bed center", 'Center object around bed center', sub {
$self->center_selected_object_on_bed; $self->center_selected_object_on_bed;
}, undef, 'arrow_in.png'); }, undef, 'arrow_in.png');
$frame->_append_menu_item($menu, "Rotate 45° clockwise", 'Rotate the selected object by 45° clockwise', sub { wxTheApp->append_menu_item($menu, "Rotate 45° clockwise", 'Rotate the selected object by 45° clockwise', sub {
$self->rotate(-45); $self->rotate(-45);
}, undef, 'arrow_rotate_clockwise.png'); }, undef, 'arrow_rotate_clockwise.png');
$frame->_append_menu_item($menu, "Rotate 45° counter-clockwise", 'Rotate the selected object by 45° counter-clockwise', sub { wxTheApp->append_menu_item($menu, "Rotate 45° counter-clockwise", 'Rotate the selected object by 45° counter-clockwise', sub {
$self->rotate(+45); $self->rotate(+45);
}, undef, 'arrow_rotate_anticlockwise.png'); }, undef, 'arrow_rotate_anticlockwise.png');
my $rotateMenu = Wx::Menu->new; {
my $rotateMenuItem = $menu->AppendSubMenu($rotateMenu, "Rotate", 'Rotate the selected object by an arbitrary angle'); my $rotateMenu = Wx::Menu->new;
wxTheApp->set_menu_item_icon($rotateMenuItem, 'textfield.png'); wxTheApp->append_menu_item($rotateMenu, "Around X axis…", 'Rotate the selected object by an arbitrary angle around X axis', sub {
$frame->_append_menu_item($rotateMenu, "Around X axis…", 'Rotate the selected object by an arbitrary angle around X axis', sub { $self->rotate(undef, X);
$self->rotate(undef, X); }, undef, 'bullet_red.png');
}, undef, 'bullet_red.png'); wxTheApp->append_menu_item($rotateMenu, "Around Y axis…", 'Rotate the selected object by an arbitrary angle around Y axis', sub {
$frame->_append_menu_item($rotateMenu, "Around Y axis…", 'Rotate the selected object by an arbitrary angle around Y axis', sub { $self->rotate(undef, Y);
$self->rotate(undef, Y); }, undef, 'bullet_green.png');
}, undef, 'bullet_green.png'); wxTheApp->append_menu_item($rotateMenu, "Around Z axis…", 'Rotate the selected object by an arbitrary angle around Z axis', sub {
$frame->_append_menu_item($rotateMenu, "Around Z axis…", 'Rotate the selected object by an arbitrary angle around Z axis', sub { $self->rotate(undef, Z);
$self->rotate(undef, Z); }, undef, 'bullet_blue.png');
}, undef, 'bullet_blue.png'); wxTheApp->append_submenu($menu, "Rotate", 'Rotate the selected object by an arbitrary angle', $rotateMenu, undef, 'textfield.png');
}
my $mirrorMenu = Wx::Menu->new; {
my $mirrorMenuItem = $menu->AppendSubMenu($mirrorMenu, "Mirror", 'Mirror the selected object'); my $mirrorMenu = Wx::Menu->new;
wxTheApp->set_menu_item_icon($mirrorMenuItem, 'shape_flip_horizontal.png'); wxTheApp->append_menu_item($mirrorMenu, "Along X axis…", 'Mirror the selected object along the X axis', sub {
$frame->_append_menu_item($mirrorMenu, "Along X axis…", 'Mirror the selected object along the X axis', sub { $self->mirror(X);
$self->mirror(X); }, undef, 'bullet_red.png');
}, undef, 'bullet_red.png'); wxTheApp->append_menu_item($mirrorMenu, "Along Y axis…", 'Mirror the selected object along the Y axis', sub {
$frame->_append_menu_item($mirrorMenu, "Along Y axis…", 'Mirror the selected object along the Y axis', sub { $self->mirror(Y);
$self->mirror(Y); }, undef, 'bullet_green.png');
}, undef, 'bullet_green.png'); wxTheApp->append_menu_item($mirrorMenu, "Along Z axis…", 'Mirror the selected object along the Z axis', sub {
$frame->_append_menu_item($mirrorMenu, "Along Z axis…", 'Mirror the selected object along the Z axis', sub { $self->mirror(Z);
$self->mirror(Z); }, undef, 'bullet_blue.png');
}, undef, 'bullet_blue.png'); wxTheApp->append_submenu($menu, "Mirror", 'Mirror the selected object', $mirrorMenu, undef, 'shape_flip_horizontal.png');
}
my $scaleMenu = Wx::Menu->new; {
my $scaleMenuItem = $menu->AppendSubMenu($scaleMenu, "Scale", 'Scale the selected object along a single axis'); my $scaleMenu = Wx::Menu->new;
wxTheApp->set_menu_item_icon($scaleMenuItem, 'arrow_out.png'); wxTheApp->append_menu_item($scaleMenu, "Uniformly…", 'Scale the selected object along the XYZ axes', sub {
$frame->_append_menu_item($scaleMenu, "Uniformly…", 'Scale the selected object along the XYZ axes', sub { $self->changescale(undef);
$self->changescale(undef); });
}); wxTheApp->append_menu_item($scaleMenu, "Along X axis…", 'Scale the selected object along the X axis', sub {
$frame->_append_menu_item($scaleMenu, "Along X axis…", 'Scale the selected object along the X axis', sub { $self->changescale(X);
$self->changescale(X); }, undef, 'bullet_red.png');
}, undef, 'bullet_red.png'); wxTheApp->append_menu_item($scaleMenu, "Along Y axis…", 'Scale the selected object along the Y axis', sub {
$frame->_append_menu_item($scaleMenu, "Along Y axis…", 'Scale the selected object along the Y axis', sub { $self->changescale(Y);
$self->changescale(Y); }, undef, 'bullet_green.png');
}, undef, 'bullet_green.png'); wxTheApp->append_menu_item($scaleMenu, "Along Z axis…", 'Scale the selected object along the Z axis', sub {
$frame->_append_menu_item($scaleMenu, "Along Z axis…", 'Scale the selected object along the Z axis', sub { $self->changescale(Z);
$self->changescale(Z); }, undef, 'bullet_blue.png');
}, undef, 'bullet_blue.png'); wxTheApp->append_submenu($menu, "Scale", 'Scale the selected object by a given factor', $scaleMenu, undef, 'arrow_out.png');
}
my $scaleToSizeMenu = Wx::Menu->new; {
my $scaleToSizeMenuItem = $menu->AppendSubMenu($scaleToSizeMenu, "Scale to size", 'Scale the selected object along a single axis'); my $scaleToSizeMenu = Wx::Menu->new;
wxTheApp->set_menu_item_icon($scaleToSizeMenuItem, 'arrow_out.png'); wxTheApp->append_menu_item($scaleToSizeMenu, "Uniformly…", 'Scale the selected object along the XYZ axes', sub {
$frame->_append_menu_item($scaleToSizeMenu, "Uniformly…", 'Scale the selected object along the XYZ axes', sub { $self->changescale(undef, 1);
$self->changescale(undef, 1); });
}); wxTheApp->append_menu_item($scaleToSizeMenu, "Along X axis…", 'Scale the selected object along the X axis', sub {
$frame->_append_menu_item($scaleToSizeMenu, "Along X axis…", 'Scale the selected object along the X axis', sub { $self->changescale(X, 1);
$self->changescale(X, 1); }, undef, 'bullet_red.png');
}, undef, 'bullet_red.png'); wxTheApp->append_menu_item($scaleToSizeMenu, "Along Y axis…", 'Scale the selected object along the Y axis', sub {
$frame->_append_menu_item($scaleToSizeMenu, "Along Y axis…", 'Scale the selected object along the Y axis', sub { $self->changescale(Y, 1);
$self->changescale(Y, 1); }, undef, 'bullet_green.png');
}, undef, 'bullet_green.png'); wxTheApp->append_menu_item($scaleToSizeMenu, "Along Z axis…", 'Scale the selected object along the Z axis', sub {
$frame->_append_menu_item($scaleToSizeMenu, "Along Z axis…", 'Scale the selected object along the Z axis', sub { $self->changescale(Z, 1);
$self->changescale(Z, 1); }, undef, 'bullet_blue.png');
}, undef, 'bullet_blue.png'); wxTheApp->append_submenu($menu, "Scale to size", 'Scale the selected object to match a given size', $scaleToSizeMenu, undef, 'arrow_out.png');
}
$frame->_append_menu_item($menu, "Split", 'Split the selected object into individual parts', sub { wxTheApp->append_menu_item($menu, "Split", 'Split the selected object into individual parts', sub {
$self->split_object; $self->split_object;
}, undef, 'shape_ungroup.png'); }, undef, 'shape_ungroup.png');
$frame->_append_menu_item($menu, "Cut…", 'Open the 3D cutting tool', sub { wxTheApp->append_menu_item($menu, "Cut…", 'Open the 3D cutting tool', sub {
$self->object_cut_dialog; $self->object_cut_dialog;
}, undef, 'package.png'); }, undef, 'package.png');
$menu->AppendSeparator(); $menu->AppendSeparator();
$frame->_append_menu_item($menu, "Settings…", 'Open the object editor dialog', sub { wxTheApp->append_menu_item($menu, "Settings…", 'Open the object editor dialog', sub {
$self->object_settings_dialog; $self->object_settings_dialog;
}, undef, 'cog.png'); }, undef, 'cog.png');
$menu->AppendSeparator(); $menu->AppendSeparator();
$frame->_append_menu_item($menu, "Reload from Disk", 'Reload the selected file from Disk', sub { wxTheApp->append_menu_item($menu, "Reload from Disk", 'Reload the selected file from Disk', sub {
$self->reload_from_disk; $self->reload_from_disk;
}, undef, 'arrow_refresh.png'); }, undef, 'arrow_refresh.png');
$frame->_append_menu_item($menu, "Export object as STL…", 'Export this single object as STL file', sub { wxTheApp->append_menu_item($menu, "Export object as STL…", 'Export this single object as STL file', sub {
$self->export_object_stl; $self->export_object_stl;
}, undef, 'brick_go.png'); }, undef, 'brick_go.png');
$frame->_append_menu_item($menu, "Export object and modifiers as AMF…", 'Export this single object and all associated modifiers as AMF file', sub { wxTheApp->append_menu_item($menu, "Export object and modifiers as AMF…", 'Export this single object and all associated modifiers as AMF file', sub {
$self->export_object_amf; $self->export_object_amf;
}, undef, 'brick_go.png'); }, undef, 'brick_go.png');

View File

@ -9,7 +9,9 @@ use utf8;
use File::Basename qw(basename); use File::Basename qw(basename);
use Wx qw(:misc :sizer :treectrl :button wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL use Wx qw(:misc :sizer :treectrl :button wxTAB_TRAVERSAL wxSUNKEN_BORDER wxBITMAP_TYPE_PNG wxID_CANCEL
wxTheApp); wxTheApp);
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED); use List::Util qw(max);
use Wx::Event qw(EVT_BUTTON EVT_TREE_ITEM_COLLAPSING EVT_TREE_SEL_CHANGED EVT_TREE_ITEM_RIGHT_CLICK);
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad rad2deg);
use base 'Wx::Panel'; use base 'Wx::Panel';
use constant ICON_OBJECT => 0; use constant ICON_OBJECT => 0;
@ -156,11 +158,56 @@ sub new {
return if $self->{disable_tree_sel_changed_event}; return if $self->{disable_tree_sel_changed_event};
$self->selection_changed; $self->selection_changed;
}); });
EVT_TREE_ITEM_RIGHT_CLICK($self, $tree, sub {
my ($self, $event) = @_;
my $item = $event->GetItem;
my $frame = $self->GetFrame;
my $menu = Wx::Menu->new;
{
my $scaleMenu = Wx::Menu->new;
wxTheApp->append_menu_item($scaleMenu, "Uniformly… ", 'Scale the selected object along the XYZ axes',
sub { $self->changescale(undef, 0) });
wxTheApp->append_menu_item($scaleMenu, "Along X axis…", 'Scale the selected object along the X axis',
sub { $self->changescale(X, 0) }, undef, 'bullet_red.png');
wxTheApp->append_menu_item($scaleMenu, "Along Y axis…", 'Scale the selected object along the Y axis',
sub { $self->changescale(Y, 0) }, undef, 'bullet_green.png');
wxTheApp->append_menu_item($scaleMenu, "Along Z axis…", 'Scale the selected object along the Z axis',
sub { $self->changescale(Z, 0) }, undef, 'bullet_blue.png');
wxTheApp->append_submenu($menu, "Scale", 'Scale the selected object by a given factor',
$scaleMenu, undef, 'arrow_out.png');
}
{
my $scaleToSizeMenu = Wx::Menu->new;
wxTheApp->append_menu_item($scaleToSizeMenu, "Uniformly… ", 'Scale the selected object along the XYZ axes',
sub { $self->changescale(undef, 1) });
wxTheApp->append_menu_item($scaleToSizeMenu, "Along X axis…", 'Scale the selected object along the X axis',
sub { $self->changescale(X, 1) }, undef, 'bullet_red.png');
wxTheApp->append_menu_item($scaleToSizeMenu, "Along Y axis…", 'Scale the selected object along the Y axis',
sub { $self->changescale(Y, 1) }, undef, 'bullet_green.png');
wxTheApp->append_menu_item($scaleToSizeMenu, "Along Z axis…", 'Scale the selected object along the Z axis',
sub { $self->changescale(Z, 1) }, undef, 'bullet_blue.png');
wxTheApp->append_submenu($menu, "Scale to size", 'Scale the selected object to match a given size',
$scaleToSizeMenu, undef, 'arrow_out.png');
}
{
my $rotateMenu = Wx::Menu->new;
wxTheApp->append_menu_item($rotateMenu, "Around X axis…", 'Rotate the selected object by an arbitrary angle around X axis',
sub { $self->rotate(undef, X) }, undef, 'bullet_red.png');
wxTheApp->append_menu_item($rotateMenu, "Around Y axis…", 'Rotate the selected object by an arbitrary angle around Y axis',
sub { $self->rotate(undef, Y) }, undef, 'bullet_green.png');
wxTheApp->append_menu_item($rotateMenu, "Around Z axis…", 'Rotate the selected object by an arbitrary angle around Z axis',
sub { $self->rotate(undef, Z) }, undef, 'bullet_blue.png');
wxTheApp->append_submenu($menu, "Rotate", 'Rotate the selected object by an arbitrary angle',
$rotateMenu, undef, 'arrow_rotate_anticlockwise.png');
}
$frame->PopupMenu($menu, $event->GetPoint);
});
EVT_BUTTON($self, $self->{btn_load_part}, sub { $self->on_btn_load(0) }); EVT_BUTTON($self, $self->{btn_load_part}, sub { $self->on_btn_load(0) });
EVT_BUTTON($self, $self->{btn_load_modifier}, sub { $self->on_btn_load(1) }); EVT_BUTTON($self, $self->{btn_load_modifier}, sub { $self->on_btn_load(1) });
EVT_BUTTON($self, $self->{btn_load_lambda_modifier}, sub { $self->on_btn_lambda(1) }); EVT_BUTTON($self, $self->{btn_load_lambda_modifier}, sub { $self->on_btn_lambda(1) });
EVT_BUTTON($self, $self->{btn_delete}, \&on_btn_delete); EVT_BUTTON($self, $self->{btn_delete}, \&on_btn_delete);
$self->reload_tree; $self->reload_tree;
return $self; return $self;
@ -371,7 +418,6 @@ sub on_btn_lambda {
# set a default extruder value, since user can't add it manually # set a default extruder value, since user can't add it manually
$new_volume->config->set_ifndef('extruder', 0); $new_volume->config->set_ifndef('extruder', 0);
$self->{parts_changed} = 1;
$self->_parts_changed($self->{model_object}->volumes_count-1); $self->_parts_changed($self->{model_object}->volumes_count-1);
} }
@ -398,6 +444,7 @@ sub on_btn_delete {
sub _parts_changed { sub _parts_changed {
my ($self, $selected_volume_idx) = @_; my ($self, $selected_volume_idx) = @_;
$self->{parts_changed} = 1;
$self->reload_tree($selected_volume_idx); $self->reload_tree($selected_volume_idx);
if ($self->{canvas}) { if ($self->{canvas}) {
$self->{canvas}->reset_objects; $self->{canvas}->reset_objects;
@ -450,4 +497,82 @@ sub _update {
$self->{canvas}->Render; $self->{canvas}->Render;
} }
sub changescale {
my ($self, $axis, $tosize) = @_;
my $itemData = $self->get_selection;
if ($itemData && $itemData->{type} eq 'volume') {
my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}];
my $object_size = $volume->bounding_box->size;
if (defined $axis) {
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
my $scale;
if (defined $tosize) {
my $cursize = $object_size->[$axis];
# Wx::GetNumberFromUser() does not support decimal numbers
my $newsize = Wx::GetTextFromUser(
sprintf("Enter the new size for the selected mesh:"),
"Scale along $axis_name",
$cursize, $self);
return if !$newsize || $newsize !~ /^\d*(?:\.\d*)?$/ || $newsize < 0;
$scale = $newsize / $cursize * 100;
} else {
# Wx::GetNumberFromUser() does not support decimal numbers
$scale = Wx::GetTextFromUser("Enter the scale % for the selected object:",
"Scale along $axis_name", 100, $self);
$scale =~ s/%$//;
return if !$scale || $scale !~ /^\d*(?:\.\d*)?$/ || $scale < 0;
}
my $versor = [1,1,1];
$versor->[$axis] = $scale/100;
$volume->mesh->scale_xyz(Slic3r::Pointf3->new(@$versor));
} else {
my $scale;
if ($tosize) {
my $cursize = max(@$object_size);
# Wx::GetNumberFromUser() does not support decimal numbers
my $newsize = Wx::GetTextFromUser("Enter the new max size for the selected object:",
"Scale", $cursize, $self);
return if !$newsize || $newsize !~ /^\d*(?:\.\d*)?$/ || $newsize < 0;
$scale = $newsize / $cursize;
} else {
# max scale factor should be above 2540 to allow importing files exported in inches
# Wx::GetNumberFromUser() does not support decimal numbers
$scale = Wx::GetTextFromUser("Enter the scale % for the selected object:", 'Scale',
100, $self);
return if !$scale || $scale !~ /^\d*(?:\.\d*)?$/ || $scale < 0;
}
return if !$scale || $scale < 0;
$volume->mesh->scale($scale);
}
$self->_parts_changed;
}
}
sub rotate {
my $self = shift;
my ($angle, $axis) = @_;
# angle is in degrees
my $itemData = $self->get_selection;
if ($itemData && $itemData->{type} eq 'volume') {
my $volume = $self->{model_object}->volumes->[$itemData->{volume_id}];
if (!defined $angle) {
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
my $default = $axis == Z ? 0 : 0;
# Wx::GetNumberFromUser() does not support decimal numbers
$angle = Wx::GetTextFromUser("Enter the rotation angle:", "Rotate around $axis_name axis",
$default, $self);
return if !$angle || $angle !~ /^-?\d*(?:\.\d*)?$/ || $angle == -1;
}
if ($axis == X) { $volume->mesh->rotate_x(deg2rad($angle)); }
if ($axis == Y) { $volume->mesh->rotate_y(deg2rad($angle)); }
if ($axis == Z) { $volume->mesh->rotate_z(deg2rad($angle)); }
$self->_parts_changed;
}
}
sub GetFrame {
my ($self) = @_;
return &Wx::GetTopLevelParent($self);
}
1; 1;

View File

@ -7,8 +7,8 @@ use strict;
use warnings; use warnings;
use utf8; use utf8;
use Wx qw(:dialog :id :misc :sizer :systemsettings :notebook wxTAB_TRAVERSAL); use Wx qw(:dialog :id :misc :sizer :systemsettings :notebook wxTAB_TRAVERSAL wxTheApp);
use Wx::Event qw(EVT_BUTTON); use Wx::Event qw(EVT_BUTTON EVT_MENU);
use base 'Wx::Dialog'; use base 'Wx::Dialog';
sub new { sub new {
@ -54,6 +54,7 @@ sub PartSettingsChanged {
return $self->{parts}->PartSettingsChanged || $self->{layers}->LayersChanged; return $self->{parts}->PartSettingsChanged || $self->{layers}->LayersChanged;
} }
package Slic3r::GUI::Plater::ObjectDialog::BaseTab; package Slic3r::GUI::Plater::ObjectDialog::BaseTab;
use base 'Wx::Panel'; use base 'Wx::Panel';

View File

@ -53,8 +53,6 @@ sub new {
my $menu = Wx::Menu->new; my $menu = Wx::Menu->new;
my $last_cat = ''; my $last_cat = '';
foreach my $opt_key (@{$self->{options}}) { foreach my $opt_key (@{$self->{options}}) {
my $id = &Wx::NewId();
# add icon, if we have one for this category # add icon, if we have one for this category
my $icon; my $icon;
if (my $cat = $Slic3r::Config::Options->{$opt_key}{category}) { if (my $cat = $Slic3r::Config::Options->{$opt_key}{category}) {
@ -65,14 +63,14 @@ sub new {
$icon = $icons{$cat}; $icon = $icons{$cat};
} }
my $menuItem = $menu->Append($id, $self->{option_labels}{$opt_key}); my $cb = sub {
wxTheApp->set_menu_item_icon($menuItem, $icon) if $icon;
EVT_MENU($menu, $id, sub {
$self->{config}->set($opt_key, $self->{default_config}->get($opt_key)); $self->{config}->set($opt_key, $self->{default_config}->get($opt_key));
$self->update_optgroup; $self->update_optgroup;
$self->{on_change}->($opt_key) if $self->{on_change}; $self->{on_change}->($opt_key) if $self->{on_change};
}); };
wxTheApp->append_menu_item($menu, $self->{option_labels}{$opt_key},
$Slic3r::Config::Options->{$opt_key}{tooltip}, $cb, undef, $icon);
} }
$self->PopupMenu($menu, $btn->GetPosition); $self->PopupMenu($menu, $btn->GetPosition);
$menu->Destroy; $menu->Destroy;

View File

@ -9,7 +9,7 @@ use Wx::Event qw(EVT_BUTTON EVT_CLOSE EVT_TEXT_ENTER EVT_SPINCTRL EVT_SLIDER);
use base qw(Wx::Dialog Class::Accessor); use base qw(Wx::Dialog Class::Accessor);
use utf8; use utf8;
__PACKAGE__->mk_accessors(qw(config config2 screen controller _optgroups)); __PACKAGE__->mk_accessors(qw(config config2 manual_control_config screen controller _optgroups));
sub new { sub new {
my ($class, $parent) = @_; my ($class, $parent) = @_;
@ -27,6 +27,12 @@ sub new {
z_lift_speed => 8, z_lift_speed => 8,
offset => [0,0], offset => [0,0],
}); });
$self->manual_control_config({
xy_travel_speed => 130,
z_travel_speed => 10,
temperature => '',
bed_temperature => '',
});
my $ini = eval { Slic3r::Config->read_ini("$Slic3r::GUI::datadir/DLP.ini") }; my $ini = eval { Slic3r::Config->read_ini("$Slic3r::GUI::datadir/DLP.ini") };
if ($ini) { if ($ini) {
@ -286,7 +292,7 @@ sub new {
return; return;
} }
my $dlg = Slic3r::GUI::Controller::ManualControlDialog->new my $dlg = Slic3r::GUI::Controller::ManualControlDialog->new
($self, $self->config, $sender); ($self, $self->config, $sender, $self->manual_control_config);
$dlg->ShowModal; $dlg->ShowModal;
$sender->disconnect; $sender->disconnect;
}); });

View File

@ -12,6 +12,10 @@ sub new {
$self->config(Slic3r::Config::SLAPrint->new); $self->config(Slic3r::Config::SLAPrint->new);
$self->config->apply_dynamic(wxTheApp->{mainframe}->{plater}->config); $self->config->apply_dynamic(wxTheApp->{mainframe}->{plater}->config);
# Set some defaults
$self->config->set('infill_extrusion_width', 0.5) if $self->config->infill_extrusion_width == 0;
$self->config->set('perimeter_extrusion_width', 1) if $self->config->perimeter_extrusion_width == 0;
my $sizer = Wx::BoxSizer->new(wxVERTICAL); my $sizer = Wx::BoxSizer->new(wxVERTICAL);
my $new_optgroup = sub { my $new_optgroup = sub {
my ($title) = @_; my ($title) = @_;

View File

@ -213,7 +213,11 @@ sub generate_support_material {
$self->clear_support_layers; $self->clear_support_layers;
if ((!$self->config->support_material && $self->config->raft_layers == 0) || scalar(@{$self->layers}) < 2) { if ((!$self->config->support_material
&& $self->config->raft_layers == 0
&& $self->config->support_material_enforce_layers == 0)
|| scalar(@{$self->layers}) < 2
) {
$self->set_step_done(STEP_SUPPORTMATERIAL); $self->set_step_done(STEP_SUPPORTMATERIAL);
return; return;
} }

View File

@ -93,18 +93,21 @@ sub generate {
sub contact_area { sub contact_area {
# $object is Slic3r::Print::Object # $object is Slic3r::Print::Object
my ($self, $object) = @_; my ($self, $object) = @_;
my $conf = $self->object_config;
# if user specified a custom angle threshold, convert it to radians # if user specified a custom angle threshold, convert it to radians
my $threshold_rad; my $threshold_rad;
if (!($self->object_config->support_material_threshold =~ /%$/)) { if (!($conf->support_material_threshold =~ /%$/)) {
$threshold_rad = deg2rad($self->object_config->support_material_threshold + 1); # +1 makes the threshold inclusive $threshold_rad = deg2rad($conf->support_material_threshold + 1); # +1 makes the threshold inclusive
Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad); Slic3r::debugf "Threshold angle = %d°\n", rad2deg($threshold_rad);
} }
# Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces # Build support on a build plate only? If so, then collect top surfaces into $buildplate_only_top_surfaces
# and subtract $buildplate_only_top_surfaces from the contact surfaces, so # and subtract $buildplate_only_top_surfaces from the contact surfaces, so
# there is no contact surface supported by a top surface. # there is no contact surface supported by a top surface.
my $buildplate_only = $self->object_config->support_material && $self->object_config->support_material_buildplate_only; my $buildplate_only =
( $conf->support_material || $conf->support_material_enforce_layers)
&& $conf->support_material_buildplate_only;
my $buildplate_only_top_surfaces = []; my $buildplate_only_top_surfaces = [];
# determine contact areas # determine contact areas
@ -115,12 +118,19 @@ sub contact_area {
# so $layer_id == 0 means first object layer # so $layer_id == 0 means first object layer
# and $layer->id == 0 means first print layer (including raft) # and $layer->id == 0 means first print layer (including raft)
if ($self->object_config->raft_layers == 0) { # if no raft, and we're at layer 0, skip to layer 1
next if $layer_id == 0; if ( $conf->raft_layers == 0 && $layer_id == 0 ) {
} elsif (!$self->object_config->support_material) { next;
}
# with or without raft, if we're above layer 1, we need to quit
# support generation if supports are disabled, or if we're at a high
# enough layer that enforce-supports no longer applies
if ( $layer_id > 0
&& !$conf->support_material
&& ($layer_id >= $conf->support_material_enforce_layers) ) {
# if we are only going to generate raft just check # if we are only going to generate raft just check
# the 'overhangs' of the first object layer # the 'overhangs' of the first object layer
last if $layer_id > 0; last;
} }
my $layer = $object->get_layer($layer_id); my $layer = $object->get_layer($layer_id);
@ -154,12 +164,19 @@ sub contact_area {
my $diff; my $diff;
# If a threshold angle was specified, use a different logic for detecting overhangs. # If a threshold angle was specified, use a different logic for detecting overhangs.
if (defined $threshold_rad if (($conf->support_material && defined $threshold_rad)
|| $layer_id < $self->object_config->support_material_enforce_layers || $layer_id <= $conf->support_material_enforce_layers
|| ($self->object_config->raft_layers > 0 && $layer_id == 0)) { || ($conf->raft_layers > 0 && $layer_id == 0)) {
my $d = defined $threshold_rad my $d = 0;
? scale $lower_layer->height * ((cos $threshold_rad) / (sin $threshold_rad)) my $layer_threshold_rad = $threshold_rad;
: 0; if ($layer_id <= $conf->support_material_enforce_layers) {
# Use ~45 deg number for enforced supports if we are in auto
$layer_threshold_rad = deg2rad(89);
}
if (defined $layer_threshold_rad) {
$d = scale $lower_layer->height
* ((cos $layer_threshold_rad) / (sin $layer_threshold_rad));
}
$diff = diff( $diff = diff(
offset([ map $_->p, @{$layerm->slices} ], -$d), offset([ map $_->p, @{$layerm->slices} ], -$d),
@ -177,7 +194,7 @@ sub contact_area {
} else { } else {
$diff = diff( $diff = diff(
[ map $_->p, @{$layerm->slices} ], [ map $_->p, @{$layerm->slices} ],
offset([ map @$_, @{$lower_layer->slices} ], +$self->object_config->get_abs_value_over('support_material_threshold', $fw)), offset([ map @$_, @{$lower_layer->slices} ], +$conf->get_abs_value_over('support_material_threshold', $fw)),
); );
# collapse very tiny spots # collapse very tiny spots
@ -189,7 +206,7 @@ sub contact_area {
# outside the lower slice boundary, thus no overhang # outside the lower slice boundary, thus no overhang
} }
if ($self->object_config->dont_support_bridges) { if ($conf->dont_support_bridges) {
# compute the area of bridging perimeters # compute the area of bridging perimeters
# Note: this is duplicate code from GCode.pm, we need to refactor # Note: this is duplicate code from GCode.pm, we need to refactor
@ -264,7 +281,7 @@ sub contact_area {
1, 1,
); );
} }
} # if ($self->object_config->dont_support_bridges) } # if ($conf->dont_support_bridges)
if ($buildplate_only) { if ($buildplate_only) {
# Don't support overhangs above the top surfaces. # Don't support overhangs above the top surfaces.
@ -309,7 +326,7 @@ sub contact_area {
my $contact_z = $layer->print_z - $self->contact_distance($layer->height, $nozzle_diameter); my $contact_z = $layer->print_z - $self->contact_distance($layer->height, $nozzle_diameter);
# ignore this contact area if it's too low # ignore this contact area if it's too low
next if $contact_z < $self->object_config->get_value('first_layer_height') - epsilon; next if $contact_z < $conf->get_value('first_layer_height') - epsilon;
$contact{$contact_z} = [ @contact ]; $contact{$contact_z} = [ @contact ];
$overhang{$contact_z} = [ @overhang ]; $overhang{$contact_z} = [ @overhang ];

View File

@ -1,7 +1,6 @@
#include <EXTERN.h> // from the Perl distribution #include <EXTERN.h> // from the Perl distribution
#include <perl.h> // from the Perl distribution #include <perl.h> // from the Perl distribution
#ifdef WIN32 #ifdef WIN32
// Perl win32 specific includes, found in perl\\lib\\CORE\\win32.h // Perl win32 specific includes, found in perl\\lib\\CORE\\win32.h
// Defines the windows specific convenience RunPerl() function, // Defines the windows specific convenience RunPerl() function,
@ -17,13 +16,8 @@
int main(int argc, char **argv, char **env) int main(int argc, char **argv, char **env)
{ {
// replaces following Windows batch file: @"%~dp0\perl5.24.0.exe"
// "%~dp0\slic3r.pl" --DataDir "C:\Users\Public\Documents\Prusa3D\Slic3r
// settings MK2"%*
// If the Slic3r is installed in a localized directory (containing non-iso // If the Slic3r is installed in a localized directory (containing non-iso
// characters), spaces or semicolons, use short file names. // characters), spaces or semicolons, use short file names.
char exe_path[MAX_PATH] = {0}; char exe_path[MAX_PATH] = {0};
char script_path[MAX_PATH]; char script_path[MAX_PATH];
char gui_flag[6] = {"--gui"}; char gui_flag[6] = {"--gui"};

View File

@ -0,0 +1,28 @@
/home/travis/builds/alexrj/Slic3r/local-lib/lib/perl5/x86_64-linux-thread-multi/Alien/wxWidgets/gtk_3_0_2_uni/lib/libwx_baseu-3.0.so.0
/home/travis/builds/alexrj/Slic3r/local-lib/lib/perl5/x86_64-linux-thread-multi/Alien/wxWidgets/gtk_3_0_2_uni/lib/libwx_gtk2u_adv-3.0.so.0
/home/travis/builds/alexrj/Slic3r/local-lib/lib/perl5/x86_64-linux-thread-multi/Alien/wxWidgets/gtk_3_0_2_uni/lib/libwx_gtk2u_core-3.0.so.0
/lib/x86_64-linux-gnu/liblzma.so.5
/lib/x86_64-linux-gnu/libm.so.6
/lib/x86_64-linux-gnu/libpcre.so.3
/lib/x86_64-linux-gnu/libpng12.so.0
/lib/x86_64-linux-gnu/libresolv.so.2
/lib/x86_64-linux-gnu/libuuid.so.1
/usr/lib/x86_64-linux-gnu/libSM.so.6
/usr/lib/x86_64-linux-gnu/libatk-1.0.so.0
/usr/lib/x86_64-linux-gnu/libdatrie.so.1
/usr/lib/x86_64-linux-gnu/libfreetype.so.6
/usr/lib/x86_64-linux-gnu/libgdk-x11-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgio-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgmodule-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0
/usr/lib/x86_64-linux-gnu/libgraphite2.so.3
/usr/lib/x86_64-linux-gnu/libgtk-x11-2.0.so.0
/usr/lib/x86_64-linux-gnu/libharfbuzz.so.0
/usr/lib/x86_64-linux-gnu/libjbig.so.0
/usr/lib/x86_64-linux-gnu/libjpeg.so.8
/usr/lib/x86_64-linux-gnu/libpango-1.0.so.0
/usr/lib/x86_64-linux-gnu/libpangocairo-1.0.so.0
/usr/lib/x86_64-linux-gnu/libpangoft2-1.0.so.0
/usr/lib/x86_64-linux-gnu/libpixman-1.so.0
/usr/lib/x86_64-linux-gnu/libtiff.so.5

View File

@ -47,7 +47,7 @@ echo "Appfolder: $appfolder, archivefolder: $archivefolder"
# Our slic3r dir and location of perl # Our slic3r dir and location of perl
PERL_BIN=$(which perl) PERL_BIN=$(which perl)
PP_BIN=$(which wxpar) PP_BIN=$(which pp)
SLIC3R_DIR="./" SLIC3R_DIR="./"
if [[ -d "${appfolder}" ]]; then if [[ -d "${appfolder}" ]]; then
@ -96,7 +96,7 @@ cp -f $PERL_BIN $archivefolder/perl-local
${PP_BIN} wxextension .0 \ ${PP_BIN} wxextension .0 \
-M attributes -M base -M bytes -M B -M POSIX \ -M attributes -M base -M bytes -M B -M POSIX \
-M FindBin -M Unicode::Normalize -M Tie::Handle \ -M FindBin -M Unicode::Normalize -M Tie::Handle \
-M Time::Local -M Math::Trig \ -M Time::Local -M Math::Trig -M IO::Socket -M Errno \
-M lib -M overload \ -M lib -M overload \
-M warnings -M local::lib \ -M warnings -M local::lib \
-M strict -M utf8 -M parent \ -M strict -M utf8 -M parent \
@ -104,8 +104,10 @@ ${PP_BIN} wxextension .0 \
unzip -qq -o $WD/_tmp/test.par -d $WD/_tmp/ unzip -qq -o $WD/_tmp/test.par -d $WD/_tmp/
cp -rf $WD/_tmp/lib/* $archivefolder/local-lib/lib/perl5/ cp -rf $WD/_tmp/lib/* $archivefolder/local-lib/lib/perl5/
cp -rf $WD/_tmp/shlib $archivefolder/ cp -rf $WD/_tmp/shlib $archivefolder/
rm -rf $WD/_tmp rm -rf $WD/_tmp
for i in $(cat $WD/libpaths.txt); do
install -v $i $archivefolder/bin
done
echo "Cleaning local-lib" echo "Cleaning local-lib"
rm -rf $archivefolder/local-lib/bin rm -rf $archivefolder/local-lib/bin

View File

@ -101,7 +101,7 @@ echo "Copying perl from $PERL_BIN"
cp -f $PERL_BIN $macosfolder/perl-local cp -f $PERL_BIN $macosfolder/perl-local
${PP_BIN} -M attributes -M base -M bytes -M B -M POSIX \ ${PP_BIN} -M attributes -M base -M bytes -M B -M POSIX \
-M FindBin -M Unicode::Normalize -M Tie::Handle \ -M FindBin -M Unicode::Normalize -M Tie::Handle \
-M Time::Local -M Math::Trig \ -M Time::Local -M Math::Trig -M IO::Socket -M Errno \
-M lib -M overload \ -M lib -M overload \
-M warnings -M local::lib \ -M warnings -M local::lib \
-M strict -M utf8 -M parent \ -M strict -M utf8 -M parent \

View File

@ -3,10 +3,6 @@ cd package/win
./compile_wrapper.ps1 524 | Write-Output ./compile_wrapper.ps1 524 | Write-Output
./package_win32.ps1 524| Write-Output ./package_win32.ps1 524| Write-Output
cd ../../ cd ../../
Add-AppveyorCompilationMessage -Message "Uploading to server." Add-AppveyorCompilationMessage -Message "Uploading to server."
& ./package/deploy/winscp.ps1 -DIR win -KEY $env:APPVEYOR_BUILD_FOLDER/package/deploy/slic3r-upload.ppk -FILE *.zip *>> ./sftplog.txt & ./package/deploy/winscp.ps1 -DIR win -KEY $env:APPVEYOR_BUILD_FOLDER/package/deploy/slic3r-upload.ppk -FILE *.zip *>> ./sftplog.txt
if (!(Test-Path C:\project\slic3r\slic3r.par)) {
Add-AppveyorCompilationMessage -Message "Failed to package!" -Category Error
return 1
}

View File

@ -1 +0,0 @@
@perl5.24.0.exe slic3r.pl %*

View File

@ -4,16 +4,27 @@ if ($args[0])
$perlver = $args[0] $perlver = $args[0]
} else } else
{ {
$perlver = 518 $perlver = 524
} }
$perllib = "-lperl$perlver" $perllib = "-lperl$perlver"
$shell_loc = "..\common\shell.cpp" $shell_loc = "..\common\shell.cpp"
# Build the resource file (used to load icon, etc)
windres slic3r.rc -O coff -o slic3r.res windres slic3r.rc -O coff -o slic3r.res
# Compile an object file that does not have gui forced.
g++ -c -I'C:\strawberry\perl\lib\CORE\' $shell_loc -o slic3r.o g++ -c -I'C:\strawberry\perl\lib\CORE\' $shell_loc -o slic3r.o
# Compile an object file with --gui automatically passed as an argument
g++ -c -I'C:\strawberry\perl\lib\CORE\' -DFORCE_GUI $shell_loc -o slic3r-gui.o g++ -c -I'C:\strawberry\perl\lib\CORE\' -DFORCE_GUI $shell_loc -o slic3r-gui.o
# Build the EXE for the unforced version as slic3r-console
g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r.o slic3r.res -o slic3r-console.exe | Write-Host g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r.o slic3r.res -o slic3r-console.exe | Write-Host
# Build the EXE for the forced GUI
g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -mwindows -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r-gui.o slic3r.res -o slic3r.exe | Write-Host g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -mwindows -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r-gui.o slic3r.res -o slic3r.exe | Write-Host
# Build an extra copy of the GUI version that creates a console window
g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r-gui.o slic3r.res -o slic3r-debug-console.exe | Write-Host g++ -static-libgcc -static-libstdc++ -L'C:\strawberry\c\lib' -L'C:\strawberry\perl\bin' -L'C:\strawberry\perl\lib\CORE\' $perllib slic3r-gui.o slic3r.res -o slic3r-debug-console.exe | Write-Host

View File

@ -1,7 +1,7 @@
# Written by Joseph Lenox # Written by Joseph Lenox
# Licensed under the same license as the rest of Slic3r. # Licensed under the same license as the rest of Slic3r.
# ------------------------ # ------------------------
# You need to have Strawberry Perl 5.24.0.1 installed for this to work, # You need to have Strawberry Perl 5.24.0.1 (or slic3r-perl) installed for this to work,
param ( param (
[switch]$exe = $false [switch]$exe = $false
) )
@ -93,6 +93,7 @@ pp `
-M IO ` -M IO `
-M IO::Handle ` -M IO::Handle `
-M IO::Select ` -M IO::Select `
-M IO::Socket `
-M LWP ` -M LWP `
-M LWP::MediaTypes ` -M LWP::MediaTypes `
-M LWP::MemberMixin ` -M LWP::MemberMixin `

View File

@ -316,6 +316,9 @@ Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ...
--save <file> Save configuration to the specified file --save <file> Save configuration to the specified file
--load <file> Load configuration from the specified file. It can be used --load <file> Load configuration from the specified file. It can be used
more than once to load options from multiple files. more than once to load options from multiple files.
--datadir <path> Load and store settings at the given directory.
This is useful for maintaining different profiles or including
configurations from a network storage.
-o, --output <file> File to output gcode to (by default, the file will be saved -o, --output <file> File to output gcode to (by default, the file will be saved
into the same directory as the input file using the into the same directory as the input file using the
--output-filename-format to generate the filename.) If a --output-filename-format to generate the filename.) If a

View File

@ -1,4 +1,4 @@
use Test::More tests => 26; use Test::More tests => 27;
use strict; use strict;
use warnings; use warnings;
@ -10,6 +10,7 @@ BEGIN {
use List::Util qw(any); use List::Util qw(any);
use Slic3r; use Slic3r;
use Slic3r::Geometry qw(epsilon);
use Slic3r::Test qw(_eq); use Slic3r::Test qw(_eq);
{ {
@ -209,20 +210,55 @@ use Slic3r::Test qw(_eq);
my $config = Slic3r::Config->new_from_defaults; my $config = Slic3r::Config->new_from_defaults;
$config->set('start_gcode', ''); $config->set('start_gcode', '');
$config->set('retract_lift', [3, 4]); $config->set('retract_lift', [3, 4]);
$config->set('only_retract_when_crossing_perimeters', 0);
my @lifted_at = (); my @lifted_at = ();
my $test = sub { my $test = sub {
my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2); my $print = Slic3r::Test::init_print('20mm_cube', config => $config, duplicate => 2);
@lifted_at = (); @lifted_at = ();
my $retracted = 0;
my $lifted = 0;
my $tool = 0;
Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub {
my ($self, $cmd, $args, $info) = @_; my ($self, $cmd, $args, $info) = @_;
if ($cmd eq 'G1' && $info->{dist_Z} < 0) { if ($cmd eq 'G1') {
push @lifted_at, $info->{new_Z}; if ($info->{dist_Z} < 0) {
# going downwards; this is a "restore lift" move
$lifted = 0;
push @lifted_at, $info->{new_Z};
} elsif (abs($info->{dist_Z} - $config->get_at('retract_lift', $tool)) < &epsilon) {
# going upwards by a large amount; this is a lift move
fail 'always lift after retraction' if !$retracted;
### It would be useful to prevent the double lift happening at layer change:
###fail 'no double lift' if $lifted;
$lifted = 1;
} elsif ($info->{retracting}) {
$retracted = 1;
} elsif ($info->{extruding} && $info->{dist_XY} == 0) {
# consider the lift as layer change if they are configured with the same distance
$lifted = 0 if $config->get_at('retract_lift', $tool) == $config->layer_height;
fail 'always unretract after unlifting' if $lifted;
$retracted = 0;
} elsif ($info->{travel} && $info->{dist_XY} >= $config->get_at('retract_before_travel', $tool)) {
#printf "dist_XY = %f, rbt = %f\n", $info->{dist_XY}, $config->get_at('retract_before_travel', 0);
my $below = $config->get_at('retract_lift_below', $tool);
fail 'no retraction for long travel move' if !$retracted;
fail 'no lift for long travel move'
if !$lifted
&& $self->Z >= $config->get_at('retract_lift_above', $tool)
&& ($below == 0 || $self->Z <= $below);
}
} elsif ($cmd =~ /^T(\d+)/) {
$tool = $1;
} }
}); });
}; };
$config->set('retract_layer_change', [1,1]);
$test->();
ok !!@lifted_at, 'lift is compatible with retract_layer_change';
$config->set('retract_lift_above', [0, 0]); $config->set('retract_lift_above', [0, 0]);
$config->set('retract_lift_below', [0, 0]); $config->set('retract_lift_below', [0, 0]);
$test->(); $test->();
@ -234,9 +270,13 @@ use Slic3r::Test qw(_eq);
ok !!@lifted_at, 'lift takes place when above/below != 0'; ok !!@lifted_at, 'lift takes place when above/below != 0';
ok !(any { $_ < $config->get_at('retract_lift_above', 0) } @lifted_at), ok !(any { $_ < $config->get_at('retract_lift_above', 0) } @lifted_at),
'Z is not lifted below the configured value'; 'Z is not lifted below the configured value';
ok !(any { $_ > $config->get_at('retract_lift_below', 0) } @lifted_at), {
'Z is not lifted above the configured value'; my $below = $config->get_at('retract_lift_below', 0);
$below += $config->layer_height if $config->get_at('retract_layer_change', 0);
ok !(any { $_ > $below } @lifted_at),
'Z is not lifted above the configured value';
}
# check lifting with different values for 2. extruder # check lifting with different values for 2. extruder
$config->set('perimeter_extruder', 2); $config->set('perimeter_extruder', 2);
$config->set('infill_extruder', 2); $config->set('infill_extruder', 2);
@ -251,8 +291,20 @@ use Slic3r::Test qw(_eq);
ok !!@lifted_at, 'lift takes place when above/below != 0 for 2. extruder'; ok !!@lifted_at, 'lift takes place when above/below != 0 for 2. extruder';
ok !(any { $_ < $config->get_at('retract_lift_above', 1) } @lifted_at), ok !(any { $_ < $config->get_at('retract_lift_above', 1) } @lifted_at),
'Z is not lifted below the configured value for 2. extruder'; 'Z is not lifted below the configured value for 2. extruder';
ok !(any { $_ > $config->get_at('retract_lift_below', 1) } @lifted_at), {
'Z is not lifted above the configured value for 2. extruder'; my $below = $config->get_at('retract_lift_below', 1);
$below += $config->layer_height if $config->get_at('retract_layer_change', 1);
ok !(any { $_ > $below } @lifted_at),
'Z is not lifted above the configured value for 2. extruder';
}
$config->set('retract_lift', [$config->layer_height]);
$config->set('perimeter_extruder', 1);
$config->set('infill_extruder', 1);
$config->set('retract_lift_above', [0, 0]);
$config->set('retract_lift_below', [0, 0]);
$test->();
} }
__END__ __END__

View File

@ -1,4 +1,4 @@
use Test::More tests => 27; use Test::More tests => 28;
use strict; use strict;
use warnings; use warnings;
@ -258,5 +258,32 @@ use Slic3r::Test;
@{ $layer_heights_by_tool{$config->support_material_extruder-1} }), @{ $layer_heights_by_tool{$config->support_material_extruder-1} }),
'no support material layer is as thin as object layers'; 'no support material layer is as thin as object layers';
} }
{
my $config = Slic3r::Config->new_from_defaults;
$config->set('support_material_enforce_layers', 100);
$config->set('support_material', 0);
my @contact_z = my @top_z = ();
my $test = sub {
my $print = Slic3r::Test::init_print('20mm_cube', config => $config);
my $flow = $print->print->objects->[0]->support_material_flow;
my $support = Slic3r::Print::SupportMaterial->new(
object_config => $print->print->objects->[0]->config,
print_config => $print->print->config,
flow => $flow,
interface_flow => $flow,
first_layer_flow => $flow,
);
my $support_z = $support->support_layers_z(\@contact_z, \@top_z, $config->layer_height);
is scalar(grep { $support_z->[$_]-$support_z->[$_-1] <= 0 } 1..$#$support_z), 0,
'forced support is generated';
};
$config->set('layer_height', 0.2);
$config->set('first_layer_height', 0.3);
@contact_z = (1.9);
@top_z = (1.1);
$test->();
}
__END__ __END__

View File

@ -67,15 +67,13 @@ my @boost_include = ();
if (defined $ENV{BOOST_INCLUDEDIR}) { if (defined $ENV{BOOST_INCLUDEDIR}) {
push @boost_include, $ENV{BOOST_INCLUDEDIR} push @boost_include, $ENV{BOOST_INCLUDEDIR}
} elsif (defined $ENV{BOOST_DIR}) { } elsif (defined $ENV{BOOST_DIR}) {
my $subdir = $ENV{BOOST_DIR} . (($mswin == 1) ? '\include' : '/include'); # User might have provided a path relative to the Build.PL in the main directory
if (-d $subdir) { foreach my $subdir ($ENV{BOOST_DIR}, "../$ENV{BOOST_DIR}", "$ENV{BOOST_DIR}/include", "../$ENV{BOOST_DIR}/include") {
push @boost_include, $subdir; if (-d $subdir) {
} elsif (-d "../$subdir") { push @boost_include, $subdir;
# User might have provided a path relative to the Build.PL in the main directory }
push @boost_include, "../$subdir";
} else {
push @boost_include, $ENV{BOOST_DIR};
} }
die "Invalid BOOST_DIR: no such directory\n" if !@boost_include;
} else { } else {
# Boost library was not defined by the environment. # Boost library was not defined by the environment.
# Try to guess at some default paths. # Try to guess at some default paths.
@ -99,15 +97,13 @@ my @boost_libs = ();
if (defined $ENV{BOOST_LIBRARYPATH}) { if (defined $ENV{BOOST_LIBRARYPATH}) {
push @boost_libs, $ENV{BOOST_LIBRARYPATH} push @boost_libs, $ENV{BOOST_LIBRARYPATH}
} elsif (defined $ENV{BOOST_DIR}) { } elsif (defined $ENV{BOOST_DIR}) {
my $subdir = $ENV{BOOST_DIR} . ($mswin ? '\stage\lib' : '/stage/lib'); # User might have provided a path relative to the Build.PL in the main directory
if (-d $subdir) { foreach my $subdir ("$ENV{BOOST_DIR}/stage/lib", "../$ENV{BOOST_DIR}/stage/lib") {
push @boost_libs, $subdir; if (-d $subdir) {
} elsif (-d "../$subdir") { push @boost_libs, $subdir;
# User might have provided a path relative to the Build.PL in the main directory }
push @boost_libs, "../$subdir";
} else {
push @boost_libs, $ENV{BOOST_DIR};
} }
die "Invalid BOOST_DIR: no such directory\n" if !@boost_libs;
} else { } else {
# Boost library was not defined by the environment. # Boost library was not defined by the environment.
# Try to guess at some default paths. # Try to guess at some default paths.

View File

@ -525,7 +525,7 @@ void FillCubic::_fill_surface_single(
direction_t direction2 = direction; direction_t direction2 = direction;
const coord_t range = scale_(this->min_spacing / this->density); const coord_t range = scale_(this->min_spacing / this->density);
const coord_t x_shift = abs(( (coord_t)(scale_(this->z) + range) % (coord_t)(range * 2)) - range); const coord_t x_shift = (coord_t)(scale_(this->z) + range) % (coord_t)(range*3);
fill2._fill_single_direction(expolygon, direction2, -x_shift, out); fill2._fill_single_direction(expolygon, direction2, -x_shift, out);

View File

@ -330,7 +330,7 @@ GCodeWriter::travel_to_z(double z, const std::string &comment)
reducing the lift amount that will be used for unlift. */ reducing the lift amount that will be used for unlift. */
if (!this->will_move_z(z)) { if (!this->will_move_z(z)) {
double nominal_z = this->_pos.z - this->_lifted; double nominal_z = this->_pos.z - this->_lifted;
this->_lifted = this->_lifted - (z - nominal_z); this->_lifted -= (z - nominal_z);
return ""; return "";
} }
@ -500,10 +500,15 @@ GCodeWriter::lift()
if (this->_pos.z >= above && (below == 0 || this->_pos.z <= below)) if (this->_pos.z >= above && (below == 0 || this->_pos.z <= below))
target_lift = this->config.retract_lift.get_at(this->_extruder->id); target_lift = this->config.retract_lift.get_at(this->_extruder->id);
} }
if (this->_lifted == 0 && target_lift > 0) {
// compare against epsilon because travel_to_z() does math on it
// and subtracting layer_height from retract_lift might not give
// exactly zero
if (std::abs(this->_lifted) < EPSILON && target_lift > 0) {
this->_lifted = target_lift; this->_lifted = target_lift;
return this->_travel_to_z(this->_pos.z + target_lift, "lift Z"); return this->_travel_to_z(this->_pos.z + target_lift, "lift Z");
} }
return ""; return "";
} }

View File

@ -574,18 +574,6 @@ class SLAPrintConfig
ConfigOptionFloat support_material_spacing; ConfigOptionFloat support_material_spacing;
ConfigOptionInt threads; ConfigOptionInt threads;
SLAPrintConfig() : StaticPrintConfig() {
this->set_defaults();
// override some defaults
this->fill_density.value = 100;
this->fill_pattern.value = ipGrid;
this->infill_extrusion_width.value = 0.5;
this->infill_extrusion_width.percent = false;
this->perimeter_extrusion_width.value = 1;
this->perimeter_extrusion_width.percent = false;
};
virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) { virtual ConfigOption* optptr(const t_config_option_key &opt_key, bool create = false) {
OPT_PTR(fill_angle); OPT_PTR(fill_angle);
OPT_PTR(fill_density); OPT_PTR(fill_density);

View File

@ -248,6 +248,15 @@ ModelMaterial::attributes()
void set_material_id(t_model_material_id material_id) void set_material_id(t_model_material_id material_id)
%code%{ THIS->material_id(material_id); %}; %code%{ THIS->material_id(material_id); %};
Ref<ModelMaterial> material(); Ref<ModelMaterial> material();
Clone<BoundingBoxf3> bounding_box()
%code%{
try {
RETVAL = THIS->mesh.bounding_box();
} catch (std::exception& e) {
croak("%s", e.what());
}
%};
Ref<DynamicPrintConfig> config() Ref<DynamicPrintConfig> config()
%code%{ RETVAL = &THIS->config; %}; %code%{ RETVAL = &THIS->config; %};