diff --git a/src/admesh/stl.h b/src/admesh/stl.h index d682b24347..63b15986a1 100644 --- a/src/admesh/stl.h +++ b/src/admesh/stl.h @@ -180,8 +180,65 @@ extern void stl_rotate_z(stl_file *stl, float angle); extern void stl_mirror_xy(stl_file *stl); extern void stl_mirror_yz(stl_file *stl); extern void stl_mirror_xz(stl_file *stl); -extern void stl_transform(stl_file *stl, float *trafo3x4); -extern void stl_transform(stl_file *stl, const Eigen::Transform& t); + +template +extern void stl_transform(stl_file *stl, T *trafo3x4) +{ + if (stl->error) + return; + + for (uint32_t i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { + stl_facet &face = stl->facet_start[i_face]; + for (int i_vertex = 0; i_vertex < 3; ++ i_vertex) { + stl_vertex &v_dst = face.vertex[i_vertex]; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]); + } + stl_vertex &v_dst = face.normal; + stl_vertex v_src = v_dst; + v_dst(0) = T(trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2)); + v_dst(1) = T(trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2)); + v_dst(2) = T(trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2)); + } + + stl_get_size(stl); +} + +template +inline void stl_transform(stl_file *stl, const Eigen::Transform& t) +{ + if (stl->error) + return; + + const Eigen::Matrix r = t.matrix().block<3, 3>(0, 0); + for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + stl_facet &f = stl->facet_start[i]; + for (size_t j = 0; j < 3; ++j) + f.vertex[j] = (t * f.vertex[j].cast()).cast().eval(); + f.normal = (r * f.normal.cast()).cast().eval(); + } + + stl_get_size(stl); +} + +template +inline void stl_transform(stl_file *stl, const Eigen::Matrix& m) +{ + if (stl->error) + return; + + for (size_t i = 0; i < stl->stats.number_of_facets; ++i) { + stl_facet &f = stl->facet_start[i]; + for (size_t j = 0; j < 3; ++j) + f.vertex[j] = (m * f.vertex[j].cast()).cast().eval(); + f.normal = (m * f.normal.cast()).cast().eval(); + } + + stl_get_size(stl); +} + extern void stl_open_merge(stl_file *stl, char *file); extern void stl_invalidate_shared_vertices(stl_file *stl); extern void stl_generate_shared_vertices(stl_file *stl); diff --git a/src/admesh/util.cpp b/src/admesh/util.cpp index 7cb69bccdd..305a58e22b 100644 --- a/src/admesh/util.cpp +++ b/src/admesh/util.cpp @@ -137,65 +137,6 @@ static void calculate_normals(stl_file *stl) } } -void stl_transform(stl_file *stl, float *trafo3x4) { - int i_face, i_vertex; - if (stl->error) - return; - for (i_face = 0; i_face < stl->stats.number_of_facets; ++ i_face) { - stl_vertex *vertices = stl->facet_start[i_face].vertex; - for (i_vertex = 0; i_vertex < 3; ++ i_vertex) { - stl_vertex &v_dst = vertices[i_vertex]; - stl_vertex v_src = v_dst; - v_dst(0) = trafo3x4[0] * v_src(0) + trafo3x4[1] * v_src(1) + trafo3x4[2] * v_src(2) + trafo3x4[3]; - v_dst(1) = trafo3x4[4] * v_src(0) + trafo3x4[5] * v_src(1) + trafo3x4[6] * v_src(2) + trafo3x4[7]; - v_dst(2) = trafo3x4[8] * v_src(0) + trafo3x4[9] * v_src(1) + trafo3x4[10] * v_src(2) + trafo3x4[11]; - } - } - stl_get_size(stl); - calculate_normals(stl); -} - -void stl_transform(stl_file *stl, const Eigen::Transform& t) -{ - if (stl->error) - return; - - unsigned int vertices_count = 3 * (unsigned int)stl->stats.number_of_facets; - if (vertices_count == 0) - return; - - Eigen::MatrixXf src_vertices(3, vertices_count); - stl_facet* facet_ptr = stl->facet_start; - unsigned int v_id = 0; - while (facet_ptr < stl->facet_start + stl->stats.number_of_facets) - { - for (int i = 0; i < 3; ++i) - { - ::memcpy((void*)src_vertices.col(v_id).data(), (const void*)&facet_ptr->vertex[i], 3 * sizeof(float)); - ++v_id; - } - facet_ptr += 1; - } - - Eigen::MatrixXf dst_vertices(3, vertices_count); - dst_vertices = t.cast() * src_vertices.colwise().homogeneous(); - - facet_ptr = stl->facet_start; - v_id = 0; - while (facet_ptr < stl->facet_start + stl->stats.number_of_facets) - { - for (int i = 0; i < 3; ++i) - { - ::memcpy((void*)&facet_ptr->vertex[i], (const void*)dst_vertices.col(v_id).data(), 3 * sizeof(float)); - ++v_id; - } - facet_ptr += 1; - } - - stl_get_size(stl); - calculate_normals(stl); -} - void stl_rotate_x(stl_file *stl, float angle) { int i; diff --git a/src/libslic3r/Geometry.hpp b/src/libslic3r/Geometry.hpp index 25b849d8ce..7b5abd2e58 100644 --- a/src/libslic3r/Geometry.hpp +++ b/src/libslic3r/Geometry.hpp @@ -269,6 +269,21 @@ extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis. extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); +// Is the angle close to a multiple of 90 degrees? +inline bool is_rotation_ninety_degrees(double a) +{ + a = fmod(std::abs(a), 0.5 * M_PI); + if (a > 0.25 * PI) + a = 0.5 * PI - a; + return a < 0.001; +} + +// Is the angle close to a multiple of 90 degrees? +inline bool is_rotation_ninety_degrees(const Vec3d &rotation) +{ + return is_rotation_ninety_degrees(rotation.x()) && is_rotation_ninety_degrees(rotation.y()) && is_rotation_ninety_degrees(rotation.z()); +} + } } #endif diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 37e1f4a1bc..3800571f07 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -24,6 +24,19 @@ unsigned int Model::s_auto_extruder_id = 1; size_t ModelBase::s_last_id = 0; +// Unique object / instance ID for the wipe tower. +ModelID wipe_tower_object_id() +{ + static ModelBase mine; + return mine.id(); +} + +ModelID wipe_tower_instance_id() +{ + static ModelBase mine; + return mine.id(); +} + Model& Model::assign_copy(const Model &rhs) { this->copy_id(rhs); @@ -1320,6 +1333,58 @@ void ModelObject::repair() v->mesh.repair(); } +// Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, +// then the scaling in world coordinate system is not representable by the Geometry::Transformation structure. +// This situation is solved by baking in the instance transformation into the mesh vertices. +// Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well. +void ModelObject::bake_xy_rotation_into_meshes(size_t instance_idx) +{ + assert(instance_idx < this->instances.size()); + + const Geometry::Transformation reference_trafo = this->instances[instance_idx]->get_transformation(); + if (Geometry::is_rotation_ninety_degrees(reference_trafo.get_rotation())) + // nothing to do, scaling in the world coordinate space is possible in the representation of Geometry::Transformation. + return; + + bool left_handed = reference_trafo.is_left_handed(); + bool has_mirrorring = ! reference_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.)); + bool uniform_scaling = std::abs(reference_trafo.get_scaling_factor().x() - reference_trafo.get_scaling_factor().y()) < EPSILON && + std::abs(reference_trafo.get_scaling_factor().x() - reference_trafo.get_scaling_factor().z()) < EPSILON; + double new_scaling_factor = uniform_scaling ? reference_trafo.get_scaling_factor().x() : 1.; + + // Adjust the instances. + for (size_t i = 0; i < this->instances.size(); ++ i) { + ModelInstance &model_instance = *this->instances[i]; + model_instance.set_rotation(Vec3d(0., 0., Geometry::rotation_diff_z(reference_trafo.get_rotation(), model_instance.get_rotation()))); + model_instance.set_scaling_factor(Vec3d(new_scaling_factor, new_scaling_factor, new_scaling_factor)); + model_instance.set_mirror(Vec3d(1., 1., 1.)); + } + + // Adjust the meshes. + // Transformation to be applied to the meshes. + Eigen::Matrix3d mesh_trafo_3x3 = reference_trafo.get_matrix(true, false, uniform_scaling, ! has_mirrorring).matrix().block<3, 3>(0, 0); + Transform3d volume_offset_correction = this->instances[instance_idx]->get_transformation().get_matrix().inverse() * reference_trafo.get_matrix(); + for (ModelVolume *model_volume : this->volumes) { + const Geometry::Transformation volume_trafo = model_volume->get_transformation(); + bool volume_left_handed = volume_trafo.is_left_handed(); + bool volume_has_mirrorring = ! volume_trafo.get_mirror().isApprox(Vec3d(1., 1., 1.)); + bool volume_uniform_scaling = std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().y()) < EPSILON && + std::abs(volume_trafo.get_scaling_factor().x() - volume_trafo.get_scaling_factor().z()) < EPSILON; + double volume_new_scaling_factor = volume_uniform_scaling ? volume_trafo.get_scaling_factor().x() : 1.; + // Transform the mesh. + Matrix3d volume_trafo_3x3 = volume_trafo.get_matrix(true, false, volume_uniform_scaling, !volume_has_mirrorring).matrix().block<3, 3>(0, 0); + model_volume->transform_mesh(mesh_trafo_3x3 * volume_trafo_3x3, left_handed != volume_left_handed); + // Reset the rotation, scaling and mirroring. + model_volume->set_rotation(Vec3d(0., 0., 0.)); + model_volume->set_scaling_factor(Vec3d(volume_new_scaling_factor, volume_new_scaling_factor, volume_new_scaling_factor)); + model_volume->set_mirror(Vec3d(1., 1., 1.)); + // Move the reference point of the volume to compensate for the change of the instance trafo. + model_volume->set_offset(volume_offset_correction * volume_trafo.get_offset()); + } + + this->invalidate_bounding_box(); +} + double ModelObject::get_min_z() const { if (instances.empty()) @@ -1656,6 +1721,22 @@ void ModelVolume::scale_geometry(const Vec3d& versor) m_convex_hull.scale(versor); } +void ModelVolume::transform_mesh(const Transform3d &mesh_trafo, bool fix_left_handed) +{ + this->mesh.transform(mesh_trafo, fix_left_handed); + this->m_convex_hull.transform(mesh_trafo, fix_left_handed); + // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded. + this->set_new_unique_id(); +} + +void ModelVolume::transform_mesh(const Matrix3d &matrix, bool fix_left_handed) +{ + this->mesh.transform(matrix, fix_left_handed); + this->m_convex_hull.transform(matrix, fix_left_handed); + // Let the rest of the application know that the geometry changed, so the meshes have to be reloaded. + this->set_new_unique_id(); +} + void ModelInstance::transform_mesh(TriangleMesh* mesh, bool dont_translate) const { mesh->transform(get_matrix(dont_translate)); diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 80187d259f..c48979e97e 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -54,6 +54,10 @@ struct ModelID size_t id; }; +// Unique object / instance ID for the wipe tower. +extern ModelID wipe_tower_object_id(); +extern ModelID wipe_tower_instance_id(); + // Base for Model, ModelObject, ModelVolume, ModelInstance or ModelMaterial to provide a unique ID // to synchronize the front end (UI) with the back end (BackgroundSlicingProcess / Print / PrintObject). // Achtung! The s_last_id counter is not thread safe, so it is expected, that the ModelBase derived instances @@ -85,6 +89,9 @@ private: static inline ModelID generate_new_id() { return ModelID(++ s_last_id); } static size_t s_last_id; + + friend ModelID wipe_tower_object_id(); + friend ModelID wipe_tower_instance_id(); }; #define MODELBASE_DERIVED_COPY_MOVE_CLONE(TYPE) \ @@ -265,6 +272,11 @@ public: ModelObjectPtrs cut(size_t instance, coordf_t z, bool keep_upper = true, bool keep_lower = true, bool rotate_lower = false); // Note: z is in world coordinates void split(ModelObjectPtrs* new_objects); void repair(); + // Support for non-uniform scaling of instances. If an instance is rotated by angles, which are not multiples of ninety degrees, + // then the scaling in world coordinate system is not representable by the Geometry::Transformation structure. + // This situation is solved by baking in the instance transformation into the mesh vertices. + // Rotation and mirroring is being baked in. In case the instance scaling was non-uniform, it is baked in as well. + void bake_xy_rotation_into_meshes(size_t instance_idx); double get_min_z() const; double get_instance_min_z(size_t instance_idx) const; @@ -414,6 +426,8 @@ protected: explicit ModelVolume(const ModelVolume &rhs) = default; void set_model_object(ModelObject *model_object) { object = model_object; } + void transform_mesh(const Transform3d& t, bool fix_left_handed); + void transform_mesh(const Matrix3d& m, bool fix_left_handed); private: // Parent object owning this ModelVolume. diff --git a/src/libslic3r/Point.hpp b/src/libslic3r/Point.hpp index 6b35600cbd..b02ead2994 100644 --- a/src/libslic3r/Point.hpp +++ b/src/libslic3r/Point.hpp @@ -40,6 +40,11 @@ typedef std::vector Points3; typedef std::vector Pointfs; typedef std::vector Pointf3s; +typedef Eigen::Matrix Matrix2f; +typedef Eigen::Matrix Matrix2d; +typedef Eigen::Matrix Matrix3f; +typedef Eigen::Matrix Matrix3d; + typedef Eigen::Transform Transform2f; typedef Eigen::Transform Transform2d; typedef Eigen::Transform Transform3f; diff --git a/src/libslic3r/TriangleMesh.cpp b/src/libslic3r/TriangleMesh.cpp index f449ac2b41..04194a0f66 100644 --- a/src/libslic3r/TriangleMesh.cpp +++ b/src/libslic3r/TriangleMesh.cpp @@ -330,6 +330,17 @@ void TriangleMesh::transform(const Transform3d& t, bool fix_left_handed) } } +void TriangleMesh::transform(const Matrix3d& m, bool fix_left_handed) +{ + stl_transform(&stl, m); + stl_invalidate_shared_vertices(&stl); + if (fix_left_handed && m.determinant() < 0.) { + // Left handed transformation is being applied. It is a good idea to flip the faces and their normals. + this->repair(); + stl_reverse_all_facets(&stl); + } +} + void TriangleMesh::align_to_origin() { this->translate( diff --git a/src/libslic3r/TriangleMesh.hpp b/src/libslic3r/TriangleMesh.hpp index 60ddcca088..c284f6482b 100644 --- a/src/libslic3r/TriangleMesh.hpp +++ b/src/libslic3r/TriangleMesh.hpp @@ -52,6 +52,7 @@ public: void mirror_y() { this->mirror(Y); } void mirror_z() { this->mirror(Z); } void transform(const Transform3d& t, bool fix_left_handed = false); + void transform(const Matrix3d& t, bool fix_left_handed = false); void align_to_origin(); void rotate(double angle, Point* center); TriangleMeshPtrs split() const; diff --git a/src/slic3r/GUI/3DScene.cpp b/src/slic3r/GUI/3DScene.cpp index 9038e388c8..bbedc08027 100644 --- a/src/slic3r/GUI/3DScene.cpp +++ b/src/slic3r/GUI/3DScene.cpp @@ -716,6 +716,8 @@ int GLVolumeCollection::load_wipe_tower_preview( v.bounding_box = v.indexed_vertex_array.bounding_box(); v.indexed_vertex_array.finalize_geometry(use_VBOs); v.composite_id = GLVolume::CompositeID(obj_idx, 0, 0); + v.geometry_id.first = 0; + v.geometry_id.second = wipe_tower_instance_id().id; v.is_wipe_tower = true; v.shader_outside_printer_detection_enabled = ! size_unknown; return int(this->volumes.size() - 1); diff --git a/src/slic3r/GUI/GLCanvas3D.cpp b/src/slic3r/GUI/GLCanvas3D.cpp index 6690e33e3a..f8859807f8 100644 --- a/src/slic3r/GUI/GLCanvas3D.cpp +++ b/src/slic3r/GUI/GLCanvas3D.cpp @@ -1770,6 +1770,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re // State of the sla_steps for all SLAPrintObjects. std::vector sla_support_state; + std::vector instance_ids_selected; std::vector map_glvolume_old_to_new(m_volumes.volumes.size(), size_t(-1)); std::vector glvolumes_new; glvolumes_new.reserve(m_volumes.volumes.size()); @@ -1834,6 +1835,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re if (it != model_volume_state.end() && it->geometry_id == key.geometry_id) mvs = &(*it); } + // Emplace instance ID of the volume. Both the aux volumes and model volumes share the same instance ID. + // The wipe tower has its own wipe_tower_instance_id(). + if (m_selection.contains_volume(volume_id)) + instance_ids_selected.emplace_back(volume->geometry_id.second); if (mvs == nullptr || force_full_scene_refresh) { // This GLVolume will be released. if (volume->is_wipe_tower) { @@ -1865,6 +1870,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re } } } + sort_remove_duplicates(instance_ids_selected); } if (m_reload_delayed) @@ -2001,7 +2007,10 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re update_volumes_colors_by_extruder(); // Update selection indices based on the old/new GLVolumeCollection. - m_selection.volumes_changed(map_glvolume_old_to_new); + if (m_selection.get_mode() == Selection::Instance) + m_selection.instances_changed(instance_ids_selected); + else + m_selection.volumes_changed(map_glvolume_old_to_new); } m_gizmos.update_data(*this); diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index f8ad8b7bb3..f65c83abb0 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1357,19 +1357,12 @@ Geometry::Transformation volume_to_bed_transformation(const Geometry::Transforma { Geometry::Transformation out; - // Is the angle close to a multiple of 90 degrees? - auto ninety_degrees = [](double a) { - a = fmod(std::abs(a), 0.5 * PI); - if (a > 0.25 * PI) - a = 0.5 * PI - a; - return a < 0.001; - }; if (instance_transformation.is_scaling_uniform()) { // No need to run the non-linear least squares fitting for uniform scaling. // Just set the inverse. out.set_from_transform(instance_transformation.get_matrix(true).inverse()); } - else if (ninety_degrees(instance_transformation.get_rotation().x()) && ninety_degrees(instance_transformation.get_rotation().y()) && ninety_degrees(instance_transformation.get_rotation().z())) + else if (Geometry::is_rotation_ninety_degrees(instance_transformation.get_rotation())) { // Anisotropic scaling, rotation by multiples of ninety degrees. Eigen::Matrix3d instance_rotation_trafo = diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index df28d8e07b..761f29e98d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -177,15 +177,19 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : void ObjectManipulation::Show(const bool show) { - if (show == IsShown()) - return; + if (show != IsShown()) { + m_og->Show(show); - m_og->Show(show); + if (show && wxGetApp().get_mode() != comSimple) { + m_og->get_grid_sizer()->Show(size_t(0), false); + m_og->get_grid_sizer()->Show(size_t(1), false); + } + } - if (show && wxGetApp().get_mode() != comSimple) { - m_og->get_grid_sizer()->Show(size_t(0), false); - m_og->get_grid_sizer()->Show(size_t(1), false); - } + if (show) { + bool show_world_local_combo = wxGetApp().plater()->canvas3D()->get_selection().is_single_full_instance(); + m_word_local_combo->Show(show_world_local_combo); + } } bool ObjectManipulation::IsShown() @@ -201,18 +205,6 @@ void ObjectManipulation::UpdateAndShow(const bool show) OG_Settings::UpdateAndShow(show); } -static bool is_rotation_ninety_degrees(const Vec3d &rotation) -{ - // Is the angle close to a multiple of 90 degrees? - auto ninety_degrees = [](double a) { - a = fmod(std::abs(a), 0.5 * PI); - if (a > 0.25 * PI) - a = 0.5 * PI - a; - return a < 0.001; - }; - return ninety_degrees(rotation.x()) && ninety_degrees(rotation.y()) && ninety_degrees(rotation.z()); -} - void ObjectManipulation::update_settings_value(const Selection& selection) { m_new_move_label_string = L("Position"); @@ -269,7 +261,7 @@ void ObjectManipulation::update_settings_value(const Selection& selection) // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); // Is the angle close to a multiple of 90 degrees? - if (! is_rotation_ninety_degrees(volume->get_instance_rotation())) { + if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { // Manipulating an instance in the world coordinate system, rotation is not multiples of ninety degrees, therefore enforce uniform scaling. m_uniform_scale = true; m_lock_bnt->SetLock(true); @@ -573,7 +565,7 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) // all volumes in the selection belongs to the same instance, any of them contains the needed instance data, so we take the first one const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); // Is the angle close to a multiple of 90 degrees? - if (! is_rotation_ninety_degrees(volume->get_instance_rotation())) { + if (! Geometry::is_rotation_ninety_degrees(volume->get_instance_rotation())) { // Cannot apply scaling in the world coordinate system. wxMessageDialog dlg(GUI::wxGetApp().mainframe, _(L("Non-uniform scaling of tilted objects is not supported in the World coordinate system.\n" @@ -586,6 +578,9 @@ void ObjectManipulation::set_uniform_scaling(const bool new_value) return; } // Bake the rotation into the meshes of the object. + (*wxGetApp().model_objects())[volume->composite_id.object_id]->bake_xy_rotation_into_meshes(volume->composite_id.instance_id); + // Update the 3D scene, selections etc. + wxGetApp().plater()->update(); } } m_uniform_scale = new_value; diff --git a/src/slic3r/GUI/Selection.cpp b/src/slic3r/GUI/Selection.cpp index 7a203fe74a..e4912918d4 100644 --- a/src/slic3r/GUI/Selection.cpp +++ b/src/slic3r/GUI/Selection.cpp @@ -310,43 +310,36 @@ void Selection::clear() wxGetApp().obj_manipul()->reset_cache(); } +// Update the selection based on the new instance IDs. +void Selection::instances_changed(const std::vector &instance_ids_selected) +{ + assert(m_valid); + assert(m_mode == Instance); + m_list.clear(); + for (unsigned int volume_idx = 0; volume_idx < (unsigned int)m_volumes->size(); ++ volume_idx) { + const GLVolume *volume = (*m_volumes)[volume_idx]; + auto it = std::lower_bound(instance_ids_selected.begin(), instance_ids_selected.end(), volume->geometry_id.second); + if (it != instance_ids_selected.end() && *it == volume->geometry_id.second) + this->do_add_volume(volume_idx); + } + update_type(); + m_bounding_box_dirty = true; +} + // Update the selection based on the map from old indices to new indices after m_volumes changed. // If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances. void Selection::volumes_changed(const std::vector &map_volume_old_to_new) { assert(m_valid); - - // 1) Update the selection set. + assert(m_mode == Volume); IndicesList list_new; - std::vector> model_instances; - for (unsigned int idx : m_list) { + for (unsigned int idx : m_list) if (map_volume_old_to_new[idx] != size_t(-1)) { unsigned int new_idx = (unsigned int)map_volume_old_to_new[idx]; + assert((*m_volumes)[new_idx]->selected); list_new.insert(new_idx); - if (m_mode == Instance) { - // Save the object_idx / instance_idx pair of selected old volumes, - // so we may add the newly added volumes of the same object_idx / instance_idx pair - // to the selection. - const GLVolume *volume = (*m_volumes)[new_idx]; - model_instances.emplace_back(volume->object_idx(), volume->instance_idx()); - } } - } m_list = std::move(list_new); - - if (!model_instances.empty()) { - // Instance selection mode. Add the newly added volumes of the same object_idx / instance_idx pair - // to the selection. - assert(m_mode == Instance); - sort_remove_duplicates(model_instances); - for (unsigned int i = 0; i < (unsigned int)m_volumes->size(); ++i) { - const GLVolume* volume = (*m_volumes)[i]; - for (const std::pair &model_instance : model_instances) - if (volume->object_idx() == model_instance.first && volume->instance_idx() == model_instance.second) - do_add_volume(i); - } - } - update_type(); m_bounding_box_dirty = true; } diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 2a54e9a188..9f9c1c3256 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -224,6 +224,8 @@ public: void add_all(); + // Update the selection based on the new instance IDs. + void instances_changed(const std::vector &instance_ids_selected); // Update the selection based on the map from old indices to new indices after m_volumes changed. // If the current selection is by instance, this call may select newly added volumes, if they belong to already selected instances. void volumes_changed(const std::vector &map_volume_old_to_new); @@ -245,7 +247,7 @@ public: bool is_from_single_instance() const { return get_instance_idx() != -1; } bool is_from_single_object() const; - bool contains_volume(unsigned int volume_idx) const { return std::find(m_list.begin(), m_list.end(), volume_idx) != m_list.end(); } + bool contains_volume(unsigned int volume_idx) const { return m_list.find(volume_idx) != m_list.end(); } bool requires_uniform_scale() const; // Returns the the object id if the selection is from a single object, otherwise is -1