You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.9 KiB
213 lines
6.9 KiB
// David Eberly, Geometric Tools, Redmond WA 98052
|
|
// Copyright (c) 1998-2021
|
|
// 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/SharedPtrCompare.h>
|
|
#include <Mathematics/ETNonmanifoldMesh.h>
|
|
|
|
// The VETNonmanifoldMesh class represents an edge-triangle nonmanifold mesh
|
|
// but additionally stores vertex adjacency information.
|
|
|
|
namespace gte
|
|
{
|
|
class VETNonmanifoldMesh : public ETNonmanifoldMesh
|
|
{
|
|
public:
|
|
// Vertex data types.
|
|
class Vertex;
|
|
typedef std::shared_ptr<Vertex>(*VCreator)(int);
|
|
typedef std::map<int, std::shared_ptr<Vertex>> VMap;
|
|
|
|
// Vertex object.
|
|
class Vertex
|
|
{
|
|
public:
|
|
virtual ~Vertex() = default;
|
|
|
|
Vertex(int vIndex)
|
|
:
|
|
V(vIndex)
|
|
{
|
|
}
|
|
|
|
// The index into the vertex pool of the mesh.
|
|
int V;
|
|
|
|
bool operator<(Vertex const& other) const
|
|
{
|
|
return V < other.V;
|
|
}
|
|
|
|
// Adjacent objects.
|
|
std::set<int> VAdjacent;
|
|
std::set<std::shared_ptr<Edge>, SharedPtrLT<Edge>> EAdjacent;
|
|
std::set<std::shared_ptr<Triangle>, SharedPtrLT<Triangle>> TAdjacent;
|
|
};
|
|
|
|
|
|
// Construction and destruction.
|
|
virtual ~VETNonmanifoldMesh() = default;
|
|
|
|
VETNonmanifoldMesh(VCreator vCreator = nullptr, ECreator eCreator = nullptr, TCreator tCreator = nullptr)
|
|
:
|
|
ETNonmanifoldMesh(eCreator, tCreator),
|
|
mVCreator(vCreator ? vCreator : CreateVertex)
|
|
{
|
|
}
|
|
|
|
// Support for a deep copy of the mesh. The mVMap, mEMap, and mTMap
|
|
// objects have dynamically allocated memory for vertices, edges, and
|
|
// triangles. A shallow copy of the pointers to this memory is
|
|
// problematic. Allowing sharing, say, via std::shared_ptr, is an
|
|
// option but not really the intent of copying the mesh graph.
|
|
VETNonmanifoldMesh(VETNonmanifoldMesh const& mesh)
|
|
{
|
|
*this = mesh;
|
|
}
|
|
|
|
VETNonmanifoldMesh& operator=(VETNonmanifoldMesh const& mesh)
|
|
{
|
|
Clear();
|
|
mVCreator = mesh.mVCreator;
|
|
ETNonmanifoldMesh::operator=(mesh);
|
|
return *this;
|
|
}
|
|
|
|
// Member access.
|
|
inline VMap const& GetVertices() const
|
|
{
|
|
return mVMap;
|
|
}
|
|
|
|
// If <v0,v1,v2> is not in the mesh, a Triangle object is created and
|
|
// returned; otherwise, <v0,v1,v2> is in the mesh and nullptr is
|
|
// returned.
|
|
virtual std::shared_ptr<Triangle> Insert(int v0, int v1, int v2) override
|
|
{
|
|
std::shared_ptr<Triangle> tri = ETNonmanifoldMesh::Insert(v0, v1, v2);
|
|
if (!tri)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
int vIndex = tri->V[i];
|
|
auto vItem = mVMap.find(vIndex);
|
|
std::shared_ptr<Vertex> vertex;
|
|
if (vItem == mVMap.end())
|
|
{
|
|
vertex = mVCreator(vIndex);
|
|
mVMap[vIndex] = vertex;
|
|
}
|
|
else
|
|
{
|
|
vertex = vItem->second;
|
|
}
|
|
|
|
vertex->TAdjacent.insert(tri);
|
|
|
|
for (int j = 0; j < 3; ++j)
|
|
{
|
|
auto edge = tri->E[j].lock();
|
|
LogAssert(edge != nullptr, "Unexpected condition.");
|
|
if (edge->V[0] == vIndex)
|
|
{
|
|
vertex->VAdjacent.insert(edge->V[1]);
|
|
vertex->EAdjacent.insert(edge);
|
|
}
|
|
else if (edge->V[1] == vIndex)
|
|
{
|
|
vertex->VAdjacent.insert(edge->V[0]);
|
|
vertex->EAdjacent.insert(edge);
|
|
}
|
|
}
|
|
}
|
|
|
|
return tri;
|
|
}
|
|
|
|
// If <v0,v1,v2> is in the mesh, it is removed and 'true' is returned;
|
|
// otherwise, <v0,v1,v2> is not in the mesh and 'false' is returned.
|
|
virtual bool Remove(int v0, int v1, int v2) override
|
|
{
|
|
auto tItem = mTMap.find(TriangleKey<true>(v0, v1, v2));
|
|
if (tItem == mTMap.end())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
std::shared_ptr<Triangle> tri = tItem->second;
|
|
for (int i = 0; i < 3; ++i)
|
|
{
|
|
int vIndex = tri->V[i];
|
|
auto vItem = mVMap.find(vIndex);
|
|
LogAssert(vItem != mVMap.end(), "Unexpected condition.");
|
|
std::shared_ptr<Vertex> vertex = vItem->second;
|
|
for (int j = 0; j < 3; ++j)
|
|
{
|
|
auto edge = tri->E[j].lock();
|
|
LogAssert(edge != nullptr, "Unexpected condition.");
|
|
|
|
// If the edge will be removed by
|
|
// ETNonmanifoldMesh::Remove, remove the vertex
|
|
// references to it.
|
|
if (edge->T.size() == 1)
|
|
{
|
|
for (auto const& adjw : edge->T)
|
|
{
|
|
auto adj = adjw.lock();
|
|
LogAssert(adj != nullptr, "Unexpected condition.");
|
|
if (edge->V[0] == vIndex)
|
|
{
|
|
vertex->VAdjacent.erase(edge->V[1]);
|
|
vertex->EAdjacent.erase(edge);
|
|
}
|
|
else if (edge->V[1] == vIndex)
|
|
{
|
|
vertex->VAdjacent.erase(edge->V[0]);
|
|
vertex->EAdjacent.erase(edge);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
vertex->TAdjacent.erase(tri);
|
|
|
|
// If the vertex is no longer shared by any triangle,
|
|
// remove it.
|
|
if (vertex->TAdjacent.size() == 0)
|
|
{
|
|
LogAssert(vertex->VAdjacent.size() != 0 || vertex->EAdjacent.size() != 0,
|
|
"Malformed mesh.");
|
|
|
|
mVMap.erase(vItem);
|
|
}
|
|
}
|
|
|
|
return ETNonmanifoldMesh::Remove(v0, v1, v2);
|
|
}
|
|
|
|
// Destroy the vertices, edges, and triangles to obtain an empty mesh.
|
|
virtual void Clear() override
|
|
{
|
|
mVMap.clear();
|
|
ETNonmanifoldMesh::Clear();
|
|
}
|
|
|
|
protected:
|
|
// The vertex data and default vertex creation.
|
|
static std::shared_ptr<Vertex> CreateVertex(int vIndex)
|
|
{
|
|
return std::make_shared<Vertex>(vIndex);
|
|
}
|
|
|
|
VCreator mVCreator;
|
|
VMap mVMap;
|
|
};
|
|
}
|
|
|