ConjugateFFSolverData.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Olga Diamanti, 2015 Alec Jacobson
  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. #ifndef IGL_CONJUGATE_FF_SOLVER_DATA_H
  9. #define IGL_CONJUGATE_FF_SOLVER_DATA_H
  10. #include "igl_inline.h"
  11. #include <Eigen/Core>
  12. #include <Eigen/Sparse>
  13. #include <igl/matlab_format.h>
  14. #include <iostream>
  15. using namespace std;
  16. namespace igl
  17. {
  18. // Data class for the Conjugate Frame Field Solver
  19. template <typename DerivedV, typename DerivedF>
  20. class ConjugateFFSolverData
  21. {
  22. public:
  23. const Eigen::PlainObjectBase<DerivedV> &V; int numV;
  24. const Eigen::PlainObjectBase<DerivedF> &F; int numF;
  25. Eigen::MatrixXi EV; int numE;
  26. Eigen::MatrixXi F2E;
  27. Eigen::MatrixXi E2F;
  28. Eigen::VectorXd K;
  29. Eigen::VectorXi isBorderEdge;
  30. int numInteriorEdges;
  31. Eigen::Matrix<int,Eigen::Dynamic,2> E2F_int;
  32. Eigen::VectorXi indInteriorToFull;
  33. Eigen::VectorXi indFullToInterior;
  34. DerivedV B1, B2, FN;
  35. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,1> kmin, kmax;
  36. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,2> dmin, dmax;
  37. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic,3> dmin3, dmax3;
  38. Eigen::VectorXd nonPlanarityMeasure;
  39. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > planarityWeight;
  40. //conjugacy matrix
  41. std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,4> > H;
  42. //conjugacy matrix eigenvectors and (scaled) eigenvalues
  43. std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,4> > UH;
  44. std::vector<Eigen::Matrix<typename DerivedV::Scalar, 4,1> > s;
  45. //laplacians
  46. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> DDA, DDB;
  47. private:
  48. IGL_INLINE void computeCurvatureAndPrincipals();
  49. IGL_INLINE void precomputeConjugacyStuff();
  50. IGL_INLINE void computeLaplacians();
  51. IGL_INLINE void computek();
  52. IGL_INLINE void computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D);
  53. IGL_INLINE void precomputeInteriorEdges();
  54. public:
  55. IGL_INLINE ConjugateFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
  56. const Eigen::PlainObjectBase<DerivedF> &_F);
  57. IGL_INLINE void evaluateConjugacy(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvU,
  58. const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvV,
  59. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &conjValues) const ;
  60. };
  61. }
  62. #include <igl/colon.h>
  63. #include <igl/edge_topology.h>
  64. #include <igl/false_barycentric_subdivision.h>
  65. #include <igl/local_basis.h>
  66. #include <igl/principal_curvature.h>
  67. #include <igl/sparse.h>
  68. template <typename DerivedV, typename DerivedF>
  69. IGL_INLINE igl::ConjugateFFSolverData<DerivedV, DerivedF>::
  70. ConjugateFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
  71. const Eigen::PlainObjectBase<DerivedF> &_F):
  72. V(_V),
  73. numV(_V.rows()),
  74. F(_F),
  75. numF(_F.rows())
  76. {
  77. igl::edge_topology(V,F,EV,F2E,E2F);
  78. numE = EV.rows();
  79. precomputeInteriorEdges();
  80. igl::local_basis(V,F,B1,B2,FN);
  81. computek();
  82. computeLaplacians();
  83. computeCurvatureAndPrincipals();
  84. precomputeConjugacyStuff();
  85. };
  86. template <typename DerivedV, typename DerivedF>
  87. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::computeCurvatureAndPrincipals()
  88. {
  89. Eigen::MatrixXd VCBary;
  90. Eigen::MatrixXi FCBary;
  91. VCBary.setZero(numV+numF,3);
  92. FCBary.setZero(3*numF,3);
  93. igl::false_barycentric_subdivision(V, F, VCBary, FCBary);
  94. Eigen::MatrixXd dmax3_,dmin3_;
  95. igl::principal_curvature(VCBary, FCBary, dmax3_, dmin3_, kmax, kmin, 5,true);
  96. dmax3 = dmax3_.bottomRows(numF);
  97. dmin3 = dmin3_.bottomRows(numF);
  98. kmax = kmax.bottomRows(numF);
  99. kmin = kmin.bottomRows(numF);
  100. cerr<<igl::matlab_format(kmax,"kmax")<<endl;
  101. cerr<<igl::matlab_format(kmin,"kmin")<<endl;
  102. // kmax = dmax3.rowwise().norm();
  103. // kmin = dmin3.rowwise().norm();
  104. dmin3.rowwise().normalize();
  105. dmax3.rowwise().normalize();
  106. dmax.setZero(numF,2);
  107. dmin.setZero(numF,2);
  108. for (int i= 0; i <numF; ++i)
  109. {
  110. if(kmin[i] != kmin[i] || kmax[i] != kmax[i] || (dmin3.row(i).array() != dmin3.row(i).array()).any() || (dmax3.row(i).array() != dmax3.row(i).array()).any())
  111. {
  112. kmin[i] = 0;
  113. kmax[i] = 0;
  114. dmin3.row(i) = B1.row(i);
  115. dmax3.row(i) = B2.row(i);
  116. }
  117. else
  118. {
  119. dmax3.row(i) = (dmax3.row(i) - (dmax3.row(i).dot(FN.row(i)))*FN.row(i)).normalized();
  120. dmin3.row(i) = dmin3.row(i) - (dmin3.row(i).dot(FN.row(i)))*FN.row(i);
  121. dmin3.row(i) = (dmin3.row(i) - (dmin3.row(i).dot(dmax3.row(i)))*dmax3.row(i)).normalized();
  122. if ((dmin3.row(i).cross(dmax3.row(i))).dot(FN.row(i))<0)
  123. dmin3.row(i) = -dmin3.row(i);
  124. }
  125. dmax.row(i) << dmax3.row(i).dot(B1.row(i)), dmax3.row(i).dot(B2.row(i));
  126. dmax.row(i).normalize();
  127. dmin.row(i) << dmin3.row(i).dot(B1.row(i)), dmin3.row(i).dot(B2.row(i));
  128. dmin.row(i).normalize();
  129. }
  130. nonPlanarityMeasure = kmax.cwiseAbs().array()*kmin.cwiseAbs().array();
  131. typename DerivedV::Scalar minP = nonPlanarityMeasure.minCoeff();
  132. typename DerivedV::Scalar maxP = nonPlanarityMeasure.maxCoeff();
  133. nonPlanarityMeasure = (nonPlanarityMeasure.array()-minP)/(maxP-minP);
  134. Eigen::VectorXi I = igl::colon<typename DerivedF::Scalar>(0, numF-1);
  135. igl::sparse(I, I, nonPlanarityMeasure, numF, numF, planarityWeight);
  136. }
  137. template <typename DerivedV, typename DerivedF>
  138. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::precomputeConjugacyStuff()
  139. {
  140. H.resize(numF);
  141. UH.resize(numF);
  142. s.resize(numF);
  143. for (int i = 0; i<numF; ++i)
  144. {
  145. //compute conjugacy matrix
  146. typename DerivedV::Scalar e1x = dmin(i,0), e1y = dmin(i,1), e2x = dmax(i,0), e2y = dmax(i,1), k1 = kmin[i], k2 = kmax[i];
  147. H[i]<<
  148. 0, 0, k1*e1x*e1x, k1*e1x*e1y,
  149. 0, 0, k1*e1x*e1y, k1*e1y*e1y,
  150. k2*e2x*e2x, k2*e2x*e2y, 0, 0,
  151. k2*e2x*e2y, k2*e2y*e2y, 0, 0;
  152. Eigen::Matrix<typename DerivedV::Scalar, 4, 4> Ht = H[i].transpose();
  153. H[i] = .5*(H[i]+Ht);
  154. Eigen::EigenSolver<Eigen::Matrix<typename DerivedV::Scalar, 4, 4> > es(H[i]);
  155. s[i] = es.eigenvalues().real();//ok to do this because H symmetric
  156. //scale
  157. s[i] = s[i]/(s[i].cwiseAbs().minCoeff());
  158. UH[i] = es.eigenvectors().real();
  159. }
  160. }
  161. template <typename DerivedV, typename DerivedF>
  162. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::computeLaplacians()
  163. {
  164. computeCoefficientLaplacian(2, DDA);
  165. computeCoefficientLaplacian(4, DDB);
  166. }
  167. template<typename DerivedV, typename DerivedF>
  168. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
  169. precomputeInteriorEdges()
  170. {
  171. // Flag border edges
  172. numInteriorEdges = 0;
  173. isBorderEdge.setZero(numE,1);
  174. indFullToInterior = -1*Eigen::VectorXi::Ones(numE,1);
  175. for(unsigned i=0; i<numE; ++i)
  176. {
  177. if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
  178. isBorderEdge[i] = 1;
  179. else
  180. {
  181. indFullToInterior[i] = numInteriorEdges;
  182. numInteriorEdges++;
  183. }
  184. }
  185. E2F_int.resize(numInteriorEdges, 2);
  186. indInteriorToFull.setZero(numInteriorEdges,1);
  187. int ii = 0;
  188. for (int k=0; k<numE; ++k)
  189. {
  190. if (isBorderEdge[k])
  191. continue;
  192. E2F_int.row(ii) = E2F.row(k);
  193. indInteriorToFull[ii] = k;
  194. ii++;
  195. }
  196. }
  197. template<typename DerivedV, typename DerivedF>
  198. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
  199. computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D)
  200. {
  201. std::vector<Eigen::Triplet<std::complex<typename DerivedV::Scalar> >> tripletList;
  202. // For every non-border edge
  203. for (unsigned eid=0; eid<numE; ++eid)
  204. {
  205. if (!isBorderEdge[eid])
  206. {
  207. int fid0 = E2F(eid,0);
  208. int fid1 = E2F(eid,1);
  209. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
  210. fid0,
  211. std::complex<typename DerivedV::Scalar>(1.)));
  212. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
  213. fid1,
  214. std::complex<typename DerivedV::Scalar>(1.)));
  215. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
  216. fid1,
  217. -1.*std::polar(1.,-1.*n*K[eid])));
  218. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
  219. fid0,
  220. -1.*std::polar(1.,1.*n*K[eid])));
  221. }
  222. }
  223. D.resize(numF,numF);
  224. D.setFromTriplets(tripletList.begin(), tripletList.end());
  225. }
  226. template<typename DerivedV, typename DerivedF>
  227. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
  228. computek()
  229. {
  230. K.setZero(numE);
  231. // For every non-border edge
  232. for (unsigned eid=0; eid<numE; ++eid)
  233. {
  234. if (!isBorderEdge[eid])
  235. {
  236. int fid0 = E2F(eid,0);
  237. int fid1 = E2F(eid,1);
  238. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0);
  239. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1);
  240. // find common edge on triangle 0 and 1
  241. int fid0_vc = -1;
  242. int fid1_vc = -1;
  243. for (unsigned i=0;i<3;++i)
  244. {
  245. if (F2E(fid0,i) == eid)
  246. fid0_vc = i;
  247. if (F2E(fid1,i) == eid)
  248. fid1_vc = i;
  249. }
  250. assert(fid0_vc != -1);
  251. assert(fid1_vc != -1);
  252. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
  253. common_edge.normalize();
  254. // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
  255. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P;
  256. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc));
  257. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge);
  258. P << common_edge, tmp, N0;
  259. // P.transposeInPlace();
  260. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0;
  261. V0.row(0) = V.row(F(fid0,0)) -o;
  262. V0.row(1) = V.row(F(fid0,1)) -o;
  263. V0.row(2) = V.row(F(fid0,2)) -o;
  264. V0 = (P*V0.transpose()).transpose();
  265. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1;
  266. V1.row(0) = V.row(F(fid1,0)) -o;
  267. V1.row(1) = V.row(F(fid1,1)) -o;
  268. V1.row(2) = V.row(F(fid1,2)) -o;
  269. V1 = (P*V1.transpose()).transpose();
  270. // compute rotation R such that R * N1 = N0
  271. // i.e. map both triangles to the same plane
  272. double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
  273. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R;
  274. R << 1, 0, 0,
  275. 0, cos(alpha), -sin(alpha) ,
  276. 0, sin(alpha), cos(alpha);
  277. V1 = (R*V1.transpose()).transpose();
  278. // measure the angle between the reference frames
  279. // k_ij is the angle between the triangle on the left and the one on the right
  280. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0);
  281. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0);
  282. ref0.normalize();
  283. ref1.normalize();
  284. double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
  285. // just to be sure, rotate ref0 using angle ktemp...
  286. Eigen::Matrix<typename DerivedV::Scalar, 2, 2> R2;
  287. R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
  288. Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose();
  289. K[eid] = ktemp;
  290. }
  291. }
  292. }
  293. template<typename DerivedV, typename DerivedF>
  294. IGL_INLINE void igl::ConjugateFFSolverData<DerivedV, DerivedF>::
  295. evaluateConjugacy(const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvU,
  296. const Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> &pvV,
  297. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &conjValues) const
  298. {
  299. conjValues.resize(numF,1);
  300. for (int j =0; j<numF; ++j)
  301. {
  302. Eigen::Matrix<typename DerivedV::Scalar, 4, 1> x; x<<pvU.row(j).transpose(), pvV.row(j).transpose();
  303. conjValues[j] = x.transpose()*H[j]*x;
  304. }
  305. }
  306. #endif