Cut: Extension for delete parts from cut objects.

When try to delete something from the cut object, than not just inform the users about an impossibility of this action,
but allow them to invalidate a cut information or delete all connectors from related objects, but leave the cut info.
This commit is contained in:
YuSanka 2022-12-01 11:08:33 +01:00
parent b51d478031
commit ba8b81b27e
5 changed files with 121 additions and 28 deletions

View File

@ -1279,6 +1279,14 @@ void ModelObject::invalidate_cut()
volume->invalidate_cut_info();
}
void ModelObject::delete_connectors()
{
for (int id = int(this->volumes.size()) - 1; id >= 0; id--) {
if (volumes[id]->is_cut_connector())
this->delete_volume(size_t(id));
}
}
void ModelObject::synchronize_model_after_cut()
{
for (ModelObject* obj : m_model->objects) {
@ -1994,6 +2002,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;

View File

@ -449,6 +449,8 @@ public:
void apply_cut_connectors(const std::string& name);
// invalidate cut state for this object and its connectors/volumes
void invalidate_cut();
// delete volumes which are marked as connector for this object
void delete_connectors();
void synchronize_model_after_cut();
void apply_cut_attributes(ModelObjectCutAttributes attributes);
void clone_for_cut(ModelObject **obj);
@ -482,6 +484,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;

View File

@ -1880,6 +1880,7 @@ bool ObjectList::del_subobject_item(wxDataViewItem& item)
wxDataViewItem parent = m_objects_model->GetParent(item);
InfoItemType item_info_type = m_objects_model->GetInfoItemType(item);
if (type & itSettings)
del_settings_from_config(parent);
else if (type & itInstanceRoot && obj_idx != -1)
@ -1889,7 +1890,7 @@ bool ObjectList::del_subobject_item(wxDataViewItem& item)
else if (type & itLayer && obj_idx != -1)
del_layer_from_object(obj_idx, m_objects_model->GetLayerRangeByItem(item));
else if (type & itInfo && obj_idx != -1)
del_info_item(obj_idx, m_objects_model->GetInfoItemType(item));
del_info_item(obj_idx, item_info_type);
else if (idx == -1 || !del_subobject_from_object(obj_idx, idx, type))
return false;
@ -1898,9 +1899,12 @@ bool ObjectList::del_subobject_item(wxDataViewItem& item)
const std::string& icon_name = get_warning_icon_name(object(obj_idx)->get_object_stl_stats());
m_objects_model->UpdateWarningIcon(parent, icon_name);
}
m_objects_model->Delete(item);
if (!(type & itInfo) || item_info_type != InfoItemType::CutConnectors) {
// Connectors Item is already updated/deleted inside the del_info_item()
m_objects_model->Delete(item);
update_info_items(obj_idx);
}
return true;
}
@ -1926,7 +1930,10 @@ void ObjectList::del_info_item(const int obj_idx, InfoItemType type)
break;
case InfoItemType::CutConnectors:
show_error(nullptr, _L("Connectors cannot be deleted from cut object."));
if (!del_from_cut_object(true)) {
// there is no need to post EVT_GLCANVAS_SCHEDULE_BACKGROUND_PROCESS if nothing was changed
return;
}
break;
case InfoItemType::MmuSegmentation:
@ -2018,6 +2025,38 @@ void ObjectList::del_layers_from_object(const int obj_idx)
changed_object(obj_idx);
}
bool ObjectList::del_from_cut_object(bool is_cut_connector, bool is_model_part/* = false*/, bool is_negative_volume/* = false*/)
{
const long buttons_style = is_cut_connector ? (wxYES | wxNO | wxCANCEL) : (wxYES | wxCANCEL);
const wxString title = is_cut_connector ? _L("Delete connector from object which is a part of cut") :
is_model_part ? _L("Delete solid part from object which is a part of cut") :
is_negative_volume ? _L("Delete negative volume from object which is a part of cut") : "";
const wxString msg_end = is_cut_connector ? ("\n" + _L("To save cut correspondence you can delete all connectors from all related objects.")) : "";
InfoDialog dialog(wxGetApp().plater(), title,
_L("This action will break a cut correspondence.\n"
"After that PrusaSlicer can't guarantee model consistency.\n"
"\n"
"To manipulate with solid parts or negative volumes you have to invalidate cut infornation first." + msg_end ),
false, buttons_style | wxCANCEL_DEFAULT | wxICON_WARNING);
dialog.SetButtonLabel(wxID_YES, _L("Invalidate cut info"));
if (is_cut_connector)
dialog.SetButtonLabel(wxID_NO, _L("Delete all connectors"));
const int answer = dialog.ShowModal();
if (answer == wxID_CANCEL)
return false;
if (answer == wxID_YES)
invalidate_cut_info_for_selection();
else if (answer == wxID_NO)
delete_all_connectors_for_selection();
return true;
}
bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, const int type)
{
assert(idx >= 0);
@ -2039,16 +2078,11 @@ bool ObjectList::del_subobject_from_object(const int obj_idx, const int idx, con
Slic3r::GUI::show_error(nullptr, _L("From Object List You can't delete the last solid part from object."));
return false;
}
if (object->is_cut()) {
if (volume->is_model_part()) {
Slic3r::GUI::show_error(nullptr, _L("Solid part cannot be deleted from cut object."));
if (object->is_cut() && (volume->is_model_part() || volume->is_negative_volume())) {
del_from_cut_object(volume->is_cut_connector(), volume->is_model_part(), volume->is_negative_volume());
// in any case return false to break the deletion
return false;
}
if (volume->is_negative_volume()) {
Slic3r::GUI::show_error(nullptr, _L("Negative volume cannot be deleted from cut object."));
return false;
}
}
take_snapshot(_L("Delete Subobject"));
@ -2489,6 +2523,7 @@ bool ObjectList::has_selected_cut_object() const
return false;
}
void ObjectList::invalidate_cut_info_for_selection()
{
const wxDataViewItem item = GetSelection();
@ -2499,27 +2534,61 @@ void ObjectList::invalidate_cut_info_for_selection()
}
}
void ObjectList::invalidate_cut_info_for_object(size_t obj_idx)
void ObjectList::invalidate_cut_info_for_object(int obj_idx)
{
ModelObject* init_obj = object(int(obj_idx));
ModelObject* init_obj = object(obj_idx);
if (!init_obj->is_cut())
return;
take_snapshot(_L("Invalidate cut info"));
auto invalidate_cut = [this](size_t obj_idx) {
object(int(obj_idx))->invalidate_cut();
update_info_items(obj_idx);
add_volumes_to_object_in_list(obj_idx);
};
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(idx); obj != init_obj && obj->cut_id.is_equal(init_obj->cut_id))
invalidate_cut(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);
}
// invalidate own cut information
invalidate_cut(size_t(obj_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(_L("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();
}
@ -3044,6 +3113,7 @@ bool ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it
return false;
m_prevent_list_events = true;
ScopeGuard sg_prevent_list_events = ScopeGuard([this]() { m_prevent_list_events = false; });
std::set<size_t> modified_objects_ids;
for (std::vector<ItemForDelete>::const_reverse_iterator item = items_for_delete.rbegin(); item != items_for_delete.rend(); ++item) {
@ -3059,7 +3129,7 @@ bool ObjectList::delete_from_model_and_list(const std::vector<ItemForDelete>& it
}
else {
if (!del_subobject_from_object(item->obj_idx, item->sub_obj_idx, item->type))
continue;
return false;// continue;
if (item->type&itVolume) {
m_objects_model->Delete(m_objects_model->GetItemByVolumeId(item->obj_idx, item->sub_obj_idx));
ModelObject* obj = object(item->obj_idx);

View File

@ -266,6 +266,7 @@ public:
void del_instances_from_object(const int obj_idx);
void del_layer_from_object(const int obj_idx, const t_layer_height_range& layer_range);
void del_layers_from_object(const int obj_idx);
bool del_from_cut_object(bool is_connector, bool is_model_part = false, bool is_negative_volume = false);
bool del_subobject_from_object(const int obj_idx, const int idx, const int type);
void del_info_item(const int obj_idx, InfoItemType type);
void split();
@ -282,7 +283,9 @@ public:
bool can_split_instances();
bool has_selected_cut_object() const;
void invalidate_cut_info_for_selection();
void invalidate_cut_info_for_object(size_t obj_idx);
void invalidate_cut_info_for_object(int obj_idx);
void delete_all_connectors_for_selection();
void delete_all_connectors_for_object(int obj_idx);
bool can_merge_to_multipart_object() const;
bool can_merge_to_single_object() const;

View File

@ -3001,7 +3001,7 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx)
InfoDialog dialog(q, _L("Delete object which is a part of cut object"),
_L("You try to delete an object which is a part of a cut object.\n"
"This action will break a cut correspondence.\n"
"After that PrusaSlicer can't garantie model consistency"),
"After that PrusaSlicer can't guarantee model consistency"),
false, wxYES | wxCANCEL | wxCANCEL_DEFAULT | wxICON_WARNING);
dialog.SetButtonLabel(wxID_YES, _L("Delete object"));
if (dialog.ShowModal() == wxID_CANCEL)