extract_cells_single_component.cpp 10 KB

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