123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686 |
- #pragma once
- #include <Mathematics/Delaunay2.h>
- #include <list>
- namespace WwiseGTE
- {
- template <typename InputType, typename ComputeType>
- class ConstrainedDelaunay2 : public Delaunay2<InputType, ComputeType>
- {
- public:
-
-
-
- virtual ~ConstrainedDelaunay2() = default;
- ConstrainedDelaunay2()
- :
- Delaunay2<InputType, ComputeType>()
- {
- }
-
-
-
-
- bool operator()(int numVertices, Vector2<InputType> const* vertices, InputType epsilon)
- {
- return Delaunay2<InputType, ComputeType>::operator()(numVertices, vertices, epsilon);
- }
-
-
-
-
-
-
-
-
-
-
-
-
- bool Insert(std::array<int, 2> const& edge, std::vector<int>& outEdge)
- {
- int v0 = edge[0], v1 = edge[1];
- if (0 <= v0 && v0 < this->mNumVertices
- && 0 <= v1 && v1 < this->mNumVertices)
- {
- int v0Triangle = GetLinkTriangle(v0);
- if (v0Triangle >= 0)
- {
-
-
-
- this->mGraph.Clear();
- outEdge.clear();
- return Insert(edge, v0Triangle, outEdge);
- }
- }
- return false;
- }
- private:
-
-
- bool Insert(std::array<int, 2> const& edge, int v0Triangle, std::vector<int>& outEdge)
- {
-
-
- int v0 = edge[0], v1 = edge[1];
- std::list<std::pair<int, int>> link;
- bool isOpen = true;
- bool success = BuildLink(v0, v0Triangle, link, isOpen);
- LogAssert(success, CDTFailure());
-
-
-
- auto item = link.begin();
- std::array<int, 3> indices;
- success = this->GetIndices(item->first, indices);
- LogAssert(success, CDTFailure());
- int vNext = indices[(item->second + 1) % 3];
- int qr0 = this->mQuery.ToLine(v1, v0, vNext);
- while (item != link.end())
- {
- if (qr0 == 0)
- {
-
-
- Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
- Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
- Vector2<ComputeType> const& ctvnext = this->mComputeVertices[vNext];
- if (Dot(ctv1 - ctv0, ctvnext - ctv0) > (ComputeType)0)
- {
-
- return ProcessCoincident(item->first, v0, v1, vNext, outEdge);
- }
-
-
- qr0 = 1;
- }
- if (qr0 > 0)
- {
-
- if (++item == link.end())
- {
- return false;
- }
- success = this->GetIndices(item->first, indices);
- LogAssert(success, CDTFailure());
- vNext = indices[(item->second + 1) % 3];
- qr0 = this->mQuery.ToLine(v1, v0, vNext);
- continue;
- }
- int vPrev = indices[(item->second + 2) % 3];
- int qr1 = this->mQuery.ToLine(v1, v0, vPrev);
- while (item != link.end())
- {
- if (qr1 == 0)
- {
-
-
- Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
- Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
- Vector2<ComputeType> const& ctvprev =
- this->mComputeVertices[vPrev];
- if (Dot(ctv1 - ctv0, ctvprev - ctv0) > (ComputeType)0)
- {
-
- return ProcessCoincident(item->first, v0, v1, vPrev, outEdge);
- }
-
-
- qr1 = -1;
- }
- if (qr1 < 0)
- {
-
-
- if (++item == link.end())
- {
- return false;
- }
- this->GetIndices(item->first, indices);
- vNext = vPrev;
- vPrev = indices[(item->second + 2) % 3];
- qr1 = this->mQuery.ToLine(v1, v0, vPrev);
- continue;
- }
-
- return ProcessInterior(item->first, v0, v1, vNext, vPrev, outEdge);
- }
- break;
- }
-
- LogError(CDTFailure());
- }
-
- bool ProcessCoincident(int tri, int v0, int v1, int vOther, std::vector<int>& outEdge)
- {
- outEdge.push_back(v0);
- if (v1 != vOther)
- {
-
- return Insert({ vOther, v1 }, tri, outEdge);
- }
- else
- {
-
- outEdge.push_back(v1);
- return true;
- }
- }
-
-
- bool ProcessInterior(int tri, int v0, int v1, int vNext, int vPrev, std::vector<int>& outEdge)
- {
-
-
-
-
- std::vector<int> polygon;
-
-
-
-
-
-
-
-
-
- std::vector<std::array<int, 2>> lBoundary, rBoundary;
- std::array<int, 2> binfo;
- polygon.push_back(tri);
- lBoundary.push_back({ v0, -1 });
- binfo = GetAdjBoundary(tri, vPrev, vPrev);
- LogAssert(binfo[0] != 2, CDTFailure());
- lBoundary.push_back(binfo);
- rBoundary.push_back({ v0, -1 });
- binfo = GetAdjBoundary(tri, vNext, v0);
- LogAssert(binfo[0] != 2, CDTFailure());
- rBoundary.push_back(binfo);
-
-
- for (int i = 0; i < this->mNumTriangles; ++i)
- {
-
-
- auto iinfo = GetAdjInterior(tri, vNext, vPrev);
- int adj = iinfo[0], vOpposite = iinfo[1];
- LogAssert(vOpposite >= 0, CDTFailure());
-
- tri = adj;
- polygon.push_back(tri);
- int qr = this->mQuery.ToLine(vOpposite, v0, v1);
- if (qr == 0)
- {
-
-
-
-
- binfo = GetAdjBoundary(tri, vOpposite, vOpposite);
- LogAssert(binfo[0] != 2, CDTFailure());
- lBoundary.push_back(binfo);
- binfo = GetAdjBoundary(tri, vOpposite, vNext);
- LogAssert(binfo[0] != 2, CDTFailure());
- rBoundary.push_back(binfo);
- Retriangulate(polygon, lBoundary, rBoundary);
- if (vOpposite != v1)
- {
- outEdge.push_back(v0);
- return Insert({ vOpposite, v1 }, tri, outEdge);
- }
- else
- {
- return true;
- }
- }
- if (qr < 0)
- {
- binfo = GetAdjBoundary(tri, vOpposite, vOpposite);
- LogAssert(binfo[0] != 2, CDTFailure());
- lBoundary.push_back(binfo);
- vPrev = vOpposite;
- }
- else
- {
- binfo = GetAdjBoundary(tri, vOpposite, vNext);
- LogAssert(binfo[0] != 2, CDTFailure());
- rBoundary.push_back(binfo);
- vNext = vOpposite;
- }
- }
-
- LogError(CDTFailure());
- }
-
-
- bool Retriangulate(std::vector<int>& polygon,
- std::vector<std::array<int, 2>> const& lBoundary,
- std::vector<std::array<int, 2>> const& rBoundary)
- {
- int t0 = RetriangulateLRecurse(lBoundary, 0,
- static_cast<int>(lBoundary.size()) - 1, -1, polygon);
- int t1 = RetriangulateRRecurse(rBoundary, 0,
- static_cast<int>(rBoundary.size()) - 1, -1, polygon);
- int v0 = lBoundary.front()[0];
- int v1 = lBoundary.back()[0];
- bool success = Connect(t0, t1, v0, v1);
- LogAssert(success, CDTFailure());
- return true;
- }
- int RetriangulateLRecurse(
- std::vector<std::array<int, 2>> const& lBoundary,
- int i0, int i1, int a0, std::vector<int>& polygon)
- {
-
-
- int v0 = lBoundary[i0][0];
- int v1 = lBoundary[i1][0];
- bool success;
- if (i1 - i0 == 1)
- {
- success = Connect(a0, lBoundary[i1][1], v1, v0);
- LogAssert(success, CDTFailure());
- return -1;
- }
- else
- {
-
-
- int i2 = SelectSplit(lBoundary, i0, i1);
- int v2 = lBoundary[i2][0];
-
- int tri = polygon.back();
- polygon.pop_back();
- this->mIndices[3 * tri + 0] = v0;
- this->mIndices[3 * tri + 1] = v1;
- this->mIndices[3 * tri + 2] = v2;
-
- int ret0 = RetriangulateLRecurse(lBoundary, i0, i2, tri, polygon);
- LogAssert(ret0 >= -1, CDTFailure());
- int ret1 = RetriangulateLRecurse(lBoundary, i2, i1, tri, polygon);
- LogAssert(ret1 >= -1, CDTFailure());
-
- success = Connect(a0, tri, v1, v0);
- LogAssert(success, CDTFailure())
- return tri;
- }
- }
- int RetriangulateRRecurse(
- std::vector<std::array<int, 2>> const& rBoundary,
- int i0, int i1, int a0, std::vector<int>& polygon)
- {
-
-
- int v0 = rBoundary[i0][0];
- int v1 = rBoundary[i1][0];
- if (i1 - i0 == 1)
- {
- bool success = Connect(a0, rBoundary[i1][1], v0, v1);
- LogAssert(success, CDTFailure());
- return -1;
- }
- else
- {
-
-
- int i2 = SelectSplit(rBoundary, i0, i1);
- int v2 = rBoundary[i2][0];
-
- int tri = polygon.back();
- polygon.pop_back();
- this->mIndices[3 * tri + 0] = v1;
- this->mIndices[3 * tri + 1] = v0;
- this->mIndices[3 * tri + 2] = v2;
-
- int ret0 = RetriangulateRRecurse(rBoundary, i0, i2, tri, polygon);
- LogAssert(ret0 >= -1, CDTFailure());
- int ret1 = RetriangulateRRecurse(rBoundary, i2, i1, tri, polygon);
- LogAssert(ret1 >= -1, CDTFailure());
-
- bool success = Connect(a0, tri, v0, v1);
- LogAssert(success, CDTFailure());
- return tri;
- }
- }
- int SelectSplit(std::vector<std::array<int, 2>> const& boundary, int i0, int i1) const
- {
- int i2;
- if (i1 - i0 == 2)
- {
-
- i2 = i0 + 1;
- }
- else
- {
-
-
-
-
- i2 = i0 + 1;
- int v0 = boundary[i0][0];
- int v1 = boundary[i1][0];
- int v2 = boundary[i2][0];
- ComputeType minpsd = ComputePSD(v0, v1, v2);
- for (int i = i2 + 1; i < i1; ++i)
- {
- v2 = boundary[i][0];
- ComputeType psd = ComputePSD(v0, v1, v2);
- if (psd < minpsd)
- {
- minpsd = psd;
- i2 = i;
- }
- }
- }
- return i2;
- }
-
-
- ComputeType ComputePSD(int v0, int v1, int v2) const
- {
- ComputeType psd;
- Vector2<ComputeType> const& ctv0 = this->mComputeVertices[v0];
- Vector2<ComputeType> const& ctv1 = this->mComputeVertices[v1];
- Vector2<ComputeType> const& ctv2 = this->mComputeVertices[v2];
- Vector2<ComputeType> V1mV0 = ctv1 - ctv0;
- Vector2<ComputeType> V2mV0 = ctv2 - ctv0;
- ComputeType sqrlen10 = Dot(V1mV0, V1mV0);
- ComputeType dot = Dot(V1mV0, V2mV0);
- ComputeType zero(0);
- if (dot <= zero)
- {
- ComputeType sqrlen20 = Dot(V2mV0, V2mV0);
- psd = sqrlen10 * sqrlen20;
- }
- else
- {
- Vector2<ComputeType> V2mV1 = ctv2 - ctv1;
- dot = Dot(V1mV0, V2mV1);
- if (dot >= zero)
- {
- ComputeType sqrlen21 = Dot(V2mV1, V2mV1);
- psd = sqrlen10 * sqrlen21;
- }
- else
- {
- dot = DotPerp(V2mV0, V1mV0);
- psd = sqrlen10 * dot * dot;
- }
- }
- return psd;
- }
-
-
- int GetLinkTriangle(int v) const
- {
-
- v = this->mDuplicates[v];
- int tri = 0;
- for (int i = 0; i < this->mNumTriangles; ++i)
- {
-
- std::array<int, 3> indices;
- bool success = this->GetIndices(tri, indices);
- LogAssert(success, CDTFailure());
- for (int j = 0; j < 3; ++j)
- {
- if (v == indices[j])
- {
- return tri;
- }
- }
-
- for (int j0 = 2, j1 = 0; j1 < 3; j0 = j1++)
- {
- if (this->mQuery.ToLine(v, indices[j0], indices[j1]) > 0)
- {
-
-
- std::array<int, 3> adjacencies;
- success = this->GetAdjacencies(tri, adjacencies);
- LogAssert(success, CDTFailure());
- int adj = adjacencies[j0];
- LogAssert(adj >= 0, CDTFailure());
- tri = adj;
- break;
- }
- }
- }
-
- LogError(CDTFailure());
- }
-
-
- int GetIndexOfVertex(int tri, int v) const
- {
- std::array<int, 3> indices;
- bool success = this->GetIndices(tri, indices);
- LogAssert(success, CDTFailure());
- int indexOfV;
- for (indexOfV = 0; indexOfV < 3; ++indexOfV)
- {
- if (v == indices[indexOfV])
- {
- return indexOfV;
- }
- }
- LogError(CDTFailure());
- }
-
-
-
-
-
-
- std::array<int, 2> GetAdjInterior(int tri, int v0, int v1) const
- {
- int vIndex = GetIndexOfVertex(tri, v0);
- LogAssert(vIndex >= 0, CDTFailure());
- int adj = this->mAdjacencies[3 * tri + vIndex];
- if (adj >= 0)
- {
- for (int v2Index = 0; v2Index < 3; ++v2Index)
- {
- int v2 = this->mIndices[3 * adj + v2Index];
- if (v2 != v0 && v2 != v1)
- {
- return{ adj, v2 };
- }
- }
- }
- else
- {
- return{ -1, -1 };
- }
- LogError(CDTFailure());
- }
-
-
-
-
-
-
- std::array<int, 2> GetAdjBoundary(int tri, int needBndVertex, int needAdjVIndex) const
- {
- int vIndex = GetIndexOfVertex(tri, needAdjVIndex);
- LogAssert(vIndex >= 0, CDTFailure());
- int adj = this->mAdjacencies[3 * tri + vIndex];
- return{ needBndVertex, adj };
- }
-
-
-
- bool Connect(int tri, int adj, int v0, int v1)
- {
- if (tri >= 0)
- {
- int v0Index = GetIndexOfVertex(tri, v0);
- LogAssert(v0Index >= 0, CDTFailure());
- if (adj >= 0)
- {
- int v1Index = GetIndexOfVertex(adj, v1);
- LogAssert(v1Index >= 0, CDTFailure());
- this->mAdjacencies[3 * adj + v1Index] = tri;
- }
- this->mAdjacencies[3 * tri + v0Index] = adj;
- }
-
-
- return true;
- }
-
-
-
-
-
-
- bool BuildLink(int v, int vTriangle, std::list<std::pair<int, int>>& link, bool& isOpen) const
- {
-
- int vStartIndex = GetIndexOfVertex(vTriangle, v);
- LogAssert(vStartIndex >= 0, CDTFailure());
- link.push_front(std::make_pair(vTriangle, vStartIndex));
-
-
- int tri = vTriangle, vIndex = vStartIndex;
- std::array<int, 3> adjacencies;
- for (int i = 0; i < this->mNumTriangles; ++i)
- {
- bool success = this->GetAdjacencies(tri, adjacencies);
- LogAssert(success, CDTFailure());
- int adjPrev = adjacencies[(vIndex + 2) % 3];
- if (adjPrev >= 0)
- {
- if (adjPrev != vTriangle)
- {
- tri = adjPrev;
- vIndex = GetIndexOfVertex(tri, v);
- LogAssert(vIndex >= 0, CDTFailure());
- link.push_back(std::make_pair(tri, vIndex));
- }
- else
- {
-
-
- isOpen = false;
- return true;
- }
- }
- else
- {
-
-
-
-
- isOpen = true;
- tri = vTriangle;
- vIndex = vStartIndex;
- for (int j = 0; j < this->mNumTriangles; ++j)
- {
- this->GetAdjacencies(tri, adjacencies);
- int adjNext = adjacencies[vIndex];
- if (adjNext >= 0)
- {
- tri = adjNext;
- vIndex = GetIndexOfVertex(tri, v);
- LogAssert(vIndex >= 0, CDTFailure());
- link.push_front(std::make_pair(tri, vIndex));
- }
- else
- {
-
-
- return true;
- }
- }
- break;
- }
- }
- LogError(CDTFailure());
- }
- static std::string const& CDTFailure()
- {
- static std::string message = "Unexpected condition. Caused by floating-point rounding error?";
- return message;
- }
- };
- }
|