propagate_winding_numbers.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014
  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 "propagate_winding_numbers.h"
  10. #include "../extract_manifold_patches.h"
  11. #include "../extract_non_manifold_edge_curves.h"
  12. #include "../facet_components.h"
  13. #include "../unique_edge_map.h"
  14. #include "../writeOBJ.h"
  15. #include "../writePLY.h"
  16. #include "order_facets_around_edge.h"
  17. #include "outer_facet.h"
  18. #include "closest_facet.h"
  19. #include "assign_scalar.h"
  20. #include "extract_cells.h"
  21. #include <stdexcept>
  22. #include <limits>
  23. #include <vector>
  24. #include <tuple>
  25. #include <queue>
  26. namespace propagate_winding_numbers_helper {
  27. template<typename DerivedW >
  28. bool winding_number_assignment_is_consistent(
  29. const std::vector<Eigen::VectorXi>& orders,
  30. const std::vector<std::vector<bool> >& orientations,
  31. const Eigen::PlainObjectBase<DerivedW>& per_patch_winding_number) {
  32. const size_t num_edge_curves = orders.size();
  33. const size_t num_labels = per_patch_winding_number.cols() / 2;
  34. for (size_t i=0; i<num_edge_curves; i++) {
  35. const auto& order = orders[i];
  36. const auto& orientation = orientations[i];
  37. assert(order.size() == orientation.size());
  38. const size_t order_size = order.size();
  39. for (size_t j=0; j<order_size; j++) {
  40. const size_t curr = j;
  41. const size_t next = (j+1) % order_size;
  42. for (size_t k=0; k<num_labels; k++) {
  43. // Retrieve the winding numbers of the current partition from
  44. // the current patch and the next patch. If the patches forms
  45. // the boundary of a 3D volume, the winding number assignments
  46. // should be consistent.
  47. int curr_winding_number = per_patch_winding_number(
  48. order[curr], k*2+(orientation[curr]? 0:1));
  49. int next_winding_number = per_patch_winding_number(
  50. order[next], k*2+(orientation[next]? 1:0));
  51. if (curr_winding_number != next_winding_number) {
  52. std::cout << "edge: " << i << std::endl;
  53. std::cout << curr_winding_number << " != " <<
  54. next_winding_number << std::endl;
  55. return false;
  56. }
  57. }
  58. }
  59. }
  60. return true;
  61. }
  62. template<
  63. typename DerivedF,
  64. typename DeriveduE,
  65. typename uE2EType >
  66. bool is_orientable(
  67. const Eigen::PlainObjectBase<DerivedF>& F,
  68. const Eigen::PlainObjectBase<DeriveduE>& uE,
  69. const std::vector<std::vector<uE2EType> >& uE2E) {
  70. const size_t num_faces = F.rows();
  71. const size_t num_edges = uE.rows();
  72. auto edge_index_to_face_index = [&](size_t ei) {
  73. return ei % num_faces;
  74. };
  75. auto is_consistent = [&](size_t fid, size_t s, size_t d) {
  76. if (F(fid, 0) == s && F(fid, 1) == d) return true;
  77. if (F(fid, 1) == s && F(fid, 2) == d) return true;
  78. if (F(fid, 2) == s && F(fid, 0) == d) return true;
  79. if (F(fid, 0) == d && F(fid, 1) == s) return false;
  80. if (F(fid, 1) == d && F(fid, 2) == s) return false;
  81. if (F(fid, 2) == d && F(fid, 0) == s) return false;
  82. throw "Invalid face!!";
  83. };
  84. for (size_t i=0; i<num_edges; i++) {
  85. const size_t s = uE(i,0);
  86. const size_t d = uE(i,1);
  87. int count=0;
  88. for (const auto& ei : uE2E[i]) {
  89. const size_t fid = edge_index_to_face_index(ei);
  90. if (is_consistent(fid, s, d)) count++;
  91. else count--;
  92. }
  93. if (count != 0) {
  94. return false;
  95. }
  96. }
  97. return true;
  98. }
  99. }
  100. template<
  101. typename DerivedV,
  102. typename DerivedF,
  103. typename DeriveduE,
  104. typename uE2EType,
  105. typename DerivedC,
  106. typename DerivedP,
  107. typename DerivedW >
  108. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  109. const Eigen::PlainObjectBase<DerivedV>& V,
  110. const Eigen::PlainObjectBase<DerivedF>& F,
  111. const Eigen::PlainObjectBase<DeriveduE>& uE,
  112. const std::vector<std::vector<uE2EType> >& uE2E,
  113. const Eigen::PlainObjectBase<DerivedC>& labels,
  114. const Eigen::PlainObjectBase<DerivedP>& P,
  115. const std::vector<std::vector<size_t> >& intersection_curves,
  116. Eigen::PlainObjectBase<DerivedW>& patch_W) {
  117. const size_t num_faces = F.rows();
  118. const size_t num_patches = P.maxCoeff() + 1;
  119. assert(labels.size() == num_patches);
  120. // Utility functions.
  121. auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
  122. auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
  123. auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
  124. return ci*num_faces + fi;
  125. };
  126. auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
  127. const size_t fi = edge_index_to_face_index(ei);
  128. const size_t ci = edge_index_to_corner_index(ei);
  129. s = F(fi, (ci+1)%3);
  130. d = F(fi, (ci+2)%3);
  131. };
  132. auto is_positively_orientated =
  133. [&](size_t fi, size_t s, size_t d) -> bool{
  134. const Eigen::Vector3i f = F.row(fi);
  135. if (f[0] == d && f[1] == s) return true;
  136. if (f[1] == d && f[2] == s) return true;
  137. if (f[2] == d && f[0] == s) return true;
  138. if (f[0] == s && f[1] == d) return false;
  139. if (f[1] == s && f[2] == d) return false;
  140. if (f[2] == s && f[0] == d) return false;
  141. throw std::runtime_error("Edge does not belong to face.");
  142. return false;
  143. };
  144. auto compute_signed_index = [&](size_t fi, size_t s, size_t d) -> int{
  145. return int(fi+1) * (is_positively_orientated(fi, s, d) ? 1:-1);
  146. };
  147. auto compute_unsigned_index = [&](int signed_idx) -> size_t {
  148. return abs(signed_idx) - 1;
  149. };
  150. // Order patches around each intersection curve.
  151. const size_t num_edge_curves = intersection_curves.size();
  152. std::vector<Eigen::VectorXi> orders(num_edge_curves);
  153. std::vector<std::vector<bool> > orientations(num_edge_curves);
  154. std::vector<std::vector<size_t> > patch_curve_adjacency(num_patches);
  155. for (size_t i=0; i<num_edge_curves; i++) {
  156. const auto& curve = intersection_curves[i];
  157. const size_t uei = curve[0];
  158. size_t s = uE(uei, 0);
  159. size_t d = uE(uei, 1);
  160. std::vector<int> adj_faces;
  161. for (size_t ei : uE2E[uei]) {
  162. const size_t fi = edge_index_to_face_index(ei);
  163. const size_t signed_fi =
  164. compute_signed_index(fi, s, d);
  165. adj_faces.push_back(signed_fi);
  166. patch_curve_adjacency[P[fi]].push_back(i);
  167. }
  168. auto& order = orders[i];
  169. igl::cgal::order_facets_around_edge(
  170. V, F, s, d, adj_faces, order);
  171. assert(order.minCoeff() == 0);
  172. assert(order.maxCoeff() == adj_faces.size() - 1);
  173. auto& orientation = orientations[i];
  174. orientation.resize(order.size());
  175. std::transform(order.data(), order.data()+order.size(),
  176. orientation.begin(),
  177. [&](size_t index) { return adj_faces[index] > 0; });
  178. std::transform(order.data(), order.data()+order.size(),
  179. order.data(), [&](size_t index) {
  180. return P[compute_unsigned_index(adj_faces[index])];
  181. } );
  182. }
  183. // Propagate winding number from infinity.
  184. // Assuming infinity has winding number 0.
  185. const size_t num_labels = labels.maxCoeff() + 1;
  186. const int INVALID = std::numeric_limits<int>::max();
  187. patch_W.resize(num_patches, 2*num_labels);
  188. patch_W.setConstant(INVALID);
  189. size_t outer_facet_idx;
  190. bool outer_facet_is_flipped;
  191. Eigen::VectorXi face_indices(num_faces);
  192. face_indices.setLinSpaced(num_faces, 0, num_faces-1);
  193. igl::cgal::outer_facet(V, F, face_indices,
  194. outer_facet_idx, outer_facet_is_flipped);
  195. size_t outer_patch_idx = P[outer_facet_idx];
  196. size_t outer_patch_label = labels[outer_patch_idx];
  197. patch_W.row(outer_patch_idx).setZero();
  198. if (outer_facet_is_flipped) {
  199. patch_W(outer_patch_idx, outer_patch_label*2) = -1;
  200. } else {
  201. patch_W(outer_patch_idx, outer_patch_label*2+1) = 1;
  202. }
  203. auto winding_num_assigned = [&](size_t patch_idx) -> bool{
  204. return (patch_W.row(patch_idx).array() != INVALID).all();
  205. };
  206. std::queue<size_t> Q;
  207. Q.push(outer_patch_idx);
  208. while (!Q.empty()) {
  209. const size_t curr_patch_idx = Q.front();
  210. const size_t curr_patch_label = labels[curr_patch_idx];
  211. Q.pop();
  212. const auto& adj_curves = patch_curve_adjacency[curr_patch_idx];
  213. for (size_t curve_idx : adj_curves) {
  214. const auto& order = orders[curve_idx];
  215. const auto& orientation = orientations[curve_idx];
  216. const size_t num_adj_patches = order.size();
  217. assert(num_adj_patches == orientation.size());
  218. size_t curr_i = std::numeric_limits<size_t>::max();
  219. for (size_t i=0; i<num_adj_patches; i++) {
  220. if (order[i] == curr_patch_idx) {
  221. curr_i = i;
  222. break;
  223. }
  224. }
  225. assert(curr_i < num_adj_patches);
  226. const bool curr_ori = orientation[curr_i];
  227. //for (size_t i=0; i<num_adj_patches; i++) {
  228. // const size_t next_i = (curr_i + 1) % num_adj_patches;
  229. // const size_t num_patch_idx = order[next_i];
  230. // const bool next_ori = orientation[next_i];
  231. // const size_t next_patch_label = labels[next_patch_idx];
  232. // // TODO
  233. //}
  234. const size_t next_i = curr_ori ? (curr_i+1) % num_adj_patches
  235. : (curr_i+num_adj_patches-1)%num_adj_patches;
  236. const size_t prev_i = curr_ori ?
  237. (curr_i+num_adj_patches-1)%num_adj_patches
  238. : (curr_i+1) % num_adj_patches;
  239. const size_t next_patch_idx = order[next_i];
  240. const size_t prev_patch_idx = order[prev_i];
  241. if (!winding_num_assigned(next_patch_idx)) {
  242. const bool next_ori = orientation[next_i];
  243. const bool next_cons = next_ori != curr_ori;
  244. const size_t next_patch_label = labels[next_patch_idx];
  245. for (size_t i=0; i<num_labels; i++) {
  246. const int shared_winding_number =
  247. patch_W(curr_patch_idx, i*2);
  248. if (i == next_patch_label) {
  249. // Truth table:
  250. // curr_ori next_ori wind_# inc
  251. // True True -1
  252. // True False 1
  253. // False True 1
  254. // False False -1
  255. patch_W(next_patch_idx, i*2+(next_cons ?0:1)) =
  256. shared_winding_number;
  257. patch_W(next_patch_idx, i*2+(next_cons ?1:0)) =
  258. shared_winding_number + (next_cons ? 1:-1);
  259. } else {
  260. patch_W(next_patch_idx, i*2 ) = shared_winding_number;
  261. patch_W(next_patch_idx, i*2+1) = shared_winding_number;
  262. }
  263. }
  264. Q.push(next_patch_idx);
  265. }
  266. if (!winding_num_assigned(prev_patch_idx)) {
  267. const bool prev_ori = orientation[prev_i];
  268. const bool prev_cons = prev_ori != curr_ori;
  269. const size_t prev_patch_label = labels[prev_patch_idx];
  270. for (size_t i=0; i<num_labels; i++) {
  271. const int shared_winding_number =
  272. patch_W(curr_patch_idx, i*2+1);
  273. if (i == prev_patch_label) {
  274. // Truth table:
  275. // curr_ori next_ori wind_# inc
  276. // True True 1
  277. // True False -1
  278. // False True -1
  279. // False False 1
  280. patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) =
  281. shared_winding_number;
  282. patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) =
  283. shared_winding_number + (prev_cons ? -1:1);
  284. } else {
  285. patch_W(prev_patch_idx, i*2 ) = shared_winding_number;
  286. patch_W(prev_patch_idx, i*2+1) = shared_winding_number;
  287. }
  288. }
  289. Q.push(prev_patch_idx);
  290. }
  291. }
  292. }
  293. assert((patch_W.array() != INVALID).all());
  294. using namespace propagate_winding_numbers_helper;
  295. return winding_number_assignment_is_consistent(orders, orientations, patch_W);
  296. }
  297. #if 0
  298. template<
  299. typename DerivedV,
  300. typename DerivedF,
  301. typename DeriveduE,
  302. typename uE2EType,
  303. typename DerivedEMAP,
  304. typename DerivedC,
  305. typename DerivedP,
  306. typename DerivedW >
  307. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  308. const Eigen::PlainObjectBase<DerivedV>& V,
  309. const Eigen::PlainObjectBase<DerivedF>& F,
  310. const Eigen::PlainObjectBase<DeriveduE>& uE,
  311. const std::vector<std::vector<uE2EType> >& uE2E,
  312. const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
  313. const Eigen::PlainObjectBase<DerivedC>& labels,
  314. const Eigen::PlainObjectBase<DerivedP>& P,
  315. Eigen::PlainObjectBase<DerivedW>& patch_W) {
  316. const size_t num_faces = F.rows();
  317. const size_t num_patches = P.maxCoeff() + 1;
  318. assert(labels.size() == num_patches);
  319. // Utility functions.
  320. auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
  321. auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
  322. auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
  323. return ci*num_faces + fi;
  324. };
  325. auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
  326. const size_t fi = edge_index_to_face_index(ei);
  327. const size_t ci = edge_index_to_corner_index(ei);
  328. s = F(fi, (ci+1)%3);
  329. d = F(fi, (ci+2)%3);
  330. };
  331. auto is_positively_orientated =
  332. [&](size_t fi, size_t s, size_t d) -> bool{
  333. const Eigen::Vector3i f = F.row(fi);
  334. if (f[0] == d && f[1] == s) return true;
  335. if (f[1] == d && f[2] == s) return true;
  336. if (f[2] == d && f[0] == s) return true;
  337. if (f[0] == s && f[1] == d) return false;
  338. if (f[1] == s && f[2] == d) return false;
  339. if (f[2] == s && f[0] == d) return false;
  340. throw std::runtime_error("Edge does not belong to face.");
  341. return false;
  342. };
  343. auto compute_signed_index = [&](size_t fi, size_t s, size_t d) -> int{
  344. return int(fi+1) * (is_positively_orientated(fi, s, d) ? 1:-1);
  345. };
  346. auto compute_unsigned_index = [&](int signed_idx) -> size_t {
  347. return abs(signed_idx) - 1;
  348. };
  349. // Order patches around each non-manifold edge.
  350. const size_t num_edges = uE.rows();
  351. std::vector<Eigen::VectorXi> orders(num_edges);
  352. std::vector<std::vector<bool> > orientations(num_edges);
  353. std::vector<std::vector<size_t> > patch_edge_adjacency(num_patches);
  354. for (size_t uei=0; uei<num_edges; uei++) {
  355. const auto& edges = uE2E[uei];
  356. if (edges.size() <= 2) continue;
  357. size_t s = uE(uei, 0);
  358. size_t d = uE(uei, 1);
  359. std::vector<int> adj_faces;
  360. for (size_t ei : uE2E[uei]) {
  361. const size_t fi = edge_index_to_face_index(ei);
  362. const size_t signed_fi =
  363. compute_signed_index(fi, s, d);
  364. adj_faces.push_back(signed_fi);
  365. patch_edge_adjacency[P[fi]].push_back(ei);
  366. }
  367. auto& order = orders[uei];
  368. igl::cgal::order_facets_around_edge(
  369. V, F, s, d, adj_faces, order);
  370. assert(order.minCoeff() == 0);
  371. assert(order.maxCoeff() == adj_faces.size() - 1);
  372. auto& orientation = orientations[uei];
  373. orientation.resize(order.size());
  374. std::transform(order.data(), order.data()+order.size(),
  375. orientation.begin(),
  376. [&](size_t index) { return adj_faces[index] > 0; });
  377. std::transform(order.data(), order.data()+order.size(),
  378. order.data(), [&](size_t index) {
  379. return compute_unsigned_index(adj_faces[index]);
  380. } );
  381. }
  382. // Propagate winding number from infinity.
  383. // Assuming infinity has winding number 0.
  384. const size_t num_labels = labels.maxCoeff() + 1;
  385. const int INVALID = std::numeric_limits<int>::max();
  386. patch_W.resize(num_patches, 2*num_labels);
  387. patch_W.setConstant(INVALID);
  388. size_t outer_facet_idx;
  389. bool outer_facet_is_flipped;
  390. Eigen::VectorXi face_indices(num_faces);
  391. face_indices.setLinSpaced(num_faces, 0, num_faces-1);
  392. igl::cgal::outer_facet(V, F, face_indices,
  393. outer_facet_idx, outer_facet_is_flipped);
  394. size_t outer_patch_idx = P[outer_facet_idx];
  395. size_t outer_patch_label = labels[outer_patch_idx];
  396. patch_W.row(outer_patch_idx).setZero();
  397. if (outer_facet_is_flipped) {
  398. patch_W(outer_patch_idx, outer_patch_label*2) = -1;
  399. } else {
  400. patch_W(outer_patch_idx, outer_patch_label*2+1) = 1;
  401. }
  402. auto winding_num_assigned = [&](size_t patch_idx) -> bool{
  403. return (patch_W.row(patch_idx).array() != INVALID).all();
  404. };
  405. std::queue<size_t> Q;
  406. Q.push(outer_patch_idx);
  407. while (!Q.empty()) {
  408. const size_t curr_patch_idx = Q.front();
  409. const size_t curr_patch_label = labels[curr_patch_idx];
  410. Q.pop();
  411. const auto& adj_edges = patch_edge_adjacency[curr_patch_idx];
  412. for (size_t ei: adj_edges) {
  413. const size_t uei = EMAP[ei];
  414. const size_t fid = edge_index_to_face_index(ei);
  415. const auto& order = orders[uei];
  416. const auto& orientation = orientations[uei];
  417. const size_t num_adj_patches = order.size();
  418. assert(num_adj_patches == orientation.size());
  419. size_t curr_i = std::numeric_limits<size_t>::max();
  420. for (size_t i=0; i<num_adj_patches; i++) {
  421. std::cout << (orientation[i]?"+":"-") << order[i] << " ";
  422. }
  423. std::cout << std::endl;
  424. for (size_t i=0; i<num_adj_patches; i++) {
  425. if (order[i] == fid) {
  426. curr_i = i;
  427. break;
  428. }
  429. }
  430. assert(curr_i < num_adj_patches);
  431. const bool curr_ori = orientation[curr_i];
  432. const size_t next_i = curr_ori ? (curr_i+1) % num_adj_patches
  433. : (curr_i+num_adj_patches-1)%num_adj_patches;
  434. const size_t prev_i = curr_ori ?
  435. (curr_i+num_adj_patches-1)%num_adj_patches
  436. : (curr_i+1) % num_adj_patches;
  437. const size_t next_patch_idx = P[order[next_i]];
  438. const size_t prev_patch_idx = P[order[prev_i]];
  439. if (!winding_num_assigned(next_patch_idx)) {
  440. const bool next_ori = orientation[next_i];
  441. const bool next_cons = next_ori != curr_ori;
  442. const size_t next_patch_label = labels[next_patch_idx];
  443. for (size_t i=0; i<num_labels; i++) {
  444. const int shared_winding_number =
  445. patch_W(curr_patch_idx, i*2);
  446. if (i == next_patch_label) {
  447. // Truth table:
  448. // curr_ori next_ori wind_# inc
  449. // True True -1
  450. // True False 1
  451. // False True 1
  452. // False False -1
  453. patch_W(next_patch_idx, i*2+(next_cons ?0:1)) =
  454. shared_winding_number;
  455. patch_W(next_patch_idx, i*2+(next_cons ?1:0)) =
  456. shared_winding_number + (next_cons ? 1:-1);
  457. } else {
  458. patch_W(next_patch_idx, i*2 ) = shared_winding_number;
  459. patch_W(next_patch_idx, i*2+1) = shared_winding_number;
  460. }
  461. }
  462. Q.push(next_patch_idx);
  463. } else {
  464. const bool next_ori = orientation[next_i];
  465. const bool next_cons = next_ori != curr_ori;
  466. const size_t next_patch_label = labels[next_patch_idx];
  467. for (size_t i=0; i<num_labels; i++) {
  468. const int shared_winding_number =
  469. patch_W(curr_patch_idx, i*2);
  470. if (i == next_patch_label) {
  471. // Truth table:
  472. // curr_ori next_ori wind_# inc
  473. // True True -1
  474. // True False 1
  475. // False True 1
  476. // False False -1
  477. assert(patch_W(next_patch_idx, i*2+(next_cons ?0:1)) ==
  478. shared_winding_number);
  479. assert(patch_W(next_patch_idx, i*2+(next_cons ?1:0)) ==
  480. shared_winding_number + (next_cons ? 1:-1));
  481. } else {
  482. assert(patch_W(next_patch_idx, i*2) ==
  483. shared_winding_number);
  484. assert(patch_W(next_patch_idx, i*2+1) ==
  485. shared_winding_number);
  486. }
  487. }
  488. }
  489. if (!winding_num_assigned(prev_patch_idx)) {
  490. const bool prev_ori = orientation[prev_i];
  491. const bool prev_cons = prev_ori != curr_ori;
  492. const size_t prev_patch_label = labels[prev_patch_idx];
  493. for (size_t i=0; i<num_labels; i++) {
  494. const int shared_winding_number =
  495. patch_W(curr_patch_idx, i*2+1);
  496. if (i == prev_patch_label) {
  497. // Truth table:
  498. // curr_ori next_ori wind_# inc
  499. // True True 1
  500. // True False -1
  501. // False True -1
  502. // False False 1
  503. patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) =
  504. shared_winding_number;
  505. patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) =
  506. shared_winding_number + (prev_cons ? -1:1);
  507. } else {
  508. patch_W(prev_patch_idx, i*2 ) = shared_winding_number;
  509. patch_W(prev_patch_idx, i*2+1) = shared_winding_number;
  510. }
  511. }
  512. Q.push(prev_patch_idx);
  513. } else {
  514. const bool prev_ori = orientation[prev_i];
  515. const bool prev_cons = prev_ori != curr_ori;
  516. const size_t prev_patch_label = labels[prev_patch_idx];
  517. for (size_t i=0; i<num_labels; i++) {
  518. const int shared_winding_number =
  519. patch_W(curr_patch_idx, i*2+1);
  520. if (i == prev_patch_label) {
  521. // Truth table:
  522. // curr_ori next_ori wind_# inc
  523. // True True 1
  524. // True False -1
  525. // False True -1
  526. // False False 1
  527. assert(patch_W(prev_patch_idx, i*2+(prev_cons ?1:0)) ==
  528. shared_winding_number);
  529. assert(patch_W(prev_patch_idx, i*2+(prev_cons ?0:1)) ==
  530. shared_winding_number + (prev_cons ? -1:1));
  531. } else {
  532. assert(patch_W(prev_patch_idx, i*2 ) ==
  533. shared_winding_number);
  534. assert(patch_W(prev_patch_idx, i*2+1) ==
  535. shared_winding_number);
  536. }
  537. }
  538. }
  539. }
  540. }
  541. assert((patch_W.array() != INVALID).all());
  542. using namespace propagate_winding_numbers_helper;
  543. if (!winding_number_assignment_is_consistent(orders, orientations, patch_W)) {
  544. Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
  545. DerivedV::IsRowMajor> Vd(V.rows(), V.cols());
  546. for (size_t j=0; j<V.rows(); j++) {
  547. for (size_t k=0; k<V.cols(); k++) {
  548. igl::cgal::assign_scalar(V(j,k), Vd(j,k));
  549. }
  550. }
  551. //for (size_t j=0; j<num_faces; j++) {
  552. // std::cout << patch_W(P[j], 1) << std::endl;
  553. //}
  554. igl::writeOBJ("debug_wn.obj", Vd, F);
  555. assert(false);
  556. }
  557. return winding_number_assignment_is_consistent(orders, orientations, patch_W);
  558. }
  559. #endif
  560. template<
  561. typename DerivedV,
  562. typename DerivedF,
  563. typename DerivedC,
  564. typename DerivedW>
  565. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  566. const Eigen::PlainObjectBase<DerivedV>& V,
  567. const Eigen::PlainObjectBase<DerivedF>& F,
  568. const Eigen::PlainObjectBase<DerivedC>& labels,
  569. Eigen::PlainObjectBase<DerivedW>& W) {
  570. typedef typename DerivedF::Scalar Index;
  571. const size_t num_faces = F.rows();
  572. // Extract unique edges.
  573. std::vector<std::vector<size_t> > uE2E;
  574. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  575. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  576. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  577. // Extract manifold patches and intersection curves.
  578. Eigen::VectorXi P;
  579. std::vector<std::vector<size_t> > intersection_curves;
  580. size_t num_patches =
  581. igl::extract_manifold_patches(F, EMAP, uE2E, P);
  582. igl::extract_non_manifold_edge_curves(F, EMAP, uE2E,
  583. intersection_curves);
  584. assert(P.size() == num_faces);
  585. assert(P.maxCoeff() + 1 == num_patches);
  586. Eigen::VectorXi patch_labels(num_patches);
  587. const int INVALID = std::numeric_limits<int>::max();
  588. patch_labels.setConstant(INVALID);
  589. for (size_t i=0; i<num_faces; i++) {
  590. if (patch_labels[P[i]] == INVALID) {
  591. patch_labels[P[i]] = labels[i];
  592. } else {
  593. assert(patch_labels[P[i]] == labels[i]);
  594. }
  595. }
  596. assert((patch_labels.array() != INVALID).all());
  597. const size_t num_labels = patch_labels.maxCoeff()+1;
  598. Eigen::MatrixXi winding_numbers;
  599. bool is_consistent =
  600. igl::cgal::propagate_winding_numbers_single_component_patch_wise(
  601. V, F, uE, uE2E, patch_labels, P, intersection_curves, winding_numbers);
  602. assert(winding_numbers.rows() == num_patches);
  603. assert(winding_numbers.cols() == 2 * num_labels);
  604. W.resize(num_faces, 2*num_labels);
  605. W.setConstant(INVALID);
  606. for (size_t i=0; i<num_faces; i++) {
  607. W.row(i) = winding_numbers.row(P[i]);
  608. }
  609. assert((W.array() != INVALID).any());
  610. return is_consistent;
  611. }
  612. template<
  613. typename DerivedV,
  614. typename DerivedF,
  615. typename DerivedW>
  616. IGL_INLINE bool igl::cgal::propagate_winding_numbers_single_component(
  617. const Eigen::PlainObjectBase<DerivedV>& V,
  618. const Eigen::PlainObjectBase<DerivedF>& F,
  619. Eigen::PlainObjectBase<DerivedW>& W) {
  620. const size_t num_faces = F.rows();
  621. Eigen::VectorXi labels(num_faces);
  622. labels.setZero();
  623. return igl::cgal::propagate_winding_numbers_single_component(V, F, labels, W);
  624. }
  625. template<
  626. typename DerivedV,
  627. typename DerivedF,
  628. typename DerivedL,
  629. typename DerivedW>
  630. IGL_INLINE void igl::cgal::propagate_winding_numbers(
  631. const Eigen::PlainObjectBase<DerivedV>& V,
  632. const Eigen::PlainObjectBase<DerivedF>& F,
  633. const Eigen::PlainObjectBase<DerivedL>& labels,
  634. Eigen::PlainObjectBase<DerivedW>& W) {
  635. typedef typename DerivedF::Scalar Index;
  636. const size_t num_faces = F.rows();
  637. // Extract unique edges.
  638. std::vector<std::vector<size_t> > uE2E;
  639. Eigen::Matrix<Index, Eigen::Dynamic, Eigen::Dynamic> E, uE;
  640. Eigen::Matrix<Index, Eigen::Dynamic, 1> EMAP;
  641. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  642. // Check to make sure there is no boundaries and no non-manifold edges with
  643. // odd number of adjacent faces.
  644. for (const auto& adj_faces : uE2E) {
  645. if (adj_faces.size() % 2 == 1) {
  646. std::stringstream err_msg;
  647. err_msg << "Input mesh contains odd number of faces "
  648. << "sharing a single edge" << std::endl;
  649. err_msg << "Indicating the input mesh does not represent a valid volume"
  650. << ", and winding number cannot be propagated." << std::endl;
  651. throw std::runtime_error(err_msg.str());
  652. }
  653. }
  654. // Gather connected components.
  655. std::vector<std::vector<std::vector<Index > > > TT,_1;
  656. triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
  657. Eigen::VectorXi counts;
  658. Eigen::VectorXi C;
  659. igl::facet_components(TT,C,counts);
  660. const size_t num_components = counts.size();
  661. std::vector<std::vector<size_t> > components(num_components);
  662. for (size_t i=0; i<num_faces; i++) {
  663. components[C[i]].push_back(i);
  664. }
  665. std::vector<Eigen::MatrixXi> comp_faces(num_components);
  666. std::vector<Eigen::VectorXi> comp_labels(num_components);
  667. for (size_t i=0; i<num_components; i++) {
  668. const auto& comp = components[i];
  669. auto& faces = comp_faces[i];
  670. auto& c_labels = comp_labels[i];
  671. const size_t comp_size = comp.size();
  672. faces.resize(comp_size, 3);
  673. c_labels.resize(comp_size);
  674. for (size_t j=0; j<comp_size; j++) {
  675. faces.row(j) = F.row(comp[j]);
  676. c_labels[j] = labels[comp[j]];
  677. }
  678. }
  679. // Compute winding number for each component.
  680. const size_t num_labels = labels.maxCoeff()+1;
  681. W.resize(num_faces, 2*num_labels);
  682. W.setZero();
  683. std::vector<Eigen::MatrixXi> Ws(num_components);
  684. for (size_t i=0; i<num_components; i++) {
  685. bool is_consistent =
  686. propagate_winding_numbers_single_component(V, comp_faces[i], comp_labels[i], Ws[i]);
  687. const size_t num_labels_in_i = comp_labels[i].maxCoeff()+1;
  688. const size_t num_faces_in_comp = comp_faces[i].rows();
  689. assert(Ws[i].cols() == num_labels_in_i*2);
  690. assert(Ws[i].rows() == num_faces_in_comp);
  691. const auto& comp = components[i];
  692. for (size_t j=0; j<num_faces_in_comp; j++) {
  693. const size_t fid = comp[j];
  694. W.block(fid, 0, 1, num_labels_in_i*2) = Ws[i].row(j);
  695. }
  696. if (!is_consistent) {
  697. Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic,
  698. DerivedV::IsRowMajor> Vd(V.rows(), V.cols());
  699. for (size_t j=0; j<V.rows(); j++) {
  700. for (size_t k=0; k<V.cols(); k++) {
  701. igl::cgal::assign_scalar(V(j,k), Vd(j,k));
  702. }
  703. }
  704. igl::writeOBJ("debug_wn.obj", Vd, comp_faces[i]);
  705. std::cout << Ws[i].col(1) << std::endl;
  706. std::stringstream err_msg;
  707. err_msg << "Component " << i
  708. << " has inconsistant winding number assignment." << std::endl;
  709. //throw std::runtime_error(err_msg.str());
  710. std::cout << err_msg.str() << std::endl;
  711. }
  712. }
  713. auto sample_component = [&](size_t cid) {
  714. const auto& f = comp_faces[cid].row(0).eval();
  715. return ((V.row(f[0]) + V.row(f[1]) + V.row(f[2])) / 3.0).eval();
  716. };
  717. std::vector<Eigen::MatrixXi> nested_Ws = Ws;
  718. Eigen::MatrixXi ambient_correction(num_components, 2*num_labels);
  719. ambient_correction.setZero();
  720. if (num_components > 1) {
  721. for (size_t i=0; i<num_components; i++) {
  722. DerivedV samples(num_components-1, 3);
  723. Eigen::VectorXi is_inside;
  724. auto index_without_i = [&](size_t index) {
  725. return index < i ? index:index-1;
  726. };
  727. for (size_t j=0; j<num_components; j++) {
  728. if (i == j) continue;
  729. samples.row(index_without_i(j)) = sample_component(j);
  730. }
  731. Eigen::VectorXi fids;
  732. Eigen::Matrix<bool, Eigen::Dynamic, 1> orientation;
  733. igl::cgal::closest_facet(V, comp_faces[i], samples,
  734. fids, orientation);
  735. const auto& comp = components[i];
  736. for (size_t j=0; j<num_components; j++) {
  737. if (i == j) continue;
  738. const size_t index = index_without_i(j);
  739. const size_t fid = fids(index, 0);
  740. const bool ori = orientation(index, 0);
  741. for (size_t k=0; k<num_labels; k++) {
  742. const int correction = W(comp[fid], k*2+(ori?0:1));
  743. ambient_correction(j, k*2 ) += correction;
  744. ambient_correction(j, k*2+1) += correction;
  745. }
  746. }
  747. }
  748. }
  749. for (size_t i=0; i<num_components; i++) {
  750. const auto& comp = components[i];
  751. const auto& correction = ambient_correction.row(i).eval();
  752. for (const auto& fid : comp) {
  753. W.row(fid) += correction;
  754. }
  755. }
  756. }
  757. template<
  758. typename DerivedV,
  759. typename DerivedF,
  760. typename DerivedL,
  761. typename DerivedW>
  762. IGL_INLINE void igl::cgal::propagate_winding_numbers_beta(
  763. const Eigen::PlainObjectBase<DerivedV>& V,
  764. const Eigen::PlainObjectBase<DerivedF>& F,
  765. const Eigen::PlainObjectBase<DerivedL>& labels,
  766. Eigen::PlainObjectBase<DerivedW>& W) {
  767. const size_t num_faces = F.rows();
  768. typedef typename DerivedF::Scalar Index;
  769. Eigen::MatrixXi E, uE;
  770. Eigen::VectorXi EMAP;
  771. std::vector<std::vector<size_t> > uE2E;
  772. igl::unique_edge_map(F, E, uE, EMAP, uE2E);
  773. assert(propagate_winding_numbers_helper::is_orientable(F, uE, uE2E));
  774. Eigen::VectorXi P;
  775. const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
  776. DerivedW per_patch_cells;
  777. const size_t num_cells =
  778. igl::cgal::extract_cells(V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
  779. typedef std::tuple<size_t, bool, size_t> CellConnection;
  780. std::vector<std::set<CellConnection> > cell_adjacency(num_cells);
  781. for (size_t i=0; i<num_patches; i++) {
  782. const int positive_cell = per_patch_cells(i,0);
  783. const int negative_cell = per_patch_cells(i,1);
  784. cell_adjacency[positive_cell].emplace(negative_cell, false, i);
  785. cell_adjacency[negative_cell].emplace(positive_cell, true, i);
  786. }
  787. auto save_cell = [&](const std::string& filename, size_t cell_id) {
  788. std::vector<size_t> faces;
  789. for (size_t i=0; i<num_patches; i++) {
  790. if ((per_patch_cells.row(i).array() == cell_id).any()) {
  791. for (size_t j=0; j<num_faces; j++) {
  792. if (P[j] == i) {
  793. faces.push_back(j);
  794. }
  795. }
  796. }
  797. }
  798. Eigen::MatrixXi cell_faces(faces.size(), 3);
  799. for (size_t i=0; i<faces.size(); i++) {
  800. cell_faces.row(i) = F.row(faces[i]);
  801. }
  802. Eigen::MatrixXd vertices(V.rows(), 3);
  803. for (size_t i=0; i<V.rows(); i++) {
  804. assign_scalar(V(i,0), vertices(i,0));
  805. assign_scalar(V(i,1), vertices(i,1));
  806. assign_scalar(V(i,2), vertices(i,2));
  807. }
  808. writePLY(filename, vertices, cell_faces);
  809. };
  810. {
  811. // Check for odd cycle.
  812. Eigen::VectorXi cell_labels(num_cells);
  813. cell_labels.setZero();
  814. Eigen::VectorXi parents(num_cells);
  815. parents.setConstant(-1);
  816. auto trace_parents = [&](size_t idx) {
  817. std::list<size_t> path;
  818. path.push_back(idx);
  819. while (parents[path.back()] != path.back()) {
  820. path.push_back(parents[path.back()]);
  821. }
  822. return path;
  823. };
  824. for (size_t i=0; i<num_cells; i++) {
  825. if (cell_labels[i] == 0) {
  826. cell_labels[i] = 1;
  827. std::queue<size_t> Q;
  828. Q.push(i);
  829. parents[i] = i;
  830. while (!Q.empty()) {
  831. size_t curr_idx = Q.front();
  832. Q.pop();
  833. int curr_label = cell_labels[curr_idx];
  834. for (const auto& neighbor : cell_adjacency[curr_idx]) {
  835. if (cell_labels[std::get<0>(neighbor)] == 0) {
  836. cell_labels[std::get<0>(neighbor)] = curr_label * -1;
  837. Q.push(std::get<0>(neighbor));
  838. parents[std::get<0>(neighbor)] = curr_idx;
  839. } else {
  840. if (cell_labels[std::get<0>(neighbor)] !=
  841. curr_label * -1) {
  842. std::cerr << "Odd cell cycle detected!" << std::endl;
  843. auto path = trace_parents(curr_idx);
  844. path.reverse();
  845. auto path2 = trace_parents(std::get<0>(neighbor));
  846. path.insert(path.end(),
  847. path2.begin(), path2.end());
  848. for (auto cell_id : path) {
  849. std::cout << cell_id << " ";
  850. std::stringstream filename;
  851. filename << "cell_" << cell_id << ".ply";
  852. save_cell(filename.str(), cell_id);
  853. }
  854. std::cout << std::endl;
  855. }
  856. assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1);
  857. }
  858. }
  859. }
  860. }
  861. }
  862. }
  863. size_t outer_facet;
  864. bool flipped;
  865. Eigen::VectorXi I;
  866. I.setLinSpaced(num_faces, 0, num_faces-1);
  867. igl::cgal::outer_facet(V, F, I, outer_facet, flipped);
  868. const size_t outer_patch = P[outer_facet];
  869. const size_t infinity_cell = per_patch_cells(outer_patch, flipped?1:0);
  870. Eigen::VectorXi patch_labels(num_patches);
  871. const int INVALID = std::numeric_limits<int>::max();
  872. patch_labels.setConstant(INVALID);
  873. for (size_t i=0; i<num_faces; i++) {
  874. if (patch_labels[P[i]] == INVALID) {
  875. patch_labels[P[i]] = labels[i];
  876. } else {
  877. assert(patch_labels[P[i]] == labels[i]);
  878. }
  879. }
  880. assert((patch_labels.array() != INVALID).all());
  881. const size_t num_labels = patch_labels.maxCoeff()+1;
  882. Eigen::MatrixXi per_cell_W(num_cells, num_labels);
  883. per_cell_W.setConstant(INVALID);
  884. per_cell_W.row(infinity_cell).setZero();
  885. std::queue<size_t> Q;
  886. Q.push(infinity_cell);
  887. while (!Q.empty()) {
  888. size_t curr_cell = Q.front();
  889. Q.pop();
  890. for (const auto& neighbor : cell_adjacency[curr_cell]) {
  891. size_t neighbor_cell, patch_idx;
  892. bool direction;
  893. std::tie(neighbor_cell, direction, patch_idx) = neighbor;
  894. if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) {
  895. per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell);
  896. for (size_t i=0; i<num_labels; i++) {
  897. int inc = (patch_labels[patch_idx] == i) ?
  898. (direction ? -1:1) :0;
  899. per_cell_W(neighbor_cell, i) =
  900. per_cell_W(curr_cell, i) + inc;
  901. }
  902. Q.push(neighbor_cell);
  903. } else {
  904. for (size_t i=0; i<num_labels; i++) {
  905. if (i == patch_labels[patch_idx]) {
  906. int inc = direction ? -1:1;
  907. assert(per_cell_W(neighbor_cell, i) ==
  908. per_cell_W(curr_cell, i) + inc);
  909. } else {
  910. assert(per_cell_W(neighbor_cell, i) ==
  911. per_cell_W(curr_cell, i));
  912. }
  913. }
  914. }
  915. }
  916. }
  917. W.resize(num_faces, num_labels*2);
  918. for (size_t i=0; i<num_faces; i++) {
  919. const size_t patch = P[i];
  920. const size_t positive_cell = per_patch_cells(patch, 0);
  921. const size_t negative_cell = per_patch_cells(patch, 1);
  922. for (size_t j=0; j<num_labels; j++) {
  923. W(i,j*2 ) = per_cell_W(positive_cell, j);
  924. W(i,j*2+1) = per_cell_W(negative_cell, j);
  925. }
  926. }
  927. //for (size_t i=0; i<num_cells; i++) {
  928. // std::stringstream filename;
  929. // filename << "cell_" << i << "_w_" << per_cell_W(i, 1) << ".ply";
  930. // save_cell(filename.str(), i);
  931. //}
  932. }