extract_cells.cpp 14 KB

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