extract_cells.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. //
  9. #include "extract_cells.h"
  10. #include "../../extract_manifold_patches.h"
  11. #include "../../facet_components.h"
  12. #include "../../triangle_triangle_adjacency.h"
  13. #include "../../unique_edge_map.h"
  14. #include "../../get_seconds.h"
  15. #include "closest_facet.h"
  16. #include "order_facets_around_edge.h"
  17. #include "outer_facet.h"
  18. #include <iostream>
  19. #include <vector>
  20. #include <queue>
  21. #include <map>
  22. #include <set>
  23. //#define EXTRACT_CELLS_DEBUG
  24. template<
  25. typename DerivedV,
  26. typename DerivedF,
  27. typename DerivedC >
  28. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  29. const Eigen::PlainObjectBase<DerivedV>& V,
  30. const Eigen::PlainObjectBase<DerivedF>& F,
  31. Eigen::PlainObjectBase<DerivedC>& cells)
  32. {
  33. const size_t num_faces = F.rows();
  34. // Construct edge adjacency
  35. Eigen::MatrixXi E, uE;
  36. Eigen::VectorXi EMAP;
  37. std::vector<std::vector<size_t> > uE2E;
  38. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  39. // Cluster into manifold patches
  40. Eigen::VectorXi P;
  41. igl::extract_manifold_patches(F, EMAP, uE2E, P);
  42. // Extract cells
  43. DerivedC per_patch_cells;
  44. const size_t num_cells =
  45. igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells);
  46. // Distribute per-patch cell information to each face
  47. cells.resize(num_faces, 2);
  48. for (size_t i=0; i<num_faces; i++)
  49. {
  50. cells.row(i) = per_patch_cells.row(P[i]);
  51. }
  52. return num_cells;
  53. }
  54. template<
  55. typename DerivedV,
  56. typename DerivedF,
  57. typename DerivedP,
  58. typename DerivedE,
  59. typename DeriveduE,
  60. typename uE2EType,
  61. typename DerivedEMAP,
  62. typename DerivedC >
  63. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  64. const Eigen::PlainObjectBase<DerivedV>& V,
  65. const Eigen::PlainObjectBase<DerivedF>& F,
  66. const Eigen::PlainObjectBase<DerivedP>& P,
  67. const Eigen::PlainObjectBase<DerivedE>& E,
  68. const Eigen::PlainObjectBase<DeriveduE>& uE,
  69. const std::vector<std::vector<uE2EType> >& uE2E,
  70. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  71. Eigen::PlainObjectBase<DerivedC>& cells)
  72. {
  73. #ifdef EXTRACT_CELLS_DEBUG
  74. const auto & tictoc = []() -> double
  75. {
  76. static double t_start = igl::get_seconds();
  77. double diff = igl::get_seconds()-t_start;
  78. t_start += diff;
  79. return diff;
  80. };
  81. const auto log_time = [&](const std::string& label) -> void {
  82. std::cout << "extract_cells." << label << ": "
  83. << tictoc() << std::endl;
  84. };
  85. tictoc();
  86. #else
  87. // no-op
  88. const auto log_time = [](const std::string){};
  89. #endif
  90. const size_t num_faces = F.rows();
  91. typedef typename DerivedF::Scalar Index;
  92. const size_t num_patches = P.maxCoeff()+1;
  93. // Extract all cells...
  94. DerivedC raw_cells;
  95. const size_t num_raw_cells =
  96. extract_cells_single_component(V,F,P,uE,uE2E,EMAP,raw_cells);
  97. log_time("extract_single_component_cells");
  98. // Compute triangle-triangle adjacency data-structure
  99. std::vector<std::vector<std::vector<Index > > > TT,_1;
  100. igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1);
  101. log_time("compute_face_adjacency");
  102. // Compute connected components of the mesh
  103. Eigen::VectorXi C, counts;
  104. igl::facet_components(TT, C, counts);
  105. log_time("form_components");
  106. const size_t num_components = counts.size();
  107. // components[c] --> list of face indices into F of faces in component c
  108. std::vector<std::vector<size_t> > components(num_components);
  109. // Loop over all faces
  110. for (size_t i=0; i<num_faces; i++)
  111. {
  112. components[C[i]].push_back(i);
  113. }
  114. // Convert vector lists to Eigen lists...
  115. std::vector<Eigen::VectorXi> Is(num_components);
  116. for (size_t i=0; i<num_components; i++)
  117. {
  118. Is[i].resize(components[i].size());
  119. std::copy(components[i].begin(), components[i].end(),Is[i].data());
  120. }
  121. // Find outer facets, their orientations and cells for each component
  122. Eigen::VectorXi outer_facets(num_components);
  123. Eigen::VectorXi outer_facet_orientation(num_components);
  124. Eigen::VectorXi outer_cells(num_components);
  125. for (size_t i=0; i<num_components; i++)
  126. {
  127. bool flipped;
  128. igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
  129. outer_facet_orientation[i] = flipped?1:0;
  130. outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
  131. }
  132. #ifdef EXTRACT_CELLS_DEBUG
  133. log_time("outer_facet_per_component");
  134. #endif
  135. // Compute barycenter of a triangle in mesh (V,F)
  136. //
  137. // Inputs:
  138. // fid index into F
  139. // Returns row-vector of barycenter coordinates
  140. const auto get_triangle_center = [&V,&F](const size_t fid)
  141. {
  142. return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
  143. };
  144. std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
  145. std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
  146. std::vector<std::vector<size_t> > ambient_comps(num_components);
  147. // Only bother if there's more than one component
  148. if(num_components > 1)
  149. {
  150. // construct bounding boxes for each component
  151. DerivedV bbox_min(num_components, 3);
  152. DerivedV bbox_max(num_components, 3);
  153. // Why not just initialize to numeric_limits::min, numeric_limits::max?
  154. bbox_min.rowwise() = V.colwise().maxCoeff().eval();
  155. bbox_max.rowwise() = V.colwise().minCoeff().eval();
  156. // Loop over faces
  157. for (size_t i=0; i<num_faces; i++)
  158. {
  159. // component of this face
  160. const auto comp_id = C[i];
  161. const auto& f = F.row(i);
  162. for (size_t j=0; j<3; j++)
  163. {
  164. for(size_t d=0;d<3;d++)
  165. {
  166. bbox_min(comp_id,d) = std::min(bbox_min(comp_id,d), V(f[j],d));
  167. bbox_max(comp_id,d) = std::max(bbox_max(comp_id,d), V(f[j],d));
  168. }
  169. }
  170. }
  171. // Return true if box of component ci intersects that of cj
  172. const auto bbox_intersects = [&bbox_max,&bbox_min](size_t ci, size_t cj)
  173. {
  174. return !(
  175. bbox_max(ci,0) < bbox_min(cj,0) ||
  176. bbox_max(ci,1) < bbox_min(cj,1) ||
  177. bbox_max(ci,2) < bbox_min(cj,2) ||
  178. bbox_max(cj,0) < bbox_min(ci,0) ||
  179. bbox_max(cj,1) < bbox_min(ci,1) ||
  180. bbox_max(cj,2) < bbox_min(ci,2));
  181. };
  182. // Loop over components. This section is O(m²)
  183. for (size_t i=0; i<num_components; i++)
  184. {
  185. // List of components that could overlap with component i
  186. std::vector<size_t> candidate_comps;
  187. candidate_comps.reserve(num_components);
  188. // Loop over components
  189. for (size_t j=0; j<num_components; j++)
  190. {
  191. if (i == j) continue;
  192. if (bbox_intersects(i,j)) candidate_comps.push_back(j);
  193. }
  194. const size_t num_candidate_comps = candidate_comps.size();
  195. if (num_candidate_comps == 0) continue;
  196. // Get query points on each candidate component: barycenter of
  197. // outer-facet
  198. DerivedV queries(num_candidate_comps, 3);
  199. for (size_t j=0; j<num_candidate_comps; j++)
  200. {
  201. const size_t index = candidate_comps[j];
  202. queries.row(j) = get_triangle_center(outer_facets[index]);
  203. }
  204. // Gather closest facets in ith component to each query point and their
  205. // orientations
  206. const auto& I = Is[i];
  207. Eigen::VectorXi closest_facets, closest_facet_orientations;
  208. closest_facet(V, F, I, queries,
  209. uE2E, EMAP, closest_facets, closest_facet_orientations);
  210. // Loop over all candidates
  211. for (size_t j=0; j<num_candidate_comps; j++)
  212. {
  213. const size_t index = candidate_comps[j];
  214. const size_t closest_patch = P[closest_facets[j]];
  215. const size_t closest_patch_side = closest_facet_orientations[j] ? 0:1;
  216. // The cell id of the closest patch
  217. const size_t ambient_cell =
  218. raw_cells(closest_patch,closest_patch_side);
  219. if (ambient_cell != (size_t)outer_cells[i])
  220. {
  221. // ---> component index inside component i, because the cell of the
  222. // closest facet on i to component index is **not** the same as the
  223. // "outer cell" of component i: component index is **not** outside of
  224. // component i (therefore it's inside).
  225. nested_cells[ambient_cell].push_back(outer_cells[index]);
  226. ambient_cells[outer_cells[index]].push_back(ambient_cell);
  227. ambient_comps[index].push_back(i);
  228. }
  229. }
  230. }
  231. }
  232. #ifdef EXTRACT_CELLS_DEBUG
  233. log_time("nested_relationship");
  234. #endif
  235. const size_t INVALID = std::numeric_limits<size_t>::max();
  236. const size_t INFINITE_CELL = num_raw_cells;
  237. std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
  238. for (size_t i=0; i<num_components; i++) {
  239. const size_t outer_cell = outer_cells[i];
  240. const auto& ambient_comps_i = ambient_comps[i];
  241. const auto& ambient_cells_i = ambient_cells[outer_cell];
  242. const size_t num_ambient_comps = ambient_comps_i.size();
  243. assert(num_ambient_comps == ambient_cells_i.size());
  244. if (num_ambient_comps > 0) {
  245. size_t embedded_comp = INVALID;
  246. size_t embedded_cell = INVALID;
  247. for (size_t j=0; j<num_ambient_comps; j++) {
  248. if (ambient_comps[ambient_comps_i[j]].size() ==
  249. num_ambient_comps-1) {
  250. embedded_comp = ambient_comps_i[j];
  251. embedded_cell = ambient_cells_i[j];
  252. break;
  253. }
  254. }
  255. assert(embedded_comp != INVALID);
  256. assert(embedded_cell != INVALID);
  257. embedded_cells[outer_cell] = embedded_cell;
  258. } else {
  259. embedded_cells[outer_cell] = INFINITE_CELL;
  260. }
  261. }
  262. for (size_t i=0; i<num_patches; i++) {
  263. if (embedded_cells[raw_cells(i,0)] != INVALID) {
  264. raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
  265. }
  266. if (embedded_cells[raw_cells(i,1)] != INVALID) {
  267. raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
  268. }
  269. }
  270. size_t count = 0;
  271. std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
  272. // Always map infinite cell to index 0.
  273. mapped_indices[INFINITE_CELL] = count;
  274. count++;
  275. for (size_t i=0; i<num_patches; i++) {
  276. const size_t old_positive_cell_id = raw_cells(i, 0);
  277. const size_t old_negative_cell_id = raw_cells(i, 1);
  278. size_t positive_cell_id, negative_cell_id;
  279. if (mapped_indices[old_positive_cell_id] == INVALID) {
  280. mapped_indices[old_positive_cell_id] = count;
  281. positive_cell_id = count;
  282. count++;
  283. } else {
  284. positive_cell_id = mapped_indices[old_positive_cell_id];
  285. }
  286. if (mapped_indices[old_negative_cell_id] == INVALID) {
  287. mapped_indices[old_negative_cell_id] = count;
  288. negative_cell_id = count;
  289. count++;
  290. } else {
  291. negative_cell_id = mapped_indices[old_negative_cell_id];
  292. }
  293. raw_cells(i, 0) = positive_cell_id;
  294. raw_cells(i, 1) = negative_cell_id;
  295. }
  296. cells = raw_cells;
  297. #ifdef EXTRACT_CELLS_DEBUG
  298. log_time("finalize");
  299. #endif
  300. return count;
  301. }
  302. template<
  303. typename DerivedV,
  304. typename DerivedF,
  305. typename DerivedP,
  306. typename DeriveduE,
  307. typename uE2EType,
  308. typename DerivedEMAP,
  309. typename DerivedC>
  310. IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
  311. const Eigen::PlainObjectBase<DerivedV>& V,
  312. const Eigen::PlainObjectBase<DerivedF>& F,
  313. const Eigen::PlainObjectBase<DerivedP>& P,
  314. const Eigen::PlainObjectBase<DeriveduE>& uE,
  315. const std::vector<std::vector<uE2EType> >& uE2E,
  316. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  317. Eigen::PlainObjectBase<DerivedC>& cells)
  318. {
  319. const size_t num_faces = F.rows();
  320. // Input:
  321. // index index into #F*3 list of undirect edges
  322. // Returns index into face
  323. const auto edge_index_to_face_index = [&num_faces](size_t index)
  324. {
  325. return index % num_faces;
  326. };
  327. // Determine if a face (containing undirected edge {s,d} is consistently
  328. // oriented with directed edge {s,d} (or otherwise it is with {d,s})
  329. //
  330. // Inputs:
  331. // fid face index into F
  332. // s source index of edge
  333. // d destination index of edge
  334. // Returns true if face F(fid,:) is consistent with {s,d}
  335. const auto is_consistent =
  336. [&F](const size_t fid, const size_t s, const size_t d) -> bool
  337. {
  338. if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
  339. if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
  340. if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
  341. if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
  342. if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
  343. if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
  344. throw "Invalid face!";
  345. return false;
  346. };
  347. const size_t num_unique_edges = uE.rows();
  348. const size_t num_patches = P.maxCoeff() + 1;
  349. // Build patch-patch adjacency list.
  350. std::vector<std::map<size_t, size_t> > patch_adj(num_patches);
  351. for (size_t i=0; i<num_unique_edges; i++) {
  352. const size_t s = uE(i,0);
  353. const size_t d = uE(i,1);
  354. const auto adj_faces = uE2E[i];
  355. const size_t num_adj_faces = adj_faces.size();
  356. if (num_adj_faces > 2) {
  357. for (size_t j=0; j<num_adj_faces; j++) {
  358. const size_t patch_j = P[edge_index_to_face_index(adj_faces[j])];
  359. for (size_t k=j+1; k<num_adj_faces; k++) {
  360. const size_t patch_k = P[edge_index_to_face_index(adj_faces[k])];
  361. if (patch_adj[patch_j].find(patch_k) == patch_adj[patch_j].end()) {
  362. patch_adj[patch_j].insert({patch_k, i});
  363. }
  364. if (patch_adj[patch_k].find(patch_j) == patch_adj[patch_k].end()) {
  365. patch_adj[patch_k].insert({patch_j, i});
  366. }
  367. }
  368. }
  369. }
  370. }
  371. const int INVALID = std::numeric_limits<int>::max();
  372. std::vector<size_t> cell_labels(num_patches * 2);
  373. for (size_t i=0; i<num_patches; i++) cell_labels[i] = i;
  374. std::vector<std::set<size_t> > equivalent_cells(num_patches*2);
  375. std::vector<bool> processed(num_unique_edges, false);
  376. size_t label_count=0;
  377. for (size_t i=0; i<num_patches; i++) {
  378. for (const auto& entry : patch_adj[i]) {
  379. const size_t neighbor_patch = entry.first;
  380. const size_t uei = entry.second;
  381. if (processed[uei]) continue;
  382. processed[uei] = true;
  383. const auto& adj_faces = uE2E[uei];
  384. const size_t num_adj_faces = adj_faces.size();
  385. assert(num_adj_faces > 2);
  386. const size_t s = uE(uei,0);
  387. const size_t d = uE(uei,1);
  388. std::vector<int> signed_adj_faces;
  389. for (auto ej : adj_faces)
  390. {
  391. const size_t fid = edge_index_to_face_index(ej);
  392. bool cons = is_consistent(fid, s, d);
  393. signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
  394. }
  395. {
  396. // Sort adjacent faces cyclically around {s,d}
  397. Eigen::VectorXi order;
  398. // order[f] will reveal the order of face f in signed_adj_faces
  399. order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
  400. for (size_t j=0; j<num_adj_faces; j++) {
  401. const size_t curr_idx = j;
  402. const size_t next_idx = (j+1)%num_adj_faces;
  403. const size_t curr_patch_idx =
  404. P[edge_index_to_face_index(adj_faces[order[curr_idx]])];
  405. const size_t next_patch_idx =
  406. P[edge_index_to_face_index(adj_faces[order[next_idx]])];
  407. const bool curr_cons = signed_adj_faces[order[curr_idx]] > 0;
  408. const bool next_cons = signed_adj_faces[order[next_idx]] > 0;
  409. const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1);
  410. const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0);
  411. equivalent_cells[curr_cell_idx].insert(next_cell_idx);
  412. equivalent_cells[next_cell_idx].insert(curr_cell_idx);
  413. }
  414. }
  415. }
  416. }
  417. size_t count=0;
  418. cells.resize(num_patches, 2);
  419. cells.setConstant(INVALID);
  420. const auto extract_equivalent_cells = [&](size_t i) {
  421. if (cells(i/2, i%2) != INVALID) return;
  422. std::queue<size_t> Q;
  423. Q.push(i);
  424. cells(i/2, i%2) = count;
  425. while (!Q.empty()) {
  426. const size_t index = Q.front();
  427. Q.pop();
  428. for (const auto j : equivalent_cells[index]) {
  429. if (cells(j/2, j%2) == INVALID) {
  430. cells(j/2, j%2) = count;
  431. Q.push(j);
  432. }
  433. }
  434. }
  435. count++;
  436. };
  437. for (size_t i=0; i<num_patches; i++) {
  438. extract_equivalent_cells(i*2);
  439. extract_equivalent_cells(i*2+1);
  440. }
  441. assert((cells.array() != INVALID).all());
  442. return count;
  443. }
  444. #ifdef IGL_STATIC_LIBRARY
  445. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  446. template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  447. #endif