From 92cdc795c7ac11ab56fbeded9fd021448d708f2e Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 25 Sep 2019 12:19:30 +0200 Subject: [PATCH] add unit tests for smart handles --- src/OpenMesh/Core/Mesh/SmartHandles.hh | 44 +-- src/Unittests/unittests_smart_handles.cc | 324 +++++++++++++++++++++++ 2 files changed, 346 insertions(+), 22 deletions(-) create mode 100644 src/Unittests/unittests_smart_handles.cc diff --git a/src/OpenMesh/Core/Mesh/SmartHandles.hh b/src/OpenMesh/Core/Mesh/SmartHandles.hh index f2cfeb76..ccad1203 100644 --- a/src/OpenMesh/Core/Mesh/SmartHandles.hh +++ b/src/OpenMesh/Core/Mesh/SmartHandles.hh @@ -102,12 +102,12 @@ struct SmartHalfedgeHandle : public SmartBaseHandle, HalfedgeHandle { explicit SmartHalfedgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), HalfedgeHandle(_idx) {} - SmartHalfedgeHandle next() const; - SmartHalfedgeHandle prev() const; - SmartHalfedgeHandle opp() const; - SmartVertexHandle to() const; - SmartVertexHandle from() const; - SmartFaceHandle face() const; + SmartHalfedgeHandle next() const; + SmartHalfedgeHandle prev() const; + SmartHalfedgeHandle opp() const; + SmartVertexHandle to() const; + SmartVertexHandle from() const; + SmartFaceHandle face() const; bool is_boundary() const; }; @@ -116,14 +116,14 @@ struct SmartEdgeHandle : public SmartBaseHandle, EdgeHandle { explicit SmartEdgeHandle(int _idx=-1, const PolyConnectivity* _mesh = nullptr) : SmartBaseHandle(_mesh), EdgeHandle(_idx) {} - SmartHalfedgeHandle halfedge(unsigned int _i) const; - SmartHalfedgeHandle h(unsigned int _i) const; - SmartHalfedgeHandle h0() const; - SmartHalfedgeHandle h1() const; - SmartVertexHandle vertex(unsigned int _i) const; - SmartVertexHandle v(unsigned int _i) const; - SmartVertexHandle v0() const; - SmartVertexHandle v1() const; + SmartHalfedgeHandle halfedge(unsigned int _i) const; + SmartHalfedgeHandle h(unsigned int _i) const; + SmartHalfedgeHandle h0() const; + SmartHalfedgeHandle h1() const; + SmartVertexHandle vertex(unsigned int _i) const; + SmartVertexHandle v(unsigned int _i) const; + SmartVertexHandle v0() const; + SmartVertexHandle v1() const; bool is_boundary() const; }; @@ -144,15 +144,15 @@ struct SmartFaceHandle : public SmartBaseHandle, FaceHandle }; -inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity* _mesh) { return SmartVertexHandle (_vh.idx(), _mesh); } -inline SmartHalfedgeHandle make_smart(HalfedgeHandle _vh, const PolyConnectivity* _mesh) { return SmartHalfedgeHandle(_vh.idx(), _mesh); } -inline SmartEdgeHandle make_smart(EdgeHandle _vh, const PolyConnectivity* _mesh) { return SmartEdgeHandle (_vh.idx(), _mesh); } -inline SmartFaceHandle make_smart(FaceHandle _vh, const PolyConnectivity* _mesh) { return SmartFaceHandle (_vh.idx(), _mesh); } +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity* _mesh) { return SmartVertexHandle (_vh.idx(), _mesh); } +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity* _mesh) { return SmartHalfedgeHandle(_hh.idx(), _mesh); } +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity* _mesh) { return SmartEdgeHandle (_eh.idx(), _mesh); } +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity* _mesh) { return SmartFaceHandle (_fh.idx(), _mesh); } -inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity& _mesh) { return SmartVertexHandle (_vh.idx(), &_mesh); } -inline SmartHalfedgeHandle make_smart(HalfedgeHandle _vh, const PolyConnectivity& _mesh) { return SmartHalfedgeHandle(_vh.idx(), &_mesh); } -inline SmartEdgeHandle make_smart(EdgeHandle _vh, const PolyConnectivity& _mesh) { return SmartEdgeHandle (_vh.idx(), &_mesh); } -inline SmartFaceHandle make_smart(FaceHandle _vh, const PolyConnectivity& _mesh) { return SmartFaceHandle (_vh.idx(), &_mesh); } +inline SmartVertexHandle make_smart(VertexHandle _vh, const PolyConnectivity& _mesh) { return SmartVertexHandle (_vh.idx(), &_mesh); } +inline SmartHalfedgeHandle make_smart(HalfedgeHandle _hh, const PolyConnectivity& _mesh) { return SmartHalfedgeHandle(_hh.idx(), &_mesh); } +inline SmartEdgeHandle make_smart(EdgeHandle _eh, const PolyConnectivity& _mesh) { return SmartEdgeHandle (_eh.idx(), &_mesh); } +inline SmartFaceHandle make_smart(FaceHandle _fh, const PolyConnectivity& _mesh) { return SmartFaceHandle (_fh.idx(), &_mesh); } //============================================================================= diff --git a/src/Unittests/unittests_smart_handles.cc b/src/Unittests/unittests_smart_handles.cc new file mode 100644 index 00000000..dd29ccf5 --- /dev/null +++ b/src/Unittests/unittests_smart_handles.cc @@ -0,0 +1,324 @@ +#include +#include + +#include + +#include +#include + +namespace { + +class OpenMeshSmartHandles : public OpenMeshBase { + +protected: + + // This function is called before each test is run + virtual void SetUp() { + + mesh_.clear(); + + // Add some vertices + Mesh::VertexHandle vhandle[8]; + vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1)); + vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1)); + vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1)); + vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1)); + vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1)); + vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1)); + vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1)); + vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1)); + + // Add six faces to form a cube + std::vector face_vhandles; + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[3]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[3]); + mesh_.add_face(face_vhandles); + + //======================= + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[5]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[4]); + mesh_.add_face(face_vhandles); + + //======================= + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[4]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[4]); + face_vhandles.push_back(vhandle[5]); + mesh_.add_face(face_vhandles); + + //======================= + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[1]); + face_vhandles.push_back(vhandle[5]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[5]); + face_vhandles.push_back(vhandle[6]); + mesh_.add_face(face_vhandles); + + + //======================= + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[2]); + face_vhandles.push_back(vhandle[6]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[6]); + face_vhandles.push_back(vhandle[7]); + mesh_.add_face(face_vhandles); + + //======================= + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[3]); + face_vhandles.push_back(vhandle[7]); + mesh_.add_face(face_vhandles); + + face_vhandles.clear(); + face_vhandles.push_back(vhandle[0]); + face_vhandles.push_back(vhandle[7]); + face_vhandles.push_back(vhandle[4]); + mesh_.add_face(face_vhandles); + + + // Test setup: + // + // + // 3 ======== 2 + // / /| + // / / | z + // 0 ======== 1 | | + // | | | | y + // | 7 | 6 | / + // | | / | / + // | |/ |/ + // 4 ======== 5 -------> x + // + + // Check setup + EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges"; + EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges"; + EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices"; + EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces"; + } + + // This function is called after all tests are through + virtual void TearDown() { + + // Do some final stuff with the member data here... + + mesh_.clear(); + } + + // Member already defined in OpenMeshBase + //Mesh mesh_; +}; + +/* + * ==================================================================== + * Define tests below + * ==================================================================== + */ + + + +/* Test if navigation operations on smart handles yield the expected element + */ +TEST_F(OpenMeshSmartHandles, SimpleNavigation) +{ + for (auto vh : mesh_.vertices()) + { + auto svh = OpenMesh::make_smart(vh, mesh_); + EXPECT_EQ(mesh_.halfedge_handle(vh), svh.halfedge()) << "outgoing halfedge of vertex does not match"; + } + + for (auto heh : mesh_.halfedges()) + { + auto sheh = OpenMesh::make_smart(heh, mesh_); + EXPECT_EQ(mesh_.next_halfedge_handle(heh), sheh.next()) << "next halfedge of halfedge does not match"; + EXPECT_EQ(mesh_.prev_halfedge_handle(heh), sheh.prev()) << "prevt halfedge of halfedge does not match"; + EXPECT_EQ(mesh_.opposite_halfedge_handle(heh), sheh.opp()) << "opposite halfedge of halfedge does not match"; + EXPECT_EQ(mesh_.to_vertex_handle(heh), sheh.to()) << "to vertex handle of halfedge does not match"; + EXPECT_EQ(mesh_.from_vertex_handle(heh), sheh.from()) << "from vertex handle of halfedge does not match"; + EXPECT_EQ(mesh_.face_handle(heh), sheh.face()) << "face handle of halfedge does not match"; + } + + for (auto eh : mesh_.edges()) + { + auto seh = OpenMesh::make_smart(eh, mesh_); + EXPECT_EQ(mesh_.halfedge_handle(eh, 0), seh.h0()) << "halfedge 0 of edge does not match"; + EXPECT_EQ(mesh_.halfedge_handle(eh, 1), seh.h1()) << "halfedge 1 of edge does not match"; + EXPECT_EQ(mesh_.from_vertex_handle(mesh_.halfedge_handle(eh, 0)), seh.v0()) << "first vertex of edge does not match"; + EXPECT_EQ(mesh_.to_vertex_handle (mesh_.halfedge_handle(eh, 0)), seh.v1()) << "second vertex of edge does not match"; + } + + for (auto fh : mesh_.faces()) + { + auto sfh = OpenMesh::make_smart(fh, mesh_); + EXPECT_EQ(mesh_.halfedge_handle(fh), sfh.halfedge()) << "halfedge of face does not match"; + } +} + + +/* Test if ranges yield the same elements when using smart handles + */ +TEST_F(OpenMeshSmartHandles, SimpleRanges) +{ + for (auto vh : mesh_.vertices()) + { + auto svh = OpenMesh::make_smart(vh, mesh_); + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.vv_range(vh)) + handles0.push_back(h); + for (auto h : svh.vertices()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "vertex range of vertex does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.voh_range(vh)) + handles0.push_back(h); + for (auto h : svh.outgoing_halfedges()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "outgoing halfedge range of vertex does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.vih_range(vh)) + handles0.push_back(h); + for (auto h : svh.incoming_halfedges()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "incoming halfedge range of vertex does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.ve_range(vh)) + handles0.push_back(h); + for (auto h : svh.edges()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "edge range of vertex does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.vf_range(vh)) + handles0.push_back(h); + for (auto h : svh.faces()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "face range of vertex does not match"; + } + } + + for (auto fh : mesh_.faces()) + { + auto sfh = OpenMesh::make_smart(fh, mesh_); + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.fv_range(fh)) + handles0.push_back(h); + for (auto h : sfh.vertices()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "vertex range of face does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.fh_range(fh)) + handles0.push_back(h); + for (auto h : sfh.halfedges()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "halfedge range of face does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.fe_range(fh)) + handles0.push_back(h); + for (auto h : sfh.edges()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "edge range of face does not match"; + } + { + std::vector handles0; + std::vector handles1; + for (auto h : mesh_.ff_range(fh)) + handles0.push_back(h); + for (auto h : sfh.faces()) + handles1.push_back(h); + EXPECT_EQ(handles0, handles1) << "face range of face does not match"; + } + } +} + + +/* Test a chain of navigation on a cube + */ +TEST_F(OpenMeshSmartHandles, ComplicatedNavigtaion) +{ + for (auto vh : mesh_.vertices()) + { + auto svh = OpenMesh::make_smart(vh, mesh_); + EXPECT_EQ(mesh_.next_halfedge_handle( + mesh_.opposite_halfedge_handle( + mesh_.halfedge_handle(vh))), + svh.out().opp().next()); + EXPECT_EQ(mesh_.prev_halfedge_handle( + mesh_.prev_halfedge_handle( + mesh_.opposite_halfedge_handle( + mesh_.next_halfedge_handle( + mesh_.next_halfedge_handle( + mesh_.halfedge_handle(vh)))))), + svh.out().next().next().opp().prev().prev()); + EXPECT_EQ(mesh_.face_handle( + mesh_.opposite_halfedge_handle( + mesh_.halfedge_handle( + mesh_.face_handle( + mesh_.opposite_halfedge_handle( + mesh_.next_halfedge_handle( + mesh_.halfedge_handle(vh))))))), + svh.out().next().opp().face().halfedge().opp().face()); + } +} + + +}