extract_cells.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  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.h"
  10. #include "extract_cells_single_component.h"
  11. #include "closest_facet.h"
  12. #include "outer_facet.h"
  13. #include "submesh_aabb_tree.h"
  14. #include "../../extract_manifold_patches.h"
  15. #include "../../facet_components.h"
  16. #include "../../IGL_ASSERT.h"
  17. #include "../../parallel_for.h"
  18. #include "../../get_seconds.h"
  19. #include "../../PlainMatrix.h"
  20. #include "../../triangle_triangle_adjacency.h"
  21. #include "../../unique_edge_map.h"
  22. #include "../../C_STR.h"
  23. #include "../../vertex_triangle_adjacency.h"
  24. #include <CGAL/AABB_tree.h>
  25. #include <CGAL/AABB_traits.h>
  26. #include <CGAL/AABB_triangle_primitive.h>
  27. #include <CGAL/intersections.h>
  28. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  29. #include <iostream>
  30. #include <vector>
  31. #include <queue>
  32. #include <map>
  33. #include <set>
  34. //#define EXTRACT_CELLS_TIMING
  35. template<
  36. typename DerivedV,
  37. typename DerivedF,
  38. typename DerivedC >
  39. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  40. const Eigen::MatrixBase<DerivedV>& V,
  41. const Eigen::MatrixBase<DerivedF>& F,
  42. Eigen::PlainObjectBase<DerivedC>& cells)
  43. {
  44. using Index = typename DerivedF::Scalar;
  45. static_assert(
  46. std::is_same<Index, typename DerivedC::Scalar>::value,
  47. "Index type mismatch");
  48. using MatrixXI = Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic>;
  49. using VectorXI = Eigen::Matrix<Index, Eigen::Dynamic, 1>;
  50. const size_t num_faces = F.rows();
  51. // Construct edge adjacency
  52. Eigen::MatrixXi E, uE;
  53. Eigen::VectorXi EMAP;
  54. Eigen::VectorXi uEC,uEE;
  55. igl::unique_edge_map(F, E, uE, EMAP, uEC, uEE);
  56. // Cluster into manifold patches
  57. Eigen::VectorXi P;
  58. igl::extract_manifold_patches(F, EMAP, uEC, uEE, P);
  59. // Extract cells
  60. DerivedC per_patch_cells;
  61. const size_t ncells = extract_cells(V,F,P,uE,EMAP,uEC,uEE,per_patch_cells);
  62. // Distribute per-patch cell information to each face
  63. cells.resize(num_faces, 2);
  64. for (size_t i=0; i<num_faces; i++)
  65. {
  66. cells.row(i) = per_patch_cells.row(P[i]);
  67. }
  68. return ncells;
  69. }
  70. template<
  71. typename DerivedV,
  72. typename DerivedF,
  73. typename DerivedP,
  74. typename DeriveduE,
  75. typename DerivedEMAP,
  76. typename DeriveduEC,
  77. typename DeriveduEE,
  78. typename DerivedC >
  79. IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
  80. const Eigen::MatrixBase<DerivedV>& V,
  81. const Eigen::MatrixBase<DerivedF>& F,
  82. const Eigen::MatrixBase<DerivedP>& P,
  83. const Eigen::MatrixBase<DeriveduE>& uE,
  84. const Eigen::MatrixBase<DerivedEMAP>& EMAP,
  85. const Eigen::MatrixBase<DeriveduEC>& uEC,
  86. const Eigen::MatrixBase<DeriveduEE>& uEE,
  87. Eigen::PlainObjectBase<DerivedC>& cells)
  88. {
  89. // Trivial base case
  90. if(P.size() == 0)
  91. {
  92. assert(F.size() == 0);
  93. cells.resize(0,2);
  94. return 0;
  95. }
  96. typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
  97. #ifdef EXTRACT_CELLS_TIMING
  98. const auto & tictoc = []() -> double
  99. {
  100. static double t_start = igl::get_seconds();
  101. double diff = igl::get_seconds()-t_start;
  102. t_start += diff;
  103. return diff;
  104. };
  105. const auto log_time = [&](const std::string& label) -> void {
  106. printf("%50s: %0.5lf\n",
  107. C_STR("extract_cells." << label),tictoc());
  108. };
  109. tictoc();
  110. #else
  111. // no-op
  112. const auto log_time = [](const std::string){};
  113. #endif
  114. const size_t num_faces = F.rows();
  115. typedef typename DerivedF::Scalar Index;
  116. using VectorXI = Eigen::Matrix<Index, Eigen::Dynamic, 1>;
  117. assert(P.size() > 0);
  118. const size_t num_patches = P.maxCoeff()+1;
  119. // Extract all cells...
  120. DerivedC raw_cells;
  121. const int num_raw_cells =
  122. extract_cells_single_component(V,F,P,uE,uEC,uEE,raw_cells);
  123. log_time("extract_cells_single_component");
  124. // Compute triangle-triangle adjacency data-structure
  125. std::vector<std::vector<std::vector<Index > > > TT,_1;
  126. igl::triangle_triangle_adjacency(EMAP, uEC, uEE, false, TT, _1);
  127. log_time("compute_face_adjacency");
  128. // Compute connected components of the mesh
  129. Eigen::VectorXi C, counts;
  130. igl::facet_components(TT, C, counts);
  131. log_time("form_components");
  132. const size_t num_components = counts.size();
  133. // components[c] --> list of face indices into F of faces in component c
  134. std::vector<std::vector<size_t> > components(num_components);
  135. // Loop over all faces
  136. for (size_t i=0; i<num_faces; i++)
  137. {
  138. components[C[i]].push_back(i);
  139. }
  140. // Convert vector lists to Eigen lists...
  141. // and precompute data-structures for each component
  142. std::vector<std::vector<size_t> > VF,VFi;
  143. igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
  144. std::vector<VectorXI> Is(num_components);
  145. std::vector<
  146. CGAL::AABB_tree<
  147. CGAL::AABB_traits<
  148. Kernel,
  149. CGAL::AABB_triangle_primitive<
  150. Kernel, std::vector<
  151. Kernel::Triangle_3 >::iterator > > > > trees(num_components);
  152. std::vector< std::vector<Kernel::Triangle_3 > >
  153. triangle_lists(num_components);
  154. // O(num_components * num_faces)
  155. // In general, extract_cells appears to have O(num_components * num_faces)
  156. // performance. This could be painfully tested by a processing a cloud of
  157. // tetrahedra.
  158. std::vector<std::vector<bool> > in_Is(num_components);
  159. // Find outer facets, their orientations and cells for each component
  160. Eigen::VectorXi outer_facets(num_components);
  161. Eigen::VectorXi outer_facet_orientation(num_components);
  162. Eigen::VectorXi outer_cells(num_components);
  163. igl::parallel_for(num_components,[&](size_t i)
  164. {
  165. Is[i].resize(components[i].size());
  166. std::copy(components[i].begin(), components[i].end(),Is[i].data());
  167. bool flipped;
  168. igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
  169. outer_facet_orientation[i] = flipped?1:0;
  170. outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
  171. },1000);
  172. #ifdef EXTRACT_CELLS_TIMING
  173. log_time("outer_facet_per_component");
  174. #endif
  175. // Compute barycenter of a triangle in mesh (V,F)
  176. //
  177. // Inputs:
  178. // fid index into F
  179. // Returns row-vector of barycenter coordinates
  180. const auto get_triangle_center = [&V,&F](const size_t fid)
  181. {
  182. return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
  183. };
  184. std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
  185. std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
  186. std::vector<std::vector<size_t> > ambient_comps(num_components);
  187. // Only bother if there's more than one component
  188. if(num_components > 1)
  189. {
  190. // construct bounding boxes for each component
  191. PlainMatrix<DerivedV,Eigen::Dynamic,3> bbox_min(num_components, 3);
  192. PlainMatrix<DerivedV,Eigen::Dynamic,3> bbox_max(num_components, 3);
  193. // Assuming our mesh (in exact numbers) fits in the range of double.
  194. bbox_min.setConstant(std::numeric_limits<double>::max());
  195. bbox_max.setConstant(std::numeric_limits<double>::lowest());
  196. // Loop over faces
  197. for (size_t i=0; i<num_faces; i++)
  198. {
  199. // component of this face
  200. const auto comp_id = C[i];
  201. const auto& f = F.row(i);
  202. for (size_t j=0; j<3; j++)
  203. {
  204. for(size_t d=0;d<3;d++)
  205. {
  206. bbox_min(comp_id,d) = std::min(bbox_min(comp_id,d), V(f[j],d));
  207. bbox_max(comp_id,d) = std::max(bbox_max(comp_id,d), V(f[j],d));
  208. }
  209. }
  210. }
  211. // Return true if box of component ci intersects that of cj
  212. const auto bbox_intersects = [&bbox_max,&bbox_min](size_t ci, size_t cj)
  213. {
  214. return !(
  215. bbox_max(ci,0) < bbox_min(cj,0) ||
  216. bbox_max(ci,1) < bbox_min(cj,1) ||
  217. bbox_max(ci,2) < bbox_min(cj,2) ||
  218. bbox_max(cj,0) < bbox_min(ci,0) ||
  219. bbox_max(cj,1) < bbox_min(ci,1) ||
  220. bbox_max(cj,2) < bbox_min(ci,2));
  221. };
  222. // Loop over components. This section is O(m²)
  223. for (size_t i=0; i<num_components; i++)
  224. {
  225. // List of components that could overlap with component i
  226. std::vector<size_t> candidate_comps;
  227. candidate_comps.reserve(num_components);
  228. // Loop over components
  229. for (size_t j=0; j<num_components; j++)
  230. {
  231. if (i == j) continue;
  232. if (bbox_intersects(i,j)) candidate_comps.push_back(j);
  233. }
  234. const size_t num_candidate_comps = candidate_comps.size();
  235. if (num_candidate_comps == 0) continue;
  236. // Build aabb tree for this component.
  237. submesh_aabb_tree(V,F,Is[i],trees[i],triangle_lists[i],in_Is[i]);
  238. // Get query points on each candidate component: barycenter of
  239. // outer-facet
  240. PlainMatrix<DerivedV,Eigen::Dynamic,3> queries(num_candidate_comps, 3);
  241. for (size_t j=0; j<num_candidate_comps; j++)
  242. {
  243. const size_t index = candidate_comps[j];
  244. queries.row(j) = get_triangle_center(outer_facets[index]);
  245. }
  246. // Gather closest facets in ith component to each query point and their
  247. // orientations
  248. const auto& I = Is[i];
  249. const auto& tree = trees[i];
  250. const auto& in_I = in_Is[i];
  251. const auto& triangles = triangle_lists[i];
  252. Eigen::VectorXi closest_facets, closest_facet_orientations;
  253. closest_facet(
  254. V,
  255. F,
  256. I,
  257. queries,
  258. EMAP,
  259. uEC,
  260. uEE,
  261. VF,
  262. VFi,
  263. tree,
  264. triangles,
  265. in_I,
  266. closest_facets,
  267. closest_facet_orientations);
  268. // Loop over all candidates
  269. for (size_t j=0; j<num_candidate_comps; j++)
  270. {
  271. const size_t index = candidate_comps[j];
  272. const size_t closest_patch = P[closest_facets[j]];
  273. const size_t closest_patch_side = closest_facet_orientations[j] ? 0:1;
  274. // The cell id of the closest patch
  275. const size_t ambient_cell =
  276. raw_cells(closest_patch,closest_patch_side);
  277. if (ambient_cell != (size_t)outer_cells[i])
  278. {
  279. // ---> component index inside component i, because the cell of the
  280. // closest facet on i to component index is **not** the same as the
  281. // "outer cell" of component i: component index is **not** outside of
  282. // component i (therefore it's inside).
  283. nested_cells[ambient_cell].push_back(outer_cells[index]);
  284. ambient_cells[outer_cells[index]].push_back(ambient_cell);
  285. ambient_comps[index].push_back(i);
  286. }
  287. }
  288. }
  289. }
  290. #ifdef EXTRACT_CELLS_TIMING
  291. log_time("nested_relationship");
  292. #endif
  293. const size_t INVALID = std::numeric_limits<size_t>::max();
  294. const size_t INFINITE_CELL = num_raw_cells;
  295. std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
  296. for (size_t i=0; i<num_components; i++) {
  297. const size_t outer_cell = outer_cells[i];
  298. const auto& ambient_comps_i = ambient_comps[i];
  299. const auto& ambient_cells_i = ambient_cells[outer_cell];
  300. const size_t num_ambient_comps = ambient_comps_i.size();
  301. assert(num_ambient_comps == ambient_cells_i.size());
  302. if (num_ambient_comps > 0) {
  303. size_t embedded_comp = INVALID;
  304. size_t embedded_cell = INVALID;
  305. for (size_t j=0; j<num_ambient_comps; j++) {
  306. if (ambient_comps[ambient_comps_i[j]].size() ==
  307. num_ambient_comps-1) {
  308. embedded_comp = ambient_comps_i[j];
  309. embedded_cell = ambient_cells_i[j];
  310. break;
  311. }
  312. }
  313. IGL_ASSERT(embedded_comp != INVALID);
  314. IGL_ASSERT(embedded_cell != INVALID);
  315. embedded_cells[outer_cell] = embedded_cell;
  316. } else {
  317. embedded_cells[outer_cell] = INFINITE_CELL;
  318. }
  319. }
  320. for (size_t i=0; i<num_patches; i++) {
  321. if (embedded_cells[raw_cells(i,0)] != INVALID) {
  322. raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
  323. }
  324. if (embedded_cells[raw_cells(i,1)] != INVALID) {
  325. raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
  326. }
  327. }
  328. size_t count = 0;
  329. std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
  330. // Always map infinite cell to index 0.
  331. mapped_indices[INFINITE_CELL] = count;
  332. count++;
  333. for (size_t i=0; i<num_patches; i++) {
  334. const size_t old_positive_cell_id = raw_cells(i, 0);
  335. const size_t old_negative_cell_id = raw_cells(i, 1);
  336. size_t positive_cell_id, negative_cell_id;
  337. if (mapped_indices[old_positive_cell_id] == INVALID) {
  338. mapped_indices[old_positive_cell_id] = count;
  339. positive_cell_id = count;
  340. count++;
  341. } else {
  342. positive_cell_id = mapped_indices[old_positive_cell_id];
  343. }
  344. if (mapped_indices[old_negative_cell_id] == INVALID) {
  345. mapped_indices[old_negative_cell_id] = count;
  346. negative_cell_id = count;
  347. count++;
  348. } else {
  349. negative_cell_id = mapped_indices[old_negative_cell_id];
  350. }
  351. raw_cells(i, 0) = positive_cell_id;
  352. raw_cells(i, 1) = negative_cell_id;
  353. }
  354. cells = raw_cells;
  355. #ifdef EXTRACT_CELLS_TIMING
  356. log_time("finalize");
  357. #endif
  358. return count;
  359. }
  360. #ifdef IGL_STATIC_LIBRARY
  361. #include <CGAL/Exact_predicates_exact_constructions_kernel.h>
  362. // Explicit template instantiation
  363. // generated by autoexplicit.sh
  364. template size_t igl::copyleft::cgal::extract_cells<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::MatrixBase<Eigen::Matrix<CGAL::Epeck::FT, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  365. template size_t igl::copyleft::cgal::extract_cells<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::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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  366. template size_t igl::copyleft::cgal::extract_cells<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::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&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
  367. #ifdef WIN32
  368. #endif
  369. #endif