mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-07-08 07:27:41 -06:00
ENH: add context menu "Mesh boolean"
Apply boolean operation on parts. No need to export stl to apply. Change-Id: I14479d0977e5ec6f5f80f55b22ed02974b8271c7 (cherry picked from commit 14fe96b2b7529380832007a3d3eb93eb8b9a5217)
This commit is contained in:
parent
45167d6b13
commit
b9abdbe4f8
6 changed files with 103 additions and 55 deletions
|
@ -924,6 +924,9 @@ msgstr "恢复到米"
|
|||
msgid "Assemble"
|
||||
msgstr "组合"
|
||||
|
||||
msgid "Mesh boolean"
|
||||
msgstr "网格布尔操作"
|
||||
|
||||
msgid "Assemble the selected objects to an object with multiple parts"
|
||||
msgstr "组合所选对象为一个多零件对象"
|
||||
|
||||
|
|
|
@ -913,9 +913,9 @@ void MenuFactory::append_menu_item_merge_to_single_object(wxMenu* menu)
|
|||
void MenuFactory::append_menu_item_merge_parts_to_single_part(wxMenu* menu)
|
||||
{
|
||||
menu->AppendSeparator();
|
||||
append_menu_item(menu, wxID_ANY, _L("Assemble"), _L("Assemble the selected parts to a single part"),
|
||||
[](wxCommandEvent&) { obj_list()->merge_volumes(); }, "", menu,
|
||||
[]() { return true; }, m_parent);
|
||||
append_menu_item(menu, wxID_ANY, _L("Mesh boolean"), _L("Mesh boolean operations including union and subtraction"),
|
||||
[](wxCommandEvent&) { obj_list()->boolean/*merge_volumes*/(); }, "", menu,
|
||||
[]() { return obj_list()->can_merge_to_single_object(); }, m_parent);
|
||||
}
|
||||
|
||||
void MenuFactory::append_menu_items_mirror(wxMenu* menu)
|
||||
|
@ -1029,6 +1029,8 @@ void MenuFactory::create_bbl_object_menu()
|
|||
append_menu_item_fix_through_netfabb(&m_object_menu);
|
||||
// Object Simplify
|
||||
append_menu_item_simplify(&m_object_menu);
|
||||
// merge to single part
|
||||
append_menu_item_merge_parts_to_single_part(&m_object_menu);
|
||||
// Object Center
|
||||
append_menu_item_center(&m_object_menu);
|
||||
// Object Split
|
||||
|
|
|
@ -2895,6 +2895,45 @@ void ObjectList::layers_editing()
|
|||
Expand(layers_item);
|
||||
}
|
||||
|
||||
// BBS: merge parts of a single object into one volume, similar to export_stl, but no need to export and then import
|
||||
void ObjectList::boolean()
|
||||
{
|
||||
std::vector<int> obj_idxs, vol_idxs;
|
||||
get_selection_indexes(obj_idxs, vol_idxs);
|
||||
if (obj_idxs.empty() && vol_idxs.empty())
|
||||
return;
|
||||
|
||||
Plater::TakeSnapshot snapshot(wxGetApp().plater(), "boolean");
|
||||
|
||||
Model* model = (*m_objects)[0]->get_model();
|
||||
ModelObject* new_object = model->add_object();
|
||||
new_object->name = (*m_objects)[0]->name;
|
||||
new_object->config.assign_config((*m_objects)[0]->config);
|
||||
if (new_object->instances.empty())
|
||||
new_object->add_instance();
|
||||
|
||||
ModelObject* object = (*m_objects)[obj_idxs.front()];
|
||||
TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1);
|
||||
ModelVolume* new_volume = new_object->add_volume(mesh);
|
||||
|
||||
// BBS: ensure on bed but no need to ensure locate in the center around origin
|
||||
new_object->ensure_on_bed();
|
||||
new_object->center_around_origin();
|
||||
new_object->translate_instances(-new_object->origin_translation);
|
||||
new_object->origin_translation = Vec3d::Zero();
|
||||
|
||||
// BBS: notify it before move
|
||||
notify_instance_updated(m_objects->size() - 1);
|
||||
|
||||
// remove selected objects
|
||||
remove();
|
||||
|
||||
// Add new object(UNION) to the object_list
|
||||
add_object_to_list(m_objects->size() - 1);
|
||||
select_item(m_objects_model->GetItemById(m_objects->size() - 1));
|
||||
update_selections_on_canvas();
|
||||
}
|
||||
|
||||
wxDataViewItem ObjectList::add_layer_root_item(const wxDataViewItem obj_item)
|
||||
{
|
||||
const int obj_idx = m_objects_model->GetIdByItem(obj_item);
|
||||
|
|
|
@ -300,6 +300,7 @@ public:
|
|||
void merge_volumes(); // BBS: merge parts to single part
|
||||
void layers_editing();
|
||||
|
||||
void boolean(); // BBS: Boolean Operation of parts
|
||||
wxDataViewItem add_layer_root_item(const wxDataViewItem obj_item);
|
||||
wxDataViewItem add_settings_item(wxDataViewItem parent_item, const DynamicPrintConfig* config);
|
||||
|
||||
|
|
|
@ -9557,23 +9557,9 @@ void Plater::export_core_3mf()
|
|||
}
|
||||
|
||||
#define USE_CGAL_BOOLEAN 0
|
||||
void Plater::export_stl(bool extended, bool selection_only)
|
||||
// Following lambda generates a combined mesh for export with normals pointing outwards.
|
||||
TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func)
|
||||
{
|
||||
if (p->model.objects.empty()) { return; }
|
||||
|
||||
wxString path = p->get_export_file(FT_STL);
|
||||
if (path.empty()) { return; }
|
||||
const std::string path_u8 = into_u8(path);
|
||||
|
||||
wxBusyCursor wait;
|
||||
|
||||
const auto &selection = p->get_selection();
|
||||
const auto obj_idx = selection.get_object_idx();
|
||||
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
|
||||
return;
|
||||
|
||||
// Following lambda generates a combined mesh for export with normals pointing outwards.
|
||||
auto mesh_to_export_fff = [this](const ModelObject& mo, int instance_id) {
|
||||
TriangleMesh mesh;
|
||||
|
||||
std::vector<csg::CSGPart> csgmesh;
|
||||
|
@ -9594,8 +9580,8 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
}
|
||||
|
||||
if (mesh.empty()) {
|
||||
get_notification_manager()->push_plater_error_notification(
|
||||
_u8L("Unable to perform boolean operation on model meshes. "
|
||||
if (notify_func)
|
||||
notify_func(_u8L("Unable to perform boolean operation on model meshes. "
|
||||
"Only positive parts will be exported."));
|
||||
|
||||
for (const ModelVolume* v : mo.volumes)
|
||||
|
@ -9618,7 +9604,22 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
else if (0 <= instance_id && instance_id < int(mo.instances.size()))
|
||||
mesh.transform(mo.instances[instance_id]->get_matrix(), true);
|
||||
return mesh;
|
||||
};
|
||||
}
|
||||
|
||||
void Plater::export_stl(bool extended, bool selection_only)
|
||||
{
|
||||
if (p->model.objects.empty()) { return; }
|
||||
|
||||
wxString path = p->get_export_file(FT_STL);
|
||||
if (path.empty()) { return; }
|
||||
const std::string path_u8 = into_u8(path);
|
||||
|
||||
wxBusyCursor wait;
|
||||
|
||||
const auto &selection = p->get_selection();
|
||||
const auto obj_idx = selection.get_object_idx();
|
||||
if (selection_only && (obj_idx == -1 || selection.is_wipe_tower()))
|
||||
return;
|
||||
|
||||
auto mesh_to_export_sla = [&, this](const ModelObject& mo, int instance_id) {
|
||||
TriangleMesh mesh;
|
||||
|
@ -9626,7 +9627,7 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
const SLAPrintObject *object = this->p->sla_print.get_print_object_by_model_object_id(mo.id());
|
||||
|
||||
if (auto m = object->get_mesh_to_print(); m.empty())
|
||||
mesh = mesh_to_export_fff(mo, instance_id);
|
||||
mesh = combine_mesh_fff(mo, instance_id, [this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); });
|
||||
else {
|
||||
const Transform3d mesh_trafo_inv = object->trafo().inverse();
|
||||
const bool is_left_handed = object->is_left_handed();
|
||||
|
@ -9690,8 +9691,9 @@ void Plater::export_stl(bool extended, bool selection_only)
|
|||
std::function<TriangleMesh(const ModelObject& mo, int instance_id)>
|
||||
mesh_to_export;
|
||||
|
||||
if (p->printer_technology == ptFFF )
|
||||
mesh_to_export = mesh_to_export_fff;
|
||||
if (p->printer_technology == ptFFF)
|
||||
mesh_to_export = [this](const ModelObject& mo, int instance_id) {return Plater::combine_mesh_fff(mo, instance_id,
|
||||
[this](const std::string& msg) {return get_notification_manager()->push_plater_error_notification(msg); }); };
|
||||
else
|
||||
mesh_to_export = mesh_to_export_sla;
|
||||
|
||||
|
|
|
@ -323,6 +323,7 @@ public:
|
|||
void export_gcode_3mf(bool export_all = false);
|
||||
void send_gcode_finish(wxString name);
|
||||
void export_core_3mf();
|
||||
static TriangleMesh combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func = {});
|
||||
void export_stl(bool extended = false, bool selection_only = false);
|
||||
//BBS: remove amf
|
||||
//void export_amf();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue