Merge branch 'bedshape'
This commit is contained in:
commit
7cc0bce97d
20 changed files with 497 additions and 130 deletions
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -297,11 +302,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
|
||||
|
|
|
@ -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;
|
||||
|
@ -111,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;
|
||||
|
||||
|
|
200
lib/Slic3r/GUI/BedShapeDialog.pm
Normal file
200
lib/Slic3r/GUI/BedShapeDialog.pm
Normal file
|
@ -0,0 +1,200 @@
|
|||
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';
|
||||
|
||||
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;
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my ($parent, $default) = @_;
|
||||
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);
|
||||
|
||||
# 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;
|
||||
|
||||
$self->SetSizerAndFit($top_sizer);
|
||||
|
||||
$self->_set_shape($default);
|
||||
$self->_update_preview;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub on_change {
|
||||
my ($self, $cb) = @_;
|
||||
$self->{on_change} = $cb // sub {};
|
||||
}
|
||||
|
||||
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->{on_change}->();
|
||||
$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;
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
@ -77,11 +80,18 @@ 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}) {
|
||||
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);
|
||||
}
|
||||
|
@ -140,10 +150,10 @@ 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->{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 +163,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);
|
||||
|
@ -169,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) = @_;
|
||||
|
@ -363,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') {
|
||||
|
@ -408,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 {
|
||||
|
@ -479,26 +499,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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -51,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_shape print_center complete_objects extruder_clearance_radius skirts skirt_distance
|
||||
));
|
||||
$self->{model} = Slic3r::Model->new;
|
||||
$self->{print} = Slic3r::Print->new;
|
||||
|
@ -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);
|
||||
|
@ -133,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);
|
||||
|
@ -285,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);
|
||||
|
@ -300,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);
|
||||
|
@ -334,8 +334,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};
|
||||
|
@ -677,12 +677,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(CANVAS_SIZE) }),
|
||||
]);
|
||||
|
||||
my $bb = Slic3r::Geometry::BoundingBoxf->new_from_points($self->{config}->bed_shape);
|
||||
eval {
|
||||
$self->{model}->arrange_objects($self->GetFrame->config->min_object_distance, $bb);
|
||||
};
|
||||
|
@ -758,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 {
|
||||
|
@ -841,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("");
|
||||
|
@ -1147,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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
@ -217,14 +221,14 @@ 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;
|
||||
} 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;
|
||||
}
|
||||
|
@ -287,12 +305,11 @@ sub points_to_pixel {
|
|||
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};
|
||||
return Slic3r::Point->new(
|
||||
scale ($point->[X] - $zero->[X]) / $self->{scaling_factor},
|
||||
scale ($zero->[Y] - $point->[Y]) / $self->{scaling_factor},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -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,43 @@ 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,
|
||||
options => ['bed_shape'],
|
||||
},
|
||||
Slic3r::GUI::OptionsGroup->single_option_line('print_center'),
|
||||
Slic3r::GUI::OptionsGroup->single_option_line('z_offset'),
|
||||
],
|
||||
},
|
||||
{
|
||||
title => 'Firmware',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -18,6 +18,7 @@ BoundingBoxBase<PointClass>::BoundingBoxBase(const std::vector<PointClass> &poin
|
|||
}
|
||||
}
|
||||
template BoundingBoxBase<Point>::BoundingBoxBase(const std::vector<Point> &points);
|
||||
template BoundingBoxBase<Pointf>::BoundingBoxBase(const std::vector<Pointf> &points);
|
||||
|
||||
template <class PointClass>
|
||||
BoundingBox3Base<PointClass>::BoundingBox3Base(const std::vector<PointClass> &points)
|
||||
|
@ -65,6 +66,7 @@ BoundingBoxBase<PointClass>::scale(double factor)
|
|||
this->max.scale(factor);
|
||||
}
|
||||
template void BoundingBoxBase<Point>::scale(double factor);
|
||||
template void BoundingBoxBase<Pointf>::scale(double factor);
|
||||
template void BoundingBoxBase<Pointf3>::scale(double factor);
|
||||
|
||||
template <class PointClass> void
|
||||
|
@ -76,6 +78,7 @@ BoundingBoxBase<PointClass>::merge(const PointClass &point)
|
|||
this->max.y = std::max(point.y, this->max.y);
|
||||
}
|
||||
template void BoundingBoxBase<Point>::merge(const Point &point);
|
||||
template void BoundingBoxBase<Pointf>::merge(const Pointf &point);
|
||||
|
||||
template <class PointClass> void
|
||||
BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
||||
|
@ -86,6 +89,7 @@ BoundingBoxBase<PointClass>::merge(const BoundingBoxBase<PointClass> &bb)
|
|||
this->max.y = std::max(bb.max.y, this->max.y);
|
||||
}
|
||||
template void BoundingBoxBase<Point>::merge(const BoundingBoxBase<Point> &bb);
|
||||
template void BoundingBoxBase<Pointf>::merge(const BoundingBoxBase<Pointf> &bb);
|
||||
|
||||
template <class PointClass> void
|
||||
BoundingBox3Base<PointClass>::merge(const PointClass &point)
|
||||
|
@ -111,6 +115,7 @@ BoundingBoxBase<PointClass>::size() const
|
|||
return PointClass(this->max.x - this->min.x, this->max.y - this->min.y);
|
||||
}
|
||||
template Point BoundingBoxBase<Point>::size() const;
|
||||
template Pointf BoundingBoxBase<Pointf>::size() const;
|
||||
|
||||
template <class PointClass> PointClass
|
||||
BoundingBox3Base<PointClass>::size() const
|
||||
|
@ -126,6 +131,7 @@ BoundingBoxBase<PointClass>::translate(coordf_t x, coordf_t y)
|
|||
this->max.translate(x, y);
|
||||
}
|
||||
template void BoundingBoxBase<Point>::translate(coordf_t x, coordf_t y);
|
||||
template void BoundingBoxBase<Pointf>::translate(coordf_t x, coordf_t y);
|
||||
|
||||
template <class PointClass> void
|
||||
BoundingBox3Base<PointClass>::translate(coordf_t x, coordf_t y, coordf_t z)
|
||||
|
@ -144,6 +150,7 @@ BoundingBoxBase<PointClass>::center() const
|
|||
);
|
||||
}
|
||||
template Point BoundingBoxBase<Point>::center() const;
|
||||
template Pointf BoundingBoxBase<Pointf>::center() const;
|
||||
|
||||
template <class PointClass> PointClass
|
||||
BoundingBox3Base<PointClass>::center() const
|
||||
|
|
|
@ -53,10 +53,15 @@ class BoundingBox : public BoundingBoxBase<Point>
|
|||
};
|
||||
|
||||
/*
|
||||
class BoundingBoxf : public BoundingBoxBase<Pointf> {};
|
||||
class BoundingBox3 : public BoundingBox3Base<Point3> {};
|
||||
*/
|
||||
|
||||
class BoundingBoxf : public BoundingBoxBase<Pointf> {
|
||||
public:
|
||||
BoundingBoxf() {};
|
||||
BoundingBoxf(const std::vector<Pointf> &points) : BoundingBoxBase<Pointf>(points) {};
|
||||
};
|
||||
|
||||
class BoundingBoxf3 : public BoundingBox3Base<Pointf3> {
|
||||
public:
|
||||
BoundingBoxf3() {};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -427,7 +427,7 @@ Print::invalidate_state_by_config_options(const std::vector<t_config_option_key>
|
|||
} 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"
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
Clone<Point> center();
|
||||
Clone<Point> min_point() %code{% RETVAL = THIS->min; %};
|
||||
Clone<Point> 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<BoundingBoxf> 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<Pointf> size();
|
||||
Clone<Pointf> center();
|
||||
Clone<Pointf> min_point() %code{% RETVAL = THIS->min; %};
|
||||
Clone<Pointf> 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<BoundingBoxf3> clone()
|
||||
|
|
|
@ -12,6 +12,10 @@ BoundingBox* O_OBJECT_SLIC3R
|
|||
Ref<BoundingBox> O_OBJECT_SLIC3R_T
|
||||
Clone<BoundingBox> O_OBJECT_SLIC3R_T
|
||||
|
||||
BoundingBoxf* O_OBJECT_SLIC3R
|
||||
Ref<BoundingBoxf> O_OBJECT_SLIC3R_T
|
||||
Clone<BoundingBoxf> O_OBJECT_SLIC3R_T
|
||||
|
||||
BoundingBoxf3* O_OBJECT_SLIC3R
|
||||
Ref<BoundingBoxf3> O_OBJECT_SLIC3R_T
|
||||
Clone<BoundingBoxf3> O_OBJECT_SLIC3R_T
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
%typemap{BoundingBox*};
|
||||
%typemap{Ref<BoundingBox>}{simple};
|
||||
%typemap{Clone<BoundingBox>}{simple};
|
||||
%typemap{BoundingBoxf*};
|
||||
%typemap{Ref<BoundingBoxf>}{simple};
|
||||
%typemap{Clone<BoundingBoxf>}{simple};
|
||||
%typemap{BoundingBoxf3*};
|
||||
%typemap{Ref<BoundingBoxf3>}{simple};
|
||||
%typemap{Clone<BoundingBoxf3>}{simple};
|
||||
|
|
Loading…
Reference in a new issue