ENH: output the part name that causes mesh boolean failure
jira: none Change-Id: Ie90809575291d66d54462f81c157d3e89fc34d55 (cherry picked from commit fdb6457798757a35b9623ece3b3071b3ad7ad38d)
This commit is contained in:
parent
356e4d825e
commit
d75e79c2ec
|
@ -70,6 +70,7 @@ struct CSGPart {
|
||||||
Transform3f trafo;
|
Transform3f trafo;
|
||||||
CSGType operation;
|
CSGType operation;
|
||||||
CSGStackOp stack_operation;
|
CSGStackOp stack_operation;
|
||||||
|
std::string name;
|
||||||
|
|
||||||
CSGPart(AnyPtr<const indexed_triangle_set> ptr = {},
|
CSGPart(AnyPtr<const indexed_triangle_set> ptr = {},
|
||||||
CSGType op = CSGType::Union,
|
CSGType op = CSGType::Union,
|
||||||
|
|
|
@ -64,7 +64,7 @@ bool model_to_csgmesh(const ModelObject &mo,
|
||||||
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,
|
||||||
(trafo * vol->get_matrix()).cast<float>()};
|
(trafo * vol->get_matrix()).cast<float>()};
|
||||||
|
part.name = vol->name;
|
||||||
*out = std::move(part);
|
*out = std::move(part);
|
||||||
++out;
|
++out;
|
||||||
}
|
}
|
||||||
|
|
|
@ -257,12 +257,13 @@ void perform_csgmesh_booleans_mcut(MeshBoolean::mcut::McutMeshPtr& mcutm,
|
||||||
|
|
||||||
|
|
||||||
template<class It, class Visitor>
|
template<class It, class Visitor>
|
||||||
BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
std::tuple<BooleanFailReason,std::string> check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vfn)
|
||||||
{
|
{
|
||||||
using namespace detail_cgal;
|
using namespace detail_cgal;
|
||||||
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
||||||
|
std::string fail_part_name;
|
||||||
std::vector<CGALMeshPtr> cgalmeshes(csgrange.size());
|
std::vector<CGALMeshPtr> cgalmeshes(csgrange.size());
|
||||||
auto check_part = [&csgrange, &cgalmeshes,&fail_reason](size_t i)
|
auto check_part = [&csgrange, &cgalmeshes,&fail_reason,&fail_part_name](size_t i)
|
||||||
{
|
{
|
||||||
auto it = csgrange.begin();
|
auto it = csgrange.begin();
|
||||||
std::advance(it, i);
|
std::advance(it, i);
|
||||||
|
@ -279,18 +280,21 @@ BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vf
|
||||||
if (!m || MeshBoolean::cgal::empty(*m)) {
|
if (!m || MeshBoolean::cgal::empty(*m)) {
|
||||||
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh " << i << "/" << csgrange.size() << " is empty, cannot do boolean!";
|
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh " << i << "/" << csgrange.size() << " is empty, cannot do boolean!";
|
||||||
fail_reason= BooleanFailReason::MeshEmpty;
|
fail_reason= BooleanFailReason::MeshEmpty;
|
||||||
|
fail_part_name = csgpart.name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!MeshBoolean::cgal::does_bound_a_volume(*m)) {
|
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!";
|
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;
|
fail_reason= BooleanFailReason::NotBoundAVolume;
|
||||||
|
fail_part_name = csgpart.name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (MeshBoolean::cgal::does_self_intersect(*m)) {
|
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!";
|
BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh " << i << "/" << csgrange.size() << " does_self_intersect is true, cannot do boolean!";
|
||||||
fail_reason= BooleanFailReason::SelfIntersect;
|
fail_reason= BooleanFailReason::SelfIntersect;
|
||||||
|
fail_part_name = csgpart.name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -312,20 +316,21 @@ BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, Visitor &&vf
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
return fail_reason;
|
return { fail_reason,fail_part_name };
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class It>
|
template<class It>
|
||||||
BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
std::tuple<BooleanFailReason, std::string> check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcut=false)
|
||||||
{
|
{
|
||||||
if(!use_mcut)
|
if(!use_mcut)
|
||||||
return check_csgmesh_booleans(csgrange, [](auto &) {});
|
return check_csgmesh_booleans(csgrange, [](auto &) {});
|
||||||
else {
|
else {
|
||||||
using namespace detail_mcut;
|
using namespace detail_mcut;
|
||||||
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
BooleanFailReason fail_reason = BooleanFailReason::OK;
|
||||||
|
std::string fail_part_name;
|
||||||
|
|
||||||
std::vector<McutMeshPtr> McutMeshes(csgrange.size());
|
std::vector<McutMeshPtr> McutMeshes(csgrange.size());
|
||||||
auto check_part = [&csgrange, &McutMeshes,&fail_reason](size_t i) {
|
auto check_part = [&csgrange, &McutMeshes,&fail_reason,&fail_part_name](size_t i) {
|
||||||
auto it = csgrange.begin();
|
auto it = csgrange.begin();
|
||||||
std::advance(it, i);
|
std::advance(it, i);
|
||||||
auto& csgpart = *it;
|
auto& csgpart = *it;
|
||||||
|
@ -340,6 +345,7 @@ BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcu
|
||||||
try {
|
try {
|
||||||
if (!m || MeshBoolean::mcut::empty(*m)) {
|
if (!m || MeshBoolean::mcut::empty(*m)) {
|
||||||
fail_reason=BooleanFailReason::MeshEmpty;
|
fail_reason=BooleanFailReason::MeshEmpty;
|
||||||
|
fail_part_name = csgpart.name;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -348,7 +354,7 @@ BooleanFailReason check_csgmesh_booleans(const Range<It> &csgrange, bool use_mcu
|
||||||
McutMeshes[i] = std::move(m);
|
McutMeshes[i] = std::move(m);
|
||||||
};
|
};
|
||||||
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part);
|
||||||
return fail_reason;
|
return { fail_reason,fail_part_name };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10987,14 +10987,15 @@ TriangleMesh Plater::combine_mesh_fff(const ModelObject& mo, int instance_id, st
|
||||||
|
|
||||||
std::string fail_msg = _u8L("Unable to perform boolean operation on model meshes. "
|
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.");
|
"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) {
|
if (auto fail_reason_name = csg::check_csgmesh_booleans(Range{ std::begin(csgmesh), std::end(csgmesh) }); std::get<0>(fail_reason_name) != csg::BooleanFailReason::OK) {
|
||||||
|
std::string name = std::get<1>(fail_reason_name);
|
||||||
std::map<csg::BooleanFailReason, std::string> fail_reasons = {
|
std::map<csg::BooleanFailReason, std::string> fail_reasons = {
|
||||||
{csg::BooleanFailReason::OK, "OK"},
|
{csg::BooleanFailReason::OK, "OK"},
|
||||||
{csg::BooleanFailReason::MeshEmpty, _u8L("Reason: mesh is empty.")},
|
{csg::BooleanFailReason::MeshEmpty, Slic3r::format( _u8L("Reason: part \"%1%\" is empty."), name)},
|
||||||
{csg::BooleanFailReason::NotBoundAVolume, _u8L("Reason: mesh does not bound a volume.")},
|
{csg::BooleanFailReason::NotBoundAVolume, Slic3r::format(_u8L("Reason: part \"%1%\" does not bound a volume."), name)},
|
||||||
{csg::BooleanFailReason::SelfIntersect, _u8L("Reason: mesh has self intersection.")},
|
{csg::BooleanFailReason::SelfIntersect, Slic3r::format(_u8L("Reason: part \"%1%\" has self intersection."), name)},
|
||||||
{csg::BooleanFailReason::NoIntersection, _u8L("Reason: meshes have no intersection.")} };
|
{csg::BooleanFailReason::NoIntersection, Slic3r::format(_u8L("Reason: \"%1%\" and another part have no intersection."), name)} };
|
||||||
fail_msg += " " + fail_reasons[fail_reason];
|
fail_msg += " " + fail_reasons[std::get<0>(fail_reason_name)];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue