123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- #include "cut_to_disk.h"
- #include <map>
- #include <set>
- #include <deque>
- #include <algorithm>
- namespace igl {
- template <typename DerivedF, typename Index>
- void cut_to_disk(
- const Eigen::MatrixBase<DerivedF> &F,
- std::vector<std::vector<Index> > &cuts)
- {
- cuts.clear();
- Index nfaces = F.rows();
- if (nfaces == 0)
- return;
- std::map<std::pair<Index, Index>, std::vector<Index> > edges;
- // build edges
- for (Index i = 0; i < nfaces; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- Index v0 = F(i, j);
- Index v1 = F(i, (j + 1) % 3);
- std::pair<Index, Index> e;
- e.first = std::min(v0, v1);
- e.second = std::max(v0, v1);
- edges[e].push_back(i);
- }
- }
- int nedges = edges.size();
- Eigen::Matrix<Index, -1, -1> edgeVerts(nedges,2);
- Eigen::Matrix<Index, -1, -1> edgeFaces(nedges,2);
- Eigen::Matrix<Index, -1, -1> faceEdges(nfaces, 3);
- std::set<Index> boundaryEdges;
- std::map<std::pair<Index, Index>, Index> edgeidx;
- Index idx = 0;
- for (auto it : edges)
- {
- edgeidx[it.first] = idx;
- edgeVerts(idx, 0) = it.first.first;
- edgeVerts(idx, 1) = it.first.second;
- edgeFaces(idx, 0) = it.second[0];
- if (it.second.size() > 1)
- {
- edgeFaces(idx, 1) = it.second[1];
- }
- else
- {
- edgeFaces(idx, 1) = -1;
- boundaryEdges.insert(idx);
- }
- idx++;
- }
- for (Index i = 0; i < nfaces; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- Index v0 = F(i, j);
- Index v1 = F(i, (j + 1) % 3);
- std::pair<Index, Index> e;
- e.first = std::min(v0, v1);
- e.second = std::max(v0, v1);
- faceEdges(i, j) = edgeidx[e];
- }
- }
- bool *deleted = new bool[nfaces];
- for (Index i = 0; i < nfaces; i++)
- deleted[i] = false;
- std::set<Index> deletededges;
- // loop over faces
- for (Index face = 0; face < nfaces; face++)
- {
- // stop at first undeleted face
- if (deleted[face])
- continue;
- deleted[face] = true;
- std::deque<Index> processEdges;
- for (int i = 0; i < 3; i++)
- {
- Index e = faceEdges(face, i);
- if (boundaryEdges.count(e))
- continue;
- int ndeleted = 0;
- if (deleted[edgeFaces(e, 0)])
- ndeleted++;
- if (deleted[edgeFaces(e, 1)])
- ndeleted++;
- if (ndeleted == 1)
- processEdges.push_back(e);
- }
- // delete all faces adjacent to edges with exactly one adjacent face
- while (!processEdges.empty())
- {
- Index nexte = processEdges.front();
- processEdges.pop_front();
- Index todelete = nfaces;
- if (!deleted[edgeFaces(nexte, 0)])
- todelete = edgeFaces(nexte, 0);
- if (!deleted[edgeFaces(nexte, 1)])
- todelete = edgeFaces(nexte, 1);
- if (todelete != nfaces)
- {
- deletededges.insert(nexte);
- deleted[todelete] = true;
- for (int i = 0; i < 3; i++)
- {
- Index e = faceEdges(todelete, i);
- if (boundaryEdges.count(e))
- continue;
- int ndeleted = 0;
- if (deleted[edgeFaces(e, 0)])
- ndeleted++;
- if (deleted[edgeFaces(e, 1)])
- ndeleted++;
- if (ndeleted == 1)
- processEdges.push_back(e);
- }
- }
- }
- }
- delete[] deleted;
- // accumulated non-deleted edges
- std::vector<Index> leftedges;
- for (Index i = 0; i < nedges; i++)
- {
- if (!deletededges.count(i))
- leftedges.push_back(i);
- }
- deletededges.clear();
- // prune spines
- std::map<Index, std::vector<Index> > spinevertedges;
- for (Index i : leftedges)
- {
- spinevertedges[edgeVerts(i, 0)].push_back(i);
- spinevertedges[edgeVerts(i, 1)].push_back(i);
- }
- std::deque<Index> vertsProcess;
- std::map<Index, int> spinevertnbs;
- for (auto it : spinevertedges)
- {
- spinevertnbs[it.first] = it.second.size();
- if (it.second.size() == 1)
- vertsProcess.push_back(it.first);
- }
- while (!vertsProcess.empty())
- {
- Index vert = vertsProcess.front();
- vertsProcess.pop_front();
- for (Index e : spinevertedges[vert])
- {
- if (!deletededges.count(e))
- {
- deletededges.insert(e);
- for (int j = 0; j < 2; j++)
- {
- spinevertnbs[edgeVerts(e, j)]--;
- if (spinevertnbs[edgeVerts(e, j)] == 1)
- {
- vertsProcess.push_back(edgeVerts(e, j));
- }
- }
- }
- }
- }
- std::vector<Index> loopedges;
- for (Index i : leftedges)
- if (!deletededges.count(i))
- loopedges.push_back(i);
- Index nloopedges = loopedges.size();
- if (nloopedges == 0)
- return;
- std::map<Index, std::vector<Index> > loopvertedges;
- for (Index e : loopedges)
- {
- loopvertedges[edgeVerts(e, 0)].push_back(e);
- loopvertedges[edgeVerts(e, 1)].push_back(e);
- }
- std::set<Index> usededges;
- for (Index e : loopedges)
- {
- // make a cycle or chain starting from this edge
- while (!usededges.count(e))
- {
- std::vector<Index> cycleverts;
- std::vector<Index> cycleedges;
- cycleverts.push_back(edgeVerts(e, 0));
- cycleverts.push_back(edgeVerts(e, 1));
- cycleedges.push_back(e);
- std::map<Index, Index> cycleidx;
- cycleidx[cycleverts[0]] = 0;
- cycleidx[cycleverts[1]] = 1;
- Index curvert = edgeVerts(e, 1);
- Index cure = e;
- bool foundcycle = false;
- while (curvert != -1 && !foundcycle)
- {
- Index nextvert = -1;
- Index nexte = -1;
- for (Index cande : loopvertedges[curvert])
- {
- if (!usededges.count(cande) && cande != cure)
- {
- int vidx = 0;
- if (curvert == edgeVerts(cande, vidx))
- vidx = 1;
- nextvert = edgeVerts(cande, vidx);
- nexte = cande;
- break;
- }
- }
- if (nextvert != -1)
- {
- auto it = cycleidx.find(nextvert);
- if (it != cycleidx.end())
- {
- // we've hit outselves
- std::vector<Index> cut;
- for (Index i = it->second; i < cycleverts.size(); i++)
- {
- cut.push_back(cycleverts[i]);
- }
- cut.push_back(nextvert);
- cuts.push_back(cut);
- for (Index i = it->second; i < cycleedges.size(); i++)
- {
- usededges.insert(cycleedges[i]);
- }
- usededges.insert(nexte);
- foundcycle = true;
- }
- else
- {
- cycleidx[nextvert] = cycleverts.size();
- cycleverts.push_back(nextvert);
- cycleedges.push_back(nexte);
- }
- }
- curvert = nextvert;
- cure = nexte;
- }
- if (!foundcycle)
- {
- // we've hit a dead end. reverse and try the other direction
- std::reverse(cycleverts.begin(), cycleverts.end());
- std::reverse(cycleedges.begin(), cycleedges.end());
- cycleidx.clear();
- for (Index i = 0; i < cycleverts.size(); i++)
- {
- cycleidx[cycleverts[i]] = i;
- }
-
- curvert = cycleverts.back();
- cure = cycleedges.back();
- while (curvert != -1 && !foundcycle)
- {
- Index nextvert = -1;
- Index nexte = -1;
- for (Index cande : loopvertedges[curvert])
- {
- if (!usededges.count(cande) && cande != cure)
- {
- int vidx = 0;
- if (curvert == edgeVerts(cande, vidx))
- vidx = 1;
- nextvert = edgeVerts(cande, vidx);
- nexte = cande;
- break;
- }
- }
- if (nextvert != -1)
- {
- auto it = cycleidx.find(nextvert);
- if (it != cycleidx.end())
- {
- // we've hit outselves
- std::vector<int> cut;
- for (Index i = it->second; i < cycleverts.size(); i++)
- {
- cut.push_back(cycleverts[i]);
- }
- cut.push_back(nextvert);
- cuts.push_back(cut);
- for (Index i = it->second; i < cycleedges.size(); i++)
- {
- usededges.insert(cycleedges[i]);
- }
- usededges.insert(nexte);
- foundcycle = true;
- }
- else
- {
- cycleidx[nextvert] = cycleverts.size();
- cycleverts.push_back(nextvert);
- cycleedges.push_back(nexte);
- }
- }
- curvert = nextvert;
- cure = nexte;
- }
- if (!foundcycle)
- {
- // we've found a chain
- std::vector<Index> cut;
- for (Index i = 0; i < cycleverts.size(); i++)
- {
- cut.push_back(cycleverts[i]);
- }
- cuts.push_back(cut);
- for (Index i = 0; i < cycleedges.size(); i++)
- {
- usededges.insert(cycleedges[i]);
- }
- }
- }
- }
- }
- }
- }
- #ifdef IGL_STATIC_LIBRARY
- // Explicit template instantiation
- template void igl::cut_to_disk<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
- #endif
|