123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/ConstrainedDelaunay2.h>
- #include <Mathematics/ContPointInPolygon2.h>
- #include <memory>
- #include <queue>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class TriangulateCDT
- {
- public:
-
-
-
-
-
-
-
- TriangulateCDT(int numPoints, Vector2<InputType> const* points)
- :
- mNumPoints(numPoints),
- mPoints(points)
- {
- LogAssert(mNumPoints >= 3 && mPoints != nullptr, "Invalid input.");
- }
- TriangulateCDT(std::vector<Vector2<InputType>> const& points)
- :
- mNumPoints(static_cast<int>(points.size())),
- mPoints(points.data())
- {
- LogAssert(mNumPoints >= 3 && mPoints != nullptr, "Invalid input.");
- }
-
- inline std::vector<std::array<int, 3>> const& GetTriangles() const
- {
- return mTriangles;
- }
-
-
- inline std::vector<std::array<int, 3>> const& GetOutsideTriangles() const
- {
- return mOutsideTriangles;
- }
-
- inline std::vector<std::array<int, 3>> const& GetAllTriangles() const
- {
- return mAllTriangles;
- }
-
-
-
- inline std::vector<bool> const& GetIsInside() const
- {
- return mIsInside;
- }
- inline bool IsInside(int triIndex) const
- {
- if (0 <= triIndex && triIndex < static_cast<int>(mIsInside.size()))
- {
- return mIsInside[triIndex];
- }
- else
- {
- return false;
- }
- }
- inline bool IsOutside(int triIndex) const
- {
- if (0 <= triIndex && triIndex < static_cast<int>(mIsInside.size()))
- {
- return !mIsInside[triIndex];
- }
- else
- {
- return false;
- }
- }
-
-
- typedef std::vector<int> Polygon;
-
-
-
- bool operator()()
- {
- if (mPoints)
- {
- auto tree = std::make_shared<Tree>();
- tree->polygon.resize(mNumPoints);
- for (int i = 0; i < mNumPoints; ++i)
- {
- tree->polygon[i] = i;
- }
- return operator()(tree);
- }
- return false;
- }
-
-
- bool operator()(Polygon const& polygon)
- {
- if (mPoints)
- {
- auto tree = std::make_shared<Tree>();
- tree->polygon = polygon;
- return operator()(tree);
- }
- return false;
- }
-
-
-
-
- bool operator()(Polygon const& outer, Polygon const& inner)
- {
- if (mPoints)
- {
- auto otree = std::make_shared<Tree>();
- otree->polygon = outer;
- otree->child.resize(1);
- auto itree = std::make_shared<Tree>();
- itree->polygon = inner;
- otree->child[0] = itree;
- return operator()(otree);
- }
- return false;
- }
-
-
-
-
- bool operator()(Polygon const& outer, std::vector<Polygon> const& inners)
- {
- if (mPoints)
- {
- auto otree = std::make_shared<Tree>();
- otree->polygon = outer;
- otree->child.resize(inners.size());
- std::vector<std::shared_ptr<Tree>> itree(inners.size());
- for (size_t i = 0; i < inners.size(); ++i)
- {
- itree[i] = std::make_shared<Tree>();
- itree[i]->polygon = inners[i];
- otree->child[i] = itree[i];
- }
- return operator()(otree);
- }
- return false;
- }
-
-
-
-
-
-
-
- class Tree
- {
- public:
- Polygon polygon;
- std::vector<std::shared_ptr<Tree>> child;
- };
-
-
- bool operator()(std::shared_ptr<Tree> const& tree)
- {
- if (mPoints)
- {
- std::map<std::shared_ptr<Tree>, int> offsets;
- int numPoints = GetNumPointsAndOffsets(tree, offsets);
- std::vector<Vector2<InputType>> points(numPoints);
- PackPoints(tree, points);
- if (TriangulatePacked(numPoints, &points[0], tree, offsets))
- {
- int numTriangles = static_cast<int>(mAllTriangles.size());
- for (int t = 0; t < numTriangles; ++t)
- {
- auto& tri = mAllTriangles[t];
- for (int j = 0; j < 3; ++j)
- {
- LookupIndex(tree, tri[j], offsets);
- }
- if (mIsInside[t])
- {
- mTriangles.push_back(tri);
- }
- else
- {
- mOutsideTriangles.push_back(tri);
- }
- }
- return true;
- }
- }
- return false;
- }
- private:
-
-
-
-
-
-
-
- bool TriangulatePacked(int numPoints, Vector2<InputType> const* points,
- std::shared_ptr<Tree> const& tree,
- std::map<std::shared_ptr<Tree>, int> const& offsets)
- {
- mTriangles.clear();
- mOutsideTriangles.clear();
- mAllTriangles.clear();
- mIsInside.clear();
- mConstrainedDelaunay(numPoints, points, static_cast<InputType>(0));
- InsertEdges(tree);
- ComputeType half = static_cast<ComputeType>(0.5);
- ComputeType fourth = static_cast<ComputeType>(0.25);
- auto const& query = mConstrainedDelaunay.GetQuery();
- auto const* ctPoints = query.GetVertices();
- int numTriangles = mConstrainedDelaunay.GetNumTriangles();
- int const* indices = &mConstrainedDelaunay.GetIndices()[0];
- mIsInside.resize(numTriangles);
- for (int t = 0; t < numTriangles; ++t)
- {
- int v0 = *indices++;
- int v1 = *indices++;
- int v2 = *indices++;
- auto ctInside = fourth * ctPoints[v0] + half * ctPoints[v1] + fourth * ctPoints[v2];
- mIsInside[t] = IsInside(tree, ctPoints, ctInside, offsets);
- mAllTriangles.push_back( { v0, v1, v2 } );
- }
- return true;
- }
- int GetNumPointsAndOffsets(std::shared_ptr<Tree> const& tree,
- std::map<std::shared_ptr<Tree>, int>& offsets) const
- {
- int numPoints = 0;
- std::queue<std::shared_ptr<Tree>> treeQueue;
- treeQueue.push(tree);
- while (treeQueue.size() > 0)
- {
- std::shared_ptr<Tree> outer = treeQueue.front();
- treeQueue.pop();
- offsets.insert(std::make_pair(outer, numPoints));
- numPoints += static_cast<int>(outer->polygon.size());
- int numChildren = static_cast<int>(outer->child.size());
- for (int c = 0; c < numChildren; ++c)
- {
- std::shared_ptr<Tree> inner = outer->child[c];
- offsets.insert(std::make_pair(inner, numPoints));
- numPoints += static_cast<int>(inner->polygon.size());
- int numGrandChildren = static_cast<int>(inner->child.size());
- for (int g = 0; g < numGrandChildren; ++g)
- {
- treeQueue.push(inner->child[g]);
- }
- }
- }
- return numPoints;
- }
- void PackPoints(std::shared_ptr<Tree> const& tree,
- std::vector<Vector2<InputType>>& points)
- {
- int numPoints = 0;
- std::queue<std::shared_ptr<Tree>> treeQueue;
- treeQueue.push(tree);
- while (treeQueue.size() > 0)
- {
- std::shared_ptr<Tree> outer = treeQueue.front();
- treeQueue.pop();
- int const numOuterIndices = static_cast<int>(outer->polygon.size());
- int const* outerIndices = outer->polygon.data();
- for (int i = 0; i < numOuterIndices; ++i)
- {
- points[numPoints++] = mPoints[outerIndices[i]];
- }
- int numChildren = static_cast<int>(outer->child.size());
- for (int c = 0; c < numChildren; ++c)
- {
- std::shared_ptr<Tree> inner = outer->child[c];
- int const numInnerIndices = static_cast<int>(inner->polygon.size());
- int const* innerIndices = inner->polygon.data();
- for (int i = 0; i < numInnerIndices; ++i)
- {
- points[numPoints++] = mPoints[innerIndices[i]];
- }
- int numGrandChildren = static_cast<int>(inner->child.size());
- for (int g = 0; g < numGrandChildren; ++g)
- {
- treeQueue.push(inner->child[g]);
- }
- }
- }
- }
- bool InsertEdges(std::shared_ptr<Tree> const& tree)
- {
- int numPoints = 0;
- std::array<int, 2> edge;
- std::vector<int> ignoreOutEdge;
- std::queue<std::shared_ptr<Tree>> treeQueue;
- treeQueue.push(tree);
- while (treeQueue.size() > 0)
- {
- auto outer = treeQueue.front();
- treeQueue.pop();
- int numOuter = static_cast<int>(outer->polygon.size());
- for (int i0 = numOuter - 1, i1 = 0; i1 < numOuter; i0 = i1++)
- {
- edge[0] = numPoints + i0;
- edge[1] = numPoints + i1;
- if (!mConstrainedDelaunay.Insert(edge, ignoreOutEdge))
- {
- return false;
- }
- }
- numPoints += numOuter;
- int numChildren = static_cast<int>(outer->child.size());
- for (int c = 0; c < numChildren; ++c)
- {
- auto inner = outer->child[c];
- int numInner = static_cast<int>(inner->polygon.size());
- for (int i0 = numInner - 1, i1 = 0; i1 < numInner; i0 = i1++)
- {
- edge[0] = numPoints + i0;
- edge[1] = numPoints + i1;
- if (!mConstrainedDelaunay.Insert(edge, ignoreOutEdge))
- {
- return false;
- }
- }
- numPoints += numInner;
- int numGrandChildren = static_cast<int>(inner->child.size());
- for (int g = 0; g < numGrandChildren; ++g)
- {
- treeQueue.push(inner->child[g]);
- }
- }
- }
- return true;
- }
- void LookupIndex(std::shared_ptr<Tree> const& tree, int& v,
- std::map<std::shared_ptr<Tree>, int> const& offsets) const
- {
- std::queue<std::shared_ptr<Tree>> treeQueue;
- treeQueue.push(tree);
- while (treeQueue.size() > 0)
- {
- auto outer = treeQueue.front();
- treeQueue.pop();
- int const numOuterIndices = static_cast<int>(outer->polygon.size());
- int const* outerIndices = outer->polygon.data();
- int offset = offsets.find(outer)->second;
- if (v < offset + numOuterIndices)
- {
- v = outerIndices[v - offset];
- return;
- }
- int numChildren = static_cast<int>(outer->child.size());
- for (int c = 0; c < numChildren; ++c)
- {
- auto inner = outer->child[c];
- int const numInnerIndices = static_cast<int>(inner->polygon.size());
- int const* innerIndices = inner->polygon.data();
- offset = offsets.find(inner)->second;
- if (v < offset + numInnerIndices)
- {
- v = innerIndices[v - offset];
- return;
- }
- int numGrandChildren = static_cast<int>(inner->child.size());
- for (int g = 0; g < numGrandChildren; ++g)
- {
- treeQueue.push(inner->child[g]);
- }
- }
- }
- }
- bool IsInside(std::shared_ptr<Tree> const& tree, Vector2<ComputeType> const* points,
- Vector2<ComputeType> const& test,
- std::map<std::shared_ptr<Tree>, int> const& offsets) const
- {
- std::queue<std::shared_ptr<Tree>> treeQueue;
- treeQueue.push(tree);
- while (treeQueue.size() > 0)
- {
- auto outer = treeQueue.front();
- treeQueue.pop();
- int const numOuterIndices = static_cast<int>(outer->polygon.size());
- int offset = offsets.find(outer)->second;
- PointInPolygon2<ComputeType> piOuter(numOuterIndices, points + offset);
- if (piOuter.Contains(test))
- {
- int numChildren = static_cast<int>(outer->child.size());
- int c;
- for (c = 0; c < numChildren; ++c)
- {
- auto inner = outer->child[c];
- int const numInnerIndices = static_cast<int>(inner->polygon.size());
- offset = offsets.find(inner)->second;
- PointInPolygon2<ComputeType> piInner(numInnerIndices, points + offset);
- if (piInner.Contains(test))
- {
- int numGrandChildren = static_cast<int>(inner->child.size());
- for (int g = 0; g < numGrandChildren; ++g)
- {
- treeQueue.push(inner->child[g]);
- }
- break;
- }
- }
- if (c == numChildren)
- {
- return true;
- }
- }
- }
- return false;
- }
-
- int mNumPoints;
- Vector2<InputType> const* mPoints;
-
-
- std::vector<std::array<int, 3>> mTriangles;
- std::vector<std::array<int, 3>> mOutsideTriangles;
- std::vector<std::array<int, 3>> mAllTriangles;
- std::vector<bool> mIsInside;
- ConstrainedDelaunay2<InputType, ComputeType> mConstrainedDelaunay;
- };
- }
|