From d75e79c2ec6c23602a7c80d07854d9f09a5fd906 Mon Sep 17 00:00:00 2001 From: Arthur Date: Wed, 7 Feb 2024 09:15:30 +0800 Subject: [PATCH] ENH: output the part name that causes mesh boolean failure jira: none Change-Id: Ie90809575291d66d54462f81c157d3e89fc34d55 (cherry picked from commit fdb6457798757a35b9623ece3b3071b3ad7ad38d) --- src/libslic3r/CSGMesh/CSGMesh.hpp | 1 + src/libslic3r/CSGMesh/ModelToCSGMesh.hpp | 2 +- .../CSGMesh/PerformCSGMeshBooleans.hpp | 18 ++++++++++++------ src/slic3r/GUI/Plater.cpp | 13 +++++++------ 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/libslic3r/CSGMesh/CSGMesh.hpp b/src/libslic3r/CSGMesh/CSGMesh.hpp index d14ed7659..177d34329 100644 --- a/src/libslic3r/CSGMesh/CSGMesh.hpp +++ b/src/libslic3r/CSGMesh/CSGMesh.hpp @@ -70,6 +70,7 @@ struct CSGPart { Transform3f trafo; CSGType operation; CSGStackOp stack_operation; + std::string name; CSGPart(AnyPtr ptr = {}, CSGType op = CSGType::Union, diff --git a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp index 446326dc8..5963b2910 100644 --- a/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp +++ b/src/libslic3r/CSGMesh/ModelToCSGMesh.hpp @@ -64,7 +64,7 @@ bool model_to_csgmesh(const ModelObject &mo, CSGPart part{&(vol->mesh().its), vol->is_model_part() ? CSGType::Union : CSGType::Difference, (trafo * vol->get_matrix()).cast()}; - + part.name = vol->name; *out = std::move(part); ++out; } diff --git a/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp b/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp index b02d1cda3..a9a48b48c 100644 --- a/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp +++ b/src/libslic3r/CSGMesh/PerformCSGMeshBooleans.hpp @@ -257,12 +257,13 @@ void perform_csgmesh_booleans_mcut(MeshBoolean::mcut::McutMeshPtr& mcutm, template -BooleanFailReason check_csgmesh_booleans(const Range &csgrange, Visitor &&vfn) +std::tuple check_csgmesh_booleans(const Range &csgrange, Visitor &&vfn) { using namespace detail_cgal; BooleanFailReason fail_reason = BooleanFailReason::OK; + std::string fail_part_name; std::vector 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(); std::advance(it, i); @@ -279,18 +280,21 @@ BooleanFailReason check_csgmesh_booleans(const Range &csgrange, Visitor &&vf 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; + fail_part_name = csgpart.name; return; } if (!MeshBoolean::cgal::does_bound_a_volume(*m)) { BOOST_LOG_TRIVIAL(info) << "check_csgmesh_booleans fails! mesh "< &csgrange, Visitor &&vf // } //} - return fail_reason; + return { fail_reason,fail_part_name }; } template -BooleanFailReason check_csgmesh_booleans(const Range &csgrange, bool use_mcut=false) +std::tuple check_csgmesh_booleans(const Range &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::string fail_part_name; std::vector 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(); std::advance(it, i); auto& csgpart = *it; @@ -340,6 +345,7 @@ BooleanFailReason check_csgmesh_booleans(const Range &csgrange, bool use_mcu try { if (!m || MeshBoolean::mcut::empty(*m)) { fail_reason=BooleanFailReason::MeshEmpty; + fail_part_name = csgpart.name; return; } } @@ -348,7 +354,7 @@ BooleanFailReason check_csgmesh_booleans(const Range &csgrange, bool use_mcu McutMeshes[i] = std::move(m); }; execution::for_each(ex_tbb, size_t(0), csgrange.size(), check_part); - return fail_reason; + return { fail_reason,fail_part_name }; } } diff --git a/src/slic3r/GUI/Plater.cpp b/src/slic3r/GUI/Plater.cpp index efd22ce7c..67e141873 100644 --- a/src/slic3r/GUI/Plater.cpp +++ b/src/slic3r/GUI/Plater.cpp @@ -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. " "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 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]; + {csg::BooleanFailReason::MeshEmpty, Slic3r::format( _u8L("Reason: part \"%1%\" is empty."), name)}, + {csg::BooleanFailReason::NotBoundAVolume, Slic3r::format(_u8L("Reason: part \"%1%\" does not bound a volume."), name)}, + {csg::BooleanFailReason::SelfIntersect, Slic3r::format(_u8L("Reason: part \"%1%\" has self intersection."), name)}, + {csg::BooleanFailReason::NoIntersection, Slic3r::format(_u8L("Reason: \"%1%\" and another part have no intersection."), name)} }; + fail_msg += " " + fail_reasons[std::get<0>(fail_reason_name)]; } else { try {