From 895bdf79184b27756bcc5e9359c0d2aa2a3e2785 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 9 Oct 2018 15:56:34 +0200 Subject: [PATCH 1/5] New selection -> rotation wip --- src/slic3r/GUI/3DScene.cpp | 17 + src/slic3r/GUI/GLCanvas3D.cpp | 370 ++++++++++++++-------- src/slic3r/GUI/GLCanvas3D.hpp | 52 ++- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 59 +++- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 5 +- 5 files changed, 345 insertions(+), 158 deletions(-) diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 2ae900e00..e5782f656 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -270,9 +270,26 @@ const Vec3d& GLVolume::get_rotation() const void GLVolume::set_rotation(const Vec3d& rotation) { +#if ENABLE_EXTENDED_SELECTION + static const double TWO_PI = 2.0 * (double)PI; +#endif // ENABLE_EXTENDED_SELECTION + if (m_rotation != rotation) { m_rotation = rotation; +#if ENABLE_EXTENDED_SELECTION + for (int i = 0; i < 3; ++i) + { + while (m_rotation(i) < 0.0) + { + m_rotation(i) += TWO_PI; + } + while (TWO_PI < m_rotation(i)) + { + m_rotation(i) -= TWO_PI; + } + } +#endif // ENABLE_EXTENDED_SELECTION m_world_matrix_dirty = true; m_transformed_bounding_box_dirty = true; m_transformed_convex_hull_bounding_box_dirty = true; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 116d8cb3b..9192182f4 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1131,28 +1131,29 @@ bool GLCanvas3D::Mouse::is_start_position_3D_defined() const #if ENABLE_EXTENDED_SELECTION GLCanvas3D::Selection::VolumeCache::VolumeCache() - : position(Vec3d::Zero()) - , rotation(Vec3d::Zero()) - , scaling_factor(Vec3d::Ones()) + : m_position(Vec3d::Zero()) + , m_rotation(Vec3d::Zero()) + , m_scaling_factor(Vec3d::Ones()) { m_rotation_matrix = Transform3d::Identity(); } GLCanvas3D::Selection::VolumeCache::VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor) - : position(position) - , rotation(rotation) - , scaling_factor(scaling_factor) + : m_position(position) + , m_rotation(rotation) + , m_scaling_factor(scaling_factor) { m_rotation_matrix = Transform3d::Identity(); - m_rotation_matrix.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); - m_rotation_matrix.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); - m_rotation_matrix.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); + m_rotation_matrix.rotate(Eigen::AngleAxisd(m_rotation(2), Vec3d::UnitZ())); + m_rotation_matrix.rotate(Eigen::AngleAxisd(m_rotation(1), Vec3d::UnitY())); + m_rotation_matrix.rotate(Eigen::AngleAxisd(m_rotation(0), Vec3d::UnitX())); } GLCanvas3D::Selection::Selection() : m_volumes(nullptr) , m_model(nullptr) , m_mode(Instance) + , m_type(Invalid) , m_valid(false) , m_bounding_box_dirty(true) { @@ -1199,6 +1200,7 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio } } + update_type(); m_bounding_box_dirty = true; } @@ -1226,6 +1228,7 @@ void GLCanvas3D::Selection::remove(unsigned int volume_idx) } } + update_type(); m_bounding_box_dirty = true; } @@ -1240,115 +1243,45 @@ void GLCanvas3D::Selection::clear() } m_list.clear(); + update_type(); m_bounding_box_dirty = true; } -bool GLCanvas3D::Selection::is_single_full_instance(int& object_idx_out, int& instance_idx_out) const +bool GLCanvas3D::Selection::is_single_full_instance() const { - if (!m_valid || is_empty() || is_wipe_tower()) + if (m_type == SingleFullInstance) + return true; + + int object_idx = m_valid ? get_object_idx() : -1; + if (object_idx != -1) { - object_idx_out = -1; - instance_idx_out = -1; - return false; + if (get_instance_idx() != -1) + return m_model->objects[object_idx]->volumes.size() == m_list.size(); } - const GLVolume* first = (*m_volumes)[*m_list.begin()]; - int object_idx = first->object_idx(); - int instance_idx = first->instance_idx(); - unsigned int count = 0; - - for (unsigned int i : m_list) - { - const GLVolume* v = (*m_volumes)[i]; - if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx)) - return false; - else - ++count; - } - - bool res = (count == (unsigned int)m_model->objects[object_idx]->volumes.size()); - object_idx_out = res ? object_idx : -1; - instance_idx_out = res ? instance_idx : -1; - return res; + return false; } -bool GLCanvas3D::Selection::is_single_full_object(int& object_idx_out) const +int GLCanvas3D::Selection::get_object_idx() const { - if (!m_valid || is_empty() || is_wipe_tower()) - { - object_idx_out = -1; - return false; - } - - int object_idx = (*m_volumes)[*m_list.begin()]->object_idx(); - unsigned int count = 0; - - for (unsigned int i : m_list) - { - const GLVolume* v = (*m_volumes)[i]; - if (v->object_idx() != object_idx) - return false; - else - ++count; - } - - bool res = (count == (unsigned int)m_model->objects[object_idx]->volumes.size() * (unsigned int)m_model->objects[object_idx]->instances.size()); - object_idx_out = res ? object_idx : -1; - return res; + return (m_cache.content.size() == 1) ? m_cache.content.begin()->first : -1; } -bool GLCanvas3D::Selection::is_from_single_instance(int& object_idx_out, int& instance_idx_out) const +int GLCanvas3D::Selection::get_instance_idx() const { - if (!m_valid || is_empty() || is_wipe_tower()) + if (m_cache.content.size() == 1) { - object_idx_out = -1; - instance_idx_out = -1; - return false; + const InstanceIdxsList& idxs = m_cache.content.begin()->second; + if (idxs.size() == 1) + return *idxs.begin(); } - const GLVolume* first = (*m_volumes)[*m_list.begin()]; - int object_idx = first->object_idx(); - int instance_idx = first->instance_idx(); - - for (unsigned int i : m_list) - { - const GLVolume* v = (*m_volumes)[i]; - if ((v->object_idx() != object_idx) || (v->instance_idx() != instance_idx)) - return false; - } - - object_idx_out = object_idx; - instance_idx_out = instance_idx; - return true; -} - -bool GLCanvas3D::Selection::is_from_single_object(int& object_idx_out) const -{ - if (!m_valid || is_empty() || is_wipe_tower()) - { - object_idx_out = -1; - return false; - } - - int object_idx = (*m_volumes)[*m_list.begin()]->object_idx(); - - for (unsigned int i : m_list) - { - const GLVolume* v = (*m_volumes)[i]; - if (v->object_idx() != object_idx) - return false; - } - - object_idx_out = object_idx; - return true; + return -1; } const GLVolume* GLCanvas3D::Selection::get_volume(unsigned int volume_idx) const { - if (!m_valid) - return nullptr; - - return (volume_idx < (unsigned int)m_volumes->size()) ? (*m_volumes)[volume_idx] : nullptr; + return (m_valid && (volume_idx < (unsigned int)m_volumes->size())) ? (*m_volumes)[volume_idx] : nullptr; } const BoundingBoxf3& GLCanvas3D::Selection::get_bounding_box() const @@ -1374,7 +1307,40 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) for (unsigned int i : m_list) { - (*m_volumes)[i]->set_offset(m_cache.volumes_data[i].position + displacement); + (*m_volumes)[i]->set_offset(m_cache.volumes_data[i].get_position() + displacement); + } + + m_bounding_box_dirty = true; +} + +void GLCanvas3D::Selection::rotate(const Vec3d& rotation) +{ + if (!m_valid) + return; + + Transform3d m = Transform3d::Identity(); + if (rotation(2) != 0.0f) + m.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); + else if (rotation(1) != 0.0f) + m.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); + else if (rotation(0) != 0.0f) + m.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); + + bool single_full_instance = is_single_full_instance(); + + for (unsigned int i : m_list) + { + Vec3d radius = m * (m_cache.volumes_data[i].get_position() - m_cache.dragging_center); + (*m_volumes)[i]->set_offset(m_cache.dragging_center + radius); + + if (single_full_instance) + (*m_volumes)[i]->set_rotation(rotation); + else + { + Eigen::Matrix new_rotation_matrix = (m * m_cache.volumes_data[i].get_rotation_matrix()).matrix().block(0, 0, 3, 3); + Vec3d angles = new_rotation_matrix.eulerAngles(2, 1, 0); + (*m_volumes)[i]->set_rotation(Vec3d(angles(2), angles(1), angles(0))); + } } m_bounding_box_dirty = true; @@ -1394,6 +1360,102 @@ void GLCanvas3D::Selection::update_valid() m_valid = (m_volumes != nullptr) && (m_model != nullptr); } +void GLCanvas3D::Selection::update_type() +{ + m_cache.content.clear(); + m_type = Mixed; + + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + int obj_idx = volume->object_idx(); + int inst_idx = volume->instance_idx(); + ObjectIdxsToInstanceIdxsMap::iterator obj_it = m_cache.content.find(obj_idx); + if (obj_it == m_cache.content.end()) + obj_it = m_cache.content.insert(ObjectIdxsToInstanceIdxsMap::value_type(obj_idx, InstanceIdxsList())).first; + + obj_it->second.insert(inst_idx); + } + + if (!m_valid) + m_type = Invalid; + else + { + if (m_list.empty()) + m_type = Empty; + else if (m_list.size() == 1) + { + const GLVolume* first = (*m_volumes)[*m_list.begin()]; + if (first->is_wipe_tower) + m_type = WipeTower; + else if (first->is_modifier) + m_type = Modifier; + else + { + const ModelObject* model_object = m_model->objects[first->object_idx()]; + unsigned int volumes_count = (unsigned int)model_object->volumes.size(); + unsigned int instances_count = (unsigned int)model_object->instances.size(); + if (volumes_count * instances_count == 1) + m_type = SingleFullObject; + else if (volumes_count == 1) // instances_count > 1 + m_type = SingleFullInstance; + } + } + else + { + if (m_cache.content.size() == 1) // single object + { + const ModelObject* model_object = m_model->objects[m_cache.content.begin()->first]; + unsigned int volumes_count = (unsigned int)model_object->volumes.size(); + unsigned int instances_count = (unsigned int)model_object->instances.size(); + if (volumes_count * instances_count == (unsigned int)m_list.size()) + m_type = SingleFullObject; + else if ((m_cache.content.begin()->second.size() == 1) && (volumes_count == (unsigned int)m_list.size())) + m_type = SingleFullInstance; + } + } + } + + switch (m_type) + { + case Invalid: + { + std::cout << "selection type: Invalid" << std::endl; + break; + } + case Empty: + { + std::cout << "selection type: Empty" << std::endl; + break; + } + case WipeTower: + { + std::cout << "selection type: WipeTower" << std::endl; + break; + } + case Modifier: + { + std::cout << "selection type: Modifier" << std::endl; + break; + } + case SingleFullObject: + { + std::cout << "selection type: SingleFullObject" << std::endl; + break; + } + case SingleFullInstance: + { + std::cout << "selection type: SingleFullInstance" << std::endl; + break; + } + case Mixed: + { + std::cout << "selection type: Mixed" << std::endl; + break; + } + } +} + void GLCanvas3D::Selection::set_caches() { m_cache.volumes_data.clear(); @@ -1753,24 +1815,19 @@ void GLCanvas3D::Gizmos::set_hover_id(int id) } #if ENABLE_EXTENDED_SELECTION -void GLCanvas3D::Gizmos::enable_grabber(EType type, unsigned int id) +void GLCanvas3D::Gizmos::enable_grabber(EType type, unsigned int id, bool enable) { if (!m_enabled) return; GizmosMap::const_iterator it = m_gizmos.find(type); if (it != m_gizmos.end()) - it->second->enable_grabber(id); -} - -void GLCanvas3D::Gizmos::disable_grabber(EType type, unsigned int id) -{ - if (!m_enabled) - return; - - GizmosMap::const_iterator it = m_gizmos.find(type); - if (it != m_gizmos.end()) - it->second->disable_grabber(id); + { + if (enable) + it->second->enable_grabber(id); + else + it->second->disable_grabber(id); + } } #endif // ENABLE_EXTENDED_SELECTION @@ -2425,7 +2482,9 @@ wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDEFINE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); +#if !ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); +#endif // !ENABLE_EXTENDED_SELECTION wxDEFINE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); GLCanvas3D::GLCanvas3D(wxGLCanvas* canvas) @@ -2977,20 +3036,21 @@ void GLCanvas3D::update_gizmos_data() return; #if ENABLE_EXTENDED_SELECTION - if (m_gizmos.get_current_type() == Gizmos::Move) + bool enable_move_z = !m_selection.is_wipe_tower(); + bool is_single_full_object = m_selection.is_single_full_object(); + bool is_single_full_instance = m_selection.is_single_full_instance(); + bool enable_rotate_xy = is_single_full_object && !is_single_full_instance; + + m_gizmos.enable_grabber(Gizmos::Move, 2, enable_move_z); + for (int i = 0; i < 2; ++i) { - if (m_selection.is_wipe_tower()) - m_gizmos.disable_grabber(Gizmos::Move, 2); - else - m_gizmos.enable_grabber(Gizmos::Move, 2); + m_gizmos.enable_grabber(Gizmos::Rotate, i, enable_rotate_xy); } - int object_idx = -1; - int instance_idx = -1; - if (m_selection.is_single_full_instance(object_idx, instance_idx)) + if (is_single_full_instance) { - ModelObject* model_object = m_model->objects[object_idx]; - ModelInstance* model_instance = model_object->instances[instance_idx]; + ModelObject* model_object = m_model->objects[m_selection.get_object_idx()]; + ModelInstance* model_instance = model_object->instances[m_selection.get_instance_idx()]; m_gizmos.set_scale(model_instance->get_scaling_factor()); m_gizmos.set_rotation(model_instance->get_rotation()); m_gizmos.set_flattening_data(model_object); @@ -3477,8 +3537,7 @@ void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) if (is_layers_editing_enabled()) { #if ENABLE_EXTENDED_SELECTION - int object_idx_selected = -1; - m_selection.is_from_single_object(object_idx_selected); + int object_idx_selected = m_selection.get_object_idx(); #else int object_idx_selected = _get_first_selected_object_id(); #endif // ENABLE_EXTENDED_SELECTION @@ -3526,8 +3585,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) Point pos(evt.GetX(), evt.GetY()); #if ENABLE_EXTENDED_SELECTION - int selected_object_idx = -1; - m_selection.is_from_single_object(selected_object_idx); + int selected_object_idx = m_selection.get_object_idx(); int layer_editing_object_idx = is_layers_editing_enabled() ? selected_object_idx : -1; #else int selected_object_idx = _get_first_selected_object_id(); @@ -3581,11 +3639,22 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +#if ENABLE_EXTENDED_SELECTION + m_regenerate_volumes = false; + const Vec3d& rotation = m_gizmos.get_rotation(); + m_selection.rotate(rotation); + _on_rotate(); +#else post_event(Vec3dEvent(EVT_GIZMO_ROTATE, std::move(m_gizmos.get_rotation()))); +#endif // ENABLE_EXTENDED_SELECTION #else m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +#if ENABLE_EXTENDED_SELECTION + wxGetApp().obj_manipul()->update_settings_value(m_selection); +#else wxGetApp().obj_manipul()->update_rotation_values(); +#endif // ENABLE_EXTENDED_SELECTION m_dirty = true; break; } @@ -3726,8 +3795,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) #if ENABLE_EXTENDED_SELECTION if (m_picking_enabled && (m_hover_volume_id != -1)) { - int object_idx = -1; - m_selection.is_from_single_object(object_idx); + int object_idx = m_selection.get_object_idx(); _on_select(m_hover_volume_id, object_idx); } #else @@ -3849,7 +3917,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) v->set_offset(v->get_offset() + Vec3d(displacement(0), displacement(1), 0.0)); } - wxGetApp().obj_manipul()->update_position_values(volume->get_offset()); + wxGetApp().obj_manipul()->update_position_value(volume->get_offset()); m_mouse.drag.start_position_3D = cur_pos; #endif // ENABLE_EXTENDED_SELECTION @@ -3897,7 +3965,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { v->set_offset(v->get_offset() + offset); } - wxGetApp().obj_manipul()->update_position_values(volume->get_offset()); + wxGetApp().obj_manipul()->update_position_value(volume->get_offset()); #endif // ENABLE_EXTENDED_SELECTION break; } @@ -3929,6 +3997,8 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) { #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM #if ENABLE_EXTENDED_SELECTION + m_selection.rotate(m_gizmos.get_rotation()); + wxGetApp().obj_manipul()->update_settings_value(m_selection); #else // Apply new temporary rotation const Vec3d& rotation = m_gizmos.get_rotation(); @@ -4121,7 +4191,12 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) case Gizmos::Rotate: { #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM +#if ENABLE_EXTENDED_SELECTION + m_regenerate_volumes = false; + _on_rotate(); +#else post_event(Vec3dEvent(EVT_GIZMO_ROTATE, m_gizmos.get_rotation())); +#endif // ENABLE_EXTENDED_SELECTION #else m_on_gizmo_rotate_callback.call((double)m_gizmos.get_angle_z()); #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM @@ -6178,7 +6253,7 @@ void GLCanvas3D::_on_move() if (object_idx < 1000) { - // Move a regular object. + // Move instances. ModelObject* model_object = m_model->objects[object_idx]; if (model_object != nullptr) { @@ -6198,6 +6273,41 @@ void GLCanvas3D::_on_move() if (wipe_tower_origin != Vec3d::Zero()) post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); } + +void GLCanvas3D::_on_rotate() +{ + if (m_model == nullptr) + return; + + std::set done; // prevent rotating instances twice + const Selection::IndicesList& selection = m_selection.get_volume_idxs(); + + for (unsigned int i : selection) + { + const GLVolume* v = m_volumes.volumes[i]; + int object_idx = v->object_idx(); + int instance_idx = v->instance_idx(); + + // prevent rotating instances twice + char done_id[64]; + ::sprintf(done_id, "%d_%d", object_idx, instance_idx); + if (done.find(done_id) != done.end()) + continue; + + done.insert(done_id); + + if (object_idx < 1000) + { + // Rotate instances. + ModelObject* model_object = m_model->objects[object_idx]; + if (model_object != nullptr) + { + model_object->instances[instance_idx]->set_rotation(v->get_rotation()); + model_object->invalidate_bounding_box(); + } + } + } +} #else void GLCanvas3D::_on_move(const std::vector& volume_idxs) { diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d900a2621..d6fdf8930 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -116,7 +116,9 @@ wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); wxDECLARE_EVENT(EVT_GIZMO_SCALE, Vec3dEvent); +#if !ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GIZMO_ROTATE, Vec3dEvent); +#endif // !ENABLE_EXTENDED_SELECTION wxDECLARE_EVENT(EVT_GIZMO_FLATTEN, Vec3dEvent); @@ -390,29 +392,45 @@ public: Object }; + enum EType : unsigned char + { + Invalid, + Empty, + WipeTower, + Modifier, + SingleFullObject, + SingleFullInstance, + Mixed + }; + private: struct VolumeCache { private: + Vec3d m_position; + Vec3d m_rotation; + Vec3d m_scaling_factor; Transform3d m_rotation_matrix; public: - Vec3d position; - Vec3d rotation; - Vec3d scaling_factor; - VolumeCache(); VolumeCache(const Vec3d& position, const Vec3d& rotation, const Vec3d& scaling_factor); + const Vec3d& get_position() const { return m_position; } + const Vec3d& get_rotation() const { return m_rotation; } + const Vec3d& get_scaling_factor() const { return m_scaling_factor; } const Transform3d& get_rotation_matrix() const { return m_rotation_matrix; } }; typedef std::map VolumesCache; + typedef std::set InstanceIdxsList; + typedef std::map ObjectIdxsToInstanceIdxsMap; struct Cache { VolumesCache volumes_data; Vec3d dragging_center; + ObjectIdxsToInstanceIdxsMap content; }; GLVolumePtrs* m_volumes; @@ -420,6 +438,7 @@ public: bool m_valid; EMode m_mode; + EType m_type; IndicesList m_list; Cache m_cache; mutable BoundingBoxf3 m_bounding_box; @@ -438,13 +457,18 @@ public: void remove(unsigned int volume_idx); void clear(); - bool is_empty() const { return m_list.empty(); } - bool is_wipe_tower() const { return m_valid && (m_list.size() == 1) && (*m_volumes)[*m_list.begin()]->is_wipe_tower; } - bool is_modifier() const { return m_valid && (m_list.size() == 1) && (*m_volumes)[*m_list.begin()]->is_modifier; } - bool is_single_full_instance(int& object_idx_out, int& instance_idx_out) const; - bool is_single_full_object(int& object_idx_out) const; - bool is_from_single_instance(int& object_idx_out, int& instance_idx_out) const; - bool is_from_single_object(int& object_idx_out) const; + bool is_empty() const { return m_type == Empty; } + bool is_wipe_tower() const { return m_type == WipeTower; } + bool is_modifier() const { return m_type == Modifier; } + bool is_single_full_instance() const; + bool is_single_full_object() const { return m_type == SingleFullObject; } + bool is_from_single_instance() const { return get_instance_idx() != -1; } + bool is_from_single_object() const { return get_object_idx() != -1; } + + // Returns the the object id if the selection is from a single object, otherwise is -1 + int get_object_idx() const; + // Returns the instance id if the selection is from a single object and from a single instance, otherwise is -1 + int get_instance_idx() const; const IndicesList& get_volume_idxs() const { return m_list; } const GLVolume* get_volume(unsigned int volume_idx) const; @@ -455,11 +479,13 @@ public: void start_dragging(); void translate(const Vec3d& displacement); + void rotate(const Vec3d& rotation); void render() const; private: void update_valid(); + void update_type(); void set_caches(); void add_volume(unsigned int volume_idx); void add_instance(unsigned int volume_idx); @@ -517,8 +543,7 @@ private: void set_hover_id(int id); #if ENABLE_EXTENDED_SELECTION - void enable_grabber(EType type, unsigned int id); - void disable_grabber(EType type, unsigned int id); + void enable_grabber(EType type, unsigned int id, bool enable); #endif // ENABLE_EXTENDED_SELECTION bool overlay_contains_mouse(const GLCanvas3D& canvas, const Vec2d& mouse_pos) const; @@ -898,6 +923,7 @@ private: #if ENABLE_EXTENDED_SELECTION void _on_move(); + void _on_rotate(); #else void _on_move(const std::vector& volume_idxs); #endif // ENABLE_EXTENDED_SELECTION diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index afdc60806..aaca076ed 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -265,27 +265,41 @@ void ObjectManipulation::update_settings_list() #if ENABLE_EXTENDED_SELECTION void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& selection) { - int object_idx = -1; - int instance_idx = -1; - if (selection.is_single_full_instance(object_idx, instance_idx)) + if (selection.is_single_full_object()) + { + if (wxGetApp().mainframe->m_plater->model().objects[selection.get_object_idx()]->instances.size() == 1) + { + // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + update_position_value(volume->get_offset()); + update_rotation_value(volume->get_rotation()); + m_og->enable(); + } + else + reset_settings_value(); + } + else if (selection.is_single_full_instance()) { // all volumes in the selection belongs to the same instance, any of them contains the needed data, so we take the first - const GLCanvas3D::Selection::IndicesList& idxs = selection.get_volume_idxs(); - update_position_values(selection.get_volume(*idxs.begin())->get_offset()); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + update_position_value(volume->get_offset()); + update_rotation_value(volume->get_rotation()); m_og->enable(); } else if (selection.is_wipe_tower()) { // the selection contains a single volume - const GLCanvas3D::Selection::IndicesList& idxs = selection.get_volume_idxs(); - update_position_values(selection.get_volume(*idxs.begin())->get_offset()); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + update_position_value(volume->get_offset()); + update_rotation_value(volume->get_rotation()); m_og->enable(); } else if (selection.is_modifier()) { // the selection contains a single volume - const GLCanvas3D::Selection::IndicesList& idxs = selection.get_volume_idxs(); - update_position_values(selection.get_volume(*idxs.begin())->get_offset()); + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + update_position_value(volume->get_offset()); + update_rotation_value(volume->get_rotation()); m_og->enable(); } else @@ -293,17 +307,34 @@ void ObjectManipulation::update_settings_value(const GLCanvas3D::Selection& sele } void ObjectManipulation::reset_settings_value() +{ + reset_position_value(); + reset_rotation_value(); + reset_scale_value(); + m_og->disable(); +} + +void ObjectManipulation::reset_position_value() { m_og->set_value("position_x", 0); m_og->set_value("position_y", 0); m_og->set_value("position_z", 0); - m_og->set_value("scale_x", 0); - m_og->set_value("scale_y", 0); - m_og->set_value("scale_z", 0); +} + +void ObjectManipulation::reset_rotation_value() +{ m_og->set_value("rotation_x", 0); m_og->set_value("rotation_y", 0); m_og->set_value("rotation_z", 0); - m_og->disable(); +} + +void ObjectManipulation::reset_scale_value() +{ + m_is_percent_scale = true; + m_og->set_value("scale_unit", _("%")); + m_og->set_value("scale_x", 100); + m_og->set_value("scale_y", 100); + m_og->set_value("scale_z", 100); } #endif // ENABLE_EXTENDED_SELECTION @@ -380,7 +411,7 @@ void ObjectManipulation::update_position_values() #endif // ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM } -void ObjectManipulation::update_position_values(const Vec3d& position) +void ObjectManipulation::update_position_value(const Vec3d& position) { m_og->set_value("position_x", int(position(0))); m_og->set_value("position_y", int(position(1))); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 2a9ec004e..7cd5fce27 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -50,12 +50,15 @@ public: #if ENABLE_EXTENDED_SELECTION void update_settings_value(const GLCanvas3D::Selection& selection); void reset_settings_value(); + void reset_position_value(); + void reset_rotation_value(); + void reset_scale_value(); #endif // ENABLE_EXTENDED_SELECTION void update_values(); // update position values displacements or "gizmos" void update_position_values(); - void update_position_values(const Vec3d& position); + void update_position_value(const Vec3d& position); // update scale values after scale unit changing or "gizmos" void update_scale_values(); #if ENABLE_MODELINSTANCE_3D_FULL_TRANSFORM From bd85ca721e2a82b447a809d30062abb469f8c8a9 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Tue, 9 Oct 2018 17:14:59 +0200 Subject: [PATCH 2/5] Plater & GLCanvas3D: Fix instance_moved event, add event handlers --- src/slic3r/GUI/GLCanvas3D.cpp | 6 +-- src/slic3r/GUI/GLCanvas3D.hpp | 2 +- src/slic3r/GUI/Plater.cpp | 82 +++++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 31 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 9192182f4..a5ed6b1f1 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -2476,7 +2476,7 @@ wxDEFINE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event); wxDEFINE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_INCREASE_OBJECTS, Event); -wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVES, SimpleEvent); +wxDEFINE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDEFINE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDEFINE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); @@ -6268,7 +6268,7 @@ void GLCanvas3D::_on_move() } if (object_moved) - post_event(SimpleEvent(EVT_GLCANVAS_WIPETOWER_MOVED)); + post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); if (wipe_tower_origin != Vec3d::Zero()) post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); @@ -6354,7 +6354,7 @@ void GLCanvas3D::_on_move(const std::vector& volume_idxs) } if (object_moved) - post_event(SimpleEvent(EVT_GLCANVAS_WIPETOWER_MOVED)); + post_event(SimpleEvent(EVT_GLCANVAS_INSTANCE_MOVED)); if (wipe_tower_origin != Vec3d::Zero()) post_event(Vec3dEvent(EVT_GLCANVAS_WIPETOWER_MOVED, std::move(wipe_tower_origin))); diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d6fdf8930..d3e762ca1 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -110,7 +110,7 @@ wxDECLARE_EVENT(EVT_GLCANVAS_ARRANGE, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ROTATE_OBJECT, Event); // data: -1 => rotate left, +1 => rotate right wxDECLARE_EVENT(EVT_GLCANVAS_SCALE_UNIFORMLY, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_INCREASE_OBJECTS, Event); // data: +1 => increase, -1 => decrease -wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVES, SimpleEvent); +wxDECLARE_EVENT(EVT_GLCANVAS_INSTANCE_MOVED, SimpleEvent); wxDECLARE_EVENT(EVT_GLCANVAS_WIPETOWER_MOVED, Vec3dEvent); wxDECLARE_EVENT(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, Event); wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_GEOMETRY, Vec3dsEvent<2>); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 99395c826..ff8592cfe 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -729,13 +729,11 @@ struct Plater::priv void on_action_selectbyparts(SimpleEvent&); #endif // !ENABLE_EXTENDED_SELECTION + void on_object_select(ObjectSelectEvent&); void on_viewport_changed(SimpleEvent&); void on_right_click(Vec2dEvent&); void on_model_update(SimpleEvent&); - void on_remove_object(SimpleEvent&); - void on_arrange(SimpleEvent&); void on_scale_uniformly(SimpleEvent&); - void on_instance_moves(SimpleEvent&); void on_wipetower_moved(Vec3dEvent&); void on_enable_action_buttons(Event&); void on_update_geometry(Vec3dsEvent<2>&); @@ -816,17 +814,17 @@ Plater::priv::priv(Plater *q, MainFrame *main_frame) : sidebar->Bind(wxEVT_COMBOBOX, &priv::on_select_preset, this); // 3DScene events: - canvas3D->Bind(EVT_GLCANVAS_OBJECT_SELECT, [](ObjectSelectEvent&) { /*TODO*/ }); + canvas3D->Bind(EVT_GLCANVAS_OBJECT_SELECT, &priv::on_object_select, this); canvas3D->Bind(EVT_GLCANVAS_VIEWPORT_CHANGED, &priv::on_viewport_changed, this); // canvas3D->Bind(EVT_GLCANVAS_DOUBLE_CLICK, [](SimpleEvent&) { }); // XXX: remove? canvas3D->Bind(EVT_GLCANVAS_RIGHT_CLICK, &priv::on_right_click, this); canvas3D->Bind(EVT_GLCANVAS_MODEL_UPDATE, &priv::on_model_update, this); - canvas3D->Bind(EVT_GLCANVAS_REMOVE_OBJECT, &priv::on_remove_object, this); - canvas3D->Bind(EVT_GLCANVAS_ARRANGE, &priv::on_arrange, this); + canvas3D->Bind(EVT_GLCANVAS_REMOVE_OBJECT, [q](SimpleEvent&) { q->remove_selected(); }); + canvas3D->Bind(EVT_GLCANVAS_ARRANGE, [this](SimpleEvent&) { arrange(); }); canvas3D->Bind(EVT_GLCANVAS_ROTATE_OBJECT, [this](Event &evt) { /*TODO: call rotate */ }); - canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, &priv::on_scale_uniformly, this); + canvas3D->Bind(EVT_GLCANVAS_SCALE_UNIFORMLY, [this](SimpleEvent&) { scale(); }); canvas3D->Bind(EVT_GLCANVAS_INCREASE_OBJECTS, [this](Event &evt) { evt.data == 1 ? increase() : decrease(); }); - canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVES, &priv::on_instance_moves, this); + canvas3D->Bind(EVT_GLCANVAS_INSTANCE_MOVED, [this](SimpleEvent&) { update(); }); canvas3D->Bind(EVT_GLCANVAS_WIPETOWER_MOVED, &priv::on_wipetower_moved, this); canvas3D->Bind(EVT_GLCANVAS_ENABLE_ACTION_BUTTONS, &priv::on_enable_action_buttons, this); canvas3D->Bind(EVT_GLCANVAS_UPDATE_GEOMETRY, &priv::on_update_geometry, this); @@ -1573,6 +1571,19 @@ void Plater::priv::on_action_selectbyparts(SimpleEvent&) } #endif // !ENABLE_EXTENDED_SELECTION +void Plater::priv::on_object_select(ObjectSelectEvent &evt) +{ + const auto obj_idx = evt.object_id(); + const auto vol_idx = evt.volume_id(); + + // TODO: + // if (($obj_idx != -1) && ($vol_idx == -1)) { + // # Ignore the special objects (the wipe tower proxy and such). + // $self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef); + // $self->item_changed_selection($obj_idx) if (defined($obj_idx)); + // } +} + void Plater::priv::on_viewport_changed(SimpleEvent& evt) { wxObject* o = evt.GetEventObject(); @@ -1592,29 +1603,47 @@ void Plater::priv::on_model_update(SimpleEvent&) // TODO } -void Plater::priv::on_remove_object(SimpleEvent&) -{ - // TODO -} - -void Plater::priv::on_arrange(SimpleEvent&) -{ - // TODO -} - void Plater::priv::on_scale_uniformly(SimpleEvent&) { - // TODO +// my ($scale) = @_; + +// my ($obj_idx, $object) = $self->selected_object; + const auto obj_idx = selected_object(); + if (! obj_idx) { return; } +// 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 $variation = $scale / $model_instance->scaling_factor; +// #FIXME Scale the layer height profile? +// foreach my $range (@{ $model_object->layer_height_ranges }) { +// $range->[0] *= $variation; +// $range->[1] *= $variation; +// } +// $_->set_scaling_factor($scale) for @{ $model_object->instances }; + +// # Set object scale on c++ side +// # Slic3r::GUI::set_object_scale($obj_idx, $model_object->instances->[0]->scaling_factor * 100); + +// # $object->transform_thumbnail($self->{model}, $obj_idx); + +// #update print and start background processing +// $self->{print}->add_model_object($model_object, $obj_idx); + +// $self->selection_changed(1); # refresh info (size, volume etc.) +// $self->update; +// $self->schedule_background_process; } -void Plater::priv::on_instance_moves(SimpleEvent&) +void Plater::priv::on_wipetower_moved(Vec3dEvent &evt) { - // TODO -} - -void Plater::priv::on_wipetower_moved(Vec3dEvent&) -{ - // TODO + DynamicPrintConfig cfg; + cfg.opt("wipe_tower_x", true)->value = evt.data(0); + cfg.opt("wipe_tower_y", true)->value = evt.data(1); + main_frame->get_preset_tab("print")->load_config(cfg); } void Plater::priv::on_enable_action_buttons(Event&) @@ -1628,7 +1657,6 @@ void Plater::priv::on_update_geometry(Vec3dsEvent<2>&) } - // Plater / Public Plater::Plater(wxWindow *parent, MainFrame *main_frame) From 6d3307756430f9be075a8d51d935610042bd13d4 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Oct 2018 11:04:04 +0200 Subject: [PATCH 3/5] New selection -> synchronization of indirectly selected instances --- src/slic3r/GUI/GLCanvas3D.cpp | 141 +++++++++++++++++++++++++++++----- src/slic3r/GUI/GLCanvas3D.hpp | 5 +- 2 files changed, 127 insertions(+), 19 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index a5ed6b1f1..800a50b1c 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1343,16 +1343,23 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) } } + if (m_mode == Instance) + synchronize_unselected_instances(); + m_bounding_box_dirty = true; } -void GLCanvas3D::Selection::render() const +void GLCanvas3D::Selection::render(bool show_indirect_selection) const { if (is_empty()) return; - float color[3] = { 1.0f, 1.0f, 1.0f }; - render_bounding_box(get_bounding_box(), color); + // render cumulative bounding box of selected volumes + render_selected_volumes(); + + // render bounding boxes of indirectly selected instances + if (show_indirect_selection && (m_mode == Instance)) + render_unselected_instances(); } void GLCanvas3D::Selection::update_valid() @@ -1555,6 +1562,62 @@ void GLCanvas3D::Selection::calc_bounding_box() const m_bounding_box_dirty = false; } +void GLCanvas3D::Selection::render_selected_volumes() const +{ + float color[3] = { 1.0f, 1.0f, 1.0f }; + render_bounding_box(get_bounding_box(), color); +} + +void GLCanvas3D::Selection::render_unselected_instances() const +{ + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + typedef std::map, BoundingBoxf3> InstanceToBoxMap; + InstanceToBoxMap boxes; + for (unsigned int i : m_list) + { + if (done.size() == m_volumes->size()) + break; + + const GLVolume* volume = (*m_volumes)[i]; + int object_idx = volume->object_idx(); + if (object_idx >= 1000) + continue; + + int instance_idx = volume->instance_idx(); + + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) + { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume* v = (*m_volumes)[j]; + int i_idx = v->instance_idx(); + if ((v->object_idx() != object_idx) || (i_idx == instance_idx)) + continue; + + std::pair box_id(object_idx, i_idx); + InstanceToBoxMap::iterator it = boxes.find(box_id); + if (it == boxes.end()) + it = boxes.insert(InstanceToBoxMap::value_type(box_id, BoundingBoxf3())).first; + + it->second.merge(v->transformed_bounding_box()); + + done.insert(j); + } + } + + float color[3] = { 1.0f, 1.0f, 0.0f }; + for (const InstanceToBoxMap::value_type& box : boxes) + { + render_bounding_box(box.second, color); + } +} + void GLCanvas3D::Selection::render_bounding_box(const BoundingBoxf3& box, float* color) const { if (color == nullptr) @@ -1604,6 +1667,46 @@ void GLCanvas3D::Selection::render_bounding_box(const BoundingBoxf3& box, float* ::glEnd(); } + +void GLCanvas3D::Selection::synchronize_unselected_instances() +{ + std::set done; // prevent processing volumes twice + done.insert(m_list.begin(), m_list.end()); + + for (unsigned int i : m_list) + { + if (done.size() == m_volumes->size()) + break; + + const GLVolume* volume = (*m_volumes)[i]; + int object_idx = volume->object_idx(); + if (object_idx >= 1000) + continue; + + int instance_idx = volume->instance_idx(); + const Vec3d& rotation = volume->get_rotation(); + const Vec3d& scaling_factor = volume->get_scaling_factor(); + + // Process unselected instances. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) + { + if (done.size() == m_volumes->size()) + break; + + if (done.find(j) != done.end()) + continue; + + GLVolume* v = (*m_volumes)[j]; + if ((v->object_idx() != object_idx) || (v->instance_idx() == instance_idx)) + continue; + + v->set_rotation(rotation); + v->set_scaling_factor(scaling_factor); + + done.insert(j); + } + } +} #endif // ENABLE_EXTENDED_SELECTION const float GLCanvas3D::Gizmos::OverlayTexturesScale = 0.75f; @@ -4884,7 +4987,9 @@ void GLCanvas3D::_render_objects() const #if ENABLE_EXTENDED_SELECTION void GLCanvas3D::_render_selection() const { - m_selection.render(); + Gizmos::EType type = m_gizmos.get_current_type(); + bool show_indirect_selection = m_gizmos.is_running() && ((type == Gizmos::Rotate) || (type == Gizmos::Scale)); + m_selection.render(show_indirect_selection); } #endif // ENABLE_EXTENDED_SELECTION @@ -6232,7 +6337,7 @@ void GLCanvas3D::_on_move() if (m_model == nullptr) return; - std::set done; // prevent moving instances twice + std::set> done; // prevent moving instances twice bool object_moved = false; Vec3d wipe_tower_origin = Vec3d::Zero(); const Selection::IndicesList& selection = m_selection.get_volume_idxs(); @@ -6244,8 +6349,7 @@ void GLCanvas3D::_on_move() int instance_idx = v->instance_idx(); // prevent moving instances twice - char done_id[64]; - ::sprintf(done_id, "%d_%d", object_idx, instance_idx); + std::pair done_id(object_idx, instance_idx); if (done.find(done_id) != done.end()) continue; @@ -6279,34 +6383,35 @@ void GLCanvas3D::_on_rotate() if (m_model == nullptr) return; - std::set done; // prevent rotating instances twice + std::set> done; // prevent rotating instances twice const Selection::IndicesList& selection = m_selection.get_volume_idxs(); for (unsigned int i : selection) { const GLVolume* v = m_volumes.volumes[i]; int object_idx = v->object_idx(); + if (object_idx >= 1000) + continue; + int instance_idx = v->instance_idx(); // prevent rotating instances twice - char done_id[64]; - ::sprintf(done_id, "%d_%d", object_idx, instance_idx); + std::pair done_id(object_idx, instance_idx); if (done.find(done_id) != done.end()) continue; done.insert(done_id); - if (object_idx < 1000) + // Rotate instances. + ModelObject* model_object = m_model->objects[object_idx]; + if (model_object != nullptr) { - // Rotate instances. - ModelObject* model_object = m_model->objects[object_idx]; - if (model_object != nullptr) - { - model_object->instances[instance_idx]->set_rotation(v->get_rotation()); - model_object->invalidate_bounding_box(); - } + model_object->instances[instance_idx]->set_rotation(v->get_rotation()); + model_object->invalidate_bounding_box(); } } + +// schedule_background_process } #else void GLCanvas3D::_on_move(const std::vector& volume_idxs) diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index d3e762ca1..222b0137e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -481,7 +481,7 @@ public: void translate(const Vec3d& displacement); void rotate(const Vec3d& rotation); - void render() const; + void render(bool show_indirect_selection) const; private: void update_valid(); @@ -494,7 +494,10 @@ public: void remove_instance(unsigned int volume_idx); void remove_object(unsigned int volume_idx); void calc_bounding_box() const; + void render_selected_volumes() const; + void render_unselected_instances() const; void render_bounding_box(const BoundingBoxf3& box, float* color) const; + void synchronize_unselected_instances(); }; private: From 7672be64885aeff90e459b4ae788431c7f4d5d83 Mon Sep 17 00:00:00 2001 From: Vojtech Kral Date: Wed, 10 Oct 2018 11:21:20 +0200 Subject: [PATCH 4/5] Plater: on_object_select --- src/slic3r/GUI/Plater.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index ff8592cfe..c40108f31 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -1576,12 +1576,11 @@ void Plater::priv::on_object_select(ObjectSelectEvent &evt) const auto obj_idx = evt.object_id(); const auto vol_idx = evt.volume_id(); - // TODO: - // if (($obj_idx != -1) && ($vol_idx == -1)) { - // # Ignore the special objects (the wipe tower proxy and such). - // $self->select_object((defined($obj_idx) && $obj_idx >= 0 && $obj_idx < 1000) ? $obj_idx : undef); - // $self->item_changed_selection($obj_idx) if (defined($obj_idx)); - // } + if (obj_idx >= 0 && obj_idx < 1000 && vol_idx == -1) { + // Ignore the special objects (the wipe tower proxy and such). + select_object(obj_idx); + item_changed_selection(); + } } void Plater::priv::on_viewport_changed(SimpleEvent& evt) From 3e5e72dafcbb8b3871a0fa58497cec1497ab88a9 Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Wed, 10 Oct 2018 13:51:11 +0200 Subject: [PATCH 5/5] New selection -> changed calculation of euler angles for multivolume rotations --- src/slic3r/GUI/GLCanvas3D.cpp | 28 ++++++++++++++++++++++------ src/slic3r/GUI/GLCanvas3D.hpp | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 800a50b1c..496942e1b 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1338,8 +1338,26 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) else { Eigen::Matrix new_rotation_matrix = (m * m_cache.volumes_data[i].get_rotation_matrix()).matrix().block(0, 0, 3, 3); - Vec3d angles = new_rotation_matrix.eulerAngles(2, 1, 0); - (*m_volumes)[i]->set_rotation(Vec3d(angles(2), angles(1), angles(0))); + // extracts euler angles from the composed transformation + // not using Eigen eulerAngles() method because it returns weird results + // see: https://www.learnopencv.com/rotation-matrix-to-euler-angles/ + double sy = ::sqrt(sqr(new_rotation_matrix(0, 0)) + sqr(new_rotation_matrix(1, 0))); + + Vec3d angles = Vec3d::Zero(); + if (sy >= 1e-6) + { + angles(0) = ::atan2(new_rotation_matrix(2, 1), new_rotation_matrix(2, 2)); + angles(1) = ::atan2(-new_rotation_matrix(2, 0), sy); + angles(2) = ::atan2(new_rotation_matrix(1, 0), new_rotation_matrix(0, 0)); + } + else + { + angles(0) = ::atan2(-new_rotation_matrix(1, 2), new_rotation_matrix(1, 1)); + angles(1) = ::atan2(-new_rotation_matrix(2, 0), sy); + angles(2) = 0.0; + } + + (*m_volumes)[i]->set_rotation(Vec3d(angles(0), angles(1), angles(2))); } } @@ -3140,9 +3158,7 @@ void GLCanvas3D::update_gizmos_data() #if ENABLE_EXTENDED_SELECTION bool enable_move_z = !m_selection.is_wipe_tower(); - bool is_single_full_object = m_selection.is_single_full_object(); - bool is_single_full_instance = m_selection.is_single_full_instance(); - bool enable_rotate_xy = is_single_full_object && !is_single_full_instance; + bool enable_rotate_xy = m_selection.is_single_full_object() || m_selection.is_mixed(); m_gizmos.enable_grabber(Gizmos::Move, 2, enable_move_z); for (int i = 0; i < 2; ++i) @@ -3150,7 +3166,7 @@ void GLCanvas3D::update_gizmos_data() m_gizmos.enable_grabber(Gizmos::Rotate, i, enable_rotate_xy); } - if (is_single_full_instance) + if (m_selection.is_single_full_instance()) { ModelObject* model_object = m_model->objects[m_selection.get_object_idx()]; ModelInstance* model_instance = model_object->instances[m_selection.get_instance_idx()]; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 222b0137e..73b877bfb 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -462,6 +462,7 @@ public: bool is_modifier() const { return m_type == Modifier; } bool is_single_full_instance() const; bool is_single_full_object() const { return m_type == SingleFullObject; } + bool is_mixed() const { return m_type == Mixed; } bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const { return get_object_idx() != -1; }