isolines_intrinsic.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2023 Alec Jacobson <[email protected]>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "isolines_intrinsic.h"
  9. #include "edge_crossings.h"
  10. #include "cat.h"
  11. #include "unique_edge_map.h"
  12. #ifndef NDEBUG
  13. # include "is_edge_manifold.h"
  14. # include "is_vertex_manifold.h"
  15. #endif
  16. #include <unordered_map>
  17. #include <vector>
  18. template <
  19. typename DerivedF,
  20. typename DerivedS,
  21. typename Derivedvals,
  22. typename DerivediB,
  23. typename DerivediFI,
  24. typename DerivediE,
  25. typename DerivedI>
  26. void igl::isolines_intrinsic(
  27. const Eigen::MatrixBase<DerivedF> & F,
  28. const Eigen::MatrixBase<DerivedS> & S,
  29. const Eigen::MatrixBase<Derivedvals> & vals,
  30. Eigen::PlainObjectBase<DerivediB> & iB,
  31. Eigen::PlainObjectBase<DerivediFI> & iFI,
  32. Eigen::PlainObjectBase<DerivediE> & iE,
  33. Eigen::PlainObjectBase<DerivedI> & I)
  34. {
  35. using Index = typename DerivedF::Scalar;
  36. Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> uE;
  37. Eigen::Vector<Index,Eigen::Dynamic> EMAP,uEC,uEE;
  38. {
  39. Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> E;
  40. igl::unique_edge_map(F,E,uE,EMAP,uEC,uEE);
  41. }
  42. {
  43. std::vector<DerivediB> viB(vals.size());
  44. std::vector<DerivediFI> viFI(vals.size());
  45. std::vector<DerivediE> viE(vals.size());
  46. std::vector<DerivedI> vI(vals.size());
  47. int num_vertices = 0;
  48. for(int j = 0;j<vals.size();j++)
  49. {
  50. isolines_intrinsic(F,S,uE,EMAP,uEC,uEE,vals(j),viB[j],viFI[j],viE[j]);
  51. viE[j].array() += num_vertices;
  52. num_vertices += viB[j].rows();
  53. vI[j] = DerivedI::Constant(viE[j].rows(),j);
  54. }
  55. igl::cat(1,viB,iB);
  56. igl::cat(1,viFI,iFI);
  57. igl::cat(1,viE,iE);
  58. igl::cat(1,vI,I);
  59. }
  60. }
  61. template <
  62. typename DerivedF,
  63. typename DerivedS,
  64. typename DeriveduE,
  65. typename DerivedEMAP,
  66. typename DeriveduEC,
  67. typename DeriveduEE,
  68. typename DerivediB,
  69. typename DerivediFI,
  70. typename DerivediE>
  71. void igl::isolines_intrinsic(
  72. const Eigen::MatrixBase<DerivedF> & F,
  73. const Eigen::MatrixBase<DerivedS> & S,
  74. const Eigen::MatrixBase<DeriveduE> & uE,
  75. const Eigen::MatrixBase<DerivedEMAP> & EMAP,
  76. const Eigen::MatrixBase<DeriveduEC> & uEC,
  77. const Eigen::MatrixBase<DeriveduEE> & uEE,
  78. const typename DerivedS::Scalar val,
  79. Eigen::PlainObjectBase<DerivediB> & iB,
  80. Eigen::PlainObjectBase<DerivediFI> & iFI,
  81. Eigen::PlainObjectBase<DerivediE> & iE)
  82. {
  83. using Scalar = typename DerivedS::Scalar;
  84. std::unordered_map<int,int> uE2I;
  85. Eigen::Matrix<Scalar,Eigen::Dynamic,1> T;
  86. igl::edge_crossings(uE,S,val,uE2I,T);
  87. iB.resize(uE2I.size(),F.cols());
  88. iFI.resize(uE2I.size());
  89. Eigen::VectorXi U(uE2I.size());
  90. for(auto & pair : uE2I)
  91. {
  92. const int u = pair.first;
  93. const int w = pair.second;
  94. // first face incident on uE(u,:)
  95. const int e = uEE(uEC(u));
  96. const int f = e % F.rows();
  97. const int k = e / F.rows();
  98. const bool flip = uE(u,0) != F(f,(k+1)%3);
  99. const double t = T(w);
  100. iB(w,k) = 0;
  101. iB(w,(k+1)%3) = flip? t:1-t;
  102. iB(w,(k+2)%3) = flip?1-t:t;
  103. iFI(w) = f;
  104. U(w) = u;
  105. }
  106. // Vertex crossings
  107. std::unordered_map<int,int> V2I;
  108. {
  109. const auto add_vertex_crossing = [&iB,&iFI](const int k, const int i, const int j)
  110. {
  111. if(k >= iB.rows())
  112. {
  113. iB.conservativeResize(2*iB.rows()+1,Eigen::NoChange);
  114. iFI.conservativeResize(2*iFI.rows()+1,Eigen::NoChange);
  115. }
  116. iFI(k) = i;
  117. iB.row(k) << 0,0,0;
  118. iB(k,j) = 1;
  119. };
  120. int k = iB.rows();
  121. for(int i = 0;i<F.rows();i++)
  122. {
  123. for(int j = 0;j<3;j++)
  124. {
  125. const int v = F(i,j);
  126. if(S(v) == val)
  127. {
  128. if(V2I.find(v) == V2I.end())
  129. {
  130. V2I[v] = k;
  131. add_vertex_crossing(k++,i,j);
  132. }
  133. }
  134. }
  135. }
  136. iB.conservativeResize(k,Eigen::NoChange);
  137. iFI.conservativeResize(k,Eigen::NoChange);
  138. }
  139. iE.resize(uE2I.size(),2);
  140. const auto set_row = [&iE](const int k, const int i, const int j)
  141. {
  142. if(k >= iE.rows())
  143. {
  144. iE.conservativeResize(2*iE.rows()+1,Eigen::NoChange);
  145. }
  146. iE.row(k) << i,j;
  147. };
  148. {
  149. int r = 0;
  150. for(int f = 0;f < F.rows();f++)
  151. {
  152. // find first crossing edge
  153. int i;
  154. for(i = 0;i<3;i++)
  155. {
  156. if(uE2I.find(EMAP(f+F.rows()*i)) != uE2I.end())
  157. {
  158. break;
  159. }
  160. }
  161. int j;
  162. for(j = i+1;j<3;j++)
  163. {
  164. if(uE2I.find(EMAP(f+F.rows()*j)) != uE2I.end())
  165. {
  166. break;
  167. }
  168. }
  169. if(j<3)
  170. {
  171. // Connect two edge crossings.
  172. // other vertex
  173. const int k = 3-i-j;
  174. const int wi = uE2I[EMAP(f+F.rows()*i)];
  175. const int wj = uE2I[EMAP(f+F.rows()*j)];
  176. // flip orientation based on triangle gradient
  177. Scalar SFfk = S(F(f,k));
  178. bool flip = SFfk < val;
  179. flip = k%2? !flip:flip;
  180. if(flip)
  181. {
  182. set_row(r++,wi,wj);
  183. }else
  184. {
  185. set_row(r++,wj,wi);
  186. }
  187. }else if(i<3)
  188. {
  189. // The only valid vertex crossing is the opposite vertex
  190. const int v = F(f,i);
  191. // Is it a crossing?
  192. assert(V2I.find(v) != V2I.end());
  193. //if(V2I.find(v) != V2I.end())
  194. {
  195. const int wv = V2I[v];
  196. const int wi = uE2I[EMAP(f+F.rows()*i)];
  197. const bool flip = S(F(f,(i+1)%3)) > val;
  198. if(flip)
  199. {
  200. set_row(r++,wi,wv);
  201. }else
  202. {
  203. set_row(r++,wv,wi);
  204. }
  205. }
  206. }else
  207. {
  208. // Could have 2 vertex crossings. We're only interested if there're exactly two and if the other vertex is "above".
  209. int i = 0;
  210. for(i = 0;i<3;i++)
  211. {
  212. if(S(F(f,i)) == val)
  213. {
  214. break;
  215. }
  216. }
  217. int j;
  218. for(j = i+1;j<3;j++)
  219. {
  220. if(S(F(f,j)) == val)
  221. {
  222. break;
  223. }
  224. }
  225. if(j<3)
  226. {
  227. // check if the third is a crossing.
  228. const int k = 3-i-j;
  229. // Triangle is constant on the val. Skip.
  230. if(S(F(f,k)) == val){ continue; }
  231. // Is this a boundary edge?
  232. const int u = EMAP(f+F.rows()*k);
  233. const int count = uEC(u+1)-uEC(u);
  234. if( count == 1 || S(F(f,k)) > val)
  235. {
  236. const int wi = V2I[F(f,i)];
  237. const int wj = V2I[F(f,j)];
  238. bool flip = S(F(f,k)) < val;
  239. flip = k%2 ? !flip:flip;
  240. if(flip)
  241. {
  242. set_row(r++,wj,wi);
  243. }else
  244. {
  245. set_row(r++,wi,wj);
  246. }
  247. }
  248. }
  249. }
  250. }
  251. iE.conservativeResize(r,Eigen::NoChange);
  252. }
  253. #ifdef IGL_ISOLINES_INTRINSIC_DEBUG
  254. if(igl::is_vertex_manifold(F) && igl::is_edge_manifold(F))
  255. {
  256. // Check that every vertex has one in one out
  257. Eigen::VectorXi in_count = Eigen::VectorXi::Zero(iB.rows());
  258. Eigen::VectorXi out_count = Eigen::VectorXi::Zero(iB.rows());
  259. for(int e = 0;e<iE.rows();e++)
  260. {
  261. const int i = iE(e,0);
  262. out_count(i)++;
  263. const int j = iE(e,1);
  264. in_count(j)++;
  265. }
  266. for(int i = 0;i<iB.rows();i++)
  267. {
  268. assert(in_count(i) <= 1);
  269. assert(out_count(i) <= 1);
  270. }
  271. }
  272. #endif
  273. }
  274. #ifdef IGL_STATIC_LIBRARY
  275. // Explicit template instantiation
  276. // generated by autoexplicit.sh
  277. template void igl::isolines_intrinsic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
  278. #endif