mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-16 03:07:55 -06:00
Fixed a crash when deleting the last object with autocenter enabled (prusa3d/PrusaSlicer#11186).
(cherry picked from commit prusa3d/PrusaSlicer@926af1ab8d)
This commit is contained in:
parent
f6e4c48fe7
commit
67c1f40eae
3 changed files with 104 additions and 93 deletions
|
@ -2289,6 +2289,14 @@ int ModelObject::get_repaired_errors_count(const int vol_idx /*= -1*/) const
|
||||||
stats.facets_reversed + stats.backwards_edges;
|
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)
|
void ModelVolume::set_material_id(t_model_material_id material_id)
|
||||||
{
|
{
|
||||||
m_material_id = material_id;
|
m_material_id = material_id;
|
||||||
|
|
|
@ -523,6 +523,8 @@ public:
|
||||||
// Get count of errors in the mesh( or all object's meshes, if volume index isn't defined)
|
// 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;
|
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 is_cut() const { return cut_id.id().valid(); }
|
||||||
bool has_connectors() const;
|
bool has_connectors() const;
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -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/libslic3r.h"
|
||||||
#include "libslic3r/PresetBundle.hpp"
|
#include "libslic3r/PresetBundle.hpp"
|
||||||
#include "GUI_ObjectList.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();
|
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<size condition is a workaround for https://github.com/prusa3d/PrusaSlicer/issues/11186,
|
||||||
|
// but not the correct fix. The deleted item probably should not be in sels in the first place.
|
||||||
|
if (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
|
bool ObjectList::can_merge_to_multipart_object() const
|
||||||
{
|
{
|
||||||
if (has_selected_cut_object())
|
if (has_selected_cut_object())
|
||||||
|
@ -3044,10 +3137,9 @@ bool ObjectList::can_merge_to_multipart_object() const
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// should be selected just objects
|
// should be selected just objects
|
||||||
for (wxDataViewItem item : sels) {
|
for (wxDataViewItem item : sels)
|
||||||
if (!(m_objects_model->GetItemType(item) & (itObject | itInstance)))
|
if (!(m_objects_model->GetItemType(item) & (itObject | itInstance)))
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
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());
|
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()
|
// NO_PARAMETERS function call means that changed object index will be determine from Selection()
|
||||||
void ObjectList::changed_object(const int obj_idx/* = -1*/) const
|
void ObjectList::changed_object(const int obj_idx/* = -1*/) const
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue