integrable_polyvector_fields.cpp 43 KB

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