angle_bound_frame_fields.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2014 Olga Diamanti <olga.diam@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. #include <igl/angle_bound_frame_fields.h>
  9. #include <igl/edge_topology.h>
  10. #include <igl/local_basis.h>
  11. #include <igl/sparse.h>
  12. #include <igl/speye.h>
  13. #include <igl/slice.h>
  14. #include <igl/polyroots.h>
  15. #include <igl/colon.h>
  16. #include <Eigen/Sparse>
  17. #include <iostream>
  18. namespace igl {
  19. template <typename DerivedV, typename DerivedF>
  20. class AngleBoundFFSolverData
  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. #warning "Constructing Eigen::PlainObjectBase directly is deprecated"
  35. Eigen::PlainObjectBase<DerivedV> B1, B2, FN;
  36. //laplacians
  37. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> DDA, DDB;
  38. private:
  39. IGL_INLINE void computeLaplacians();
  40. IGL_INLINE void computek();
  41. IGL_INLINE void computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D);
  42. IGL_INLINE void precomputeInteriorEdges();
  43. public:
  44. IGL_INLINE AngleBoundFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
  45. const Eigen::PlainObjectBase<DerivedF> &_F);
  46. };
  47. template <typename DerivedV, typename DerivedF, typename DerivedO>
  48. class AngleBoundFFSolver
  49. {
  50. public:
  51. IGL_INLINE AngleBoundFFSolver(const AngleBoundFFSolverData<DerivedV, DerivedF> &_data,
  52. const typename DerivedV::Scalar &_thetaMin = 30,
  53. int _maxIter = 50,
  54. const typename DerivedV::Scalar &_lambdaInit = 100,
  55. const typename DerivedV::Scalar &_lambdaMultFactor = 1.01,
  56. const bool _doHardConstraints = false);
  57. IGL_INLINE bool solve(const Eigen::VectorXi &isConstrained,
  58. const Eigen::PlainObjectBase<DerivedO> &initialSolution,
  59. Eigen::PlainObjectBase<DerivedO> &output,
  60. typename DerivedV::Scalar *lambdaOut = NULL);
  61. private:
  62. const AngleBoundFFSolverData<DerivedV, DerivedF> &data;
  63. //polyVF data
  64. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> Acoeff, Bcoeff;
  65. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 2> pvU, pvV;
  66. typename DerivedV::Scalar lambda;
  67. //parameters
  68. typename DerivedV::Scalar lambdaInit,lambdaMultFactor;
  69. int maxIter;
  70. typename DerivedV::Scalar thetaMin;
  71. bool doHardConstraints;
  72. typename DerivedV::Scalar computeAngle(const std::complex<typename DerivedV::Scalar> &u,
  73. const std::complex<typename DerivedV::Scalar> &v);
  74. // IGL_INLINE void computeAngles(Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &angles);
  75. IGL_INLINE int getNumOutOfBounds();
  76. IGL_INLINE void rotateAroundBisector(const std::complex<typename DerivedV::Scalar> &uin,
  77. const std::complex<typename DerivedV::Scalar> &vin,
  78. const typename DerivedV::Scalar theta,
  79. std::complex<typename DerivedV::Scalar> &uout,
  80. std::complex<typename DerivedV::Scalar> &vout);
  81. IGL_INLINE void localStep();
  82. IGL_INLINE void globalStep(const Eigen::Matrix<int, Eigen::Dynamic, 1> &isConstrained,
  83. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &Ak,
  84. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &Bk);
  85. IGL_INLINE void minQuadWithKnownMini(const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &Q,
  86. const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &f,
  87. const Eigen::VectorXi isConstrained,
  88. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &xknown,
  89. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &x);
  90. IGL_INLINE void setFieldFromCoefficients();
  91. IGL_INLINE void setCoefficientsFromField();
  92. };
  93. }
  94. //Implementation
  95. /***************************** Data ***********************************/
  96. template <typename DerivedV, typename DerivedF>
  97. IGL_INLINE igl::AngleBoundFFSolverData<DerivedV, DerivedF>::
  98. AngleBoundFFSolverData(const Eigen::PlainObjectBase<DerivedV> &_V,
  99. const Eigen::PlainObjectBase<DerivedF> &_F):
  100. V(_V),
  101. numV(_V.rows()),
  102. F(_F),
  103. numF(_F.rows())
  104. {
  105. igl::edge_topology(V,F,EV,F2E,E2F);
  106. numE = EV.rows();
  107. precomputeInteriorEdges();
  108. igl::local_basis(V,F,B1,B2,FN);
  109. computek();
  110. computeLaplacians();
  111. };
  112. template <typename DerivedV, typename DerivedF>
  113. IGL_INLINE void igl::AngleBoundFFSolverData<DerivedV, DerivedF>::computeLaplacians()
  114. {
  115. computeCoefficientLaplacian(2, DDA);
  116. computeCoefficientLaplacian(4, DDB);
  117. }
  118. template<typename DerivedV, typename DerivedF>
  119. IGL_INLINE void igl::AngleBoundFFSolverData<DerivedV, DerivedF>::
  120. precomputeInteriorEdges()
  121. {
  122. // Flag border edges
  123. numInteriorEdges = 0;
  124. isBorderEdge.setZero(numE,1);
  125. indFullToInterior = -1.*Eigen::VectorXi::Ones(numE,1);
  126. for(unsigned i=0; i<numE; ++i)
  127. {
  128. if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
  129. isBorderEdge[i] = 1;
  130. else
  131. {
  132. indFullToInterior[i] = numInteriorEdges;
  133. numInteriorEdges++;
  134. }
  135. }
  136. E2F_int.resize(numInteriorEdges, 2);
  137. indInteriorToFull.setZero(numInteriorEdges,1);
  138. int ii = 0;
  139. for (int k=0; k<numE; ++k)
  140. {
  141. if (isBorderEdge[k])
  142. continue;
  143. E2F_int.row(ii) = E2F.row(k);
  144. indInteriorToFull[ii] = k;
  145. ii++;
  146. }
  147. }
  148. template<typename DerivedV, typename DerivedF>
  149. IGL_INLINE void igl::AngleBoundFFSolverData<DerivedV, DerivedF>::
  150. computeCoefficientLaplacian(int n, Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &D)
  151. {
  152. std::vector<Eigen::Triplet<std::complex<typename DerivedV::Scalar> >> tripletList;
  153. // For every non-border edge
  154. for (unsigned eid=0; eid<numE; ++eid)
  155. {
  156. if (!isBorderEdge[eid])
  157. {
  158. int fid0 = E2F(eid,0);
  159. int fid1 = E2F(eid,1);
  160. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
  161. fid0,
  162. std::complex<typename DerivedV::Scalar>(1.)));
  163. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
  164. fid1,
  165. std::complex<typename DerivedV::Scalar>(1.)));
  166. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid0,
  167. fid1,
  168. -1.*std::polar(1.,-1.*n*K[eid])));
  169. tripletList.push_back(Eigen::Triplet<std::complex<typename DerivedV::Scalar> >(fid1,
  170. fid0,
  171. -1.*std::polar(1.,1.*n*K[eid])));
  172. }
  173. }
  174. D.resize(numF,numF);
  175. D.setFromTriplets(tripletList.begin(), tripletList.end());
  176. }
  177. template<typename DerivedV, typename DerivedF>
  178. IGL_INLINE void igl::AngleBoundFFSolverData<DerivedV, DerivedF>::
  179. computek()
  180. {
  181. K.setZero(numE);
  182. // For every non-border edge
  183. for (unsigned eid=0; eid<numE; ++eid)
  184. {
  185. if (!isBorderEdge[eid])
  186. {
  187. int fid0 = E2F(eid,0);
  188. int fid1 = E2F(eid,1);
  189. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0);
  190. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1);
  191. // find common edge on triangle 0 and 1
  192. int fid0_vc = -1;
  193. int fid1_vc = -1;
  194. for (unsigned i=0;i<3;++i)
  195. {
  196. if (F2E(fid0,i) == eid)
  197. fid0_vc = i;
  198. if (F2E(fid1,i) == eid)
  199. fid1_vc = i;
  200. }
  201. assert(fid0_vc != -1);
  202. assert(fid1_vc != -1);
  203. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
  204. common_edge.normalize();
  205. // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
  206. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P;
  207. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc));
  208. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge);
  209. P << common_edge, tmp, N0;
  210. // P.transposeInPlace();
  211. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0;
  212. V0.row(0) = V.row(F(fid0,0)) -o;
  213. V0.row(1) = V.row(F(fid0,1)) -o;
  214. V0.row(2) = V.row(F(fid0,2)) -o;
  215. V0 = (P*V0.transpose()).transpose();
  216. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1;
  217. V1.row(0) = V.row(F(fid1,0)) -o;
  218. V1.row(1) = V.row(F(fid1,1)) -o;
  219. V1.row(2) = V.row(F(fid1,2)) -o;
  220. V1 = (P*V1.transpose()).transpose();
  221. // compute rotation R such that R * N1 = N0
  222. // i.e. map both triangles to the same plane
  223. double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
  224. Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R;
  225. R << 1, 0, 0,
  226. 0, cos(alpha), -sin(alpha) ,
  227. 0, sin(alpha), cos(alpha);
  228. V1 = (R*V1.transpose()).transpose();
  229. // measure the angle between the reference frames
  230. // k_ij is the angle between the triangle on the left and the one on the right
  231. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0);
  232. Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0);
  233. ref0.normalize();
  234. ref1.normalize();
  235. double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
  236. // just to be sure, rotate ref0 using angle ktemp...
  237. Eigen::Matrix<typename DerivedV::Scalar, 2, 2> R2;
  238. R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
  239. Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose();
  240. K[eid] = ktemp;
  241. }
  242. }
  243. }
  244. /***************************** Solver ***********************************/
  245. template <typename DerivedV, typename DerivedF, typename DerivedO>
  246. IGL_INLINE igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  247. AngleBoundFFSolver(const AngleBoundFFSolverData<DerivedV, DerivedF> &_data,
  248. const typename DerivedV::Scalar &_thetaMin,
  249. int _maxIter,
  250. const typename DerivedV::Scalar &_lambdaInit,
  251. const typename DerivedV::Scalar &_lambdaMultFactor,
  252. const bool _doHardConstraints):
  253. data(_data),
  254. lambdaInit(_lambdaInit),
  255. maxIter(_maxIter),
  256. lambdaMultFactor(_lambdaMultFactor),
  257. doHardConstraints(_doHardConstraints),
  258. thetaMin(_thetaMin)
  259. {
  260. Acoeff.resize(data.numF,1);
  261. Bcoeff.resize(data.numF,1);
  262. pvU.setZero(data.numF, 2);
  263. pvV.setZero(data.numF, 2);
  264. };
  265. template<typename DerivedV, typename DerivedF, typename DerivedO>
  266. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  267. rotateAroundBisector(const std::complex<typename DerivedV::Scalar> &uin,
  268. const std::complex<typename DerivedV::Scalar> &vin,
  269. const typename DerivedV::Scalar diff,
  270. std::complex<typename DerivedV::Scalar> &uout,
  271. std::complex<typename DerivedV::Scalar> &vout)
  272. {
  273. //rotate 2D complex vectors u and v around their bisector so that their
  274. //angle is at least theta
  275. uout = uin;
  276. vout = vin;
  277. typename DerivedV::Scalar au = arg(uin);
  278. typename DerivedV::Scalar av = arg(vin);
  279. if (au<av)
  280. {
  281. uout = std::polar (1.0,-.5*diff)*uin;
  282. vout = std::polar (1.0, .5*diff)*vin;
  283. }
  284. else
  285. {
  286. uout = std::polar (1.0, .5*diff)*uin;
  287. vout = std::polar (1.0,-.5*diff)*vin;
  288. }
  289. }
  290. template<typename DerivedV, typename DerivedF, typename DerivedO>
  291. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  292. localStep()
  293. {
  294. for (int j =0; j<data.numF; ++j)
  295. {
  296. std::complex<typename DerivedV::Scalar> u(pvU(j,0),pvU(j,1));
  297. std::complex<typename DerivedV::Scalar> v(pvV(j,0),pvV(j,1));
  298. typename DerivedV::Scalar current_angle = computeAngle(u, v);
  299. if (current_angle<thetaMin*M_PI/180)
  300. {
  301. // bring all to 1st or 4th quarter plane
  302. if ((arg(u)>=0.5*M_PI || arg(u)<-0.5*M_PI ))
  303. u = -u;
  304. if ((arg(v)>=0.5*M_PI || arg(v)<-0.5*M_PI ))
  305. v = -v;
  306. assert(fabs(computeAngle(u, v) - current_angle)<1e-5);
  307. if ( fabs(arg(u) - arg(v)) >0.5*M_PI )
  308. v = -v;
  309. assert(fabs(computeAngle(u, v) - current_angle)<1e-5);
  310. std::complex<typename DerivedV::Scalar> u1, v1;
  311. typename DerivedV::Scalar diff = thetaMin*M_PI/180 - current_angle + 1e-6;
  312. rotateAroundBisector(u, v, diff, u1, v1);
  313. // if (computeAngle(u1, v1)<thetaMin*M_PI/180)
  314. // {
  315. // std::cerr<<"u = ["<<real(u)<<","<<imag(u)<< "]; v= ["<<real(v)<<","<<imag(v)<<"];"<<std::endl;
  316. // std::cerr<<"u1 = ["<<real(u1)<<","<<imag(u1)<< "]; v1= ["<<real(v1)<<","<<imag(v1)<<"];"<<std::endl;
  317. // std::cerr<<"current_angle = "<<current_angle<<std::endl;
  318. // std::cerr<<"aout = "<<computeAngle(u1, v1)<< "; theta= "<<thetaMin*M_PI/180<<";"<<std::endl;
  319. // }
  320. // assert(computeAngle(u1, v1)>=thetaMin*M_PI/180);
  321. pvU.row(j) << real(u1),imag(u1);
  322. pvV.row(j) << real(v1),imag(v1);
  323. }
  324. }
  325. }
  326. //
  327. //template<typename DerivedV, typename DerivedF, typename DerivedO>
  328. //IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  329. //computeAngles(Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> &angles)
  330. //{
  331. // angles.resize(data.numF,1);
  332. // for (int i =0; i<data.numF; ++i)
  333. // {
  334. // std::complex<typename DerivedV::Scalar> u(pvU(i,0),pvU(i,1));
  335. // std::complex<typename DerivedV::Scalar> v(pvV(i,0),pvV(i,1));
  336. // angles[i] = fabs(arg(u) - arg(v));
  337. // if (angles[i]>M_PI)
  338. // angles[i] = 2*M_PI-angles[i];
  339. // if (angles[i]>.5*M_PI)
  340. // angles[i] = M_PI-angles[i];
  341. // }
  342. //}
  343. template<typename DerivedV, typename DerivedF, typename DerivedO>
  344. IGL_INLINE typename DerivedV::Scalar igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  345. computeAngle(const std::complex<typename DerivedV::Scalar> &u,
  346. const std::complex<typename DerivedV::Scalar> &v)
  347. {
  348. typename DerivedV::Scalar angle = std::min(fabs(arg(u*conj(v))), fabs(arg(u*conj(-v))));
  349. // typename DerivedV::Scalar angle;
  350. // typename DerivedV::Scalar a1 = fabs(arg(u*conj(v)));
  351. // typename DerivedV::Scalar a2 = fabs(arg(u*conj(-v)));
  352. // if (a1 < a2)
  353. // angle = a1;
  354. // else
  355. // {
  356. // angle = a2; v = -v;
  357. // }
  358. // typename DerivedV::Scalar angle = fabs(arg(u) - arg(v));
  359. // if (angle>M_PI)
  360. // {
  361. // u = -u;
  362. // angle = fabs(arg(u) - arg(v));
  363. // };
  364. //
  365. // if (angle>.5*M_PI)
  366. // {
  367. // v = -v;
  368. // angle = fabs(arg(u) - arg(v));
  369. // };
  370. //
  371. // assert(fabs(angle-angle1)<1e-6);
  372. // if (angle>M_PI)
  373. // angle = 2*M_PI-angle;
  374. // if (angle>.5*M_PI)
  375. // angle = M_PI-angle;
  376. // typename DerivedV::Scalar angle = fabs(arg(u) - arg(v));
  377. // if (angle>M_PI)
  378. // angle = 2*M_PI-angle;
  379. // if (angle>.5*M_PI)
  380. // angle = M_PI-angle;
  381. assert(angle <= .5*M_PI && angle >0);
  382. return angle;
  383. }
  384. template<typename DerivedV, typename DerivedF, typename DerivedO>
  385. IGL_INLINE int igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  386. getNumOutOfBounds()
  387. {
  388. Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> angles;
  389. // computeAngles(angles);
  390. int numOoB = 0;
  391. for (int i =0; i<data.numF; ++i)
  392. {
  393. std::complex<typename DerivedV::Scalar> u(pvU(i,0),pvU(i,1));
  394. std::complex<typename DerivedV::Scalar> v(pvV(i,0),pvV(i,1));
  395. typename DerivedV::Scalar angle = computeAngle(u,v);
  396. // if (angles[i] <thetaMin*M_PI/180)
  397. if (angle <thetaMin*M_PI/180)
  398. numOoB ++;
  399. }
  400. return numOoB;
  401. }
  402. template<typename DerivedV, typename DerivedF, typename DerivedO>
  403. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  404. setCoefficientsFromField()
  405. {
  406. for (int i = 0; i <data.numF; ++i)
  407. {
  408. std::complex<typename DerivedV::Scalar> u(pvU(i,0),pvU(i,1));
  409. std::complex<typename DerivedV::Scalar> v(pvV(i,0),pvV(i,1));
  410. Acoeff(i) = u*u+v*v;
  411. Bcoeff(i) = u*u*v*v;
  412. }
  413. }
  414. template<typename DerivedV, typename DerivedF, typename DerivedO>
  415. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  416. globalStep(const Eigen::Matrix<int, Eigen::Dynamic, 1> &isConstrained,
  417. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &Ak,
  418. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &Bk)
  419. {
  420. setCoefficientsFromField();
  421. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > I;
  422. igl::speye(data.numF, data.numF, I);
  423. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > QA = data.DDA+lambda*I;
  424. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > fA = (-2*lambda*Acoeff).sparseView();
  425. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > QB = data.DDB+lambda*I;
  426. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > fB = (-2*lambda*I*Bcoeff).sparseView();
  427. if(doHardConstraints)
  428. {
  429. minQuadWithKnownMini(QA, fA, isConstrained, Ak, Acoeff);
  430. minQuadWithKnownMini(QB, fB, isConstrained, Bk, Bcoeff);
  431. }
  432. else
  433. {
  434. Eigen::Matrix<int, Eigen::Dynamic, 1>isknown_; isknown_.setZero(data.numF,1);
  435. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> xknown_; xknown_.setZero(0,1);
  436. minQuadWithKnownMini(QA, fA, isknown_, xknown_, Acoeff);
  437. minQuadWithKnownMini(QB, fB, isknown_, xknown_, Bcoeff);
  438. }
  439. setFieldFromCoefficients();
  440. }
  441. template<typename DerivedV, typename DerivedF, typename DerivedO>
  442. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  443. setFieldFromCoefficients()
  444. {
  445. for (int i = 0; i <data.numF; ++i)
  446. {
  447. // poly coefficients: 1, 0, -Acoeff, 0, Bcoeff
  448. // matlab code from roots (given there are no trailing zeros in the polynomial coefficients)
  449. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> polyCoeff(5,1);
  450. polyCoeff<<1., 0., -Acoeff(i), 0., Bcoeff(i);
  451. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> roots;
  452. polyRoots<std::complex<typename DerivedV::Scalar>>(polyCoeff,roots);
  453. std::complex<typename DerivedV::Scalar> u = roots[0];
  454. int maxi = -1;
  455. float maxd = -1;
  456. for (int k =1; k<4; ++k)
  457. {
  458. float dist = abs(roots[k]+u);
  459. if (dist>maxd)
  460. {
  461. maxd = dist;
  462. maxi = k;
  463. }
  464. }
  465. std::complex<typename DerivedV::Scalar> v = roots[maxi];
  466. pvU(i,0) = real(u); pvU(i,1) = imag(u);
  467. pvV(i,0) = real(v); pvV(i,1) = imag(v);
  468. }
  469. }
  470. template<typename DerivedV, typename DerivedF, typename DerivedO>
  471. IGL_INLINE void igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  472. minQuadWithKnownMini(const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &Q,
  473. const Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > &f,
  474. const Eigen::VectorXi isConstrained,
  475. const Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &xknown,
  476. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> &x)
  477. {
  478. int N = Q.rows();
  479. int nc = xknown.rows();
  480. Eigen::VectorXi known; known.setZero(nc,1);
  481. Eigen::VectorXi unknown; unknown.setZero(N-nc,1);
  482. int indk = 0, indu = 0;
  483. for (int i = 0; i<N; ++i)
  484. if (isConstrained[i])
  485. {
  486. known[indk] = i;
  487. indk++;
  488. }
  489. else
  490. {
  491. unknown[indu] = i;
  492. indu++;
  493. }
  494. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> Quu, Quk;
  495. igl::slice(Q,unknown, unknown, Quu);
  496. igl::slice(Q,unknown, known, Quk);
  497. std::vector<typename Eigen::Triplet<std::complex<typename DerivedV::Scalar> > > tripletList;
  498. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > fu(N-nc,1);
  499. igl::slice(f,unknown, Eigen::VectorXi::Zero(1,1), fu);
  500. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar> > rhs = (Quk*xknown).sparseView()+.5*fu;
  501. Eigen::SparseLU< Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>>> solver;
  502. solver.compute(-Quu);
  503. if(solver.info()!=Eigen::Success)
  504. {
  505. std::cerr<<"Decomposition failed!"<<std::endl;
  506. return;
  507. }
  508. Eigen::SparseMatrix<std::complex<typename DerivedV::Scalar>> b = solver.solve(rhs);
  509. if(solver.info()!=Eigen::Success)
  510. {
  511. std::cerr<<"Solving failed!"<<std::endl;
  512. return;
  513. }
  514. indk = 0, indu = 0;
  515. x.setZero(N,1);
  516. for (int i = 0; i<N; ++i)
  517. if (isConstrained[i])
  518. x[i] = xknown[indk++];
  519. else
  520. x[i] = b.coeff(indu++,0);
  521. }
  522. template<typename DerivedV, typename DerivedF, typename DerivedO>
  523. IGL_INLINE bool igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO>::
  524. solve(const Eigen::VectorXi &isConstrained,
  525. const Eigen::PlainObjectBase<DerivedO> &initialSolution,
  526. Eigen::PlainObjectBase<DerivedO> &output,
  527. typename DerivedV::Scalar *lambdaOut)
  528. {
  529. int numConstrained = isConstrained.sum();
  530. // coefficient values
  531. Eigen::Matrix<std::complex<typename DerivedV::Scalar>, Eigen::Dynamic, 1> Ak, Bk;
  532. pvU.resize(data.numF,2);
  533. pvV.resize(data.numF,2);
  534. for (int fi = 0; fi <data.numF; ++fi)
  535. {
  536. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b1 = data.B1.row(fi);
  537. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b2 = data.B2.row(fi);
  538. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &u3 = initialSolution.block(fi,0,1,3);
  539. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &v3 = initialSolution.block(fi,3,1,3);
  540. pvU.row(fi)<< u3.dot(b1), u3.dot(b2);
  541. pvV.row(fi)<< v3.dot(b1), v3.dot(b2);
  542. }
  543. setCoefficientsFromField();
  544. Ak.resize(numConstrained,1);
  545. Bk.resize(numConstrained,1);
  546. int ind = 0;
  547. for (int i = 0; i <data.numF; ++i)
  548. {
  549. if(isConstrained[i])
  550. {
  551. Ak(ind) = Acoeff[i];
  552. Bk(ind) = Bcoeff[i];
  553. ind ++;
  554. }
  555. }
  556. typename DerivedV::Scalar smoothnessValue;
  557. int oob;
  558. smoothnessValue = (Acoeff.adjoint()*data.DDA*Acoeff + Bcoeff.adjoint()*data.DDB*Bcoeff).real()[0];
  559. printf("\n\nInitial smoothness: %.5g\n",smoothnessValue);
  560. oob = getNumOutOfBounds();
  561. printf("\n\nInitial out-of-bounds: %d\n",oob);
  562. printf(" %d %.5g %d\n",-1, smoothnessValue, oob);
  563. lambda = lambdaInit;
  564. for (int iter = 0; iter<maxIter; ++iter)
  565. {
  566. printf("\n\n--- Iteration %d ---\n",iter);
  567. localStep();
  568. globalStep(isConstrained, Ak, Bk);
  569. smoothnessValue = (Acoeff.adjoint()*data.DDA*Acoeff + Bcoeff.adjoint()*data.DDB*Bcoeff).real()[0];
  570. printf("Smoothness: %.5g\n",smoothnessValue);
  571. oob = getNumOutOfBounds();
  572. bool stoppingCriterion = (oob == 0) ;
  573. if (stoppingCriterion)
  574. break;
  575. lambda = lambda*lambdaMultFactor;
  576. // printf(" %d %.5g %d\n",iter, smoothnessValue, oob);
  577. }
  578. output.setZero(data.numF,6);
  579. for (int fi=0; fi<data.numF; ++fi)
  580. {
  581. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b1 = data.B1.row(fi);
  582. const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> &b2 = data.B2.row(fi);
  583. output.block(fi,0, 1, 3) = pvU(fi,0)*b1 + pvU(fi,1)*b2;
  584. output.block(fi,3, 1, 3) = pvV(fi,0)*b1 + pvV(fi,1)*b2;
  585. }
  586. if (lambdaOut)
  587. *lambdaOut = lambda;
  588. return (oob==0);
  589. }
  590. template <typename DerivedV, typename DerivedF, typename DerivedO>
  591. IGL_INLINE bool igl::angle_bound_frame_fields(const Eigen::PlainObjectBase<DerivedV> &V,
  592. const Eigen::PlainObjectBase<DerivedF> &F,
  593. const typename DerivedV::Scalar &thetaMin,
  594. const Eigen::VectorXi &isConstrained,
  595. const Eigen::PlainObjectBase<DerivedO> &initialSolution,
  596. Eigen::PlainObjectBase<DerivedO> &output,
  597. int maxIter,
  598. const typename DerivedV::Scalar &lambdaInit,
  599. const typename DerivedV::Scalar &lambdaMultFactor,
  600. const bool doHardConstraints)
  601. {
  602. igl::AngleBoundFFSolverData<DerivedV, DerivedF> csdata(V, F);
  603. igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO> cs(csdata, thetaMin, maxIter, lambdaInit, lambdaMultFactor, doHardConstraints);
  604. return (cs.solve(isConstrained, initialSolution, output));
  605. }
  606. template <typename DerivedV, typename DerivedF, typename DerivedO>
  607. IGL_INLINE bool igl::angle_bound_frame_fields(const igl::AngleBoundFFSolverData<DerivedV, DerivedF> &csdata,
  608. const typename DerivedV::Scalar &thetaMin,
  609. const Eigen::VectorXi &isConstrained,
  610. const Eigen::PlainObjectBase<DerivedO> &initialSolution,
  611. Eigen::PlainObjectBase<DerivedO> &output,
  612. int maxIter,
  613. const typename DerivedV::Scalar &lambdaInit,
  614. const typename DerivedV::Scalar &lambdaMultFactor,
  615. const bool doHardConstraints,
  616. typename DerivedV::Scalar *lambdaOut)
  617. {
  618. igl::AngleBoundFFSolver<DerivedV, DerivedF, DerivedO> cs(csdata, thetaMin, maxIter, lambdaInit, lambdaMultFactor, doHardConstraints);
  619. return (cs.solve(isConstrained, initialSolution, output, lambdaOut));
  620. }
  621. #ifdef IGL_STATIC_LIBRARY
  622. // Explicit template specialization
  623. #endif