propagate_winding_numbers.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775
  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 "../writeOBJ.h"
  7. #include "order_facets_around_edge.h"
  8. #include "outer_facet.h"
  9. #include "closest_facet.h"
  10. #include "assign_scalar.h"
  11. #include "extract_cells.h"
  12. #include <stdexcept>
  13. #include <limits>
  14. #include <vector>
  15. namespace propagate_winding_numbers_helper {
  16. template<typename DerivedW >
  17. bool winding_number_assignment_is_consistent(
  18. const std::vector<Eigen::VectorXi>& orders,
  19. const std::vector<std::vector<bool> >& orientations,
  20. const Eigen::PlainObjectBase<DerivedW>& per_patch_winding_number) {
  21. const size_t num_edge_curves = orders.size();
  22. const size_t num_labels = per_patch_winding_number.cols() / 2;
  23. for (size_t i=0; i<num_edge_curves; i++) {
  24. const auto& order = orders[i];
  25. const auto& orientation = orientations[i];
  26. assert(order.size() == orientation.size());
  27. const size_t order_size = order.size();
  28. for (size_t j=0; j<order_size; j++) {
  29. const size_t curr = j;
  30. const size_t next = (j+1) % order_size;
  31. for (size_t k=0; k<num_labels; k++) {
  32. // Retrieve the winding numbers of the current partition from
  33. // the current patch and the next patch. If the patches forms
  34. // the boundary of a 3D volume, the winding number assignments
  35. // should be consistent.
  36. int curr_winding_number = per_patch_winding_number(
  37. order[curr], k*2+(orientation[curr]? 0:1));
  38. int next_winding_number = per_patch_winding_number(
  39. order[next], k*2+(orientation[next]? 1:0));
  40. if (curr_winding_number != next_winding_number) {
  41. std::cout << "edge: " << i << std::endl;
  42. std::cout << curr_winding_number << " != " <<
  43. next_winding_number << std::endl;
  44. return false;
  45. }
  46. }
  47. }
  48. }
  49. return true;
  50. }
  51. }
  52. template<
  53. typename DerivedV,
  54. typename DerivedF,
  55. typename DeriveduE,
  56. typename uE2EType,
  57. typename DerivedC,
  58. typename DerivedP,
  59. typename DerivedW >
  60. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  61. const Eigen::PlainObjectBase<DerivedV>& V,
  62. const Eigen::PlainObjectBase<DerivedF>& F,
  63. const Eigen::PlainObjectBase<DeriveduE>& uE,
  64. const std::vector<std::vector<uE2EType> >& uE2E,
  65. const Eigen::PlainObjectBase<DerivedC>& labels,
  66. const Eigen::PlainObjectBase<DerivedP>& P,
  67. const std::vector<std::vector<size_t> >& intersection_curves,
  68. Eigen::PlainObjectBase<DerivedW>& patch_W) {
  69. const size_t num_faces = F.rows();
  70. const size_t num_patches = P.maxCoeff() + 1;
  71. assert(labels.size() == num_patches);
  72. // Utility functions.
  73. auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
  74. auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
  75. auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
  76. return ci*num_faces + fi;
  77. };
  78. auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
  79. const size_t fi = edge_index_to_face_index(ei);
  80. const size_t ci = edge_index_to_corner_index(ei);
  81. s = F(fi, (ci+1)%3);
  82. d = F(fi, (ci+2)%3);
  83. };
  84. auto is_positively_orientated =
  85. [&](size_t fi, size_t s, size_t d) -> bool{
  86. const Eigen::Vector3i f = F.row(fi);
  87. if (f[0] == d && f[1] == s) return true;
  88. if (f[1] == d && f[2] == s) return true;
  89. if (f[2] == d && f[0] == s) return true;
  90. if (f[0] == s && f[1] == d) return false;
  91. if (f[1] == s && f[2] == d) return false;
  92. if (f[2] == s && f[0] == d) return false;
  93. throw std::runtime_error("Edge does not belong to face.");
  94. return false;
  95. };
  96. auto compute_signed_index = [&](size_t fi, size_t s, size_t d) -> int{
  97. return int(fi+1) * (is_positively_orientated(fi, s, d) ? 1:-1);
  98. };
  99. auto compute_unsigned_index = [&](int signed_idx) -> size_t {
  100. return abs(signed_idx) - 1;
  101. };
  102. // Order patches around each intersection curve.
  103. const size_t num_edge_curves = intersection_curves.size();
  104. std::vector<Eigen::VectorXi> orders(num_edge_curves);
  105. std::vector<std::vector<bool> > orientations(num_edge_curves);
  106. std::vector<std::vector<size_t> > patch_curve_adjacency(num_patches);
  107. for (size_t i=0; i<num_edge_curves; i++) {
  108. const auto& curve = intersection_curves[i];
  109. const size_t uei = curve[0];
  110. size_t s = uE(uei, 0);
  111. size_t d = uE(uei, 1);
  112. std::vector<int> adj_faces;
  113. for (size_t ei : uE2E[uei]) {
  114. const size_t fi = edge_index_to_face_index(ei);
  115. const size_t signed_fi =
  116. compute_signed_index(fi, s, d);
  117. adj_faces.push_back(signed_fi);
  118. patch_curve_adjacency[P[fi]].push_back(i);
  119. }
  120. auto& order = orders[i];
  121. igl::cgal::order_facets_around_edge(
  122. V, F, s, d, adj_faces, order);
  123. assert(order.minCoeff() == 0);
  124. assert(order.maxCoeff() == adj_faces.size() - 1);
  125. auto& orientation = orientations[i];
  126. orientation.resize(order.size());
  127. std::transform(order.data(), order.data()+order.size(),
  128. orientation.begin(),
  129. [&](size_t index) { return adj_faces[index] > 0; });
  130. std::transform(order.data(), order.data()+order.size(),
  131. order.data(), [&](size_t index) {
  132. return P[compute_unsigned_index(adj_faces[index])];
  133. } );
  134. }
  135. // Propagate winding number from infinity.
  136. // Assuming infinity has winding number 0.
  137. const size_t num_labels = labels.maxCoeff() + 1;
  138. const int INVALID = std::numeric_limits<int>::max();
  139. patch_W.resize(num_patches, 2*num_labels);
  140. patch_W.setConstant(INVALID);
  141. size_t outer_facet_idx;
  142. bool outer_facet_is_flipped;
  143. Eigen::VectorXi face_indices(num_faces);
  144. face_indices.setLinSpaced(num_faces, 0, num_faces-1);
  145. igl::cgal::outer_facet(V, F, face_indices,
  146. outer_facet_idx, outer_facet_is_flipped);
  147. size_t outer_patch_idx = P[outer_facet_idx];
  148. size_t outer_patch_label = labels[outer_patch_idx];
  149. patch_W.row(outer_patch_idx).setZero();
  150. if (outer_facet_is_flipped) {
  151. patch_W(outer_patch_idx, outer_patch_label*2) = -1;
  152. } else {
  153. patch_W(outer_patch_idx, outer_patch_label*2+1) = 1;
  154. }
  155. auto winding_num_assigned = [&](size_t patch_idx) -> bool{
  156. return (patch_W.row(patch_idx).array() != INVALID).all();
  157. };
  158. std::queue<size_t> Q;
  159. Q.push(outer_patch_idx);
  160. while (!Q.empty()) {
  161. const size_t curr_patch_idx = Q.front();
  162. const size_t curr_patch_label = labels[curr_patch_idx];
  163. Q.pop();
  164. const auto& adj_curves = patch_curve_adjacency[curr_patch_idx];
  165. for (size_t curve_idx : adj_curves) {
  166. const auto& order = orders[curve_idx];
  167. const auto& orientation = orientations[curve_idx];
  168. const size_t num_adj_patches = order.size();
  169. assert(num_adj_patches == orientation.size());
  170. size_t curr_i = std::numeric_limits<size_t>::max();
  171. for (size_t i=0; i<num_adj_patches; i++) {
  172. if (order[i] == curr_patch_idx) {
  173. curr_i = i;
  174. break;
  175. }
  176. }
  177. assert(curr_i < num_adj_patches);
  178. const bool curr_ori = orientation[curr_i];
  179. //for (size_t i=0; i<num_adj_patches; i++) {
  180. // const size_t next_i = (curr_i + 1) % num_adj_patches;
  181. // const size_t num_patch_idx = order[next_i];
  182. // const bool next_ori = orientation[next_i];
  183. // const size_t next_patch_label = labels[next_patch_idx];
  184. // // TODO
  185. //}
  186. const size_t next_i = curr_ori ? (curr_i+1) % num_adj_patches
  187. : (curr_i+num_adj_patches-1)%num_adj_patches;
  188. const size_t prev_i = curr_ori ?
  189. (curr_i+num_adj_patches-1)%num_adj_patches
  190. : (curr_i+1) % num_adj_patches;
  191. const size_t next_patch_idx = order[next_i];
  192. const size_t prev_patch_idx = order[prev_i];
  193. if (!winding_num_assigned(next_patch_idx)) {
  194. const bool next_ori = orientation[next_i];
  195. const bool next_cons = next_ori != curr_ori;
  196. const size_t next_patch_label = labels[next_patch_idx];
  197. for (size_t i=0; i<num_labels; i++) {
  198. const int shared_winding_number =
  199. patch_W(curr_patch_idx, i*2);
  200. if (i == next_patch_label) {
  201. // Truth table:
  202. // curr_ori next_ori wind_# inc
  203. // True True -1
  204. // True False 1
  205. // False True 1
  206. // False False -1
  207. patch_W(next_patch_idx, i*2+(next_cons ?0:1)) =
  208. shared_winding_number;
  209. patch_W(next_patch_idx, i*2+(next_cons ?1:0)) =
  210. shared_winding_number + (next_cons ? 1:-1);
  211. } else {
  212. patch_W(next_patch_idx, i*2 ) = shared_winding_number;
  213. patch_W(next_patch_idx, i*2+1) = shared_winding_number;
  214. }
  215. }
  216. Q.push(next_patch_idx);
  217. }
  218. if (!winding_num_assigned(prev_patch_idx)) {
  219. const bool prev_ori = orientation[prev_i];
  220. const bool prev_cons = prev_ori != curr_ori;
  221. const size_t prev_patch_label = labels[prev_patch_idx];
  222. for (size_t i=0; i<num_labels; i++) {
  223. const int shared_winding_number =
  224. patch_W(curr_patch_idx, i*2+1);
  225. if (i == prev_patch_label) {
  226. // Truth table:
  227. // curr_ori next_ori wind_# inc
  228. // True True 1
  229. // True False -1
  230. // False True -1
  231. // False False 1
  232. patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) =
  233. shared_winding_number;
  234. patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) =
  235. shared_winding_number + (prev_cons ? -1:1);
  236. } else {
  237. patch_W(prev_patch_idx, i*2 ) = shared_winding_number;
  238. patch_W(prev_patch_idx, i*2+1) = shared_winding_number;
  239. }
  240. }
  241. Q.push(prev_patch_idx);
  242. }
  243. }
  244. }
  245. assert((patch_W.array() != INVALID).all());
  246. using namespace propagate_winding_numbers_helper;
  247. return winding_number_assignment_is_consistent(orders, orientations, patch_W);
  248. }
  249. #if 0
  250. template<
  251. typename DerivedV,
  252. typename DerivedF,
  253. typename DeriveduE,
  254. typename uE2EType,
  255. typename DerivedEMAP,
  256. typename DerivedC,
  257. typename DerivedP,
  258. typename DerivedW >
  259. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  260. const Eigen::PlainObjectBase<DerivedV>& V,
  261. const Eigen::PlainObjectBase<DerivedF>& F,
  262. const Eigen::PlainObjectBase<DeriveduE>& uE,
  263. const std::vector<std::vector<uE2EType> >& uE2E,
  264. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  265. const Eigen::PlainObjectBase<DerivedC>& labels,
  266. const Eigen::PlainObjectBase<DerivedP>& P,
  267. Eigen::PlainObjectBase<DerivedW>& patch_W) {
  268. const size_t num_faces = F.rows();
  269. const size_t num_patches = P.maxCoeff() + 1;
  270. assert(labels.size() == num_patches);
  271. // Utility functions.
  272. auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
  273. auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
  274. auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
  275. return ci*num_faces + fi;
  276. };
  277. auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
  278. const size_t fi = edge_index_to_face_index(ei);
  279. const size_t ci = edge_index_to_corner_index(ei);
  280. s = F(fi, (ci+1)%3);
  281. d = F(fi, (ci+2)%3);
  282. };
  283. auto is_positively_orientated =
  284. [&](size_t fi, size_t s, size_t d) -> bool{
  285. const Eigen::Vector3i f = F.row(fi);
  286. if (f[0] == d && f[1] == s) return true;
  287. if (f[1] == d && f[2] == s) return true;
  288. if (f[2] == d && f[0] == s) return true;
  289. if (f[0] == s && f[1] == d) return false;
  290. if (f[1] == s && f[2] == d) return false;
  291. if (f[2] == s && f[0] == d) return false;
  292. throw std::runtime_error("Edge does not belong to face.");
  293. return false;
  294. };
  295. auto compute_signed_index = [&](size_t fi, size_t s, size_t d) -> int{
  296. return int(fi+1) * (is_positively_orientated(fi, s, d) ? 1:-1);
  297. };
  298. auto compute_unsigned_index = [&](int signed_idx) -> size_t {
  299. return abs(signed_idx) - 1;
  300. };
  301. // Order patches around each non-manifold edge.
  302. const size_t num_edges = uE.rows();
  303. std::vector<Eigen::VectorXi> orders(num_edges);
  304. std::vector<std::vector<bool> > orientations(num_edges);
  305. std::vector<std::vector<size_t> > patch_edge_adjacency(num_patches);
  306. for (size_t uei=0; uei<num_edges; uei++) {
  307. const auto& edges = uE2E[uei];
  308. if (edges.size() <= 2) continue;
  309. size_t s = uE(uei, 0);
  310. size_t d = uE(uei, 1);
  311. std::vector<int> adj_faces;
  312. for (size_t ei : uE2E[uei]) {
  313. const size_t fi = edge_index_to_face_index(ei);
  314. const size_t signed_fi =
  315. compute_signed_index(fi, s, d);
  316. adj_faces.push_back(signed_fi);
  317. patch_edge_adjacency[P[fi]].push_back(ei);
  318. }
  319. auto& order = orders[uei];
  320. igl::cgal::order_facets_around_edge(
  321. V, F, s, d, adj_faces, order);
  322. assert(order.minCoeff() == 0);
  323. assert(order.maxCoeff() == adj_faces.size() - 1);
  324. auto& orientation = orientations[uei];
  325. orientation.resize(order.size());
  326. std::transform(order.data(), order.data()+order.size(),
  327. orientation.begin(),
  328. [&](size_t index) { return adj_faces[index] > 0; });
  329. std::transform(order.data(), order.data()+order.size(),
  330. order.data(), [&](size_t index) {
  331. return compute_unsigned_index(adj_faces[index]);
  332. } );
  333. }
  334. // Propagate winding number from infinity.
  335. // Assuming infinity has winding number 0.
  336. const size_t num_labels = labels.maxCoeff() + 1;
  337. const int INVALID = std::numeric_limits<int>::max();
  338. patch_W.resize(num_patches, 2*num_labels);
  339. patch_W.setConstant(INVALID);
  340. size_t outer_facet_idx;
  341. bool outer_facet_is_flipped;
  342. Eigen::VectorXi face_indices(num_faces);
  343. face_indices.setLinSpaced(num_faces, 0, num_faces-1);
  344. igl::cgal::outer_facet(V, F, face_indices,
  345. outer_facet_idx, outer_facet_is_flipped);
  346. size_t outer_patch_idx = P[outer_facet_idx];
  347. size_t outer_patch_label = labels[outer_patch_idx];
  348. patch_W.row(outer_patch_idx).setZero();
  349. if (outer_facet_is_flipped) {
  350. patch_W(outer_patch_idx, outer_patch_label*2) = -1;
  351. } else {
  352. patch_W(outer_patch_idx, outer_patch_label*2+1) = 1;
  353. }
  354. auto winding_num_assigned = [&](size_t patch_idx) -> bool{
  355. return (patch_W.row(patch_idx).array() != INVALID).all();
  356. };
  357. std::queue<size_t> Q;
  358. Q.push(outer_patch_idx);
  359. while (!Q.empty()) {
  360. const size_t curr_patch_idx = Q.front();
  361. const size_t curr_patch_label = labels[curr_patch_idx];
  362. Q.pop();
  363. const auto& adj_edges = patch_edge_adjacency[curr_patch_idx];
  364. for (size_t ei: adj_edges) {
  365. const size_t uei = EMAP[ei];
  366. const size_t fid = edge_index_to_face_index(ei);
  367. const auto& order = orders[uei];
  368. const auto& orientation = orientations[uei];
  369. const size_t num_adj_patches = order.size();
  370. assert(num_adj_patches == orientation.size());
  371. size_t curr_i = std::numeric_limits<size_t>::max();
  372. for (size_t i=0; i<num_adj_patches; i++) {
  373. std::cout << (orientation[i]?"+":"-") << order[i] << " ";
  374. }
  375. std::cout << std::endl;
  376. for (size_t i=0; i<num_adj_patches; i++) {
  377. if (order[i] == fid) {
  378. curr_i = i;
  379. break;
  380. }
  381. }
  382. assert(curr_i < num_adj_patches);
  383. const bool curr_ori = orientation[curr_i];
  384. const size_t next_i = curr_ori ? (curr_i+1) % num_adj_patches
  385. : (curr_i+num_adj_patches-1)%num_adj_patches;
  386. const size_t prev_i = curr_ori ?
  387. (curr_i+num_adj_patches-1)%num_adj_patches
  388. : (curr_i+1) % num_adj_patches;
  389. const size_t next_patch_idx = P[order[next_i]];
  390. const size_t prev_patch_idx = P[order[prev_i]];
  391. if (!winding_num_assigned(next_patch_idx)) {
  392. const bool next_ori = orientation[next_i];
  393. const bool next_cons = next_ori != curr_ori;
  394. const size_t next_patch_label = labels[next_patch_idx];
  395. for (size_t i=0; i<num_labels; i++) {
  396. const int shared_winding_number =
  397. patch_W(curr_patch_idx, i*2);
  398. if (i == next_patch_label) {
  399. // Truth table:
  400. // curr_ori next_ori wind_# inc
  401. // True True -1
  402. // True False 1
  403. // False True 1
  404. // False False -1
  405. patch_W(next_patch_idx, i*2+(next_cons ?0:1)) =
  406. shared_winding_number;
  407. patch_W(next_patch_idx, i*2+(next_cons ?1:0)) =
  408. shared_winding_number + (next_cons ? 1:-1);
  409. } else {
  410. patch_W(next_patch_idx, i*2 ) = shared_winding_number;
  411. patch_W(next_patch_idx, i*2+1) = shared_winding_number;
  412. }
  413. }
  414. Q.push(next_patch_idx);
  415. } else {
  416. const bool next_ori = orientation[next_i];
  417. const bool next_cons = next_ori != curr_ori;
  418. const size_t next_patch_label = labels[next_patch_idx];
  419. for (size_t i=0; i<num_labels; i++) {
  420. const int shared_winding_number =
  421. patch_W(curr_patch_idx, i*2);
  422. if (i == next_patch_label) {
  423. // Truth table:
  424. // curr_ori next_ori wind_# inc
  425. // True True -1
  426. // True False 1
  427. // False True 1
  428. // False False -1
  429. assert(patch_W(next_patch_idx, i*2+(next_cons ?0:1)) ==
  430. shared_winding_number);
  431. assert(patch_W(next_patch_idx, i*2+(next_cons ?1:0)) ==
  432. shared_winding_number + (next_cons ? 1:-1));
  433. } else {
  434. assert(patch_W(next_patch_idx, i*2) ==
  435. shared_winding_number);
  436. assert(patch_W(next_patch_idx, i*2+1) ==
  437. shared_winding_number);
  438. }
  439. }
  440. }
  441. if (!winding_num_assigned(prev_patch_idx)) {
  442. const bool prev_ori = orientation[prev_i];
  443. const bool prev_cons = prev_ori != curr_ori;
  444. const size_t prev_patch_label = labels[prev_patch_idx];
  445. for (size_t i=0; i<num_labels; i++) {
  446. const int shared_winding_number =
  447. patch_W(curr_patch_idx, i*2+1);
  448. if (i == prev_patch_label) {
  449. // Truth table:
  450. // curr_ori next_ori wind_# inc
  451. // True True 1
  452. // True False -1
  453. // False True -1
  454. // False False 1
  455. patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) =
  456. shared_winding_number;
  457. patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) =
  458. shared_winding_number + (prev_cons ? -1:1);
  459. } else {
  460. patch_W(prev_patch_idx, i*2 ) = shared_winding_number;
  461. patch_W(prev_patch_idx, i*2+1) = shared_winding_number;
  462. }
  463. }
  464. Q.push(prev_patch_idx);
  465. } else {
  466. const bool prev_ori = orientation[prev_i];
  467. const bool prev_cons = prev_ori != curr_ori;
  468. const size_t prev_patch_label = labels[prev_patch_idx];
  469. for (size_t i=0; i<num_labels; i++) {
  470. const int shared_winding_number =
  471. patch_W(curr_patch_idx, i*2+1);
  472. if (i == prev_patch_label) {
  473. // Truth table:
  474. // curr_ori next_ori wind_# inc
  475. // True True 1
  476. // True False -1
  477. // False True -1
  478. // False False 1
  479. assert(patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) ==
  480. shared_winding_number);
  481. assert(patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) ==
  482. shared_winding_number + (prev_cons ? -1:1));
  483. } else {
  484. assert(patch_W(prev_patch_idx, i*2 ) ==
  485. shared_winding_number);
  486. assert(patch_W(prev_patch_idx, i*2+1) ==
  487. shared_winding_number);
  488. }
  489. }
  490. }
  491. }
  492. }
  493. assert((patch_W.array() != INVALID).all());
  494. using namespace propagate_winding_numbers_helper;
  495. if (!winding_number_assignment_is_consistent(orders, orientations, patch_W)) {
  496. Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
  497. DerivedV::IsRowMajor> Vd(V.rows(), V.cols());
  498. for (size_t j=0; j<V.rows(); j++) {
  499. for (size_t k=0; k<V.cols(); k++) {
  500. igl::cgal::assign_scalar(V(j,k), Vd(j,k));
  501. }
  502. }
  503. //for (size_t j=0; j<num_faces; j++) {
  504. // std::cout << patch_W(P[j], 1) << std::endl;
  505. //}
  506. igl::writeOBJ("debug_wn.obj", Vd, F);
  507. assert(false);
  508. }
  509. return winding_number_assignment_is_consistent(orders, orientations, patch_W);
  510. }
  511. #endif
  512. template<
  513. typename DerivedV,
  514. typename DerivedF,
  515. typename DerivedC,
  516. typename DerivedW>
  517. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  518. const Eigen::PlainObjectBase<DerivedV>& V,
  519. const Eigen::PlainObjectBase<DerivedF>& F,
  520. const Eigen::PlainObjectBase<DerivedC>& labels,
  521. Eigen::PlainObjectBase<DerivedW>& W) {
  522. typedef typename DerivedF::Scalar Index;
  523. const size_t num_faces = F.rows();
  524. // Extract unique edges.
  525. std::vector<std::vector<size_t> > uE2E;
  526. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  527. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  528. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  529. // Extract manifold patches and intersection curves.
  530. Eigen::VectorXi P;
  531. std::vector<std::vector<size_t> > intersection_curves;
  532. size_t num_patches =
  533. igl::extract_manifold_patches(F, EMAP, uE2E, P);
  534. igl::extract_non_manifold_edge_curves(F, EMAP, uE2E,
  535. intersection_curves);
  536. assert(P.size() == num_faces);
  537. assert(P.maxCoeff() + 1 == num_patches);
  538. Eigen::VectorXi patch_labels(num_patches);
  539. const int INVALID = std::numeric_limits<int>::max();
  540. patch_labels.setConstant(INVALID);
  541. for (size_t i=0; i<num_faces; i++) {
  542. if (patch_labels[P[i]] == INVALID) {
  543. patch_labels[P[i]] = labels[i];
  544. } else {
  545. assert(patch_labels[P[i]] == labels[i]);
  546. }
  547. }
  548. assert((patch_labels.array() != INVALID).all());
  549. const size_t num_labels = patch_labels.maxCoeff()+1;
  550. Eigen::MatrixXi winding_numbers;
  551. bool is_consistent =
  552. igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  553. V, F, uE, uE2E, patch_labels, P, intersection_curves, winding_numbers);
  554. assert(winding_numbers.rows() == num_patches);
  555. assert(winding_numbers.cols() == 2 * num_labels);
  556. W.resize(num_faces, 2*num_labels);
  557. W.setConstant(INVALID);
  558. for (size_t i=0; i<num_faces; i++) {
  559. W.row(i) = winding_numbers.row(P[i]);
  560. }
  561. assert((W.array() != INVALID).any());
  562. return is_consistent;
  563. }
  564. template<
  565. typename DerivedV,
  566. typename DerivedF,
  567. typename DerivedW>
  568. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  569. const Eigen::PlainObjectBase<DerivedV>& V,
  570. const Eigen::PlainObjectBase<DerivedF>& F,
  571. Eigen::PlainObjectBase<DerivedW>& W) {
  572. const size_t num_faces = F.rows();
  573. Eigen::VectorXi labels(num_faces);
  574. labels.setZero();
  575. return igl::cgal::propagate_winding_numbers_single_component(V, F, labels, W);
  576. }
  577. template<
  578. typename DerivedV,
  579. typename DerivedF,
  580. typename DerivedL,
  581. typename DerivedW>
  582. IGL_INLINE void igl::cgal::propagate_winding_numbers(
  583. const Eigen::PlainObjectBase<DerivedV>& V,
  584. const Eigen::PlainObjectBase<DerivedF>& F,
  585. const Eigen::PlainObjectBase<DerivedL>& labels,
  586. Eigen::PlainObjectBase<DerivedW>& W) {
  587. typedef typename DerivedF::Scalar Index;
  588. const size_t num_faces = F.rows();
  589. // Extract unique edges.
  590. std::vector<std::vector<size_t> > uE2E;
  591. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  592. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  593. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  594. // Check to make sure there is no boundaries and no non-manifold edges with
  595. // odd number of adjacent faces.
  596. for (const auto& adj_faces : uE2E) {
  597. if (adj_faces.size() % 2 == 1) {
  598. std::stringstream err_msg;
  599. err_msg << "Input mesh contains odd number of faces "
  600. << "sharing a single edge" << std::endl;
  601. err_msg << "Indicating the input mesh does not represent a valid volume"
  602. << ", and winding number cannot be propagated." << std::endl;
  603. throw std::runtime_error(err_msg.str());
  604. }
  605. }
  606. // Gather connected components.
  607. std::vector<std::vector<std::vector<Index > > > TT,_1;
  608. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  609. Eigen::VectorXi counts;
  610. Eigen::VectorXi C;
  611. igl::facet_components(TT,C,counts);
  612. const size_t num_components = counts.size();
  613. std::vector<std::vector<size_t> > components(num_components);
  614. for (size_t i=0; i<num_faces; i++) {
  615. components[C[i]].push_back(i);
  616. }
  617. std::vector<Eigen::MatrixXi> comp_faces(num_components);
  618. std::vector<Eigen::VectorXi> comp_labels(num_components);
  619. for (size_t i=0; i<num_components; i++) {
  620. const auto& comp = components[i];
  621. auto& faces = comp_faces[i];
  622. auto& c_labels = comp_labels[i];
  623. const size_t comp_size = comp.size();
  624. faces.resize(comp_size, 3);
  625. c_labels.resize(comp_size);
  626. for (size_t j=0; j<comp_size; j++) {
  627. faces.row(j) = F.row(comp[j]);
  628. c_labels[j] = labels[comp[j]];
  629. }
  630. }
  631. // Compute winding number for each component.
  632. const size_t num_labels = labels.maxCoeff()+1;
  633. W.resize(num_faces, 2*num_labels);
  634. W.setZero();
  635. std::vector<Eigen::MatrixXi> Ws(num_components);
  636. for (size_t i=0; i<num_components; i++) {
  637. bool is_consistent =
  638. propagate_winding_numbers_single_component(V, comp_faces[i], comp_labels[i], Ws[i]);
  639. const size_t num_labels_in_i = comp_labels[i].maxCoeff()+1;
  640. const size_t num_faces_in_comp = comp_faces[i].rows();
  641. assert(Ws[i].cols() == num_labels_in_i*2);
  642. assert(Ws[i].rows() == num_faces_in_comp);
  643. const auto& comp = components[i];
  644. for (size_t j=0; j<num_faces_in_comp; j++) {
  645. const size_t fid = comp[j];
  646. W.block(fid, 0, 1, num_labels_in_i*2) = Ws[i].row(j);
  647. }
  648. if (!is_consistent) {
  649. Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
  650. DerivedV::IsRowMajor> Vd(V.rows(), V.cols());
  651. for (size_t j=0; j<V.rows(); j++) {
  652. for (size_t k=0; k<V.cols(); k++) {
  653. igl::cgal::assign_scalar(V(j,k), Vd(j,k));
  654. }
  655. }
  656. igl::writeOBJ("debug_wn.obj", Vd, comp_faces[i]);
  657. std::cout << Ws[i].col(1) << std::endl;
  658. std::stringstream err_msg;
  659. err_msg << "Component " << i
  660. << " has inconsistant winding number assignment." << std::endl;
  661. //throw std::runtime_error(err_msg.str());
  662. std::cout << err_msg.str() << std::endl;
  663. }
  664. }
  665. auto sample_component = [&](size_t cid) {
  666. const auto& f = comp_faces[cid].row(0).eval();
  667. return ((V.row(f[0]) + V.row(f[1]) + V.row(f[2])) / 3.0).eval();
  668. };
  669. std::vector<Eigen::MatrixXi> nested_Ws = Ws;
  670. Eigen::MatrixXi ambient_correction(num_components, 2*num_labels);
  671. ambient_correction.setZero();
  672. if (num_components > 1) {
  673. for (size_t i=0; i<num_components; i++) {
  674. DerivedV samples(num_components-1, 3);
  675. Eigen::VectorXi is_inside;
  676. auto index_without_i = [&](size_t index) {
  677. return index < i ? index:index-1;
  678. };
  679. for (size_t j=0; j<num_components; j++) {
  680. if (i == j) continue;
  681. samples.row(index_without_i(j)) = sample_component(j);
  682. }
  683. Eigen::VectorXi fids;
  684. Eigen::Matrix<bool, Eigen::Dynamic, 1> orientation;
  685. igl::cgal::closest_facet(V, comp_faces[i], samples,
  686. fids, orientation);
  687. const auto& comp = components[i];
  688. for (size_t j=0; j<num_components; j++) {
  689. if (i == j) continue;
  690. const size_t index = index_without_i(j);
  691. const size_t fid = fids(index, 0);
  692. const bool ori = orientation(index, 0);
  693. for (size_t k=0; k<num_labels; k++) {
  694. const int correction = W(comp[fid], k*2+(ori?0:1));
  695. ambient_correction(j, k*2 ) += correction;
  696. ambient_correction(j, k*2+1) += correction;
  697. }
  698. }
  699. }
  700. }
  701. for (size_t i=0; i<num_components; i++) {
  702. const auto& comp = components[i];
  703. const auto& correction = ambient_correction.row(i).eval();
  704. for (const auto& fid : comp) {
  705. W.row(fid) += correction;
  706. }
  707. }
  708. }