From 57c769b63b036b99cf50edb4646590b62007539e Mon Sep 17 00:00:00 2001 From: Enrico Turri Date: Tue, 6 Nov 2018 15:51:33 +0100 Subject: [PATCH] Selection of modifiers in 3D scene --- src/libslic3r/Model.cpp | 11 +++ src/libslic3r/Model.hpp | 4 ++ src/slic3r/GUI/GLCanvas3D.cpp | 111 +++++++++++++++++++++++++++--- src/slic3r/GUI/GLCanvas3D.hpp | 6 +- src/slic3r/GUI/GUI_ObjectList.cpp | 10 ++- src/slic3r/GUI/Plater.cpp | 2 + 6 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 9cd7846f38..15eaa89c17 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -1038,6 +1038,9 @@ double ModelObject::get_instance_min_z(size_t instance_idx) const for (const ModelVolume* v : volumes) { + if (!v->is_model_part()) + continue; + #if ENABLE_MODELVOLUME_TRANSFORM Transform3d mv = mi * v->get_matrix(); const TriangleMesh& hull = v->get_convex_hull(); @@ -1152,6 +1155,14 @@ void ModelVolume::set_material(t_model_material_id material_id, const ModelMater this->object->get_model()->add_material(material_id, material); } +#if ENABLE_MODELVOLUME_TRANSFORM +void ModelVolume::translate_geometry(const Vec3d& displacement) +{ + mesh.translate((float)displacement(0), (float)displacement(1), (float)displacement(2)); + m_convex_hull.translate((float)displacement(0), (float)displacement(1), (float)displacement(2)); +} +#endif // ENABLE_MODELVOLUME_TRANSFORM + void ModelVolume::calculate_convex_hull() { m_convex_hull = mesh.convex_hull_3d(); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 1850cce1f1..b965f09ba7 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -322,6 +322,10 @@ public: void rotate(double angle, const Vec3d& axis); void mirror(Axis axis); +#if ENABLE_MODELVOLUME_TRANSFORM + void translate_geometry(const Vec3d& displacement); +#endif // ENABLE_MODELVOLUME_TRANSFORM + void calculate_convex_hull(); const TriangleMesh& get_convex_hull() const; diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index f69d798bd4..958037d4cc 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1197,16 +1197,30 @@ void GLCanvas3D::Selection::add(unsigned int volume_idx, bool as_single_selectio if (!m_valid || ((unsigned int)m_volumes->size() <= volume_idx)) return; - // resets the current list if needed const GLVolume* volume = (*m_volumes)[volume_idx]; - if (as_single_selection || volume->is_wipe_tower || is_wipe_tower() || volume->is_modifier || is_modifier()) + // wipe tower is already selected + if (is_wipe_tower() && volume->is_wipe_tower) + return; + + // resets the current list if needed + bool needs_reset = as_single_selection; + needs_reset |= volume->is_wipe_tower; + needs_reset |= is_wipe_tower() && !volume->is_wipe_tower; + needs_reset |= !is_modifier() && volume->is_modifier; + needs_reset |= is_modifier() && !volume->is_modifier; + + if (needs_reset) clear(); + m_mode = volume->is_modifier ? Volume : Instance; + switch (m_mode) { case Volume: { - _add_volume(volume_idx); + if (is_empty() || ((is_modifier() && volume->is_modifier) && (volume->instance_idx() == get_instance_idx()))) + _add_volume(volume_idx); + break; } case Instance: @@ -1435,6 +1449,11 @@ void GLCanvas3D::Selection::translate(const Vec3d& displacement) #endif // ENABLE_MODELVOLUME_TRANSFORM } +#if !DISABLE_INSTANCES_SYNCH + if (m_mode == Volume) + _synchronize_unselected_volumes(); +#endif // !DISABLE_INSTANCES_SYNCH + m_bounding_box_dirty = true; } @@ -1466,7 +1485,6 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) { // extracts rotations from the composed transformation Vec3d new_rotation = Geometry::extract_euler_angles(m * m_cache.volumes_data[i].get_volume_rotation_matrix()); - (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_volume_position() - m_cache.dragging_center)); (*m_volumes)[i]->set_volume_rotation(new_rotation); } #else @@ -1481,6 +1499,8 @@ void GLCanvas3D::Selection::rotate(const Vec3d& rotation) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1497,6 +1517,7 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) for (unsigned int i : m_list) { +#if ENABLE_MODELVOLUME_TRANSFORM Transform3d wst = m_cache.volumes_data[i].get_instance_scale_matrix() * m_cache.volumes_data[i].get_volume_scale_matrix(); Vec3d scaling_factor = Vec3d(1./wst(0,0), 1./wst(1,1), 1./wst(2,2)); @@ -1512,6 +1533,23 @@ void GLCanvas3D::Selection::flattening_rotate(const Vec3d& normal) Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_instance_rotation_matrix() ); (*m_volumes)[i]->set_instance_rotation(new_rotation); +#else + Transform3d wst = m_cache.volumes_data[i].get_scale_matrix() * m_cache.volumes_data[i].get_scale_matrix(); + Vec3d scaling_factor = Vec3d(1. / wst(0, 0), 1. / wst(1, 1), 1. / wst(2, 2)); + + Vec3d rotation = Geometry::extract_euler_angles(m_cache.volumes_data[i].get_rotation_matrix() * m_cache.volumes_data[i].get_rotation_matrix()); + Vec3d transformed_normal = Geometry::assemble_transform(Vec3d::Zero(), rotation, scaling_factor) * normal; + transformed_normal.normalize(); + + Vec3d axis = transformed_normal(2) > 0.999f ? Vec3d(1., 0., 0.) : Vec3d(transformed_normal.cross(Vec3d(0., 0., -1.))); + axis.normalize(); + + Transform3d extra_rotation = Transform3d::Identity(); + extra_rotation.rotate(Eigen::AngleAxisd(acos(-transformed_normal(2)), axis)); + + Vec3d new_rotation = Geometry::extract_euler_angles(extra_rotation * m_cache.volumes_data[i].get_rotation_matrix()); + (*m_volumes)[i]->set_rotation(new_rotation); +#endif // ENABLE_MODELVOLUME_TRANSFORM } #if !DISABLE_INSTANCES_SYNCH @@ -1553,7 +1591,6 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) Eigen::Matrix new_matrix = (m * m_cache.volumes_data[i].get_volume_scale_matrix()).matrix().block(0, 0, 3, 3); // extracts scaling factors from the composed transformation Vec3d new_scale(new_matrix.col(0).norm(), new_matrix.col(1).norm(), new_matrix.col(2).norm()); - (*m_volumes)[i]->set_volume_offset(m_cache.dragging_center + m * (m_cache.volumes_data[i].get_volume_position() - m_cache.dragging_center)); (*m_volumes)[i]->set_volume_scaling_factor(new_scale); } #else @@ -1569,6 +1606,8 @@ void GLCanvas3D::Selection::scale(const Vec3d& scale) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1592,6 +1631,8 @@ void GLCanvas3D::Selection::mirror(Axis axis) #if !DISABLE_INSTANCES_SYNCH if (m_mode == Instance) _synchronize_unselected_instances(); + else if (m_mode == Volume) + _synchronize_unselected_volumes(); #endif // !DISABLE_INSTANCES_SYNCH m_bounding_box_dirty = true; @@ -1746,7 +1787,7 @@ void GLCanvas3D::Selection::_update_type() if (first->is_wipe_tower) m_type = WipeTower; else if (first->is_modifier) - m_type = Modifier; + m_type = SingleModifier; else { const ModelObject* model_object = m_model->objects[first->object_idx()]; @@ -1769,6 +1810,8 @@ void GLCanvas3D::Selection::_update_type() m_type = SingleFullObject; else if ((m_cache.content.begin()->second.size() == 1) && (volumes_count == (unsigned int)m_list.size())) m_type = SingleFullInstance; + else if ((*m_volumes)[*m_list.begin()]->is_modifier) + m_type = MultipleModifier; } } } @@ -1790,9 +1833,14 @@ void GLCanvas3D::Selection::_update_type() std::cout << "selection type: WipeTower" << std::endl; break; } - case Modifier: + case SingleModifier: { - std::cout << "selection type: Modifier" << std::endl; + std::cout << "selection type: SingleModifier" << std::endl; + break; + } + case MultipleModifier: + { + std::cout << "selection type: MultipleModifier" << std::endl; break; } case SingleFullObject: @@ -2012,6 +2060,53 @@ void GLCanvas3D::Selection::_synchronize_unselected_instances() } } +void GLCanvas3D::Selection::_synchronize_unselected_volumes() +{ + for (unsigned int i : m_list) + { + const GLVolume* volume = (*m_volumes)[i]; + int object_idx = volume->object_idx(); + if (object_idx >= 1000) + continue; + + int volume_idx = volume->volume_idx(); +#if ENABLE_MODELVOLUME_TRANSFORM + const Vec3d& offset = volume->get_volume_offset(); + const Vec3d& rotation = volume->get_volume_rotation(); + const Vec3d& scaling_factor = volume->get_volume_scaling_factor(); + const Vec3d& mirror = volume->get_volume_mirror(); +#else + const Vec3d& offset = volume->get_offset(); + const Vec3d& rotation = volume->get_rotation(); + const Vec3d& scaling_factor = volume->get_scaling_factor(); + const Vec3d& mirror = volume->get_mirror(); +#endif // ENABLE_MODELVOLUME_TRANSFORM + + // Process unselected volumes. + for (unsigned int j = 0; j < (unsigned int)m_volumes->size(); ++j) + { + if (j == i) + continue; + + GLVolume* v = (*m_volumes)[j]; + if ((v->object_idx() != object_idx) || (v->volume_idx() != volume_idx)) + continue; + +#if ENABLE_MODELVOLUME_TRANSFORM + v->set_volume_offset(offset); + v->set_volume_rotation(rotation); + v->set_volume_scaling_factor(scaling_factor); + v->set_volume_mirror(mirror); +#else + v->set_offset(offset); + v->set_rotation(Vec3d(rotation)); + v->set_scaling_factor(scaling_factor); + v->set_mirror(mirror); +#endif // ENABLE_MODELVOLUME_TRANSFORM + } + } +} + const float GLCanvas3D::Gizmos::OverlayTexturesScale = 0.75f; const float GLCanvas3D::Gizmos::OverlayOffsetX = 10.0f * OverlayTexturesScale; const float GLCanvas3D::Gizmos::OverlayGapY = 5.0f * OverlayTexturesScale; diff --git a/src/slic3r/GUI/GLCanvas3D.hpp b/src/slic3r/GUI/GLCanvas3D.hpp index 07bca269b0..2db3cfc65e 100644 --- a/src/slic3r/GUI/GLCanvas3D.hpp +++ b/src/slic3r/GUI/GLCanvas3D.hpp @@ -373,7 +373,8 @@ public: Invalid, Empty, WipeTower, - Modifier, + SingleModifier, + MultipleModifier, SingleFullObject, SingleFullInstance, Mixed @@ -483,7 +484,7 @@ public: 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_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); } bool is_single_full_instance() const; bool is_single_full_object() const { return m_type == SingleFullObject; } bool is_mixed() const { return m_type == Mixed; } @@ -533,6 +534,7 @@ public: void _render_selected_volumes() const; void _render_bounding_box(const BoundingBoxf3& box, float* color) const; void _synchronize_unselected_instances(); + void _synchronize_unselected_volumes(); }; private: diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4aed6d7017..c5eb84c58f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -734,19 +734,27 @@ void ObjectList::load_part( ModelObject* model_object, if (model_object->origin_translation != Vec3d::Zero()) { object->center_around_origin(); +#if !ENABLE_MODELVOLUME_TRANSFORM object->ensure_on_bed(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM delta = model_object->origin_translation - object->origin_translation; } for (auto volume : object->volumes) { +#if ENABLE_MODELVOLUME_TRANSFORM + Vec3d shift = volume->mesh.bounding_box().center(); + volume->translate_geometry(-shift); + volume->translate(delta + shift); +#endif // ENABLE_MODELVOLUME_TRANSFORM auto new_volume = model_object->add_volume(*volume); new_volume->set_type(static_cast(type)); - boost::filesystem::path(input_file).filename().string(); new_volume->name = boost::filesystem::path(input_file).filename().string(); part_names.Add(new_volume->name); +#if !ENABLE_MODELVOLUME_TRANSFORM if (delta != Vec3d::Zero()) new_volume->translate(delta); +#endif // !ENABLE_MODELVOLUME_TRANSFORM // set a default extruder value, since user can't add it manually new_volume->config.set_key_value("extruder", new ConfigOptionInt(0)); diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index dadeec4ec1..911c930efa 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -2255,7 +2255,9 @@ void Plater::changed_object(int obj_idx) if (list->is_parts_changed()) { // recenter and re - align to Z = 0 auto model_object = p->model.objects[obj_idx]; +#if !ENABLE_MODELVOLUME_TRANSFORM model_object->center_around_origin(); +#endif // !ENABLE_MODELVOLUME_TRANSFORM model_object->ensure_on_bed(); _3DScene::reload_scene(p->canvas3D, false); }