text: #ifndef TEST_HALF_EDGE_STRUCTURE_H
  #define TEST_HALF_EDGE_STRUCTURE_H
  
  // Libraries
  #include <reactphysics3d/reactphysics3d.h>
  #include "Test.h"
  #include <vector>
  
  /// Reactphysics3D namespace
  namespace reactphysics3d {
  
  
  // Class TestHalfEdgeStructure
  /**
   * Unit test for the HalfEdgeStructure class.
   */
  class TestHalfEdgeStructure : public Test {
  
      private :
  
          // ---------- Atributes ---------- //
  
          /// Memory allocator
          DefaultAllocator mAllocator;
  
  
      public :
  
          // ---------- Methods ---------- //
  
          /// Constructor
          TestHalfEdgeStructure(const std::string& name) : Test(name) {
  
          }
  
          /// Destructor
          virtual ~TestHalfEdgeStructure() {
  
          }
  
          /// Run the tests
          void run() {
              testCube();
              testTetrahedron();
          }
  
          void testCube() {
  
              // Create the half-edge structure for a cube
              rp3d::HalfEdgeStructure cubeStructure(mAllocator, 6, 8, 24);
  
              rp3d::Vector3 vertices[8] = {
                  rp3d::Vector3(-0.5, -0.5, 0.5),
                  rp3d::Vector3(0.5, -0.5, 0.5),
                  rp3d::Vector3(0.5, 0.5, 0.5),
                  rp3d::Vector3(-0.5, 0.5, 0.5),
                  rp3d::Vector3(-0.5, -0.5, -0.5),
                  rp3d::Vector3(0.5, -0.5, -0.5),
                  rp3d::Vector3(0.5, 0.5, -0.5),
                  rp3d::Vector3(-0.5, 0.5, -0.5)
              };
  
              // Vertices
              cubeStructure.addVertex(0);
              cubeStructure.addVertex(1);
              cubeStructure.addVertex(2);
              cubeStructure.addVertex(3);
              cubeStructure.addVertex(4);
              cubeStructure.addVertex(5);
              cubeStructure.addVertex(6);
              cubeStructure.addVertex(7);
  
              // Faces
              List<uint> face0(mAllocator, 4);
              face0.add(0); face0.add(1); face0.add(2); face0.add(3);
              List<uint> face1(mAllocator, 4);
              face1.add(1); face1.add(5); face1.add(6); face1.add(2);
              List<uint> face2(mAllocator, 4);
              face2.add(5); face2.add(4); face2.add(7); face2.add(6);
              List<uint> face3(mAllocator, 4);
              face3.add(4); face3.add(0); face3.add(3); face3.add(7);
              List<uint> face4(mAllocator, 4);
              face4.add(0); face4.add(4); face4.add(5); face4.add(1);
              List<uint> face5(mAllocator, 4);
              face5.add(2); face5.add(6); face5.add(7); face5.add(3);
  
              cubeStructure.addFace(face0);
              cubeStructure.addFace(face1);
              cubeStructure.addFace(face2);
              cubeStructure.addFace(face3);
              cubeStructure.addFace(face4);
              cubeStructure.addFace(face5);
  
              cubeStructure.init();
  
              // --- Test that the half-edge structure of the cube is valid --- //
  
              rp3d_test(cubeStructure.getNbFaces() == 6);
              rp3d_test(cubeStructure.getNbVertices() == 8);
              rp3d_test(cubeStructure.getNbHalfEdges() == 24);
  
              // Test vertices
              rp3d_test(vertices[cubeStructure.getVertex(0).vertexPointIndex].x == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(0).vertexPointIndex].y == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(0).vertexPointIndex].z == 0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(0).edgeIndex).vertexIndex == 0);
  
              rp3d_test(vertices[cubeStructure.getVertex(1).vertexPointIndex].x == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(1).vertexPointIndex].y == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(1).vertexPointIndex].z == 0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(1).edgeIndex).vertexIndex == 1);
  
              rp3d_test(vertices[cubeStructure.getVertex(2).vertexPointIndex].x == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(2).vertexPointIndex].y == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(2).vertexPointIndex].z == 0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(2).edgeIndex).vertexIndex == 2);
  
              rp3d_test(vertices[cubeStructure.getVertex(3).vertexPointIndex].x == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(3).vertexPointIndex].y == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(3).vertexPointIndex].z == 0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(3).edgeIndex).vertexIndex == 3);
  
              rp3d_test(vertices[cubeStructure.getVertex(4).vertexPointIndex].x == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(4).vertexPointIndex].y == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(4).vertexPointIndex].z == -0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(4).edgeIndex).vertexIndex == 4);
  
              rp3d_test(vertices[cubeStructure.getVertex(5).vertexPointIndex].x == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(5).vertexPointIndex].y == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(5).vertexPointIndex].z == -0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(5).edgeIndex).vertexIndex == 5);
  
              rp3d_test(vertices[cubeStructure.getVertex(6).vertexPointIndex].x == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(6).vertexPointIndex].y == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(6).vertexPointIndex].z == -0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(6).edgeIndex).vertexIndex == 6);
  
              rp3d_test(vertices[cubeStructure.getVertex(7).vertexPointIndex].x == -0.5);
              rp3d_test(vertices[cubeStructure.getVertex(7).vertexPointIndex].y == 0.5);
              rp3d_test(vertices[cubeStructure.getVertex(7).vertexPointIndex].z == -0.5);
              rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getVertex(7).edgeIndex).vertexIndex == 7);
  
              // Test faces
              for (uint f=0; f<6; f++) {
                  rp3d_test(cubeStructure.getHalfEdge(cubeStructure.getFace(f).edgeIndex).faceIndex == f);
              }
  
              // Test edges
              for (uint f=0; f<6; f++) {
  
  
                  uint edgeIndex = cubeStructure.getFace(f).edgeIndex;
                  const uint firstEdgeIndex = edgeIndex;
  
                  // For each half-edge of the face
                  for (uint e=0; e<4; e++) {
  
                      rp3d::HalfEdgeStructure::Edge edge = cubeStructure.getHalfEdge(edgeIndex);
  
                      rp3d_test(cubeStructure.getHalfEdge(edge.twinEdgeIndex).twinEdgeIndex == edgeIndex);
                      rp3d_test(edge.faceIndex == f);
  
                      // Go to the next edge
                      edgeIndex = edge.nextEdgeIndex;
                  }
  
                  rp3d_test(firstEdgeIndex == edgeIndex);
              }
          }
  
          void testTetrahedron() {
  
              // Create the half-edge structure for a tetrahedron
              std::vector<std::vector<uint>> faces;
              rp3d::HalfEdgeStructure tetrahedron(mAllocator, 4, 4, 12);
  
              // Vertices
              rp3d::Vector3 vertices[4] = {
                  rp3d::Vector3(1, -1, -1),
                  rp3d::Vector3(-1, -1, -1),
                  rp3d::Vector3(0, -1, 1),
                  rp3d::Vector3(0, 1, 0)
              };
  
              tetrahedron.addVertex(0);
              tetrahedron.addVertex(1);
              tetrahedron.addVertex(2);
              tetrahedron.addVertex(3);
  
              // Faces
              List<uint> face0(mAllocator, 3);
              face0.add(0); face0.add(1); face0.add(2);
              List<uint> face1(mAllocator, 3);
              face1.add(0); face1.add(3); face1.add(1);
              List<uint> face2(mAllocator, 3);
              face2.add(1); face2.add(3); face2.add(2);
              List<uint> face3(mAllocator, 3);
              face3.add(0); face3.add(2); face3.add(3);
  
              tetrahedron.addFace(face0);
              tetrahedron.addFace(face1);
              tetrahedron.addFace(face2);
              tetrahedron.addFace(face3);
  
              tetrahedron.init();
  
              // --- Test that the half-edge structure of the tetrahedron is valid --- //
  
              rp3d_test(tetrahedron.getNbFaces() == 4);
              rp3d_test(tetrahedron.getNbVertices() == 4);
              rp3d_test(tetrahedron.getNbHalfEdges() == 12);
  
              // Test vertices
              rp3d_test(vertices[tetrahedron.getVertex(0).vertexPointIndex].x == 1);
              rp3d_test(vertices[tetrahedron.getVertex(0).vertexPointIndex].y == -1);
              rp3d_test(vertices[tetrahedron.getVertex(0).vertexPointIndex].z == -1);
              rp3d_test(tetrahedron.getHalfEdge(tetrahedron.getVertex(0).edgeIndex).vertexIndex == 0);
  
              rp3d_test(vertices[tetrahedron.getVertex(1).vertexPointIndex].x == -1);
              rp3d_test(vertices[tetrahedron.getVertex(1).vertexPointIndex].y == -1);
              rp3d_test(vertices[tetrahedron.getVertex(1).vertexPointIndex].z == -1);
              rp3d_test(tetrahedron.getHalfEdge(tetrahedron.getVertex(1).edgeIndex).vertexIndex == 1);
  
              rp3d_test(vertices[tetrahedron.getVertex(2).vertexPointIndex].x == 0);
              rp3d_test(vertices[tetrahedron.getVertex(2).vertexPointIndex].y == -1);
              rp3d_test(vertices[tetrahedron.getVertex(2).vertexPointIndex].z == 1);
              rp3d_test(tetrahedron.getHalfEdge(tetrahedron.getVertex(2).edgeIndex).vertexIndex == 2);
  
              rp3d_test(vertices[tetrahedron.getVertex(3).vertexPointIndex].x == 0);
              rp3d_test(vertices[tetrahedron.getVertex(3).vertexPointIndex].y == 1);
              rp3d_test(vertices[tetrahedron.getVertex(3).vertexPointIndex].z == 0);
              rp3d_test(tetrahedron.getHalfEdge(tetrahedron.getVertex(3).edgeIndex).vertexIndex == 3);
  
              // Test faces
              for (uint f=0; f<4; f++) {
                  rp3d_test(tetrahedron.getHalfEdge(tetrahedron.getFace(f).edgeIndex).faceIndex == f);
              }
  
              // Test edges
              for (uint f=0; f<4; f++) {
  
                  uint edgeIndex = tetrahedron.getFace(f).edgeIndex;
                  const uint firstEdgeIndex = edgeIndex;
  
                  // For each half-edge of the face
                  for (uint e=0; e<3; e++) {
  
                      rp3d::HalfEdgeStructure::Edge edge = tetrahedron.getHalfEdge(edgeIndex);
  
                      rp3d_test(tetrahedron.getHalfEdge(edge.twinEdgeIndex).twinEdgeIndex == edgeIndex);
                      rp3d_test(edge.faceIndex == f);
  
                      // Go to the next edge
                      edgeIndex = edge.nextEdgeIndex;
                  }
  
                  rp3d_test(firstEdgeIndex == edgeIndex);
              }
          }
   };
  
  }
  
  #endif
  