123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- #pragma once
- #include <Mathematics/MinHeap.h>
- #include <Mathematics/Polygon2.h>
- #include <Mathematics/TriangulateEC.h>
- #include <Mathematics/Vector3.h>
- #include <Mathematics/VETManifoldMesh.h>
- #include <set>
- namespace WwiseGTE
- {
- template <typename Real>
- class VertexCollapseMesh
- {
- public:
-
- VertexCollapseMesh(int numPositions, Vector3<Real> const* positions,
- int numIndices, int const* indices)
- :
- mNumPositions(numPositions),
- mPositions(positions),
- mMesh(VCVertex::Create)
- {
- if (numPositions <= 0 || !positions || numIndices < 3 || !indices)
- {
- mNumPositions = 0;
- mPositions = nullptr;
- return;
- }
-
- int numTriangles = numIndices / 3;
- int const* current = indices;
- for (int t = 0; t < numTriangles; ++t)
- {
- int v0 = *current++;
- int v1 = *current++;
- int v2 = *current++;
- mMesh.Insert(v0, v1, v2);
- }
-
- auto const& vmap = mMesh.GetVertices();
- for (auto const& eelement : mMesh.GetEdges())
- {
- auto edge = eelement.second;
- if (!edge->T[1].lock())
- {
- for (int i = 0; i < 2; ++i)
- {
- auto velement = vmap.find(edge->V[i]);
- auto vertex = std::static_pointer_cast<VCVertex>(velement->second);
- vertex->isBoundary = true;
- }
- }
- }
-
- mMinHeap.Reset((int)vmap.size());
- for (auto const& velement : vmap)
- {
- auto vertex = std::static_pointer_cast<VCVertex>(velement.second);
- Real weight;
- if (vertex->isBoundary)
- {
- weight = std::numeric_limits<Real>::max();
- }
- else
- {
- weight = vertex->ComputeWeight(mPositions);
- }
- auto record = mMinHeap.Insert(velement.first, weight);
- mHeapRecords.insert(std::make_pair(velement.first, record));
- }
- }
-
- struct Record
- {
-
-
-
-
-
- int vertex;
- std::vector<TriangleKey<true>> removed;
- std::vector<TriangleKey<true>> inserted;
- };
-
-
-
-
-
-
-
-
- bool DoCollapse(Record& record)
- {
- record.vertex = 0x80000000;
- record.removed.clear();
- record.inserted.clear();
- if (mNumPositions == 0)
- {
-
- return false;
- }
- while (mMinHeap.GetNumElements() > 0)
- {
- int v = -1;
- Real weight = std::numeric_limits<Real>::max();
- mMinHeap.GetMinimum(v, weight);
- if (weight == std::numeric_limits<Real>::max())
- {
-
- return false;
- }
- auto const& vmap = mMesh.GetVertices();
- auto velement = vmap.find(v);
- if (velement == vmap.end())
- {
-
- return false;
- }
- auto vertex = std::static_pointer_cast<VCVertex>(velement->second);
- std::vector<TriangleKey<true>> removed, inserted;
- std::vector<int> linkVertices;
- int result = TriangulateLink(vertex, removed, inserted, linkVertices);
- if (result == VCM_UNEXPECTED_ERROR)
- {
- return false;
- }
- if (result == VCM_ALLOWED)
- {
- result = Collapsed(removed, inserted, linkVertices);
- if (result == VCM_UNEXPECTED_ERROR)
- {
- return false;
- }
- if (result == VCM_ALLOWED)
- {
-
- mMinHeap.Remove(v, weight);
- mHeapRecords.erase(v);
-
- for (auto vlink : linkVertices)
- {
- velement = vmap.find(vlink);
- if (velement == vmap.end())
- {
-
- return false;
- }
- vertex = std::static_pointer_cast<VCVertex>(velement->second);
- if (!vertex->isBoundary)
- {
- auto iter = mHeapRecords.find(vlink);
- if (iter == mHeapRecords.end())
- {
-
- return false;
- }
- weight = vertex->ComputeWeight(mPositions);
- mMinHeap.Update(iter->second, weight);
- }
- }
- record.vertex = v;
- record.removed = std::move(removed);
- record.inserted = std::move(inserted);
- return true;
- }
-
- }
-
-
-
-
-
- auto iter = mHeapRecords.find(v);
- if (iter == mHeapRecords.end())
- {
-
- return false;
- }
- mMinHeap.Update(iter->second, std::numeric_limits<Real>::max());
- }
-
-
-
- return false;
- }
-
-
- inline ETManifoldMesh const& GetMesh() const
- {
- return mMesh;
- }
- private:
- struct VCVertex : public VETManifoldMesh::Vertex
- {
- VCVertex(int v)
- :
- VETManifoldMesh::Vertex(v),
- normal(Vector3<Real>::Zero()),
- isBoundary(false)
- {
- }
- static std::shared_ptr<Vertex> Create(int v)
- {
- return std::make_shared<VCVertex>(v);
- }
-
-
-
-
- Real ComputeWeight(Vector3<Real> const* positions)
- {
- Real weight = (Real)0;
- normal = { (Real)0, (Real)0, (Real)0 };
- for (auto const& tri : TAdjacent)
- {
- Vector3<Real> E0 = positions[tri->V[1]] - positions[tri->V[0]];
- Vector3<Real> E1 = positions[tri->V[2]] - positions[tri->V[0]];
- Vector3<Real> N = Cross(E0, E1);
- normal += N;
- weight += Length(N);
- }
- Normalize(normal);
- for (int index : VAdjacent)
- {
- Vector3<Real> diff = positions[index] - positions[V];
- weight += std::fabs(Dot(normal, diff));
- }
- return weight;
- }
- Vector3<Real> normal;
- bool isBoundary;
- };
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- enum
- {
- VCM_NO_MORE_ALLOWED,
- VCM_ALLOWED,
- VCM_DEFERRED,
- VCM_UNEXPECTED_ERROR
- };
- int TriangulateLink(std::shared_ptr<VCVertex> const& vertex, std::vector<TriangleKey<true>>& removed,
- std::vector<TriangleKey<true>>& inserted, std::vector<int>& linkVertices) const
- {
-
-
-
-
-
-
-
- int const numVertices = static_cast<int>(vertex->TAdjacent.size());
- removed.resize(numVertices);
- int j = 0;
- std::map<int, int> edgeMap;
- for (auto tri : vertex->TAdjacent)
- {
- for (int i = 0; i < 3; ++i)
- {
- if (tri->V[i] == vertex->V)
- {
- edgeMap.insert(std::make_pair(tri->V[(i + 1) % 3], tri->V[(i + 2) % 3]));
- break;
- }
- }
- removed[j++] = TriangleKey<true>(tri->V[0], tri->V[1], tri->V[2]);
- }
- if (edgeMap.size() != vertex->TAdjacent.size())
- {
- return VCM_UNEXPECTED_ERROR;
- }
-
- linkVertices.resize(numVertices);
- auto iter = edgeMap.begin();
- for (int i = 0; i < numVertices; ++i)
- {
- linkVertices[i] = iter->first;
- iter = edgeMap.find(iter->second);
- if (iter == edgeMap.end())
- {
- return VCM_UNEXPECTED_ERROR;
- }
- }
- if (iter->first != linkVertices[0])
- {
- return VCM_UNEXPECTED_ERROR;
- }
-
-
-
- Vector3<Real> center = mPositions[vertex->V];
- Vector3<Real> basis[3];
- basis[0] = vertex->normal;
- ComputeOrthogonalComplement(1, basis);
- std::vector<Vector2<Real>> projected(numVertices);
- std::vector<int> indices(numVertices);
- for (int i = 0; i < numVertices; ++i)
- {
- Vector3<Real> diff = mPositions[linkVertices[i]] - center;
- projected[i][0] = Dot(basis[1], diff);
- projected[i][1] = Dot(basis[2], diff);
- indices[i] = i;
- }
-
- Polygon2<Real> polygon(projected.data(), numVertices, indices.data(), true);
- if (polygon.IsSimple())
- {
- TriangulateEC<Real, Real> triangulator(numVertices, projected.data());
- triangulator();
- auto const& triangles = triangulator.GetTriangles();
- if (triangles.size() == 0)
- {
- return VCM_UNEXPECTED_ERROR;
- }
- int const numTriangles = static_cast<int>(triangles.size());
- inserted.resize(numTriangles);
- for (int t = 0; t < numTriangles; ++t)
- {
- inserted[t] = TriangleKey<true>(
- linkVertices[triangles[t][0]],
- linkVertices[triangles[t][1]],
- linkVertices[triangles[t][2]]);
- }
- return VCM_ALLOWED;
- }
- else
- {
- return VCM_DEFERRED;
- }
- }
- int Collapsed(std::vector<TriangleKey<true>> const& removed,
- std::vector<TriangleKey<true>> const& inserted, std::vector<int> const& linkVertices)
- {
-
-
-
-
-
-
-
-
- bool isCollapsible = true;
- auto const& emap = mMesh.GetEdges();
- std::set<EdgeKey<false>> edges;
- for (auto const& tri : inserted)
- {
- for (int k0 = 2, k1 = 0; k1 < 3; k0 = k1++)
- {
- EdgeKey<false> edge(tri.V[k0], tri.V[k1]);
- if (edges.find(edge) == edges.end())
- {
- edges.insert(edge);
- }
- else
- {
-
-
- auto eelement = emap.find(edge);
- if (eelement != emap.end())
- {
- if (eelement->second->T[1].lock())
- {
-
-
- isCollapsible = false;
- break;
- }
- }
- edges.erase(edge);
- }
- };
- if (!isCollapsible)
- {
- return VCM_DEFERRED;
- }
- }
-
-
- for (auto tri : removed)
- {
- mMesh.Remove(tri.V[0], tri.V[1], tri.V[2]);
- }
-
- for (auto const& tri : inserted)
- {
- mMesh.Insert(tri.V[0], tri.V[1], tri.V[2]);
- }
-
-
-
-
- auto const& vmap = mMesh.GetVertices();
- size_t const numVertices = linkVertices.size();
- for (size_t i0 = numVertices - 1, i1 = 0; i1 < numVertices; i0 = i1++)
- {
- EdgeKey<false> ekey(linkVertices[i0], linkVertices[i1]);
- auto eelement = emap.find(ekey);
- if (eelement == emap.end())
- {
- return VCM_UNEXPECTED_ERROR;
- }
- auto edge = eelement->second;
- if (!edge)
- {
- return VCM_UNEXPECTED_ERROR;
- }
- if (edge->T[0].lock() && !edge->T[1].lock())
- {
- for (int k = 0; k < 2; ++k)
- {
- auto velement = vmap.find(edge->V[k]);
- if (velement == vmap.end())
- {
- return VCM_UNEXPECTED_ERROR;
- }
- auto vertex = std::static_pointer_cast<VCVertex>(velement->second);
- vertex->isBoundary = true;
- }
- }
- }
- return VCM_ALLOWED;
- }
- int mNumPositions;
- Vector3<Real> const* mPositions;
- VETManifoldMesh mMesh;
- MinHeap<int, Real> mMinHeap;
- std::map<int, typename MinHeap<int, Real>::Record*> mHeapRecords;
- };
- }
|