// David Eberly, Geometric Tools, Redmond WA 98052 // Copyright (c) 1998-2020 // Distributed under the Boost Software License, Version 1.0. // https://www.boost.org/LICENSE_1_0.txt // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt // Version: 4.0.2019.08.13 #pragma once #include #include #include #include // The Polyhedron3 object represents a simple polyhedron. The 'vertexPool' // array can contain more points than needed to define the polyhedron, which // allows the vertex pool to have multiple polyhedra associated with it. // Thus, the programmer must ensure that the vertex pool persists as long as // any Polyhedron3 objects exist that depend on the pool. The number of // polyhedron indices is 'numIndices' and must be 6 or larger The 'indices' // array refers to the points in 'vertexPool' that form the triangle faces, // so 'numIndices' must be a multiple of 3. The number of vertices is // the number of unique elements in 'indices' and is determined during // construction. The programmer should ensure the polyhedron is simple. The // geometric queries are valid regardless of whether the polyhedron triangles // are oriented clockwise or counterclockwise. // // NOTE: Comparison operators are not provided. The semantics of equal // polyhedra is complicated and (at the moment) not useful. The vertex pools // can be different and indices do not match, but the vertices they reference // can match. Even with a shared vertex pool, the indices can be permuted, // leading to the same polyhedron abstractly but the data structures do not // match. namespace WwiseGTE { template class Polyhedron3 { public: // Construction. The constructor succeeds when 'numIndices >= 12' (at // least 4 triangles), and 'vertexPool' and 'indices' are not null; we // cannot test whether you have a valid number of elements in the // input arrays. A copy is made of 'indices', but the 'vertexPool' is // not copied. If the constructor fails, the internal vertex pointer // is set to null, the number of vertices is set to zero, the index // array has no elements, and the triangle face orientation is set to // clockwise. Polyhedron3(std::shared_ptr>> const& vertexPool, int numIndices, int const* indices, bool counterClockwise) : mVertexPool(vertexPool), mCounterClockwise(counterClockwise) { if (vertexPool && indices && numIndices >= 12 && (numIndices % 3) == 0) { for (int i = 0; i < numIndices; ++i) { mUniqueIndices.insert(indices[i]); } mIndices.resize(numIndices); std::copy(indices, indices + numIndices, mIndices.begin()); } else { // Encountered an invalid input. mVertexPool = nullptr; mCounterClockwise = false; } } // To validate construction, create an object as shown: // Polyhedron3 polyhedron(parameters); // if (!polyhedron) { ; } inline operator bool() const { return mVertexPool != nullptr; } // Member access. inline std::shared_ptr>> const& GetVertexPool() const { return mVertexPool; } inline std::vector> const& GetVertices() const { return *mVertexPool.get(); } inline std::set const& GetUniqueIndices() const { return mUniqueIndices; } inline std::vector const& GetIndices() const { return mIndices; } inline bool CounterClockwise() const { return mCounterClockwise; } // Geometric queries. Vector3 ComputeVertexAverage() const { Vector3 average = Vector3::Zero(); if (mVertexPool) { auto vertexPool = GetVertices(); for (int index : mUniqueIndices) { average += vertexPool[index]; } average /= static_cast(mUniqueIndices.size()); } return average; } Real ComputeSurfaceArea() const { Real surfaceArea(0); if (mVertexPool) { auto vertexPool = GetVertices(); int const numTriangles = static_cast(mIndices.size()) / 3; int const* indices = mIndices.data(); for (int t = 0; t < numTriangles; ++t) { int v0 = *indices++; int v1 = *indices++; int v2 = *indices++; Vector3 edge0 = vertexPool[v1] - vertexPool[v0]; Vector3 edge1 = vertexPool[v2] - vertexPool[v0]; Vector3 cross = Cross(edge0, edge1); surfaceArea += Length(cross); } surfaceArea *= (Real)0.5; } return surfaceArea; } Real ComputeVolume() const { Real volume(0); if (mVertexPool) { auto vertexPool = GetVertices(); int const numTriangles = static_cast(mIndices.size()) / 3; int const* indices = mIndices.data(); for (int t = 0; t < numTriangles; ++t) { int v0 = *indices++; int v1 = *indices++; int v2 = *indices++; volume += DotCross(vertexPool[v0], vertexPool[v1], vertexPool[v2]); } volume /= (Real)6; } return std::fabs(volume); } private: std::shared_ptr>> mVertexPool; std::set mUniqueIndices; std::vector mIndices; bool mCounterClockwise; }; }