propagate_winding_numbers.cpp 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  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. {
  788. auto save_cell = [&](const std::string& filename, size_t cell_id) {
  789. std::vector<size_t> faces;
  790. for (size_t i=0; i<num_patches; i++) {
  791. if ((per_patch_cells.row(i).array() == cell_id).any()) {
  792. for (size_t j=0; j<num_faces; j++) {
  793. if (P[j] == i) {
  794. faces.push_back(j);
  795. }
  796. }
  797. }
  798. }
  799. Eigen::MatrixXi cell_faces(faces.size(), 3);
  800. for (size_t i=0; i<faces.size(); i++) {
  801. cell_faces.row(i) = F.row(faces[i]);
  802. }
  803. Eigen::MatrixXd vertices(V.rows(), 3);
  804. for (size_t i=0; i<V.rows(); i++) {
  805. assign_scalar(V(i,0), vertices(i,0));
  806. assign_scalar(V(i,1), vertices(i,1));
  807. assign_scalar(V(i,2), vertices(i,2));
  808. }
  809. writePLY(filename, vertices, cell_faces);
  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. } else {
  903. for (size_t i=0; i<num_labels; i++) {
  904. if (i == patch_labels[patch_idx]) {
  905. int inc = direction ? -1:1;
  906. assert(per_cell_W(neighbor_cell, i) ==
  907. per_cell_W(curr_cell, i) + inc);
  908. } else {
  909. assert(per_cell_W(neighbor_cell, i) ==
  910. per_cell_W(curr_cell, i));
  911. }
  912. }
  913. }
  914. }
  915. }
  916. W.resize(num_faces, num_labels*2);
  917. for (size_t i=0; i<num_faces; i++) {
  918. const size_t patch = P[i];
  919. const size_t positive_cell = per_patch_cells(patch, 0);
  920. const size_t negative_cell = per_patch_cells(patch, 1);
  921. for (size_t j=0; j<num_labels; j++) {
  922. W(i,j*2 ) = per_cell_W(positive_cell, j);
  923. W(i,j*2+1) = per_cell_W(negative_cell, j);
  924. }
  925. }
  926. }