Merge branch 'master' into sender
This commit is contained in:
commit
29d64107de
6
Build.PL
6
Build.PL
@ -28,6 +28,8 @@ my %prereqs = qw(
|
||||
);
|
||||
my %recommends = qw(
|
||||
Class::XSAccessor 0
|
||||
LWP::UserAgent 0
|
||||
Net::Bonjour 0
|
||||
XML::SAX::ExpatXS 0
|
||||
);
|
||||
|
||||
@ -109,7 +111,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;
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
@ -34,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,
|
||||
);
|
||||
|
||||
|
@ -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;
|
||||
@ -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) {
|
||||
|
@ -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;
|
||||
@ -27,6 +28,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 +230,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 {
|
||||
|
51
lib/Slic3r/GUI/BonjourBrowser.pm
Normal file
51
lib/Slic3r/GUI/BonjourBrowser.pm
Normal file
@ -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;
|
@ -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?",
|
||||
|
@ -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 {
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
@ -88,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
|
||||
@ -181,9 +173,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 +186,7 @@ sub new {
|
||||
reset cross.png
|
||||
arrange bricks.png
|
||||
export_gcode cog_go.png
|
||||
send_gcode arrow_up.png
|
||||
export_stl brick_go.png
|
||||
|
||||
increase add.png
|
||||
@ -213,7 +208,11 @@ sub new {
|
||||
$self->export_gcode;
|
||||
Slic3r::thread_cleanup();
|
||||
});
|
||||
#EVT_BUTTON($self, $self->{btn_export_stl}, \&export_stl);
|
||||
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}) {
|
||||
EVT_TOOL($self, TB_ADD, sub { $self->add; });
|
||||
@ -355,6 +354,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);
|
||||
@ -555,7 +555,6 @@ sub remove {
|
||||
|
||||
$self->select_object(undef);
|
||||
$self->update;
|
||||
|
||||
$self->schedule_background_process;
|
||||
}
|
||||
|
||||
@ -666,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 {
|
||||
@ -694,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 {
|
||||
@ -749,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 {
|
||||
@ -769,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 {
|
||||
@ -788,19 +774,22 @@ 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.");
|
||||
$self->resume_background_process;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -944,7 +933,7 @@ sub resume_background_process {
|
||||
}
|
||||
|
||||
sub export_gcode {
|
||||
my $self = shift;
|
||||
my ($self, $output_file) = @_;
|
||||
|
||||
return if !@{$self->{objects}};
|
||||
|
||||
@ -976,14 +965,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 +1000,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 +1063,52 @@ 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 => [
|
||||
# OctoPrint doesn't like Windows paths
|
||||
file => [ $self->{send_gcode_file}, basename($self->{send_gcode_file}) ],
|
||||
],
|
||||
);
|
||||
|
||||
$self->statusbar->StopBusy;
|
||||
|
||||
if ($res->is_success) {
|
||||
$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;
|
||||
Slic3r::GUI::show_error($self, $message);
|
||||
$self->statusbar->SetStatusText($message);
|
||||
}
|
||||
}
|
||||
|
||||
sub export_stl {
|
||||
@ -1159,7 +1188,6 @@ sub on_thumbnail_made {
|
||||
my ($obj_idx) = @_;
|
||||
|
||||
$self->{objects}[$obj_idx]->transform_thumbnail($self->{model}, $obj_idx);
|
||||
$self->update;
|
||||
$self->refresh_canvases;
|
||||
}
|
||||
|
||||
@ -1172,9 +1200,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) = @_;
|
||||
|
||||
@ -1208,6 +1250,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 +1362,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)
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
|
@ -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');
|
||||
|
@ -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,45 @@ sub build {
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('OctoPrint upload');
|
||||
|
||||
# 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/zoom.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);
|
||||
$self->reload_config;
|
||||
}
|
||||
});
|
||||
|
||||
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');
|
||||
}
|
||||
{
|
||||
my $optgroup = $page->new_optgroup('Advanced');
|
||||
$optgroup->append_single_option_line('use_firmware_retraction');
|
||||
@ -1129,6 +1169,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 +1361,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;
|
||||
|
||||
|
@ -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}));
|
||||
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
39
t/multi.t
39
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);
|
||||
|
BIN
var/zoom.png
Executable file
BIN
var/zoom.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 692 B |
@ -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;
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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).";
|
||||
|
@ -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;
|
||||
};
|
||||
};
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#define SLIC3R_VERSION "1.2.2"
|
||||
#define SLIC3R_VERSION "1.2.4"
|
||||
|
||||
#define EPSILON 1e-4
|
||||
#define SCALING_FACTOR 0.000001
|
||||
|
@ -42,9 +42,9 @@ template <class T>
|
||||
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<T>::name_ref; }
|
||||
};
|
||||
|
||||
@ -52,10 +52,10 @@ template <class T>
|
||||
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<T>::name; }
|
||||
};
|
||||
};
|
||||
|
@ -143,6 +143,7 @@ _constant()
|
||||
Ref<PrintObject> 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(); %};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user