From 07274589a35948e135ccb2eed59626a41c61444b Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Thu, 20 Sep 2018 15:00:40 +0200 Subject: [PATCH] 1st installment of ModelInstance 3D rotation components --- lib/Slic3r/GUI/Plater.pm | 54 ++++++++++++++++ xs/src/libslic3r/Format/3mf.cpp | 8 +++ xs/src/libslic3r/Format/AMF.cpp | 64 ++++++++++++++++++- xs/src/libslic3r/Format/PRUS.cpp | 16 ++++- xs/src/libslic3r/Model.cpp | 36 +++++++++++ xs/src/libslic3r/Model.hpp | 19 ++++++ xs/src/libslic3r/ModelArrange.hpp | 12 +++- xs/src/libslic3r/Technologies.hpp | 2 + xs/src/slic3r/GUI/3DScene.cpp | 70 ++++++++++++++++++++- xs/src/slic3r/GUI/3DScene.hpp | 14 ++++- xs/src/slic3r/GUI/GLCanvas3D.cpp | 82 ++++++++++++++++++++++++- xs/src/slic3r/GUI/GLCanvas3D.hpp | 21 ++++++- xs/src/slic3r/GUI/GLCanvas3DManager.cpp | 16 +++++ xs/src/slic3r/GUI/GLCanvas3DManager.hpp | 5 ++ xs/src/slic3r/GUI/GLGizmo.cpp | 58 ++++++++++++++++- xs/src/slic3r/GUI/GLGizmo.hpp | 23 +++++++ xs/src/slic3r/GUI/GUI_ObjectParts.cpp | 14 +++++ xs/src/slic3r/GUI/GUI_ObjectParts.hpp | 3 + xs/xsp/GUI_3DScene.xsp | 14 +++++ xs/xsp/Model.xsp | 14 +++++ 20 files changed, 533 insertions(+), 12 deletions(-) diff --git a/lib/Slic3r/GUI/Plater.pm b/lib/Slic3r/GUI/Plater.pm index c4c7224fb..525cc7931 100644 --- a/lib/Slic3r/GUI/Plater.pm +++ b/lib/Slic3r/GUI/Plater.pm @@ -150,12 +150,64 @@ sub new { $self->rotate(rad2deg($angle), Z, 'absolute'); }; + # callback to react to gizmo rotate + my $on_gizmo_rotate_3D = sub { + my ($angle_x, $angle_y, $angle_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]; + + $self->stop_background_process; + + my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z); + foreach my $inst (@{ $model_object->instances }) { + $inst->set_rotations($rotation); + } + Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); + + # update print and start background processing + $self->{print}->add_model_object($model_object, $obj_idx); + + $self->selection_changed; # refresh info (size etc.) + $self->update; + $self->schedule_background_process; + }; + # callback to react to gizmo flatten my $on_gizmo_flatten = sub { my ($angle, $axis_x, $axis_y, $axis_z) = @_; $self->rotate(rad2deg($angle), undef, 'absolute', $axis_x, $axis_y, $axis_z) if $angle != 0; }; + # callback to react to gizmo flatten + my $on_gizmo_flatten_3D = sub { + my ($angle_x, $angle_y, $angle_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]; + + $self->stop_background_process; + + my $rotation = Slic3r::Pointf3->new($angle_x, $angle_y, $angle_z); + foreach my $inst (@{ $model_object->instances }) { + $inst->set_rotations($rotation); + } + Slic3r::GUI::_3DScene::update_gizmos_data($self->{canvas3D}) if ($self->{canvas3D}); + + # update print and start background processing + $self->{print}->add_model_object($model_object, $obj_idx); + + $self->selection_changed; # refresh info (size etc.) + $self->update; + $self->schedule_background_process; + }; + # callback to update object's geometry info while using gizmos my $on_update_geometry_info = sub { my ($size_x, $size_y, $size_z, $scale_factor) = @_; @@ -261,7 +313,9 @@ sub new { Slic3r::GUI::_3DScene::register_on_enable_action_buttons_callback($self->{canvas3D}, $enable_action_buttons); Slic3r::GUI::_3DScene::register_on_gizmo_scale_uniformly_callback($self->{canvas3D}, $on_gizmo_scale_uniformly); Slic3r::GUI::_3DScene::register_on_gizmo_rotate_callback($self->{canvas3D}, $on_gizmo_rotate); + Slic3r::GUI::_3DScene::register_on_gizmo_rotate_3D_callback($self->{canvas3D}, $on_gizmo_rotate_3D); Slic3r::GUI::_3DScene::register_on_gizmo_flatten_callback($self->{canvas3D}, $on_gizmo_flatten); + Slic3r::GUI::_3DScene::register_on_gizmo_flatten_3D_callback($self->{canvas3D}, $on_gizmo_flatten_3D); Slic3r::GUI::_3DScene::register_on_update_geometry_info_callback($self->{canvas3D}, $on_update_geometry_info); Slic3r::GUI::_3DScene::register_action_add_callback($self->{canvas3D}, $on_action_add); Slic3r::GUI::_3DScene::register_action_delete_callback($self->{canvas3D}, $on_action_delete); diff --git a/xs/src/libslic3r/Format/3mf.cpp b/xs/src/libslic3r/Format/3mf.cpp index 43c99f19f..8a9d6870d 100644 --- a/xs/src/libslic3r/Format/3mf.cpp +++ b/xs/src/libslic3r/Format/3mf.cpp @@ -1283,6 +1283,9 @@ namespace Slic3r { transform(1, 0) * inv_sx, transform(1, 1) * inv_sy, transform(1, 2) * inv_sz, transform(2, 0) * inv_sx, transform(2, 1) * inv_sy, transform(2, 2) * inv_sz; +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d rotation = m3x3.eulerAngles(0, 1, 2); +#else Eigen::AngleAxisd rotation; rotation.fromRotationMatrix(m3x3); @@ -1291,6 +1294,7 @@ namespace Slic3r { return; double angle_z = (rotation.axis() == Vec3d::UnitZ()) ? rotation.angle() : -rotation.angle(); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #if ENABLE_MODELINSTANCE_3D_OFFSET instance.set_offset(offset); @@ -1299,7 +1303,11 @@ namespace Slic3r { instance.offset(1) = offset_y; #endif // ENABLE_MODELINSTANCE_3D_OFFSET instance.scaling_factor = sx; +#if ENABLE_MODELINSTANCE_3D_ROTATION + instance.set_rotation(rotation); +#else instance.rotation = angle_z; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } bool _3MF_Importer::_handle_start_config(const char** attributes, unsigned int num_attributes) diff --git a/xs/src/libslic3r/Format/AMF.cpp b/xs/src/libslic3r/Format/AMF.cpp index 458ce79de..6d3e06407 100644 --- a/xs/src/libslic3r/Format/AMF.cpp +++ b/xs/src/libslic3r/Format/AMF.cpp @@ -30,7 +30,12 @@ // 0 : .amf, .amf.xml and .zip.amf files saved by older slic3r. No version definition in them. // 1 : Introduction of amf versioning. No other change in data saved into amf files. #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION +// 2 : Added z component of offset +// Added x and y components of rotation +#else // 2 : Added z component of offset. +#endif // ENABLE_MODELINSTANCE_3D_ROTATION const unsigned int VERSION_AMF = 2; #else const unsigned int VERSION_AMF = 1; @@ -127,6 +132,10 @@ struct AMFParserContext #if ENABLE_MODELINSTANCE_3D_OFFSET NODE_TYPE_DELTAZ, // amf/constellation/instance/deltaz #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + NODE_TYPE_RX, // amf/constellation/instance/rx + NODE_TYPE_RY, // amf/constellation/instance/ry +#endif // ENABLE_MODELINSTANCE_3D_ROTATION NODE_TYPE_RZ, // amf/constellation/instance/rz NODE_TYPE_SCALE, // amf/constellation/instance/scale NODE_TYPE_METADATA, // anywhere under amf/*/metadata @@ -134,7 +143,11 @@ struct AMFParserContext struct Instance { #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rx_set(false), ry_set(false), rz_set(false), scale_set(false) {} +#else Instance() : deltax_set(false), deltay_set(false), deltaz_set(false), rz_set(false), scale_set(false) {} +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else Instance() : deltax_set(false), deltay_set(false), rz_set(false), scale_set(false) {} #endif // ENABLE_MODELINSTANCE_3D_OFFSET @@ -149,6 +162,14 @@ struct AMFParserContext float deltaz; bool deltaz_set; #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + // Rotation around the X axis. + float rx; + bool rx_set; + // Rotation around the Y axis. + float ry; + bool ry_set; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION // Rotation around the Z axis. float rz; bool rz_set; @@ -275,6 +296,12 @@ void AMFParserContext::startElement(const char *name, const char **atts) else if (strcmp(name, "deltaz") == 0) node_type_new = NODE_TYPE_DELTAZ; #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + else if (strcmp(name, "rx") == 0) + node_type_new = NODE_TYPE_RX; + else if (strcmp(name, "ry") == 0) + node_type_new = NODE_TYPE_RY; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION else if (strcmp(name, "rz") == 0) node_type_new = NODE_TYPE_RZ; else if (strcmp(name, "scale") == 0) @@ -339,7 +366,11 @@ void AMFParserContext::characters(const XML_Char *s, int len) if (m_path.back() == NODE_TYPE_DELTAX || m_path.back() == NODE_TYPE_DELTAY || m_path.back() == NODE_TYPE_DELTAZ || - m_path.back() == NODE_TYPE_RZ || +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_path.back() == NODE_TYPE_RX || + m_path.back() == NODE_TYPE_RY || +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + m_path.back() == NODE_TYPE_RZ || m_path.back() == NODE_TYPE_SCALE) #else if (m_path.back() == NODE_TYPE_DELTAX || m_path.back() == NODE_TYPE_DELTAY || m_path.back() == NODE_TYPE_RZ || m_path.back() == NODE_TYPE_SCALE) @@ -391,6 +422,20 @@ void AMFParserContext::endElement(const char * /* name */) m_value[0].clear(); break; #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + case NODE_TYPE_RX: + assert(m_instance); + m_instance->rx = float(atof(m_value[0].c_str())); + m_instance->rx_set = true; + m_value[0].clear(); + break; + case NODE_TYPE_RY: + assert(m_instance); + m_instance->ry = float(atof(m_value[0].c_str())); + m_instance->ry_set = true; + m_value[0].clear(); + break; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION case NODE_TYPE_RZ: assert(m_instance); m_instance->rz = float(atof(m_value[0].c_str())); @@ -541,12 +586,16 @@ void AMFParserContext::endDocument() if (instance.deltax_set && instance.deltay_set) { ModelInstance *mi = m_model.objects[object.second.idx]->add_instance(); #if ENABLE_MODELINSTANCE_3D_OFFSET - mi->set_offset(Vec3d((double)instance.deltax, (double)instance.deltay, (double)instance.deltaz)); + mi->set_offset(Vec3d(instance.deltax_set ? (double)instance.deltax : 0.0, instance.deltay_set ? (double)instance.deltay : 0.0, instance.deltaz_set ? (double)instance.deltaz : 0.0)); #else mi->offset(0) = instance.deltax; mi->offset(1) = instance.deltay; #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + mi->set_rotation(Vec3d(instance.rx_set ? (double)instance.rx : 0.0, instance.ry_set ? (double)instance.ry : 0.0, instance.rz_set ? (double)instance.rz : 0.0)); +#else mi->rotation = instance.rz_set ? instance.rz : 0.f; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION mi->scaling_factor = instance.scale_set ? instance.scale : 1.f; } } @@ -850,6 +899,10 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c #if ENABLE_MODELINSTANCE_3D_OFFSET " %lf\n" #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + " %lf\n" + " %lf\n" +#endif // ENABLE_MODELINSTANCE_3D_ROTATION " %lf\n" " %lf\n" " \n", @@ -862,8 +915,15 @@ bool store_amf(const char *path, Model *model, Print* print, bool export_print_c instance->offset(0), instance->offset(1), #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + instance->get_rotation(X), + instance->get_rotation(Y), + instance->get_rotation(Z), +#else instance->rotation, +#endif // ENABLE_MODELINSTANCE_3D_ROTATION instance->scaling_factor); + //FIXME missing instance->scaling_factor instances.append(buf); } diff --git a/xs/src/libslic3r/Format/PRUS.cpp b/xs/src/libslic3r/Format/PRUS.cpp index 45eb56c63..27095acef 100644 --- a/xs/src/libslic3r/Format/PRUS.cpp +++ b/xs/src/libslic3r/Format/PRUS.cpp @@ -164,7 +164,11 @@ bool load_prus(const char *path, Model *model) const char *zero_tag = ""; const char *zero_xml = strstr(scene_xml_data.data(), zero_tag); float trafo[3][4] = { 0 }; +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d instance_rotation = Vec3d::Zero(); +#else double instance_rotation = 0.; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION double instance_scaling_factor = 1.f; #if ENABLE_MODELINSTANCE_3D_OFFSET Vec3d instance_offset = Vec3d::Zero(); @@ -197,10 +201,14 @@ bool load_prus(const char *path, Model *model) instance_scaling_factor = scale[0]; scale[0] = scale[1] = scale[2] = 1.; } +#if ENABLE_MODELINSTANCE_3D_ROTATION + instance_rotation = Vec3d(-(double)rotation[0], -(double)rotation[1], -(double)rotation[2]); +#else if (rotation[0] == 0. && rotation[1] == 0.) { instance_rotation = - rotation[2]; rotation[2] = 0.; } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION Eigen::Matrix3f mat_rot, mat_scale, mat_trafo; mat_rot = Eigen::AngleAxisf(-rotation[2], Eigen::Vector3f::UnitZ()) * Eigen::AngleAxisf(-rotation[1], Eigen::Vector3f::UnitY()) * @@ -366,8 +374,12 @@ bool load_prus(const char *path, Model *model) model_object = model->add_object(name_utf8.data(), path, std::move(mesh)); volume = model_object->volumes.front(); ModelInstance *instance = model_object->add_instance(); - instance->rotation = instance_rotation; - instance->scaling_factor = instance_scaling_factor; +#if ENABLE_MODELINSTANCE_3D_ROTATION + instance->set_rotation(instance_rotation); +#else + instance->rotation = instance_rotation; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + instance->scaling_factor = instance_scaling_factor; #if ENABLE_MODELINSTANCE_3D_OFFSET instance->set_offset(instance_offset); #else diff --git a/xs/src/libslic3r/Model.cpp b/xs/src/libslic3r/Model.cpp index ec7447352..65743da8d 100644 --- a/xs/src/libslic3r/Model.cpp +++ b/xs/src/libslic3r/Model.cpp @@ -1054,6 +1054,29 @@ size_t ModelVolume::split(unsigned int max_extruders) return idx; } +#if ENABLE_MODELINSTANCE_3D_ROTATION +void ModelInstance::set_rotation(const Vec3d& rotation) +{ + set_rotation(X, rotation(0)); + set_rotation(Y, rotation(1)); + set_rotation(Z, rotation(2)); +} + +void ModelInstance::set_rotation(Axis axis, double rotation) +{ + static const double TWO_PI = 2.0 * (double)PI; + while (rotation < 0.0) + { + rotation += TWO_PI; + } + while (TWO_PI < rotation) + { + rotation -= TWO_PI; + } + m_rotation(axis) = rotation; +} +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->transform(world_matrix(dont_translate).cast()); @@ -1098,7 +1121,12 @@ Vec3d ModelInstance::transform_vector(const Vec3d& v, bool dont_translate) const void ModelInstance::transform_polygon(Polygon* polygon) const { +#if ENABLE_MODELINSTANCE_3D_ROTATION + // CHECK_ME -> Is the following correct or it should take in account all three rotations ? + polygon->rotate(this->m_rotation(2)); // rotate around polygon origin +#else polygon->rotate(this->rotation); // rotate around polygon origin +#endif // ENABLE_MODELINSTANCE_3D_ROTATION polygon->scale(this->scaling_factor); // scale around polygon origin } @@ -1114,7 +1142,15 @@ Transform3d ModelInstance::world_matrix(bool dont_translate, bool dont_rotate, b #endif // ENABLE_MODELINSTANCE_3D_OFFSET if (!dont_rotate) +#if ENABLE_MODELINSTANCE_3D_ROTATION + { + m.rotate(Eigen::AngleAxisd(m_rotation(2), Vec3d::UnitZ())); + m.rotate(Eigen::AngleAxisd(m_rotation(1), Vec3d::UnitY())); + m.rotate(Eigen::AngleAxisd(m_rotation(0), Vec3d::UnitX())); + } +#else m.rotate(Eigen::AngleAxisd(rotation, Vec3d::UnitZ())); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION if (!dont_scale) m.scale(scaling_factor); diff --git a/xs/src/libslic3r/Model.hpp b/xs/src/libslic3r/Model.hpp index 4c2356429..ba315e3d6 100644 --- a/xs/src/libslic3r/Model.hpp +++ b/xs/src/libslic3r/Model.hpp @@ -246,11 +246,16 @@ public: #if ENABLE_MODELINSTANCE_3D_OFFSET private: Vec3d m_offset; // in unscaled coordinates +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d m_rotation; // Rotation around the three axes, in radians around mesh center point +#endif // ENABLE_MODELINSTANCE_3D_ROTATION public: #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if !ENABLE_MODELINSTANCE_3D_ROTATION double rotation; // Rotation around the Z axis, in radians around mesh center point +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION double scaling_factor; #if !ENABLE_MODELINSTANCE_3D_OFFSET Vec2d offset; // in unscaled coordinates @@ -269,6 +274,14 @@ public: void set_offset(Axis axis, double offset) { m_offset(axis) = offset; } #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + const Vec3d& get_rotation() const { return m_rotation; } + double get_rotation(Axis axis) const { return m_rotation(axis); } + + void set_rotation(const Vec3d& rotation); + void set_rotation(Axis axis, double rotation); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + // To be called on an external mesh void transform_mesh(TriangleMesh* mesh, bool dont_translate = false) const; // Calculate a bounding box of a transformed mesh. To be called on an external mesh. @@ -289,9 +302,15 @@ private: ModelObject* object; #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + ModelInstance(ModelObject *object) : m_rotation(Vec3d::Zero()), scaling_factor(1), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {} + ModelInstance(ModelObject *object, const ModelInstance &other) : + m_rotation(other.m_rotation), scaling_factor(other.scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {} +#else ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), m_offset(Vec3d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : rotation(other.rotation), scaling_factor(other.scaling_factor), m_offset(other.m_offset), object(object), print_volume_state(PVS_Inside) {} +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else ModelInstance(ModelObject *object) : rotation(0), scaling_factor(1), offset(Vec2d::Zero()), object(object), print_volume_state(PVS_Inside) {} ModelInstance(ModelObject *object, const ModelInstance &other) : diff --git a/xs/src/libslic3r/ModelArrange.hpp b/xs/src/libslic3r/ModelArrange.hpp index 4b91131ed..9f983ee9f 100644 --- a/xs/src/libslic3r/ModelArrange.hpp +++ b/xs/src/libslic3r/ModelArrange.hpp @@ -527,8 +527,13 @@ ShapeData2D projectModelFromTop(const Slic3r::Model &model) { // Invalid geometries would throw exceptions when arranging if(item.vertexCount() > 3) { +#if ENABLE_MODELINSTANCE_3D_ROTATION + // CHECK_ME -> is the following correct or it should take in account all three rotations ? + item.rotation(objinst->get_rotation(Z)); +#else item.rotation(objinst->rotation); - item.translation( { +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + item.translation({ #if ENABLE_MODELINSTANCE_3D_OFFSET ClipperLib::cInt(objinst->get_offset(X)/SCALING_FACTOR), ClipperLib::cInt(objinst->get_offset(Y)/SCALING_FACTOR) @@ -681,7 +686,12 @@ void applyResult( #endif // ENABLE_MODELINSTANCE_3D_OFFSET // write the transformation data into the model instance +#if ENABLE_MODELINSTANCE_3D_ROTATION + // CHECK_ME -> Is the following correct ? + inst_ptr->set_rotation(Vec3d(0.0, 0.0, rot)); +#else inst_ptr->rotation = rot; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #if ENABLE_MODELINSTANCE_3D_OFFSET inst_ptr->set_offset(foff); #else diff --git a/xs/src/libslic3r/Technologies.hpp b/xs/src/libslic3r/Technologies.hpp index 0343bb00c..25e6b85e7 100644 --- a/xs/src/libslic3r/Technologies.hpp +++ b/xs/src/libslic3r/Technologies.hpp @@ -8,6 +8,8 @@ #define ENABLE_MODELINSTANCE_3D_OFFSET (1 && ENABLE_1_42_0) // Add double click on gizmo grabbers to reset transformation components to their default value #define ENABLE_GIZMOS_RESET (1 && ENABLE_1_42_0) +// Add x and y rotation components to model instances' offset +#define ENABLE_MODELINSTANCE_3D_ROTATION (1 && ENABLE_MODELINSTANCE_3D_OFFSET) #endif // _technologies_h_ diff --git a/xs/src/slic3r/GUI/3DScene.cpp b/xs/src/slic3r/GUI/3DScene.cpp index e6f038042..5b830b30d 100644 --- a/xs/src/slic3r/GUI/3DScene.cpp +++ b/xs/src/slic3r/GUI/3DScene.cpp @@ -196,7 +196,11 @@ const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; GLVolume::GLVolume(float r, float g, float b, float a) : m_offset(Vec3d::Zero()) +#if ENABLE_MODELINSTANCE_3D_ROTATION + , m_rotation(Vec3d::Zero()) +#else , m_rotation(0.0) +#endif // ENABLE_MODELINSTANCE_3D_ROTATION , m_scaling_factor(1.0) , m_world_matrix(Transform3f::Identity()) , m_world_matrix_dirty(true) @@ -255,7 +259,24 @@ void GLVolume::set_render_color() set_render_color(color, 4); } -double GLVolume::get_rotation() +#if ENABLE_MODELINSTANCE_3D_ROTATION +const Vec3d& GLVolume::get_rotation() const +{ + return m_rotation; +} + +void GLVolume::set_rotation(const Vec3d& rotation) +{ + if (m_rotation != rotation) + { + m_rotation = rotation; + m_world_matrix_dirty = true; + m_transformed_bounding_box_dirty = true; + m_transformed_convex_hull_bounding_box_dirty = true; + } +} +#else +double GLVolume::get_rotation() const { return m_rotation; } @@ -270,6 +291,7 @@ void GLVolume::set_rotation(double rotation) m_transformed_convex_hull_bounding_box_dirty = true; } } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION const Vec3d& GLVolume::get_offset() const { @@ -327,7 +349,13 @@ const Transform3f& GLVolume::world_matrix() const { m_world_matrix = Transform3f::Identity(); m_world_matrix.translate(m_offset.cast()); +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(2), Vec3f::UnitZ())); + m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(1), Vec3f::UnitY())); + m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation(0), Vec3f::UnitX())); +#else m_world_matrix.rotate(Eigen::AngleAxisf((float)m_rotation, Vec3f::UnitZ())); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION m_world_matrix.scale((float)m_scaling_factor); m_world_matrix_dirty = false; } @@ -403,7 +431,13 @@ void GLVolume::render() const ::glCullFace(GL_BACK); ::glPushMatrix(); ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); +#if ENABLE_MODELINSTANCE_3D_ROTATION + ::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0); + ::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0); + ::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0); +#else ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); if (this->indexed_vertex_array.indexed()) this->indexed_vertex_array.render(this->tverts_range, this->qverts_range); @@ -529,7 +563,13 @@ void GLVolume::render_VBOs(int color_id, int detection_id, int worldmatrix_id) c ::glPushMatrix(); ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); +#if ENABLE_MODELINSTANCE_3D_ROTATION + ::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0); + ::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0); + ::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0); +#else ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); if (n_triangles > 0) @@ -574,7 +614,13 @@ void GLVolume::render_legacy() const ::glPushMatrix(); ::glTranslated(m_offset(0), m_offset(1), m_offset(2)); +#if ENABLE_MODELINSTANCE_3D_ROTATION + ::glRotated(m_rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0); + ::glRotated(m_rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0); + ::glRotated(m_rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0); +#else ::glRotated(m_rotation * 180.0 / (double)PI, 0.0, 0.0, 1.0); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION ::glScaled(m_scaling_factor, m_scaling_factor, m_scaling_factor); if (n_triangles > 0) @@ -698,7 +744,11 @@ std::vector GLVolumeCollection::load_object( #else v.set_offset(Vec3d(instance->offset(0), instance->offset(1), 0.0)); #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + v.set_rotation(instance->get_rotation()); +#else v.set_rotation(instance->rotation); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION v.set_scaling_factor(instance->scaling_factor); } } @@ -2067,12 +2117,30 @@ void _3DScene::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, vo void _3DScene::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) { +#if !ENABLE_MODELINSTANCE_3D_ROTATION s_canvas_mgr.register_on_gizmo_rotate_callback(canvas, callback); +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION +} + +void _3DScene::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback) +{ +#if ENABLE_MODELINSTANCE_3D_ROTATION + s_canvas_mgr.register_on_gizmo_rotate_3D_callback(canvas, callback); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } void _3DScene::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback) { +#if !ENABLE_MODELINSTANCE_3D_ROTATION s_canvas_mgr.register_on_gizmo_flatten_callback(canvas, callback); +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION +} + +void _3DScene::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback) +{ +#if ENABLE_MODELINSTANCE_3D_ROTATION + s_canvas_mgr.register_on_gizmo_flatten_3D_callback(canvas, callback); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } void _3DScene::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) diff --git a/xs/src/slic3r/GUI/3DScene.hpp b/xs/src/slic3r/GUI/3DScene.hpp index f2d1c0786..8fc1661fc 100644 --- a/xs/src/slic3r/GUI/3DScene.hpp +++ b/xs/src/slic3r/GUI/3DScene.hpp @@ -256,8 +256,13 @@ public: private: // Offset of the volume to be rendered. Vec3d m_offset; +#if ENABLE_MODELINSTANCE_3D_ROTATION + // Rotation around three axes of the volume to be rendered. + Vec3d m_rotation; +#else // Rotation around Z axis of the volume to be rendered. double m_rotation; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION // Scale factor of the volume to be rendered. double m_scaling_factor; // World matrix of the volume to be rendered. @@ -327,8 +332,13 @@ public: // Sets render color in dependence of current state void set_render_color(); - double get_rotation(); +#if ENABLE_MODELINSTANCE_3D_ROTATION + const Vec3d& get_rotation() const; + void set_rotation(const Vec3d& rotation); +#else + double get_rotation() const; void set_rotation(double rotation); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION const Vec3d& get_offset() const; void set_offset(const Vec3d& offset); @@ -558,7 +568,9 @@ public: static void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); + static void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback); static void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback); + static void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback); static void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); static void register_action_add_callback(wxGLCanvas* canvas, void* callback); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.cpp b/xs/src/slic3r/GUI/GLCanvas3D.cpp index efb2b2dab..658e1731a 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.cpp @@ -1184,9 +1184,11 @@ bool GLCanvas3D::Gizmos::init(GLCanvas3D& parent) return false; } +#if !ENABLE_MODELINSTANCE_3D_ROTATION // temporary disable x and y grabbers gizmo->disable_grabber(0); gizmo->disable_grabber(1); +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION m_gizmos.insert(GizmosMap::value_type(Rotate, gizmo)); @@ -1436,6 +1438,35 @@ void GLCanvas3D::Gizmos::set_scale(float scale) reinterpret_cast(it->second)->set_scale(scale); } +#if ENABLE_MODELINSTANCE_3D_ROTATION +Vec3d GLCanvas3D::Gizmos::get_rotation() const +{ + if (!m_enabled) + return Vec3d::Zero(); + + GizmosMap::const_iterator it = m_gizmos.find(Rotate); + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_rotation() : Vec3d::Zero(); +} + +void GLCanvas3D::Gizmos::set_rotation(const Vec3d& rotation) +{ + if (!m_enabled) + return; + + GizmosMap::const_iterator it = m_gizmos.find(Rotate); + if (it != m_gizmos.end()) + reinterpret_cast(it->second)->set_rotation(rotation); +} + +Vec3d GLCanvas3D::Gizmos::get_flattening_rotation() const +{ + if (!m_enabled) + return Vec3d::Zero(); + + GizmosMap::const_iterator it = m_gizmos.find(Flatten); + return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_flattening_rotation() : Vec3d::Zero(); +} +#else float GLCanvas3D::Gizmos::get_angle_z() const { if (!m_enabled) @@ -1463,6 +1494,7 @@ Vec3d GLCanvas3D::Gizmos::get_flattening_normal() const GizmosMap::const_iterator it = m_gizmos.find(Flatten); return (it != m_gizmos.end()) ? reinterpret_cast(it->second)->get_flattening_normal() : Vec3d::Zero(); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void GLCanvas3D::Gizmos::set_flattening_data(const ModelObject* model_object) { @@ -2400,7 +2432,11 @@ void GLCanvas3D::update_gizmos_data() m_gizmos.set_position(Vec3d(model_instance->offset(0), model_instance->offset(1), 0.0)); #endif // ENABLE_MODELINSTANCE_3D_OFFSET m_gizmos.set_scale(model_instance->scaling_factor); +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_gizmos.set_rotation(model_instance->get_rotation()); +#else m_gizmos.set_angle_z(model_instance->rotation); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION m_gizmos.set_flattening_data(model_object); } } @@ -2409,7 +2445,11 @@ void GLCanvas3D::update_gizmos_data() { m_gizmos.set_position(Vec3d::Zero()); m_gizmos.set_scale(1.0f); +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_gizmos.set_rotation(Vec3d::Zero()); +#else m_gizmos.set_angle_z(0.0f); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION m_gizmos.set_flattening_data(nullptr); } } @@ -2772,6 +2812,19 @@ void GLCanvas3D::register_on_gizmo_scale_uniformly_callback(void* callback) m_on_gizmo_scale_uniformly_callback.register_callback(callback); } +#if ENABLE_MODELINSTANCE_3D_ROTATION +void GLCanvas3D::register_on_gizmo_rotate_3D_callback(void* callback) +{ + if (callback != nullptr) + m_on_gizmo_rotate_3D_callback.register_callback(callback); +} + +void GLCanvas3D::register_on_gizmo_flatten_3D_callback(void* callback) +{ + if (callback != nullptr) + m_on_gizmo_flatten_3D_callback.register_callback(callback); +} +#else void GLCanvas3D::register_on_gizmo_rotate_callback(void* callback) { if (callback != nullptr) @@ -2783,6 +2836,7 @@ void GLCanvas3D::register_on_gizmo_flatten_callback(void* callback) if (callback != nullptr) m_on_gizmo_flatten_callback.register_callback(callback); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void GLCanvas3D::register_on_update_geometry_info_callback(void* callback) { @@ -3133,6 +3187,11 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) m_mouse.drag.gizmo_volume_idx = _get_first_selected_volume_id(selected_object_idx); if (m_gizmos.get_current_type() == Gizmos::Flatten) { +#if ENABLE_MODELINSTANCE_3D_ROTATION + // Rotate the object so the normal points downward: + const Vec3d& rotation = m_gizmos.get_flattening_rotation(); + m_on_gizmo_flatten_3D_callback.call(rotation(0), rotation(1), rotation(2)); +#else // Rotate the object so the normal points downward: Vec3d normal = m_gizmos.get_flattening_normal(); if (normal(0) != 0.0 || normal(1) != 0.0 || normal(2) != 0.0) { @@ -3140,6 +3199,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) float angle = acos(clamp(-1.0, 1.0, -normal(2))); m_on_gizmo_flatten_callback.call(angle, (float)axis(0), (float)axis(1), (float)axis(2)); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } m_dirty = true; @@ -3322,6 +3382,15 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } case Gizmos::Rotate: { +#if ENABLE_MODELINSTANCE_3D_ROTATION + // Apply new temporary rotation + Vec3d rotation = m_gizmos.get_rotation(); + for (GLVolume* v : volumes) + { + v->set_rotation(rotation); + } + update_rotation_value(rotation); +#else // Apply new temporary angle_z float angle_z = m_gizmos.get_angle_z(); for (GLVolume* v : volumes) @@ -3329,6 +3398,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) v->set_rotation((double)angle_z); } update_rotation_value((double)angle_z, Z); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION break; } default: @@ -3474,14 +3544,19 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) } case Gizmos::Rotate: { +#if ENABLE_MODELINSTANCE_3D_ROTATION + const Vec3d& rotation = m_gizmos.get_rotation(); + m_on_gizmo_rotate_3D_callback.call(rotation(0), rotation(1), rotation(2)); +#else m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION break; } default: break; } m_gizmos.stop_dragging(); - Slic3r::GUI::update_settings_value(); + update_settings_value(); } m_mouse.drag.move_volume_idx = -1; @@ -3921,8 +3996,13 @@ void GLCanvas3D::_deregister_callbacks() m_on_wipe_tower_moved_callback.deregister_callback(); m_on_enable_action_buttons_callback.deregister_callback(); m_on_gizmo_scale_uniformly_callback.deregister_callback(); +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_on_gizmo_rotate_3D_callback.deregister_callback(); + m_on_gizmo_flatten_3D_callback.deregister_callback(); +#else m_on_gizmo_rotate_callback.deregister_callback(); m_on_gizmo_flatten_callback.deregister_callback(); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION m_on_update_geometry_info_callback.deregister_callback(); m_action_add_callback.deregister_callback(); diff --git a/xs/src/slic3r/GUI/GLCanvas3D.hpp b/xs/src/slic3r/GUI/GLCanvas3D.hpp index b123efccf..712ffbefc 100644 --- a/xs/src/slic3r/GUI/GLCanvas3D.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3D.hpp @@ -387,11 +387,20 @@ class GLCanvas3D float get_scale() const; void set_scale(float scale); +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d get_rotation() const; + void set_rotation(const Vec3d& rotation); +#else float get_angle_z() const; void set_angle_z(float angle_z); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION - void set_flattening_data(const ModelObject* model_object); +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d get_flattening_rotation() const; +#else Vec3d get_flattening_normal() const; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + void set_flattening_data(const ModelObject* model_object); void render_current_gizmo(const BoundingBoxf3& box) const; @@ -507,8 +516,13 @@ class GLCanvas3D PerlCallback m_on_wipe_tower_moved_callback; PerlCallback m_on_enable_action_buttons_callback; PerlCallback m_on_gizmo_scale_uniformly_callback; +#if ENABLE_MODELINSTANCE_3D_ROTATION + PerlCallback m_on_gizmo_rotate_3D_callback; + PerlCallback m_on_gizmo_flatten_3D_callback; +#else PerlCallback m_on_gizmo_rotate_callback; PerlCallback m_on_gizmo_flatten_callback; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION PerlCallback m_on_update_geometry_info_callback; PerlCallback m_action_add_callback; @@ -632,8 +646,13 @@ public: void register_on_wipe_tower_moved_callback(void* callback); void register_on_enable_action_buttons_callback(void* callback); void register_on_gizmo_scale_uniformly_callback(void* callback); +#if ENABLE_MODELINSTANCE_3D_ROTATION + void register_on_gizmo_rotate_3D_callback(void* callback); + void register_on_gizmo_flatten_3D_callback(void* callback); +#else void register_on_gizmo_rotate_callback(void* callback); void register_on_gizmo_flatten_callback(void* callback); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void register_on_update_geometry_info_callback(void* callback); void register_action_add_callback(void* callback); diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp index 495f49425..1ac588f6c 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.cpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.cpp @@ -699,6 +699,21 @@ void GLCanvas3DManager::register_on_gizmo_scale_uniformly_callback(wxGLCanvas* c it->second->register_on_gizmo_scale_uniformly_callback(callback); } +#if ENABLE_MODELINSTANCE_3D_ROTATION +void GLCanvas3DManager::register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_gizmo_rotate_3D_callback(callback); +} + +void GLCanvas3DManager::register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback) +{ + CanvasesMap::iterator it = _get_canvas(canvas); + if (it != m_canvases.end()) + it->second->register_on_gizmo_flatten_3D_callback(callback); +} +#else void GLCanvas3DManager::register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback) { CanvasesMap::iterator it = _get_canvas(canvas); @@ -712,6 +727,7 @@ void GLCanvas3DManager::register_on_gizmo_flatten_callback(wxGLCanvas* canvas, v if (it != m_canvases.end()) it->second->register_on_gizmo_flatten_callback(callback); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void GLCanvas3DManager::register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback) { diff --git a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp index 4922b6171..2331ec3f5 100644 --- a/xs/src/slic3r/GUI/GLCanvas3DManager.hpp +++ b/xs/src/slic3r/GUI/GLCanvas3DManager.hpp @@ -163,8 +163,13 @@ public: void register_on_wipe_tower_moved_callback(wxGLCanvas* canvas, void* callback); void register_on_enable_action_buttons_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_scale_uniformly_callback(wxGLCanvas* canvas, void* callback); +#if ENABLE_MODELINSTANCE_3D_ROTATION + void register_on_gizmo_rotate_3D_callback(wxGLCanvas* canvas, void* callback); + void register_on_gizmo_flatten_3D_callback(wxGLCanvas* canvas, void* callback); +#else void register_on_gizmo_rotate_callback(wxGLCanvas* canvas, void* callback); void register_on_gizmo_flatten_callback(wxGLCanvas* canvas, void* callback); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void register_on_update_geometry_info_callback(wxGLCanvas* canvas, void* callback); void register_action_add_callback(wxGLCanvas* canvas, void* callback); diff --git a/xs/src/slic3r/GUI/GLGizmo.cpp b/xs/src/slic3r/GUI/GLGizmo.cpp index 1890a7bf8..f9b481a31 100644 --- a/xs/src/slic3r/GUI/GLGizmo.cpp +++ b/xs/src/slic3r/GUI/GLGizmo.cpp @@ -1251,15 +1251,28 @@ void GLGizmoFlatten::on_render(const BoundingBoxf3& box) const ::glColor4f(0.9f, 0.9f, 0.9f, 0.5f); #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + for (const InstanceData& inst : m_instances) { + Vec3d position = inst.position + dragged_offset; +#else for (Vec3d offset : m_instances_positions) { offset += dragged_offset; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else for (Vec2d offset : m_instances_positions) { offset += to_2d(dragged_offset); #endif // ENABLE_MODELINSTANCE_3D_OFFSET ::glPushMatrix(); #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + ::glTranslated(position(0), position(1), position(2)); + ::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0); + ::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0); + ::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0); + ::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor); +#else ::glTranslated(offset(0), offset(1), offset(2)); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); #endif // ENABLE_MODELINSTANCE_3D_OFFSET @@ -1282,13 +1295,25 @@ void GLGizmoFlatten::on_render_for_picking(const BoundingBoxf3& box) const { ::glColor3f(1.0f, 1.0f, picking_color_component(i)); #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + for (const InstanceData& inst : m_instances) { +#else for (const Vec3d& offset : m_instances_positions) { +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else for (const Vec2d& offset : m_instances_positions) { #endif // ENABLE_MODELINSTANCE_3D_OFFSET ::glPushMatrix(); #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + ::glTranslated(inst.position(0), inst.position(1), inst.position(2)); + ::glRotated(inst.rotation(2) * 180.0 / (double)PI, 0.0, 0.0, 1.0); + ::glRotated(inst.rotation(1) * 180.0 / (double)PI, 0.0, 1.0, 0.0); + ::glRotated(inst.rotation(0) * 180.0 / (double)PI, 1.0, 0.0, 0.0); + ::glScaled(inst.scaling_factor, inst.scaling_factor, inst.scaling_factor); +#else ::glTranslated(offset(0), offset(1), offset(2)); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else ::glTranslatef((GLfloat)offset(0), (GLfloat)offset(1), 0.0f); #endif // ENABLE_MODELINSTANCE_3D_OFFSET @@ -1307,10 +1332,18 @@ void GLGizmoFlatten::set_flattening_data(const ModelObject* model_object) // ...and save the updated positions of the object instances: if (m_model_object && !m_model_object->instances.empty()) { +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_instances.clear(); +#else m_instances_positions.clear(); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION for (const auto* instance : m_model_object->instances) #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + m_instances.emplace_back(instance->get_offset(), instance->get_rotation(), instance->scaling_factor); +#else m_instances_positions.emplace_back(instance->get_offset()); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else m_instances_positions.emplace_back(instance->offset); #endif // ENABLE_MODELINSTANCE_3D_OFFSET @@ -1326,8 +1359,10 @@ void GLGizmoFlatten::update_planes() for (const ModelVolume* vol : m_model_object->volumes) ch.merge(vol->get_convex_hull()); ch = ch.convex_hull_3d(); +#if !ENABLE_MODELINSTANCE_3D_ROTATION ch.scale(m_model_object->instances.front()->scaling_factor); ch.rotate_z(m_model_object->instances.front()->rotation); +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION m_planes.clear(); @@ -1372,8 +1407,8 @@ void GLGizmoFlatten::update_planes() // if this is a just a very small triangle, remove it to speed up further calculations (it would be rejected anyway): if (m_planes.back().vertices.size() == 3 && (m_planes.back().vertices[0] - m_planes.back().vertices[1]).norm() < 1.f - || (m_planes.back().vertices[0] - m_planes.back().vertices[2]).norm() < 1.f) - m_planes.pop_back(); + || (m_planes.back().vertices[0] - m_planes.back().vertices[2]).norm() < 1.f) + m_planes.pop_back(); } // Now we'll go through all the polygons, transform the points into xy plane to process them: @@ -1476,8 +1511,10 @@ void GLGizmoFlatten::update_planes() m_source_data.bounding_boxes.clear(); for (const auto& vol : m_model_object->volumes) m_source_data.bounding_boxes.push_back(vol->get_convex_hull().bounding_box()); +#if !ENABLE_MODELINSTANCE_3D_ROTATION m_source_data.scaling_factor = m_model_object->instances.front()->scaling_factor; m_source_data.rotation = m_model_object->instances.front()->rotation; +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION const float* first_vertex = m_model_object->volumes.front()->get_convex_hull().first_vertex(); m_source_data.mesh_first_point = Vec3d((double)first_vertex[0], (double)first_vertex[1], (double)first_vertex[2]); } @@ -1489,10 +1526,14 @@ bool GLGizmoFlatten::is_plane_update_necessary() const if (m_state != On || !m_model_object || m_model_object->instances.empty()) return false; +#if ENABLE_MODELINSTANCE_3D_ROTATION + if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size()) +#else if (m_model_object->volumes.size() != m_source_data.bounding_boxes.size() || m_model_object->instances.front()->scaling_factor != m_source_data.scaling_factor || m_model_object->instances.front()->rotation != m_source_data.rotation) - return true; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + return true; // now compare the bounding boxes: for (unsigned int i=0; ivolumes.size(); ++i) @@ -1507,11 +1548,22 @@ bool GLGizmoFlatten::is_plane_update_necessary() const return false; } +#if ENABLE_MODELINSTANCE_3D_ROTATION +Vec3d GLGizmoFlatten::get_flattening_rotation() const +{ + // calculates the rotations in model space + Eigen::Quaterniond q; + Vec3d angles = q.setFromTwoVectors(m_normal, -Vec3d::UnitZ()).toRotationMatrix().eulerAngles(2, 1, 0); + m_normal = Vec3d::Zero(); + return Vec3d(angles(2), angles(1), angles(0)); +} +#else Vec3d GLGizmoFlatten::get_flattening_normal() const { Vec3d normal = m_model_object->instances.front()->world_matrix(true).matrix().block(0, 0, 3, 3).inverse() * m_normal; m_normal = Vec3d::Zero(); return normal.normalized(); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } // namespace GUI } // namespace Slic3r diff --git a/xs/src/slic3r/GUI/GLGizmo.hpp b/xs/src/slic3r/GUI/GLGizmo.hpp index bf5838f72..e0f2c73d0 100644 --- a/xs/src/slic3r/GUI/GLGizmo.hpp +++ b/xs/src/slic3r/GUI/GLGizmo.hpp @@ -188,6 +188,10 @@ class GLGizmoRotate3D : public GLGizmoBase public: explicit GLGizmoRotate3D(GLCanvas3D& parent); +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d get_rotation() const { return Vec3d(m_gizmos[X].get_angle(), m_gizmos[Y].get_angle(), m_gizmos[Z].get_angle()); } + void set_rotation(const Vec3d& rotation) { m_gizmos[X].set_angle(rotation(0)); m_gizmos[Y].set_angle(rotation(1)); m_gizmos[Z].set_angle(rotation(2)); } +#else double get_angle_x() const { return m_gizmos[X].get_angle(); } void set_angle_x(double angle) { m_gizmos[X].set_angle(angle); } @@ -196,6 +200,7 @@ public: double get_angle_z() const { return m_gizmos[Z].get_angle(); } void set_angle_z(double angle) { m_gizmos[Z].set_angle(angle); } +#endif // ENABLE_MODELINSTANCE_3D_ROTATION protected: virtual bool on_init(); @@ -340,8 +345,10 @@ private: }; struct SourceDataSummary { std::vector bounding_boxes; // bounding boxes of convex hulls of individual volumes +#if !ENABLE_MODELINSTANCE_3D_ROTATION float scaling_factor; float rotation; +#endif // !ENABLE_MODELINSTANCE_3D_ROTATION Vec3d mesh_first_point; }; @@ -350,7 +357,19 @@ private: std::vector m_planes; #if ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + struct InstanceData + { + Vec3d position; + Vec3d rotation; + double scaling_factor; + + InstanceData(const Vec3d& position, const Vec3d& rotation, double scaling_factor) : position(position), rotation(rotation), scaling_factor(scaling_factor) {} + }; + std::vector m_instances; +#else Pointf3s m_instances_positions; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION #else std::vector m_instances_positions; #endif // ENABLE_MODELINSTANCE_3D_OFFSET @@ -364,7 +383,11 @@ public: explicit GLGizmoFlatten(GLCanvas3D& parent); void set_flattening_data(const ModelObject* model_object); +#if ENABLE_MODELINSTANCE_3D_ROTATION + Vec3d get_flattening_rotation() const; +#else Vec3d get_flattening_normal() const; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION protected: virtual bool on_init(); diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp index ae34359ce..b336a34a9 100644 --- a/xs/src/slic3r/GUI/GUI_ObjectParts.cpp +++ b/xs/src/slic3r/GUI/GUI_ObjectParts.cpp @@ -1802,11 +1802,15 @@ void update_scale_values(double scaling_factor) void update_rotation_values() { +#if ENABLE_MODELINSTANCE_3D_ROTATION + update_rotation_value((*m_objects)[m_selected_object_id]->instances.front()->get_rotation()); +#else auto og = get_optgroup(ogFrequentlyObjectSettings); auto instance = (*m_objects)[m_selected_object_id]->instances.front(); og->set_value("rotation_x", 0); og->set_value("rotation_y", 0); og->set_value("rotation_z", int(Geometry::rad2deg(instance->rotation))); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION } void update_rotation_value(double angle, Axis axis) @@ -1836,6 +1840,16 @@ void update_rotation_value(double angle, Axis axis) og->set_value(axis_str, int(Geometry::rad2deg(angle))); } +#if ENABLE_MODELINSTANCE_3D_ROTATION +void update_rotation_value(const Vec3d& rotation) +{ + auto og = get_optgroup(ogFrequentlyObjectSettings); + og->set_value("rotation_x", int(Geometry::rad2deg(rotation(0)))); + og->set_value("rotation_y", int(Geometry::rad2deg(rotation(1)))); + og->set_value("rotation_z", int(Geometry::rad2deg(rotation(2)))); +} +#endif // ENABLE_MODELINSTANCE_3D_ROTATION + void set_uniform_scaling(const bool uniform_scale) { g_is_uniform_scale = uniform_scale; diff --git a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp index e66b4d1db..fdeb7a629 100644 --- a/xs/src/slic3r/GUI/GUI_ObjectParts.hpp +++ b/xs/src/slic3r/GUI/GUI_ObjectParts.hpp @@ -124,6 +124,9 @@ void update_scale_values(double scaling_factor); void update_rotation_values(); // update rotation value after "gizmos" void update_rotation_value(double angle, Axis axis); +#if ENABLE_MODELINSTANCE_3D_ROTATION +void update_rotation_value(const Vec3d& rotation); +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void set_uniform_scaling(const bool uniform_scale); void on_begin_drag(wxDataViewEvent &event); diff --git a/xs/xsp/GUI_3DScene.xsp b/xs/xsp/GUI_3DScene.xsp index c3e4ba3b7..0a3d11ed6 100644 --- a/xs/xsp/GUI_3DScene.xsp +++ b/xs/xsp/GUI_3DScene.xsp @@ -651,6 +651,13 @@ register_on_gizmo_rotate_callback(canvas, callback) CODE: _3DScene::register_on_gizmo_rotate_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); +void +register_on_gizmo_rotate_3D_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_gizmo_rotate_3D_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + void register_on_gizmo_flatten_callback(canvas, callback) SV *canvas; @@ -658,6 +665,13 @@ register_on_gizmo_flatten_callback(canvas, callback) CODE: _3DScene::register_on_gizmo_flatten_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); +void +register_on_gizmo_flatten_3D_callback(canvas, callback) + SV *canvas; + SV *callback; + CODE: + _3DScene::register_on_gizmo_flatten_3D_callback((wxGLCanvas*)wxPli_sv_2_object(aTHX_ canvas, "Wx::GLCanvas"), (void*)callback); + void register_on_update_geometry_info_callback(canvas, callback) SV *canvas; diff --git a/xs/xsp/Model.xsp b/xs/xsp/Model.xsp index 101faf564..892ecd861 100644 --- a/xs/xsp/Model.xsp +++ b/xs/xsp/Model.xsp @@ -364,8 +364,13 @@ ModelMaterial::attributes() Ref object() %code%{ RETVAL = THIS->get_object(); %}; +#if ENABLE_MODELINSTANCE_3D_ROTATION + double rotation() + %code%{ RETVAL = THIS->get_rotation(Z); %}; +#else double rotation() %code%{ RETVAL = THIS->rotation; %}; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION double scaling_factor() %code%{ RETVAL = THIS->scaling_factor; %}; #if ENABLE_MODELINSTANCE_3D_OFFSET @@ -376,8 +381,17 @@ ModelMaterial::attributes() %code%{ RETVAL = &THIS->offset; %}; #endif // ENABLE_MODELINSTANCE_3D_OFFSET +#if ENABLE_MODELINSTANCE_3D_ROTATION + void set_rotation(double val) + %code%{ THIS->set_rotation(Z, val); THIS->get_object()->invalidate_bounding_box(); %}; + + void set_rotations(Vec3d *rotation) + %code%{ THIS->set_rotation(*rotation); THIS->get_object()->invalidate_bounding_box(); %}; + +#else void set_rotation(double val) %code%{ THIS->rotation = val; THIS->get_object()->invalidate_bounding_box(); %}; +#endif // ENABLE_MODELINSTANCE_3D_ROTATION void set_scaling_factor(double val) %code%{ THIS->scaling_factor = val; THIS->get_object()->invalidate_bounding_box(); %}; #if ENABLE_MODELINSTANCE_3D_OFFSET