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