integrable_polyvector_fields.cpp 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2015 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/integrable_polyvector_fields.h>
  9. #include <igl/field_local_global_conversions.h>
  10. #include <igl/parallel_transport_angles.h>
  11. #include <igl/local_basis.h>
  12. #include <igl/edge_topology.h>
  13. #include <igl/sparse.h>
  14. #include <igl/sort.h>
  15. #include <igl/slice.h>
  16. #include <igl/slice_into.h>
  17. #include <igl/sort_vectors_ccw.h>
  18. #include <iostream>
  19. IGL_INLINE igl::integrable_polyvector_fields_parameters::integrable_polyvector_fields_parameters():
  20. numIter(5),
  21. wBarrier(0.1),
  22. sBarrier(0.9),
  23. wCurl(10),
  24. wQuotCurl(10),
  25. wSmooth(1.),
  26. wCloseUnconstrained(1e-3),
  27. wCloseConstrained(100),
  28. redFactor_wsmooth(.8),
  29. gamma(0.1),
  30. tikh_gamma(1e-8),
  31. do_partial(false)
  32. {}
  33. namespace igl {
  34. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  35. class IntegrableFieldSolver
  36. {
  37. private:
  38. IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data;
  39. //Symbolic calculations
  40. IGL_INLINE void rj_barrier_face(const Eigen::RowVectorXd &vec2D_a,
  41. const double &s,
  42. Eigen::VectorXd &residuals,
  43. bool do_jac = false,
  44. Eigen::MatrixXd &J = *(Eigen::MatrixXd*)NULL);
  45. IGL_INLINE void rj_polycurl_edge(const Eigen::RowVectorXd &vec2D_a,
  46. const Eigen::RowVector2d &ea,
  47. const Eigen::RowVectorXd &vec2D_b,
  48. const Eigen::RowVector2d &eb,
  49. Eigen::VectorXd &residuals,
  50. bool do_jac = false,
  51. Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
  52. IGL_INLINE void rj_quotcurl_edge_polyversion(const Eigen::RowVectorXd &vec2D_a,
  53. const Eigen::RowVector2d &ea,
  54. const Eigen::RowVectorXd &vec2D_b,
  55. const Eigen::RowVector2d &eb,
  56. Eigen::VectorXd &residuals,
  57. bool do_jac = false,
  58. Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
  59. IGL_INLINE void rj_smoothness_edge(const Eigen::RowVectorXd &vec2D_a,
  60. const Eigen::RowVectorXd &vec2D_b,
  61. const double &k,
  62. const int nA,
  63. const int nB,
  64. Eigen::VectorXd &residuals,
  65. bool do_jac = false,
  66. Eigen::MatrixXd &Jac = *(Eigen::MatrixXd*)NULL);
  67. public:
  68. IGL_INLINE IntegrableFieldSolver(IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata);
  69. IGL_INLINE bool solve(integrable_polyvector_fields_parameters &params,
  70. Eigen::PlainObjectBase<DerivedFF>& current_field,
  71. bool current_field_is_not_ccw);
  72. IGL_INLINE void solveGaussNewton(integrable_polyvector_fields_parameters &params,
  73. const Eigen::VectorXd &x_initial,
  74. Eigen::VectorXd &x);
  75. //Compute residuals and Jacobian for Gauss Newton
  76. IGL_INLINE double RJ(const Eigen::VectorXd &x,
  77. const Eigen::VectorXd &x0,
  78. const integrable_polyvector_fields_parameters &params,
  79. bool doJacs = false);
  80. IGL_INLINE void RJ_Smoothness(const Eigen::MatrixXd &sol2D,
  81. const double &wSmoothSqrt,
  82. const int startRowInJacobian,
  83. bool doJacs = false,
  84. const int startIndexInVectors = 0);
  85. IGL_INLINE void RJ_Barrier(const Eigen::MatrixXd &sol2D,
  86. const double &s,
  87. const double &wBarrierSqrt,
  88. const int startRowInJacobian,
  89. bool doJacs = false,
  90. const int startIndexInVectors = 0);
  91. IGL_INLINE void RJ_Closeness(const Eigen::MatrixXd &sol2D,
  92. const Eigen::MatrixXd &sol02D,
  93. const double &wCloseUnconstrainedSqrt,
  94. const double &wCloseConstrainedSqrt,
  95. const bool do_partial,
  96. const int startRowInJacobian,
  97. bool doJacs = false,
  98. const int startIndexInVectors = 0);
  99. IGL_INLINE void RJ_Curl(const Eigen::MatrixXd &sol2D,
  100. const double &wCASqrt,
  101. const double &wCBSqrt,
  102. const int startRowInJacobian,
  103. bool doJacs = false,
  104. const int startIndexInVectors = 0);
  105. IGL_INLINE void RJ_QuotCurl(const Eigen::MatrixXd &sol2D,
  106. const double &wQuotCurlSqrt,
  107. const int startRowInJacobian,
  108. bool doJacs = false,
  109. const int startIndexInVectors = 0);
  110. };
  111. };
  112. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  113. IGL_INLINE igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::IntegrableFieldSolverData()
  114. {}
  115. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  116. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  117. precomputeMesh(const Eigen::PlainObjectBase<DerivedV> &_V,
  118. const Eigen::PlainObjectBase<DerivedF> &_F)
  119. {
  120. numV = _V.rows();
  121. numF = _F.rows();
  122. numVariables = 2*2*numF;
  123. //Mesh stuff
  124. igl::edge_topology(_V,_F,E,F2E,E2F);
  125. numE = E.rows();
  126. igl::local_basis(_V,_F,B1,B2,FN);
  127. computeInteriorEdges();
  128. igl::parallel_transport_angles(_V, _F, FN, E2F, F2E, K);
  129. EVecNorm.setZero(numE,3);
  130. for (int k = 0; k<numE; ++k)
  131. EVecNorm.row(k) = (_V.row(E(k,1))-_V.row(E(k,0))).normalized();
  132. }
  133. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  134. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  135. initializeConstraints(const Eigen::VectorXi& b,
  136. const Eigen::PlainObjectBase<DerivedC>& bc,
  137. const Eigen::VectorXi& constraint_level)
  138. {
  139. //save constrained
  140. Eigen::VectorXi iSorted, constrained_unsorted;
  141. constrained_unsorted.resize(2*2*b.size());
  142. is_constrained_face.setZero(numF, 1);
  143. int ind = 0;
  144. indInConstrained.setConstant(numF,1,-1);
  145. for (int k =0; k<b.size(); ++k)
  146. {
  147. is_constrained_face[b[k]] = constraint_level[k];
  148. for (int i=0; i<2;++i)
  149. {
  150. int xi = 2*2*b[k] + 2*i +0;
  151. int yi = 2*2*b[k] + 2*i +1;
  152. constrained_unsorted[ind++] = xi;
  153. constrained_unsorted[ind++] = yi;
  154. }
  155. indInConstrained[b[k]] = k;
  156. }
  157. //sort in descending order (so removing rows will work)
  158. igl::sort(constrained_unsorted, 1, false, constrained, iSorted);
  159. constrained_vec3 = bc.template cast<double>();
  160. }
  161. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  162. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  163. makeFieldCCW(Eigen::MatrixXd &sol3D)
  164. {
  165. //sort ccw
  166. Eigen::RowVectorXd t;
  167. Eigen::RowVectorXd all(1,2*2*3);
  168. Eigen::VectorXi order;
  169. for (int fi=0; fi<numF; ++fi)
  170. {
  171. //take all 4 vectors (including opposites) and pick two that are in ccw order
  172. all << sol3D.row(fi), -sol3D.row(fi);
  173. igl::sort_vectors_ccw(all, FN.row(fi).eval(), order, true, t);
  174. //if we are in a constrained face, we need to make sure that the first vector is always the same vector as in the constraints
  175. if(is_constrained_face[fi])
  176. {
  177. const Eigen::RowVector3d &constraint = constrained_vec3.block(indInConstrained[fi], 0, 1, 3);;
  178. int best_i = -1; double best_score = std::numeric_limits<double>::max();
  179. for (int i = 0; i<2*2; ++i)
  180. {
  181. double score = (t.segment(i*3,3) - constraint).norm();
  182. if (score<best_score)
  183. {
  184. best_score = score;
  185. best_i = i;
  186. }
  187. }
  188. //do a circshift
  189. Eigen::RowVectorXd temp = t.segment(0, 3*best_i);
  190. int s1 = 3*best_i;
  191. int n2 = 3*best_i;
  192. int n1 = 3*2*2-n2;
  193. t.segment(0,n1) = t.segment(s1,n1);
  194. t.segment(n1, n2) = temp;
  195. }
  196. sol3D.row(fi) = t.segment(0, 2*3);
  197. }
  198. }
  199. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  200. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  201. initializeOriginalVariable(const Eigen::PlainObjectBase<DerivedFF>& original_field)
  202. {
  203. Eigen::MatrixXd sol2D;
  204. Eigen::MatrixXd sol3D = original_field.template cast<double>();
  205. makeFieldCCW(sol3D);
  206. igl::global2local(B1, B2, sol3D, sol2D);
  207. xOriginal.setZero(numVariables);
  208. for (int i =0; i<numF; i++)
  209. xOriginal.segment(i*2*2, 2*2) = sol2D.row(i);
  210. }
  211. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  212. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  213. computeInteriorEdges()
  214. {
  215. Eigen::VectorXi isBorderEdge;
  216. // Flag border edges
  217. numInteriorEdges = 0;
  218. isBorderEdge.setZero(numE,1);
  219. indFullToInterior = -1.*Eigen::VectorXi::Ones(numE,1);
  220. for(unsigned i=0; i<numE; ++i)
  221. {
  222. if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
  223. isBorderEdge[i] = 1;
  224. else
  225. {
  226. indFullToInterior[i] = numInteriorEdges;
  227. numInteriorEdges++;
  228. }
  229. }
  230. E2F_int.resize(numInteriorEdges, 2);
  231. indInteriorToFull.setZero(numInteriorEdges,1);
  232. int ii = 0;
  233. for (int k=0; k<numE; ++k)
  234. {
  235. if (isBorderEdge[k])
  236. continue;
  237. E2F_int.row(ii) = E2F.row(k);
  238. indInteriorToFull[ii] = k;
  239. ii++;
  240. }
  241. }
  242. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  243. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  244. add_Jacobian_to_svector(const int &toplace,
  245. const Eigen::MatrixXd &tJac,
  246. Eigen::VectorXd &SS_Jac)
  247. {
  248. int numInnerRows = tJac.rows();
  249. int numInnerCols = tJac.cols();
  250. int ind = toplace;
  251. for (int j=0; j<numInnerRows; ++j)
  252. for (int k=0; k<numInnerCols; ++k, ++ind)
  253. SS_Jac(ind) = tJac(j,k);
  254. }
  255. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  256. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  257. add_jac_indices_face(const int numInnerRows,
  258. const int numInnerCols,
  259. const int startRowInJacobian,
  260. const int startIndexInVectors,
  261. Eigen::VectorXi &Rows,
  262. Eigen::VectorXi &Columns)
  263. {
  264. for (int fi=0; fi<numF; ++fi)
  265. {
  266. int startRow = startRowInJacobian+numInnerRows*fi;
  267. int startIndex = startIndexInVectors+numInnerRows*numInnerCols*fi;
  268. face_Jacobian_indices(startRow, startIndex, fi, 2, numInnerRows, numInnerCols, Rows, Columns);
  269. }
  270. }
  271. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  272. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  273. face_Jacobian_indices(const int &startRow,
  274. const int &toplace,
  275. const int& fi,
  276. const int& half_degree,
  277. const int &numInnerRows,
  278. const int &numInnerCols,
  279. Eigen::VectorXi &rows,
  280. Eigen::VectorXi &columns)
  281. {
  282. int ind = toplace;
  283. for (int j=0; j<numInnerRows; ++j)
  284. {
  285. for (int k=0; k<numInnerCols; ++k, ++ind)
  286. {
  287. int iv = k/2;//which vector (0..half_degree-1) am i at
  288. int ixy = k%2;//which part (real/imag) am i at
  289. rows(ind) = startRow+j;
  290. columns(ind) = 2*half_degree*fi + 2*iv +ixy;
  291. }
  292. }
  293. }
  294. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  295. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  296. add_jac_indices_edge(const int numInnerRows,
  297. const int numInnerCols,
  298. const int startRowInJacobian,
  299. const int startIndexInVectors,
  300. Eigen::VectorXi &Rows,
  301. Eigen::VectorXi &Columns)
  302. {
  303. for (int ii=0; ii<numInteriorEdges; ++ii)
  304. {
  305. // the two faces of the flap
  306. int a = E2F_int(ii,0);
  307. int b = E2F_int(ii,1);
  308. int startRow = startRowInJacobian+numInnerRows*ii;
  309. int startIndex = startIndexInVectors+numInnerRows*numInnerCols*ii;
  310. edge_Jacobian_indices(startRow, startIndex, a, b, 2, numInnerRows, numInnerCols, Rows, Columns);
  311. }
  312. }
  313. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  314. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  315. edge_Jacobian_indices(const int &startRow,
  316. const int &toplace,
  317. const int& a,
  318. const int& b,
  319. const int& half_degree,
  320. const int &numInnerRows,
  321. const int &numInnerCols,
  322. Eigen::VectorXi &rows,
  323. Eigen::VectorXi &columns)
  324. {
  325. int ind = toplace;
  326. for (int j=0; j<numInnerRows; ++j)
  327. {
  328. for (int k=0; k<numInnerCols; ++k, ++ind)
  329. {
  330. int f = (k<2*half_degree)?a:b;//which face i am at
  331. int iv = (k%(2*half_degree))/2;//which vector (0..half_degree-1) am i at
  332. int ixy = k%2;//which part (real/imag) am i at
  333. rows(ind) = startRow+j;
  334. columns(ind) = 2*half_degree*f + 2*iv +ixy;
  335. }
  336. }
  337. }
  338. template<typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  339. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  340. computeJacobianPattern()
  341. {
  342. num_residuals_smooth = 4*numInteriorEdges;
  343. num_residuals_close = 4*numF;
  344. num_residuals_polycurl = 2*numInteriorEdges;
  345. num_residuals_quotcurl = numInteriorEdges;
  346. num_residuals_barrier = numF;
  347. num_residuals = num_residuals_smooth + num_residuals_close + num_residuals_polycurl + num_residuals_quotcurl + num_residuals_barrier;
  348. residuals.setZero(num_residuals,1);
  349. //per edge
  350. numJacElements_smooth = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_smooth;
  351. numJacElements_polycurl = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_polycurl;
  352. numJacElements_quotcurl = numInteriorEdges*numInnerJacCols_edge*numInnerJacRows_quotcurl;
  353. //per face
  354. numJacElements_barrier = numF*numInnerJacCols_face*numInnerJacRows_barrier;
  355. numJacElements_close = numF*numInnerJacCols_face*numInnerJacRows_close;
  356. numJacElements = (numJacElements_smooth +numJacElements_polycurl + numJacElements_quotcurl) + (numJacElements_barrier +numJacElements_close);
  357. //allocate
  358. II_Jac.setZero(numJacElements);
  359. JJ_Jac.setZero(numJacElements);
  360. SS_Jac.setOnes(numJacElements);
  361. //set stuff (attention: order !)
  362. int startRowInJacobian = 0;
  363. int startIndexInVectors = 0;
  364. //smoothness
  365. add_jac_indices_edge(numInnerJacRows_smooth,
  366. numInnerJacCols_edge,
  367. startRowInJacobian,
  368. startIndexInVectors,
  369. II_Jac,
  370. JJ_Jac);
  371. startRowInJacobian += num_residuals_smooth;
  372. startIndexInVectors += numJacElements_smooth;
  373. //closeness
  374. add_jac_indices_face(numInnerJacRows_close,
  375. numInnerJacCols_face,
  376. startRowInJacobian,
  377. startIndexInVectors,
  378. II_Jac,
  379. JJ_Jac);
  380. startRowInJacobian += num_residuals_close;
  381. startIndexInVectors += numJacElements_close;
  382. //barrier
  383. add_jac_indices_face(numInnerJacRows_barrier,
  384. numInnerJacCols_face,
  385. startRowInJacobian,
  386. startIndexInVectors,
  387. II_Jac,
  388. JJ_Jac);
  389. startRowInJacobian += num_residuals_barrier;
  390. startIndexInVectors += numJacElements_barrier;
  391. //polycurl
  392. add_jac_indices_edge(numInnerJacRows_polycurl,
  393. numInnerJacCols_edge,
  394. startRowInJacobian,
  395. startIndexInVectors,
  396. II_Jac,
  397. JJ_Jac);
  398. startRowInJacobian += num_residuals_polycurl;
  399. startIndexInVectors += numJacElements_polycurl;
  400. //quotcurl
  401. add_jac_indices_edge(numInnerJacRows_quotcurl,
  402. numInnerJacCols_edge,
  403. startRowInJacobian,
  404. startIndexInVectors,
  405. II_Jac,
  406. JJ_Jac);
  407. igl::sparse(II_Jac, JJ_Jac, SS_Jac, Jac);
  408. }
  409. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  410. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  411. computeHessianPattern()
  412. {
  413. //II_Jac is sorted in ascending order already
  414. int starti = 0;
  415. int currI = II_Jac(0);
  416. for (int ii = 0; ii<II_Jac.rows(); ++ii)
  417. {
  418. if(currI != II_Jac(ii))
  419. {
  420. starti = ii;
  421. currI = II_Jac(ii);
  422. }
  423. int k1 = II_Jac(ii);
  424. for (int jj = starti; jj<II_Jac.rows(); ++jj)
  425. {
  426. int k2 = II_Jac(jj);
  427. if (k1 !=k2)
  428. break;
  429. indInSS_Hess_1_vec.push_back(ii);
  430. indInSS_Hess_2_vec.push_back(jj);
  431. Hess_triplets.push_back(Eigen::Triplet<double> (JJ_Jac(ii),
  432. JJ_Jac(jj),
  433. SS_Jac(ii)*SS_Jac(jj)
  434. )
  435. );
  436. }
  437. }
  438. Hess.resize(Jac.cols(),Jac.cols());
  439. Hess.setFromTriplets(Hess_triplets.begin(), Hess_triplets.end());
  440. Hess.makeCompressed();
  441. }
  442. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  443. IGL_INLINE void igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC>::
  444. computeNewHessValues()
  445. {
  446. for (int i =0; i<Hess_triplets.size(); ++i)
  447. Hess_triplets[i] = Eigen::Triplet<double>(Hess_triplets[i].row(),
  448. Hess_triplets[i].col(),
  449. SS_Jac(indInSS_Hess_1_vec[i])*SS_Jac(indInSS_Hess_2_vec[i])
  450. );
  451. Hess.setFromTriplets(Hess_triplets.begin(), Hess_triplets.end());
  452. }
  453. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  454. IGL_INLINE igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::IntegrableFieldSolver( IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata):
  455. data(cffsoldata)
  456. { };
  457. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  458. IGL_INLINE bool igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  459. solve(igl::integrable_polyvector_fields_parameters &params,
  460. Eigen::PlainObjectBase<DerivedFF>& current_field,
  461. bool current_field_is_not_ccw)
  462. {
  463. Eigen::MatrixXd sol2D;
  464. Eigen::MatrixXd sol3D = current_field.template cast<double>();
  465. if (current_field_is_not_ccw)
  466. data.makeFieldCCW(sol3D);
  467. igl::global2local(data.B1, data.B2, sol3D, sol2D);
  468. Eigen::VectorXd x;
  469. x.setZero(data.numVariables);
  470. for (int i =0; i<data.numF; i++)
  471. x.segment(i*2*2, 2*2) = sol2D.row(i);
  472. //get x
  473. solveGaussNewton(params, data.xOriginal, x);
  474. //get output from x
  475. for (int i =0; i<data.numF; i++)
  476. sol2D.row(i) = x.segment(i*2*2, 2*2);
  477. igl::local2global(data.B1, data.B2, sol2D, sol3D);
  478. current_field = sol3D.cast<typename DerivedFF::Scalar>();
  479. return true;
  480. }
  481. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  482. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  483. solveGaussNewton(integrable_polyvector_fields_parameters &params,
  484. const Eigen::VectorXd &x_initial,
  485. Eigen::VectorXd &x)
  486. {
  487. bool converged = false;
  488. double F;
  489. Eigen::VectorXd xprev = x;
  490. Eigen::VectorXd xc = igl::slice(x_initial, data.constrained, 1);
  491. // double ESmooth, EClose, ECurl, EQuotCurl, EBarrier;
  492. for (int innerIter = 0; innerIter<params.numIter; ++innerIter)
  493. {
  494. //set constrained entries to those of the initial
  495. igl::slice_into(xc, data.constrained, 1, xprev);
  496. //get function, gradients and Hessians
  497. F = RJ(x, xprev, params, true);
  498. printf("IntegrableFieldSolver -- Iteration %d\n", innerIter);
  499. if((data.residuals.array() == std::numeric_limits<double>::infinity()).any())
  500. {
  501. std::cerr<<"IntegrableFieldSolver -- residuals: got infinity somewhere"<<std::endl;
  502. exit(1);
  503. };
  504. if((data.residuals.array() != data.residuals.array()).any())
  505. {
  506. std::cerr<<"IntegrableFieldSolver -- residuals: got infinity somewhere"<<std::endl;
  507. exit(1);
  508. };
  509. converged = false;
  510. Eigen::VectorXd rhs = data.Jac.transpose()*data.residuals;
  511. bool success;
  512. data.solver.factorize(data.Hess);
  513. success = data.solver.info() == Eigen::Success;
  514. if(!success)
  515. std::cerr<<"IntegrableFieldSolver -- Could not do LU"<<std::endl;
  516. Eigen::VectorXd direction;
  517. double error;
  518. direction = data.solver.solve(rhs);
  519. error = (data.Hess*direction - rhs).cwiseAbs().maxCoeff();
  520. if(error> 1e-4)
  521. {
  522. std::cerr<<"IntegrableFieldSolver -- Could not solve"<<std::endl;
  523. }
  524. // adaptive backtracking
  525. bool repeat = true;
  526. int run = 0;
  527. Eigen::VectorXd cx;
  528. Eigen::VectorXd tRes;
  529. double newF;
  530. while(repeat)
  531. {
  532. cx = x - params.gamma*direction;
  533. newF = RJ(cx, xprev, params);
  534. if(newF < F)
  535. {
  536. repeat = false;
  537. if(run == 0)
  538. params.gamma *= 2;
  539. }
  540. else
  541. {
  542. params.gamma *= 0.5f;
  543. if(params.gamma<1e-30)
  544. {
  545. repeat = false;
  546. converged = true;
  547. }
  548. }
  549. run++;
  550. }
  551. if (!converged)
  552. {
  553. xprev = x;
  554. x = cx;
  555. }
  556. else
  557. {
  558. std::cerr<<"IntegrableFieldSolver -- Converged"<<std::endl;
  559. break;
  560. }
  561. }
  562. }
  563. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  564. IGL_INLINE double igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  565. RJ(const Eigen::VectorXd &x,
  566. const Eigen::VectorXd &x0,
  567. const integrable_polyvector_fields_parameters &params,
  568. bool doJacs)
  569. {
  570. Eigen::MatrixXd sol2D(data.numF,4), sol02D(data.numF,4);
  571. for (int i =0; i<data.numF; i++)
  572. sol2D.row(i) = x.segment(i*2*2, 2*2);
  573. for (int i =0; i<data.numF; i++)
  574. sol02D.row(i) = x0.segment(i*2*2, 2*2);
  575. data.SS_Jac.setZero(data.numJacElements);
  576. //set stuff (attention: order !)
  577. int startRowInJacobian = 0;
  578. int startIndexInVectors = 0;
  579. //smoothness
  580. RJ_Smoothness(sol2D, sqrt(params.wSmooth), startRowInJacobian, doJacs, startIndexInVectors);
  581. startRowInJacobian += data.num_residuals_smooth;
  582. startIndexInVectors += data.numJacElements_smooth;
  583. //closeness
  584. RJ_Closeness(sol2D, sol02D, sqrt(params.wCloseUnconstrained), sqrt(params.wCloseConstrained), params.do_partial, startRowInJacobian, doJacs, startIndexInVectors);
  585. startRowInJacobian += data.num_residuals_close;
  586. startIndexInVectors += data.numJacElements_close;
  587. //barrier
  588. RJ_Barrier(sol2D, params.sBarrier, sqrt(params.wBarrier), startRowInJacobian, doJacs, startIndexInVectors);
  589. startRowInJacobian += data.num_residuals_barrier;
  590. startIndexInVectors += data.numJacElements_barrier;
  591. //polycurl
  592. RJ_Curl(sol2D, params.wCurl, powl(params.wCurl, 2), startRowInJacobian, doJacs, startIndexInVectors);
  593. startRowInJacobian += data.num_residuals_polycurl;
  594. startIndexInVectors += data.numJacElements_polycurl;
  595. //quotcurl
  596. RJ_QuotCurl(sol2D, sqrt(params.wQuotCurl), startRowInJacobian, doJacs, startIndexInVectors);
  597. if(doJacs)
  598. {
  599. for (int i =0; i<data.numJacElements; ++i)
  600. data.Jac.coeffRef(data.II_Jac(i), data.JJ_Jac(i)) = data.SS_Jac(i);
  601. data.computeNewHessValues();
  602. }
  603. return data.residuals.transpose()*data.residuals;
  604. }
  605. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  606. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  607. rj_smoothness_edge(const Eigen::RowVectorXd &vec2D_a,
  608. const Eigen::RowVectorXd &vec2D_b,
  609. const double &k,
  610. const int nA,
  611. const int nB,
  612. Eigen::VectorXd &residuals,
  613. bool do_jac,
  614. Eigen::MatrixXd &Jac)
  615. {
  616. const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
  617. const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
  618. const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
  619. const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
  620. const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
  621. const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
  622. double xua_2 = xua*xua;
  623. double xva_2 = xva*xva;
  624. double yua_2 = yua*yua;
  625. double yva_2 = yva*yva;
  626. double xub_2 = xub*xub;
  627. double xvb_2 = xvb*xvb;
  628. double yub_2 = yub*yub;
  629. double yvb_2 = yvb*yvb;
  630. double sA = sin(nA*k);
  631. double cA = cos(nA*k);
  632. double sB = sin(nB*k);
  633. double cB = cos(nB*k);
  634. double t1 = xua*yua;
  635. double t2 = xva*yva;
  636. double t3 = xub*xvb;
  637. double t4 = yub*yvb;
  638. double t5 = xua*xva;
  639. double t6 = xub*yub;
  640. double t7 = yua*yva;
  641. double t8 = xvb*yvb;
  642. double t9 = xva_2 - yva_2;
  643. double t10 = xua_2 - yua_2;
  644. double t11 = xvb_2 - yvb_2;
  645. double t12 = xub_2 - yub_2;
  646. double t13 = 2*t1 + 2*t2;
  647. double t17 = (2*t1*t9 + 2*t2*t10);
  648. double t19 = (t10*t9 - 4*t5*t7);
  649. residuals.resize(4, 1);
  650. residuals <<
  651. cA*(t10 + t9) - sA*(t13) - t12 - t11,
  652. sA*(t10 + t9) - 2*t8 - 2*t6 + cA*(t13),
  653. cB*t19 - (t12)*(t11) - sB*t17 + 4*t3*t4,
  654. cB*t17 + sB*t19 - 2*t6*(t11) - 2*t8*(t12);
  655. if (do_jac)
  656. {
  657. double t20 = 2*yua*t9 + 4*xua*t2;
  658. double t21 = 2*xua*t9 - 4*xva*t7;
  659. double t22 = 2*yva*t10 + 4*t5*yua;
  660. double t23 = 2*xva*t10 - 4*t1*yva;
  661. Jac.resize(4,8);
  662. Jac << 2*xua*cA - 2*yua*sA, - 2*yua*cA - 2*xua*sA, 2*xva*cA - 2*yva*sA, - 2*yva*cA - 2*xva*sA, -2*xub, 2*yub, -2*xvb, 2*yvb,
  663. 2*yua*cA + 2*xua*sA, 2*xua*cA - 2*yua*sA, 2*yva*cA + 2*xva*sA, 2*xva*cA - 2*yva*sA, -2*yub, -2*xub, -2*yvb, -2*xvb,
  664. cB*(t21) - sB*(t20), - cB*(t20) - sB*(t21), cB*(t23) - sB*(t22), - cB*(t22) - sB*(t23), 4*xvb*t4 - 2*xub*t11, 2*yub*t11 + 4*t3*yvb, 4*xub*t4 - 2*xvb*t12, 2*yvb*t12 + 4*t3*yub,
  665. cB*(t20) + sB*(t21), cB*(t21) - sB*(t20), cB*(t22) + sB*(t23), cB*(t23) - sB*(t22), - 2*yub*t11 - 4*t3*yvb, 4*xvb*t4 - 2*xub*t11, - 2*yvb*t12 - 4*t3*yub, 4*xub*t4 - 2*xvb*t12;
  666. }
  667. }
  668. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  669. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  670. RJ_Smoothness(const Eigen::MatrixXd &sol2D,
  671. const double &wSmoothSqrt,
  672. const int startRowInJacobian,
  673. bool doJacs,
  674. const int startIndexInVectors)
  675. {
  676. if (wSmoothSqrt ==0)
  677. return;
  678. for (int ii=0; ii<data.numInteriorEdges; ++ii)
  679. {
  680. // the two faces of the flap
  681. int a = data.E2F_int(ii,0);
  682. int b = data.E2F_int(ii,1);
  683. int k = data.indInteriorToFull[ii];
  684. Eigen::MatrixXd tJac;
  685. Eigen::VectorXd tRes;
  686. rj_smoothness_edge(sol2D.row(a),
  687. sol2D.row(b),
  688. data.K[k],
  689. 2*(0+1), //degree of first coefficient
  690. 2*(1+1), //degree of second coefficient
  691. tRes,
  692. doJacs,
  693. tJac);
  694. int startRow = startRowInJacobian+data.numInnerJacRows_smooth*ii;
  695. data.residuals.segment(startRow,data.numInnerJacRows_smooth) = wSmoothSqrt*tRes;
  696. if(doJacs)
  697. {
  698. int startIndex = startIndexInVectors+data.numInnerJacRows_smooth*data.numInnerJacCols_edge*ii;
  699. data.add_Jacobian_to_svector(startIndex, wSmoothSqrt*tJac,data.SS_Jac);
  700. }
  701. }
  702. }
  703. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  704. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  705. rj_barrier_face(const Eigen::RowVectorXd &vec2D_a,
  706. const double &s,
  707. Eigen::VectorXd &residuals,
  708. bool do_jac,
  709. Eigen::MatrixXd &Jac)
  710. {
  711. const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
  712. const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
  713. const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
  714. double xva_2 = xva*xva;
  715. double yua_2 = yua*yua;
  716. double xua_2 = xua*xua;
  717. double yva_2 = yva*yva;
  718. double s_2 = s*s;
  719. double s_3 = s*s_2;
  720. double t00 = xua*yva;
  721. double t01 = xva*yua;
  722. double t05 = t00 - t01;
  723. double t05_2 = t05*t05;
  724. double t05_3 = t05*t05_2;
  725. if (do_jac)
  726. Jac.setZero(1,4);
  727. residuals.resize(1, 1);
  728. if (t05>=s)
  729. residuals << 0;
  730. else if (t05<0)
  731. residuals << std::numeric_limits<double>::infinity();
  732. else
  733. {
  734. residuals << 1/((3*t00 - 3*t01)/s - (3*t05_2)/s_2 + t05_3/s_3) - 1;
  735. double t03 = (s - t05)*(s - t05);
  736. double t06 = (3*s_2 - 3*s*t00 + 3*s*t01 + xua_2*yva_2 - 2*xua*t01*yva + xva_2*yua_2);
  737. double t04 = t06*t06;
  738. if (do_jac)
  739. Jac<<
  740. -(3*s_3*yva*t03)/(t05_2*t04),
  741. (3*s_3*xva*t03)/(t05_2*t04),
  742. (3*s_3*yua*t03)/(t05_2*t04),
  743. -(3*s_3*xua*t03)/(t05_2*t04);
  744. }
  745. }
  746. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  747. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  748. RJ_Barrier(const Eigen::MatrixXd &sol2D,
  749. const double &s,
  750. const double &wBarrierSqrt,
  751. const int startRowInJacobian,
  752. bool doJacs,
  753. const int startIndexInVectors)
  754. {
  755. if (wBarrierSqrt ==0)
  756. return;
  757. for (int fi=0; fi<data.numF; ++fi)
  758. {
  759. Eigen::MatrixXd tJac;
  760. Eigen::VectorXd tRes;
  761. rj_barrier_face(sol2D.row(fi),
  762. s,
  763. tRes,
  764. doJacs,
  765. tJac);
  766. int startRow = startRowInJacobian+ data.numInnerJacRows_barrier * fi;
  767. data.residuals.segment(startRow,data.numInnerJacRows_barrier) = wBarrierSqrt*tRes;
  768. if(doJacs)
  769. {
  770. int startIndex = startIndexInVectors+data.numInnerJacRows_barrier*data.numInnerJacCols_face*fi;
  771. data.add_Jacobian_to_svector(startIndex, wBarrierSqrt*tJac,data.SS_Jac);
  772. }
  773. }
  774. }
  775. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  776. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  777. RJ_Closeness(const Eigen::MatrixXd &sol2D,
  778. const Eigen::MatrixXd &sol02D,
  779. const double &wCloseUnconstrainedSqrt,
  780. const double &wCloseConstrainedSqrt,
  781. const bool do_partial,
  782. const int startRowInJacobian,
  783. bool doJacs,
  784. const int startIndexInVectors)
  785. {
  786. if (wCloseUnconstrainedSqrt ==0 && wCloseConstrainedSqrt ==0)
  787. return;
  788. for (int fi=0; fi<data.numF; ++fi)
  789. {
  790. Eigen::Vector4d weights;
  791. if (!data.is_constrained_face[fi])
  792. weights.setConstant(wCloseUnconstrainedSqrt);
  793. else
  794. {
  795. if (do_partial&&data.is_constrained_face[fi]==1)
  796. //only constrain the first vector
  797. weights<<wCloseConstrainedSqrt,wCloseConstrainedSqrt,wCloseUnconstrainedSqrt,wCloseUnconstrainedSqrt;
  798. else
  799. //either not partial, or partial with 2 constraints
  800. weights.setConstant(wCloseConstrainedSqrt);
  801. }
  802. Eigen::MatrixXd tJac;
  803. Eigen::VectorXd tRes;
  804. tJac = Eigen::MatrixXd::Identity(4,4);
  805. tRes.resize(4, 1); tRes<<(sol2D.row(fi)-sol02D.row(fi)).transpose();
  806. int startRow = startRowInJacobian+data.numInnerJacRows_close*fi;
  807. data.residuals.segment(startRow,data.numInnerJacRows_close) = weights.array()*tRes.array();
  808. if(doJacs)
  809. {
  810. int startIndex = startIndexInVectors+data.numInnerJacRows_close*data.numInnerJacCols_face*fi;
  811. data.add_Jacobian_to_svector(startIndex, weights.asDiagonal()*tJac,data.SS_Jac);
  812. }
  813. }
  814. }
  815. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  816. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  817. rj_polycurl_edge(const Eigen::RowVectorXd &vec2D_a,
  818. const Eigen::RowVector2d &ea,
  819. const Eigen::RowVectorXd &vec2D_b,
  820. const Eigen::RowVector2d &eb,
  821. Eigen::VectorXd &residuals,
  822. bool do_jac,
  823. Eigen::MatrixXd &Jac)
  824. {
  825. const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
  826. const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
  827. const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
  828. const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
  829. const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
  830. const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
  831. const double &xea=ea[0], &yea=ea[1];
  832. const double &xeb=eb[0], &yeb=eb[1];
  833. const double dua = (xea*xua + yea*yua);
  834. const double dub = (xeb*xub + yeb*yub);
  835. const double dva = (xea*xva + yea*yva);
  836. const double dvb = (xeb*xvb + yeb*yvb);
  837. const double dua_2 = dua*dua;
  838. const double dva_2 = dva*dva;
  839. const double dub_2 = dub*dub;
  840. const double dvb_2 = dvb*dvb;
  841. residuals.resize(2, 1);
  842. residuals << dua_2 - dub_2 + dva_2 - dvb_2,
  843. dua_2*dva_2 - dub_2*dvb_2 ;
  844. if (do_jac)
  845. {
  846. Jac.resize(2,8);
  847. Jac << 2*xea*dua, 2*yea*dua, 2*xea*dva, 2*yea*dva, -2*xeb*dub, -2*yeb*dub, -2*xeb*dvb, -2*yeb*dvb,
  848. 2*xea*dua*dva_2, 2*yea*dua*dva_2, 2*xea*dua_2*dva, 2*yea*dua_2*dva, -2*xeb*dub*dvb_2, -2*yeb*dub*dvb_2, -2*xeb*dub_2*dvb, -2*yeb*dub_2*dvb;
  849. }
  850. }
  851. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  852. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  853. RJ_Curl(const Eigen::MatrixXd &sol2D,
  854. const double &wCASqrt,
  855. const double &wCBSqrt,
  856. const int startRowInJacobian,
  857. bool doJacs,
  858. const int startIndexInVectors)
  859. {
  860. if((wCASqrt==0) &&(wCBSqrt==0))
  861. return;
  862. for (int ii=0; ii<data.numInteriorEdges; ++ii)
  863. {
  864. // the two faces of the flap
  865. int a = data.E2F_int(ii,0);
  866. int b = data.E2F_int(ii,1);
  867. int k = data.indInteriorToFull[ii];
  868. // the common edge, a 3 vector
  869. const Eigen::RowVector3d &ce = data.EVecNorm.row(k);
  870. // the common edge expressed in local coordinates in the two faces
  871. // x/y denotes real/imaginary
  872. double xea = data.B1.row(a).dot(ce);
  873. double yea = data.B2.row(a).dot(ce);
  874. Eigen::RowVector2d ea; ea<<xea, yea;
  875. double xeb = data.B1.row(b).dot(ce);
  876. double yeb = data.B2.row(b).dot(ce);
  877. Eigen::RowVector2d eb; eb<<xeb, yeb;
  878. Eigen::MatrixXd tJac;
  879. Eigen::VectorXd tRes;
  880. rj_polycurl_edge(sol2D.row(a),
  881. ea,
  882. sol2D.row(b),
  883. eb,
  884. tRes,
  885. doJacs,
  886. tJac);
  887. tRes[0] = tRes[0]*wCASqrt;
  888. tRes[1] = tRes[1]*wCBSqrt;
  889. int startRow = startRowInJacobian+data.numInnerJacRows_polycurl*ii;
  890. data.residuals.segment(startRow,data.numInnerJacRows_polycurl) = tRes;
  891. if(doJacs)
  892. {
  893. tJac.row(0) = tJac.row(0)*wCASqrt;
  894. tJac.row(1) = tJac.row(1)*wCBSqrt;
  895. int startIndex = startIndexInVectors+data.numInnerJacRows_polycurl*data.numInnerJacCols_edge*ii;
  896. data.add_Jacobian_to_svector(startIndex, tJac,data.SS_Jac);
  897. }
  898. }
  899. }
  900. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  901. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  902. rj_quotcurl_edge_polyversion(const Eigen::RowVectorXd &vec2D_a,
  903. const Eigen::RowVector2d &ea,
  904. const Eigen::RowVectorXd &vec2D_b,
  905. const Eigen::RowVector2d &eb,
  906. Eigen::VectorXd &residuals,
  907. bool do_jac,
  908. Eigen::MatrixXd &Jac)
  909. {
  910. const Eigen::RowVector2d &ua = vec2D_a.segment(0, 2);
  911. const Eigen::RowVector2d &va = vec2D_a.segment(2, 2);
  912. const Eigen::RowVector2d &ub = vec2D_b.segment(0, 2);
  913. const Eigen::RowVector2d &vb = vec2D_b.segment(2, 2);
  914. const double &xua=ua[0], &yua=ua[1], &xva=va[0], &yva=va[1];
  915. const double &xub=ub[0], &yub=ub[1], &xvb=vb[0], &yvb=vb[1];
  916. const double &xea=ea[0], &yea=ea[1];
  917. const double &xeb=eb[0], &yeb=eb[1];
  918. double dua = (xea*xua + yea*yua);
  919. double dva = (xea*xva + yea*yva);
  920. double dub = (xeb*xub + yeb*yub);
  921. double dvb = (xeb*xvb + yeb*yvb);
  922. double dua_2 = dua * dua;
  923. double dva_2 = dva * dva;
  924. double dub_2 = dub * dub;
  925. double dvb_2 = dvb * dvb;
  926. double t00 = (dub_2 - dvb_2);
  927. double t01 = (dua_2 - dva_2);
  928. residuals.resize(1, 1);
  929. residuals << dua*dva*t00 - dub*dvb*t01;
  930. if (do_jac)
  931. {
  932. Jac.resize(1,8);
  933. Jac << xea*dva*t00 - 2*xea*dua*dub*dvb, yea*dva*t00 - 2*yea*dua*dub*dvb, xea*dua*t00 + 2*xea*dub*dva*dvb, yea*dua*t00 + 2*yea*dub*dva*dvb, 2*xeb*dua*dub*dva - xeb*dvb*t01, 2*yeb*dua*dub*dva - yeb*dvb*t01, - xeb*dub*t01 - 2*xeb*dua*dva*dvb, - yeb*dub*t01 - 2*yeb*dua*dva*dvb;
  934. }
  935. }
  936. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  937. IGL_INLINE void igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC>::
  938. RJ_QuotCurl(const Eigen::MatrixXd &sol2D,
  939. const double &wQuotCurlSqrt,
  940. const int startRowInJacobian,
  941. bool doJacs,
  942. const int startIndexInVectors)
  943. {
  944. for (int ii=0; ii<data.numInteriorEdges; ++ii)
  945. {
  946. // the two faces of the flap
  947. int a = data.E2F_int(ii,0);
  948. int b = data.E2F_int(ii,1);
  949. int k = data.indInteriorToFull[ii];
  950. // the common edge, a 3 vector
  951. const Eigen::RowVector3d &ce = data.EVecNorm.row(k);
  952. // the common edge expressed in local coordinates in the two faces
  953. // x/y denotes real/imaginary
  954. double xea = data.B1.row(a).dot(ce);
  955. double yea = data.B2.row(a).dot(ce);
  956. Eigen::RowVector2d ea; ea<<xea, yea;
  957. double xeb = data.B1.row(b).dot(ce);
  958. double yeb = data.B2.row(b).dot(ce);
  959. Eigen::RowVector2d eb; eb<<xeb, yeb;
  960. Eigen::MatrixXd tJac;
  961. Eigen::VectorXd tRes;
  962. rj_quotcurl_edge_polyversion(sol2D.row(a),
  963. ea,
  964. sol2D.row(b),
  965. eb,
  966. tRes,
  967. doJacs,
  968. tJac);
  969. int startRow = startRowInJacobian+ data.numInnerJacRows_quotcurl*ii;
  970. data.residuals.segment(startRow,data.numInnerJacRows_quotcurl) = wQuotCurlSqrt*tRes;
  971. if(doJacs)
  972. {
  973. int startIndex = startIndexInVectors+data.numInnerJacRows_quotcurl*data.numInnerJacCols_edge*ii;
  974. data.add_Jacobian_to_svector(startIndex, wQuotCurlSqrt*tJac,data.SS_Jac);
  975. }
  976. }
  977. }
  978. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  979. IGL_INLINE void igl::integrable_polyvector_fields_precompute(
  980. const Eigen::PlainObjectBase<DerivedV>& V,
  981. const Eigen::PlainObjectBase<DerivedF>& F,
  982. const Eigen::VectorXi& b,
  983. const Eigen::PlainObjectBase<DerivedC>& bc,
  984. const Eigen::VectorXi& constraint_level,
  985. const Eigen::PlainObjectBase<DerivedFF>& original_field,
  986. igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &data)
  987. {
  988. data.precomputeMesh(V,F);
  989. data.computeJacobianPattern();
  990. data.computeHessianPattern();
  991. data.solver.analyzePattern(data.Hess);
  992. data.initializeConstraints(b,bc,constraint_level);
  993. data.initializeOriginalVariable(original_field);
  994. };
  995. template <typename DerivedV, typename DerivedF, typename DerivedFF, typename DerivedC>
  996. IGL_INLINE void igl::integrable_polyvector_fields_solve(igl::IntegrableFieldSolverData<DerivedV, DerivedF, DerivedFF, DerivedC> &cffsoldata,
  997. integrable_polyvector_fields_parameters &params,
  998. Eigen::PlainObjectBase<DerivedFF>& current_field,
  999. bool current_field_is_not_ccw)
  1000. {
  1001. igl::IntegrableFieldSolver<DerivedV, DerivedF, DerivedFF, DerivedC> cffs(cffsoldata);
  1002. cffs.solve(params, current_field, current_field_is_not_ccw);
  1003. };
  1004. #ifdef IGL_STATIC_LIBRARY
  1005. // Explicit template specialization
  1006. template igl::IntegrableFieldSolverData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >::IntegrableFieldSolverData();
  1007. template void igl::integrable_polyvector_fields_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::IntegrableFieldSolverData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, igl::integrable_polyvector_fields_parameters&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, bool);
  1008. template void igl::integrable_polyvector_fields_precompute<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 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::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::IntegrableFieldSolverData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  1009. #endif