extract_cells_single_component.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 Qingnan Zhou <[email protected]>
  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_single_component.h"
  10. #include "order_facets_around_edge.h"
  11. #include "../../C_STR.h"
  12. #include "../../get_seconds.h"
  13. #include <limits>
  14. #include <vector>
  15. #include <set>
  16. #include <map>
  17. #include <queue>
  18. //#define EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
  19. template<
  20. typename DerivedV,
  21. typename DerivedF,
  22. typename DerivedP,
  23. typename DeriveduE,
  24. typename DeriveduEC,
  25. typename DeriveduEE,
  26. typename DerivedC>
  27. IGL_INLINE int igl::copyleft::cgal::extract_cells_single_component(
  28. const Eigen::MatrixBase<DerivedV>& V,
  29. const Eigen::MatrixBase<DerivedF>& F,
  30. const Eigen::MatrixBase<DerivedP>& P,
  31. const Eigen::MatrixBase<DeriveduE>& uE,
  32. const Eigen::MatrixBase<DeriveduEC>& uEC,
  33. const Eigen::MatrixBase<DeriveduEE>& uEE,
  34. Eigen::PlainObjectBase<DerivedC>& cells)
  35. {
  36. #ifdef EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
  37. const auto & tictoc = []() -> double
  38. {
  39. static double t_start = igl::get_seconds();
  40. double diff = igl::get_seconds()-t_start;
  41. t_start += diff;
  42. return diff;
  43. };
  44. const auto log_time = [&](const std::string& label) -> void {
  45. printf("%50s: %0.5lf\n",
  46. C_STR("extrac*_single_component." << label),tictoc());
  47. };
  48. tictoc();
  49. #else
  50. // no-op
  51. const auto log_time = [](const std::string){};
  52. #endif
  53. const size_t num_faces = F.rows();
  54. // Input:
  55. // index index into #F*3 list of undirect edges
  56. // Returns index into face
  57. const auto e2f = [&num_faces](size_t index) { return index % num_faces; };
  58. // Determine if a face (containing undirected edge {s,d} is consistently
  59. // oriented with directed edge {s,d} (or otherwise it is with {d,s})
  60. //
  61. // Inputs:
  62. // fid face index into F
  63. // s source index of edge
  64. // d destination index of edge
  65. // Returns true if face F(fid,:) is consistent with {s,d}
  66. const auto is_consistent =
  67. [&F](const size_t fid, const size_t s, const size_t d) -> bool
  68. {
  69. if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
  70. if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
  71. if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
  72. if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
  73. if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
  74. if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
  75. throw "Invalid face!";
  76. return false;
  77. };
  78. const size_t num_unique_edges = uE.rows();
  79. const size_t num_patches = P.maxCoeff() + 1;
  80. // Build patch-patch adjacency list.
  81. //
  82. // Does this really need to be a map? Or do I just want a list of neighbors
  83. // and for each neighbor an index to a unique edge? (i.e., a sparse matrix)
  84. std::vector<std::map<size_t, size_t> > patch_adj(num_patches);
  85. for (size_t i=0; i<num_unique_edges; i++)
  86. {
  87. //const auto adj_faces = uE2E[i];
  88. //const size_t num_adj_faces = adj_faces.size();
  89. const size_t num_adj_faces = uEC(i+1)-uEC(i);
  90. if (num_adj_faces > 2)
  91. {
  92. //for (size_t j=0; j<num_adj_faces; j++) {
  93. // const auto aj = adj_faces[j];
  94. for (size_t ij=uEC(i); ij<uEC(i+1); ij++)
  95. {
  96. const auto aj = uEE(ij);
  97. const size_t patch_j = P[e2f(aj)];
  98. //for (size_t k=j+1; k<num_adj_faces; k++) {
  99. // const auto ak = adj_faces[k];
  100. for (size_t ik=ij+1; ik<uEC(i+1); ik++)
  101. {
  102. const auto ak = uEE(ik);
  103. const size_t patch_k = P[e2f(ak)];
  104. if (patch_adj[patch_j].find(patch_k) == patch_adj[patch_j].end())
  105. {
  106. patch_adj[patch_j].insert({patch_k, i});
  107. }
  108. if (patch_adj[patch_k].find(patch_j) == patch_adj[patch_k].end())
  109. {
  110. patch_adj[patch_k].insert({patch_j, i});
  111. }
  112. }
  113. }
  114. }
  115. }
  116. log_time("patch-adjacency");
  117. const int INVALID = std::numeric_limits<int>::max();
  118. //std::vector<size_t> cell_labels(num_patches * 2);
  119. //for (size_t i=0; i<num_patches; i++) cell_labels[i] = i;
  120. std::vector<std::set<size_t> > equivalent_cells(num_patches*2);
  121. std::vector<bool> processed(num_unique_edges, false);
  122. // bottleneck appears to be `order_facets_around_edge`
  123. for (size_t i=0; i<num_patches; i++)
  124. {
  125. for (const auto& entry : patch_adj[i])
  126. {
  127. const size_t uei = entry.second;
  128. if (processed[uei]) continue;
  129. processed[uei] = true;
  130. //const auto& adj_faces = uE2E[uei];
  131. //const size_t num_adj_faces = adj_faces.size();
  132. const size_t num_adj_faces = uEC(uei+1)-uEC(uei);
  133. assert(num_adj_faces > 2);
  134. const size_t s = uE(uei,0);
  135. const size_t d = uE(uei,1);
  136. std::vector<int> signed_adj_faces;
  137. //for (auto ej : adj_faces)
  138. for(size_t ij = uEC(uei);ij<uEC(uei+1);ij++)
  139. {
  140. const size_t ej = uEE(ij);
  141. const size_t fid = e2f(ej);
  142. bool cons = is_consistent(fid, s, d);
  143. signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
  144. }
  145. {
  146. // Sort adjacent faces cyclically around {s,d}
  147. Eigen::VectorXi order;
  148. // order[f] will reveal the order of face f in signed_adj_faces
  149. order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
  150. for (size_t j=0; j<num_adj_faces; j++)
  151. {
  152. const size_t curr_idx = j;
  153. const size_t next_idx = (j+1)%num_adj_faces;
  154. //const size_t curr_patch_idx = P[e2f(adj_faces[order[curr_idx]])];
  155. //const size_t next_patch_idx = P[e2f(adj_faces[order[next_idx]])];
  156. const size_t curr_patch_idx = P[e2f( uEE(uEC(uei)+order[curr_idx]) )];
  157. const size_t next_patch_idx = P[e2f( uEE(uEC(uei)+order[next_idx]) )];
  158. const bool curr_cons = signed_adj_faces[order[curr_idx]] > 0;
  159. const bool next_cons = signed_adj_faces[order[next_idx]] > 0;
  160. const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1);
  161. const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0);
  162. equivalent_cells[curr_cell_idx].insert(next_cell_idx);
  163. equivalent_cells[next_cell_idx].insert(curr_cell_idx);
  164. }
  165. }
  166. }
  167. }
  168. #ifdef EXTRACT_CELLS_SINGLE_COMPONENT_TIMING
  169. log_time("equivalent_cells");
  170. #endif
  171. size_t count=0;
  172. cells.resize(num_patches, 2);
  173. cells.setConstant(INVALID);
  174. const auto extract_equivalent_cells = [&](size_t i) {
  175. if (cells(i/2, i%2) != INVALID) return;
  176. std::queue<size_t> Q;
  177. Q.push(i);
  178. cells(i/2, i%2) = count;
  179. while (!Q.empty()) {
  180. const size_t index = Q.front();
  181. Q.pop();
  182. for (const auto j : equivalent_cells[index]) {
  183. if (cells(j/2, j%2) == INVALID) {
  184. cells(j/2, j%2) = count;
  185. Q.push(j);
  186. }
  187. }
  188. }
  189. count++;
  190. };
  191. for (size_t i=0; i<num_patches; i++) {
  192. extract_equivalent_cells(i*2);
  193. extract_equivalent_cells(i*2+1);
  194. }
  195. log_time("extract-equivalent_cells");
  196. assert((cells.array() != INVALID).all());
  197. return count;
  198. }
  199. #ifdef IGL_STATIC_LIBRARY
  200. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  201. // Explicit template instantiation
  202. template int igl::copyleft::cgal::extract_cells_single_component<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -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>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&,
  203. Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  204. template int igl::copyleft::cgal::extract_cells_single_component<Eigen::Matrix<CGAL::Epeck::FT, -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>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&,
  205. Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  206. #endif