123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271 |
- // 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 <Mathematics/Logger.h>
- #include <array>
- #include <map>
- #include <memory>
- namespace WwiseGTE
- {
- class VEManifoldMesh
- {
- public:
- // Vertex data types.
- class Vertex;
- typedef std::shared_ptr<Vertex>(*VCreator)(int);
- typedef std::map<int, std::shared_ptr<Vertex>> VMap;
- // Edge data types.
- class Edge;
- typedef std::shared_ptr<Edge>(*ECreator)(int, int);
- typedef std::map<std::pair<int, int>, std::shared_ptr<Edge>> EMap;
- // Vertex object.
- class Vertex
- {
- public:
- virtual ~Vertex() = default;
- Vertex(int v)
- :
- V(v)
- {
- }
- // The unique vertex index.
- int V;
- // The edges (if any) sharing the vertex.
- std::array<std::weak_ptr<Edge>, 2> E;
- };
- // Edge object.
- class Edge
- {
- public:
- virtual ~Edge() = default;
- Edge(int v0, int v1)
- :
- V{ v0, v1 }
- {
- }
- // Vertices, listed as a directed edge <V[0],V[1]>.
- std::array<int, 2> V;
- // Adjacent edges. E[i] points to edge sharing V[i].
- std::array<std::weak_ptr<Edge>, 2> E;
- };
- // Construction and destruction.
- virtual ~VEManifoldMesh() = default;
- VEManifoldMesh(VCreator vCreator = nullptr, ECreator eCreator = nullptr)
- :
- mVCreator(vCreator ? vCreator : CreateVertex),
- mECreator(eCreator ? eCreator : CreateEdge),
- mThrowOnNonmanifoldInsertion(true)
- {
- }
- // Member access.
- inline VMap const& GetVertices() const
- {
- return mVMap;
- }
- inline EMap const& GetEdges() const
- {
- return mEMap;
- }
- // If the insertion of an edge fails because the mesh would become
- // nonmanifold, the default behavior is to throw an exception. You
- // can disable this behavior and continue gracefully without an
- // exception.
- void ThrowOnNonmanifoldInsertion(bool doException)
- {
- mThrowOnNonmanifoldInsertion = doException;
- }
- // If <v0,v1> is not in the mesh, an Edge object is created and
- // returned; otherwise, <v0,v1> is in the mesh and nullptr is
- // returned. If the insertion leads to a nonmanifold mesh, the
- // call fails with a nullptr returned.
- std::shared_ptr<Edge> Insert(int v0, int v1)
- {
- std::pair<int, int> ekey(v0, v1);
- if (mEMap.find(ekey) != mEMap.end())
- {
- // The edge already exists. Return a null pointer as a
- // signal to the caller that the insertion failed.
- return nullptr;
- }
- // Add the new edge.
- std::shared_ptr<Edge> edge = mECreator(v0, v1);
- mEMap[ekey] = edge;
- // Add the vertices if they do not already exist.
- for (int i = 0; i < 2; ++i)
- {
- int v = edge->V[i];
- std::shared_ptr<Vertex> vertex;
- auto viter = mVMap.find(v);
- if (viter == mVMap.end())
- {
- // This is the first time the vertex is encountered.
- vertex = mVCreator(v);
- mVMap[v] = vertex;
- // Update the vertex.
- vertex->E[0] = edge;
- }
- else
- {
- // This is the second time the vertex is encountered.
- vertex = viter->second;
- LogAssert(vertex != nullptr, "Unexpected condition.");
- // Update the vertex.
- if (vertex->E[1].lock())
- {
- if (mThrowOnNonmanifoldInsertion)
- {
- LogError("The mesh must be manifold.");
- }
- else
- {
- return nullptr;
- }
- }
- vertex->E[1] = edge;
- // Update the adjacent edge.
- auto adjacent = vertex->E[0].lock();
- LogAssert(adjacent != nullptr, "Unexpected condition.");
- for (int j = 0; j < 2; ++j)
- {
- if (adjacent->V[j] == v)
- {
- adjacent->E[j] = edge;
- break;
- }
- }
- // Update the edge.
- edge->E[i] = adjacent;
- }
- }
- return edge;
- }
- // If <v0,v1> is in the mesh, it is removed and 'true' is returned;
- // otherwise, <v0,v1> is not in the mesh and 'false' is returned.
- bool Remove(int v0, int v1)
- {
- std::pair<int, int> ekey(v0, v1);
- auto eiter = mEMap.find(ekey);
- if (eiter == mEMap.end())
- {
- // The edge does not exist.
- return false;
- }
- // Get the edge.
- std::shared_ptr<Edge> edge = eiter->second;
- // Remove the vertices if necessary (when they are not shared).
- for (int i = 0; i < 2; ++i)
- {
- // Inform the vertices the edge is being deleted.
- auto viter = mVMap.find(edge->V[i]);
- LogAssert(viter != mVMap.end(), "Unexpected condition.");
- std::shared_ptr<Vertex> vertex = viter->second;
- LogAssert(vertex != nullptr, "Unexpected condition.");
- if (vertex->E[0].lock() == edge)
- {
- // One-edge vertices always have pointer at index zero.
- vertex->E[0] = vertex->E[1];
- vertex->E[1].reset();
- }
- else if (vertex->E[1].lock() == edge)
- {
- vertex->E[1].reset();
- }
- else
- {
- LogError("Unexpected condition.");
- }
- // Remove the vertex if you have the last reference to it.
- if (!vertex->E[0].lock() && !vertex->E[1].lock())
- {
- mVMap.erase(vertex->V);
- }
- // Inform adjacent edges the edge is being deleted.
- auto adjacent = edge->E[i].lock();
- if (adjacent)
- {
- for (int j = 0; j < 2; ++j)
- {
- if (adjacent->E[j].lock() == edge)
- {
- adjacent->E[j].reset();
- break;
- }
- }
- }
- }
- mEMap.erase(ekey);
- return true;
- }
- // A manifold mesh is closed if each vertex is shared twice.
- bool IsClosed() const
- {
- for (auto const& element : mVMap)
- {
- auto vertex = element.second;
- if (!vertex->E[0].lock() || !vertex->E[1].lock())
- {
- return false;
- }
- }
- return true;
- }
- protected:
- // The vertex data and default vertex creation.
- static std::shared_ptr<Vertex> CreateVertex(int v0)
- {
- return std::make_shared<Vertex>(v0);
- }
- VCreator mVCreator;
- VMap mVMap;
- // The edge data and default edge creation.
- static std::shared_ptr<Edge> CreateEdge(int v0, int v1)
- {
- return std::make_shared<Edge>(v0, v1);
- }
- ECreator mECreator;
- EMap mEMap;
- bool mThrowOnNonmanifoldInsertion; // default: true
- };
- }
|