diff --git a/src/libslic3r/Model.cpp b/src/libslic3r/Model.cpp index 2d0ff44ca..1cd76fc2c 100644 --- a/src/libslic3r/Model.cpp +++ b/src/libslic3r/Model.cpp @@ -2289,6 +2289,14 @@ int ModelObject::get_repaired_errors_count(const int vol_idx /*= -1*/) const stats.facets_reversed + stats.backwards_edges; } +bool ModelObject::has_solid_mesh() const +{ + for (const ModelVolume* volume : volumes) + if (volume->is_model_part()) + return true; + return false; +} + void ModelVolume::set_material_id(t_model_material_id material_id) { m_material_id = material_id; diff --git a/src/libslic3r/Model.hpp b/src/libslic3r/Model.hpp index 0705012c7..02220c2aa 100644 --- a/src/libslic3r/Model.hpp +++ b/src/libslic3r/Model.hpp @@ -523,6 +523,8 @@ public: // Get count of errors in the mesh( or all object's meshes, if volume index isn't defined) int get_repaired_errors_count(const int vol_idx = -1) const; + // Detect if object has at least one solid mash + bool has_solid_mesh() const; bool is_cut() const { return cut_id.id().valid(); } bool has_connectors() const; private: diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 4d632d17e..bbe4de5ea 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -1,3 +1,9 @@ +///|/ Copyright (c) Prusa Research 2018 - 2023 Oleksandra Iushchenko @YuSanka, Enrico Turri @enricoturri1966, Lukáš Matěna @lukasmatena, Lukáš Hejl @hejllukas, Tomáš Mészáros @tamasmeszaros, Vojtěch Bubník @bubnikv, Pavel Mikuš @Godrak, David Kocík @kocikdav, Filip Sykala @Jony01, Vojtěch Král @vojtechkral +///|/ Copyright (c) 2021 Mathias Rasmussen +///|/ Copyright (c) 2020 rongith +///|/ +///|/ PrusaSlicer is released under the terms of the AGPLv3 or higher +///|/ #include "libslic3r/libslic3r.h" #include "libslic3r/PresetBundle.hpp" #include "GUI_ObjectList.hpp" @@ -3030,6 +3036,93 @@ bool ObjectList::can_split_instances() return selection.is_multiple_full_instance() || selection.is_single_full_instance(); } +bool ObjectList::has_selected_cut_object() const +{ + wxDataViewItemArray sels; + GetSelections(sels); + if (sels.IsEmpty()) + return false; + + for (wxDataViewItem item : sels) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + // ys_FIXME: The obj_idx= 0 && obj_idx < int(m_objects->size()) && object(obj_idx)->is_cut()) + return true; + } + + return false; +} + +void ObjectList::invalidate_cut_info_for_selection() +{ + const wxDataViewItem item = GetSelection(); + if (item) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0) + invalidate_cut_info_for_object(size_t(obj_idx)); + } +} + +void ObjectList::invalidate_cut_info_for_object(int obj_idx) +{ + ModelObject* init_obj = object(obj_idx); + if (!init_obj->is_cut()) + return; + + take_snapshot(_u8L("Invalidate cut info")); + + const CutObjectBase cut_id = init_obj->cut_id; + // invalidate cut for related objects (which have the same cut_id) + for (size_t idx = 0; idx < m_objects->size(); idx++) + if (ModelObject* obj = object(int(idx)); obj->cut_id.is_equal(cut_id)) { + obj->invalidate_cut(); + update_info_items(idx); + add_volumes_to_object_in_list(idx); + } + + update_lock_icons_for_model(); +} + +void ObjectList::delete_all_connectors_for_selection() +{ + const wxDataViewItem item = GetSelection(); + if (item) { + const int obj_idx = m_objects_model->GetObjectIdByItem(item); + if (obj_idx >= 0) + delete_all_connectors_for_object(size_t(obj_idx)); + } +} + +void ObjectList::delete_all_connectors_for_object(int obj_idx) +{ + ModelObject* init_obj = object(obj_idx); + if (!init_obj->is_cut()) + return; + + take_snapshot(_u8L("Delete all connectors")); + + const CutObjectBase cut_id = init_obj->cut_id; + // Delete all connectors for related objects (which have the same cut_id) + Model& model = wxGetApp().plater()->model(); + for (int idx = int(m_objects->size())-1; idx >= 0; idx--) + if (ModelObject* obj = object(idx); obj->cut_id.is_equal(cut_id)) { + obj->delete_connectors(); + + if (obj->volumes.empty() || !obj->has_solid_mesh()) { + model.delete_object(idx); + m_objects_model->Delete(m_objects_model->GetItemById(idx)); + continue; + } + + update_info_items(idx); + add_volumes_to_object_in_list(idx); + changed_object(int(idx)); + } + + update_lock_icons_for_model(); +} + bool ObjectList::can_merge_to_multipart_object() const { if (has_selected_cut_object()) @@ -3044,10 +3137,9 @@ bool ObjectList::can_merge_to_multipart_object() const return false; // should be selected just objects - for (wxDataViewItem item : sels) { + for (wxDataViewItem item : sels) if (!(m_objects_model->GetItemType(item) & (itObject | itInstance))) return false; - } return true; } @@ -3072,97 +3164,6 @@ bool ObjectList::can_mesh_boolean() const return (*m_objects)[obj_idx]->volumes.size() > 1 || ((*m_objects)[obj_idx]->volumes.size() == 1 && (*m_objects)[obj_idx]->volumes[0]->is_splittable()); } -bool ObjectList::has_selected_cut_object() const -{ - wxDataViewItemArray sels; - GetSelections(sels); - if (sels.IsEmpty()) - return false; - - for (wxDataViewItem item : sels) { - const int obj_idx = m_objects_model->GetObjectIdByItem(item); - if (obj_idx >= 0 && object(obj_idx)->is_cut()) - return true; - } - - return false; -} - -void ObjectList::invalidate_cut_info_for_selection() -{ - const wxDataViewItem item = GetSelection(); - if (item) { - const int obj_idx = m_objects_model->GetObjectIdByItem(item); - if (obj_idx >= 0) - invalidate_cut_info_for_object(size_t(obj_idx)); - } -} - -void ObjectList::invalidate_cut_info_for_object(int obj_idx) -{ - ModelObject *init_obj = object(obj_idx); - if (!init_obj->is_cut()) return; - - take_snapshot("Invalidate cut info"); - - const CutObjectBase cut_id = init_obj->cut_id; - // invalidate cut for related objects (which have the same cut_id) - for (size_t idx = 0; idx < m_objects->size(); idx++) - if (ModelObject *obj = object(int(idx)); obj->cut_id.is_equal(cut_id)) { - obj->invalidate_cut(); - update_info_items(idx); - add_volumes_to_object_in_list(idx); - } - - update_lock_icons_for_model(); -} - -void ObjectList::delete_all_connectors_for_selection() -{ - const wxDataViewItem item = GetSelection(); - if (item) { - const int obj_idx = m_objects_model->GetObjectIdByItem(item); - if (obj_idx >= 0) - delete_all_connectors_for_object(size_t(obj_idx)); - } -} - -void ObjectList::delete_all_connectors_for_object(int obj_idx) -{ - ModelObject *init_obj = object(obj_idx); - if (!init_obj->is_cut()) - return; - - take_snapshot("Delete all connectors"); - - auto has_solid_mesh = [](ModelObject* obj) { - for (const ModelVolume *volume : obj->volumes) - if (volume->is_model_part()) return true; - return false; - }; - - const CutObjectBase cut_id = init_obj->cut_id; - // Delete all connectors for related objects (which have the same cut_id) - Model &model = wxGetApp().plater()->model(); - for (int idx = int(m_objects->size()) - 1; idx >= 0; idx--) - if (ModelObject *obj = object(idx); obj->cut_id.is_equal(cut_id)) { - obj->delete_connectors(); - - if (obj->volumes.empty() || !has_solid_mesh(obj)) { - model.delete_object(idx); - m_objects_model->Delete(m_objects_model->GetItemById(idx)); - continue; - } - - update_info_items(idx); - add_volumes_to_object_in_list(idx); - changed_object(int(idx)); - } - - update_lock_icons_for_model(); -} - - // NO_PARAMETERS function call means that changed object index will be determine from Selection() void ObjectList::changed_object(const int obj_idx/* = -1*/) const {