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)
This commit is contained in:
Arthur 2023-06-21 15:30:04 +08:00 committed by Lane.Wei
parent 1fe741b7f0
commit 40b8d9b87f
3 changed files with 22 additions and 11 deletions

View File

@ -19,7 +19,7 @@ enum ModelParts {
}; };
template<class OutIt> template<class OutIt>
void model_to_csgmesh(const ModelObject &mo, bool model_to_csgmesh(const ModelObject &mo,
const Transform3d &trafo, // Applies to all exported parts const Transform3d &trafo, // Applies to all exported parts
OutIt out, // Output iterator OutIt out, // Output iterator
// values of ModelParts OR-ed // 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_negatives = parts_to_include & mpartsNegative;
bool do_drillholes = parts_to_include & mpartsDrillHoles; bool do_drillholes = parts_to_include & mpartsDrillHoles;
bool do_splits = parts_to_include & mpartsDoSplits; bool do_splits = parts_to_include & mpartsDoSplits;
bool has_splitable_volume = false;
for (const ModelVolume *vol : mo.volumes) { for (const ModelVolume *vol : mo.volumes) {
if (vol && vol->mesh_ptr() && if (vol && vol->mesh_ptr() &&
@ -58,6 +59,7 @@ void model_to_csgmesh(const ModelObject &mo,
part_end.stack_operation = CSGStackOp::Pop; part_end.stack_operation = CSGStackOp::Pop;
*out = std::move(part_end); *out = std::move(part_end);
++out; ++out;
has_splitable_volume = true;
} else { } else {
CSGPart part{&(vol->mesh().its), CSGPart part{&(vol->mesh().its),
vol->is_model_part() ? CSGType::Union : CSGType::Difference, vol->is_model_part() ? CSGType::Union : CSGType::Difference,
@ -81,6 +83,8 @@ void model_to_csgmesh(const ModelObject &mo,
// ++out; // ++out;
// } // }
//} //}
return has_splitable_volume;
} }
}} // namespace Slic3r::csg }} // namespace Slic3r::csg

View File

@ -2913,7 +2913,7 @@ void ObjectList::boolean()
new_object->add_instance(); new_object->add_instance();
ModelObject* object = (*m_objects)[obj_idxs.front()]; 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); ModelVolume* new_volume = new_object->add_volume(mesh);
// BBS: ensure on bed but no need to ensure locate in the center around origin // BBS: ensure on bed but no need to ensure locate in the center around origin

View File

@ -9945,7 +9945,6 @@ void Plater::export_core_3mf()
export_3mf(path_u8, SaveStrategy::Silence); export_3mf(path_u8, SaveStrategy::Silence);
} }
#define USE_CGAL_BOOLEAN 0
// Following lambda generates a combined mesh for export with normals pointing outwards. // 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) TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, std::function<void(const std::string&)> notify_func)
{ {
@ -9953,19 +9952,27 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st
std::vector<csg::CSGPart> csgmesh; std::vector<csg::CSGPart> csgmesh;
csgmesh.reserve(2 * mo.volumes.size()); 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); 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 { try {
#if USE_CGAL_BOOLEAN // mcut can't handle splitable positive volumes
auto meshPtr = csg::perform_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }); if (!has_splitable_volume) {
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) }); MeshBoolean::mcut::McutMeshPtr meshPtr = csg::perform_csgmesh_booleans_mcut(Range{ std::begin(csgmesh), std::end(csgmesh) });
mesh = MeshBoolean::mcut::mcut_to_triangle_mesh(*meshPtr); mesh = MeshBoolean::mcut::mcut_to_triangle_mesh(*meshPtr);
#endif }
} catch (...) {} }
catch (...) {}
// if mcut fails, try again with CGAL
if (mesh.empty()) {
try {
auto meshPtr = csg::perform_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) });
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*meshPtr);
}
catch (...) {}
}
} }
if (mesh.empty()) { if (mesh.empty()) {