extract_cells.cpp 17 KB

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