1 /********************************************************************************
2 * ReactPhysics3D physics library, http://www.reactphysics3d.com                 *
3 * Copyright (c) 2010-2020 Daniel Chappuis                                       *
4 *********************************************************************************
5 *                                                                               *
6 * This software is provided 'as-is', without any express or implied warranty.   *
7 * In no event will the authors be held liable for any damages arising from the  *
8 * use of this software.                                                         *
9 *                                                                               *
10 * Permission is granted to anyone to use this software for any purpose,         *
11 * including commercial applications, and to alter it and redistribute it        *
12 * freely, subject to the following restrictions:                                *
13 *                                                                               *
14 * 1. The origin of this software must not be misrepresented; you must not claim *
15 *    that you wrote the original software. If you use this software in a        *
16 *    product, an acknowledgment in the product documentation would be           *
17 *    appreciated but is not required.                                           *
18 *                                                                               *
19 * 2. Altered source versions must be plainly marked as such, and must not be    *
20 *    misrepresented as being the original software.                             *
21 *                                                                               *
22 * 3. This notice may not be removed or altered from any source distribution.    *
23 *                                                                               *
24 ********************************************************************************/
25 
26 // Libraries
27 #include <reactphysics3d/collision/PolyhedronMesh.h>
28 #include <reactphysics3d/memory/MemoryManager.h>
29 #include <reactphysics3d/collision/PolygonVertexArray.h>
30 #include <cstdlib>
31 
32 using namespace reactphysics3d;
33 
34 
35 // Constructor
36 /**
37  * Create a polyhedron mesh given an array of polygons.
38  * @param polygonVertexArray Pointer to the array of polygons and their vertices
39  */
PolyhedronMesh(PolygonVertexArray * polygonVertexArray,MemoryAllocator & allocator)40 PolyhedronMesh::PolyhedronMesh(PolygonVertexArray* polygonVertexArray, MemoryAllocator &allocator)
41                : mMemoryAllocator(allocator), mHalfEdgeStructure(allocator, polygonVertexArray->getNbFaces(), polygonVertexArray->getNbVertices(),
42                                     (polygonVertexArray->getNbFaces() + polygonVertexArray->getNbVertices() - 2) * 2) {
43 
44    mPolygonVertexArray = polygonVertexArray;
45 
46    // Create the half-edge structure of the mesh
47    createHalfEdgeStructure();
48 
49    // Create the face normals array
50    mFacesNormals = new Vector3[mHalfEdgeStructure.getNbFaces()];
51 
52    // Compute the faces normals
53    computeFacesNormals();
54 
55    // Compute the centroid
56    computeCentroid();
57 }
58 
59 // Destructor
~PolyhedronMesh()60 PolyhedronMesh::~PolyhedronMesh() {
61     delete[] mFacesNormals;
62 }
63 
64 // Create the half-edge structure of the mesh
createHalfEdgeStructure()65 void PolyhedronMesh::createHalfEdgeStructure() {
66 
67     // For each vertex of the mesh
68     for (uint v=0; v < mPolygonVertexArray->getNbVertices(); v++) {
69         mHalfEdgeStructure.addVertex(v);
70     }
71 
72     // For each polygon face of the mesh
73     for (uint f=0; f < mPolygonVertexArray->getNbFaces(); f++) {
74 
75         // Get the polygon face
76         PolygonVertexArray::PolygonFace* face = mPolygonVertexArray->getPolygonFace(f);
77 
78         List<uint> faceVertices(mMemoryAllocator, face->nbVertices);
79 
80         // For each vertex of the face
81         for (uint v=0; v < face->nbVertices; v++) {
82             faceVertices.add(mPolygonVertexArray->getVertexIndexInFace(f, v));
83         }
84 
85         assert(faceVertices.size() >= 3);
86 
87         // Addd the face into the half-edge structure
88         mHalfEdgeStructure.addFace(faceVertices);
89     }
90 
91     // Initialize the half-edge structure
92     mHalfEdgeStructure.init();
93 }
94 
95 /// Return a vertex
96 /**
97  * @param index Index of a given vertex in the mesh
98  * @return The coordinates of a given vertex in the mesh
99  */
getVertex(uint index) const100 Vector3 PolyhedronMesh::getVertex(uint index) const {
101     assert(index < getNbVertices());
102 
103     // Get the vertex index in the array with all vertices
104     uint vertexIndex = mHalfEdgeStructure.getVertex(index).vertexPointIndex;
105 
106     PolygonVertexArray::VertexDataType vertexType = mPolygonVertexArray->getVertexDataType();
107     const unsigned char* verticesStart = mPolygonVertexArray->getVerticesStart();
108     int vertexStride = mPolygonVertexArray->getVerticesStride();
109 
110     Vector3 vertex;
111     if (vertexType == PolygonVertexArray::VertexDataType::VERTEX_FLOAT_TYPE) {
112         const float* vertices = (float*)(verticesStart + vertexIndex * vertexStride);
113         vertex.x = decimal(vertices[0]);
114         vertex.y = decimal(vertices[1]);
115         vertex.z = decimal(vertices[2]);
116     }
117     else if (vertexType == PolygonVertexArray::VertexDataType::VERTEX_DOUBLE_TYPE) {
118         const double* vertices = (double*)(verticesStart + vertexIndex * vertexStride);
119         vertex.x = decimal(vertices[0]);
120         vertex.y = decimal(vertices[1]);
121         vertex.z = decimal(vertices[2]);
122     }
123     else {
124         assert(false);
125     }
126 
127     return vertex;
128 }
129 
130 // Compute the faces normals
computeFacesNormals()131 void PolyhedronMesh::computeFacesNormals() {
132 
133     // For each face
134     for (uint f=0; f < mHalfEdgeStructure.getNbFaces(); f++) {
135         const HalfEdgeStructure::Face& face = mHalfEdgeStructure.getFace(f);
136 
137         assert(face.faceVertices.size() >= 3);
138 
139         const Vector3 vec1 = getVertex(face.faceVertices[1]) - getVertex(face.faceVertices[0]);
140         const Vector3 vec2 = getVertex(face.faceVertices[2]) - getVertex(face.faceVertices[0]);
141         mFacesNormals[f] = vec1.cross(vec2);
142         mFacesNormals[f].normalize();
143     }
144 }
145 
146 // Compute the centroid of the polyhedron
computeCentroid()147 void PolyhedronMesh::computeCentroid() {
148 
149     mCentroid.setToZero();
150 
151     for (uint v=0; v < getNbVertices(); v++) {
152         mCentroid += getVertex(v);
153     }
154 
155     mCentroid /= getNbVertices();
156 }
157 
158 // Compute and return the area of a face
getFaceArea(uint faceIndex) const159 decimal PolyhedronMesh::getFaceArea(uint faceIndex) const {
160 
161     Vector3 sumCrossProducts(0, 0, 0);
162 
163     const HalfEdgeStructure::Face& face = mHalfEdgeStructure.getFace(faceIndex);
164     assert(face.faceVertices.size() >= 3);
165 
166     Vector3 v1 = getVertex(face.faceVertices[0]);
167 
168     // For each vertex of the face
169     for (uint i=2; i < face.faceVertices.size(); i++) {
170 
171         const Vector3 v2 = getVertex(face.faceVertices[i-1]);
172         const Vector3 v3 = getVertex(face.faceVertices[i]);
173 
174         const Vector3 v1v2 = v2 - v1;
175         const Vector3 v1v3 = v3 - v1;
176 
177         sumCrossProducts +=  v1v2.cross(v1v3);
178     }
179 
180     return decimal(0.5) * sumCrossProducts.length();
181 }
182 
183 // Compute and return the volume of the polyhedron
184 /// We use the divergence theorem to compute the volume of the polyhedron using a sum over its faces.
getVolume() const185 decimal PolyhedronMesh::getVolume() const {
186 
187     decimal sum = 0.0;
188 
189     // For each face of the polyhedron
190     for (uint f=0; f < getNbFaces(); f++) {
191 
192         const HalfEdgeStructure::Face& face = mHalfEdgeStructure.getFace(f);
193         const decimal faceArea = getFaceArea(f);
194         const Vector3 faceNormal = mFacesNormals[f];
195         const Vector3 faceVertex = getVertex(face.faceVertices[0]);
196 
197         sum += faceVertex.dot(faceNormal) * faceArea;
198     }
199 
200     return std::abs(sum) / decimal(3.0);
201 }
202