From b142469cf37d4c64fb4ad033a2d334cbfa210fab Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Sun, 15 Jun 2014 00:03:17 +0200 Subject: [PATCH 1/8] Revert "Add 5.20 to Travis CI builds" as it looks like Travis has issues with 5.20 This reverts commit 4522b7f31b7e753f4e19af60e55633d7c3e0ee52. --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d7f3d7e72..6b5086838 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ perl: - "5.12" - "5.14" - "5.18" - - "5.20" branches: only: - master From 4fe2128fc424c879ffe5e4c7fc2b8783980ed8f4 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 01:49:49 +0200 Subject: [PATCH 2/8] Initial work for custom bed shape --- lib/Slic3r/Config.pm | 2 +- lib/Slic3r/GUI.pm | 1 + lib/Slic3r/GUI/BedShapeDialog.pm | 167 +++++++++++++++++++++++++++++++ lib/Slic3r/GUI/OptionsGroup.pm | 40 ++++---- lib/Slic3r/GUI/Tab.pm | 42 +++++++- xs/src/PrintConfig.cpp | 7 +- xs/src/PrintConfig.hpp | 9 +- xs/t/10_line.t | 11 +- 8 files changed, 248 insertions(+), 31 deletions(-) create mode 100644 lib/Slic3r/GUI/BedShapeDialog.pm diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index ae1912120..6693dcb18 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -23,7 +23,7 @@ $Options->{threads}{readonly} = !$Slic3r::have_threads; *{$opt_key} = sub { $_[0]->get($opt_key) }; } } - +sub bed_size { [200,200] } sub new_from_defaults { my $class = shift; my (@opt_keys) = @_; diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index e9ad5399b..29c6708a6 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -6,6 +6,7 @@ use utf8; use File::Basename qw(basename); use FindBin; use Slic3r::GUI::AboutDialog; +use Slic3r::GUI::BedShapeDialog; use Slic3r::GUI::ConfigWizard; use Slic3r::GUI::MainFrame; use Slic3r::GUI::Notifier; diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm new file mode 100644 index 000000000..2cc7998b7 --- /dev/null +++ b/lib/Slic3r/GUI/BedShapeDialog.pm @@ -0,0 +1,167 @@ +package Slic3r::GUI::BedShapeDialog; +use strict; +use warnings; +use utf8; + +use List::Util qw(min max); +use Slic3r::Geometry qw(PI X Y unscale); +use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_CHOICE); +use base 'Wx::Dialog'; + +use constant SHAPE_RECTANGULAR => 0; +use constant SHAPE_CIRCULAR => 1; +use constant SHAPE_CUSTOM => 2; + +sub new { + my $class = shift; + my ($parent, $default) = @_; + my $self = $class->SUPER::new($parent, -1, "Bed Shape", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + my $box = Wx::StaticBox->new($self, -1, "Shape"); + my $sbsizer = Wx::StaticBoxSizer->new($box, wxVERTICAL); + + # shape options + $self->{shape_options_book} = Wx::Choicebook->new($self, -1, wxDefaultPosition, [300,-1], wxCHB_TOP); + $sbsizer->Add($self->{shape_options_book}); + + $self->{optgroups} = []; + $self->_init_shape_options_page('Rectangular', [ + { + opt_key => 'rect_size', + type => 'point', + label => 'Size', + tooltip => 'Size in X and Y of the rectangular plate.', + default => [200,200], + }, + { + opt_key => 'rect_origin', + type => 'select', + label => 'Origin', + tooltip => 'Position of the 0,0 point.', + labels => ['Front left corner','Center'], + values => ['corner','center'], + default => 'corner', + }, + ]); + + # right pane with preview canvas + my $canvas; + + # main sizer + my $top_sizer = Wx::BoxSizer->new(wxHORIZONTAL); + $top_sizer->Add($sbsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); + $top_sizer->Add($canvas, 1, wxEXPAND | wxALL, 0) if $canvas; + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($top_sizer, 1, wxEXPAND); + $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; + }); + + $self->_set_shape($default); + $self->_update_preview; + + return $self; +} + +sub _set_shape { + my ($self, $points) = @_; + + $self->{bed_shape} = $points; + + # is this a rectangle? + if (@$points == 4) { + my $polygon = Slic3r::Polygon->new_scale(@$points); + my $lines = $polygon->lines; + if ($lines->[0]->parallel_to_line($lines->[2]) && $lines->[1]->parallel_to_line($lines->[3])) { + # okay, it's a rectangle + # let's check whether origin is at a known point + my $x_min = min(map $_->[X], @$points); + my $x_max = max(map $_->[X], @$points); + my $y_min = min(map $_->[Y], @$points); + my $y_max = max(map $_->[Y], @$points); + my $origin; + if ($x_min == 0 && $y_min == 0) { + $origin = 'corner'; + } elsif (($x_min + $x_max)/2 == 0 && ($y_min + $y_max)/2 == 0) { + $origin = 'center'; + } + if (defined $origin) { + $self->{shape_options_book}->SetSelection(SHAPE_RECTANGULAR); + my $optgroup = $self->{optgroups}[SHAPE_RECTANGULAR]; + $optgroup->set_value('rect_size', [ $x_max-$x_min, $y_max-$y_min ]); + $optgroup->set_value('rect_origin', $origin); + return; + } + } + } + + $self->{shape_options_book}->SetSelection(SHAPE_CUSTOM); +} + +sub _update_shape { + my ($self) = @_; + + my $page_idx = $self->{shape_options_book}->GetSelection; + if ($page_idx == SHAPE_RECTANGULAR) { + return if grep !defined($self->{"_$_"}), qw(rect_size rect_origin); # not loaded yet + my ($x, $y) = @{$self->{_rect_size}}; + my ($x0, $y0) = (0,0); + my ($x1, $y1) = ($x,$y); + if ($self->{_rect_origin} eq 'center') { + $x0 -= $x/2; + $x1 -= $x/2; + $y0 -= $y/2; + $y1 -= $y/2; + } + $self->{bed_shape} = [ + [$x0,$y0], + [$x1,$y0], + [$x1,$y1], + [$x0,$y1], + ]; + } + + $self->_update_preview; +} + +sub _update_preview { + my ($self) = @_; + + +} + +sub _init_shape_options_page { + my ($self, $title, $options) = @_; + + my $panel = Wx::Panel->new($self->{shape_options_book}); + push @{$self->{optgroups}}, my $optgroup = Slic3r::GUI::OptionsGroup->new( + parent => $panel, + title => 'Settings', + options => $options, + on_change => sub { + my ($opt_key, $value) = @_; + $self->{"_$opt_key"} = $value; + $self->_update_shape; + }, + label_width => 100, + ); + $panel->SetSizerAndFit($optgroup->sizer); + $self->{shape_options_book}->AddPage($panel, $title); +} + +sub GetValue { + my ($self) = @_; + return $self->{bed_shape}; +} + +1; diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 31fda69d7..2c9089a28 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -48,6 +48,7 @@ has 'options' => (is => 'ro', required => 1, trigger => 1); has 'lines' => (is => 'lazy'); has 'on_change' => (is => 'ro', default => sub { sub {} }); has 'no_labels' => (is => 'ro', default => sub { 0 }); +has 'staticbox' => (is => 'ro', default => sub { 1 }); has 'label_width' => (is => 'ro', default => sub { 180 }); has 'extra_column' => (is => 'ro'); has 'label_font' => (is => 'ro'); @@ -63,9 +64,11 @@ sub _trigger_options {} sub BUILD { my $self = shift; - { + if ($self->staticbox) { my $box = Wx::StaticBox->new($self->parent, -1, $self->title); $self->sizer(Wx::StaticBoxSizer->new($box, wxVERTICAL)); + } else { + $self->sizer(Wx::BoxSizer->new(wxVERTICAL)); } my $num_columns = $self->extra_column ? 3 : 2; @@ -79,9 +82,9 @@ sub BUILD { foreach my $line (@{$self->lines}) { if ($line->{sizer}) { $self->sizer->Add($line->{sizer}, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15); - } elsif ($line->{widget}) { - my $window = $line->{widget}->GetWindow($self->parent); - $self->sizer->Add($window, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15); + } elsif ($line->{widget} && $line->{full_width}) { + my $sizer = $line->{widget}->($self->parent); + $self->sizer->Add($sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15); } else { $self->_build_line($line, $grid_sizer); } @@ -143,7 +146,7 @@ sub _build_line { push @fields, $self->_build_field($opt); push @field_labels, $opt->{label}; } - if (@fields > 1 || $line->{sidetext}) { + if (@fields > 1 || $line->{widget} || $line->{sidetext}) { my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); for my $i (0 .. $#fields) { if (@fields > 1 && $field_labels[$i]) { @@ -153,7 +156,10 @@ sub _build_line { } $sizer->Add($fields[$i], 0, wxALIGN_CENTER_VERTICAL, 0); } - if ($line->{sidetext}) { + if ($line->{widget}) { + my $widget_sizer = $line->{widget}->($self->parent); + $sizer->Add($widget_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15); + } elsif ($line->{sidetext}) { my $sidetext = Wx::StaticText->new($self->parent, -1, $line->{sidetext}, wxDefaultPosition, wxDefaultSize); $sidetext->SetFont($self->sidetext_font); $sizer->Add($sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL , 4); @@ -479,26 +485,24 @@ sub _config_methods { } package Slic3r::GUI::OptionsGroup::StaticTextLine; -use Moo; use Wx qw(:misc :systemsettings); +use base 'Wx::StaticText'; -sub GetWindow { - my $self = shift; - my ($parent) = @_; +sub new { + my ($class, $parent) = @_; - $self->{statictext} = Wx::StaticText->new($parent, -1, "foo", wxDefaultPosition, wxDefaultSize); + my $self = $class->SUPER::new($parent, -1, "", wxDefaultPosition, wxDefaultSize); my $font = Wx::SystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - $self->{statictext}->SetFont($font); - return $self->{statictext}; + $self->SetFont($font); + return $self; } sub SetText { - my $self = shift; - my ($value) = @_; + my ($self, $value) = @_; - $self->{statictext}->SetLabel($value); - $self->{statictext}->Wrap(400); - $self->{statictext}->GetParent->Layout; + $self->SetLabel($value); + $self->Wrap(400); + $self->GetParent->Layout; } 1; diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index 811621d4d..a4e02b15d 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -599,7 +599,11 @@ sub build { Slic3r::GUI::OptionsGroup->single_option_line('cooling'), { label => '', - widget => ($self->{description_line} = Slic3r::GUI::OptionsGroup::StaticTextLine->new), + full_width => 1, + widget => sub { + my ($parent) = @_; + return $self->{description_line} = Slic3r::GUI::OptionsGroup::StaticTextLine->new($parent); + }, }, ], }, @@ -662,6 +666,8 @@ sub on_value_change { package Slic3r::GUI::Tab::Printer; use base 'Slic3r::GUI::Tab'; +use Wx qw(:sizer :button :bitmap :misc :id); +use Wx::Event qw(EVT_BUTTON); sub name { 'printer' } sub title { 'Printer Settings' } @@ -671,10 +677,42 @@ sub build { $self->{extruders_count} = 1; + my $bed_shape_widget = sub { + my ($parent) = @_; + + my $btn = Wx::Button->new($parent, -1, "Set…", 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)); + } + + my $sizer = Wx::BoxSizer->new(wxHORIZONTAL); + $sizer->Add($btn); + + EVT_BUTTON($self, $btn, sub { + my $dlg = Slic3r::GUI::BedShapeDialog->new($self, $self->{config}->bed_shape); + if ($dlg->ShowModal == wxID_OK) { + my $value = $dlg->GetValue; + $self->{config}->set('bed_shape', $value); + $self->on_value_change('bed_shape', $value); + } + }); + + return $sizer; + }; + $self->add_options_page('General', 'printer_empty.png', optgroups => [ { title => 'Size and coordinates', - options => [qw(bed_size print_center z_offset)], + options => [qw(bed_shape print_center z_offset)], + lines => [ + { + label => 'Bed shape', + widget => $bed_shape_widget, + }, + Slic3r::GUI::OptionsGroup->single_option_line('print_center'), + Slic3r::GUI::OptionsGroup->single_option_line('z_offset'), + ], }, { title => 'Firmware', diff --git a/xs/src/PrintConfig.cpp b/xs/src/PrintConfig.cpp index 725ef502f..88561f6ed 100644 --- a/xs/src/PrintConfig.cpp +++ b/xs/src/PrintConfig.cpp @@ -11,11 +11,8 @@ PrintConfigDef::build_def() { Options["avoid_crossing_perimeters"].tooltip = "Optimize travel moves in order to minimize the crossing of perimeters. This is mostly useful with Bowden extruders which suffer from oozing. This feature slows down both the print and the G-code generation."; Options["avoid_crossing_perimeters"].cli = "avoid-crossing-perimeters!"; - Options["bed_size"].type = coPoint; - Options["bed_size"].label = "Bed size"; - Options["bed_size"].tooltip = "Size of your bed. This is used to adjust the preview in the plater and for auto-arranging parts in it."; - Options["bed_size"].sidetext = "mm"; - Options["bed_size"].cli = "bed-size=s"; + Options["bed_shape"].type = coPoints; + Options["bed_shape"].label = "Bed shape"; Options["bed_temperature"].type = coInt; Options["bed_temperature"].label = "Other layers"; diff --git a/xs/src/PrintConfig.hpp b/xs/src/PrintConfig.hpp index 6f05dd586..470cdd385 100644 --- a/xs/src/PrintConfig.hpp +++ b/xs/src/PrintConfig.hpp @@ -307,7 +307,7 @@ class PrintConfig : public virtual StaticPrintConfig { public: ConfigOptionBool avoid_crossing_perimeters; - ConfigOptionPoint bed_size; + ConfigOptionPoints bed_shape; ConfigOptionInt bed_temperature; ConfigOptionFloat bridge_acceleration; ConfigOptionInt bridge_fan_speed; @@ -378,7 +378,10 @@ class PrintConfig : public virtual StaticPrintConfig PrintConfig() : StaticPrintConfig() { this->avoid_crossing_perimeters.value = false; - this->bed_size.point = Pointf(200,200); + this->bed_shape.values.push_back(Pointf(0,0)); + this->bed_shape.values.push_back(Pointf(200,0)); + this->bed_shape.values.push_back(Pointf(200,200)); + this->bed_shape.values.push_back(Pointf(0,200)); this->bed_temperature.value = 0; this->bridge_acceleration.value = 0; this->bridge_fan_speed.value = 100; @@ -466,7 +469,7 @@ class PrintConfig : public virtual StaticPrintConfig ConfigOption* option(const t_config_option_key opt_key, bool create = false) { if (opt_key == "avoid_crossing_perimeters") return &this->avoid_crossing_perimeters; - if (opt_key == "bed_size") return &this->bed_size; + if (opt_key == "bed_shape") return &this->bed_shape; if (opt_key == "bed_temperature") return &this->bed_temperature; if (opt_key == "bridge_acceleration") return &this->bridge_acceleration; if (opt_key == "bridge_fan_speed") return &this->bridge_fan_speed; diff --git a/xs/t/10_line.t b/xs/t/10_line.t index b6ec3c316..67c3cd353 100644 --- a/xs/t/10_line.t +++ b/xs/t/10_line.t @@ -4,7 +4,7 @@ use strict; use warnings; use Slic3r::XS; -use Test::More tests => 34; +use Test::More tests => 39; use constant PI => 4 * atan2(1, 1); use constant EPSILON => 1E-4; @@ -40,10 +40,17 @@ isa_ok $line->[0], 'Slic3r::Point::Ref', 'line point is blessed'; ], 'translate'; } +{ + ok +Slic3r::Line->new([0,0],[200,0])->parallel_to_line(Slic3r::Line->new([200,200],[0,200])), 'parallel_to'; +} + foreach my $base_angle (0, PI/4, PI/2, PI) { my $line = Slic3r::Line->new([0,0], [100,0]); $line->rotate($base_angle, [0,0]); - ok $line->parallel_to_line($line->clone), 'line is parallel to self'; + my $clone = $line->clone; + ok $line->parallel_to_line($clone), 'line is parallel to self'; + $clone->reverse; + ok $line->parallel_to_line($clone), 'line is parallel to self + PI'; ok $line->parallel_to($line->direction), 'line is parallel to its direction'; ok $line->parallel_to($line->direction + PI), 'line is parallel to its direction + PI'; ok $line->parallel_to($line->direction - PI), 'line is parallel to its direction - PI'; From f4e4640c731ff99a7e957ad5f3ebb490082295a1 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 02:00:13 +0200 Subject: [PATCH 3/8] Liquid resizing of plater --- lib/Slic3r/GUI/Plater.pm | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 8dbdcaa44..edc0b5d10 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -38,7 +38,6 @@ our $ERROR_EVENT : shared = Wx::NewEventType; our $EXPORT_COMPLETED_EVENT : shared = Wx::NewEventType; our $PROCESS_COMPLETED_EVENT : shared = Wx::NewEventType; -use constant CANVAS_SIZE => [335,335]; use constant FILAMENT_CHOOSERS_SPACING => 3; use constant PROCESS_DELAY => 0.5 * 1000; # milliseconds @@ -69,7 +68,7 @@ sub new { } }); - $self->{canvas} = Slic3r::GUI::Plater::2D->new($self, CANVAS_SIZE, $self->{objects}, $self->{model}, $self->{config}); + $self->{canvas} = Slic3r::GUI::Plater::2D->new($self, [335,335], $self->{objects}, $self->{model}, $self->{config}); $self->{canvas}->on_select_object(sub { my ($obj_idx) = @_; $self->select_object($obj_idx); @@ -334,8 +333,8 @@ sub new { $right_sizer->Add($object_info_sizer, 0, wxEXPAND | wxLEFT | wxRIGHT, 5); my $hsizer = Wx::BoxSizer->new(wxHORIZONTAL); - $hsizer->Add($self->{canvas}, 0, wxTOP, 1); - $hsizer->Add($right_sizer, 1, wxEXPAND | wxBOTTOM, 0); + $hsizer->Add($self->{canvas}, 1, wxEXPAND | wxTOP, 1); + $hsizer->Add($right_sizer, 0, wxEXPAND | wxBOTTOM, 0); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($self->{htoolbar}, 0, wxEXPAND, 0) if $self->{htoolbar}; @@ -680,7 +679,7 @@ sub arrange { # get the bounding box of the model area shown in the viewport my $bb = Slic3r::Geometry::BoundingBox->new_from_points([ Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([0,0]) }), - Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units(CANVAS_SIZE) }), + Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([ map { $_->GetWidth, $_->GetHeight } $self->{canvas}->GetSize ]) }), ]); eval { From 7a20c4d52a1545378eba57e3f928240cbf9ec454 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 14:05:22 +0200 Subject: [PATCH 4/8] More incomplete work for using bed_shape in plater --- lib/Slic3r/GUI/Plater.pm | 9 +-- lib/Slic3r/GUI/Plater/2D.pm | 126 +++++++++++++++++++++--------------- lib/Slic3r/Model.pm | 1 + xs/src/Print.cpp | 2 +- 4 files changed, 77 insertions(+), 61 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index edc0b5d10..8565e6668 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -50,7 +50,7 @@ sub new { my ($parent) = @_; my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{config} = Slic3r::Config->new_from_defaults(qw( - bed_size print_center complete_objects extruder_clearance_radius skirts skirt_distance + bed_size bed_shape print_center complete_objects extruder_clearance_radius skirts skirt_distance )); $self->{model} = Slic3r::Model->new; $self->{print} = Slic3r::Print->new; @@ -676,12 +676,7 @@ sub changescale { sub arrange { my $self = shift; - # get the bounding box of the model area shown in the viewport - my $bb = Slic3r::Geometry::BoundingBox->new_from_points([ - Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([0,0]) }), - Slic3r::Point->new(@{ $self->{canvas}->point_to_model_units([ map { $_->GetWidth, $_->GetHeight } $self->{canvas}->GetSize ]) }), - ]); - + my $bb = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape})->bounding_box; eval { $self->{model}->arrange_objects($self->GetFrame->config->min_object_distance, $bb); }; diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index b335ab876..e7e69d7eb 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -3,11 +3,11 @@ use strict; use warnings; use utf8; -use List::Util qw(max first); +use List::Util qw(min max first); use Slic3r::Geometry qw(X Y scale unscale convex_hull); use Slic3r::Geometry::Clipper qw(offset JT_ROUND); use Wx qw(:misc :pen :brush :sizer :font :cursor wxTAB_TRAVERSAL); -use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT); +use Wx::Event qw(EVT_MOUSE_EVENTS EVT_PAINT EVT_SIZE); use base 'Wx::Panel'; use constant CANVAS_TEXT => join('-', +(localtime)[3,4]) eq '13-8' @@ -40,6 +40,9 @@ sub new { EVT_PAINT($self, \&repaint); EVT_MOUSE_EVENTS($self, \&mouse_event); + EVT_SIZE($self, sub { + $self->update_bed_size; + }); return $self; } @@ -71,25 +74,27 @@ sub repaint { my $size = $self->GetSize; my @size = ($size->GetWidth, $size->GetHeight); - # draw grid - $dc->SetPen($self->{grid_pen}); - my $step = 10 * $self->{scaling_factor}; - for (my $x = $step; $x <= $size[X]; $x += $step) { - $dc->DrawLine($x, 0, $x, $size[Y]); - } - for (my $y = $step; $y <= $size[Y]; $y += $step) { - $dc->DrawLine(0, $y, $size[X], $y); + # draw bed + { + $dc->SetPen($self->{print_center_pen}); + $dc->SetBrush($self->{transparent_brush}); + $dc->DrawPolygon($self->scaled_points_to_pixel($self->{bed_polygon}, 1), 0, 0); } + # draw grid + $dc->SetPen($self->{grid_pen}); + $dc->DrawLine(map @$_, @$_) for @{$self->{grid}}; + # draw print center - if (@{$self->{objects}}) { + if (@{$self->{objects}} && $Slic3r::GUI::Settings->{_}{autocenter}) { + my $center = $self->unscaled_point_to_pixel($self->{config}->print_center); $dc->SetPen($self->{print_center_pen}); - $dc->DrawLine($size[X]/2, 0, $size[X]/2, $size[Y]); - $dc->DrawLine(0, $size[Y]/2, $size[X], $size[Y]/2); + $dc->DrawLine($center->[X], 0, $center->[X], $size[Y]); + $dc->DrawLine(0, $center->[Y], $size[X], $center->[Y]); $dc->SetTextForeground(Wx::Colour->new(0,0,0)); $dc->SetFont(Wx::Font->new(10, wxDEFAULT, wxNORMAL, wxNORMAL)); - $dc->DrawLabel("X = " . $self->{config}->print_center->[X], Wx::Rect->new(0, 0, $self->GetSize->GetWidth, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM); - $dc->DrawRotatedText("Y = " . $self->{config}->print_center->[Y], 0, $size[Y]/2+15, 90); + $dc->DrawLabel("X = " . $self->{config}->print_center->[X], Wx::Rect->new(0, 0, $center->[X]*2, $self->GetSize->GetHeight), wxALIGN_CENTER_HORIZONTAL | wxALIGN_BOTTOM); + $dc->DrawRotatedText("Y = " . $self->{config}->print_center->[Y], 0, $center->[Y]+15, 90); } # draw frame @@ -131,7 +136,7 @@ sub repaint { } foreach my $expolygon (@$thumbnail) { foreach my $points (@{$expolygon->pp}) { - $dc->DrawPolygon($self->points_to_pixel($points, 1), 0, 0); + $dc->DrawPolygon($self->scaled_points_to_pixel($points, 1), 0, 0); } } @@ -151,7 +156,7 @@ sub repaint { my ($clearance) = @{offset([$thumbnail->convex_hull], (scale($self->{config}->extruder_clearance_radius) / 2), 1, JT_ROUND, scale(0.1))}; $dc->SetPen($self->{clearance_pen}); $dc->SetBrush($self->{transparent_brush}); - $dc->DrawPolygon($self->points_to_pixel($clearance, 1), 0, 0); + $dc->DrawPolygon($self->scaled_points_to_pixel($clearance, 1), 0, 0); } } } @@ -163,7 +168,7 @@ sub repaint { my ($convex_hull) = @{offset([convex_hull(\@points)], scale($self->{config}->skirt_distance), 1, JT_ROUND, scale(0.1))}; $dc->SetPen($self->{skirt_pen}); $dc->SetBrush($self->{transparent_brush}); - $dc->DrawPolygon($self->points_to_pixel($convex_hull, 1), 0, 0); + $dc->DrawPolygon($self->scaled_points_to_pixel($convex_hull, 1), 0, 0); } } @@ -173,16 +178,15 @@ sub repaint { sub mouse_event { my ($self, $event) = @_; - my $point = $event->GetPosition; - my $pos = $self->point_to_model_units([ $point->x, $point->y ]); #]] - $pos = Slic3r::Point->new_scale(@$pos); + my $pos = $event->GetPosition; + my $point = $self->point_to_model_units([ $pos->x, $pos->y ]); #]] if ($event->ButtonDown) { $self->{on_select_object}->(undef); OBJECTS: for my $obj_idx (0 .. $#{$self->{objects}}) { my $object = $self->{objects}->[$obj_idx]; for my $instance_idx (0 .. $#{ $object->instance_thumbnails }) { my $thumbnail = $object->instance_thumbnails->[$instance_idx]; - if (defined first { $_->contour->contains_point($pos) } @$thumbnail) { + if (defined first { $_->contour->contains_point($point) } @$thumbnail) { $self->{on_select_object}->($obj_idx); if ($event->LeftDown) { @@ -190,12 +194,12 @@ sub mouse_event { my $instance = $self->{model}->objects->[$obj_idx]->instances->[$instance_idx]; my $instance_origin = [ map scale($_), @{$instance->offset} ]; $self->{drag_start_pos} = [ # displacement between the click and the instance origin in scaled model units - $pos->x - $instance_origin->[X], - $pos->y - $instance_origin->[Y], #- + $point->x - $instance_origin->[X], + $point->y - $instance_origin->[Y], #- ]; $self->{drag_object} = [ $obj_idx, $instance_idx ]; } elsif ($event->RightDown) { - $self->{on_right_click}->($point); + $self->{on_right_click}->($pos); } last OBJECTS; @@ -224,7 +228,7 @@ sub mouse_event { $self->Refresh; } elsif ($event->Moving) { my $cursor = wxSTANDARD_CURSOR; - if (defined first { $_->contour->contains_point($pos) } map @$_, map @{$_->instance_thumbnails}, @{ $self->{objects} }) { + if (defined first { $_->contour->contains_point($point) } map @$_, map @{$_->instance_thumbnails}, @{ $self->{objects} }) { $cursor = Wx::Cursor->new(wxCURSOR_HAND); } $self->SetCursor($cursor); @@ -234,13 +238,37 @@ sub mouse_event { sub update_bed_size { my $self = shift; - # supposing the preview canvas is square, calculate the scaling factor - # to constrain print bed area inside preview # when the canvas is not rendered yet, its GetSize() method returns 0,0 + my $canvas_size = $self->GetSize; + my ($canvas_w, $canvas_h) = ($canvas_size->GetWidth, $canvas_size->GetHeight); + return if $canvas_w == 0; + + # get bed shape polygon + $self->{bed_polygon} = my $polygon = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape}); + my $bb = $polygon->bounding_box; + my $size = $bb->size; + + # calculate the scaling factor needed for constraining print bed area inside preview # scaling_factor is expressed in pixel / mm - my $width = $self->GetSize->GetWidth; - $self->{scaling_factor} = $width / max(@{ $self->{config}->bed_size }) - if $width != 0; + $self->{scaling_factor} = min($canvas_w / unscale($size->x), $canvas_h / unscale($size->y)); #) + + # calculate the displacement needed to center bed + $self->{bed_origin} = [ + $self->GetSize->GetWidth/2 - (unscale($bb->x_max + $bb->x_min)/2 * $self->{scaling_factor}), + $canvas_h - ($self->GetSize->GetHeight/2 - (unscale($bb->y_max + $bb->y_min)/2 * $self->{scaling_factor})), + ]; + + # cache bed contours and grid + { + my $step = scale 10; # 1cm grid + $self->{grid} = my $grid = []; # arrayref of lines + for (my $x = $bb->x_min + $step; $x < $bb->x_max; $x += $step) { + push @$grid, $self->scaled_points_to_pixel([[$x, $bb->y_min], [$x, $bb->y_max]], 1); + } + for (my $y = $bb->y_min + $step; $y < $bb->y_max; $y += $step) { + push @$grid, $self->scaled_points_to_pixel([[$bb->x_min, $y], [$bb->x_max, $y]], 1); + } + } } sub clean_instance_thumbnails { @@ -251,35 +279,25 @@ sub clean_instance_thumbnails { } } -# coordinates of the model origin (0,0) in pixels -sub model_origin_to_pixel { - my ($self) = @_; - - return [ - $self->GetSize->GetWidth/2 - ($self->{config}->print_center->[X] * $self->{scaling_factor}), - $self->GetSize->GetHeight/2 - ($self->{config}->print_center->[Y] * $self->{scaling_factor}), - ]; -} - -# convert a model coordinate into a pixel coordinate, assuming preview has square shape -sub point_to_pixel { +# convert a model coordinate into a pixel coordinate +sub unscaled_point_to_pixel { my ($self, $point) = @_; my $canvas_height = $self->GetSize->GetHeight; - my $zero = $self->model_origin_to_pixel; + my $zero = $self->{bed_origin}; return [ - $point->[X] * $self->{scaling_factor} + $zero->[X], - $canvas_height - ($point->[Y] * $self->{scaling_factor} + $zero->[Y]), + $point->[X] * $self->{scaling_factor} + $zero->[X], + $canvas_height - $point->[Y] * $self->{scaling_factor} + ($zero->[Y] - $canvas_height), ]; } -sub points_to_pixel { +sub scaled_points_to_pixel { my ($self, $points, $unscale) = @_; my $result = []; foreach my $point (@$points) { $point = [ map unscale($_), @$point ] if $unscale; - push @$result, $self->point_to_pixel($point); + push @$result, $self->unscaled_point_to_pixel($point); } return $result; } @@ -288,11 +306,13 @@ sub point_to_model_units { my ($self, $point) = @_; my $canvas_height = $self->GetSize->GetHeight; - my $zero = $self->model_origin_to_pixel; - return [ - ($point->[X] - $zero->[X]) / $self->{scaling_factor}, - (($canvas_height - $point->[Y] - $zero->[Y]) / $self->{scaling_factor}), - ]; + my $zero = $self->{bed_origin}; + my $p = Slic3r::Point->new( + scale ($point->[X] - $zero->[X]) / $self->{scaling_factor}, + scale ($point->[Y] - $zero->[Y]) / $self->{scaling_factor}, + ); + use XXX; YYY $p->pp; + return $p; } 1; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 24f17016c..c4c80e1f9 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -146,6 +146,7 @@ sub duplicate { sub _arrange { my ($self, $sizes, $distance, $bb) = @_; + # we supply unscaled data to arrange() return Slic3r::Geometry::arrange( scalar(@$sizes), # number of parts max(map $_->x, @$sizes), # cell width diff --git a/xs/src/Print.cpp b/xs/src/Print.cpp index 3b38b8e94..67efad678 100644 --- a/xs/src/Print.cpp +++ b/xs/src/Print.cpp @@ -427,7 +427,7 @@ Print::invalidate_state_by_config_options(const std::vector } else if (*opt_key == "nozzle_diameter") { steps.insert(psInitExtruders); } else if (*opt_key == "avoid_crossing_perimeters" - || *opt_key == "bed_size" + || *opt_key == "bed_shape" || *opt_key == "bed_temperature" || *opt_key == "bridge_acceleration" || *opt_key == "bridge_fan_speed" From 998a4225de14e4f36e97f3fc864320732d854036 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 15:18:39 +0200 Subject: [PATCH 5/8] Finished implementation of bed_shape in plater --- lib/Slic3r/Config.pm | 9 ++------- lib/Slic3r/GUI/Plater.pm | 20 ++++++++++--------- lib/Slic3r/GUI/Plater/2D.pm | 11 ++++------- xs/src/BoundingBox.cpp | 7 +++++++ xs/src/BoundingBox.hpp | 7 ++++++- xs/src/Point.cpp | 12 ++++++++++++ xs/src/Point.hpp | 1 + xs/xsp/BoundingBox.xsp | 39 +++++++++++++++++++++++++++++++++---- xs/xsp/my.map | 4 ++++ xs/xsp/typemap.xspt | 3 +++ 10 files changed, 85 insertions(+), 28 deletions(-) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index 6693dcb18..b17c93106 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -9,7 +9,7 @@ use List::Util qw(first max); our @Ignore = qw(duplicate_x duplicate_y multiply_x multiply_y support_material_tool acceleration adjust_overhang_flow standby_temperature scale rotate duplicate duplicate_grid rotate scale duplicate_grid start_perimeters_at_concave_points start_perimeters_at_non_overhang - randomize_start seal_position); + randomize_start seal_position bed_size); our $Options = print_config_def(); @@ -23,7 +23,7 @@ $Options->{threads}{readonly} = !$Slic3r::have_threads; *{$opt_key} = sub { $_[0]->get($opt_key) }; } } -sub bed_size { [200,200] } + sub new_from_defaults { my $class = shift; my (@opt_keys) = @_; @@ -297,11 +297,6 @@ sub validate { die "Invalid value for --infill-every-layers\n" if $self->infill_every_layers !~ /^\d+$/ || $self->infill_every_layers < 1; - # --bed-size - die "Invalid value for --bed-size\n" - if !ref $self->bed_size - && (!$self->bed_size || $self->bed_size !~ /^\d+,\d+$/); - # --skirt-height die "Invalid value for --skirt-height\n" if $self->skirt_height < -1; # -1 means as tall as the object diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 8565e6668..1007c33fa 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -50,7 +50,7 @@ sub new { my ($parent) = @_; my $self = $class->SUPER::new($parent, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL); $self->{config} = Slic3r::Config->new_from_defaults(qw( - bed_size bed_shape print_center complete_objects extruder_clearance_radius skirts skirt_distance + bed_shape print_center complete_objects extruder_clearance_radius skirts skirt_distance )); $self->{model} = Slic3r::Model->new; $self->{print} = Slic3r::Print->new; @@ -132,7 +132,7 @@ sub new { } } - $self->{list} = Wx::ListView->new($self, -1, wxDefaultPosition, wxDefaultSize, wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN | wxTAB_TRAVERSAL | wxWANTS_CHARS); + $self->{list} = Wx::ListView->new($self, -1, wxDefaultPosition, [250,-1], wxLC_SINGLE_SEL | wxLC_REPORT | wxBORDER_SUNKEN | wxTAB_TRAVERSAL | wxWANTS_CHARS); $self->{list}->InsertColumn(0, "Name", wxLIST_FORMAT_LEFT, 145); $self->{list}->InsertColumn(1, "Copies", wxLIST_FORMAT_CENTER, 45); $self->{list}->InsertColumn(2, "Scale", wxLIST_FORMAT_CENTER, wxLIST_AUTOSIZE_USEHEADER); @@ -284,6 +284,7 @@ sub new { { my $box = Wx::StaticBox->new($self, -1, "Info"); $object_info_sizer = Wx::StaticBoxSizer->new($box, wxVERTICAL); + $object_info_sizer->SetMinSize([350,-1]); my $grid_sizer = Wx::FlexGridSizer->new(3, 4, 5, 5); $grid_sizer->SetFlexibleDirection(wxHORIZONTAL); $grid_sizer->AddGrowableCol(1, 1); @@ -299,14 +300,14 @@ sub new { ); while (my $field = shift @info) { my $label = shift @info; - my $text = Wx::StaticText->new($self, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + my $text = Wx::StaticText->new($box, -1, "$label:", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); $text->SetFont($Slic3r::GUI::small_font); $grid_sizer->Add($text, 0); - $self->{"object_info_$field"} = Wx::StaticText->new($self, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); + $self->{"object_info_$field"} = Wx::StaticText->new($box, -1, "", wxDefaultPosition, wxDefaultSize, wxALIGN_LEFT); $self->{"object_info_$field"}->SetFont($Slic3r::GUI::small_font); if ($field eq 'manifold') { - $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($self, -1, Wx::Bitmap->new("$Slic3r::var/error.png", wxBITMAP_TYPE_PNG)); + $self->{object_info_manifold_warning_icon} = Wx::StaticBitmap->new($box, -1, Wx::Bitmap->new("$Slic3r::var/error.png", wxBITMAP_TYPE_PNG)); $self->{object_info_manifold_warning_icon}->Hide; my $h_sizer = Wx::BoxSizer->new(wxHORIZONTAL); @@ -676,7 +677,7 @@ sub changescale { sub arrange { my $self = shift; - my $bb = Slic3r::Polygon->new_scale(@{$self->{config}->bed_shape})->bounding_box; + my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape); eval { $self->{model}->arrange_objects($self->GetFrame->config->min_object_distance, $bb); }; @@ -752,7 +753,8 @@ sub split_object { sub schedule_background_process { my ($self) = @_; - $self->{apply_config_timer}->Start(PROCESS_DELAY, 1); # 1 = one shot + $self->{apply_config_timer}->Start(PROCESS_DELAY, 1) # 1 = one shot + if defined $self->{apply_config_timer}; } sub async_apply_config { @@ -835,7 +837,7 @@ sub start_background_process { sub stop_background_process { my ($self) = @_; - $self->{apply_config_timer}->Stop; + $self->{apply_config_timer}->Stop if defined $self->{apply_config_timer}; $self->statusbar->SetCancelCallback(undef); $self->statusbar->StopBusy; $self->statusbar->SetStatusText(""); @@ -1141,7 +1143,7 @@ sub on_config_change { $self->Layout; } elsif ($self->{config}->has($opt_key)) { $self->{config}->set($opt_key, $value); - if ($opt_key eq 'bed_size') { + if ($opt_key eq 'bed_shape') { $self->{canvas}->update_bed_size; $self->update; } diff --git a/lib/Slic3r/GUI/Plater/2D.pm b/lib/Slic3r/GUI/Plater/2D.pm index e7e69d7eb..97ef5fb36 100644 --- a/lib/Slic3r/GUI/Plater/2D.pm +++ b/lib/Slic3r/GUI/Plater/2D.pm @@ -221,8 +221,8 @@ sub mouse_event { my $model_object = $self->{model}->objects->[$obj_idx]; $model_object->instances->[$instance_idx]->set_offset( Slic3r::Pointf->new( - unscale($pos->[X] - $self->{drag_start_pos}[X]), - unscale($pos->[Y] - $self->{drag_start_pos}[Y]), + unscale($point->[X] - $self->{drag_start_pos}[X]), + unscale($point->[Y] - $self->{drag_start_pos}[Y]), )); $model_object->update_bounding_box; $self->Refresh; @@ -305,14 +305,11 @@ sub scaled_points_to_pixel { sub point_to_model_units { my ($self, $point) = @_; - my $canvas_height = $self->GetSize->GetHeight; my $zero = $self->{bed_origin}; - my $p = Slic3r::Point->new( + return Slic3r::Point->new( scale ($point->[X] - $zero->[X]) / $self->{scaling_factor}, - scale ($point->[Y] - $zero->[Y]) / $self->{scaling_factor}, + scale ($zero->[Y] - $point->[Y]) / $self->{scaling_factor}, ); - use XXX; YYY $p->pp; - return $p; } 1; diff --git a/xs/src/BoundingBox.cpp b/xs/src/BoundingBox.cpp index 9975eb025..17a9f5644 100644 --- a/xs/src/BoundingBox.cpp +++ b/xs/src/BoundingBox.cpp @@ -18,6 +18,7 @@ BoundingBoxBase::BoundingBoxBase(const std::vector &poin } } template BoundingBoxBase::BoundingBoxBase(const std::vector &points); +template BoundingBoxBase::BoundingBoxBase(const std::vector &points); template BoundingBox3Base::BoundingBox3Base(const std::vector &points) @@ -65,6 +66,7 @@ BoundingBoxBase::scale(double factor) this->max.scale(factor); } template void BoundingBoxBase::scale(double factor); +template void BoundingBoxBase::scale(double factor); template void BoundingBoxBase::scale(double factor); template void @@ -76,6 +78,7 @@ BoundingBoxBase::merge(const PointClass &point) this->max.y = std::max(point.y, this->max.y); } template void BoundingBoxBase::merge(const Point &point); +template void BoundingBoxBase::merge(const Pointf &point); template void BoundingBoxBase::merge(const BoundingBoxBase &bb) @@ -86,6 +89,7 @@ BoundingBoxBase::merge(const BoundingBoxBase &bb) this->max.y = std::max(bb.max.y, this->max.y); } template void BoundingBoxBase::merge(const BoundingBoxBase &bb); +template void BoundingBoxBase::merge(const BoundingBoxBase &bb); template void BoundingBox3Base::merge(const PointClass &point) @@ -111,6 +115,7 @@ BoundingBoxBase::size() const return PointClass(this->max.x - this->min.x, this->max.y - this->min.y); } template Point BoundingBoxBase::size() const; +template Pointf BoundingBoxBase::size() const; template PointClass BoundingBox3Base::size() const @@ -126,6 +131,7 @@ BoundingBoxBase::translate(coordf_t x, coordf_t y) this->max.translate(x, y); } template void BoundingBoxBase::translate(coordf_t x, coordf_t y); +template void BoundingBoxBase::translate(coordf_t x, coordf_t y); template void BoundingBox3Base::translate(coordf_t x, coordf_t y, coordf_t z) @@ -144,6 +150,7 @@ BoundingBoxBase::center() const ); } template Point BoundingBoxBase::center() const; +template Pointf BoundingBoxBase::center() const; template PointClass BoundingBox3Base::center() const diff --git a/xs/src/BoundingBox.hpp b/xs/src/BoundingBox.hpp index 92c2d063f..371985ec5 100644 --- a/xs/src/BoundingBox.hpp +++ b/xs/src/BoundingBox.hpp @@ -53,10 +53,15 @@ class BoundingBox : public BoundingBoxBase }; /* -class BoundingBoxf : public BoundingBoxBase {}; class BoundingBox3 : public BoundingBox3Base {}; */ +class BoundingBoxf : public BoundingBoxBase { + public: + BoundingBoxf() {}; + BoundingBoxf(const std::vector &points) : BoundingBoxBase(points) {}; +}; + class BoundingBoxf3 : public BoundingBox3Base { public: BoundingBoxf3() {}; diff --git a/xs/src/Point.cpp b/xs/src/Point.cpp index a17d0cd39..1f3cd9eb9 100644 --- a/xs/src/Point.cpp +++ b/xs/src/Point.cpp @@ -293,6 +293,18 @@ Pointf::from_SV(SV* point_sv) this->y = SvNV(sv_y); return true; } + +void +Pointf::from_SV_check(SV* point_sv) +{ + if (sv_isobject(point_sv) && (SvTYPE(SvRV(point_sv)) == SVt_PVMG)) { + if (!sv_isa(point_sv, perl_class_name(this)) && !sv_isa(point_sv, perl_class_name_ref(this))) + CONFESS("Not a valid %s object (got %s)", perl_class_name(this), HvNAME(SvSTASH(SvRV(point_sv)))); + *this = *(Pointf*)SvIV((SV*)SvRV( point_sv )); + } else { + this->from_SV(point_sv); + } +} #endif void diff --git a/xs/src/Point.hpp b/xs/src/Point.hpp index 9ba665f55..44914eea0 100644 --- a/xs/src/Point.hpp +++ b/xs/src/Point.hpp @@ -74,6 +74,7 @@ class Pointf #ifdef SLIC3RXS bool from_SV(SV* point_sv); + void from_SV_check(SV* point_sv); SV* to_SV_pureperl() const; #endif }; diff --git a/xs/xsp/BoundingBox.xsp b/xs/xsp/BoundingBox.xsp index 8ae2653be..3154de194 100644 --- a/xs/xsp/BoundingBox.xsp +++ b/xs/xsp/BoundingBox.xsp @@ -20,10 +20,10 @@ Clone center(); Clone min_point() %code{% RETVAL = THIS->min; %}; Clone max_point() %code{% RETVAL = THIS->max; %}; - double x_min() %code{% RETVAL = THIS->min.x; %}; - double x_max() %code{% RETVAL = THIS->max.x; %}; - double y_min() %code{% RETVAL = THIS->min.y; %}; - double y_max() %code{% RETVAL = THIS->max.y; %}; + long x_min() %code{% RETVAL = THIS->min.x; %}; + long x_max() %code{% RETVAL = THIS->max.x; %}; + long y_min() %code{% RETVAL = THIS->min.y; %}; + long y_max() %code{% RETVAL = THIS->max.y; %}; %{ @@ -39,6 +39,37 @@ new_from_points(CLASS, points) %} }; +%name{Slic3r::Geometry::BoundingBoxf} class BoundingBoxf { + ~BoundingBoxf(); + Clone clone() + %code{% RETVAL = THIS; %}; + void merge(BoundingBoxf* bb) %code{% THIS->merge(*bb); %}; + void merge_point(Pointf* point) %code{% THIS->merge(*point); %}; + void scale(double factor); + void translate(double x, double y); + Clone size(); + Clone center(); + Clone min_point() %code{% RETVAL = THIS->min; %}; + Clone max_point() %code{% RETVAL = THIS->max; %}; + double x_min() %code{% RETVAL = THIS->min.x; %}; + double x_max() %code{% RETVAL = THIS->max.x; %}; + double y_min() %code{% RETVAL = THIS->min.y; %}; + double y_max() %code{% RETVAL = THIS->max.y; %}; + +%{ + +BoundingBoxf* +new_from_points(CLASS, points) + char* CLASS + Pointfs points + CODE: + RETVAL = new BoundingBoxf(points); + OUTPUT: + RETVAL + +%} +}; + %name{Slic3r::Geometry::BoundingBoxf3} class BoundingBoxf3 { ~BoundingBoxf3(); Clone clone() diff --git a/xs/xsp/my.map b/xs/xsp/my.map index e84a14403..27c85fe49 100644 --- a/xs/xsp/my.map +++ b/xs/xsp/my.map @@ -12,6 +12,10 @@ BoundingBox* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T +BoundingBoxf* O_OBJECT_SLIC3R +Ref O_OBJECT_SLIC3R_T +Clone O_OBJECT_SLIC3R_T + BoundingBoxf3* O_OBJECT_SLIC3R Ref O_OBJECT_SLIC3R_T Clone O_OBJECT_SLIC3R_T diff --git a/xs/xsp/typemap.xspt b/xs/xsp/typemap.xspt index d56f3fda0..a7959ad87 100644 --- a/xs/xsp/typemap.xspt +++ b/xs/xsp/typemap.xspt @@ -28,6 +28,9 @@ %typemap{BoundingBox*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; +%typemap{BoundingBoxf*}; +%typemap{Ref}{simple}; +%typemap{Clone}{simple}; %typemap{BoundingBoxf3*}; %typemap{Ref}{simple}; %typemap{Clone}{simple}; From db031a621045facbc916075ec7bddc16a857499e Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 20:11:52 +0200 Subject: [PATCH 6/8] Incomplete work for adapting wizard to bed_shape --- lib/Slic3r/GUI/BedShapeDialog.pm | 61 ++++++++++++++++++++++++-------- lib/Slic3r/GUI/ConfigWizard.pm | 38 +++++++++++++++----- lib/Slic3r/GUI/MainFrame.pm | 4 +-- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/lib/Slic3r/GUI/BedShapeDialog.pm b/lib/Slic3r/GUI/BedShapeDialog.pm index 2cc7998b7..7295d027d 100644 --- a/lib/Slic3r/GUI/BedShapeDialog.pm +++ b/lib/Slic3r/GUI/BedShapeDialog.pm @@ -9,6 +9,43 @@ use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL); use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_CHOICE); use base 'Wx::Dialog'; +sub new { + my $class = shift; + my ($parent, $default) = @_; + my $self = $class->SUPER::new($parent, -1, "Bed Shape", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + $self->{panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $default); + + my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); + $main_sizer->Add($panel, 1, wxEXPAND); + $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->{panel}->GetValue; +} + +package Slic3r::GUI::BedShapePanel; + +use List::Util qw(min max); +use Slic3r::Geometry qw(PI X Y unscale); +use Wx qw(:dialog :id :misc :sizer :choicebook wxTAB_TRAVERSAL); +use Wx::Event qw(EVT_CLOSE EVT_BUTTON EVT_CHOICE); +use base 'Wx::Panel'; + use constant SHAPE_RECTANGULAR => 0; use constant SHAPE_CIRCULAR => 1; use constant SHAPE_CUSTOM => 2; @@ -16,7 +53,9 @@ use constant SHAPE_CUSTOM => 2; sub new { my $class = shift; my ($parent, $default) = @_; - my $self = $class->SUPER::new($parent, -1, "Bed Shape", wxDefaultPosition, [350,700], wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + my $self = $class->SUPER::new($parent, -1); + + $self->on_change(undef); my $box = Wx::StaticBox->new($self, -1, "Shape"); my $sbsizer = Wx::StaticBoxSizer->new($box, wxVERTICAL); @@ -53,19 +92,7 @@ sub new { $top_sizer->Add($sbsizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); $top_sizer->Add($canvas, 1, wxEXPAND | wxALL, 0) if $canvas; - my $main_sizer = Wx::BoxSizer->new(wxVERTICAL); - $main_sizer->Add($top_sizer, 1, wxEXPAND); - $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; - }); + $self->SetSizerAndFit($top_sizer); $self->_set_shape($default); $self->_update_preview; @@ -73,6 +100,11 @@ sub new { return $self; } +sub on_change { + my ($self, $cb) = @_; + $self->{on_change} = $cb // sub {}; +} + sub _set_shape { my ($self, $points) = @_; @@ -131,6 +163,7 @@ sub _update_shape { ]; } + $self->{on_change}->(); $self->_update_preview; } diff --git a/lib/Slic3r/GUI/ConfigWizard.pm b/lib/Slic3r/GUI/ConfigWizard.pm index efa1117f1..a5fa9c1cc 100644 --- a/lib/Slic3r/GUI/ConfigWizard.pm +++ b/lib/Slic3r/GUI/ConfigWizard.pm @@ -5,6 +5,7 @@ use utf8; use Wx; use base 'Wx::Wizard'; +use Slic3r::Geometry qw(unscale); # adhere to various human interface guidelines our $wizard = 'Wizard'; @@ -52,9 +53,13 @@ sub run { # it would be cleaner to have these defined inside each page class, # in some event getting called before leaving the page { - # set print_center to centre of bed_size - my $bed_size = $self->{config}->bed_size; - $self->{config}->set('print_center', [$bed_size->[0]/2, $bed_size->[1]/2]); + # set print_center to center of bed_shape + { + my $bed_shape = $self->{config}->bed_shape; + my $polygon = Slic3r::Polygon->new_scale(@$bed_shape); + my $center = $polygon->centroid; + $self->{config}->set('print_center', [ map unscale($_), @$center ]); + } # set first_layer_height + layer_height based on nozzle_diameter my $nozzle = $self->{config}->nozzle_diameter; @@ -204,19 +209,24 @@ sub append_option { # populate repository with the factory default my $opt_key = $full_key; $opt_key =~ s/#.+//; - $self->GetParent->{config}->apply(Slic3r::Config->new_from_defaults($opt_key)); + $self->config->apply(Slic3r::Config->new_from_defaults($opt_key)); # draw the control my $optgroup = Slic3r::GUI::ConfigOptionsGroup->new( parent => $self, title => '', - config => $self->GetParent->{config}, + config => $self->config, options => [$full_key], full_labels => 1, ); $self->{vsizer}->Add($optgroup->sizer, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); } +sub append_panel { + my ($self, $panel) = @_; + $self->{vsizer}->Add($panel, 0, wxEXPAND | wxTOP | wxBOTTOM, 10); +} + sub set_previous_page { my $self = shift; my ($previous_page) = @_; @@ -253,6 +263,11 @@ sub build_index { $self->{index}->append_title($page->get_short_title) while ($page = $page->GetNext); } +sub config { + my ($self) = @_; + return $self->GetParent->{config}; +} + package Slic3r::GUI::ConfigWizard::Page::Welcome; use base 'Slic3r::GUI::ConfigWizard::Page'; @@ -290,9 +305,14 @@ sub new { my ($parent) = @_; my $self = $class->SUPER::new($parent, 'Bed Size'); - $self->append_text('Enter the size of your printers bed, then click Next.'); - $self->append_option('bed_size'); - + $self->append_text('Set the shape of your printer\'s bed, then click Next.'); + + $self->config->apply(Slic3r::Config->new_from_defaults('bed_shape')); + $self->{bed_shape_panel} = my $panel = Slic3r::GUI::BedShapePanel->new($self, $self->config->bed_shape); + $self->{bed_shape_panel}->on_change(sub { + $self->config->set('bed_shape', $self->{bed_shape_panel}->GetValue); + }); + $self->append_panel($self->{bed_shape_panel}); return $self; } @@ -304,7 +324,7 @@ sub new { my ($parent) = @_; my $self = $class->SUPER::new($parent, 'Nozzle Diameter'); - $self->append_text('Enter the diameter of your printers hot end nozzle, then click Next.'); + $self->append_text('Enter the diameter of your printer\'s hot end nozzle, then click Next.'); $self->append_option('nozzle_diameter#0'); return $self; diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 49c154068..cb11e2f1f 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -551,13 +551,13 @@ sub config_wizard { my $self = shift; return unless $self->check_unsaved_changes; - if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) { + if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) {use XXX; YYY $config->bed_shape; if ($self->{mode} eq 'expert') { for my $tab (values %{$self->{options_tabs}}) { $tab->select_default_preset; } } - $self->load_config($config); + $self->load_config($config);use XXX; YYY $self->config->bed_shape; if ($self->{mode} eq 'expert') { for my $tab (values %{$self->{options_tabs}}) { $tab->save_preset('My Settings'); From d6d796fdd48b3f0561a66853cb51c6ea2b3d3310 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 22:45:13 +0200 Subject: [PATCH 7/8] Finished implementing bed shape configuration within wizard --- lib/Slic3r/GUI/MainFrame.pm | 4 ++-- lib/Slic3r/GUI/OptionsGroup.pm | 22 ++++++++++++++++++---- lib/Slic3r/GUI/Tab.pm | 1 + 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index cb11e2f1f..49c154068 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -551,13 +551,13 @@ sub config_wizard { my $self = shift; return unless $self->check_unsaved_changes; - if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) {use XXX; YYY $config->bed_shape; + if (my $config = Slic3r::GUI::ConfigWizard->new($self)->run) { if ($self->{mode} eq 'expert') { for my $tab (values %{$self->{options_tabs}}) { $tab->select_default_preset; } } - $self->load_config($config);use XXX; YYY $self->config->bed_shape; + $self->load_config($config); if ($self->{mode} eq 'expert') { for my $tab (values %{$self->{options_tabs}}) { $tab->save_preset('My Settings'); diff --git a/lib/Slic3r/GUI/OptionsGroup.pm b/lib/Slic3r/GUI/OptionsGroup.pm index 2c9089a28..9d2c8f5c8 100644 --- a/lib/Slic3r/GUI/OptionsGroup.pm +++ b/lib/Slic3r/GUI/OptionsGroup.pm @@ -80,6 +80,13 @@ sub BUILD { $self->sizer->Add($grid_sizer, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 5); foreach my $line (@{$self->lines}) { + # build default callbacks in case we don't call _build_line() below + foreach my $opt_key (@{$line->{options}}) { + my $opt = first { $_->{opt_key} eq $opt_key } @{$self->options}; + $self->_setters->{$opt_key} //= sub {}; + $self->_triggers->{$opt_key} = $opt->{on_change} || sub { return 1 }; + } + if ($line->{sizer}) { $self->sizer->Add($line->{sizer}, 0, wxEXPAND | wxALL, &Wx::wxMAC ? 0 : 15); } elsif ($line->{widget} && $line->{full_width}) { @@ -143,7 +150,7 @@ sub _build_line { my @field_labels = (); foreach my $opt_key (@{$line->{options}}) { my $opt = first { $_->{opt_key} eq $opt_key } @{$self->options}; - push @fields, $self->_build_field($opt); + push @fields, $self->_build_field($opt) unless $line->{widget}; push @field_labels, $opt->{label}; } if (@fields > 1 || $line->{widget} || $line->{sidetext}) { @@ -175,7 +182,6 @@ sub _build_field { my ($opt) = @_; my $opt_key = $opt->{opt_key}; - $self->_triggers->{$opt_key} = $opt->{on_change} || sub { return 1 }; my $on_kill_focus = sub { my ($s, $event) = @_; @@ -369,6 +375,7 @@ has '+ignore_on_change_return' => (is => 'ro', default => sub { 0 }); sub _trigger_options { my $self = shift; + $self->SUPER::_trigger_options; @{$self->options} = map { my $opt = $_; if (ref $opt ne 'HASH') { @@ -414,10 +421,17 @@ sub set_value { if ($key eq $opt_key) { $self->config->set($key, $value); $self->SUPER::set_value($full_key, $self->_get_config($key, $index)); - $changed = 1; + return 1; } } - return $changed; + + # if we're here, we know this option but we found no setter, so we just propagate it + if ($self->config->has($opt_key)) { + $self->config->set($opt_key, $value); + $self->SUPER::set_value($opt_key, $value); + return 1; + } + return 0; } sub on_kill_focus { diff --git a/lib/Slic3r/GUI/Tab.pm b/lib/Slic3r/GUI/Tab.pm index a4e02b15d..56e052ff7 100644 --- a/lib/Slic3r/GUI/Tab.pm +++ b/lib/Slic3r/GUI/Tab.pm @@ -709,6 +709,7 @@ sub build { { label => 'Bed shape', widget => $bed_shape_widget, + options => ['bed_shape'], }, Slic3r::GUI::OptionsGroup->single_option_line('print_center'), Slic3r::GUI::OptionsGroup->single_option_line('z_offset'), From ba37a8fb790a774c751ee802229d30151773d192 Mon Sep 17 00:00:00 2001 From: Alessandro Ranellucci Date: Mon, 16 Jun 2014 22:56:28 +0200 Subject: [PATCH 8/8] Handle legacy configs --- lib/Slic3r/Config.pm | 7 ++++++- lib/Slic3r/GUI.pm | 5 +++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/Slic3r/Config.pm b/lib/Slic3r/Config.pm index b17c93106..2f37b9f67 100644 --- a/lib/Slic3r/Config.pm +++ b/lib/Slic3r/Config.pm @@ -124,7 +124,6 @@ sub _handle_legacy { my ($opt_key, $value) = @_; # handle legacy options - return () if first { $_ eq $opt_key } @Ignore; if ($opt_key =~ /^(extrusion_width|bottom_layer_speed|first_layer_height)_ratio$/) { $opt_key = $1; $opt_key =~ s/^bottom_layer_speed$/first_layer_speed/; @@ -145,6 +144,12 @@ sub _handle_legacy { $opt_key = 'seam_position'; $value = 'random'; } + if ($opt_key eq 'bed_size' && $value) { + $opt_key = 'bed_shape'; + my ($x, $y) = split /,/, $value; + $value = "0x0,${x}x0,${x}x${y},0x${y}"; + } + return () if first { $_ eq $opt_key } @Ignore; # For historical reasons, the world's full of configs having these very low values; # to avoid unexpected behavior we need to ignore them. Banning these two hard-coded diff --git a/lib/Slic3r/GUI.pm b/lib/Slic3r/GUI.pm index 29c6708a6..84c4e6c1a 100644 --- a/lib/Slic3r/GUI.pm +++ b/lib/Slic3r/GUI.pm @@ -112,6 +112,11 @@ sub OnInit { . "your support material settings to the factory defaults and start from " . "those. Enjoy and provide feedback!", "Support Material"); } + if (!defined $last_version || $last_version =~ /^(?:0|1\.[01])\./) { + show_info($self->{mainframe}, "Hello! In this version a new Bed Shape option was " + . "added. If the bed placement in the plater preview screen looks wrong, go " + . "to Print Settings and click the \"Set\" button next to \"Bed Shape\".", "Bed Shape"); + } } $self->{mainframe}->config_wizard if $run_wizard;