cut_to_disk.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #include "cut_to_disk.h"
  2. #include <map>
  3. #include <set>
  4. #include <deque>
  5. #include <algorithm>
  6. namespace igl {
  7. template <typename DerivedF, typename Index>
  8. void cut_to_disk(
  9. const Eigen::MatrixBase<DerivedF> &F,
  10. std::vector<std::vector<Index> > &cuts)
  11. {
  12. cuts.clear();
  13. Index nfaces = F.rows();
  14. if (nfaces == 0)
  15. return;
  16. std::map<std::pair<Index, Index>, std::vector<Index> > edges;
  17. // build edges
  18. for (Index i = 0; i < nfaces; i++)
  19. {
  20. for (int j = 0; j < 3; j++)
  21. {
  22. Index v0 = F(i, j);
  23. Index v1 = F(i, (j + 1) % 3);
  24. std::pair<Index, Index> e;
  25. e.first = std::min(v0, v1);
  26. e.second = std::max(v0, v1);
  27. edges[e].push_back(i);
  28. }
  29. }
  30. int nedges = edges.size();
  31. Eigen::Matrix<Index, -1, -1> edgeVerts(nedges,2);
  32. Eigen::Matrix<Index, -1, -1> edgeFaces(nedges,2);
  33. Eigen::Matrix<Index, -1, -1> faceEdges(nfaces, 3);
  34. std::set<Index> boundaryEdges;
  35. std::map<std::pair<Index, Index>, Index> edgeidx;
  36. Index idx = 0;
  37. for (auto it : edges)
  38. {
  39. edgeidx[it.first] = idx;
  40. edgeVerts(idx, 0) = it.first.first;
  41. edgeVerts(idx, 1) = it.first.second;
  42. edgeFaces(idx, 0) = it.second[0];
  43. if (it.second.size() > 1)
  44. {
  45. edgeFaces(idx, 1) = it.second[1];
  46. }
  47. else
  48. {
  49. edgeFaces(idx, 1) = -1;
  50. boundaryEdges.insert(idx);
  51. }
  52. idx++;
  53. }
  54. for (Index i = 0; i < nfaces; i++)
  55. {
  56. for (int j = 0; j < 3; j++)
  57. {
  58. Index v0 = F(i, j);
  59. Index v1 = F(i, (j + 1) % 3);
  60. std::pair<Index, Index> e;
  61. e.first = std::min(v0, v1);
  62. e.second = std::max(v0, v1);
  63. faceEdges(i, j) = edgeidx[e];
  64. }
  65. }
  66. bool *deleted = new bool[nfaces];
  67. for (Index i = 0; i < nfaces; i++)
  68. deleted[i] = false;
  69. std::set<Index> deletededges;
  70. // loop over faces
  71. for (Index face = 0; face < nfaces; face++)
  72. {
  73. // stop at first undeleted face
  74. if (deleted[face])
  75. continue;
  76. deleted[face] = true;
  77. std::deque<Index> processEdges;
  78. for (int i = 0; i < 3; i++)
  79. {
  80. Index e = faceEdges(face, i);
  81. if (boundaryEdges.count(e))
  82. continue;
  83. int ndeleted = 0;
  84. if (deleted[edgeFaces(e, 0)])
  85. ndeleted++;
  86. if (deleted[edgeFaces(e, 1)])
  87. ndeleted++;
  88. if (ndeleted == 1)
  89. processEdges.push_back(e);
  90. }
  91. // delete all faces adjacent to edges with exactly one adjacent face
  92. while (!processEdges.empty())
  93. {
  94. Index nexte = processEdges.front();
  95. processEdges.pop_front();
  96. Index todelete = nfaces;
  97. if (!deleted[edgeFaces(nexte, 0)])
  98. todelete = edgeFaces(nexte, 0);
  99. if (!deleted[edgeFaces(nexte, 1)])
  100. todelete = edgeFaces(nexte, 1);
  101. if (todelete != nfaces)
  102. {
  103. deletededges.insert(nexte);
  104. deleted[todelete] = true;
  105. for (int i = 0; i < 3; i++)
  106. {
  107. Index e = faceEdges(todelete, i);
  108. if (boundaryEdges.count(e))
  109. continue;
  110. int ndeleted = 0;
  111. if (deleted[edgeFaces(e, 0)])
  112. ndeleted++;
  113. if (deleted[edgeFaces(e, 1)])
  114. ndeleted++;
  115. if (ndeleted == 1)
  116. processEdges.push_back(e);
  117. }
  118. }
  119. }
  120. }
  121. delete[] deleted;
  122. // accumulated non-deleted edges
  123. std::vector<Index> leftedges;
  124. for (Index i = 0; i < nedges; i++)
  125. {
  126. if (!deletededges.count(i))
  127. leftedges.push_back(i);
  128. }
  129. deletededges.clear();
  130. // prune spines
  131. std::map<Index, std::vector<Index> > spinevertedges;
  132. for (Index i : leftedges)
  133. {
  134. spinevertedges[edgeVerts(i, 0)].push_back(i);
  135. spinevertedges[edgeVerts(i, 1)].push_back(i);
  136. }
  137. std::deque<Index> vertsProcess;
  138. std::map<Index, int> spinevertnbs;
  139. for (auto it : spinevertedges)
  140. {
  141. spinevertnbs[it.first] = it.second.size();
  142. if (it.second.size() == 1)
  143. vertsProcess.push_back(it.first);
  144. }
  145. while (!vertsProcess.empty())
  146. {
  147. Index vert = vertsProcess.front();
  148. vertsProcess.pop_front();
  149. for (Index e : spinevertedges[vert])
  150. {
  151. if (!deletededges.count(e))
  152. {
  153. deletededges.insert(e);
  154. for (int j = 0; j < 2; j++)
  155. {
  156. spinevertnbs[edgeVerts(e, j)]--;
  157. if (spinevertnbs[edgeVerts(e, j)] == 1)
  158. {
  159. vertsProcess.push_back(edgeVerts(e, j));
  160. }
  161. }
  162. }
  163. }
  164. }
  165. std::vector<Index> loopedges;
  166. for (Index i : leftedges)
  167. if (!deletededges.count(i))
  168. loopedges.push_back(i);
  169. Index nloopedges = loopedges.size();
  170. if (nloopedges == 0)
  171. return;
  172. std::map<Index, std::vector<Index> > loopvertedges;
  173. for (Index e : loopedges)
  174. {
  175. loopvertedges[edgeVerts(e, 0)].push_back(e);
  176. loopvertedges[edgeVerts(e, 1)].push_back(e);
  177. }
  178. std::set<Index> usededges;
  179. for (Index e : loopedges)
  180. {
  181. // make a cycle or chain starting from this edge
  182. while (!usededges.count(e))
  183. {
  184. std::vector<Index> cycleverts;
  185. std::vector<Index> cycleedges;
  186. cycleverts.push_back(edgeVerts(e, 0));
  187. cycleverts.push_back(edgeVerts(e, 1));
  188. cycleedges.push_back(e);
  189. std::map<Index, Index> cycleidx;
  190. cycleidx[cycleverts[0]] = 0;
  191. cycleidx[cycleverts[1]] = 1;
  192. Index curvert = edgeVerts(e, 1);
  193. Index cure = e;
  194. bool foundcycle = false;
  195. while (curvert != -1 && !foundcycle)
  196. {
  197. Index nextvert = -1;
  198. Index nexte = -1;
  199. for (Index cande : loopvertedges[curvert])
  200. {
  201. if (!usededges.count(cande) && cande != cure)
  202. {
  203. int vidx = 0;
  204. if (curvert == edgeVerts(cande, vidx))
  205. vidx = 1;
  206. nextvert = edgeVerts(cande, vidx);
  207. nexte = cande;
  208. break;
  209. }
  210. }
  211. if (nextvert != -1)
  212. {
  213. auto it = cycleidx.find(nextvert);
  214. if (it != cycleidx.end())
  215. {
  216. // we've hit outselves
  217. std::vector<Index> cut;
  218. for (Index i = it->second; i < cycleverts.size(); i++)
  219. {
  220. cut.push_back(cycleverts[i]);
  221. }
  222. cut.push_back(nextvert);
  223. cuts.push_back(cut);
  224. for (Index i = it->second; i < cycleedges.size(); i++)
  225. {
  226. usededges.insert(cycleedges[i]);
  227. }
  228. usededges.insert(nexte);
  229. foundcycle = true;
  230. }
  231. else
  232. {
  233. cycleidx[nextvert] = cycleverts.size();
  234. cycleverts.push_back(nextvert);
  235. cycleedges.push_back(nexte);
  236. }
  237. }
  238. curvert = nextvert;
  239. cure = nexte;
  240. }
  241. if (!foundcycle)
  242. {
  243. // we've hit a dead end. reverse and try the other direction
  244. std::reverse(cycleverts.begin(), cycleverts.end());
  245. std::reverse(cycleedges.begin(), cycleedges.end());
  246. cycleidx.clear();
  247. for (Index i = 0; i < cycleverts.size(); i++)
  248. {
  249. cycleidx[cycleverts[i]] = i;
  250. }
  251. curvert = cycleverts.back();
  252. cure = cycleedges.back();
  253. while (curvert != -1 && !foundcycle)
  254. {
  255. Index nextvert = -1;
  256. Index nexte = -1;
  257. for (Index cande : loopvertedges[curvert])
  258. {
  259. if (!usededges.count(cande) && cande != cure)
  260. {
  261. int vidx = 0;
  262. if (curvert == edgeVerts(cande, vidx))
  263. vidx = 1;
  264. nextvert = edgeVerts(cande, vidx);
  265. nexte = cande;
  266. break;
  267. }
  268. }
  269. if (nextvert != -1)
  270. {
  271. auto it = cycleidx.find(nextvert);
  272. if (it != cycleidx.end())
  273. {
  274. // we've hit outselves
  275. std::vector<int> cut;
  276. for (Index i = it->second; i < cycleverts.size(); i++)
  277. {
  278. cut.push_back(cycleverts[i]);
  279. }
  280. cut.push_back(nextvert);
  281. cuts.push_back(cut);
  282. for (Index i = it->second; i < cycleedges.size(); i++)
  283. {
  284. usededges.insert(cycleedges[i]);
  285. }
  286. usededges.insert(nexte);
  287. foundcycle = true;
  288. }
  289. else
  290. {
  291. cycleidx[nextvert] = cycleverts.size();
  292. cycleverts.push_back(nextvert);
  293. cycleedges.push_back(nexte);
  294. }
  295. }
  296. curvert = nextvert;
  297. cure = nexte;
  298. }
  299. if (!foundcycle)
  300. {
  301. // we've found a chain
  302. std::vector<Index> cut;
  303. for (Index i = 0; i < cycleverts.size(); i++)
  304. {
  305. cut.push_back(cycleverts[i]);
  306. }
  307. cuts.push_back(cut);
  308. for (Index i = 0; i < cycleedges.size(); i++)
  309. {
  310. usededges.insert(cycleedges[i]);
  311. }
  312. }
  313. }
  314. }
  315. }
  316. }
  317. }
  318. #ifdef IGL_STATIC_LIBRARY
  319. // Explicit template instantiation
  320. 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> > > >&);
  321. #endif