Fixed DnD for "Model part" volumes inside the object

Fixed volumes order inside the object
This commit is contained in:
YuSanka 2021-06-02 12:52:47 +02:00
parent 2d9953069a
commit 7eebd56b5f
7 changed files with 101 additions and 96 deletions

View file

@ -652,23 +652,10 @@ ModelVolume* ModelObject::add_volume(const TriangleMesh &mesh)
return v;
}
static void add_v_to_volumes(ModelVolumePtrs* volumes, ModelVolume* v)
{
if (volumes->empty() || v->type() >= volumes->back()->type())
volumes->push_back(v);
else {
for (int pos = volumes->size() - 1; pos >= 0; pos--)
if (v->type() >= (*volumes)[pos]->type()) {
volumes->insert(volumes->begin() + pos + 1, v);
break;
}
}
}
ModelVolume* ModelObject::add_volume(TriangleMesh &&mesh, ModelVolumeType type /*= ModelVolumeType::MODEL_PART*/)
{
ModelVolume* v = new ModelVolume(this, std::move(mesh), type);
add_v_to_volumes(&(this->volumes), v);
this->volumes.push_back(v);
v->center_geometry_after_creation();
this->invalidate_bounding_box();
return v;
@ -679,7 +666,7 @@ ModelVolume* ModelObject::add_volume(const ModelVolume &other, ModelVolumeType t
ModelVolume* v = new ModelVolume(this, other);
if (type != ModelVolumeType::INVALID && v->type() != type)
v->set_type(type);
add_v_to_volumes(&(this->volumes), v);
this->volumes.push_back(v);
// The volume should already be centered at this point of time when copying shared pointers of the triangle mesh and convex hull.
// v->center_geometry_after_creation();
// this->invalidate_bounding_box();
@ -728,6 +715,20 @@ void ModelObject::clear_volumes()
this->invalidate_bounding_box();
}
void ModelObject::sort_volumes(bool full_sort)
{
// sort volumes inside the object to order "Model Part, Negative Volume, Modifier, Support Blocker and Support Enforcer. "
if (full_sort)
std::stable_sort(volumes.begin(), volumes.end(), [](ModelVolume* vl, ModelVolume* vr) {
return vl->type() < vr->type();
});
// sort have to controll "place" of the support blockers/enforcers. But one of the model parts have to be on the first place.
else
std::stable_sort(volumes.begin(), volumes.end(), [](ModelVolume* vl, ModelVolume* vr) {
return vl->type() > ModelVolumeType::PARAMETER_MODIFIER && vl->type() < vr->type();
});
}
ModelInstance* ModelObject::add_instance()
{
ModelInstance* i = new ModelInstance(this);

View file

@ -277,6 +277,7 @@ public:
ModelVolume* add_volume(const ModelVolume &volume, TriangleMesh &&mesh);
void delete_volume(size_t idx);
void clear_volumes();
void sort_volumes(bool full_sort);
bool is_multiparts() const { return volumes.size() > 1; }
ModelInstance* add_instance();

View file

@ -401,7 +401,12 @@ void GLVolume::set_render_color()
void GLVolume::set_color_from_model_volume(const ModelVolume *model_volume)
{
if (model_volume->is_modifier()) {
if (model_volume->is_negative_volume()) {
color[0] = 0.2f;
color[1] = 0.2f;
color[2] = 0.2f;
}
else if (model_volume->is_modifier()) {
color[0] = 0.2f;
color[1] = 1.0f;
color[2] = 0.2f;

View file

@ -738,23 +738,9 @@ void ObjectList::paste_volumes_into_list(int obj_idx, const ModelVolumePtrs& vol
if (volumes.empty())
return;
const auto object_item = m_objects_model->GetItemById(obj_idx);
wxDataViewItemArray items;
for (const ModelVolume* volume : volumes)
{
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(object_item, wxString::FromUTF8(volume->name.c_str()), volume->type(),
volume->get_mesh_errors_count()>0 ,
volume->config.has("extruder") ? volume->config.extruder() : 0);
add_settings_item(vol_item, &volume->config.get());
items.Add(vol_item);
}
changed_object(obj_idx);
if (items.size() > 1)
{
wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [volumes](const ModelVolume* volume) {
return std::find(volumes.begin(), volumes.end(), volume) != volumes.end(); });
if (items.size() > 1) {
m_selection_mode = smVolume;
m_last_selected_item = wxDataViewItem(nullptr);
}
@ -1149,7 +1135,7 @@ bool ObjectList::can_drop(const wxDataViewItem& item) const
if (dragged_item_v_type == item_v_type && dragged_item_v_type != ModelVolumeType::MODEL_PART)
return true;
if (wxGetApp().app_config->get("order_volumes") == "1" || // we can't reorder volumes outside of types
if ((wxGetApp().app_config->get("order_volumes") == "1" && dragged_item_v_type != item_v_type) || // we can't reorder volumes outside of types
item_v_type >= ModelVolumeType::SUPPORT_BLOCKER) // support blockers/enforcers can't change its place
return false;
@ -1359,27 +1345,25 @@ void ObjectList::load_subobject(ModelVolumeType type)
take_snapshot(_L("Load Part"));
std::vector<std::pair<wxString, bool>> volumes_info;
load_part((*m_objects)[obj_idx], volumes_info, type);
std::vector<ModelVolume*> volumes;
load_part((*m_objects)[obj_idx], volumes, type);
wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [volumes](const ModelVolume* volume) {
return std::find(volumes.begin(), volumes.end(), volume) != volumes.end(); });
changed_object(obj_idx);
if (type == ModelVolumeType::MODEL_PART)
// update printable state on canvas
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx);
wxDataViewItem sel_item;
for (const auto& volume : volumes_info )
sel_item = m_objects_model->AddVolumeChild(item, volume.first, type, volume.second);
if (sel_item)
select_item(sel_item);
if (items.size() > 1) {
m_selection_mode = smVolume;
m_last_selected_item = wxDataViewItem(nullptr);
}
select_items(items);
selection_changed();
}
void ObjectList::load_part( ModelObject* model_object,
std::vector<std::pair<wxString, bool>> &volumes_info,
ModelVolumeType type)
void ObjectList::load_part(ModelObject* model_object, std::vector<ModelVolume*>& added_volumes, ModelVolumeType type)
{
wxWindow* parent = wxGetApp().tab_panel()->GetPage(0);
@ -1416,11 +1400,10 @@ void ObjectList::load_part( ModelObject* model_object,
volume->translate(delta);
auto new_volume = model_object->add_volume(*volume, type);
new_volume->name = boost::filesystem::path(input_file).filename().string();
volumes_info.push_back(std::make_pair(from_u8(new_volume->name), new_volume->get_mesh_errors_count()>0));
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
added_volumes.push_back(new_volume);
}
}
}
@ -1507,14 +1490,19 @@ void ObjectList::load_generic_subobject(const std::string& type_name, const Mode
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
changed_object(obj_idx);
select_item([this, obj_idx, new_volume]() {
wxDataViewItem sel_item;
wxDataViewItemArray items = reorder_volumes_and_get_selection(obj_idx, [new_volume](const ModelVolume* volume) { return volume == new_volume; });
if (!items.IsEmpty())
sel_item = items.front();
return sel_item;
});
if (type == ModelVolumeType::MODEL_PART)
// update printable state on canvas
wxGetApp().plater()->canvas3D()->update_instance_printable_state_for_object((size_t)obj_idx);
const auto object_item = m_objects_model->GetTopParent(GetSelection());
select_item([this, object_item, name, type, new_volume]() { return m_objects_model->AddVolumeChild(object_item, name, type,
new_volume->get_mesh_errors_count() > 0); });
selection_changed();
}
@ -1556,6 +1544,7 @@ void ObjectList::load_mesh_object(const TriangleMesh &mesh, const wxString &name
new_object->add_instance(); // each object should have at list one instance
ModelVolume* new_volume = new_object->add_volume(mesh);
new_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
new_volume->name = into_u8(name);
// set a default extruder value, since user can't add it manually
new_volume->config.set_key_value("extruder", new ConfigOptionInt(0));
@ -1784,7 +1773,7 @@ void ObjectList::split()
for (const ModelVolume* volume : model_object->volumes) {
const wxDataViewItem& vol_item = m_objects_model->AddVolumeChild(parent, from_u8(volume->name),
volume->is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART,
volume->type(),// is_modifier() ? ModelVolumeType::PARAMETER_MODIFIER : ModelVolumeType::MODEL_PART,
volume->get_mesh_errors_count()>0,
volume->config.has("extruder") ? volume->config.extruder() : 0,
false);
@ -1940,6 +1929,7 @@ void ObjectList::merge(bool to_multipart_object)
Vec3d vol_offset = volume_offset_correction* new_volume->get_offset();
new_volume->set_offset(vol_offset);
}
new_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
// merge settings
auto new_opt_keys = config.keys();
@ -3456,12 +3446,12 @@ void ObjectList::change_part_type()
if (!volume)
return;
const int obj_idx = get_selected_obj_idx();
if (obj_idx < 0) return;
const ModelVolumeType type = volume->type();
if (type == ModelVolumeType::MODEL_PART)
{
const int obj_idx = get_selected_obj_idx();
if (obj_idx < 0) return;
int model_part_cnt = 0;
for (auto vol : (*m_objects)[obj_idx]->volumes) {
if (vol->type() == ModelVolumeType::MODEL_PART)
@ -3480,27 +3470,12 @@ void ObjectList::change_part_type()
if (new_type == type || new_type == ModelVolumeType::INVALID)
return;
take_snapshot(_(L("Change Part Type")));
take_snapshot(_L("Change Part Type"));
volume->set_type(new_type);
wxDataViewItem item = GetSelection();
if (m_objects_model->GetItemType(item) != itVolume && m_objects_model->GetItemType(m_objects_model->GetParent(item)) == itVolume)
item = m_objects_model->GetParent(item);
m_objects_model->SetVolumeType(item, new_type);
changed_object(get_selected_obj_idx());
// Update settings showing, if we have it
//(we show additional settings for Part and Modifier and hide it for Support Blocker/Enforcer)
const auto settings_item = m_objects_model->GetSettingsItem(item);
if (settings_item &&
(new_type == ModelVolumeType::SUPPORT_ENFORCER || new_type == ModelVolumeType::SUPPORT_BLOCKER || new_type == ModelVolumeType::NEGATIVE_VOLUME)) {
m_objects_model->Delete(settings_item);
}
else if (!settings_item &&
(new_type == ModelVolumeType::MODEL_PART || new_type == ModelVolumeType::PARAMETER_MODIFIER)) {
add_settings_item(item, &volume->config.get());
}
wxDataViewItemArray sel = reorder_volumes_and_get_selection(obj_idx, [volume](const ModelVolume* vol) { return vol == volume; });
if (!sel.IsEmpty())
select_item(sel.front());
}
void ObjectList::last_volume_is_deleted(const int obj_idx)
@ -3906,6 +3881,42 @@ void ObjectList::set_extruder_for_selected_items(const int extruder) const
wxGetApp().plater()->update();
}
wxDataViewItemArray ObjectList::reorder_volumes_and_get_selection(int obj_idx, std::function<bool(const ModelVolume*)> add_to_selection/* = nullptr*/)
{
wxDataViewItemArray items;
ModelObject* object = (*m_objects)[obj_idx];
object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
wxDataViewItem object_item = m_objects_model->GetItemById(obj_idx);
m_objects_model->DeleteVolumeChildren(object_item);
for (const ModelVolume* volume : object->volumes) {
wxDataViewItem vol_item = m_objects_model->AddVolumeChild(object_item, from_u8(volume->name),
volume->type(),
volume->get_mesh_errors_count() > 0,
volume->config.has("extruder") ? volume->config.extruder() : 0,
false);
// add settings to the part, if it has those
add_settings_item(vol_item, &volume->config.get());
if (add_to_selection && add_to_selection(volume))
items.Add(vol_item);
}
changed_object(obj_idx);
return items;
}
void ObjectList::apply_volumes_order()
{
if (wxGetApp().app_config->get("order_volumes") != "1" || !m_objects)
return;
for (int obj_idx = 0; m_objects->size(); obj_idx++)
reorder_volumes_and_get_selection(obj_idx);
}
void ObjectList::update_after_undo_redo()
{
m_prevent_canvas_selection_update = true;

View file

@ -238,7 +238,7 @@ public:
bool is_instance_or_object_selected();
void load_subobject(ModelVolumeType type);
void load_part(ModelObject* model_object, std::vector<std::pair<wxString, bool>> &volumes_info, ModelVolumeType type);
void load_part(ModelObject* model_object, std::vector<ModelVolume*> &added_volumes, ModelVolumeType type);
void load_generic_subobject(const std::string& type_name, const ModelVolumeType type);
void load_shape_object(const std::string &type_name);
void load_mesh_object(const TriangleMesh &mesh, const wxString &name, bool center = true);
@ -371,6 +371,8 @@ public:
void toggle_printable_state();
void set_extruder_for_selected_items(const int extruder) const ;
wxDataViewItemArray reorder_volumes_and_get_selection(int obj_idx, std::function<bool(const ModelVolume*)> add_to_selection = nullptr);
void apply_volumes_order();
private:
#ifdef __WXOSX__

View file

@ -368,25 +368,7 @@ wxDataViewItem ObjectDataViewModel::AddVolumeChild( const wxDataViewItem &parent
if (insert_position >= 0) insert_position++;
}
size_t new_volume_id = root->m_volumes_cnt;
// find insert_position in respect to the volume type
for (int pos = (insert_position < 0 ? (int)root->GetChildCount() : insert_position) - 1; pos >= 0; pos--) {
ObjectDataViewModelNode* node = root->GetNthChild(pos);
if (volume_type >= node->m_volume_type) {
insert_position = pos + 1;
new_volume_id = (size_t)(node->GetIdx()) + 1;
for (int new_pos = pos + 1; new_pos < (int)root->GetChildCount(); new_pos++) {
ObjectDataViewModelNode* new_node = root->GetNthChild(new_pos);
if (new_node->GetType() != itVolume)
break;
new_node->SetIdx(new_node->GetIdx() + 1);
}
break;
}
}
const auto node = new ObjectDataViewModelNode(root, name, volume_type, GetVolumeIcon(volume_type, has_errors), extruder_str, new_volume_id);
const auto node = new ObjectDataViewModelNode(root, name, volume_type, GetVolumeIcon(volume_type, has_errors), extruder_str, root->m_volumes_cnt);
insert_position < 0 ? root->Append(node) : root->Insert(node, insert_position);
// if part with errors is added, but object wasn't marked, then mark it

View file

@ -1362,6 +1362,7 @@ void Sidebar::update_ui_from_settings()
p->plater->canvas3D()->update_gizmos_on_off_state();
p->plater->set_current_canvas_as_dirty();
p->plater->get_current_canvas3D()->request_extra_frame();
p->object_list->apply_volumes_order();
}
std::vector<PlaterPresetComboBox*>& Sidebar::combos_filament()
@ -2449,6 +2450,7 @@ std::vector<size_t> Plater::priv::load_model_objects(const ModelObjectPtrs &mode
#endif /* AUTOPLACEMENT_ON_LOAD */
for (ModelObject *model_object : model_objects) {
auto *object = model.add_object(*model_object);
object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
std::string object_name = object->name.empty() ? fs::path(object->input_file).filename().string() : object->name;
obj_idxs.push_back(obj_count++);
@ -3307,6 +3309,7 @@ void Plater::priv::reload_from_disk()
if (!sinking)
#endif // ENABLE_ALLOW_NEGATIVE_Z
old_model_object->ensure_on_bed();
old_model_object->sort_volumes(wxGetApp().app_config->get("order_volumes") == "1");
sla::reproject_points_and_holes(old_model_object);
}