From 40b8d9b87fbebd5663968c23a7e291908a7b57d7 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 21 Jun 2023 15:30:04 +0800 Subject: [PATCH] ENH: improve mesh boolean 1. Don't use mcut on splitable volumes 2. If MCut fails, try again with CGAL. Change-Id: I55d352b166633db9e4548b5c9e6913cf931f5f8f (cherry picked from commit c1bde5358524d2291db6efa584ff072308ed9d20) --- src/libslic3r/CSGMesh/ModelToCSGMesh.hpp | 6 +++++- src/slic3r/GUI/GUI_ObjectList.cpp | 2 +- src/slic3r/GUI/Plater.cpp | 25 +++++++++++++++--------- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp index b0d32710e..446326dc8 100644 --- a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp @@ -19,7 +19,7 @@ enum ModelParts { }; template -void model_to_csgmesh(const ModelObject &mo, +bool model_to_csgmesh(const ModelObject &mo, const Transform3d &trafo, // Applies to all exported parts OutIt out, // Output iterator // values of ModelParts OR-ed @@ -30,6 +30,7 @@ void model_to_csgmesh(const ModelObject &mo, bool do_negatives = parts_to_include & mpartsNegative; bool do_drillholes = parts_to_include & mpartsDrillHoles; bool do_splits = parts_to_include & mpartsDoSplits; + bool has_splitable_volume = false; for (const ModelVolume *vol : mo.volumes) { if (vol && vol->mesh_ptr() && @@ -58,6 +59,7 @@ void model_to_csgmesh(const ModelObject &mo, part_end.stack_operation = CSGStackOp::Pop; *out = std::move(part_end); ++out; + has_splitable_volume = true; } else { CSGPart part{&(vol->mesh().its), vol->is_model_part() ? CSGType::Union : CSGType::Difference, @@ -81,6 +83,8 @@ void model_to_csgmesh(const ModelObject &mo, // ++out; // } //} + + return has_splitable_volume; } }} // namespace Slic3r::csg diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index 5451e28aa..191e263bf 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -2913,7 +2913,7 @@ void ObjectList::boolean() new_object->add_instance(); ModelObject* object = (*m_objects)[obj_idxs.front()]; - TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1); + TriangleMesh mesh = Plater::combine_mesh_fff(*object, -1, [this](const std::string& msg) {return wxGetApp().notification_manager()->push_plater_error_notification(msg); }); ModelVolume* new_volume = new_object->add_volume(mesh); // BBS: ensure on bed but no need to ensure locate in the center around origin diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index 3d9b56740..8f2588cdb 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -9945,7 +9945,6 @@ void Plater::export_core_3mf() export_3mf(path_u8, SaveStrategy::Silence); } -#define USE_CGAL_BOOLEAN 0 // 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 notify_func) { @@ -9953,20 +9952,28 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st std::vector csgmesh; csgmesh.reserve(2 * mo.volumes.size()); - csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh), + bool has_splitable_volume = csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh), csg::mpartsPositive | csg::mpartsNegative | csg::mpartsDoSplits); - if (csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }) == csgmesh.end()) { + if (csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }) == csgmesh.end()) { + try { + // mcut can't handle splitable positive volumes + if (!has_splitable_volume) { + MeshBoolean::mcut::McutMeshPtr meshPtr = csg::perform_csgmesh_booleans_mcut(Range{ std::begin(csgmesh), std::end(csgmesh) }); + mesh = MeshBoolean::mcut::mcut_to_triangle_mesh(*meshPtr); + } + } + catch (...) {} + + // if mcut fails, try again with CGAL + if (mesh.empty()) { try { -#if USE_CGAL_BOOLEAN auto meshPtr = csg::perform_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }); mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*meshPtr); -#else - MeshBoolean::mcut::McutMeshPtr meshPtr = csg::perform_csgmesh_booleans_mcut(Range{std::begin(csgmesh), std::end(csgmesh)}); - mesh = MeshBoolean::mcut::mcut_to_triangle_mesh(*meshPtr); -#endif - } catch (...) {} + } + catch (...) {} } + } if (mesh.empty()) { if (notify_func)