diff --git a/include/sdf/Mesh.hh b/include/sdf/Mesh.hh index f19d98818..5270f90e0 100644 --- a/include/sdf/Mesh.hh +++ b/include/sdf/Mesh.hh @@ -37,6 +37,17 @@ namespace sdf // Forward declarations. class ParserConfig; + /// \brief Mesh simplification method + enum class MeshSimplification + { + /// \brief No mesh simplification + NONE, + /// \brief Convex hull + CONVEX_HULL, + /// \brief Convex decomposition + CONVEX_DECOMPOSITION + }; + /// \brief Mesh represents a mesh shape, and is usually accessed through a /// Geometry. class SDFORMAT_VISIBLE Mesh @@ -61,6 +72,27 @@ namespace sdf /// an error code and message. An empty vector indicates no error. public: Errors Load(sdf::ElementPtr _sdf, const ParserConfig &_config); + /// \brief Get the mesh's simplifcation method + /// \return The mesh simplification method. + /// MeshSimplification::NONE if no mesh simplificaton is done. + public: MeshSimplification Simplification() const; + + /// \brief Get the mesh's simplifcation method + /// \return The mesh simplification method. + /// Empty string if no mesh simplificaton is done. + public: std::string SimplificationStr() const; + + /// \brief Set the mesh simplification method. + /// \param[in] _simplifcation The mesh simplification method. + public: void SetSimplification(MeshSimplification _simplifcation); + + /// \brief Set the mesh simplification method. + /// \param[in] _simplifcation The mesh simplification method. + /// \return True if the _simplificationStr parameter matched a known + /// mesh simplification method. False if the mesh simplification method + /// could not be set. + public: bool SetSimplification(const std::string &_simplifcationStr); + /// \brief Get the mesh's URI. /// \return The URI of the mesh data. public: std::string Uri() const; diff --git a/sdf/1.11/mesh_shape.sdf b/sdf/1.11/mesh_shape.sdf index 61bce76dd..347414eca 100644 --- a/sdf/1.11/mesh_shape.sdf +++ b/sdf/1.11/mesh_shape.sdf @@ -1,5 +1,12 @@ Mesh shape + + + + Set whether to simplify the mesh using one of the specified methods. Values include: "convex_hull" - a single convex hull that encapsulates the mesh, "convex_decomposition" - decompose the mesh into multiple convex hull meshes. Default value is an empty string which means no mesh simplification. + + + Mesh uri diff --git a/src/Mesh.cc b/src/Mesh.cc index 9dfddcf2b..d97a98cd4 100644 --- a/src/Mesh.cc +++ b/src/Mesh.cc @@ -27,9 +27,22 @@ using namespace sdf; +/// Mesh Simplification method strings. These should match the data in +/// `enum class MeshSimplification` located in Mesh.hh, and the size +/// template parameter should match the number of elements as well. +constexpr std::array kMeshSimplificationStrs = +{ + "", + "convex_hull", + "convex_decomposition" +}; + // Private data class class sdf::Mesh::Implementation { + /// \brief Mesh simplification method + public: MeshSimplification simplification = MeshSimplification::NONE; + /// \brief The mesh's URI. public: std::string uri = ""; @@ -87,6 +100,12 @@ Errors Mesh::Load(ElementPtr _sdf, const ParserConfig &_config) return errors; } + // Simplify + if (_sdf->HasAttribute("simplification")) + { + this->SetSimplification(_sdf->Get("simplification", "").first); + } + if (_sdf->HasElement("uri")) { std::unordered_set paths; @@ -140,6 +159,41 @@ sdf::ElementPtr Mesh::Element() const return this->dataPtr->sdf; } +////////////////////////////////////////////////// +MeshSimplification Mesh::Simplification() const +{ + return this->dataPtr->simplification; +} + +////////////////////////////////////////////////// +std::string Mesh::SimplificationStr() const +{ + size_t index = static_cast(this->dataPtr->simplification); + if (index < kMeshSimplificationStrs.size()) + return std::string(kMeshSimplificationStrs[index]); + return ""; +} + +////////////////////////////////////////////////// +bool Mesh::SetSimplification(const std::string &_simplificationStr) +{ + for (size_t i = 0; i < kMeshSimplificationStrs.size(); ++i) + { + if (_simplificationStr == kMeshSimplificationStrs[i]) + { + this->dataPtr->simplification = static_cast(i); + return true; + } + } + return false; +} + +////////////////////////////////////////////////// +void Mesh::SetSimplification(MeshSimplification _simplification) +{ + this->dataPtr->simplification = _simplification; +} + ////////////////////////////////////////////////// std::string Mesh::Uri() const { @@ -244,6 +298,10 @@ sdf::ElementPtr Mesh::ToElement(sdf::Errors &_errors) const sdf::ElementPtr elem(new sdf::Element); sdf::initFile("mesh_shape.sdf", elem); + // Simplification + elem->GetAttribute("simplification")->Set( + this->SimplificationStr()); + // Uri sdf::ElementPtr uriElem = elem->GetElement("uri", _errors); uriElem->Set(_errors, this->Uri()); diff --git a/src/Mesh_TEST.cc b/src/Mesh_TEST.cc index 51c1751f4..8f79451c8 100644 --- a/src/Mesh_TEST.cc +++ b/src/Mesh_TEST.cc @@ -34,6 +34,8 @@ TEST(DOMMesh, Construction) sdf::Mesh mesh; EXPECT_EQ(nullptr, mesh.Element()); + EXPECT_EQ(std::string(), mesh.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::NONE, mesh.Simplification()); EXPECT_EQ(std::string(), mesh.FilePath()); EXPECT_EQ(std::string(), mesh.Uri()); EXPECT_EQ(std::string(), mesh.Submesh()); @@ -45,6 +47,7 @@ TEST(DOMMesh, Construction) TEST(DOMMesh, MoveConstructor) { sdf::Mesh mesh; + mesh.SetSimplification("convex_hull"); mesh.SetUri("banana"); mesh.SetSubmesh("watermelon"); mesh.SetCenterSubmesh(true); @@ -52,6 +55,8 @@ TEST(DOMMesh, MoveConstructor) mesh.SetFilePath("/pear"); sdf::Mesh mesh2(std::move(mesh)); + EXPECT_EQ("convex_hull", mesh2.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, mesh2.Simplification()); EXPECT_EQ("banana", mesh2.Uri()); EXPECT_EQ("watermelon", mesh2.Submesh()); EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale()); @@ -63,6 +68,7 @@ TEST(DOMMesh, MoveConstructor) TEST(DOMMesh, CopyConstructor) { sdf::Mesh mesh; + mesh.SetSimplification("convex_hull"); mesh.SetUri("banana"); mesh.SetSubmesh("watermelon"); mesh.SetCenterSubmesh(true); @@ -70,6 +76,8 @@ TEST(DOMMesh, CopyConstructor) mesh.SetFilePath("/pear"); sdf::Mesh mesh2(mesh); + EXPECT_EQ("convex_hull", mesh2.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, mesh2.Simplification()); EXPECT_EQ("banana", mesh2.Uri()); EXPECT_EQ("watermelon", mesh2.Submesh()); EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale()); @@ -81,6 +89,7 @@ TEST(DOMMesh, CopyConstructor) TEST(DOMMesh, CopyAssignmentOperator) { sdf::Mesh mesh; + mesh.SetSimplification("convex_hull"); mesh.SetUri("banana"); mesh.SetSubmesh("watermelon"); mesh.SetCenterSubmesh(true); @@ -89,6 +98,8 @@ TEST(DOMMesh, CopyAssignmentOperator) sdf::Mesh mesh2; mesh2 = mesh; + EXPECT_EQ("convex_hull", mesh2.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, mesh2.Simplification()); EXPECT_EQ("banana", mesh2.Uri()); EXPECT_EQ("watermelon", mesh2.Submesh()); EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale()); @@ -100,6 +111,7 @@ TEST(DOMMesh, CopyAssignmentOperator) TEST(DOMMesh, MoveAssignmentOperator) { sdf::Mesh mesh; + mesh.SetSimplification("convex_hull"); mesh.SetUri("banana"); mesh.SetSubmesh("watermelon"); mesh.SetCenterSubmesh(true); @@ -108,6 +120,8 @@ TEST(DOMMesh, MoveAssignmentOperator) sdf::Mesh mesh2; mesh2 = std::move(mesh); + EXPECT_EQ("convex_hull", mesh2.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, mesh2.Simplification()); EXPECT_EQ("banana", mesh2.Uri()); EXPECT_EQ("watermelon", mesh2.Submesh()); EXPECT_EQ(gz::math::Vector3d(0.5, 0.6, 0.7), mesh2.Scale()); @@ -140,6 +154,15 @@ TEST(DOMMesh, Set) sdf::Mesh mesh; EXPECT_EQ(nullptr, mesh.Element()); + EXPECT_EQ(std::string(), mesh.SimplificationStr()); + mesh.SetSimplification("convex_hull"); + EXPECT_EQ("convex_hull", mesh.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, mesh.Simplification()); + mesh.SetSimplification(sdf::MeshSimplification::CONVEX_DECOMPOSITION); + EXPECT_EQ("convex_decomposition", mesh.SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_DECOMPOSITION, + mesh.Simplification()); + EXPECT_EQ(std::string(), mesh.Uri()); mesh.SetUri("http://myuri.com"); EXPECT_EQ("http://myuri.com", mesh.Uri()); @@ -296,6 +319,7 @@ TEST(DOMMesh, ToElement) { sdf::Mesh mesh; + mesh.SetSimplification("convex_hull"); mesh.SetUri("mesh-uri"); mesh.SetScale(gz::math::Vector3d(1, 2, 3)); mesh.SetSubmesh("submesh"); @@ -307,6 +331,8 @@ TEST(DOMMesh, ToElement) sdf::Mesh mesh2; mesh2.Load(elem); + EXPECT_EQ(mesh.SimplificationStr(), mesh2.SimplificationStr()); + EXPECT_EQ(mesh.Simplification(), mesh2.Simplification()); EXPECT_EQ(mesh.Uri(), mesh2.Uri()); EXPECT_EQ(mesh.Scale(), mesh2.Scale()); EXPECT_EQ(mesh.Submesh(), mesh2.Submesh()); @@ -332,6 +358,7 @@ TEST(DOMMesh, ToElementErrorOutput) sdf::Mesh mesh; sdf::Errors errors; + mesh.SetSimplification("convex_hull"); mesh.SetUri("mesh-uri"); mesh.SetScale(gz::math::Vector3d(1, 2, 3)); mesh.SetSubmesh("submesh"); @@ -345,6 +372,8 @@ TEST(DOMMesh, ToElementErrorOutput) errors = mesh2.Load(elem); EXPECT_TRUE(errors.empty()); + EXPECT_EQ(mesh.SimplificationStr(), mesh2.SimplificationStr()); + EXPECT_EQ(mesh.Simplification(), mesh2.Simplification()); EXPECT_EQ(mesh.Uri(), mesh2.Uri()); EXPECT_EQ(mesh.Scale(), mesh2.Scale()); EXPECT_EQ(mesh.Submesh(), mesh2.Submesh()); diff --git a/test/integration/geometry_dom.cc b/test/integration/geometry_dom.cc index 07d50d570..ceef3fa15 100644 --- a/test/integration/geometry_dom.cc +++ b/test/integration/geometry_dom.cc @@ -179,6 +179,10 @@ TEST(DOMGeometry, Shapes) EXPECT_EQ(sdf::GeometryType::MESH, meshCol->Geom()->Type()); const sdf::Mesh *meshColGeom = meshCol->Geom()->MeshShape(); ASSERT_NE(nullptr, meshColGeom); + EXPECT_EQ("convex_hull", meshColGeom->SimplificationStr()); + EXPECT_EQ(sdf::MeshSimplification::CONVEX_HULL, + meshColGeom->Simplification()); + EXPECT_EQ("https://fuel.gazebosim.org/1.0/an_org/models/a_model/mesh/" "mesh.dae", meshColGeom->Uri()); EXPECT_TRUE(gz::math::Vector3d(0.1, 0.2, 0.3) == diff --git a/test/sdf/shapes.sdf b/test/sdf/shapes.sdf index 1f5f4fa27..bfa50c934 100644 --- a/test/sdf/shapes.sdf +++ b/test/sdf/shapes.sdf @@ -120,7 +120,7 @@ - + https://fuel.gazebosim.org/1.0/an_org/models/a_model/mesh/mesh.dae my_submesh