Cut Improvements: Fixed Undo/Redo for cut performance

+ ObjectList: Fixed items update after Invalidate cut information
+ CutGizmo: Fixed wrong mode selection after delete object and that add new
This commit is contained in:
YuSanka 2022-10-17 10:46:33 +02:00
parent 85af9b93f1
commit 64c57faf8f
7 changed files with 69 additions and 37 deletions

View File

@ -1259,11 +1259,9 @@ void ModelObject::apply_cut_connectors(const std::string& new_name)
void ModelObject::invalidate_cut()
{
for (ModelObject* obj : m_model->objects)
if (obj != this && obj->cut_id.is_equal(this->cut_id))
obj->cut_id.invalidate();
// invalidate own cut_id
this->cut_id.invalidate();
for (ModelVolume* volume : this->volumes)
volume->invalidate_cut_info();
}
void ModelObject::synchronize_model_after_cut()

View File

@ -444,7 +444,7 @@ public:
size_t parts_count() const;
static indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes);
void apply_cut_connectors(const std::string& name);
// invalidate cut state for this and related objects from the whole model
// invalidate cut state for this object and its connectors/volumes
void invalidate_cut();
void synchronize_model_after_cut();
void apply_cut_attributes(ModelObjectCutAttributes attributes);
@ -742,10 +742,16 @@ public:
{}
void set_processed() { is_processed = true; }
void invalidate() { is_connector = false; }
template<class Archive> inline void serialize(Archive& ar) {
ar(is_connector, is_processed, connector_type, radius_tolerance, height_tolerance);
}
};
CutInfo cut_info;
bool is_cut_connector() const { return cut_info.is_processed && cut_info.is_connector; }
void invalidate_cut_info() { cut_info.invalidate(); }
// The triangular model.
const TriangleMesh& mesh() const { return *m_mesh.get(); }
@ -954,7 +960,8 @@ private:
ObjectBase(other),
name(other.name), source(other.source), m_mesh(other.m_mesh), m_convex_hull(other.m_convex_hull),
config(other.config), m_type(other.m_type), object(object), m_transformation(other.m_transformation),
supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets)
supported_facets(other.supported_facets), seam_facets(other.seam_facets), mmu_segmentation_facets(other.mmu_segmentation_facets),
cut_info(other.cut_info)
{
assert(this->id().valid());
assert(this->config.id().valid());
@ -974,7 +981,8 @@ private:
}
// Providing a new mesh, therefore this volume will get a new unique ID assigned.
ModelVolume(ModelObject *object, const ModelVolume &other, TriangleMesh &&mesh) :
name(other.name), source(other.source), config(other.config), object(object), m_mesh(new TriangleMesh(std::move(mesh))), m_type(other.m_type), m_transformation(other.m_transformation)
name(other.name), source(other.source), config(other.config), object(object), m_mesh(new TriangleMesh(std::move(mesh))), m_type(other.m_type), m_transformation(other.m_transformation),
cut_info(other.cut_info)
{
assert(this->id().valid());
assert(this->config.id().valid());
@ -1016,7 +1024,7 @@ private:
}
template<class Archive> void load(Archive &ar) {
bool has_convex_hull;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull, cut_info);
cereal::load_by_value(ar, supported_facets);
cereal::load_by_value(ar, seam_facets);
cereal::load_by_value(ar, mmu_segmentation_facets);
@ -1032,7 +1040,7 @@ private:
}
template<class Archive> void save(Archive &ar) const {
bool has_convex_hull = m_convex_hull.get() != nullptr;
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull);
ar(name, source, m_mesh, m_type, m_material_id, m_transformation, m_is_splittable, has_convex_hull, cut_info);
cereal::save_by_value(ar, supported_facets);
cereal::save_by_value(ar, seam_facets);
cereal::save_by_value(ar, mmu_segmentation_facets);

View File

@ -156,7 +156,7 @@ public:
this->m_check_sum = rhs.check_sum();
this->m_connectors_cnt = rhs.connectors_cnt() ;
}
CutObjectBase operator=(const CutObjectBase& other) {
CutObjectBase& operator=(const CutObjectBase& other) {
this->copy(other);
return *this;
}
@ -179,6 +179,13 @@ public:
size_t connectors_cnt() const { return m_connectors_cnt; }
void increase_connectors_cnt(size_t connectors_cnt) { m_connectors_cnt += connectors_cnt; }
private:
friend class cereal::access;
template<class Archive> void serialize(Archive& ar) {
ar(cereal::base_class<ObjectBase>(this));
ar(m_check_sum, m_connectors_cnt);
}
};
// Unique object / instance ID for the wipe tower.

View File

@ -2458,19 +2458,37 @@ bool ObjectList::has_selected_cut_object() const
return false;
}
void ObjectList::invalidate_cut_info_for_selection()
{
wxDataViewItemArray sels;
GetSelections(sels);
if (sels.IsEmpty())
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(size_t obj_idx)
{
ModelObject* init_obj = object(int(obj_idx));
if (!init_obj->is_cut())
return;
for (wxDataViewItem item : sels) {
const int obj_idx = m_objects_model->GetObjectIdByItem(item);
if (obj_idx >= 0 && object(obj_idx)->is_cut())
object(obj_idx)->invalidate_cut();
}
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);
};
// 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);
// invalidate own cut information
invalidate_cut(size_t(obj_idx));
update_lock_icons_for_model();
}
@ -2970,8 +2988,6 @@ void ObjectList::update_lock_icons_for_model()
bool ObjectList::delete_from_model_and_list(const ItemType type, const int obj_idx, const int sub_obj_idx)
{
// take_snapshot(_(L("Delete Selected Item"))); // #ysFIXME - delete this redundant snapshot after test
if (type & (itObject | itVolume | itInstance)) {
if (type & itObject) {
bool was_cut = object(obj_idx)->is_cut();
@ -2983,7 +2999,7 @@ bool ObjectList::delete_from_model_and_list(const ItemType type, const int obj_i
}
return false;
}
else if (del_subobject_from_object(obj_idx, sub_obj_idx, type)) {
if (del_subobject_from_object(obj_idx, sub_obj_idx, type)) {
type == itVolume ? delete_volume_from_list(obj_idx, sub_obj_idx) :
delete_instance_from_list(obj_idx, sub_obj_idx);
return true;
@ -3189,6 +3205,8 @@ void ObjectList::remove()
if (m_objects_model->InvalidItem(item)) // item can be deleted for this moment (like last 2 Instances or Volumes)
continue;
parent = delete_item(item);
if (parent == item && m_objects_model->GetItemType(item) & itObject) // Object wasn't deleted
break;
}
}

View File

@ -279,6 +279,7 @@ 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);
bool can_merge_to_multipart_object() const;
bool can_merge_to_single_object() const;

View File

@ -1223,11 +1223,10 @@ bool GLGizmoCut3D::update_bb()
on_unregister_raycasters_for_picking();
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info()) {
clear_selection();
clear_selection();
if (CommonGizmosDataObjects::SelectionInfo* selection = m_c->selection_info())
m_selected.resize(selection->model_object()->cut_connectors.size(), false);
m_connectors_editing = !m_selected.empty();
}
m_connectors_editing = !m_selected.empty();
return true;
}
@ -1811,6 +1810,9 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
if (!mo)
return;
// deactivate CutGizmo and than perform a cut
m_parent.reset_all_gizmos();
// m_cut_z is the distance from the bed. Subtract possible SLA elevation.
const double sla_shift_z = selection.get_first_volume()->get_sla_shift_z();
const double object_cut_z = m_plane_center.z() - sla_shift_z;
@ -1820,13 +1822,12 @@ void GLGizmoCut3D::perform_cut(const Selection& selection)
cut_center_offset[Z] -= sla_shift_z;
if (0.0 < object_cut_z && can_perform_cut()) {
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane"));
bool create_dowels_as_separate_object = false;
const bool has_connectors = !mo->cut_connectors.empty();
{
Plater::TakeSnapshot snapshot(wxGetApp().plater(), _L("Cut by Plane"));
// update connectors pos as offset of its center before cut performing
apply_connectors_in_model(mo, create_dowels_as_separate_object);
}
// update connectors pos as offset of its center before cut performing
apply_connectors_in_model(mo, create_dowels_as_separate_object);
plater->cut(object_idx, instance_idx, assemble_transform(cut_center_offset) * m_rotation_m,
only_if(has_connectors ? true : m_keep_upper, ModelObjectCutAttribute::KeepUpper) |

View File

@ -3020,8 +3020,6 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx)
dialog.SetButtonLabel(wxID_YES, _L("Delete object"));
if (dialog.ShowModal() == wxID_CANCEL)
return false;
// unmark all related CutParts of initial object
obj->invalidate_cut();
}
wxString snapshot_label = _L("Delete Object");
@ -3029,6 +3027,10 @@ bool Plater::priv::delete_object_from_model(size_t obj_idx)
snapshot_label += ": " + wxString::FromUTF8(obj->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label);
m_worker.cancel_all();
if (obj->is_cut())
sidebar->obj_list()->invalidate_cut_info_for_object(obj_idx);
model.delete_object(obj_idx);
update();
object_list_changed();
@ -5940,9 +5942,8 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_mat
wxCHECK_RET(instance_idx < object->instances.size(), "instance_idx out of bounds");
this->suppress_snapshots();
wxBusyCursor wait;
const auto new_objects = object->cut(instance_idx, cut_matrix, attributes);
model().delete_object(obj_idx);
@ -5951,8 +5952,6 @@ void Plater::cut(size_t obj_idx, size_t instance_idx, const Transform3d& cut_mat
// suppress to call selection update for Object List to avoid call of early Gizmos on/off update
p->load_model_objects(new_objects, false, false);
this->allow_snapshots();
// now process all updates of the 3d scene
update();
// Update InfoItems in ObjectList after update() to use of a correct value of the GLCanvas3D::is_sinking(),