propagate_winding_numbers.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. #include "propagate_winding_numbers.h"
  2. #include "../extract_manifold_patches.h"
  3. #include "../extract_non_manifold_edge_curves.h"
  4. #include "../facet_components.h"
  5. #include "../unique_edge_map.h"
  6. #include "order_facets_around_edge.h"
  7. #include "outer_facet.h"
  8. #include "closest_facet.h"
  9. #include <stdexcept>
  10. #include <limits>
  11. #include <vector>
  12. namespace propagate_winding_numbers_helper {
  13. template<typename DerivedW >
  14. bool winding_number_assignment_is_consistent(
  15. const std::vector<Eigen::VectorXi>& orders,
  16. const std::vector<std::vector<bool> >& orientations,
  17. const Eigen::PlainObjectBase<DerivedW>& per_patch_winding_number) {
  18. const size_t num_edge_curves = orders.size();
  19. const size_t num_labels = per_patch_winding_number.cols() / 2;
  20. for (size_t i=0; i<num_edge_curves; i++) {
  21. const auto& order = orders[i];
  22. const auto& orientation = orientations[i];
  23. assert(order.size() == orientation.size());
  24. const size_t order_size = order.size();
  25. for (size_t j=0; j<order_size; j++) {
  26. const size_t curr = j;
  27. const size_t next = (j+1) % order_size;
  28. for (size_t k=0; k<num_labels; k++) {
  29. // Retrieve the winding numbers of the current partition from
  30. // the current patch and the next patch. If the patches forms
  31. // the boundary of a 3D volume, the winding number assignments
  32. // should be consistent.
  33. int curr_winding_number = per_patch_winding_number(
  34. order[curr], k*2+(orientation[curr]? 0:1));
  35. int next_winding_number = per_patch_winding_number(
  36. order[next], k*2+(orientation[next]? 1:0));
  37. if (curr_winding_number != next_winding_number) {
  38. return false;
  39. }
  40. }
  41. }
  42. }
  43. return true;
  44. }
  45. }
  46. template<
  47. typename DerivedV,
  48. typename DerivedF,
  49. typename DeriveduE,
  50. typename uE2EType,
  51. typename DerivedC,
  52. typename DerivedP,
  53. typename DerivedW >
  54. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  55. const Eigen::PlainObjectBase<DerivedV>& V,
  56. const Eigen::PlainObjectBase<DerivedF>& F,
  57. const Eigen::PlainObjectBase<DeriveduE>& uE,
  58. const std::vector<std::vector<uE2EType> >& uE2E,
  59. const Eigen::PlainObjectBase<DerivedC>& labels,
  60. const Eigen::PlainObjectBase<DerivedP>& P,
  61. const std::vector<std::vector<size_t> >& intersection_curves,
  62. Eigen::PlainObjectBase<DerivedW>& patch_W) {
  63. const size_t num_faces = F.rows();
  64. const size_t num_patches = P.maxCoeff() + 1;
  65. assert(labels.size() == num_patches);
  66. // Utility functions.
  67. auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
  68. auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
  69. auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
  70. return ci*num_faces + fi;
  71. };
  72. auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
  73. const size_t fi = edge_index_to_face_index(ei);
  74. const size_t ci = edge_index_to_corner_index(ei);
  75. s = F(fi, (ci+1)%3);
  76. d = F(fi, (ci+2)%3);
  77. };
  78. auto is_positively_orientated =
  79. [&](size_t fi, size_t s, size_t d) -> bool{
  80. const Eigen::Vector3i f = F.row(fi);
  81. if (f[0] == d && f[1] == s) return true;
  82. if (f[1] == d && f[2] == s) return true;
  83. if (f[2] == d && f[0] == s) return true;
  84. if (f[0] == s && f[1] == d) return false;
  85. if (f[1] == s && f[2] == d) return false;
  86. if (f[2] == s && f[0] == d) return false;
  87. throw std::runtime_error("Edge does not belong to face.");
  88. return false;
  89. };
  90. auto compute_signed_index = [&](size_t fi, size_t s, size_t d) -> int{
  91. return int(fi+1) * (is_positively_orientated(fi, s, d) ? 1:-1);
  92. };
  93. auto compute_unsigned_index = [&](int signed_idx) -> size_t {
  94. return abs(signed_idx) - 1;
  95. };
  96. // Order patches around each intersection curve.
  97. const size_t num_edge_curves = intersection_curves.size();
  98. std::vector<Eigen::VectorXi> orders(num_edge_curves);
  99. std::vector<std::vector<bool> > orientations(num_edge_curves);
  100. std::vector<std::vector<size_t> > patch_curve_adjacency(num_patches);
  101. for (size_t i=0; i<num_edge_curves; i++) {
  102. const auto& curve = intersection_curves[i];
  103. const size_t uei = curve[0];
  104. size_t s = uE(uei, 0);
  105. size_t d = uE(uei, 1);
  106. std::vector<int> adj_faces;
  107. for (size_t ei : uE2E[uei]) {
  108. const size_t fi = edge_index_to_face_index(ei);
  109. const size_t signed_fi =
  110. compute_signed_index(fi, s, d);
  111. adj_faces.push_back(signed_fi);
  112. patch_curve_adjacency[P[fi]].push_back(i);
  113. }
  114. auto& order = orders[i];
  115. igl::cgal::order_facets_around_edge(
  116. V, F, s, d, adj_faces, order);
  117. assert(order.minCoeff() == 0);
  118. assert(order.maxCoeff() == adj_faces.size() - 1);
  119. auto& orientation = orientations[i];
  120. orientation.resize(order.size());
  121. std::transform(order.data(), order.data()+order.size(),
  122. orientation.begin(),
  123. [&](size_t index) { return adj_faces[index] > 0; });
  124. std::transform(order.data(), order.data()+order.size(),
  125. order.data(), [&](size_t index) {
  126. return P[compute_unsigned_index(adj_faces[index])];
  127. } );
  128. }
  129. // Propagate winding number from infinity.
  130. // Assuming infinity has winding number 0.
  131. const size_t num_labels = labels.maxCoeff() + 1;
  132. const int INVALID = std::numeric_limits<int>::max();
  133. patch_W.resize(num_patches, 2*num_labels);
  134. patch_W.setConstant(INVALID);
  135. size_t outer_facet_idx;
  136. bool outer_facet_is_flipped;
  137. Eigen::VectorXi face_indices(num_faces);
  138. face_indices.setLinSpaced(num_faces, 0, num_faces-1);
  139. igl::cgal::outer_facet(V, F, face_indices,
  140. outer_facet_idx, outer_facet_is_flipped);
  141. size_t outer_patch_idx = P[outer_facet_idx];
  142. size_t outer_patch_label = labels[outer_patch_idx];
  143. patch_W.row(outer_patch_idx).setZero();
  144. if (outer_facet_is_flipped) {
  145. patch_W(outer_patch_idx, outer_patch_label*2) = -1;
  146. } else {
  147. patch_W(outer_patch_idx, outer_patch_label*2+1) = 1;
  148. }
  149. auto winding_num_assigned = [&](size_t patch_idx) -> bool{
  150. return (patch_W.row(patch_idx).array() != INVALID).all();
  151. };
  152. std::queue<size_t> Q;
  153. Q.push(outer_patch_idx);
  154. while (!Q.empty()) {
  155. const size_t curr_patch_idx = Q.front();
  156. const size_t curr_patch_label = labels[curr_patch_idx];
  157. Q.pop();
  158. const auto& adj_curves = patch_curve_adjacency[curr_patch_idx];
  159. for (size_t curve_idx : adj_curves) {
  160. const auto& order = orders[curve_idx];
  161. const auto& orientation = orientations[curve_idx];
  162. const size_t num_adj_patches = order.size();
  163. assert(num_adj_patches == orientation.size());
  164. size_t curr_i = std::numeric_limits<size_t>::max();
  165. for (size_t i=0; i<num_adj_patches; i++) {
  166. if (order[i] == curr_patch_idx) {
  167. curr_i = i;
  168. break;
  169. }
  170. }
  171. assert(curr_i < num_adj_patches);
  172. const bool curr_ori = orientation[curr_i];
  173. const size_t next_i = curr_ori ? (curr_i+1) % num_adj_patches
  174. : (curr_i+num_adj_patches-1)%num_adj_patches;
  175. const size_t prev_i = curr_ori ?
  176. (curr_i+num_adj_patches-1)%num_adj_patches
  177. : (curr_i+1) % num_adj_patches;
  178. const size_t next_patch_idx = order[next_i];
  179. const size_t prev_patch_idx = order[prev_i];
  180. if (!winding_num_assigned(next_patch_idx)) {
  181. const bool next_ori = orientation[next_i];
  182. const bool next_cons = next_ori != curr_ori;
  183. const size_t next_patch_label = labels[next_patch_idx];
  184. for (size_t i=0; i<num_labels; i++) {
  185. const int shared_winding_number =
  186. patch_W(curr_patch_idx, i*2);
  187. if (i == next_patch_label) {
  188. // Truth table:
  189. // curr_ori next_ori wind_# inc
  190. // True True -1
  191. // True False 1
  192. // False True 1
  193. // False False -1
  194. patch_W(next_patch_idx, i*2+(next_cons ?0:1)) =
  195. shared_winding_number;
  196. patch_W(next_patch_idx, i*2+(next_cons ?1:0)) =
  197. shared_winding_number + (next_cons ? 1:-1);
  198. } else {
  199. patch_W(next_patch_idx, i*2 ) = shared_winding_number;
  200. patch_W(next_patch_idx, i*2+1) = shared_winding_number;
  201. }
  202. }
  203. Q.push(next_patch_idx);
  204. }
  205. if (!winding_num_assigned(prev_patch_idx)) {
  206. const bool prev_ori = orientation[prev_i];
  207. const bool prev_cons = prev_ori != curr_ori;
  208. const size_t prev_patch_label = labels[prev_patch_idx];
  209. for (size_t i=0; i<num_labels; i++) {
  210. const int shared_winding_number =
  211. patch_W(curr_patch_idx, i*2+1);
  212. if (i == prev_patch_label) {
  213. // Truth table:
  214. // curr_ori next_ori wind_# inc
  215. // True True 1
  216. // True False -1
  217. // False True -1
  218. // False False 1
  219. patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) =
  220. shared_winding_number;
  221. patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) =
  222. shared_winding_number + (prev_cons ? -1:1);
  223. } else {
  224. patch_W(prev_patch_idx, i*2 ) = shared_winding_number;
  225. patch_W(prev_patch_idx, i*2+1) = shared_winding_number;
  226. }
  227. }
  228. Q.push(prev_patch_idx);
  229. }
  230. }
  231. }
  232. using namespace propagate_winding_numbers_helper;
  233. return winding_number_assignment_is_consistent(orders, orientations, patch_W);
  234. }
  235. template<
  236. typename DerivedV,
  237. typename DerivedF,
  238. typename DerivedC,
  239. typename DerivedW>
  240. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  241. const Eigen::PlainObjectBase<DerivedV>& V,
  242. const Eigen::PlainObjectBase<DerivedF>& F,
  243. const Eigen::PlainObjectBase<DerivedC>& labels,
  244. Eigen::PlainObjectBase<DerivedW>& W) {
  245. typedef typename DerivedF::Scalar Index;
  246. const size_t num_faces = F.rows();
  247. // Extract unique edges.
  248. std::vector<std::vector<size_t> > uE2E;
  249. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  250. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  251. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  252. // Extract manifold patches and intersection curves.
  253. Eigen::VectorXi P;
  254. std::vector<std::vector<size_t> > intersection_curves;
  255. size_t num_patches =
  256. igl::extract_manifold_patches(F, EMAP, uE2E, P);
  257. igl::extract_non_manifold_edge_curves(F, EMAP, uE2E,
  258. intersection_curves);
  259. assert(P.size() == num_faces);
  260. assert(P.maxCoeff() + 1 == num_patches);
  261. Eigen::VectorXi patch_labels(num_patches);
  262. const int INVALID = std::numeric_limits<int>::max();
  263. patch_labels.setConstant(INVALID);
  264. for (size_t i=0; i<num_faces; i++) {
  265. if (patch_labels[P[i]] == INVALID) {
  266. patch_labels[P[i]] = labels[i];
  267. } else {
  268. assert(patch_labels[P[i]] == labels[i]);
  269. }
  270. }
  271. assert((patch_labels.array() != INVALID).all());
  272. const size_t num_labels = patch_labels.maxCoeff()+1;
  273. Eigen::MatrixXi winding_numbers;
  274. bool is_consistent =
  275. igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  276. V, F, uE, uE2E, patch_labels, P, intersection_curves, winding_numbers);
  277. assert(winding_numbers.rows() == num_patches);
  278. assert(winding_numbers.cols() == 2 * num_labels);
  279. W.resize(num_faces, 2*num_labels);
  280. for (size_t i=0; i<num_faces; i++) {
  281. W.row(i) = winding_numbers.row(P[i]);
  282. }
  283. return is_consistent;
  284. }
  285. template<
  286. typename DerivedV,
  287. typename DerivedF,
  288. typename DerivedW>
  289. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  290. const Eigen::PlainObjectBase<DerivedV>& V,
  291. const Eigen::PlainObjectBase<DerivedF>& F,
  292. Eigen::PlainObjectBase<DerivedW>& W) {
  293. const size_t num_faces = F.rows();
  294. Eigen::VectorXi labels(num_faces);
  295. labels.setZero();
  296. return igl::cgal::propagate_winding_numbers_single_component(V, F, labels, W);
  297. }
  298. template<
  299. typename DerivedV,
  300. typename DerivedF,
  301. typename DerivedL,
  302. typename DerivedW>
  303. IGL_INLINE void igl::cgal::propagate_winding_numbers(
  304. const Eigen::PlainObjectBase<DerivedV>& V,
  305. const Eigen::PlainObjectBase<DerivedF>& F,
  306. const Eigen::PlainObjectBase<DerivedL>& labels,
  307. Eigen::PlainObjectBase<DerivedW>& W) {
  308. typedef typename DerivedF::Scalar Index;
  309. const size_t num_faces = F.rows();
  310. // Extract unique edges.
  311. std::vector<std::vector<size_t> > uE2E;
  312. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  313. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  314. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  315. // Check to make sure there is no boundaries and no non-manifold edges with
  316. // odd number of adjacent faces.
  317. for (const auto& adj_faces : uE2E) {
  318. if (adj_faces.size() % 2 == 1) {
  319. std::stringstream err_msg;
  320. err_msg << "Input mesh contains odd number of faces "
  321. << "sharing a single edge" << std::endl;
  322. err_msg << "Indicating the input mesh does not represent a valid volume"
  323. << ", and winding number cannot be propagated." << std::endl;
  324. throw std::runtime_error(err_msg.str());
  325. }
  326. }
  327. // Gather connected components.
  328. std::vector<std::vector<std::vector<Index > > > TT,_1;
  329. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  330. Eigen::VectorXi counts;
  331. Eigen::VectorXi C;
  332. igl::facet_components(TT,C,counts);
  333. const size_t num_components = counts.size();
  334. std::vector<std::vector<size_t> > components(num_components);
  335. for (size_t i=0; i<num_faces; i++) {
  336. components[C[i]].push_back(i);
  337. }
  338. std::vector<Eigen::MatrixXi> comp_faces(num_components);
  339. std::vector<Eigen::VectorXi> comp_labels(num_components);
  340. for (size_t i=0; i<num_components; i++) {
  341. const auto& comp = components[i];
  342. auto& faces = comp_faces[i];
  343. auto& c_labels = comp_labels[i];
  344. const size_t comp_size = comp.size();
  345. faces.resize(comp_size, 3);
  346. c_labels.resize(comp_size);
  347. for (size_t j=0; j<comp_size; j++) {
  348. faces.row(j) = F.row(comp[j]);
  349. c_labels[j] = labels[comp[j]];
  350. }
  351. }
  352. // Compute winding number for each component.
  353. const size_t num_labels = labels.maxCoeff()+1;
  354. W.resize(num_faces, 2*num_labels);
  355. W.setZero();
  356. std::vector<Eigen::MatrixXi> Ws(num_components);
  357. for (size_t i=0; i<num_components; i++) {
  358. bool is_consistent =
  359. propagate_winding_numbers_single_component(V, comp_faces[i], comp_labels[i], Ws[i]);
  360. const size_t num_labels_in_i = comp_labels[i].maxCoeff()+1;
  361. const size_t num_faces_in_comp = comp_faces[i].rows();
  362. assert(Ws[i].cols() == num_labels_in_i*2);
  363. assert(Ws[i].rows() == num_faces_in_comp);
  364. const auto& comp = components[i];
  365. for (size_t j=0; j<num_faces_in_comp; j++) {
  366. const size_t fid = comp[j];
  367. W.block(fid, 0, 1, num_labels_in_i*2) = Ws[i].row(j);
  368. }
  369. if (!is_consistent) {
  370. std::stringstream err_msg;
  371. err_msg << "Component " << i
  372. << " has inconsistant winding number assignment." << std::endl;
  373. throw std::runtime_error(err_msg.str());
  374. }
  375. }
  376. auto sample_component = [&](size_t cid) {
  377. const auto& f = comp_faces[cid].row(0).eval();
  378. return ((V.row(f[0]) + V.row(f[1]) + V.row(f[2])) / 3.0).eval();
  379. };
  380. std::vector<Eigen::MatrixXi> nested_Ws = Ws;
  381. Eigen::MatrixXi ambient_correction(num_components, 2*num_labels);
  382. ambient_correction.setZero();
  383. for (size_t i=0; i<num_components; i++) {
  384. DerivedV samples(num_components-1, 3);
  385. Eigen::VectorXi is_inside;
  386. auto index_without_i = [&](size_t index) {
  387. return index < i ? index:index-1;
  388. };
  389. for (size_t j=0; j<num_components; j++) {
  390. if (i == j) continue;
  391. samples.row(index_without_i(j)) = sample_component(j);
  392. }
  393. Eigen::VectorXi fids;
  394. Eigen::Matrix<bool, Eigen::Dynamic, 1> orientation;
  395. igl::cgal::closest_facet(V, comp_faces[i], samples,
  396. fids, orientation);
  397. const auto& comp = components[i];
  398. for (size_t j=0; j<num_components; j++) {
  399. if (i == j) continue;
  400. const size_t index = index_without_i(j);
  401. const size_t fid = fids(index, 0);
  402. const bool ori = orientation(index, 0);
  403. for (size_t k=0; k<num_labels; k++) {
  404. const int correction = W(comp[fid], k*2+(ori?0:1));
  405. ambient_correction(j, k*2 ) += correction;
  406. ambient_correction(j, k*2+1) += correction;
  407. }
  408. }
  409. }
  410. for (size_t i=0; i<num_components; i++) {
  411. const auto& comp = components[i];
  412. const auto& correction = ambient_correction.row(i).eval();
  413. for (const auto& fid : comp) {
  414. W.row(fid) += correction;
  415. }
  416. }
  417. }