extract_cells.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  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 "closest_facet.h"
  15. #include "order_facets_around_edge.h"
  16. #include "outer_facet.h"
  17. #include <vector>
  18. template<
  19. typename DerivedV,
  20. typename DerivedF,
  21. typename DerivedP,
  22. typename DeriveduE,
  23. typename uE2EType,
  24. typename DerivedEMAP,
  25. typename DerivedC >
  26. IGL_INLINE size_t igl::cgal::extract_cells_single_component(
  27. const Eigen::PlainObjectBase<DerivedV>& V,
  28. const Eigen::PlainObjectBase<DerivedF>& F,
  29. const Eigen::PlainObjectBase<DerivedP>& P,
  30. const Eigen::PlainObjectBase<DeriveduE>& uE,
  31. const std::vector<std::vector<uE2EType> >& uE2E,
  32. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  33. Eigen::PlainObjectBase<DerivedC>& cells) {
  34. typedef typename DerivedF::Scalar Index;
  35. const size_t num_faces = F.rows();
  36. auto edge_index_to_face_index = [&](size_t index) {
  37. return index % num_faces;
  38. };
  39. auto is_consistent = [&](const size_t fid, const size_t s, const size_t d) {
  40. if (F(fid, 0) == s && F(fid, 1) == d) return false;
  41. if (F(fid, 1) == s && F(fid, 2) == d) return false;
  42. if (F(fid, 2) == s && F(fid, 0) == d) return false;
  43. if (F(fid, 0) == d && F(fid, 1) == s) return true;
  44. if (F(fid, 1) == d && F(fid, 2) == s) return true;
  45. if (F(fid, 2) == d && F(fid, 0) == s) return true;
  46. throw "Invalid face!";
  47. return false;
  48. };
  49. const size_t num_unique_edges = uE.rows();
  50. const size_t num_patches = P.maxCoeff() + 1;
  51. std::vector<std::vector<size_t> > patch_edge_adj(num_patches);
  52. std::vector<Eigen::VectorXi> orders(num_unique_edges);
  53. std::vector<std::vector<bool> > orientations(num_unique_edges);
  54. for (size_t i=0; i<num_unique_edges; i++) {
  55. const size_t s = uE(i,0);
  56. const size_t d = uE(i,1);
  57. const auto adj_faces = uE2E[i];
  58. if (adj_faces.size() > 2) {
  59. std::vector<int> signed_adj_faces;
  60. for (auto ei : adj_faces) {
  61. const size_t fid = edge_index_to_face_index(ei);
  62. bool cons = is_consistent(fid, s, d);
  63. signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
  64. }
  65. auto& order = orders[i];
  66. igl::cgal::order_facets_around_edge(
  67. V, F, s, d, signed_adj_faces, order);
  68. auto& orientation = orientations[i];
  69. orientation.resize(order.size());
  70. std::transform(order.data(), order.data() + order.size(),
  71. orientation.begin(), [&](int index) { return
  72. signed_adj_faces[index] > 0; });
  73. std::transform(order.data(), order.data() + order.size(),
  74. order.data(), [&](int index) { return adj_faces[index]; });
  75. for (auto ei : adj_faces) {
  76. const size_t fid = edge_index_to_face_index(ei);
  77. patch_edge_adj[P[fid]].push_back(ei);
  78. }
  79. }
  80. }
  81. const int INVALID = std::numeric_limits<int>::max();
  82. cells.resize(num_patches, 2);
  83. cells.setConstant(INVALID);
  84. auto peel_cell_bd = [&](
  85. size_t seed_patch_id,
  86. short seed_patch_side,
  87. size_t cell_idx) {
  88. typedef std::pair<size_t, short> PatchSide;
  89. std::queue<PatchSide> Q;
  90. Q.emplace(seed_patch_id, seed_patch_side);
  91. cells(seed_patch_id, seed_patch_side) = cell_idx;
  92. while (!Q.empty()) {
  93. auto entry = Q.front();
  94. Q.pop();
  95. const size_t patch_id = entry.first;
  96. const short side = entry.second;
  97. const auto& adj_edges = patch_edge_adj[patch_id];
  98. for (const auto& ei : adj_edges) {
  99. const size_t uei = EMAP[ei];
  100. const auto& order = orders[uei];
  101. const auto& orientation = orientations[uei];
  102. const size_t edge_valance = order.size();
  103. size_t curr_i = 0;
  104. for (curr_i=0; curr_i < edge_valance; curr_i++) {
  105. if (order[curr_i] == ei) break;
  106. }
  107. assert(curr_i < edge_valance);
  108. const bool cons = orientation[curr_i];
  109. size_t next;
  110. if (side == 0) {
  111. next = (cons ? (curr_i + 1) :
  112. (curr_i + edge_valance - 1)) % edge_valance;
  113. } else {
  114. next = (cons ? (curr_i + edge_valance - 1) :
  115. (curr_i + 1)) % edge_valance;
  116. }
  117. const size_t next_ei = order[next];
  118. const bool next_cons = orientation[next];
  119. const size_t next_patch_id = P[next_ei % num_faces];
  120. const short next_patch_side = (next_cons != cons) ?
  121. side:abs(side-1);
  122. if (cells(next_patch_id, next_patch_side) == INVALID) {
  123. Q.emplace(next_patch_id, next_patch_side);
  124. cells(next_patch_id, next_patch_side) = cell_idx;
  125. } else {
  126. assert(cells(next_patch_id, next_patch_side) == cell_idx);
  127. }
  128. }
  129. }
  130. };
  131. size_t count=0;
  132. for (size_t i=0; i<num_patches; i++) {
  133. if (cells(i, 0) == INVALID) {
  134. peel_cell_bd(i, 0, count);
  135. count++;
  136. }
  137. if (cells(i, 1) == INVALID) {
  138. peel_cell_bd(i, 1, count);
  139. count++;
  140. }
  141. }
  142. return count;
  143. }
  144. template<
  145. typename DerivedV,
  146. typename DerivedF,
  147. typename DerivedP,
  148. typename DerivedE,
  149. typename DeriveduE,
  150. typename uE2EType,
  151. typename DerivedEMAP,
  152. typename DerivedC >
  153. IGL_INLINE size_t igl::cgal::extract_cells(
  154. const Eigen::PlainObjectBase<DerivedV>& V,
  155. const Eigen::PlainObjectBase<DerivedF>& F,
  156. const Eigen::PlainObjectBase<DerivedP>& P,
  157. const Eigen::PlainObjectBase<DerivedE>& E,
  158. const Eigen::PlainObjectBase<DeriveduE>& uE,
  159. const std::vector<std::vector<uE2EType> >& uE2E,
  160. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  161. Eigen::PlainObjectBase<DerivedC>& cells) {
  162. const size_t num_faces = F.rows();
  163. typedef typename DerivedF::Scalar Index;
  164. const size_t num_patches = P.maxCoeff()+1;
  165. DerivedC raw_cells;
  166. const size_t num_raw_cells =
  167. igl::cgal::extract_cells_single_component(
  168. V, F, P, uE, uE2E, EMAP, raw_cells);
  169. std::vector<std::vector<std::vector<Index > > > TT,_1;
  170. igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1);
  171. Eigen::VectorXi C, counts;
  172. igl::facet_components(TT, C, counts);
  173. const size_t num_components = counts.size();
  174. std::vector<std::vector<size_t> > components(num_components);
  175. for (size_t i=0; i<num_faces; i++) {
  176. components[C[i]].push_back(i);
  177. }
  178. std::vector<Eigen::VectorXi> Is(num_components);
  179. for (size_t i=0; i<num_components; i++) {
  180. Is[i].resize(components[i].size());
  181. std::copy(components[i].begin(), components[i].end(),
  182. Is[i].data());
  183. }
  184. Eigen::VectorXi outer_facets(num_components);
  185. Eigen::VectorXi outer_facet_orientation(num_components);
  186. Eigen::VectorXi outer_cells(num_components);
  187. for (size_t i=0; i<num_components; i++) {
  188. bool flipped;
  189. igl::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
  190. outer_facet_orientation[i] = flipped?1:0;
  191. outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
  192. }
  193. auto get_triangle_center = [&](const size_t fid) {
  194. return ((V.row(F(fid, 0)) + V.row(F(fid, 1)) + V.row(F(fid, 2)))
  195. /3.0).eval();
  196. };
  197. std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
  198. std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
  199. std::vector<std::vector<size_t> > ambient_comps(num_components);
  200. for (size_t i=0; i<num_components; i++) {
  201. DerivedV queries(num_components-1, 3);
  202. for (size_t j=0; j<num_components; j++) {
  203. if (i == j) continue;
  204. size_t index = j<i ? j:j-1;
  205. queries.row(index) = get_triangle_center(outer_facets[j]);
  206. }
  207. const auto& I = Is[i];
  208. Eigen::VectorXi closest_facets, closest_facet_orientations;
  209. igl::cgal::closest_facet(V, F, I, queries,
  210. closest_facets, closest_facet_orientations);
  211. for (size_t j=0; j<num_components; j++) {
  212. if (i == j) continue;
  213. size_t index = j<i ? j:j-1;
  214. const size_t closest_patch = P[closest_facets[index]];
  215. const size_t closest_patch_side = closest_facet_orientations[index]
  216. ? 0:1;
  217. const size_t ambient_cell = raw_cells(closest_patch,
  218. closest_patch_side);
  219. if (ambient_cell != outer_cells[i]) {
  220. nested_cells[ambient_cell].push_back(outer_cells[j]);
  221. ambient_cells[outer_cells[j]].push_back(ambient_cell);
  222. ambient_comps[j].push_back(i);
  223. }
  224. }
  225. }
  226. const size_t INVALID = std::numeric_limits<size_t>::max();
  227. const size_t INFINITE_CELL = num_raw_cells;
  228. std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
  229. for (size_t i=0; i<num_components; i++) {
  230. const size_t outer_cell = outer_cells[i];
  231. const auto& ambient_comps_i = ambient_comps[i];
  232. const auto& ambient_cells_i = ambient_cells[outer_cell];
  233. const size_t num_ambient_comps = ambient_comps_i.size();
  234. assert(num_ambient_comps == ambient_cells_i.size());
  235. if (num_ambient_comps > 0) {
  236. size_t embedded_comp = INVALID;
  237. size_t embedded_cell = INVALID;
  238. for (size_t j=0; j<num_ambient_comps; j++) {
  239. if (ambient_comps[ambient_comps_i[j]].size() ==
  240. num_ambient_comps-1) {
  241. embedded_comp = ambient_comps_i[j];
  242. embedded_cell = ambient_cells_i[j];
  243. break;
  244. }
  245. }
  246. assert(embedded_comp != INVALID);
  247. assert(embedded_cell != INVALID);
  248. embedded_cells[outer_cell] = embedded_cell;
  249. } else {
  250. embedded_cells[outer_cell] = INFINITE_CELL;
  251. }
  252. }
  253. for (size_t i=0; i<num_patches; i++) {
  254. if (embedded_cells[raw_cells(i,0)] != INVALID) {
  255. raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
  256. }
  257. if (embedded_cells[raw_cells(i,1)] != INVALID) {
  258. raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
  259. }
  260. }
  261. size_t count = 0;
  262. std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
  263. for (size_t i=0; i<num_patches; i++) {
  264. const size_t old_positive_cell_id = raw_cells(i, 0);
  265. const size_t old_negative_cell_id = raw_cells(i, 1);
  266. size_t positive_cell_id, negative_cell_id;
  267. if (mapped_indices[old_positive_cell_id] == INVALID) {
  268. mapped_indices[old_positive_cell_id] = count;
  269. positive_cell_id = count;
  270. count++;
  271. } else {
  272. positive_cell_id = mapped_indices[old_positive_cell_id];
  273. }
  274. if (mapped_indices[old_negative_cell_id] == INVALID) {
  275. mapped_indices[old_negative_cell_id] = count;
  276. negative_cell_id = count;
  277. count++;
  278. } else {
  279. negative_cell_id = mapped_indices[old_negative_cell_id];
  280. }
  281. raw_cells(i, 0) = positive_cell_id;
  282. raw_cells(i, 1) = negative_cell_id;
  283. }
  284. cells = raw_cells;
  285. return count;
  286. }
  287. template<
  288. typename DerivedV,
  289. typename DerivedF,
  290. typename DerivedC >
  291. IGL_INLINE size_t igl::cgal::extract_cells(
  292. const Eigen::PlainObjectBase<DerivedV>& V,
  293. const Eigen::PlainObjectBase<DerivedF>& F,
  294. Eigen::PlainObjectBase<DerivedC>& cells) {
  295. const size_t num_faces = F.rows();
  296. typedef typename DerivedF::Scalar Index;
  297. Eigen::MatrixXi E, uE;
  298. Eigen::VectorXi EMAP;
  299. std::vector<std::vector<size_t> > uE2E;
  300. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  301. Eigen::VectorXi P;
  302. const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
  303. DerivedC per_patch_cells;
  304. const size_t num_cells =
  305. igl::cgal::extract_cells(V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
  306. cells.resize(num_faces, 2);
  307. for (size_t i=0; i<num_faces; i++) {
  308. cells.row(i) = per_patch_cells.row(P[i]);
  309. }
  310. return num_cells;
  311. }