extract_cells.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491
  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 <vector>
  19. #include <queue>
  20. //#define EXTRACT_CELLS_DEBUG
  21. template<
  22. typename DerivedV,
  23. typename DerivedF,
  24. typename DerivedC >
  25. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  26. const Eigen::PlainObjectBase<DerivedV>& V,
  27. const Eigen::PlainObjectBase<DerivedF>& F,
  28. Eigen::PlainObjectBase<DerivedC>& cells)
  29. {
  30. const size_t num_faces = F.rows();
  31. // Construct edge adjacency
  32. Eigen::MatrixXi E, uE;
  33. Eigen::VectorXi EMAP;
  34. std::vector<std::vector<size_t> > uE2E;
  35. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  36. // Cluster into manifold patches
  37. Eigen::VectorXi P;
  38. igl::extract_manifold_patches(F, EMAP, uE2E, P);
  39. // Extract cells
  40. DerivedC per_patch_cells;
  41. const size_t num_cells =
  42. igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells);
  43. // Distribute per-patch cell information to each face
  44. cells.resize(num_faces, 2);
  45. for (size_t i=0; i<num_faces; i++)
  46. {
  47. cells.row(i) = per_patch_cells.row(P[i]);
  48. }
  49. return num_cells;
  50. }
  51. template<
  52. typename DerivedV,
  53. typename DerivedF,
  54. typename DerivedP,
  55. typename DeriveduE,
  56. typename uE2EType,
  57. typename DerivedEMAP,
  58. typename DerivedC>
  59. IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
  60. const Eigen::PlainObjectBase<DerivedV>& V,
  61. const Eigen::PlainObjectBase<DerivedF>& F,
  62. const Eigen::PlainObjectBase<DerivedP>& P,
  63. const Eigen::PlainObjectBase<DeriveduE>& uE,
  64. const std::vector<std::vector<uE2EType> >& uE2E,
  65. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  66. Eigen::PlainObjectBase<DerivedC>& cells)
  67. {
  68. const size_t num_faces = F.rows();
  69. // Input:
  70. // index index into #F*3 list of undirect edges
  71. // Returns index into face
  72. const auto edge_index_to_face_index = [&num_faces](size_t index)
  73. {
  74. return index % num_faces;
  75. };
  76. // Determine if a face (containing undirected edge {s,d} is consistently
  77. // oriented with directed edge {s,d} (or otherwise it is with {d,s})
  78. //
  79. // Inputs:
  80. // fid face index into F
  81. // s source index of edge
  82. // d destination index of edge
  83. // Returns true if face F(fid,:) is consistent with {s,d}
  84. const auto is_consistent =
  85. [&F](const size_t fid, const size_t s, const size_t d) -> bool
  86. {
  87. if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
  88. if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
  89. if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
  90. if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
  91. if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
  92. if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
  93. throw "Invalid face!";
  94. return false;
  95. };
  96. const size_t num_unique_edges = uE.rows();
  97. const size_t num_patches = P.maxCoeff() + 1;
  98. // patch_edge_adj[p] --> list {e,f,g,...} such that p is a patch id and
  99. // e,f,g etc. are edge indices into
  100. std::vector<std::vector<size_t> > patch_edge_adj(num_patches);
  101. // orders[u] --> J where u is an index into unique edges uE and J is a
  102. // #adjacent-faces list of face-edge indices into F*3 sorted cyclicaly around
  103. // edge u.
  104. std::vector<Eigen::VectorXi> orders(num_unique_edges);
  105. // orientations[u] ---> list {f1,f2, ...} where u is an index into unique edges uE
  106. // and points to #adj-facets long list of flags whether faces are oriented
  107. // to point their normals clockwise around edge when looking along the
  108. // edge.
  109. std::vector<std::vector<bool> > orientations(num_unique_edges);
  110. // Loop over unique edges
  111. for (size_t i=0; i<num_unique_edges; i++)
  112. {
  113. const size_t s = uE(i,0);
  114. const size_t d = uE(i,1);
  115. const auto adj_faces = uE2E[i];
  116. // If non-manifold (more than two incident faces)
  117. if (adj_faces.size() > 2)
  118. {
  119. // signed_adj_faces[a] --> sid where a is an index into adj_faces
  120. // (list of face edges on {s,d}) and sid is a signed index for resolve
  121. // co-planar duplicates consistently (i.e. using simulation of
  122. // simplicity).
  123. std::vector<int> signed_adj_faces;
  124. for (auto ei : adj_faces)
  125. {
  126. const size_t fid = edge_index_to_face_index(ei);
  127. bool cons = is_consistent(fid, s, d);
  128. signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
  129. }
  130. {
  131. // Sort adjacent faces cyclically around {s,d}
  132. auto& order = orders[i];
  133. // order[f] will reveal the order of face f in signed_adj_faces
  134. order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
  135. // Determine if each facet is oriented to point its normal clockwise or
  136. // not around the {s,d} (normals are not explicitly computed/used)
  137. auto& orientation = orientations[i];
  138. orientation.resize(order.size());
  139. std::transform(
  140. order.data(),
  141. order.data() + order.size(),
  142. orientation.begin(),
  143. [&signed_adj_faces](const int i){ return signed_adj_faces[i] > 0;});
  144. // re-index order from adjacent faces to full face list. Now order
  145. // indexes F directly
  146. std::transform(
  147. order.data(),
  148. order.data() + order.size(),
  149. order.data(),
  150. [&adj_faces](const int index){ return adj_faces[index];});
  151. }
  152. // loop over adjacent faces, remember that patch is adjacent to this edge
  153. for(const auto & ei : adj_faces)
  154. {
  155. const size_t fid = edge_index_to_face_index(ei);
  156. patch_edge_adj[P[fid]].push_back(ei);
  157. }
  158. }
  159. }
  160. // Initialize all patch-to-cell indices as "invalid" (unlabeled)
  161. const int INVALID = std::numeric_limits<int>::max();
  162. cells.resize(num_patches, 2);
  163. cells.setConstant(INVALID);
  164. // Given a "seed" patch id, a cell id, and which side of the patch that cell
  165. // lies, identify all other patches bounding this cell (and tell them that
  166. // they do)
  167. //
  168. // Inputs:
  169. // seed_patch_id index into patches
  170. // cell_idx index into cells
  171. // seed_patch_side 0 or 1 depending on whether cell_idx is on left or
  172. // right side of seed_patch_id
  173. // cells #cells by 2 list of current assignment of cells incident on each
  174. // side of a patch
  175. // Outputs:
  176. // cells udpated (see input)
  177. //
  178. const auto & peel_cell_bd =
  179. [&P,&patch_edge_adj,&EMAP,&orders,&orientations,&num_faces](
  180. const size_t seed_patch_id,
  181. const short seed_patch_side,
  182. const size_t cell_idx,
  183. Eigen::PlainObjectBase<DerivedC>& cells)
  184. {
  185. typedef std::pair<size_t, short> PatchSide;
  186. // Initialize a queue to BFS over all patches
  187. std::queue<PatchSide> Q;
  188. Q.emplace(seed_patch_id, seed_patch_side);
  189. // assign cell id of seed patch on appropriate side
  190. cells(seed_patch_id, seed_patch_side) = cell_idx;
  191. while (!Q.empty())
  192. {
  193. auto entry = Q.front();
  194. Q.pop();
  195. const size_t patch_id = entry.first;
  196. const short side = entry.second;
  197. const auto& adj_edges = patch_edge_adj[patch_id];
  198. for (const auto& ei : adj_edges)
  199. {
  200. const size_t uei = EMAP[ei];
  201. const auto& order = orders[uei];
  202. const auto& orientation = orientations[uei];
  203. const size_t edge_valance = order.size();
  204. size_t curr_i = 0;
  205. for (curr_i=0; curr_i < edge_valance; curr_i++)
  206. {
  207. if ((size_t)order[curr_i] == ei) break;
  208. }
  209. assert(curr_i < edge_valance && "Failed to find edge.");
  210. const bool cons = orientation[curr_i];
  211. size_t next;
  212. if (side == 0)
  213. {
  214. next = (cons ? (curr_i + 1) :
  215. (curr_i + edge_valance - 1)) % edge_valance;
  216. } else {
  217. next = (cons ? (curr_i+edge_valance-1) : (curr_i+1))%edge_valance;
  218. }
  219. const size_t next_ei = order[next];
  220. const bool next_cons = orientation[next];
  221. const size_t next_patch_id = P[next_ei % num_faces];
  222. const short next_patch_side = (next_cons != cons) ? side:abs(side-1);
  223. if (cells(next_patch_id, next_patch_side) == INVALID)
  224. {
  225. Q.emplace(next_patch_id, next_patch_side);
  226. cells(next_patch_id, next_patch_side) = cell_idx;
  227. }else
  228. {
  229. assert(
  230. (size_t)cells(next_patch_id, next_patch_side) == cell_idx &&
  231. "Encountered cell assignment inconsistency");
  232. }
  233. }
  234. }
  235. };
  236. size_t count=0;
  237. for (size_t i=0; i<num_patches; i++) {
  238. if (cells(i, 0) == INVALID) {
  239. peel_cell_bd(i, 0, count,cells);
  240. count++;
  241. }
  242. if (cells(i, 1) == INVALID) {
  243. peel_cell_bd(i, 1, count,cells);
  244. count++;
  245. }
  246. }
  247. return count;
  248. }
  249. template<
  250. typename DerivedV,
  251. typename DerivedF,
  252. typename DerivedP,
  253. typename DerivedE,
  254. typename DeriveduE,
  255. typename uE2EType,
  256. typename DerivedEMAP,
  257. typename DerivedC >
  258. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  259. const Eigen::PlainObjectBase<DerivedV>& V,
  260. const Eigen::PlainObjectBase<DerivedF>& F,
  261. const Eigen::PlainObjectBase<DerivedP>& P,
  262. const Eigen::PlainObjectBase<DerivedE>& E,
  263. const Eigen::PlainObjectBase<DeriveduE>& uE,
  264. const std::vector<std::vector<uE2EType> >& uE2E,
  265. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  266. Eigen::PlainObjectBase<DerivedC>& cells) {
  267. #ifdef EXTRACT_CELLS_DEBUG
  268. const auto & tictoc = []() -> double
  269. {
  270. static double t_start = igl::get_seconds();
  271. double diff = igl::get_seconds()-t_start;
  272. t_start += diff;
  273. return diff;
  274. };
  275. const auto log_time = [&](const std::string& label) -> void {
  276. std::cout << "extract_cells." << label << ": "
  277. << tictoc() << std::endl;
  278. };
  279. tictoc();
  280. #endif
  281. const size_t num_faces = F.rows();
  282. typedef typename DerivedF::Scalar Index;
  283. const size_t num_patches = P.maxCoeff()+1;
  284. DerivedC raw_cells;
  285. const size_t num_raw_cells =
  286. igl::copyleft::cgal::extract_cells_single_component(
  287. V, F, P, uE, uE2E, EMAP, raw_cells);
  288. #ifdef EXTRACT_CELLS_DEBUG
  289. log_time("extract_single_component_cells");
  290. #endif
  291. std::vector<std::vector<std::vector<Index > > > TT,_1;
  292. igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1);
  293. #ifdef EXTRACT_CELLS_DEBUG
  294. log_time("compute_face_adjacency");
  295. #endif
  296. Eigen::VectorXi C, counts;
  297. igl::facet_components(TT, C, counts);
  298. #ifdef EXTRACT_CELLS_DEBUG
  299. log_time("form_components");
  300. #endif
  301. const size_t num_components = counts.size();
  302. std::vector<std::vector<size_t> > components(num_components);
  303. for (size_t i=0; i<num_faces; i++) {
  304. components[C[i]].push_back(i);
  305. }
  306. std::vector<Eigen::VectorXi> Is(num_components);
  307. for (size_t i=0; i<num_components; i++) {
  308. Is[i].resize(components[i].size());
  309. std::copy(components[i].begin(), components[i].end(),
  310. Is[i].data());
  311. }
  312. Eigen::VectorXi outer_facets(num_components);
  313. Eigen::VectorXi outer_facet_orientation(num_components);
  314. Eigen::VectorXi outer_cells(num_components);
  315. for (size_t i=0; i<num_components; i++) {
  316. bool flipped;
  317. igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
  318. outer_facet_orientation[i] = flipped?1:0;
  319. outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
  320. }
  321. #ifdef EXTRACT_CELLS_DEBUG
  322. log_time("outer_facet_per_component");
  323. #endif
  324. auto get_triangle_center = [&](const size_t fid) {
  325. return ((V.row(F(fid, 0)) + V.row(F(fid, 1)) + V.row(F(fid, 2)))
  326. /3.0).eval();
  327. };
  328. std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
  329. std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
  330. std::vector<std::vector<size_t> > ambient_comps(num_components);
  331. if (num_components > 1) {
  332. DerivedV bbox_min(num_components, 3);
  333. DerivedV bbox_max(num_components, 3);
  334. bbox_min.rowwise() = V.colwise().maxCoeff().eval();
  335. bbox_max.rowwise() = V.colwise().minCoeff().eval();
  336. for (size_t i=0; i<num_faces; i++) {
  337. const auto comp_id = C[i];
  338. const auto& f = F.row(i);
  339. for (size_t j=0; j<3; j++) {
  340. bbox_min(comp_id, 0) = std::min(bbox_min(comp_id, 0), V(f[j], 0));
  341. bbox_min(comp_id, 1) = std::min(bbox_min(comp_id, 1), V(f[j], 1));
  342. bbox_min(comp_id, 2) = std::min(bbox_min(comp_id, 2), V(f[j], 2));
  343. bbox_max(comp_id, 0) = std::max(bbox_max(comp_id, 0), V(f[j], 0));
  344. bbox_max(comp_id, 1) = std::max(bbox_max(comp_id, 1), V(f[j], 1));
  345. bbox_max(comp_id, 2) = std::max(bbox_max(comp_id, 2), V(f[j], 2));
  346. }
  347. }
  348. auto bbox_intersects = [&](size_t comp_i, size_t comp_j) {
  349. return !(
  350. bbox_max(comp_i,0) < bbox_min(comp_j,0) ||
  351. bbox_max(comp_i,1) < bbox_min(comp_j,1) ||
  352. bbox_max(comp_i,2) < bbox_min(comp_j,2) ||
  353. bbox_max(comp_j,0) < bbox_min(comp_i,0) ||
  354. bbox_max(comp_j,1) < bbox_min(comp_i,1) ||
  355. bbox_max(comp_j,2) < bbox_min(comp_i,2));
  356. };
  357. for (size_t i=0; i<num_components; i++) {
  358. std::vector<size_t> candidate_comps;
  359. candidate_comps.reserve(num_components);
  360. for (size_t j=0; j<num_components; j++) {
  361. if (i == j) continue;
  362. if (bbox_intersects(i,j)) candidate_comps.push_back(j);
  363. }
  364. const size_t num_candidate_comps = candidate_comps.size();
  365. if (num_candidate_comps == 0) continue;
  366. DerivedV queries(num_candidate_comps, 3);
  367. for (size_t j=0; j<num_candidate_comps; j++) {
  368. const size_t index = candidate_comps[j];
  369. queries.row(j) = get_triangle_center(outer_facets[index]);
  370. }
  371. const auto& I = Is[i];
  372. Eigen::VectorXi closest_facets, closest_facet_orientations;
  373. igl::copyleft::cgal::closest_facet(V, F, I, queries,
  374. uE2E, EMAP, closest_facets, closest_facet_orientations);
  375. for (size_t j=0; j<num_candidate_comps; j++) {
  376. const size_t index = candidate_comps[j];
  377. const size_t closest_patch = P[closest_facets[j]];
  378. const size_t closest_patch_side = closest_facet_orientations[j]
  379. ? 0:1;
  380. const size_t ambient_cell = raw_cells(closest_patch,
  381. closest_patch_side);
  382. if (ambient_cell != (size_t)outer_cells[i]) {
  383. nested_cells[ambient_cell].push_back(outer_cells[index]);
  384. ambient_cells[outer_cells[index]].push_back(ambient_cell);
  385. ambient_comps[index].push_back(i);
  386. }
  387. }
  388. }
  389. }
  390. #ifdef EXTRACT_CELLS_DEBUG
  391. log_time("nested_relationship");
  392. #endif
  393. const size_t INVALID = std::numeric_limits<size_t>::max();
  394. const size_t INFINITE_CELL = num_raw_cells;
  395. std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
  396. for (size_t i=0; i<num_components; i++) {
  397. const size_t outer_cell = outer_cells[i];
  398. const auto& ambient_comps_i = ambient_comps[i];
  399. const auto& ambient_cells_i = ambient_cells[outer_cell];
  400. const size_t num_ambient_comps = ambient_comps_i.size();
  401. assert(num_ambient_comps == ambient_cells_i.size());
  402. if (num_ambient_comps > 0) {
  403. size_t embedded_comp = INVALID;
  404. size_t embedded_cell = INVALID;
  405. for (size_t j=0; j<num_ambient_comps; j++) {
  406. if (ambient_comps[ambient_comps_i[j]].size() ==
  407. num_ambient_comps-1) {
  408. embedded_comp = ambient_comps_i[j];
  409. embedded_cell = ambient_cells_i[j];
  410. break;
  411. }
  412. }
  413. assert(embedded_comp != INVALID);
  414. assert(embedded_cell != INVALID);
  415. embedded_cells[outer_cell] = embedded_cell;
  416. } else {
  417. embedded_cells[outer_cell] = INFINITE_CELL;
  418. }
  419. }
  420. for (size_t i=0; i<num_patches; i++) {
  421. if (embedded_cells[raw_cells(i,0)] != INVALID) {
  422. raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
  423. }
  424. if (embedded_cells[raw_cells(i,1)] != INVALID) {
  425. raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
  426. }
  427. }
  428. size_t count = 0;
  429. std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
  430. // Always map infinite cell to index 0.
  431. mapped_indices[INFINITE_CELL] = count;
  432. count++;
  433. for (size_t i=0; i<num_patches; i++) {
  434. const size_t old_positive_cell_id = raw_cells(i, 0);
  435. const size_t old_negative_cell_id = raw_cells(i, 1);
  436. size_t positive_cell_id, negative_cell_id;
  437. if (mapped_indices[old_positive_cell_id] == INVALID) {
  438. mapped_indices[old_positive_cell_id] = count;
  439. positive_cell_id = count;
  440. count++;
  441. } else {
  442. positive_cell_id = mapped_indices[old_positive_cell_id];
  443. }
  444. if (mapped_indices[old_negative_cell_id] == INVALID) {
  445. mapped_indices[old_negative_cell_id] = count;
  446. negative_cell_id = count;
  447. count++;
  448. } else {
  449. negative_cell_id = mapped_indices[old_negative_cell_id];
  450. }
  451. raw_cells(i, 0) = positive_cell_id;
  452. raw_cells(i, 1) = negative_cell_id;
  453. }
  454. cells = raw_cells;
  455. #ifdef EXTRACT_CELLS_DEBUG
  456. log_time("finalize");
  457. #endif
  458. return count;
  459. }
  460. #ifdef IGL_STATIC_LIBRARY
  461. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  462. 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> >&);
  463. #endif