mirror of
				https://github.com/SoftFever/OrcaSlicer.git
				synced 2025-10-31 04:31:15 -06:00 
			
		
		
		
	Fixed DnD for "Model part" volumes inside the object
Fixed volumes order inside the object
This commit is contained in:
		
							parent
							
								
									2d9953069a
								
							
						
					
					
						commit
						7eebd56b5f
					
				
					 7 changed files with 101 additions and 96 deletions
				
			
		|  | @ -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); | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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; | ||||
|  |  | |||
|  | @ -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__ | ||||
|  |  | |||
|  | @ -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
 | ||||
|  |  | |||
|  | @ -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); | ||||
|                 } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 YuSanka
						YuSanka