diff --git a/src/user/user_mesh.cc b/src/user/user_mesh.cc index f3aa3f00..f4cf9fee 100644 --- a/src/user/user_mesh.cc +++ b/src/user/user_mesh.cc @@ -114,7 +114,8 @@ mjCMesh::mjCMesh(mjCModel* _model, mjCDef* _def) { face = NULL; graph = NULL; needhull = false; - validorientation = true; + invalidorientation.first = -1; + invalidorientation.second = -1; validarea = true; validvolume = true; valideigenvalue = true; @@ -275,7 +276,8 @@ void mjCMesh::Compile(const mjVFS* vfs) { std::sort(useredge.begin(), useredge.end()); auto iterator = std::adjacent_find(useredge.begin(), useredge.end()); if (iterator != useredge.end()) { - validorientation = false; + invalidorientation.first = iterator->first+1; + invalidorientation.second = iterator->second+1; } } @@ -1195,8 +1197,11 @@ void mjCMesh::CheckMesh() { if (!processed) { return; } - if (!validorientation) - throw mjCError(this, "faces have inconsistent orientation: %s", name.c_str()); + if (invalidorientation.first>=0 || invalidorientation.second>=0) + throw mjCError(this, + "faces of mesh '%s' have inconsistent orientation. Please check the " + "faces containing the vertices %d and %d.", + name.c_str(), invalidorientation.first, invalidorientation.second); if (!validarea) throw mjCError(this, "mesh surface area is too small: %s", name.c_str()); if (!validvolume) diff --git a/src/user/user_objects.h b/src/user/user_objects.h index cf22cc02..f04e9922 100644 --- a/src/user/user_objects.h +++ b/src/user/user_objects.h @@ -494,12 +494,12 @@ class mjCMesh: public mjCBase { void CheckMesh(void); // check if the mesh is valid // mesh properties that indicate a well-formed mesh - bool validorientation; // false if mesh have inconsistent faces - bool validarea; // false if the area is too small - bool validvolume; // false if the volume is too small - bool valideigenvalue; // false if inertia eigenvalue is too small - bool validinequality; // false if inertia inequality is not satisfied - bool processed; // false if the mesh has not been processed yet + std::pair invalidorientation; // indices of invalid edge; -1 if none + bool validarea; // false if the area is too small + bool validvolume; // false if the volume is too small + bool valideigenvalue; // false if inertia eigenvalue is too small + bool validinequality; // false if inertia inequality is not satisfied + bool processed; // false if the mesh has not been processed yet // mesh properties computed by Compile double pos_volume[3]; // CoM position diff --git a/test/user/user_mesh_test.cc b/test/user/user_mesh_test.cc index b5fe6343..b3b12611 100644 --- a/test/user/user_mesh_test.cc +++ b/test/user/user_mesh_test.cc @@ -222,7 +222,9 @@ TEST_F(MjCMeshTest, MalformedFaceFails) { std::array error; mjModel* model = mj_loadXML(xml_path.c_str(), 0, error.data(), error.size()); EXPECT_THAT(model, testing::IsNull()); - EXPECT_THAT(error.data(), HasSubstr("faces have inconsistent orientation")); + EXPECT_THAT(error.data(), HasSubstr( + "Error: faces of mesh 'malformed_face' have inconsistent orientation. " + "Please check the faces containing the vertices 1 and 2.")); } TEST_F(MjCMeshTest, FlippedFaceFails) { @@ -243,7 +245,9 @@ TEST_F(MjCMeshTest, FlippedFaceFails) { std::array error; mjModel* model = LoadModelFromString(xml, error.data(), error.size()); EXPECT_THAT(model, testing::IsNull()); - EXPECT_THAT(error.data(), HasSubstr("faces have inconsistent orientation")); + EXPECT_THAT(error.data(), HasSubstr( + "Error: faces of mesh 'example_mesh' have inconsistent orientation. " + "Please check the faces containing the vertices 1 and 2.")); } void CheckTetrahedronWasRescaled(mjModel* model) {