* Suppress to delete/add a SolidPart/NegativeVolume from/for objects which are marked as "is cut"
* Suppress to delete Instances which are marked as "is cut"
* Allow delete an object which is marked as "is cut", but show warning message about break of the "cut consistency".
  And if this deletion was performed, the all related objects will be unmarked.
* m_connectors_cnt is added into CutObjectBase class to correct synchronization of a connectors count between related objects
This commit is contained in:
YuSanka 2022-04-12 14:27:34 +02:00
parent 463e9ab530
commit c29b7b1eef
6 changed files with 58 additions and 18 deletions

View file

@ -1,5 +1,4 @@
#include "Model.hpp"
#include "Model.hpp"
#include "libslic3r.h"
#include "BuildVolume.hpp"
#include "Exception.hpp"
@ -611,7 +610,6 @@ ModelObject& ModelObject::assign_copy(const ModelObject &rhs)
this->layer_height_profile = rhs.layer_height_profile;
this->printable = rhs.printable;
this->origin_translation = rhs.origin_translation;
this->cut_connectors_count = rhs.cut_connectors_count;
this->cut_id.copy(rhs.cut_id);
m_bounding_box = rhs.m_bounding_box;
m_bounding_box_valid = rhs.m_bounding_box_valid;
@ -1382,8 +1380,7 @@ void ModelObject::apply_cut_connectors(const std::string& name, CutConnectorAttr
indexed_triangle_set connector_mesh = get_connector_mesh(connector_attributes);
size_t connector_id = cut_connectors_count;
size_t connector_id = cut_id.connectors_cnt();
for (const CutConnector& connector : cut_connectors) {
TriangleMesh mesh = TriangleMesh(connector_mesh);
// Mesh will be centered when loading.
@ -1400,18 +1397,26 @@ void ModelObject::apply_cut_connectors(const std::string& name, CutConnectorAttr
new_volume->name = name + "-" + std::to_string(++connector_id);
new_volume->source.is_connector = true;
}
cut_id.increase_connectors_cnt(cut_connectors.size());
cut_connectors_count += cut_connectors.size();
// delete all connectors
cut_connectors.clear();
}
void ModelObject::invalidate_cut()
{
for (ModelObject* obj : m_model->objects)
if (obj != this && obj->cut_id.is_equal(this->cut_id))
obj->cut_id.ivalidate();
}
void ModelObject::synchronize_model_after_cut()
{
for (ModelObject* obj : m_model->objects) {
if (obj == this || obj->cut_id.is_equal(this->cut_id))
continue;
obj->cut_id.set_check_sum(this->cut_id.check_sum());
if (obj->is_cut() && obj->cut_id.has_same_id(this->cut_id))
obj->cut_id.copy(this->cut_id);
}
}

View file

@ -346,8 +346,6 @@ public:
// Connectors to be added into the object after cut
CutConnectors cut_connectors;
// count of connectors in object
size_t cut_connectors_count{ 0 };
CutObjectBase cut_id;
/* This vector accumulates the total translation applied to the object by the
@ -437,6 +435,8 @@ public:
ModelObjectPtrs cut(size_t instance, coordf_t z, ModelObjectCutAttributes attributes);
static indexed_triangle_set get_connector_mesh(CutConnectorAttributes connector_attributes);
void apply_cut_connectors(const std::string& name, CutConnectorAttributes connector_attributes);
// invalidate cut state for this and related objects from the whole model
void invalidate_cut();
void synchronize_model_after_cut();
ModelObjectPtrs cut(size_t instance, const Vec3d& cut_center, const Vec3d& cut_rotation, ModelObjectCutAttributes attributes);
void split(ModelObjectPtrs* new_objects);

View file

@ -130,8 +130,10 @@ private:
class CutObjectBase : public ObjectBase
{
// check sum of CutPartsObject
// check sum of CutParts in initial Object
size_t m_check_sum{ 1 };
// connectors count
size_t m_connectors_cnt{ 0 };
public:
// Default Constructor to assign an invalid ID
@ -148,19 +150,31 @@ public:
void copy(const CutObjectBase& rhs) {
this->copy_id(rhs);
this->m_check_sum = rhs.check_sum();
this->m_connectors_cnt = rhs.connectors_cnt() ;
}
CutObjectBase operator=(const CutObjectBase& other) {
this->copy(other);
return *this;
}
void ivalidate() {
set_invalid_id();
m_check_sum = 1;
m_connectors_cnt = 0;
}
void init() { this->set_new_unique_id(); }
bool has_same_id(const CutObjectBase& rhs) { return this->id() == rhs.id(); }
bool is_equal(const CutObjectBase& rhs) { return this->id() == rhs.id() && this->check_sum() == rhs.check_sum(); }
bool is_equal(const CutObjectBase& rhs) { return this->id() == rhs.id() &&
this->check_sum() == rhs.check_sum() &&
this->connectors_cnt() == rhs.connectors_cnt() ; }
size_t check_sum() const { return m_check_sum; }
void set_check_sum(size_t cs) { m_check_sum = cs; }
void increase_check_sum(size_t cnt) { m_check_sum += cnt; }
size_t connectors_cnt() const { return m_connectors_cnt; }
void increase_connectors_cnt(size_t connectors_cnt) { m_connectors_cnt += connectors_cnt; }
};
// Unique object / instance ID for the wipe tower.

View file

@ -494,7 +494,9 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
append_menu_item(menu, wxID_ANY, _(ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART)].first), "",
[](wxCommandEvent&) { obj_list()->load_subobject(ModelVolumeType::MODEL_PART); },
ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::MODEL_PART)].second, nullptr,
[]() { return obj_list()->is_instance_or_object_selected(); }, m_parent);
[]() { return obj_list()->is_instance_or_object_selected()
&& !obj_list()->is_selected_object_cut();
}, m_parent);
}
if (mode == comSimple) {
append_menu_item(menu, wxID_ANY, _(ADD_VOLUME_MENU_ITEMS[int(ModelVolumeType::SUPPORT_ENFORCER)].first), "",
@ -515,7 +517,10 @@ void MenuFactory::append_menu_items_add_volume(wxMenu* menu)
wxMenu* sub_menu = append_submenu_add_generic(menu, ModelVolumeType(type));
append_submenu(menu, sub_menu, wxID_ANY, _(item.first), "", item.second,
[]() { return obj_list()->is_instance_or_object_selected(); }, m_parent);
[type]() {
bool can_add = type < size_t(ModelVolumeType::PARAMETER_MODIFIER) ? !obj_list()->is_selected_object_cut() : true;
return can_add && obj_list()->is_instance_or_object_selected();
}, m_parent);
}
append_menu_item_layers_editing(menu);

View file

@ -1794,7 +1794,7 @@ struct Plater::priv
void select_all();
void deselect_all();
void remove(size_t obj_idx);
void delete_object_from_model(size_t obj_idx);
bool delete_object_from_model(size_t obj_idx);
void delete_all_objects_from_model();
void reset();
void mirror(Axis axis);
@ -2959,16 +2959,32 @@ void Plater::priv::remove(size_t obj_idx)
}
void Plater::priv::delete_object_from_model(size_t obj_idx)
bool Plater::priv::delete_object_from_model(size_t obj_idx)
{
// check if object isn't cut
// show warning message that "cut consistancy" will not be supported any more
ModelObject* obj = model.objects[obj_idx];
if (obj->is_cut()) {
MessageDialog dialog(q, _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"),
_L("Delete object which is a part of cut object"), wxYES | wxCANCEL | wxCANCEL_DEFAULT);
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");
if (! model.objects[obj_idx]->name.empty())
snapshot_label += ": " + wxString::FromUTF8(model.objects[obj_idx]->name.c_str());
if (!obj->name.empty())
snapshot_label += ": " + wxString::FromUTF8(obj->name.c_str());
Plater::TakeSnapshot snapshot(q, snapshot_label);
m_worker.cancel_all();
model.delete_object(obj_idx);
update();
object_list_changed();
return true;
}
void Plater::priv::delete_all_objects_from_model()
@ -5679,7 +5695,7 @@ void Plater::reset_with_confirm()
reset();
}
void Plater::delete_object_from_model(size_t obj_idx) { p->delete_object_from_model(obj_idx); }
bool Plater::delete_object_from_model(size_t obj_idx) { return p->delete_object_from_model(obj_idx); }
void Plater::remove_selected()
{

View file

@ -242,7 +242,7 @@ public:
void remove(size_t obj_idx);
void reset();
void reset_with_confirm();
void delete_object_from_model(size_t obj_idx);
bool delete_object_from_model(size_t obj_idx);
void remove_selected();
void increase_instances(size_t num = 1);
void decrease_instances(size_t num = 1);