Rotation around X and Y axes from plater

This commit is contained in:
Alessandro Ranellucci 2014-06-14 20:52:21 +02:00
parent 51cf78534c
commit ec7bb40da9
4 changed files with 51 additions and 21 deletions

View File

@ -4,6 +4,7 @@ use warnings;
use utf8;
use List::Util qw(min);
use Slic3r::Geometry qw(X Y Z);
use Wx qw(:frame :bitmap :id :misc :notebook :panel :sizer :menu :dialog :filedialog
:font :icon wxTheApp);
use Wx::Event qw(EVT_CLOSE EVT_MENU);
@ -192,9 +193,19 @@ sub _init_menubar {
$self->_append_menu_item($self->{object_menu}, "Rotate 45° counter-clockwise", 'Rotate the selected object by 45° counter-clockwise', sub {
$plater->rotate(+45);
});
$self->_append_menu_item($self->{object_menu}, "Rotate…", 'Rotate the selected object by an arbitrary angle around Z axis', sub {
$plater->rotate(undef);
my $rotateMenu = Wx::Menu->new;
$self->{object_menu}->AppendSubMenu($rotateMenu, "Rotate…", 'Rotate the selected object by an arbitrary angle');
$self->_append_menu_item($rotateMenu, "Around X axis…", 'Rotate the selected object by an arbitrary angle around X axis', sub {
$plater->rotate(undef, X);
});
$self->_append_menu_item($rotateMenu, "Around Y axis…", 'Rotate the selected object by an arbitrary angle around Y axis', sub {
$plater->rotate(undef, Y);
});
$self->_append_menu_item($rotateMenu, "Around Z axis…", 'Rotate the selected object by an arbitrary angle around Z axis', sub {
$plater->rotate(undef, Z);
});
$self->_append_menu_item($self->{object_menu}, "Scale…", 'Scale the selected object by an arbitrary factor', sub {
$plater->changescale;
});

View File

@ -5,7 +5,7 @@ use utf8;
use File::Basename qw(basename dirname);
use List::Util qw(sum first);
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale);
use Slic3r::Geometry qw(X Y Z MIN MAX scale unscale deg2rad);
use threads::shared qw(shared_clone);
use Thread::Semaphore;
use Wx qw(:button :cursor :dialog :filedialog :keycode :icon :font :id :listctrl :misc
@ -25,7 +25,6 @@ use constant TB_MORE => &Wx::NewId;
use constant TB_FEWER => &Wx::NewId;
use constant TB_45CW => &Wx::NewId;
use constant TB_45CCW => &Wx::NewId;
use constant TB_ROTATE => &Wx::NewId;
use constant TB_SCALE => &Wx::NewId;
use constant TB_SPLIT => &Wx::NewId;
use constant TB_VIEW => &Wx::NewId;
@ -96,7 +95,6 @@ sub new {
$self->{htoolbar}->AddSeparator;
$self->{htoolbar}->AddTool(TB_45CCW, "45° ccw", Wx::Bitmap->new("$Slic3r::var/arrow_rotate_anticlockwise.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_45CW, "45° cw", Wx::Bitmap->new("$Slic3r::var/arrow_rotate_clockwise.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_ROTATE, "Rotate…", Wx::Bitmap->new("$Slic3r::var/arrow_rotate_clockwise.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_SCALE, "Scale…", Wx::Bitmap->new("$Slic3r::var/arrow_out.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddTool(TB_SPLIT, "Split", Wx::Bitmap->new("$Slic3r::var/shape_ungroup.png", wxBITMAP_TYPE_PNG), '');
$self->{htoolbar}->AddSeparator;
@ -160,7 +158,6 @@ sub new {
decrease delete.png
rotate45cw arrow_rotate_clockwise.png
rotate45ccw arrow_rotate_anticlockwise.png
rotate arrow_rotate_clockwise.png
changescale arrow_out.png
split shape_ungroup.png
view package.png
@ -187,7 +184,6 @@ sub new {
EVT_TOOL($self, TB_FEWER, \&decrease);
EVT_TOOL($self, TB_45CW, sub { $_[0]->rotate(-45) });
EVT_TOOL($self, TB_45CCW, sub { $_[0]->rotate(45) });
EVT_TOOL($self, TB_ROTATE, sub { $_[0]->rotate(undef) });
EVT_TOOL($self, TB_SCALE, \&changescale);
EVT_TOOL($self, TB_SPLIT, \&split_object);
EVT_TOOL($self, TB_VIEW, sub { $_[0]->object_cut_dialog });
@ -202,7 +198,6 @@ sub new {
EVT_BUTTON($self, $self->{btn_rotate45cw}, sub { $_[0]->rotate(-45) });
EVT_BUTTON($self, $self->{btn_rotate45ccw}, sub { $_[0]->rotate(45) });
EVT_BUTTON($self, $self->{btn_changescale}, \&changescale);
EVT_BUTTON($self, $self->{btn_rotate}, sub { $_[0]->rotate(undef) });
EVT_BUTTON($self, $self->{btn_split}, \&split_object);
EVT_BUTTON($self, $self->{btn_view}, sub { $_[0]->object_cut_dialog });
EVT_BUTTON($self, $self->{btn_settings}, sub { $_[0]->object_settings_dialog });
@ -555,9 +550,13 @@ sub decrease {
sub rotate {
my $self = shift;
my ($angle) = @_;
my ($angle, $axis) = @_;
$axis //= Z;
my ($obj_idx, $object) = $self->selected_object;
return if !defined $obj_idx;
my $model_object = $self->{model}->objects->[$obj_idx];
my $model_instance = $model_object->instances->[0];
@ -565,14 +564,27 @@ sub rotate {
return if !$object->thumbnail;
if (!defined $angle) {
$angle = Wx::GetNumberFromUser("", "Enter the rotation angle:", "Rotate", $model_instance->rotation, -364, 364, $self);
my $axis_name = $axis == X ? 'X' : $axis == Y ? 'Y' : 'Z';
$angle = Wx::GetNumberFromUser("", "Enter the rotation angle:", "Rotate around $axis_name axis", $model_instance->rotation, -364, 364, $self);
return if !$angle || $angle == -1;
$angle = 0 - $angle; # rotate clockwise (be consistent with button icon)
}
{
my $new_angle = $model_instance->rotation + $angle;
$_->set_rotation($new_angle) for @{ $model_object->instances };
if ($axis == Z) {
my $new_angle = $model_instance->rotation + $angle;
$_->set_rotation($new_angle) for @{ $model_object->instances };
$object->transform_thumbnail($self->{model}, $obj_idx);
} else {
# rotation around X and Y needs to be performed on mesh
# so we first apply any Z rotation
if ($model_object->instances->[0]->rotation != 0) {
$model_object->rotate(deg2rad($model_object->instances->[0]->rotation), Z);
$_->set_rotation(0) for @{ $model_object->instances };
}
$model_object->rotate(deg2rad($angle), $axis);
$self->make_thumbnail($obj_idx);
}
$model_object->update_bounding_box;
# update print and start background processing
@ -580,7 +592,6 @@ sub rotate {
$self->{print}->add_model_object($model_object, $obj_idx);
$self->schedule_background_process;
$object->transform_thumbnail($self->{model}, $obj_idx);
}
$self->selection_changed; # refresh info (size etc.)
$self->update;
@ -1210,11 +1221,11 @@ sub selection_changed {
my $method = $have_sel ? 'Enable' : 'Disable';
$self->{"btn_$_"}->$method
for grep $self->{"btn_$_"}, qw(remove increase decrease rotate45cw rotate45ccw rotate changescale split view settings);
for grep $self->{"btn_$_"}, qw(remove increase decrease rotate45cw rotate45ccw changescale split view settings);
if ($self->{htoolbar}) {
$self->{htoolbar}->EnableTool($_, $have_sel)
for (TB_REMOVE, TB_MORE, TB_FEWER, TB_45CW, TB_45CCW, TB_ROTATE, TB_SCALE, TB_SPLIT, TB_VIEW, TB_SETTINGS);
for (TB_REMOVE, TB_MORE, TB_FEWER, TB_45CW, TB_45CCW, TB_SCALE, TB_SPLIT, TB_VIEW, TB_SETTINGS);
}
if ($self->{object_info_size}) { # have we already loaded the info pane?
@ -1338,8 +1349,10 @@ has 'selected' => (is => 'rw', default => sub { 0 });
sub make_thumbnail {
my ($self, $model, $obj_idx) = @_;
my $mesh = $model->objects->[$obj_idx]->raw_mesh;
# make method idempotent
$self->thumbnail->clear;
my $mesh = $model->objects->[$obj_idx]->raw_mesh;
if ($mesh->facets_count <= 5000) {
# remove polygons with area <= 1mm
my $area_threshold = Slic3r::Geometry::scale 1;

View File

@ -3,7 +3,7 @@ use strict;
use warnings;
use utf8;
use Slic3r::Geometry qw(PI);
use Slic3r::Geometry qw(PI X);
use Wx qw(:dialog :id :misc :sizer wxTAB_TRAVERSAL);
use Wx::Event qw(EVT_CLOSE EVT_BUTTON);
use base 'Wx::Dialog';
@ -133,7 +133,7 @@ sub perform_cut {
if ($self->{cut_options}{keep_lower} && defined $lower_object) {
push @{$self->{new_model_objects}}, $lower_object;
if ($self->{cut_options}{rotate_lower}) {
$lower_object->rotate_x(PI);
$lower_object->rotate(PI, X);
}
}

View File

@ -463,13 +463,19 @@ sub translate {
$self->_bounding_box->translate(@shift) if defined $self->_bounding_box;
}
sub rotate_x {
my ($self, $angle) = @_;
sub rotate {
my ($self, $angle, $axis) = @_;
# we accept angle in radians but mesh currently uses degrees
$angle = rad2deg($angle);
$_->mesh->rotate_x($angle) for @{$self->volumes};
if ($axis == X) {
$_->mesh->rotate_x($angle) for @{$self->volumes};
} elsif ($axis == Y) {
$_->mesh->rotate_y($angle) for @{$self->volumes};
} elsif ($axis == Z) {
$_->mesh->rotate_z($angle) for @{$self->volumes};
}
$self->invalidate_bounding_box;
}