123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/PrimalQuery3.h>
- #include <Mathematics/TSManifoldMesh.h>
- #include <Mathematics/Line.h>
- #include <Mathematics/Hyperplane.h>
- #include <set>
- #include <vector>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class Delaunay3
- {
- public:
-
-
-
- Delaunay3()
- :
- mEpsilon((InputType)0),
- mDimension(0),
- mLine(Vector3<InputType>::Zero(), Vector3<InputType>::Zero()),
- mPlane(Vector3<InputType>::Zero(), (InputType)0),
- mNumVertices(0),
- mNumUniqueVertices(0),
- mNumTetrahedra(0),
- mVertices(nullptr)
- {
- }
-
-
-
-
-
-
- bool operator()(int numVertices, Vector3<InputType> const* vertices, InputType epsilon)
- {
- mEpsilon = std::max(epsilon, (InputType)0);
- mDimension = 0;
- mLine.origin = Vector3<InputType>::Zero();
- mLine.direction = Vector3<InputType>::Zero();
- mPlane.normal = Vector3<InputType>::Zero();
- mPlane.constant = (InputType)0;
- mNumVertices = numVertices;
- mNumUniqueVertices = 0;
- mNumTetrahedra = 0;
- mVertices = vertices;
- mGraph = TSManifoldMesh();
- mIndices.clear();
- mAdjacencies.clear();
- int i, j;
- if (mNumVertices < 4)
- {
-
- return false;
- }
- IntrinsicsVector3<InputType> info(mNumVertices, vertices, mEpsilon);
- if (info.dimension == 0)
- {
-
-
- return false;
- }
- if (info.dimension == 1)
- {
-
- mDimension = 1;
- mLine = Line3<InputType>(info.origin, info.direction[0]);
- return false;
- }
- if (info.dimension == 2)
- {
-
- mDimension = 2;
- mPlane = Plane3<InputType>(UnitCross(info.direction[0],
- info.direction[1]), info.origin);
- return false;
- }
- mDimension = 3;
-
- mComputeVertices.resize(mNumVertices);
- mQuery.Set(mNumVertices, &mComputeVertices[0]);
- for (i = 0; i < mNumVertices; ++i)
- {
- for (j = 0; j < 3; ++j)
- {
- mComputeVertices[i][j] = vertices[i][j];
- }
- }
-
-
-
- if (!info.extremeCCW)
- {
- std::swap(info.extreme[2], info.extreme[3]);
- }
- if (!mGraph.Insert(info.extreme[0], info.extreme[1], info.extreme[2], info.extreme[3]))
- {
- return false;
- }
-
-
-
-
- std::set<Vector3<InputType>> processed;
- for (i = 0; i < 4; ++i)
- {
- processed.insert(vertices[info.extreme[i]]);
- }
- for (i = 0; i < mNumVertices; ++i)
- {
- if (processed.find(vertices[i]) == processed.end())
- {
- if (!Update(i))
- {
-
-
- return false;
- }
- processed.insert(vertices[i]);
- }
- }
- mNumUniqueVertices = static_cast<int>(processed.size());
-
- std::map<std::shared_ptr<Tetrahedron>, int> permute;
- i = -1;
- permute[nullptr] = i++;
- for (auto const& element : mGraph.GetTetrahedra())
- {
- permute[element.second] = i++;
- }
-
-
- mNumTetrahedra = static_cast<int>(mGraph.GetTetrahedra().size());
- int numIndices = 4 * mNumTetrahedra;
- if (mNumTetrahedra > 0)
- {
- mIndices.resize(numIndices);
- mAdjacencies.resize(numIndices);
- i = 0;
- for (auto const& element : mGraph.GetTetrahedra())
- {
- std::shared_ptr<Tetrahedron> tetra = element.second;
- for (j = 0; j < 4; ++j, ++i)
- {
- mIndices[i] = tetra->V[j];
- mAdjacencies[i] = permute[tetra->S[j].lock()];
- }
- }
- }
- return true;
- }
-
-
-
-
-
-
-
-
- inline InputType GetEpsilon() const
- {
- return mEpsilon;
- }
- inline int GetDimension() const
- {
- return mDimension;
- }
- inline Line3<InputType> const& GetLine() const
- {
- return mLine;
- }
- inline Plane3<InputType> const& GetPlane() const
- {
- return mPlane;
- }
-
- inline int GetNumVertices() const
- {
- return mNumVertices;
- }
- inline int GetNumUniqueVertices() const
- {
- return mNumUniqueVertices;
- }
- inline int GetNumTetrahedra() const
- {
- return mNumTetrahedra;
- }
- inline Vector3<InputType> const* GetVertices() const
- {
- return mVertices;
- }
- inline PrimalQuery3<ComputeType> const& GetQuery() const
- {
- return mQuery;
- }
- inline TSManifoldMesh const& GetGraph() const
- {
- return mGraph;
- }
- inline std::vector<int> const& GetIndices() const
- {
- return mIndices;
- }
- inline std::vector<int> const& GetAdjacencies() const
- {
- return mAdjacencies;
- }
-
-
-
-
-
- bool GetHull(std::vector<int>& hull) const
- {
- if (mDimension == 3)
- {
-
-
- int numTriangles = 0;
- for (auto adj : mAdjacencies)
- {
- if (adj == -1)
- {
- ++numTriangles;
- }
- }
- if (numTriangles > 0)
- {
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- hull.resize(3 * numTriangles);
- int current = 0, i = 0;
- for (auto adj : mAdjacencies)
- {
- if (adj == -1)
- {
- int tetra = i / 4, face = i % 4;
- for (int j = 0; j < 4; ++j)
- {
- if (j != face)
- {
- hull[current++] = mIndices[4 * tetra + j];
- }
- }
- if ((face % 2) != 0)
- {
- std::swap(hull[current - 1], hull[current - 2]);
- }
- }
- ++i;
- }
- return true;
- }
- else
- {
- LogError("Unexpected. There must be at least one tetrahedron.");
- }
- }
- else
- {
- LogError("The dimension must be 3.");
- }
- }
-
-
-
-
- bool GetIndices(int i, std::array<int, 4>& indices) const
- {
- if (mDimension == 3)
- {
- int numTetrahedra = static_cast<int>(mIndices.size() / 4);
- if (0 <= i && i < numTetrahedra)
- {
- indices[0] = mIndices[4 * i];
- indices[1] = mIndices[4 * i + 1];
- indices[2] = mIndices[4 * i + 2];
- indices[3] = mIndices[4 * i + 3];
- return true;
- }
- }
- else
- {
- LogError("The dimension must be 3.");
- }
- return false;
- }
-
-
-
-
-
- bool GetAdjacencies(int i, std::array<int, 4>& adjacencies) const
- {
- if (mDimension == 3)
- {
- int numTetrahedra = static_cast<int>(mIndices.size() / 4);
- if (0 <= i && i < numTetrahedra)
- {
- adjacencies[0] = mAdjacencies[4 * i];
- adjacencies[1] = mAdjacencies[4 * i + 1];
- adjacencies[2] = mAdjacencies[4 * i + 2];
- adjacencies[3] = mAdjacencies[4 * i + 3];
- return true;
- }
- }
- else
- {
- LogError("The dimension must be 3.");
- }
- return false;
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- struct SearchInfo
- {
- int initialTetrahedron;
- int numPath;
- std::vector<int> path;
- int finalTetrahedron;
- std::array<int, 4> finalV;
- };
-
- int GetContainingTetrahedron(Vector3<InputType> const& p, SearchInfo& info) const
- {
- if (mDimension == 3)
- {
- Vector3<ComputeType> test{ p[0], p[1], p[2] };
- int numTetrahedra = static_cast<int>(mIndices.size() / 4);
- info.path.resize(numTetrahedra);
- info.numPath = 0;
- int tetrahedron;
- if (0 <= info.initialTetrahedron
- && info.initialTetrahedron < numTetrahedra)
- {
- tetrahedron = info.initialTetrahedron;
- }
- else
- {
- info.initialTetrahedron = 0;
- tetrahedron = 0;
- }
-
- for (int i = 0; i < numTetrahedra; ++i)
- {
- int ibase = 4 * tetrahedron;
- int const* v = &mIndices[ibase];
- info.path[info.numPath++] = tetrahedron;
- info.finalTetrahedron = tetrahedron;
- info.finalV[0] = v[0];
- info.finalV[1] = v[1];
- info.finalV[2] = v[2];
- info.finalV[3] = v[3];
-
-
- if (mQuery.ToPlane(test, v[1], v[2], v[3]) > 0)
- {
- tetrahedron = mAdjacencies[ibase];
- if (tetrahedron == -1)
- {
- info.finalV[0] = v[1];
- info.finalV[1] = v[2];
- info.finalV[2] = v[3];
- info.finalV[3] = v[0];
- return -1;
- }
- continue;
- }
-
-
- if (mQuery.ToPlane(test, v[0], v[2], v[3]) < 0)
- {
- tetrahedron = mAdjacencies[ibase + 1];
- if (tetrahedron == -1)
- {
- info.finalV[0] = v[0];
- info.finalV[1] = v[2];
- info.finalV[2] = v[3];
- info.finalV[3] = v[1];
- return -1;
- }
- continue;
- }
-
-
- if (mQuery.ToPlane(test, v[0], v[1], v[3]) > 0)
- {
- tetrahedron = mAdjacencies[ibase + 2];
- if (tetrahedron == -1)
- {
- info.finalV[0] = v[0];
- info.finalV[1] = v[1];
- info.finalV[2] = v[3];
- info.finalV[3] = v[2];
- return -1;
- }
- continue;
- }
-
-
- if (mQuery.ToPlane(test, v[0], v[1], v[2]) < 0)
- {
- tetrahedron = mAdjacencies[ibase + 3];
- if (tetrahedron == -1)
- {
- info.finalV[0] = v[0];
- info.finalV[1] = v[1];
- info.finalV[2] = v[2];
- info.finalV[3] = v[3];
- return -1;
- }
- continue;
- }
- return tetrahedron;
- }
- }
- else
- {
- LogError("The dimension must be 3.");
- }
- return -1;
- }
- private:
-
- typedef TSManifoldMesh::Tetrahedron Tetrahedron;
- bool GetContainingTetrahedron(int i, std::shared_ptr<Tetrahedron>& tetra) const
- {
- int numTetrahedra = static_cast<int>(mGraph.GetTetrahedra().size());
- for (int t = 0; t < numTetrahedra; ++t)
- {
- int j;
- for (j = 0; j < 4; ++j)
- {
- auto const& opposite = TetrahedronKey<true>::GetOppositeFace();
- int v0 = tetra->V[opposite[j][0]];
- int v1 = tetra->V[opposite[j][1]];
- int v2 = tetra->V[opposite[j][2]];
- if (mQuery.ToPlane(i, v0, v1, v2) > 0)
- {
-
-
- auto adjTetra = tetra->S[j].lock();
- if (adjTetra)
- {
-
- tetra = adjTetra;
- break;
- }
- else
- {
-
-
-
-
- return false;
- }
- }
- }
- if (j == 4)
- {
-
-
- return true;
- }
- }
- LogError("Unexpected termination of loop.");
- }
- bool GetAndRemoveInsertionPolyhedron(int i, std::set<std::shared_ptr<Tetrahedron>>& candidates,
- std::set<TriangleKey<true>>& boundary)
- {
-
- TSManifoldMesh polyhedron;
- while (candidates.size() > 0)
- {
- std::shared_ptr<Tetrahedron> tetra = *candidates.begin();
- candidates.erase(candidates.begin());
- for (int j = 0; j < 4; ++j)
- {
- auto adj = tetra->S[j].lock();
- if (adj && candidates.find(adj) == candidates.end())
- {
- int a0 = adj->V[0];
- int a1 = adj->V[1];
- int a2 = adj->V[2];
- int a3 = adj->V[3];
- if (mQuery.ToCircumsphere(i, a0, a1, a2, a3) <= 0)
- {
-
- candidates.insert(adj);
- }
- }
- }
- int v0 = tetra->V[0];
- int v1 = tetra->V[1];
- int v2 = tetra->V[2];
- int v3 = tetra->V[3];
- if (!polyhedron.Insert(v0, v1, v2, v3))
- {
- return false;
- }
- if (!mGraph.Remove(v0, v1, v2, v3))
- {
- return false;
- }
- }
-
- for (auto const& element : polyhedron.GetTetrahedra())
- {
- std::shared_ptr<Tetrahedron> tetra = element.second;
- for (int j = 0; j < 4; ++j)
- {
- if (!tetra->S[j].lock())
- {
- auto const& opposite = TetrahedronKey<true>::GetOppositeFace();
- int v0 = tetra->V[opposite[j][0]];
- int v1 = tetra->V[opposite[j][1]];
- int v2 = tetra->V[opposite[j][2]];
- boundary.insert(TriangleKey<true>(v0, v1, v2));
- }
- }
- }
- return true;
- }
- bool Update(int i)
- {
- auto const& smap = mGraph.GetTetrahedra();
- std::shared_ptr<Tetrahedron> tetra = smap.begin()->second;
- if (GetContainingTetrahedron(i, tetra))
- {
-
-
-
-
-
- std::set<std::shared_ptr<Tetrahedron>> candidates;
- candidates.insert(tetra);
-
-
-
- std::set<TriangleKey<true>> boundary;
- if (!GetAndRemoveInsertionPolyhedron(i, candidates, boundary))
- {
- return false;
- }
-
-
- for (auto const& key : boundary)
- {
- int v0 = key.V[0];
- int v1 = key.V[1];
- int v2 = key.V[2];
- if (mQuery.ToPlane(i, v0, v1, v2) < 0)
- {
- if (!mGraph.Insert(i, v0, v1, v2))
- {
- return false;
- }
- }
-
-
- }
- }
- else
- {
-
-
-
-
-
-
- std::set<TriangleKey<true>> hull;
- for (auto const& element : smap)
- {
- std::shared_ptr<Tetrahedron> t = element.second;
- for (int j = 0; j < 4; ++j)
- {
- if (!t->S[j].lock())
- {
- auto const& opposite = TetrahedronKey<true>::GetOppositeFace();
- int v0 = t->V[opposite[j][0]];
- int v1 = t->V[opposite[j][1]];
- int v2 = t->V[opposite[j][2]];
- hull.insert(TriangleKey<true>(v0, v1, v2));
- }
- }
- }
-
-
-
- auto const& tmap = mGraph.GetTriangles();
- std::set<std::shared_ptr<Tetrahedron>> candidates;
- std::set<TriangleKey<true>> visible;
- for (auto const& key : hull)
- {
- int v0 = key.V[0];
- int v1 = key.V[1];
- int v2 = key.V[2];
- if (mQuery.ToPlane(i, v0, v1, v2) > 0)
- {
- auto iter = tmap.find(TriangleKey<false>(v0, v1, v2));
- if (iter != tmap.end() && iter->second->T[1].lock() == nullptr)
- {
- auto adj = iter->second->T[0].lock();
- if (adj && candidates.find(adj) == candidates.end())
- {
- int a0 = adj->V[0];
- int a1 = adj->V[1];
- int a2 = adj->V[2];
- int a3 = adj->V[3];
- if (mQuery.ToCircumsphere(i, a0, a1, a2, a3) <= 0)
- {
-
- candidates.insert(adj);
- }
- else
- {
-
-
- visible.insert(key);
- }
- }
- }
- else
- {
-
-
-
-
-
-
- return false;
- }
- }
- }
-
-
-
- std::set<TriangleKey<true>> boundary;
- if (!GetAndRemoveInsertionPolyhedron(i, candidates, boundary))
- {
- return false;
- }
-
-
-
- for (auto const& key : boundary)
- {
- int v0 = key.V[0];
- int v1 = key.V[1];
- int v2 = key.V[2];
- if (mQuery.ToPlane(i, v0, v1, v2) < 0)
- {
-
- if (!mGraph.Insert(i, v0, v1, v2))
- {
- return false;
- }
- }
- }
- for (auto const& key : visible)
- {
- if (!mGraph.Insert(i, key.V[0], key.V[2], key.V[1]))
- {
- return false;
- }
- }
- }
- return true;
- }
-
-
-
-
-
-
-
-
-
-
- InputType mEpsilon;
- int mDimension;
- Line3<InputType> mLine;
- Plane3<InputType> mPlane;
-
-
- std::vector<Vector3<ComputeType>> mComputeVertices;
- PrimalQuery3<ComputeType> mQuery;
-
- int mNumVertices;
- int mNumUniqueVertices;
- int mNumTetrahedra;
- Vector3<InputType> const* mVertices;
- TSManifoldMesh mGraph;
- std::vector<int> mIndices;
- std::vector<int> mAdjacencies;
- };
- }
|