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:
parent
1fe741b7f0
commit
40b8d9b87f
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
Loading…
Reference in New Issue