123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- #pragma once
- #include <Mathematics/MinHeap.h>
- #include <array>
- #include <map>
- #include <memory>
- #include <set>
- #include <stack>
- namespace WwiseGTE
- {
- template <typename Real>
- class MinimalCycleBasis
- {
- public:
- struct Tree
- {
- std::vector<int> cycle;
- std::vector<std::shared_ptr<Tree>> children;
- };
-
-
-
- MinimalCycleBasis(
- std::vector<std::array<Real, 2>> const& positions,
- std::vector<std::array<int, 2>> const& edges,
- std::vector<std::shared_ptr<Tree>>& forest)
- {
- forest.clear();
- if (positions.size() == 0 || edges.size() == 0)
- {
-
- return;
- }
-
- std::map<int, std::shared_ptr<Vertex>> unique;
- for (auto const& edge : edges)
- {
- for (int i = 0; i < 2; ++i)
- {
- int name = edge[i];
- if (unique.find(name) == unique.end())
- {
- auto vertex = std::make_shared<Vertex>(name, &positions[name]);
- unique.insert(std::make_pair(name, vertex));
- }
- }
- }
-
- std::vector<Vertex*> vertices;
- mVertexStorage.reserve(unique.size());
- vertices.reserve(unique.size());
- for (auto const& element : unique)
- {
- mVertexStorage.push_back(element.second);
- vertices.push_back(element.second.get());
- }
-
- for (auto const& edge : edges)
- {
- auto iter0 = unique.find(edge[0]);
- auto iter1 = unique.find(edge[1]);
- iter0->second->adjacent.insert(iter1->second.get());
- iter1->second->adjacent.insert(iter0->second.get());
- }
-
-
-
- std::vector<std::vector<Vertex*>> components;
- for (auto vInitial : mVertexStorage)
- {
- if (vInitial->visited == 0)
- {
- components.push_back(std::vector<Vertex*>());
- DepthFirstSearch(vInitial.get(), components.back());
- }
- }
-
-
-
- for (auto vertex : mVertexStorage)
- {
- vertex->visited = 0;
- }
-
- for (auto& component : components)
- {
- forest.push_back(ExtractBasis(component));
- }
- }
-
- MinimalCycleBasis(MinimalCycleBasis const&) = delete;
- MinimalCycleBasis& operator=(MinimalCycleBasis const&) = delete;
- private:
- struct Vertex
- {
- Vertex(int inName, std::array<Real, 2> const* inPosition)
- :
- name(inName),
- position(inPosition),
- visited(0)
- {
- }
- bool operator< (Vertex const& vertex) const
- {
- return name < vertex.name;
- }
-
-
-
- int name;
-
-
- std::array<Real, 2> const* position;
-
-
-
-
- std::set<Vertex*> adjacent;
-
- int visited;
- };
-
-
-
-
- static void DepthFirstSearch(Vertex* vInitial, std::vector<Vertex*>& component)
- {
- std::stack<Vertex*> vStack;
- vStack.push(vInitial);
- while (vStack.size() > 0)
- {
- Vertex* vertex = vStack.top();
- vertex->visited = 1;
- size_t i = 0;
- for (auto adjacent : vertex->adjacent)
- {
- if (adjacent && adjacent->visited == 0)
- {
- vStack.push(adjacent);
- break;
- }
- ++i;
- }
- if (i == vertex->adjacent.size())
- {
- vertex->visited = 2;
- component.push_back(vertex);
- vStack.pop();
- }
- }
- }
-
- std::shared_ptr<Tree> ExtractBasis(std::vector<Vertex*>& component)
- {
-
-
- auto tree = std::make_shared<Tree>();
- while (component.size() > 0)
- {
- RemoveFilaments(component);
- if (component.size() > 0)
- {
- tree->children.push_back(ExtractCycleFromComponent(component));
- }
- }
- if (tree->cycle.size() == 0 && tree->children.size() == 1)
- {
-
-
- auto child = tree->children.back();
- tree->cycle = std::move(child->cycle);
- tree->children = std::move(child->children);
- }
- return tree;
- }
- void RemoveFilaments(std::vector<Vertex*>& component)
- {
-
-
- std::vector<Vertex*> endpoints;
- for (auto vertex : component)
- {
- if (vertex->adjacent.size() == 1)
- {
- endpoints.push_back(vertex);
- }
- }
- if (endpoints.size() > 0)
- {
-
-
-
-
-
- for (auto vertex : endpoints)
- {
- if (vertex->adjacent.size() == 1)
- {
-
- while (vertex->adjacent.size() == 1)
- {
-
- Vertex* adjacent = *vertex->adjacent.begin();
- adjacent->adjacent.erase(vertex);
- vertex->adjacent.erase(adjacent);
-
- vertex = adjacent;
- }
- }
- }
-
-
-
-
- std::vector<Vertex*> remaining;
- remaining.reserve(component.size());
- for (auto vertex : component)
- {
- if (vertex->adjacent.size() > 0)
- {
- remaining.push_back(vertex);
- }
- }
- component = std::move(remaining);
- }
- }
- std::shared_ptr<Tree> ExtractCycleFromComponent(std::vector<Vertex*>& component)
- {
-
-
-
- Vertex* minVertex = component[0];
- for (auto vertex : component)
- {
- if (*vertex->position < *minVertex->position)
- {
- minVertex = vertex;
- }
- }
-
-
- std::vector<Vertex*> closedWalk;
- Vertex* vCurr = minVertex;
- Vertex* vStart = vCurr;
- closedWalk.push_back(vStart);
- Vertex* vAdj = GetClockwiseMost(nullptr, vStart);
- while (vAdj != vStart)
- {
- closedWalk.push_back(vAdj);
- Vertex* vNext = GetCounterclockwiseMost(vCurr, vAdj);
- vCurr = vAdj;
- vAdj = vNext;
- }
- closedWalk.push_back(vStart);
-
- auto tree = ExtractCycleFromClosedWalk(closedWalk);
-
-
- std::vector<Vertex*> remaining;
- remaining.reserve(component.size());
- for (auto vertex : component)
- {
- if (vertex->adjacent.size() > 0)
- {
- remaining.push_back(vertex);
- }
- }
- component = std::move(remaining);
- return tree;
- }
- std::shared_ptr<Tree> ExtractCycleFromClosedWalk(std::vector<Vertex*>& closedWalk)
- {
- auto tree = std::make_shared<Tree>();
- std::map<Vertex*, int> duplicates;
- std::set<int> detachments;
- int numClosedWalk = static_cast<int>(closedWalk.size());
- for (int i = 1; i < numClosedWalk - 1; ++i)
- {
- auto diter = duplicates.find(closedWalk[i]);
- if (diter == duplicates.end())
- {
-
- duplicates.insert(std::make_pair(closedWalk[i], i));
- continue;
- }
-
-
-
-
- int iMin = diter->second, iMax = i;
- detachments.insert(iMin);
- for (int j = iMin + 1; j < iMax; ++j)
- {
- Vertex* vertex = closedWalk[j];
- duplicates.erase(vertex);
- detachments.erase(j);
- }
- closedWalk.erase(closedWalk.begin() + iMin + 1, closedWalk.begin() + iMax + 1);
- numClosedWalk = static_cast<int>(closedWalk.size());
- i = iMin;
- }
- if (numClosedWalk > 3)
- {
-
-
-
-
-
-
-
-
-
-
- detachments.insert(0);
-
- for (auto i : detachments)
- {
- Vertex* original = closedWalk[i];
- Vertex* maxVertex = closedWalk[i + 1];
- Vertex* minVertex = (i > 0 ? closedWalk[i - 1] : closedWalk[numClosedWalk - 2]);
- std::array<Real, 2> dMin, dMax;
- for (int j = 0; j < 2; ++j)
- {
- dMin[j] = (*minVertex->position)[j] - (*original->position)[j];
- dMax[j] = (*maxVertex->position)[j] - (*original->position)[j];
- }
-
- bool isConvex = (dMax[0] * dMin[1] >= dMax[1] * dMin[0]);
- (void)isConvex;
- std::set<Vertex*> inWedge;
- std::set<Vertex*> adjacent = original->adjacent;
- for (auto vertex : adjacent)
- {
- if (vertex->name == minVertex->name || vertex->name == maxVertex->name)
- {
- continue;
- }
- std::array<Real, 2> dVer;
- for (int j = 0; j < 2; ++j)
- {
- dVer[j] = (*vertex->position)[j] - (*original->position)[j];
- }
- bool containsVertex;
- if (isConvex)
- {
- containsVertex =
- dVer[0] * dMin[1] > dVer[1] * dMin[0] &&
- dVer[0] * dMax[1] < dVer[1] * dMax[0];
- }
- else
- {
- containsVertex =
- (dVer[0] * dMin[1] > dVer[1] * dMin[0]) ||
- (dVer[0] * dMax[1] < dVer[1] * dMax[0]);
- }
- if (containsVertex)
- {
- inWedge.insert(vertex);
- }
- }
- if (inWedge.size() > 0)
- {
-
-
-
-
- auto clone = std::make_shared<Vertex>(original->name, original->position);
- mVertexStorage.push_back(clone);
-
- for (auto vertex : inWedge)
- {
- original->adjacent.erase(vertex);
- vertex->adjacent.erase(original);
- clone->adjacent.insert(vertex);
- vertex->adjacent.insert(clone.get());
- }
-
-
- std::vector<Vertex*> component;
- DepthFirstSearch(clone.get(), component);
-
- tree->children.push_back(ExtractBasis(component));
- }
-
-
- }
- tree->cycle = std::move(ExtractCycle(closedWalk));
- }
- else
- {
-
-
- Vertex* original = closedWalk[0];
- Vertex* adjacent = closedWalk[1];
- auto clone = std::make_shared<Vertex>(original->name, original->position);
- mVertexStorage.push_back(clone);
- original->adjacent.erase(adjacent);
- adjacent->adjacent.erase(original);
- clone->adjacent.insert(adjacent);
- adjacent->adjacent.insert(clone.get());
-
- std::vector<Vertex*> component;
- DepthFirstSearch(clone.get(), component);
-
- tree->children.push_back(ExtractBasis(component));
- if (tree->cycle.size() == 0 && tree->children.size() == 1)
- {
-
-
- auto child = tree->children.back();
- tree->cycle = std::move(child->cycle);
- tree->children = std::move(child->children);
- }
- }
- return tree;
- }
- std::vector<int> ExtractCycle(std::vector<Vertex*>& closedWalk)
- {
-
-
-
-
- int const numVertices = static_cast<int>(closedWalk.size());
- std::vector<int> cycle(numVertices);
- for (int i = 0; i < numVertices; ++i)
- {
- cycle[i] = closedWalk[i]->name;
- }
-
- Vertex* v0 = closedWalk[0];
- Vertex* v1 = closedWalk[1];
- Vertex* vBranch = (v0->adjacent.size() > 2 ? v0 : nullptr);
- v0->adjacent.erase(v1);
- v1->adjacent.erase(v0);
-
- while (v1 != vBranch && v1->adjacent.size() == 1)
- {
- Vertex* adj = *v1->adjacent.begin();
- v1->adjacent.erase(adj);
- adj->adjacent.erase(v1);
- v1 = adj;
- }
- if (v1 != v0)
- {
-
-
-
-
-
-
-
- vBranch = v1;
-
- while (v0 != vBranch && v0->adjacent.size() == 1)
- {
- v1 = *v0->adjacent.begin();
- v0->adjacent.erase(v1);
- v1->adjacent.erase(v0);
- v0 = v1;
- }
- }
-
- return cycle;
- }
- Vertex* GetClockwiseMost(Vertex* vPrev, Vertex* vCurr) const
- {
- Vertex* vNext = nullptr;
- bool vCurrConvex = false;
- std::array<Real, 2> dCurr, dNext;
- if (vPrev)
- {
- dCurr[0] = (*vCurr->position)[0] - (*vPrev->position)[0];
- dCurr[1] = (*vCurr->position)[1] - (*vPrev->position)[1];
- }
- else
- {
- dCurr[0] = static_cast<Real>(0);
- dCurr[1] = static_cast<Real>(-1);
- }
- for (auto vAdj : vCurr->adjacent)
- {
-
-
- if (vAdj == vPrev)
- {
- continue;
- }
-
- std::array<Real, 2> dAdj;
- dAdj[0] = (*vAdj->position)[0] - (*vCurr->position)[0];
- dAdj[1] = (*vAdj->position)[1] - (*vCurr->position)[1];
-
- if (!vNext)
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
- continue;
- }
-
-
- if (vCurrConvex)
- {
- if (dCurr[0] * dAdj[1] < dCurr[1] * dAdj[0]
- || dNext[0] * dAdj[1] < dNext[1] * dAdj[0])
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
- }
- }
- else
- {
- if (dCurr[0] * dAdj[1] < dCurr[1] * dAdj[0]
- && dNext[0] * dAdj[1] < dNext[1] * dAdj[0])
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] < dNext[1] * dCurr[0]);
- }
- }
- }
- return vNext;
- }
- Vertex* GetCounterclockwiseMost(Vertex* vPrev, Vertex* vCurr) const
- {
- Vertex* vNext = nullptr;
- bool vCurrConvex = false;
- std::array<Real, 2> dCurr, dNext;
- if (vPrev)
- {
- dCurr[0] = (*vCurr->position)[0] - (*vPrev->position)[0];
- dCurr[1] = (*vCurr->position)[1] - (*vPrev->position)[1];
- }
- else
- {
- dCurr[0] = static_cast<Real>(0);
- dCurr[1] = static_cast<Real>(-1);
- }
- for (auto vAdj : vCurr->adjacent)
- {
-
-
- if (vAdj == vPrev)
- {
- continue;
- }
-
- std::array<Real, 2> dAdj;
- dAdj[0] = (*vAdj->position)[0] - (*vCurr->position)[0];
- dAdj[1] = (*vAdj->position)[1] - (*vCurr->position)[1];
-
- if (!vNext)
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
- continue;
- }
-
-
- if (vCurrConvex)
- {
- if (dCurr[0] * dAdj[1] > dCurr[1] * dAdj[0]
- && dNext[0] * dAdj[1] > dNext[1] * dAdj[0])
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
- }
- }
- else
- {
- if (dCurr[0] * dAdj[1] > dCurr[1] * dAdj[0]
- || dNext[0] * dAdj[1] > dNext[1] * dAdj[0])
- {
- vNext = vAdj;
- dNext = dAdj;
- vCurrConvex = (dNext[0] * dCurr[1] <= dNext[1] * dCurr[0]);
- }
- }
- }
- return vNext;
- }
-
-
- std::vector<std::shared_ptr<Vertex>> mVertexStorage;
- };
- }
|