diff --git a/documentation/UserManual/ReactPhysics3D-UserManual.tex b/documentation/UserManual/ReactPhysics3D-UserManual.tex index 60ff1353..dabb5bc8 100644 --- a/documentation/UserManual/ReactPhysics3D-UserManual.tex +++ b/documentation/UserManual/ReactPhysics3D-UserManual.tex @@ -1236,6 +1236,9 @@ ConvexMeshShape* convexMeshShape = physicsCommon.createConvexMeshShape(polyhedro that you need to avoid coplanar faces in your convex mesh shape. Coplanar faces have to be merged together. Remember that convex meshes are not limited to triangular faces, you can create faces with more than three vertices. \\ + Also note that meshes with duplicated vertices are not supported. The number of vertices you pass to create the PolygonVertexArray must be exactly + the number of vertices in your convex mesh. \\ + When you specify the vertices for each face of your convex mesh, be careful with their order. The vertices of a face must be specified in counter clockwise order as seen from the outside of your convex mesh. \\ diff --git a/include/reactphysics3d/collision/PolyhedronMesh.h b/include/reactphysics3d/collision/PolyhedronMesh.h index f4e57bc9..210173d7 100644 --- a/include/reactphysics3d/collision/PolyhedronMesh.h +++ b/include/reactphysics3d/collision/PolyhedronMesh.h @@ -28,6 +28,7 @@ // Libraries #include <reactphysics3d/mathematics/mathematics.h> +#include <reactphysics3d/containers/Array.h> #include "HalfEdgeStructure.h" namespace reactphysics3d { @@ -69,7 +70,7 @@ class PolyhedronMesh { PolyhedronMesh(PolygonVertexArray* polygonVertexArray, MemoryAllocator& allocator); /// Create the half-edge structure of the mesh - void createHalfEdgeStructure(); + bool createHalfEdgeStructure(); /// Compute the faces normals void computeFacesNormals(); @@ -80,6 +81,9 @@ class PolyhedronMesh { /// Compute and return the area of a face decimal getFaceArea(uint faceIndex) const; + /// Static factory method to create a polyhedron mesh + static PolyhedronMesh* create(PolygonVertexArray* polygonVertexArray, MemoryAllocator& polyhedronMeshAllocator, MemoryAllocator& dataAllocator); + public: // -------------------- Methods -------------------- // diff --git a/src/collision/PolyhedronMesh.cpp b/src/collision/PolyhedronMesh.cpp index 9d92fc00..b205b1cd 100644 --- a/src/collision/PolyhedronMesh.cpp +++ b/src/collision/PolyhedronMesh.cpp @@ -27,6 +27,8 @@ #include <reactphysics3d/collision/PolyhedronMesh.h> #include <reactphysics3d/memory/MemoryManager.h> #include <reactphysics3d/collision/PolygonVertexArray.h> +#include <reactphysics3d/utils/DefaultLogger.h> +#include <reactphysics3d/engine/PhysicsCommon.h> #include <cstdlib> using namespace reactphysics3d; @@ -37,38 +39,62 @@ using namespace reactphysics3d; * Create a polyhedron mesh given an array of polygons. * @param polygonVertexArray Pointer to the array of polygons and their vertices */ -PolyhedronMesh::PolyhedronMesh(PolygonVertexArray* polygonVertexArray, MemoryAllocator &allocator) +PolyhedronMesh::PolyhedronMesh(PolygonVertexArray* polygonVertexArray, MemoryAllocator& allocator) : mMemoryAllocator(allocator), mHalfEdgeStructure(allocator, polygonVertexArray->getNbFaces(), polygonVertexArray->getNbVertices(), - (polygonVertexArray->getNbFaces() + polygonVertexArray->getNbVertices() - 2) * 2) { + (polygonVertexArray->getNbFaces() + polygonVertexArray->getNbVertices() - 2) * 2), mFacesNormals(nullptr) { mPolygonVertexArray = polygonVertexArray; - - // Create the half-edge structure of the mesh - createHalfEdgeStructure(); - - // Create the face normals array - mFacesNormals = new Vector3[mHalfEdgeStructure.getNbFaces()]; - - // Compute the faces normals - computeFacesNormals(); - - // Compute the centroid - computeCentroid(); } // Destructor PolyhedronMesh::~PolyhedronMesh() { - delete[] mFacesNormals; + + if (mFacesNormals != nullptr) { + + for (uint f=0; f < mHalfEdgeStructure.getNbFaces(); f++) { + mFacesNormals[f].~Vector3(); + } + + mMemoryAllocator.release(mFacesNormals, mHalfEdgeStructure.getNbFaces() * sizeof(Vector3)); + } +} + +/// Static factory method to create a polyhedron mesh. This methods returns null_ptr if the mesh is not valid +PolyhedronMesh* PolyhedronMesh::create(PolygonVertexArray* polygonVertexArray, MemoryAllocator& polyhedronMeshAllocator, MemoryAllocator& dataAllocator) { + + PolyhedronMesh* mesh = new (polyhedronMeshAllocator.allocate(sizeof(PolyhedronMesh))) PolyhedronMesh(polygonVertexArray, dataAllocator); + + // Create the half-edge structure of the mesh + bool isValid = mesh->createHalfEdgeStructure(); + + if (isValid) { + + // Compute the faces normals + mesh->computeFacesNormals(); + + // Compute the centroid + mesh->computeCentroid(); + } + else { + mesh->~PolyhedronMesh(); + polyhedronMeshAllocator.release(mesh, sizeof(PolyhedronMesh)); + mesh = nullptr; + } + + return mesh; } // Create the half-edge structure of the mesh -void PolyhedronMesh::createHalfEdgeStructure() { +/// This method returns true if the mesh is valid or false otherwise +bool PolyhedronMesh::createHalfEdgeStructure() { // For each vertex of the mesh for (uint v=0; v < mPolygonVertexArray->getNbVertices(); v++) { mHalfEdgeStructure.addVertex(v); } + uint32 nbEdges = 0; + // For each polygon face of the mesh for (uint f=0; f < mPolygonVertexArray->getNbFaces(); f++) { @@ -82,14 +108,34 @@ void PolyhedronMesh::createHalfEdgeStructure() { faceVertices.add(mPolygonVertexArray->getVertexIndexInFace(f, v)); } + nbEdges += face->nbVertices; + assert(faceVertices.size() >= 3); // Addd the face into the half-edge structure mHalfEdgeStructure.addFace(faceVertices); } + nbEdges /= 2; + + // If the mesh is valid (check Euler formula V + F - E = 2) and does not use duplicated vertices + if (2 + nbEdges - mPolygonVertexArray->getNbFaces() != mPolygonVertexArray->getNbVertices()) { + + RP3D_LOG("PhysicsCommon", Logger::Level::Error, Logger::Category::PhysicCommon, + "Error when creating a PolyhedronMesh: input PolygonVertexArray is not valid. Mesh with duplicated vertices is not supported.", __FILE__, __LINE__); + + assert(false); + + return false; + } + // Initialize the half-edge structure mHalfEdgeStructure.init(); + + // Create the face normals array + mFacesNormals = new (mMemoryAllocator.allocate(mHalfEdgeStructure.getNbFaces() * sizeof(Vector3))) Vector3[mHalfEdgeStructure.getNbFaces()]; + + return true; } /// Return a vertex diff --git a/src/engine/PhysicsCommon.cpp b/src/engine/PhysicsCommon.cpp index 08ef4248..a36e6e26 100644 --- a/src/engine/PhysicsCommon.cpp +++ b/src/engine/PhysicsCommon.cpp @@ -488,13 +488,18 @@ void PhysicsCommon::deleteConcaveMeshShape(ConcaveMeshShape* concaveMeshShape) { // Create a polyhedron mesh /** * @param polygonVertexArray A pointer to the polygon vertex array to use to create the polyhedron mesh - * @return A pointer to the created polyhedron mesh + * @return A pointer to the created polyhedron mesh or nullptr if the mesh is not valid */ PolyhedronMesh* PhysicsCommon::createPolyhedronMesh(PolygonVertexArray* polygonVertexArray) { - PolyhedronMesh* mesh = new (mMemoryManager.allocate(MemoryManager::AllocationType::Pool, sizeof(PolyhedronMesh))) PolyhedronMesh(polygonVertexArray, mMemoryManager.getHeapAllocator()); + // Create the polyhedron mesh + PolyhedronMesh* mesh = PolyhedronMesh::create(polygonVertexArray, mMemoryManager.getPoolAllocator(), mMemoryManager.getHeapAllocator()); - mPolyhedronMeshes.add(mesh); + // If the mesh is valid + if (mesh != nullptr) { + + mPolyhedronMeshes.add(mesh); + } return mesh; }