diff --git a/lib/Slic3r/GUI/MainFrame.pm b/lib/Slic3r/GUI/MainFrame.pm index 058facbb4..86e4e18c6 100644 --- a/lib/Slic3r/GUI/MainFrame.pm +++ b/lib/Slic3r/GUI/MainFrame.pm @@ -206,6 +206,18 @@ sub _init_menubar { $plater->rotate(undef, Z); }); + my $flipMenu = Wx::Menu->new; + $self->{object_menu}->AppendSubMenu($flipMenu, "Flip…", 'Mirror the selected object'); + $self->_append_menu_item($flipMenu, "Along X axis…", 'Mirror the selected object along the X axis', sub { + $plater->flip(X); + }); + $self->_append_menu_item($flipMenu, "Along Y axis…", 'Mirror the selected object along the Y axis', sub { + $plater->flip(Y); + }); + $self->_append_menu_item($flipMenu, "Along Z axis…", 'Mirror the selected object along the Z axis', sub { + $plater->flip(Z); + }); + $self->_append_menu_item($self->{object_menu}, "Scale…", 'Scale the selected object by an arbitrary factor', sub { $plater->changescale; }); diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index 82497ef1f..322929d80 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -578,8 +578,8 @@ sub rotate { } 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); + if ($model_instance->rotation != 0) { + $model_object->rotate(deg2rad($model_instance->rotation), Z); $_->set_rotation(0) for @{ $model_object->instances }; } $model_object->rotate(deg2rad($angle), $axis); @@ -598,6 +598,35 @@ sub rotate { $self->{canvas}->Refresh; } +sub flip { + my ($self, $axis) = @_; + + 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]; + + # apply Z rotation before flipping + if ($model_instance->rotation != 0) { + $model_object->rotate(deg2rad($model_instance->rotation), Z); + $_->set_rotation(0) for @{ $model_object->instances }; + } + + $model_object->flip($axis); + $model_object->update_bounding_box; + $self->make_thumbnail($obj_idx); + + # update print and start background processing + $self->stop_background_process; + $self->{print}->add_model_object($model_object, $obj_idx); + $self->schedule_background_process; + + $self->selection_changed; # refresh info (size etc.) + $self->update; + $self->{canvas}->Refresh; +} + sub changescale { my $self = shift; diff --git a/lib/Slic3r/Model.pm b/lib/Slic3r/Model.pm index 50393b0d5..3a0d60547 100644 --- a/lib/Slic3r/Model.pm +++ b/lib/Slic3r/Model.pm @@ -479,6 +479,19 @@ sub rotate { $self->invalidate_bounding_box; } +sub flip { + my ($self, $axis) = @_; + + if ($axis == X) { + $_->mesh->flip_x for @{$self->volumes}; + } elsif ($axis == Y) { + $_->mesh->flip_y for @{$self->volumes}; + } elsif ($axis == Z) { + $_->mesh->flip_z for @{$self->volumes}; + } + $self->invalidate_bounding_box; +} + sub materials_count { my $self = shift; diff --git a/xs/src/TriangleMesh.cpp b/xs/src/TriangleMesh.cpp index dc478322f..77b11c5f8 100644 --- a/xs/src/TriangleMesh.cpp +++ b/xs/src/TriangleMesh.cpp @@ -193,6 +193,21 @@ void TriangleMesh::rotate_z(float angle) stl_rotate_z(&(this->stl), angle); } +void TriangleMesh::flip_x() +{ + stl_mirror_yz(&this->stl); +} + +void TriangleMesh::flip_y() +{ + stl_mirror_xz(&this->stl); +} + +void TriangleMesh::flip_z() +{ + stl_mirror_xy(&this->stl); +} + void TriangleMesh::align_to_origin() { this->translate( diff --git a/xs/src/TriangleMesh.hpp b/xs/src/TriangleMesh.hpp index 0d39453e1..b16f867eb 100644 --- a/xs/src/TriangleMesh.hpp +++ b/xs/src/TriangleMesh.hpp @@ -34,6 +34,9 @@ class TriangleMesh void rotate_x(float angle); void rotate_y(float angle); void rotate_z(float angle); + void flip_x(); + void flip_y(); + void flip_z(); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; diff --git a/xs/src/admesh/util.c b/xs/src/admesh/util.c index a1a90fb19..eec705b9a 100644 --- a/xs/src/admesh/util.c +++ b/xs/src/admesh/util.c @@ -295,6 +295,9 @@ stl_mirror_xy(stl_file *stl) stl->stats.max.z = temp_size; stl->stats.min.z *= -1.0; stl->stats.max.z *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats + } void @@ -316,6 +319,8 @@ stl_mirror_yz(stl_file *stl) stl->stats.max.x = temp_size; stl->stats.min.x *= -1.0; stl->stats.max.x *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats } void @@ -337,6 +342,8 @@ stl_mirror_xz(stl_file *stl) stl->stats.max.y = temp_size; stl->stats.min.y *= -1.0; stl->stats.max.y *= -1.0; + stl_reverse_all_facets(stl); + stl->stats.facets_reversed -= stl->stats.number_of_facets; // for not altering stats } static float get_volume(stl_file *stl) diff --git a/xs/xsp/TriangleMesh.xsp b/xs/xsp/TriangleMesh.xsp index 3338d971c..5ac5f4349 100644 --- a/xs/xsp/TriangleMesh.xsp +++ b/xs/xsp/TriangleMesh.xsp @@ -23,6 +23,9 @@ void rotate_x(float angle); void rotate_y(float angle); void rotate_z(float angle); + void flip_x(); + void flip_y(); + void flip_z(); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split();