#include "cut_to_disk.h" #include #include #include #include namespace igl { template void cut_to_disk( const Eigen::MatrixBase &F, std::vector > &cuts) { cuts.clear(); Index nfaces = F.rows(); if (nfaces == 0) return; std::map, std::vector > 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 e; e.first = std::min(v0, v1); e.second = std::max(v0, v1); edges[e].push_back(i); } } int nedges = edges.size(); Eigen::Matrix edgeVerts(nedges,2); Eigen::Matrix edgeFaces(nedges,2); Eigen::Matrix faceEdges(nfaces, 3); std::set boundaryEdges; std::map, 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 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 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 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 leftedges; for (Index i = 0; i < nedges; i++) { if (!deletededges.count(i)) leftedges.push_back(i); } deletededges.clear(); // prune spines std::map > spinevertedges; for (Index i : leftedges) { spinevertedges[edgeVerts(i, 0)].push_back(i); spinevertedges[edgeVerts(i, 1)].push_back(i); } std::deque vertsProcess; std::map 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 loopedges; for (Index i : leftedges) if (!deletededges.count(i)) loopedges.push_back(i); Index nloopedges = loopedges.size(); if (nloopedges == 0) return; std::map > loopvertedges; for (Index e : loopedges) { loopvertedges[edgeVerts(e, 0)].push_back(e); loopvertedges[edgeVerts(e, 1)].push_back(e); } std::set usededges; for (Index e : loopedges) { // make a cycle or chain starting from this edge while (!usededges.count(e)) { std::vector cycleverts; std::vector cycleedges; cycleverts.push_back(edgeVerts(e, 0)); cycleverts.push_back(edgeVerts(e, 1)); cycleedges.push_back(e); std::map 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 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 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 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, int>(Eigen::MatrixBase > const&, std::vector >, std::allocator > > >&); #endif