ENH: give exaxt reason of boolean fail
jira: none Change-Id: Ied645373a4516be7466078ace73c69ef584a743a (cherry picked from commit f21819b4f6718357984650e7eb89a2e496dfa03c)
This commit is contained in:
parent
cb1a384593
commit
72ef0a4d2a
|
@ -11,6 +11,7 @@
|
|||
#include "libslic3r/MeshBoolean.hpp"
|
||||
|
||||
namespace Slic3r { namespace csg {
|
||||
enum class BooleanFailReason { OK, MeshEmpty, NotBoundAVolume, SelfIntersect, NoIntersection};
|
||||
|
||||
// This method can be overriden when a specific CSGPart type supports caching
|
||||
// of the voxel grid
|
||||
|
@ -256,12 +257,12 @@ void perform_csgmesh_booleans_mcut(MeshBoolean::mcut::McutMeshPtr& mcutm,
|
|||
|
||||
|
||||
template<class It, class Visitor>
|
||||
It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
||||
BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
||||
{
|
||||
using namespace detail_cgal;
|
||||
|
||||
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
||||
std::vector<CGALMeshPtr> cgalmeshes(csgrange.size());
|
||||
auto check_part = [&csgrange, &cgalmeshes](size_t i)
|
||||
auto check_part = [&csgrange, &cgalmeshes,&fail_reason](size_t i)
|
||||
{
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
|
@ -277,16 +278,19 @@ It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
|||
try {
|
||||
if (!m || MeshBoolean::cgal::empty(*m)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh " << i << "/" << csgrange.size() << " is empty, cannot do boolean!";
|
||||
fail_reason= BooleanFailReason::MeshEmpty;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh "<<i<<"/"<<csgrange.size()<<" does_bound_a_volume is false, cannot do boolean!";
|
||||
fail_reason= BooleanFailReason::NotBoundAVolume;
|
||||
return;
|
||||
}
|
||||
|
||||
if (MeshBoolean::cgal::does_self_intersect(*m)) {
|
||||
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh " << i << "/" << csgrange.size() << " does_self_intersect is true, cannot do boolean!";
|
||||
fail_reason= BooleanFailReason::SelfIntersect;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -296,31 +300,32 @@ It check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
|||
};
|
||||
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
||||
|
||||
It ret = csgrange.end();
|
||||
for (size_t i = 0; i < csgrange.size(); ++i) {
|
||||
if (!cgalmeshes[i]) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
vfn(it);
|
||||
//It ret = csgrange.end();
|
||||
//for (size_t i = 0; i < csgrange.size(); ++i) {
|
||||
// if (!cgalmeshes[i]) {
|
||||
// auto it = csgrange.begin();
|
||||
// std::advance(it, i);
|
||||
// vfn(it);
|
||||
|
||||
if (ret == csgrange.end())
|
||||
ret = it;
|
||||
}
|
||||
}
|
||||
// if (ret == csgrange.end())
|
||||
// ret = it;
|
||||
// }
|
||||
//}
|
||||
|
||||
return ret;
|
||||
return fail_reason;
|
||||
}
|
||||
|
||||
template<class It>
|
||||
It check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
||||
BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
||||
{
|
||||
if(!use_mcut)
|
||||
return check_csgmesh_booleans(csgrange, [](auto &) {});
|
||||
else {
|
||||
using namespace detail_mcut;
|
||||
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
||||
|
||||
std::vector<McutMeshPtr> McutMeshes(csgrange.size());
|
||||
auto check_part = [&csgrange, &McutMeshes](size_t i) {
|
||||
auto check_part = [&csgrange, &McutMeshes,&fail_reason](size_t i) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
auto& csgpart = *it;
|
||||
|
@ -333,27 +338,17 @@ It check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
|||
}
|
||||
|
||||
try {
|
||||
if (!m || MeshBoolean::mcut::empty(*m))
|
||||
if (!m || MeshBoolean::mcut::empty(*m)) {
|
||||
fail_reason=BooleanFailReason::MeshEmpty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (...) { return; }
|
||||
|
||||
McutMeshes[i] = std::move(m);
|
||||
};
|
||||
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
||||
|
||||
It ret = csgrange.end();
|
||||
for (size_t i = 0; i < csgrange.size(); ++i) {
|
||||
if (!McutMeshes[i]) {
|
||||
auto it = csgrange.begin();
|
||||
std::advance(it, i);
|
||||
|
||||
if (ret == csgrange.end())
|
||||
ret = it;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
return fail_reason;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10881,11 +10881,22 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st
|
|||
bool has_splitable_volume = csg::model_to_csgmesh(mo, Transform3d::Identity(), std::back_inserter(csgmesh),
|
||||
csg::mpartsPositive | csg::mpartsNegative);
|
||||
|
||||
if (csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }) == csgmesh.end()) {
|
||||
std::string fail_msg = _u8L("Unable to perform boolean operation on model meshes. "
|
||||
"Only positive parts will be kept. You may fix the meshes and try agian.");
|
||||
if (auto fail_reason = csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }); fail_reason != csg::BooleanFailReason::OK) {
|
||||
std::map<csg::BooleanFailReason, std::string> fail_reasons = {
|
||||
{csg::BooleanFailReason::OK, "OK"},
|
||||
{csg::BooleanFailReason::MeshEmpty, _u8L("Reason: mesh is empty.")},
|
||||
{csg::BooleanFailReason::NotBoundAVolume, _u8L("Reason: mesh does not bound a volume.")},
|
||||
{csg::BooleanFailReason::SelfIntersect, _u8L("Reason: mesh has self intersection.")},
|
||||
{csg::BooleanFailReason::NoIntersection, _u8L("Reason: meshes have no intersection.")} };
|
||||
fail_msg += " " + fail_reasons[fail_reason];
|
||||
}
|
||||
else {
|
||||
try {
|
||||
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 0
|
||||
// if mcut fails, try again with CGAL
|
||||
|
@ -10893,7 +10904,7 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st
|
|||
try {
|
||||
auto meshPtr = csg::perform_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) });
|
||||
mesh = MeshBoolean::cgal::cgal_to_triangle_mesh(*meshPtr);
|
||||
}
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
#endif
|
||||
|
@ -10901,8 +10912,7 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st
|
|||
|
||||
if (mesh.empty()) {
|
||||
if (notify_func)
|
||||
notify_func(_u8L("Unable to perform boolean operation on model meshes. "
|
||||
"Only positive parts will be exported."));
|
||||
notify_func(fail_msg);
|
||||
|
||||
for (const ModelVolume* v : mo.volumes)
|
||||
if (v->is_model_part()) {
|
||||
|
|
Loading…
Reference in New Issue