From eba19aaba47576cd471384a4cfce2840e4c72bd7 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 00:16:15 +0100 Subject: [PATCH 01/26] Fixed Object part editor because it wasn't updated with the new PreviewCanvas API. #2455 --- lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm index fb4b0291c..255a1685a 100644 --- a/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm +++ b/lib/Slic3r/GUI/Plater/ObjectPartsPanel.pm @@ -224,13 +224,7 @@ sub on_btn_load { } } - $self->reload_tree; - if ($self->{canvas}) { - $self->{canvas}->reset_objects; - $self->{canvas}->load_object($self->{model_object}); - $self->{canvas}->set_bounding_box($self->{model_object}->bounding_box); - $self->{canvas}->Render; - } + $self->_parts_changed; } sub on_btn_delete { @@ -250,9 +244,17 @@ sub on_btn_delete { $self->{parts_changed} = 1; } + $self->_parts_changed; +} + +sub _parts_changed { + my ($self) = @_; + $self->reload_tree; if ($self->{canvas}) { + $self->{canvas}->reset_objects; $self->{canvas}->load_object($self->{model_object}); + $self->{canvas}->zoom_to_volumes; $self->{canvas}->Render; } } From efe7d5f857941add25c9f5dd10cdda5a6056108b Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 01:30:05 +0100 Subject: [PATCH 02/26] Integration with Octoprint. #1826 --- Build.PL | 1 + lib/Slic3r/GUI.pm | 3 +- lib/Slic3r/GUI/Plater.pm | 67 ++++++++++++++++++++++++++++---- lib/Slic3r/GUI/Tab.pm | 10 ++++- xs/src/libslic3r/PrintConfig.cpp | 10 +++++ xs/src/libslic3r/PrintConfig.hpp | 23 ++++++++++- 6 files changed, 104 insertions(+), 10 deletions(-) diff --git a/Build.PL b/Build.PL index fc5b16211..3921e37f9 100644 --- a/Build.PL +++ b/Build.PL @@ -27,6 +27,7 @@ my %prereqs = qw( ); my %recommends = qw( Class::XSAccessor 0 + LWP::UserAgent 0 XML::SAX::ExpatXS 0 ); diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index d089bbf29..e9e1ff387 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -27,6 +27,7 @@ use Slic3r::GUI::SimpleTab; use Slic3r::GUI::Tab; our $have_OpenGL = eval "use Slic3r::GUI::PreviewCanvas; 1"; +our $have_LWP = eval "use LWP::UserAgent; 1"; use Wx 0.9901 qw(:bitmap :dialog :icon :id :misc :systemsettings :toplevelwindow :filedialog); @@ -228,7 +229,7 @@ sub have_version_check { my ($self) = @_; # return an explicit 0 - return ($Slic3r::have_threads && $Slic3r::build && eval "use LWP::UserAgent; 1") || 0; + return ($Slic3r::have_threads && $Slic3r::build && $have_LWP) || 0; } sub check_version { diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 42b875036..b874cd958 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -48,6 +48,7 @@ sub new { my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{config} = Slic3r::Config->new_from_defaults(qw( bed_shape complete_objects extruder_clearance_radius skirts skirt_distance brim_width + octoprint_host octoprint_apikey )); $self->{model} = Slic3r::Model->new; $self->{print} = Slic3r::Print->new; @@ -181,9 +182,11 @@ sub new { # right pane buttons $self->{btn_export_gcode} = Wx::Button->new($self, -1, "Export G-code…", wxDefaultPosition, [-1, 30], wxBU_LEFT); + $self->{btn_send_gcode} = Wx::Button->new($self, -1, "Send to printer", wxDefaultPosition, [-1, 30], wxBU_LEFT); $self->{btn_export_stl} = Wx::Button->new($self, -1, "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_send_gcode}->Hide; if ($Slic3r::GUI::have_button_icons) { my %icons = qw( @@ -192,6 +195,7 @@ sub new { reset cross.png arrange bricks.png export_gcode cog_go.png + send_gcode cog_go.png export_stl brick_go.png increase add.png @@ -213,6 +217,10 @@ sub new { $self->export_gcode; Slic3r::thread_cleanup(); }); + EVT_BUTTON($self, $self->{btn_send_gcode}, sub { + $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir()); + Slic3r::thread_cleanup(); + }); #EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); if ($self->{htoolbar}) { @@ -355,6 +363,7 @@ sub new { my $buttons_sizer = Wx::BoxSizer->new(wxHORIZONTAL); $buttons_sizer->AddStretchSpacer(1); $buttons_sizer->Add($self->{btn_export_stl}, 0, wxALIGN_RIGHT, 0); + $buttons_sizer->Add($self->{btn_send_gcode}, 0, wxALIGN_RIGHT, 0); $buttons_sizer->Add($self->{btn_export_gcode}, 0, wxALIGN_RIGHT, 0); my $right_sizer = Wx::BoxSizer->new(wxVERTICAL); @@ -944,7 +953,7 @@ sub resume_background_process { } sub export_gcode { - my $self = shift; + my ($self, $output_file) = @_; return if !@{$self->{objects}}; @@ -976,14 +985,14 @@ sub export_gcode { } # select output file - $self->{export_gcode_output_file} = $main::opt{output}; - { - my $default_output_file = $self->{print}->expanded_output_filepath($self->{export_gcode_output_file}); + if ($output_file) { + $self->{export_gcode_output_file} = $self->{print}->expanded_output_filepath($output_file); + } else { + my $default_output_file = $self->{print}->expanded_output_filepath($main::opt{output}); my $dlg = Wx::FileDialog->new($self, 'Save G-code file as:', wxTheApp->output_path(dirname($default_output_file)), basename($default_output_file), &Slic3r::GUI::FILE_WILDCARDS->{gcode}, wxFD_SAVE); if ($dlg->ShowModal != wxID_OK) { $dlg->Destroy; - $self->{export_gcode_output_file} = undef; return; } $Slic3r::GUI::Settings->{_}{last_output_path} = dirname($dlg->GetPath); @@ -1011,6 +1020,8 @@ sub export_gcode { my $result = !Slic3r::GUI::catch_error($self); $self->on_export_completed($result); } + + return $self->{export_gcode_output_file}; } # This gets called only if we have threads. @@ -1072,14 +1083,49 @@ sub on_export_completed { $self->{export_thread} = undef; my $message; + my $send_gcode = 0; if ($result) { - $message = "G-code file exported to " . $self->{export_gcode_output_file}; + if ($self->{send_gcode_file}) { + $message = "Sending G-code file to the Octoprint server..."; + $send_gcode = 1; + } else { + $message = "G-code file exported to " . $self->{export_gcode_output_file}; + } } else { $message = "Export failed"; } $self->{export_gcode_output_file} = undef; $self->statusbar->SetStatusText($message); wxTheApp->notify($message); + + $self->send_gcode if $send_gcode; + $self->{send_gcode_file} = undef; +} + +sub send_gcode { + my ($self) = @_; + + $self->statusbar->StartBusy; + + my $ua = LWP::UserAgent->new; + $ua->timeout(10); + + my $res = $ua->post( + "http://" . $self->{config}->octoprint_host . "/api/files/local", + Content_Type => 'form-data', + 'X-Api-Key' => $self->{config}->octoprint_apikey, + Content => [ + fn => [$self->{send_gcode_file}], + ], + ); + + $self->statusbar->StopBusy; + + if ($res->is_success) { + $self->statusbar->SetStatusText("G-code file successfully uploaded to the Octoprint server"); + } else { + $self->statusbar->SetStatusText("Error while uploading to the Octoprint server: " . $res->status_line); + } } sub export_stl { @@ -1208,6 +1254,13 @@ sub on_config_change { $self->{canvas}->update_bed_size; $self->{canvas3D}->update_bed_size if $self->{canvas3D}; $self->update; + } elsif ($opt_key eq 'octoprint_host') { + if ($config->get('octoprint_host')) { + $self->{btn_send_gcode}->Show; + } else { + $self->{btn_send_gcode}->Hide; + } + $self->Layout; } } @@ -1313,7 +1366,7 @@ sub object_list_changed { my $have_objects = @{$self->{objects}} ? 1 : 0; my $method = $have_objects ? 'Enable' : 'Disable'; $self->{"btn_$_"}->$method - for grep $self->{"btn_$_"}, qw(reset arrange export_gcode export_stl); + for grep $self->{"btn_$_"}, qw(reset arrange export_gcode export_stl send_gcode); if ($self->{htoolbar}) { $self->{htoolbar}->EnableTool($_, $have_objects) diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 398aecac2..a1b4768b5 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -923,6 +923,7 @@ sub build { $self->init_config_options(qw( bed_shape z_offset gcode_flavor use_relative_e_distances + octoprint_host octoprint_apikey use_firmware_retraction pressure_advance vibration_limit start_gcode end_gcode layer_gcode toolchange_gcode nozzle_diameter extruder_offset @@ -996,6 +997,11 @@ sub build { } }); } + { + my $optgroup = $page->new_optgroup('Octoprint upload'); + $optgroup->append_single_option_line('octoprint_host'); + $optgroup->append_single_option_line('octoprint_apikey'); + } { my $optgroup = $page->new_optgroup('Advanced'); $optgroup->append_single_option_line('use_firmware_retraction'); @@ -1129,6 +1135,8 @@ sub _update { my $config = $self->{config}; + $self->get_field('octoprint_apikey')->toggle($config->get('octoprint_host')); + my $have_multiple_extruders = $self->{extruders_count} > 1; $self->get_field('toolchange_gcode')->toggle($have_multiple_extruders); @@ -1319,8 +1327,8 @@ sub config { } # apply preset values on top of defaults + my $config = Slic3r::Config->new_from_defaults(@$keys); my $external_config = Slic3r::Config->load($self->file); - my $config = Slic3r::Config->new; $config->set($_, $external_config->get($_)) for grep $external_config->has($_), @$keys; diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 4565ba5af..805667a8a 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -498,6 +498,16 @@ PrintConfigDef::build_def() { Options["nozzle_diameter"].sidetext = "mm"; Options["nozzle_diameter"].cli = "nozzle-diameter=f@"; + Options["octoprint_apikey"].type = coString; + Options["octoprint_apikey"].label = "API Key"; + Options["octoprint_apikey"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the API Key required for authentication."; + Options["octoprint_apikey"].cli = "octoprint-apikey=s"; + + Options["octoprint_host"].type = coString; + Options["octoprint_host"].label = "Host or IP"; + Options["octoprint_host"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the hostname or IP address of the Octoprint instance."; + Options["octoprint_host"].cli = "octoprint-host=s"; + Options["only_retract_when_crossing_perimeters"].type = coBool; Options["only_retract_when_crossing_perimeters"].label = "Only retract when crossing perimeters"; Options["only_retract_when_crossing_perimeters"].tooltip = "Disables retraction when the travel path does not exceed the upper layer's perimeters (and thus any ooze will be probably invisible)."; diff --git a/xs/src/libslic3r/PrintConfig.hpp b/xs/src/libslic3r/PrintConfig.hpp index 48235c7d1..b647acfb8 100644 --- a/xs/src/libslic3r/PrintConfig.hpp +++ b/xs/src/libslic3r/PrintConfig.hpp @@ -582,7 +582,27 @@ class PrintConfig : public GCodeConfig }; }; -class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig +class HostConfig : public virtual StaticPrintConfig +{ + public: + ConfigOptionString octoprint_host; + ConfigOptionString octoprint_apikey; + + HostConfig() : StaticPrintConfig() { + this->octoprint_host.value = ""; + this->octoprint_apikey.value = ""; + }; + + ConfigOption* option(const t_config_option_key opt_key, bool create = false) { + if (opt_key == "octoprint_host") return &this->octoprint_host; + if (opt_key == "octoprint_apikey") return &this->octoprint_apikey; + + return NULL; + }; +}; + +class FullPrintConfig + : public PrintObjectConfig, public PrintRegionConfig, public PrintConfig, public HostConfig { public: ConfigOption* option(const t_config_option_key opt_key, bool create = false) { @@ -590,6 +610,7 @@ class FullPrintConfig : public PrintObjectConfig, public PrintRegionConfig, publ if ((opt = PrintObjectConfig::option(opt_key, create)) != NULL) return opt; if ((opt = PrintRegionConfig::option(opt_key, create)) != NULL) return opt; if ((opt = PrintConfig::option(opt_key, create)) != NULL) return opt; + if ((opt = HostConfig::option(opt_key, create)) != NULL) return opt; return NULL; }; }; From fbb3462f5b9a49f9a9253d16342a75d2c318cc03 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 14:57:45 +0100 Subject: [PATCH 03/26] Bump version number --- xs/src/libslic3r/libslic3r.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 42bfa6164..defe708ee 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -6,7 +6,7 @@ #include #include -#define SLIC3R_VERSION "1.2.2" +#define SLIC3R_VERSION "1.2.3-dev" #define EPSILON 1e-4 #define SCALING_FACTOR 0.000001 From c1e44eb59196b3999ba41cc5731fb5dd4ec4ee55 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 14:58:24 +0100 Subject: [PATCH 04/26] Fixed extra comment that prevented the Export STL button from working after the recent changes in plater layout. #2458 --- lib/Slic3r/GUI/Plater.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index b874cd958..cd5617778 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -221,7 +221,7 @@ sub new { $self->{send_gcode_file} = $self->export_gcode(Wx::StandardPaths::Get->GetTempDir()); Slic3r::thread_cleanup(); }); - #EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); + EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl); if ($self->{htoolbar}) { EVT_TOOL($self, TB_ADD, sub { $self->add; }); From 959eb60ad08e9dc7450d56da735abf001ef48be2 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 16:19:55 +0100 Subject: [PATCH 05/26] Scoping error caused the Unsaved Changes dialog not to be shown when closing the main window --- lib/Slic3r/GUI/MainFrame.pm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 31b9ff0a3..4cd4db706 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -673,7 +673,11 @@ sub config { sub check_unsaved_changes { my $self = shift; - my @dirty = map $_->title, grep $_->is_dirty, values %{$self->{options_tabs}}; + my @dirty = (); + foreach my $tab (values %{$self->{options_tabs}}) { + push @dirty, $tab->title if $tab->is_dirty; + } + if (@dirty) { my $titles = join ', ', @dirty; my $confirm = Wx::MessageDialog->new($self, "You have unsaved changes ($titles). Discard changes and continue anyway?", From 5d4d79191a10e7542b8bf5515d4d39554d43e8cb Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 17:29:21 +0100 Subject: [PATCH 06/26] Fixed regression causing bridges not to be printed with rectilinear pattern when --external-fill-pattern was set. #2460 --- lib/Slic3r/Fill.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/Fill.pm b/lib/Slic3r/Fill.pm index 504230933..1881d461b 100644 --- a/lib/Slic3r/Fill.pm +++ b/lib/Slic3r/Fill.pm @@ -187,7 +187,7 @@ sub make_fill { if ($surface->is_solid) { $density = 100; $filler = 'rectilinear'; - if ($surface->is_external) { + if ($surface->is_external && !$is_bridge) { $filler = $layerm->config->external_fill_pattern; } } else { From b468e68c59940f8019799bb8eee07d5ea314a0e9 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 18:49:13 +0100 Subject: [PATCH 07/26] Bonjour autodiscovery of the Octoprint instances in local network. #1826 --- Build.PL | 1 + lib/Slic3r/GUI.pm | 1 + lib/Slic3r/GUI/BonjourBrowser.pm | 51 ++++++++++++++++++++++++++++ lib/Slic3r/GUI/OptionsGroup.pm | 35 ++++++++++++++++--- lib/Slic3r/GUI/OptionsGroup/Field.pm | 1 + lib/Slic3r/GUI/Tab.pm | 35 ++++++++++++++++++- 6 files changed, 118 insertions(+), 6 deletions(-) create mode 100644 lib/Slic3r/GUI/BonjourBrowser.pm diff --git a/Build.PL b/Build.PL index 3921e37f9..117b0aeeb 100644 --- a/Build.PL +++ b/Build.PL @@ -28,6 +28,7 @@ my %prereqs = qw( my %recommends = qw( Class::XSAccessor 0 LWP::UserAgent 0 + Net::Bonjour 0 XML::SAX::ExpatXS 0 ); diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index e9e1ff387..e08e6362d 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -7,6 +7,7 @@ use File::Basename qw(basename); use FindBin; use Slic3r::GUI::AboutDialog; use Slic3r::GUI::BedShapeDialog; +use Slic3r::GUI::BonjourBrowser; use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::MainFrame; use Slic3r::GUI::Notifier; diff --git a/lib/Slic3r/GUI/BonjourBrowser.pm b/lib/Slic3r/GUI/BonjourBrowser.pm new file mode 100644 index 000000000..bb2282e59 --- /dev/null +++ b/lib/Slic3r/GUI/BonjourBrowser.pm @@ -0,0 +1,51 @@ +package Slic3r::GUI::BonjourBrowser; +use strict; +use warnings; +use utf8; + +use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_CLOSE); +use base 'Wx::Dialog'; + +sub new { + my $class = shift; + my ($parent) = @_; + my $self = $class->SUPER::new($parent, -1, "Device Browser", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + # look for devices + eval "use Net::Bonjour; 1"; + my $res = Net::Bonjour->new('http'); + $res->discover; + $self->{devices} = [ $res->entries ]; + + # label + my $text = Wx::StaticText->new($self, -1, "Choose an Octoprint device in your network:", wxDefaultPosition, wxDefaultSize); + + # selector + $self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, + [ map $_->name, @{$self->{devices}} ]); + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($text, 1, wxEXPAND | wxALL, 10); + $main_sizer->Add($choice, 1, wxEXPAND | wxALL, 10); + $main_sizer->Add($self->CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND); + + $self->SetSizer($main_sizer); + $self->SetMinSize($self->GetSize); + $main_sizer->SetSizeHints($self); + + # needed to actually free memory + EVT_CLOSE($self, sub { + $self->EndModal(wxID_OK); + $self->Destroy; + }); + + return $self; +} + +sub GetValue { + my ($self) = @_; + return $self->{devices}[ $self->{choice}->GetSelection ]->address; +} + +1; diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 46d8aa678..d6a486828 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -83,7 +83,7 @@ sub append_line { # if we have a single option with no sidetext just add it directly to the grid sizer my @options = @{$line->get_options}; $self->_options->{$_->opt_id} = $_ for @options; - if (@options == 1 && !$options[0]->sidetext) { + if (@options == 1 && !$options[0]->sidetext && !@{$line->get_extra_widgets}) { my $option = $options[0]; my $field = $self->_build_field($option); $grid_sizer->Add($field, 0, ($option->full_width ? wxEXPAND : 0) | wxALIGN_CENTER_VERTICAL, 0); @@ -114,9 +114,14 @@ sub append_line { $sizer->Add($sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4); } } + + # add extra sizers if any + foreach my $extra_widget (@{$line->get_extra_widgets}) { + $sizer->Add($extra_widget->($self->parent), 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4); + } } -sub append_single_option_line { +sub create_single_option_line { my ($self, $option) = @_; my $line = Slic3r::GUI::OptionsGroup::Line->new( @@ -125,11 +130,15 @@ sub append_single_option_line { ); $option->label(""); $line->append_option($option); - $self->append_line($line); return $line; } +sub append_single_option_line { + my ($self, $option) = @_; + return $self->append_line($self->create_single_option_line($option)); +} + sub _build_field { my $self = shift; my ($opt) = @_; @@ -241,6 +250,7 @@ has 'label_tooltip' => (is => 'rw', default => sub { "" }); has 'sizer' => (is => 'rw'); has 'widget' => (is => 'rw'); has '_options' => (is => 'ro', default => sub { [] }); +has '_extra_widgets' => (is => 'ro', default => sub { [] }); # this method accepts a Slic3r::GUI::OptionsGroup::Option object sub append_option { @@ -248,11 +258,21 @@ sub append_option { push @{$self->_options}, $option; } +sub append_widget { + my ($self, $widget) = @_; + push @{$self->_extra_widgets}, $widget; +} + sub get_options { my ($self) = @_; return [ @{$self->_options} ]; } +sub get_extra_widgets { + my ($self) = @_; + return [ @{$self->_extra_widgets} ]; +} + package Slic3r::GUI::OptionsGroup::Option; use Moo; @@ -320,7 +340,7 @@ sub get_option { ); } -sub append_single_option_line { +sub create_single_option_line { my ($self, $opt_key, $opt_index) = @_; my $option; @@ -329,7 +349,12 @@ sub append_single_option_line { } else { $option = $self->get_option($opt_key, $opt_index); } - return $self->SUPER::append_single_option_line($option); + return $self->SUPER::create_single_option_line($option); +} + +sub append_single_option_line { + my ($self, $option, $opt_index) = @_; + return $self->append_line($self->create_single_option_line($option, $opt_index)); } sub reload_config { diff --git a/lib/Slic3r/GUI/OptionsGroup/Field.pm b/lib/Slic3r/GUI/OptionsGroup/Field.pm index fcf97eb3f..13b86cdfc 100644 --- a/lib/Slic3r/GUI/OptionsGroup/Field.pm +++ b/lib/Slic3r/GUI/OptionsGroup/Field.pm @@ -347,6 +347,7 @@ sub BUILD { $self->wxSizer($sizer); my $field_size = Wx::Size->new(40, -1); + $self->x_textctrl(Wx::TextCtrl->new($self->parent, -1, $self->option->default->[X], wxDefaultPosition, $field_size)); $self->y_textctrl(Wx::TextCtrl->new($self->parent, -1, $self->option->default->[Y], wxDefaultPosition, $field_size)); diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index a1b4768b5..b5250f047 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -999,7 +999,40 @@ sub build { } { my $optgroup = $page->new_optgroup('Octoprint upload'); - $optgroup->append_single_option_line('octoprint_host'); + + # append a button to the Host line + my $octoprint_host_widget = sub { + my ($parent) = @_; + + my $btn = Wx::Button->new($parent, -1, "Browse…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); + $btn->SetFont($Slic3r::GUI::small_font); + if ($Slic3r::GUI::have_button_icons) { + $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG)); + } + + if (!eval "use Net::Bonjour; 1") { + $btn->Disable; + } + + my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); + $sizer->Add($btn); + + EVT_BUTTON($self, $btn, sub { + my $dlg = Slic3r::GUI::BonjourBrowser->new($self); + if ($dlg->ShowModal == wxID_OK) { + my $value = $dlg->GetValue; + $self->{config}->set('octoprint_host', $value); + $self->update_dirty; + $self->_on_value_change('octoprint_host', $value); + } + }); + + return $sizer; + }; + + my $host_line = $optgroup->create_single_option_line('octoprint_host'); + $host_line->append_widget($octoprint_host_widget); + $optgroup->append_line($host_line); $optgroup->append_single_option_line('octoprint_apikey'); } { From c43049e13bee2d59d0ca1fffdc39d78a2d3fbb5f Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 28 Dec 2014 22:09:28 +0100 Subject: [PATCH 08/26] Prevent rare crashes using Ooze Prevention --- lib/Slic3r/GCode.pm | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 7adec0529..21dc773fb 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -328,6 +328,7 @@ sub _extrude_path { return $gcode; } +# This method accepts $point in print coordinates. sub travel_to { my ($self, $point, $role, $comment) = @_; @@ -355,11 +356,11 @@ sub travel_to { || (defined $role && $role == EXTR_ROLE_SUPPORTMATERIAL && $self->layer->support_islands->contains_line($travel)) ) { # Just perform a straight travel move without any retraction. - $gcode .= $self->writer->travel_to_xy($self->point_to_gcode($point), $comment); + $gcode .= $self->writer->travel_to_xy($self->point_to_gcode($point), $comment || ''); } elsif ($self->config->avoid_crossing_perimeters && !$self->avoid_crossing_perimeters->disable_once) { # If avoid_crossing_perimeters is enabled and the disable_once flag is not set # we need to plan a multi-segment travel move inside the configuration space. - $gcode .= $self->avoid_crossing_perimeters->travel_to($self, $point, $comment); + $gcode .= $self->avoid_crossing_perimeters->travel_to($self, $point, $comment || ''); } else { # If avoid_crossing_perimeters is disabled or the disable_once flag is set, # perform a straight move with a retraction. @@ -473,7 +474,7 @@ sub pre_toolchange { $last_pos->translate(scale +$gcodegen->origin->x, scale +$gcodegen->origin->y); #)) my $standby_point = $last_pos->nearest_point($self->standby_points); $standby_point->translate(scale -$gcodegen->origin->x, scale -$gcodegen->origin->y); #)) - $gcode .= $gcodegen->travel_to($standby_point); + $gcode .= $gcodegen->travel_to($standby_point, undef, 'move to standby position'); } if ($gcodegen->config->standby_temperature_delta != 0) { From e8dc9817745343b73317ac90c9853ac3533edea9 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 00:51:27 +0100 Subject: [PATCH 09/26] Fixes to Ooze Prevention --- lib/Slic3r/Print.pm | 2 +- lib/Slic3r/Print/GCode.pm | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/Print.pm b/lib/Slic3r/Print.pm index 69df1c900..b68e191a5 100644 --- a/lib/Slic3r/Print.pm +++ b/lib/Slic3r/Print.pm @@ -219,7 +219,7 @@ sub make_skirt { # $skirt_height_z in this case is the highest possible skirt height for safety. my $skirt_height_z = -1; foreach my $object (@{$self->objects}) { - my $skirt_height = ($self->config->skirt_height == -1) + my $skirt_height = ($self->config->skirt_height == -1 || $self->config->ooze_prevention) ? scalar(@{$object->layers}) : min($self->config->skirt_height, scalar(@{$object->layers})); diff --git a/lib/Slic3r/Print/GCode.pm b/lib/Slic3r/Print/GCode.pm index dae9eb3a7..a40a64e28 100644 --- a/lib/Slic3r/Print/GCode.pm +++ b/lib/Slic3r/Print/GCode.pm @@ -147,15 +147,26 @@ sub export { my $outer_skirt = convex_hull(\@skirt_points); my @skirts = (); foreach my $extruder_id (@{$self->print->extruders}) { + my $extruder_offset = $self->config->get_at('extruder_offset', $extruder_id); push @skirts, my $s = $outer_skirt->clone; - $s->translate(map scale($_), @{$self->config->get_at('extruder_offset', $extruder_id)}); + $s->translate(-scale($extruder_offset->x), -scale($extruder_offset->y)); #) } my $convex_hull = convex_hull([ map @$_, @skirts ]); $gcodegen->ooze_prevention->enable(1); $gcodegen->ooze_prevention->standby_points( - [ map $_->clone, map @$_, map $_->subdivide(scale 10), @{offset([$convex_hull], scale 3)} ] + [ map @{$_->equally_spaced_points(scale 10)}, @{offset([$convex_hull], scale 3)} ] ); + + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output( + "ooze_prevention.svg", + polygons => [$outer_skirt], + red_polygons => \@skirts, + points => $gcodegen->ooze_prevention->standby_points, + ); + } } } From 0b77fe743cfd1534800b3967ca6f107f276da5d9 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 01:10:34 +0100 Subject: [PATCH 10/26] Workaround for upstream bug in OpenGL test that prevents installation --- Build.PL | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Build.PL b/Build.PL index 117b0aeeb..2bbc3fac9 100644 --- a/Build.PL +++ b/Build.PL @@ -110,7 +110,9 @@ EOF my %modules = (%prereqs, %recommends); foreach my $module (sort keys %modules) { my $version = $modules{$module}; - my @cmd = ($cpanm, @cpanm_args, "$module~$version"); + my @cmd = ($cpanm, @cpanm_args); + push @cmd, '-f', if $module eq 'OpenGL'; # temporary workaround for upstream bug in test + push @cmd, "$module~$version"; if ($module eq 'XML::SAX::ExpatXS' && $^O eq 'MSWin32') { my $mingw = 'C:\dev\CitrusPerl\mingw64'; $mingw = 'C:\dev\CitrusPerl\mingw32' if !-d $mingw; From de2fd9721c0772151f2841c5a4797110e2a70f4c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 01:37:34 +0100 Subject: [PATCH 11/26] Fixed ooze prevention test as well --- t/multi.t | 39 ++++++++++++++++++++++++++++++--------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/t/multi.t b/t/multi.t index 5431370dd..96703bed2 100644 --- a/t/multi.t +++ b/t/multi.t @@ -17,23 +17,25 @@ use Slic3r::Test; my $config = Slic3r::Config->new_from_defaults; $config->set('raft_layers', 2); $config->set('infill_extruder', 2); - $config->set('support_material_extruder', 3); + $config->set('solid_infill_extruder', 3); + $config->set('support_material_extruder', 4); $config->set('ooze_prevention', 1); - $config->set('extruder_offset', [ [0,0], [20,0], [0,20] ]); - $config->set('temperature', [200, 180, 170]); - $config->set('first_layer_temperature', [206, 186, 166]); + $config->set('extruder_offset', [ [0,0], [20,0], [0,20], [20,20] ]); + $config->set('temperature', [200, 180, 170, 160]); + $config->set('first_layer_temperature', [206, 186, 166, 156]); $config->set('toolchange_gcode', ';toolchange'); # test that it doesn't crash when this is supplied my $print = Slic3r::Test::init_print('20mm_cube', config => $config); my $tool = undef; - my @tool_temp = (0,0,0); + my @tool_temp = (0,0,0,0); my @toolchange_points = (); my @extrusion_points = (); Slic3r::GCode::Reader->new->parse(Slic3r::Test::gcode($print), sub { my ($self, $cmd, $args, $info) = @_; if ($cmd =~ /^T(\d+)/) { + # ignore initial toolchange if (defined $tool) { my $expected_temp = $self->Z == ($config->get_value('first_layer_height') + $config->z_offset) ? $config->first_layer_temperature->[$tool] @@ -41,8 +43,8 @@ use Slic3r::Test; die 'standby temperature was not set before toolchange' if $tool_temp[$tool] != $expected_temp + $config->standby_temperature_delta; - # ignore initial toolchange - push @toolchange_points, Slic3r::Point->new_scale($self->X, $self->Y); + push @toolchange_points, my $point = Slic3r::Point->new_scale($self->X, $self->Y); + $point->translate(map +scale($_), @{ $config->extruder_offset->[$tool] }); } $tool = $1; } elsif ($cmd eq 'M104' || $cmd eq 'M109') { @@ -54,11 +56,30 @@ use Slic3r::Test; $tool_temp[$t] = $args->{S}; } elsif ($cmd eq 'G1' && $info->{extruding} && $info->{dist_XY} > 0) { push @extrusion_points, my $point = Slic3r::Point->new_scale($args->{X}, $args->{Y}); - $point->translate(map scale($_), @{ $config->extruder_offset->[$tool] }); + $point->translate(map +scale($_), @{ $config->extruder_offset->[$tool] }); } }); my $convex_hull = convex_hull(\@extrusion_points); - ok !(defined first { $convex_hull->contains_point($_) } @toolchange_points), 'all toolchanges happen outside skirt'; + + my @t = (); + foreach my $point (@toolchange_points) { + foreach my $offset (@{$config->extruder_offset}) { + push @t, my $p = $point->clone; + $p->translate(map +scale($_), @$offset); + } + } + ok !(defined first { $convex_hull->contains_point($_) } @t), 'all nozzles are outside skirt at toolchange'; + + if (0) { + require "Slic3r/SVG.pm"; + Slic3r::SVG::output( + "ooze_prevention.svg", + no_arrows => 1, + polygons => [$convex_hull], + points => \@toolchange_points, + red_points => \@t, + ); + } # offset the skirt by the maximum displacement between extruders plus a safety extra margin my $delta = scale(20 * sqrt(2) + 1); From 242dc176802c0164242a3df93273b3b7afbe0487 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 11:45:09 +0100 Subject: [PATCH 12/26] Minor improvements to Octoprint integration --- lib/Slic3r/GUI/Plater.pm | 6 ++++-- lib/Slic3r/GUI/Tab.pm | 3 ++- var/zoom.png | Bin 0 -> 692 bytes 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100755 var/zoom.png diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index cd5617778..fe754a044 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -195,7 +195,7 @@ sub new { reset cross.png arrange bricks.png export_gcode cog_go.png - send_gcode cog_go.png + send_gcode arrow_up.png export_stl brick_go.png increase add.png @@ -1124,7 +1124,9 @@ sub send_gcode { if ($res->is_success) { $self->statusbar->SetStatusText("G-code file successfully uploaded to the Octoprint server"); } else { - $self->statusbar->SetStatusText("Error while uploading to the Octoprint server: " . $res->status_line); + my $message = "Error while uploading to the Octoprint server: " . $res->status_line; + Slic3r::GUI::show_error($self, $message); + $self->statusbar->SetStatusText($message); } } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index b5250f047..af7aae4fe 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -1007,7 +1007,7 @@ sub build { my $btn = Wx::Button->new($parent, -1, "Browse…", wxDefaultPosition, wxDefaultSize, wxBU_LEFT); $btn->SetFont($Slic3r::GUI::small_font); if ($Slic3r::GUI::have_button_icons) { - $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/cog.png", wxBITMAP_TYPE_PNG)); + $btn->SetBitmap(Wx::Bitmap->new("$Slic3r::var/zoom.png", wxBITMAP_TYPE_PNG)); } if (!eval "use Net::Bonjour; 1") { @@ -1024,6 +1024,7 @@ sub build { $self->{config}->set('octoprint_host', $value); $self->update_dirty; $self->_on_value_change('octoprint_host', $value); + $self->reload_config; } }); diff --git a/var/zoom.png b/var/zoom.png new file mode 100755 index 0000000000000000000000000000000000000000..908612e394525fc2e52a7e9b94689c25ce167381 GIT binary patch literal 692 zcmV;l0!#ggP)m+BBgry{~j2fHLegbHP( zrgXNbr0}2;^nywdjLjZe?uxtrd3D(pZH@fFFc0{BW_~jxoO1w7-VX;6vK@ROA$$R6 zEmo;Ht-Mj|>5jUy{bQ^V5@53LRI8AgLpUm|m+15sqcz@QtVSo|oz7ArM8?pIn+>gN z0b=4_b5O|4A*;Q+vc9Vqr~%3V155*NV~@gTz}KSUiKB-uJzjMZ>5%Q#n24H!V{ zTY(LLAE*NAHZ}C#wnj%Bw5OFIkRhkkAW#kDC3j9Wm0YXRaXlyyp>#mVfYG)eC;@ab zDb=T-BCAY4LI(Z@GOTr2V_A{pRwSmz+8Be>CjAw(=gnbVWAeguvZa93JmL(EDxv1m z0OP4q=fpAK1Mq!C2`OkEn37o;m#wF#(t(8Pu#S?2f#x<~4EO{@fmm`p9veD6RZ_jp z@Au4};q&`XuKEYgIiB4((kgxOs#YdqJw0fY>9^K_agEu5+$#k;w#%I2N>n_?)YIqu z`tq&#_^p?-%K*U0^}|7+9U(&k0?s;=r=uCZ%)H9_edH8wK}gB(nUB1FFk+2Ol%BXV zHoFY`D~2x|2 Date: Mon, 29 Dec 2014 11:45:41 +0100 Subject: [PATCH 13/26] Releasing 1.2.3 --- xs/src/libslic3r/libslic3r.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index defe708ee..b9f3f1e07 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -6,7 +6,7 @@ #include #include -#define SLIC3R_VERSION "1.2.3-dev" +#define SLIC3R_VERSION "1.2.3" #define EPSILON 1e-4 #define SCALING_FACTOR 0.000001 From 6896e53078f62980732554cea644b9ee237b9e56 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 12:49:32 +0100 Subject: [PATCH 14/26] Octoprint -> OctoPrint --- lib/Slic3r/GUI/BonjourBrowser.pm | 2 +- lib/Slic3r/GUI/Plater.pm | 6 +++--- lib/Slic3r/GUI/Tab.pm | 2 +- xs/src/libslic3r/PrintConfig.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Slic3r/GUI/BonjourBrowser.pm b/lib/Slic3r/GUI/BonjourBrowser.pm index bb2282e59..281277768 100644 --- a/lib/Slic3r/GUI/BonjourBrowser.pm +++ b/lib/Slic3r/GUI/BonjourBrowser.pm @@ -19,7 +19,7 @@ sub new { $self->{devices} = [ $res->entries ]; # label - my $text = Wx::StaticText->new($self, -1, "Choose an Octoprint device in your network:", wxDefaultPosition, wxDefaultSize); + my $text = Wx::StaticText->new($self, -1, "Choose an OctoPrint device in your network:", wxDefaultPosition, wxDefaultSize); # selector $self->{choice} = my $choice = Wx::Choice->new($self, -1, wxDefaultPosition, wxDefaultSize, diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index fe754a044..f14da581d 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1086,7 +1086,7 @@ sub on_export_completed { my $send_gcode = 0; if ($result) { if ($self->{send_gcode_file}) { - $message = "Sending G-code file to the Octoprint server..."; + $message = "Sending G-code file to the OctoPrint server..."; $send_gcode = 1; } else { $message = "G-code file exported to " . $self->{export_gcode_output_file}; @@ -1122,9 +1122,9 @@ sub send_gcode { $self->statusbar->StopBusy; if ($res->is_success) { - $self->statusbar->SetStatusText("G-code file successfully uploaded to the Octoprint server"); + $self->statusbar->SetStatusText("G-code file successfully uploaded to the OctoPrint server"); } else { - my $message = "Error while uploading to the Octoprint server: " . $res->status_line; + my $message = "Error while uploading to the OctoPrint server: " . $res->status_line; Slic3r::GUI::show_error($self, $message); $self->statusbar->SetStatusText($message); } diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index af7aae4fe..6aac1c862 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -998,7 +998,7 @@ sub build { }); } { - my $optgroup = $page->new_optgroup('Octoprint upload'); + my $optgroup = $page->new_optgroup('OctoPrint upload'); # append a button to the Host line my $octoprint_host_widget = sub { diff --git a/xs/src/libslic3r/PrintConfig.cpp b/xs/src/libslic3r/PrintConfig.cpp index 805667a8a..2ca83c15e 100644 --- a/xs/src/libslic3r/PrintConfig.cpp +++ b/xs/src/libslic3r/PrintConfig.cpp @@ -500,12 +500,12 @@ PrintConfigDef::build_def() { Options["octoprint_apikey"].type = coString; Options["octoprint_apikey"].label = "API Key"; - Options["octoprint_apikey"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the API Key required for authentication."; + Options["octoprint_apikey"].tooltip = "Slic3r can upload G-code files to OctoPrint. This field should contain the API Key required for authentication."; Options["octoprint_apikey"].cli = "octoprint-apikey=s"; Options["octoprint_host"].type = coString; Options["octoprint_host"].label = "Host or IP"; - Options["octoprint_host"].tooltip = "Slic3r can upload G-code files to Octoprint. This field should contain the hostname or IP address of the Octoprint instance."; + Options["octoprint_host"].tooltip = "Slic3r can upload G-code files to OctoPrint. This field should contain the hostname or IP address of the OctoPrint instance."; Options["octoprint_host"].cli = "octoprint-host=s"; Options["only_retract_when_crossing_perimeters"].type = coBool; From 200130bc10132b4df238eab38c3154b6871770c2 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 12:49:49 +0100 Subject: [PATCH 15/26] Bump version number --- xs/src/libslic3r/libslic3r.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index b9f3f1e07..34a88e840 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -6,7 +6,7 @@ #include #include -#define SLIC3R_VERSION "1.2.3" +#define SLIC3R_VERSION "1.2.4-dev" #define EPSILON 1e-4 #define SCALING_FACTOR 0.000001 From d38503bf44fbc5740fbf47248d4e73a2ad5096f6 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 14:29:21 +0100 Subject: [PATCH 16/26] Bugfix: downwards interface detection might cause a crash --- lib/Slic3r/Print/SupportMaterial.pm | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/Slic3r/Print/SupportMaterial.pm b/lib/Slic3r/Print/SupportMaterial.pm index a738c1dd8..7e23a75c7 100644 --- a/lib/Slic3r/Print/SupportMaterial.pm +++ b/lib/Slic3r/Print/SupportMaterial.pm @@ -442,23 +442,25 @@ sub generate_bottom_interface_layers { my $z = $support_z->[$layer_id]; next unless $z > $top_z; - # get the support material area that should be considered interface - my $interface_area = intersection( - $base->{$layer_id}, - $this, - ); + if ($base->{$layer_id}) { + # get the support material area that should be considered interface + my $interface_area = intersection( + $base->{$layer_id}, + $this, + ); - # discard too small areas - $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ]; + # discard too small areas + $interface_area = [ grep abs($_->area) >= $area_threshold, @$interface_area ]; - # subtract new interface area from base - $base->{$layer_id} = diff( - $base->{$layer_id}, - $interface_area, - ); + # subtract new interface area from base + $base->{$layer_id} = diff( + $base->{$layer_id}, + $interface_area, + ); - # add new interface area to interface - push @{$interface->{$layer_id}}, @$interface_area; + # add new interface area to interface + push @{$interface->{$layer_id}}, @$interface_area; + } $interface_layers++; last if $interface_layers == $self->object_config->support_material_interface_layers; From 67d7658c59e66443a39d859d6c37bcfc1dc257ad Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 14:42:41 +0100 Subject: [PATCH 17/26] Bugfix: random misalignment of the 3D Honeycomb pattern --- lib/Slic3r/Fill/3DHoneycomb.pm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/Slic3r/Fill/3DHoneycomb.pm b/lib/Slic3r/Fill/3DHoneycomb.pm index 256437707..b24caf49a 100644 --- a/lib/Slic3r/Fill/3DHoneycomb.pm +++ b/lib/Slic3r/Fill/3DHoneycomb.pm @@ -19,12 +19,14 @@ sub fill_surface { my $distance = scale($self->spacing) / $params{density}; - # align bounding box to a multiple of our honeycomb grid + # align bounding box to a multiple of our honeycomb grid module + # (a module is 2*$distance since one $distance half-module is + # growing while the other $distance half-module is shrinking) { my $min = $bb->min_point; $min->translate( - -($bb->x_min % $distance), - -($bb->y_min % $distance), + -($bb->x_min % (2*$distance)), + -($bb->y_min % (2*$distance)), ); $bb->merge_point($min); } From 1c0437bc7b010f0745d946db9a85797ac5e73ccf Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 15:52:48 +0100 Subject: [PATCH 18/26] One more fix to 3D honeycomb not covering the entire area after last commit --- lib/Slic3r/Fill/3DHoneycomb.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/Fill/3DHoneycomb.pm b/lib/Slic3r/Fill/3DHoneycomb.pm index b24caf49a..3bf7e547f 100644 --- a/lib/Slic3r/Fill/3DHoneycomb.pm +++ b/lib/Slic3r/Fill/3DHoneycomb.pm @@ -36,8 +36,8 @@ sub fill_surface { makeGrid( scale($self->z), $distance, - ceil($size->x / $distance), - ceil($size->y / $distance), #// + ceil($size->x / $distance) + 1, + ceil($size->y / $distance) + 1, #// (($self->layer_id / $surface->thickness_layers) % 2) + 1, ); From 9d5f55af7722858bcae5b544f018f1c5fe30f035 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 17:40:56 +0100 Subject: [PATCH 19/26] Minor optimization in G-code export --- lib/Slic3r/GCode.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/GCode.pm b/lib/Slic3r/GCode.pm index 21dc773fb..0a8f3951c 100644 --- a/lib/Slic3r/GCode.pm +++ b/lib/Slic3r/GCode.pm @@ -220,7 +220,7 @@ sub extrude_loop { $point->rotate($angle, $first_segment->a); # generate the travel move - $gcode .= $self->travel_to($point, $paths[-1]->role, "move inwards before travel"); + $gcode .= $self->writer->travel_to_xy($self->point_to_gcode($point), "move inwards before travel"); } return $gcode; From 4b7cec28b926aab2d7b0ded080bf75854dfd8635 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 20:34:33 +0100 Subject: [PATCH 20/26] Fix to Octoprint upload. #2465 --- lib/Slic3r/GUI/Plater.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index f14da581d..46aa55139 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -1115,7 +1115,7 @@ sub send_gcode { Content_Type => 'form-data', 'X-Api-Key' => $self->{config}->octoprint_apikey, Content => [ - fn => [$self->{send_gcode_file}], + file => [$self->{send_gcode_file}], ], ); From 494efe65b2263bf64872a791816e3453c469d6b3 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 29 Dec 2014 22:29:24 +0100 Subject: [PATCH 21/26] Bugfix: auto-center didn't update the PrintObject copies properly, causing misalignment. #2464 --- lib/Slic3r/GUI/Plater.pm | 44 +++++++++++++++----------------------- xs/src/libslic3r/Print.cpp | 10 +++++++++ xs/src/libslic3r/Print.hpp | 1 + xs/xsp/Print.xsp | 1 + 4 files changed, 29 insertions(+), 27 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 46aa55139..ca548e1aa 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -89,16 +89,7 @@ sub new { }; my $on_instance_moved = sub { my ($obj_idx, $instance_idx) = @_; - $self->update; - - $self->pause_background_process; - my $invalidated = $self->{print}->objects->[$obj_idx]->reload_model_instances(); - if ($invalidated) { - $self->schedule_background_process; - } else { - $self->resume_background_process; - } }; # Initialize 2D preview canvas @@ -564,7 +555,6 @@ sub remove { $self->select_object(undef); $self->update; - $self->schedule_background_process; } @@ -675,10 +665,10 @@ sub rotate { $model_object->update_bounding_box; # update print and start background processing $self->{print}->add_model_object($model_object, $obj_idx); - $self->schedule_background_process; $self->selection_changed; # refresh info (size etc.) $self->update; + $self->schedule_background_process; } sub flip { @@ -703,11 +693,10 @@ sub flip { # update print and start background processing $self->stop_background_process; $self->{print}->add_model_object($model_object, $obj_idx); - $self->schedule_background_process; $self->selection_changed; # refresh info (size etc.) $self->update; - $self->refresh_canvases; + $self->schedule_background_process; } sub changescale { @@ -758,11 +747,10 @@ sub changescale { # update print and start background processing $self->stop_background_process; $self->{print}->add_model_object($model_object, $obj_idx); - $self->schedule_background_process; $self->selection_changed(1); # refresh info (size, volume etc.) $self->update; - $self->refresh_canvases; + $self->schedule_background_process; } sub arrange { @@ -778,17 +766,6 @@ sub arrange { # when parts don't fit in print bed $self->update(1); - - my $invalidated = 0; - foreach my $object (@{$self->{print}->objects}) { - $invalidated = 1 if $object->reload_model_instances; - } - if ($invalidated) { - $self->schedule_background_process; - } else { - $self->resume_background_process; - } - $self->refresh_canvases; } sub split_object { @@ -1207,7 +1184,6 @@ sub on_thumbnail_made { my ($obj_idx) = @_; $self->{objects}[$obj_idx]->transform_thumbnail($self->{model}, $obj_idx); - $self->update; $self->refresh_canvases; } @@ -1220,9 +1196,23 @@ sub update { $self->{model}->center_instances_around_point($self->bed_centerf); } + $self->pause_background_process; + my $invalidated = $self->{print}->reload_model_instances(); + if ($invalidated) { + $self->schedule_background_process; + } else { + $self->resume_background_process; + } + $self->refresh_canvases; } +sub on_model_instances_changed { + my ($self) = @_; + + +} + sub on_extruders_change { my ($self, $num_extruders) = @_; diff --git a/xs/src/libslic3r/Print.cpp b/xs/src/libslic3r/Print.cpp index b40430fec..b87d1c8cf 100644 --- a/xs/src/libslic3r/Print.cpp +++ b/xs/src/libslic3r/Print.cpp @@ -116,6 +116,16 @@ Print::reload_object(size_t idx) } } +bool +Print::reload_model_instances() +{ + bool invalidated = false; + FOREACH_OBJECT(this, object) { + if ((*object)->reload_model_instances()) invalidated = true; + } + return invalidated; +} + void Print::clear_regions() { diff --git a/xs/src/libslic3r/Print.hpp b/xs/src/libslic3r/Print.hpp index 0e7334eaf..aa67e1c6d 100644 --- a/xs/src/libslic3r/Print.hpp +++ b/xs/src/libslic3r/Print.hpp @@ -174,6 +174,7 @@ class Print PrintObject* get_object(size_t idx); void delete_object(size_t idx); void reload_object(size_t idx); + bool reload_model_instances(); // methods for handling regions PrintRegion* get_region(size_t idx); diff --git a/xs/xsp/Print.xsp b/xs/xsp/Print.xsp index c3c9a97c5..fb0d17721 100644 --- a/xs/xsp/Print.xsp +++ b/xs/xsp/Print.xsp @@ -143,6 +143,7 @@ _constant() Ref get_object(int idx); void delete_object(int idx); void reload_object(int idx); + bool reload_model_instances(); size_t object_count() %code%{ RETVAL = THIS->objects.size(); %}; From c4832c534295380f95088fa249327e0713722095 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 30 Dec 2014 13:16:28 +0100 Subject: [PATCH 22/26] Bugfix: early object destruction caused a segfault when splitting. Also fixed a memory leak and restore background processing when split only detected one part. #2466 #2398 --- lib/Slic3r/GUI/Plater.pm | 10 ++++++---- xs/src/libslic3r/Model.cpp | 3 ++- xs/src/perlglue.hpp | 8 ++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index ca548e1aa..f83ba8a60 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -774,18 +774,20 @@ sub split_object { 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 duplicated when we call load_model_objects() - my $current_model_object = $self->{model}->clone->objects->[$obj_idx]; + # 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} > 1) { + if ($current_model_object->volumes_count > 1) { Slic3r::GUI::warning_catcher($self)->("The selected object can't be split because it contains more than one volume/material."); return; } - $self->stop_background_process; + $self->pause_background_process; my @model_objects = @{$current_model_object->split_object}; if (@model_objects == 1) { + $self->resume_background_process; Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be split because it contains only one part."); return; } diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index 06919cedd..40926eb93 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -13,7 +13,7 @@ Model::Model(const Model &other) // copy objects this->objects.reserve(other.objects.size()); for (ModelObjectPtrs::const_iterator i = other.objects.begin(); i != other.objects.end(); ++i) - this->add_object(**i); + this->add_object(**i, true); } Model& Model::operator= (Model other) @@ -618,6 +618,7 @@ ModelObject::split(ModelObjectPtrs* new_objects) new_volume->material_id(volume->material_id()); new_objects->push_back(new_object); + delete *mesh; } return; diff --git a/xs/src/perlglue.hpp b/xs/src/perlglue.hpp index 833eee6f3..84c9a7ae9 100644 --- a/xs/src/perlglue.hpp +++ b/xs/src/perlglue.hpp @@ -42,9 +42,9 @@ template class Ref { T* val; public: - Ref() {} + Ref() : val(NULL) {} Ref(T* t) : val(t) {} - operator T*() const {return val; } + operator T*() const { return val; } static const char* CLASS() { return ClassTraits::name_ref; } }; @@ -52,10 +52,10 @@ template class Clone { T* val; public: - Clone() : val() {} + Clone() : val(NULL) {} Clone(T* t) : val(new T(*t)) {} Clone(const T& t) : val(new T(t)) {} - operator T*() const {return val; } + operator T*() const { return val; } static const char* CLASS() { return ClassTraits::name; } }; }; From 77d2a8aa8ccf4a7317343f7fd030efc513cf1240 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 30 Dec 2014 13:24:00 +0100 Subject: [PATCH 23/26] Fix Preferences window size. #2463 --- lib/Slic3r/GUI/Preferences.pm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Slic3r/GUI/Preferences.pm b/lib/Slic3r/GUI/Preferences.pm index aab037ce7..74846cfc9 100644 --- a/lib/Slic3r/GUI/Preferences.pm +++ b/lib/Slic3r/GUI/Preferences.pm @@ -5,7 +5,7 @@ use base 'Wx::Dialog'; sub new { my ($class, $parent) = @_; - my $self = $class->SUPER::new($parent, -1, "Preferences", wxDefaultPosition, [500,200]); + my $self = $class->SUPER::new($parent, -1, "Preferences", wxDefaultPosition, wxDefaultSize); $self->{values} = {}; my $optgroup; @@ -16,7 +16,7 @@ sub new { my ($opt_id) = @_; $self->{values}{$opt_id} = $optgroup->get_value($opt_id); }, - label_width => 100, + label_width => 200, ); $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( opt_id => 'mode', @@ -26,6 +26,7 @@ sub new { labels => ['Simple','Expert'], values => ['simple','expert'], default => $Slic3r::GUI::Settings->{_}{mode}, + width => 100, )); $optgroup->append_single_option_line(Slic3r::GUI::OptionsGroup::Option->new( opt_id => 'version_check', From 7fa27c958a69706e2766e173f3c6103b46a1a2c4 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 30 Dec 2014 14:21:10 +0100 Subject: [PATCH 24/26] Bugfix: when dragging an object, only one part was moving. #2467 --- lib/Slic3r/GUI/PreviewCanvas.pm | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/Slic3r/GUI/PreviewCanvas.pm b/lib/Slic3r/GUI/PreviewCanvas.pm index d9e418345..f48240392 100644 --- a/lib/Slic3r/GUI/PreviewCanvas.pm +++ b/lib/Slic3r/GUI/PreviewCanvas.pm @@ -151,9 +151,6 @@ sub mouse_event { } } } elsif ($e->Dragging && $e->LeftIsDown && defined($self->_drag_volume_idx)) { - # get volume being dragged - my $volume = $self->volumes->[$self->_drag_volume_idx]; - # get new position at the same Z of the initial click point my $mouse_ray = $self->mouse_ray($e->GetX, $e->GetY); my $cur_pos = $mouse_ray->intersect_plane($self->_drag_start_pos->z); @@ -161,8 +158,14 @@ sub mouse_event { # calculate the translation vector my $vector = $self->_drag_start_pos->vector_to($cur_pos); + # get volume being dragged + my $volume = $self->volumes->[$self->_drag_volume_idx]; + + # get all volumes belonging to the same group but only having the same instance_idx + my @volumes = grep $_->group_id == $volume->group_id && $_->instance_idx == $volume->instance_idx, @{$self->volumes}; + # apply new temporary volume origin and ignore Z - $volume->origin->translate($vector->x, $vector->y, 0); #,, + $_->origin->translate($vector->x, $vector->y, 0) for @volumes; #,, $self->_drag_start_pos($cur_pos); $self->_dragged(1); $self->Refresh; @@ -346,6 +349,7 @@ sub load_object { # sort volumes: non-modifiers first my @volumes = sort { ($a->modifier // 0) <=> ($b->modifier // 0) } @{$object->volumes}; my @volumes_idx = (); + my $group_id = $#{$self->volumes} + 1; foreach my $volume (@volumes) { my @instance_idxs = $all_instances ? (0..$#{$object->instances}) : (0); foreach my $instance_idx (@instance_idxs) { @@ -363,6 +367,7 @@ sub load_object { my $color = [ @{COLORS->[ $color_idx % scalar(@{&COLORS}) ]} ]; push @$color, $volume->modifier ? 0.5 : 1; push @{$self->volumes}, my $v = Slic3r::GUI::PreviewCanvas::Volume->new( + group_id => $group_id, instance_idx => $instance_idx, mesh => $mesh, color => $color, @@ -888,6 +893,7 @@ use Moo; has 'mesh' => (is => 'ro', required => 1); has 'color' => (is => 'ro', required => 1); +has 'group_id' => (is => 'ro', required => 1); has 'instance_idx' => (is => 'ro', default => sub { 0 }); has 'origin' => (is => 'rw', default => sub { Slic3r::Pointf3->new(0,0,0) }); has 'verts' => (is => 'rw'); From fffdbe0abb032a795e680825b058d6d660f27668 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 30 Dec 2014 14:51:59 +0100 Subject: [PATCH 25/26] Releasing 1.2.4 --- xs/src/libslic3r/libslic3r.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xs/src/libslic3r/libslic3r.h b/xs/src/libslic3r/libslic3r.h index 34a88e840..4a02ac2cd 100644 --- a/xs/src/libslic3r/libslic3r.h +++ b/xs/src/libslic3r/libslic3r.h @@ -6,7 +6,7 @@ #include #include -#define SLIC3R_VERSION "1.2.4-dev" +#define SLIC3R_VERSION "1.2.4" #define EPSILON 1e-4 #define SCALING_FACTOR 0.000001 From 1eac452d71f4ea4d0d375159f192c52ac81a690c Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Tue, 30 Dec 2014 22:07:21 +0100 Subject: [PATCH 26/26] Send file basename when uploading to OctoPrint --- lib/Slic3r/GUI/Plater.pm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index f83ba8a60..2517cd893 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -789,6 +789,7 @@ sub split_object { if (@model_objects == 1) { $self->resume_background_process; Slic3r::GUI::warning_catcher($self)->("The selected object couldn't be split because it contains only one part."); + $self->resume_background_process; return; } @@ -1094,7 +1095,8 @@ sub send_gcode { Content_Type => 'form-data', 'X-Api-Key' => $self->{config}->octoprint_apikey, Content => [ - file => [$self->{send_gcode_file}], + # OctoPrint doesn't like Windows paths + file => [ $self->{send_gcode_file}, basename($self->{send_gcode_file}) ], ], );