arap_dof.cpp 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Alec Jacobson <alecjacobson@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 "arap_dof.h"
  9. #include "cotmatrix.h"
  10. #include "massmatrix.h"
  11. #include "speye.h"
  12. #include "repdiag.h"
  13. #include "repmat.h"
  14. #include "slice.h"
  15. #include "colon.h"
  16. #include "full.h"
  17. #include "is_sparse.h"
  18. #include "mode.h"
  19. #include "is_symmetric.h"
  20. #include "group_sum_matrix.h"
  21. #include "arap_rhs.h"
  22. #include "covariance_scatter_matrix.h"
  23. #include "fit_rotations.h"
  24. #include "verbose.h"
  25. #include "print_ijv.h"
  26. #include "get_seconds_hires.h"
  27. //#include "MKLEigenInterface.h"
  28. #include "min_quad_dense.h"
  29. #include "get_seconds.h"
  30. #include "columnize.h"
  31. // defined if no early exit is supported, i.e., always take a fixed number of iterations
  32. #define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  33. // A carefull derivation of this implementation is given in the corresponding
  34. // matlab function arap_dof.m
  35. template <typename LbsMatrixType, typename SSCALAR>
  36. IGL_INLINE bool igl::arap_dof_precomputation(
  37. const Eigen::MatrixXd & V,
  38. const Eigen::MatrixXi & F,
  39. const LbsMatrixType & M,
  40. const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
  41. ArapDOFData<LbsMatrixType, SSCALAR> & data)
  42. {
  43. using namespace Eigen;
  44. typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
  45. // number of mesh (domain) vertices
  46. int n = V.rows();
  47. // cache problem size
  48. data.n = n;
  49. // dimension of mesh
  50. data.dim = V.cols();
  51. assert(data.dim == M.rows()/n);
  52. assert(data.dim*n == M.rows());
  53. if(data.dim == 3)
  54. {
  55. // Check if z-coordinate is all zeros
  56. if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0)
  57. {
  58. data.effective_dim = 2;
  59. }
  60. }else
  61. {
  62. data.effective_dim = data.dim;
  63. }
  64. // Number of handles
  65. data.m = M.cols()/data.dim/(data.dim+1);
  66. assert(data.m*data.dim*(data.dim+1) == M.cols());
  67. //assert(m == C.rows());
  68. //printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
  69. // Build cotangent laplacian
  70. SparseMatrix<double> Lcot;
  71. //printf("cotmatrix()\n");
  72. cotmatrix(V,F,Lcot);
  73. // Discrete laplacian (should be minus matlab version)
  74. SparseMatrix<double> Lapl = -2.0*Lcot;
  75. #ifdef EXTREME_VERBOSE
  76. cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
  77. endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
  78. Lapl.rows()<<","<<Lapl.cols()<<");"<<endl;
  79. #endif
  80. // Get group sum scatter matrix, when applied sums all entries of the same
  81. // group according to G
  82. SparseMatrix<double> G_sum;
  83. if(G.size() == 0)
  84. {
  85. speye(n,G_sum);
  86. }else
  87. {
  88. // groups are defined per vertex, convert to per face using mode
  89. Eigen::Matrix<int,Eigen::Dynamic,1> GG;
  90. if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
  91. {
  92. MatrixXi GF(F.rows(),F.cols());
  93. for(int j = 0;j<F.cols();j++)
  94. {
  95. Matrix<int,Eigen::Dynamic,1> GFj;
  96. slice(G,F.col(j),GFj);
  97. GF.col(j) = GFj;
  98. }
  99. mode<int>(GF,2,GG);
  100. }else
  101. {
  102. GG=G;
  103. }
  104. //printf("group_sum_matrix()\n");
  105. group_sum_matrix(GG,G_sum);
  106. }
  107. #ifdef EXTREME_VERBOSE
  108. cout<<"G_sumIJV=["<<endl;print_ijv(G_sum,1);cout<<endl<<"];"<<
  109. endl<<"G_sum=sparse(G_sumIJV(:,1),G_sumIJV(:,2),G_sumIJV(:,3),"<<
  110. G_sum.rows()<<","<<G_sum.cols()<<");"<<endl;
  111. #endif
  112. // Get covariance scatter matrix, when applied collects the covariance matrices
  113. // used to fit rotations to during optimization
  114. SparseMatrix<double> CSM;
  115. //printf("covariance_scatter_matrix()\n");
  116. covariance_scatter_matrix(V,F,data.energy,CSM);
  117. #ifdef EXTREME_VERBOSE
  118. cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
  119. endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
  120. CSM.rows()<<","<<CSM.cols()<<");"<<endl;
  121. #endif
  122. // Build the covariance matrix "constructor". This is a set of *scatter*
  123. // matrices that when multiplied on the right by column of the transformation
  124. // matrix entries (the degrees of freedom) L, we get a stack of dim by 1
  125. // covariance matrix column, with a column in the stack for each rotation
  126. // *group*. The output is a list of matrices because we construct each column
  127. // in the stack of covariance matrices with an independent matrix-vector
  128. // multiplication.
  129. //
  130. // We want to build S which is a stack of dim by dim covariance matrices.
  131. // Thus S is dim*g by dim, where dim is the number of dimensions and g is the
  132. // number of groups. We can precompute dim matrices CSM_M such that column i
  133. // in S is computed as S(:,i) = CSM_M{i} * L, where L is a column of the
  134. // skinning transformation matrix values. To be clear, the covariance matrix
  135. // for group k is then given as the dim by dim matrix pulled from the stack:
  136. // S((k-1)*dim + 1:dim,:)
  137. // Apply group sum to each dimension's block of covariance scatter matrix
  138. SparseMatrix<double> G_sum_dim;
  139. repdiag(G_sum,data.dim,G_sum_dim);
  140. CSM = G_sum_dim * CSM;
  141. #ifdef EXTREME_VERBOSE
  142. cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
  143. endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
  144. CSM.rows()<<","<<CSM.cols()<<");"<<endl;
  145. #endif
  146. //printf("CSM_M()\n");
  147. // Precompute CSM times M for each dimension
  148. data.CSM_M.resize(data.dim);
  149. #ifdef EXTREME_VERBOSE
  150. cout<<"data.CSM_M = cell("<<data.dim<<",1);"<<endl;
  151. #endif
  152. // span of integers from 0 to n-1
  153. Eigen::Matrix<int,Eigen::Dynamic,1> span_n(n);
  154. for(int i = 0;i<n;i++)
  155. {
  156. span_n(i) = i;
  157. }
  158. // span of integers from 0 to M.cols()-1
  159. Eigen::Matrix<int,Eigen::Dynamic,1> span_mlbs_cols(M.cols());
  160. for(int i = 0;i<M.cols();i++)
  161. {
  162. span_mlbs_cols(i) = i;
  163. }
  164. // number of groups
  165. int k = CSM.rows()/data.dim;
  166. for(int i = 0;i<data.dim;i++)
  167. {
  168. //printf("CSM_M(): Mi\n");
  169. LbsMatrixType M_i;
  170. //printf("CSM_M(): slice\n");
  171. slice(M,(span_n.array()+i*n).matrix(),span_mlbs_cols,M_i);
  172. LbsMatrixType M_i_dim;
  173. data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1));
  174. assert(data.CSM_M[i].cols() == M.cols());
  175. for(int j = 0;j<data.dim;j++)
  176. {
  177. SparseMatrix<double> CSMj;
  178. //printf("CSM_M(): slice\n");
  179. slice(
  180. CSM,
  181. colon<int>(j*k,(j+1)*k-1),
  182. colon<int>(j*n,(j+1)*n-1),
  183. CSMj);
  184. assert(CSMj.rows() == k);
  185. assert(CSMj.cols() == n);
  186. LbsMatrixType CSMjM_i = CSMj * M_i;
  187. if(is_sparse(CSMjM_i))
  188. {
  189. // Convert to full
  190. MatrixXd CSMjM_ifull;
  191. //printf("CSM_M(): full\n");
  192. full(CSMjM_i,CSMjM_ifull);
  193. // printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
  194. // printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
  195. // data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
  196. // data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols());
  197. // printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols());
  198. // printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols());
  199. data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull;
  200. }else
  201. {
  202. data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i;
  203. }
  204. }
  205. #ifdef EXTREME_VERBOSE
  206. cout<<"CSM_Mi=["<<endl<<data.CSM_M[i]<<endl<<"];"<<endl;
  207. #endif
  208. }
  209. // precompute arap_rhs matrix
  210. //printf("arap_rhs()\n");
  211. SparseMatrix<double> K;
  212. arap_rhs(V,F,V.cols(),data.energy,K);
  213. //#ifdef EXTREME_VERBOSE
  214. // cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
  215. // endl<<"K=sparse(KIJV(:,1),KIJV(:,2),KIJV(:,3),"<<
  216. // K.rows()<<","<<K.cols()<<");"<<endl;
  217. //#endif
  218. // Precompute left muliplication by M and right multiplication by G_sum
  219. SparseMatrix<double> G_sumT = G_sum.transpose();
  220. SparseMatrix<double> G_sumT_dim_dim;
  221. repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
  222. LbsMatrixType MT = M.transpose();
  223. // If this is a bottle neck then consider reordering matrix multiplication
  224. data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim));
  225. //#ifdef EXTREME_VERBOSE
  226. // cout<<"data.M_KGIJV=["<<endl;print_ijv(data.M_KG,1);cout<<endl<<"];"<<
  227. // endl<<"data.M_KG=sparse(data.M_KGIJV(:,1),data.M_KGIJV(:,2),data.M_KGIJV(:,3),"<<
  228. // data.M_KG.rows()<<","<<data.M_KG.cols()<<");"<<endl;
  229. //#endif
  230. // Precompute system matrix
  231. //printf("A()\n");
  232. SparseMatrix<double> A;
  233. repdiag(Lapl,data.dim,A);
  234. data.Q = MT * (A * M);
  235. //#ifdef EXTREME_VERBOSE
  236. // cout<<"QIJV=["<<endl;print_ijv(data.Q,1);cout<<endl<<"];"<<
  237. // endl<<"Q=sparse(QIJV(:,1),QIJV(:,2),QIJV(:,3),"<<
  238. // data.Q.rows()<<","<<data.Q.cols()<<");"<<endl;
  239. //#endif
  240. // Always do dynamics precomputation so we can hot-switch
  241. //if(data.with_dynamics)
  242. //{
  243. // Build cotangent laplacian
  244. SparseMatrix<double> Mass;
  245. //printf("massmatrix()\n");
  246. massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
  247. //cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
  248. // endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
  249. // Mass.rows()<<","<<Mass.cols()<<");"<<endl;
  250. //speye(data.n,Mass);
  251. SparseMatrix<double> Mass_rep;
  252. repdiag(Mass,data.dim,Mass_rep);
  253. // Multiply either side by weights matrix (should be dense)
  254. data.Mass_tilde = MT * Mass_rep * M;
  255. MatrixXd ones(data.dim*data.n,data.dim);
  256. for(int i = 0;i<data.n;i++)
  257. {
  258. for(int d = 0;d<data.dim;d++)
  259. {
  260. ones(i+d*data.n,d) = 1;
  261. }
  262. }
  263. data.fgrav = MT * (Mass_rep * ones);
  264. data.fext = MatrixXS::Zero(MT.rows(),1);
  265. //data.fgrav = MT * (ones);
  266. //}
  267. // This may/should be superfluous
  268. //printf("is_symmetric()\n");
  269. if(!is_symmetric(data.Q))
  270. {
  271. //printf("Fixing symmetry...\n");
  272. // "Fix" symmetry
  273. LbsMatrixType QT = data.Q.transpose();
  274. LbsMatrixType Q_copy = data.Q;
  275. data.Q = 0.5*(Q_copy+QT);
  276. // Check that ^^^ this really worked. It doesn't always
  277. //assert(is_symmetric(*Q));
  278. }
  279. //printf("arap_dof_precomputation() succeeded... so far...\n");
  280. verbose("Number of handles: %i\n", data.m);
  281. return true;
  282. }
  283. /////////////////////////////////////////////////////////////////////////
  284. //
  285. // STATIC FUNCTIONS (These should be removed or properly defined)
  286. //
  287. /////////////////////////////////////////////////////////////////////////
  288. namespace igl
  289. {
  290. // returns maximal difference of 'blok' from scalar times 3x3 identity:
  291. template <typename SSCALAR>
  292. inline static SSCALAR maxBlokErr(const Eigen::Matrix3f &blok)
  293. {
  294. SSCALAR mD;
  295. SSCALAR value = blok(0,0);
  296. SSCALAR diff1 = fabs(blok(1,1) - value);
  297. SSCALAR diff2 = fabs(blok(2,2) - value);
  298. if (diff1 > diff2) mD = diff1;
  299. else mD = diff2;
  300. for (int v=0; v<3; v++)
  301. {
  302. for (int w=0; w<3; w++)
  303. {
  304. if (v == w)
  305. {
  306. continue;
  307. }
  308. if (mD < fabs(blok(v, w)))
  309. {
  310. mD = fabs(blok(v, w));
  311. }
  312. }
  313. }
  314. return mD;
  315. }
  316. // converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
  317. // "condensed" matrix CSM while checking we're not loosing any information by
  318. // this process; specifically, returns maximal difference from scaled 3x3
  319. // identity blocks, which should be pretty small number
  320. template <typename MatrixXS>
  321. static typename MatrixXS::Scalar condense_CSM(
  322. const std::vector<MatrixXS> &CSM_M_SSCALAR,
  323. int numBones,
  324. int dim,
  325. MatrixXS &CSM)
  326. {
  327. const int numRows = CSM_M_SSCALAR[0].rows();
  328. assert(CSM_M_SSCALAR[0].cols() == dim*(dim+1)*numBones);
  329. assert(CSM_M_SSCALAR[1].cols() == dim*(dim+1)*numBones);
  330. assert(CSM_M_SSCALAR[2].cols() == dim*(dim+1)*numBones);
  331. assert(CSM_M_SSCALAR[1].rows() == numRows);
  332. assert(CSM_M_SSCALAR[2].rows() == numRows);
  333. const int numCols = (dim + 1)*numBones;
  334. CSM.resize(numRows, numCols);
  335. typedef typename MatrixXS::Scalar SSCALAR;
  336. SSCALAR maxDiff = 0.0f;
  337. for (int r=0; r<numRows; r++)
  338. {
  339. for (int coord=0; coord<dim+1; coord++)
  340. {
  341. for (int b=0; b<numBones; b++)
  342. {
  343. // this is just a test if we really have a multiple of 3x3 identity
  344. Eigen::Matrix3f blok;
  345. for (int v=0; v<3; v++)
  346. {
  347. for (int w=0; w<3; w++)
  348. {
  349. blok(v,w) = CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + w*numBones);
  350. }
  351. }
  352. //SSCALAR value[3];
  353. //for (int v=0; v<3; v++)
  354. // CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + v*numBones);
  355. SSCALAR mD = maxBlokErr<SSCALAR>(blok);
  356. if (mD > maxDiff) maxDiff = mD;
  357. // use the first value:
  358. CSM(r, coord*numBones + b) = blok(0,0);
  359. }
  360. }
  361. }
  362. return maxDiff;
  363. }
  364. // splits x_0, ... , x_dim coordinates in column vector 'L' into a numBones*(dimp1) x dim matrix 'Lsep';
  365. // assumes 'Lsep' has already been preallocated
  366. //
  367. // is this the same as uncolumnize? no.
  368. template <typename MatL, typename MatLsep>
  369. static void splitColumns(
  370. const MatL &L,
  371. int numBones,
  372. int dim,
  373. int dimp1,
  374. MatLsep &Lsep)
  375. {
  376. assert(L.cols() == 1);
  377. assert(L.rows() == dim*(dimp1)*numBones);
  378. assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
  379. for (int b=0; b<numBones; b++)
  380. {
  381. for (int coord=0; coord<dimp1; coord++)
  382. {
  383. for (int c=0; c<dim; c++)
  384. {
  385. Lsep(coord*numBones + b, c) = L(coord*numBones*dim + c*numBones + b, 0);
  386. }
  387. }
  388. }
  389. }
  390. // the inverse of splitColumns, i.e., takes numBones*(dimp1) x dim matrix 'Lsep' and merges the dimensions
  391. // into columns vector 'L' (which is assumed to be already allocated):
  392. //
  393. // is this the same as columnize? no.
  394. template <typename MatrixXS>
  395. static void mergeColumns(const MatrixXS &Lsep, int numBones, int dim, int dimp1, MatrixXS &L)
  396. {
  397. assert(L.cols() == 1);
  398. assert(L.rows() == dim*(dimp1)*numBones);
  399. assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
  400. for (int b=0; b<numBones; b++)
  401. {
  402. for (int coord=0; coord<dimp1; coord++)
  403. {
  404. for (int c=0; c<dim; c++)
  405. {
  406. L(coord*numBones*dim + c*numBones + b, 0) = Lsep(coord*numBones + b, c);
  407. }
  408. }
  409. }
  410. }
  411. // converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
  412. // into one "condensed" matrix CSolve1 while checking we're not loosing any
  413. // information by this process; specifically, returns maximal difference from
  414. // scaled 3x3 identity blocks, which should be pretty small number
  415. template <typename MatrixXS>
  416. static typename MatrixXS::Scalar condense_Solve1(MatrixXS &Solve1, int numBones, int numGroups, int dim, MatrixXS &CSolve1)
  417. {
  418. assert(Solve1.rows() == dim*(dim + 1)*numBones);
  419. assert(Solve1.cols() == dim*dim*numGroups);
  420. typedef typename MatrixXS::Scalar SSCALAR;
  421. SSCALAR maxDiff = 0.0f;
  422. CSolve1.resize((dim + 1)*numBones, dim*numGroups);
  423. for (int rowCoord=0; rowCoord<dim+1; rowCoord++)
  424. {
  425. for (int b=0; b<numBones; b++)
  426. {
  427. for (int colCoord=0; colCoord<dim; colCoord++)
  428. {
  429. for (int g=0; g<numGroups; g++)
  430. {
  431. Eigen::Matrix3f blok;
  432. for (int r=0; r<3; r++)
  433. {
  434. for (int c=0; c<3; c++)
  435. {
  436. blok(r, c) = Solve1(rowCoord*numBones*dim + r*numBones + b, colCoord*numGroups*dim + c*numGroups + g);
  437. }
  438. }
  439. SSCALAR mD = maxBlokErr<SSCALAR>(blok);
  440. if (mD > maxDiff) maxDiff = mD;
  441. CSolve1(rowCoord*numBones + b, colCoord*numGroups + g) = blok(0,0);
  442. }
  443. }
  444. }
  445. }
  446. return maxDiff;
  447. }
  448. }
  449. template <typename LbsMatrixType, typename SSCALAR>
  450. IGL_INLINE bool igl::arap_dof_recomputation(
  451. const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
  452. const Eigen::SparseMatrix<double> & A_eq,
  453. ArapDOFData<LbsMatrixType, SSCALAR> & data)
  454. {
  455. using namespace Eigen;
  456. typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
  457. LbsMatrixType * Q;
  458. LbsMatrixType Qdyn;
  459. if(data.with_dynamics)
  460. {
  461. // multiply by 1/timestep and to quadratic coefficients matrix
  462. // Might be missing a 0.5 here
  463. LbsMatrixType Q_copy = data.Q;
  464. Qdyn = Q_copy + (1.0/(data.h*data.h))*data.Mass_tilde;
  465. Q = &Qdyn;
  466. // This may/should be superfluous
  467. //printf("is_symmetric()\n");
  468. if(!is_symmetric(*Q))
  469. {
  470. //printf("Fixing symmetry...\n");
  471. // "Fix" symmetry
  472. LbsMatrixType QT = (*Q).transpose();
  473. LbsMatrixType Q_copy = *Q;
  474. *Q = 0.5*(Q_copy+QT);
  475. // Check that ^^^ this really worked. It doesn't always
  476. //assert(is_symmetric(*Q));
  477. }
  478. }else
  479. {
  480. Q = &data.Q;
  481. }
  482. assert((int)data.CSM_M.size() == data.dim);
  483. assert(A_eq.cols() == data.m*data.dim*(data.dim+1));
  484. data.fixed_dim = fixed_dim;
  485. if(fixed_dim.size() > 0)
  486. {
  487. assert(fixed_dim.maxCoeff() < data.m*data.dim*(data.dim+1));
  488. assert(fixed_dim.minCoeff() >= 0);
  489. }
  490. #ifdef EXTREME_VERBOSE
  491. cout<<"data.fixed_dim=["<<endl<<data.fixed_dim<<endl<<"]+1;"<<endl;
  492. #endif
  493. // Compute dense solve matrix (alternative of matrix factorization)
  494. //printf("min_quad_dense_precompute()\n");
  495. MatrixXd Qfull; full(*Q, Qfull);
  496. MatrixXd A_eqfull; full(A_eq, A_eqfull);
  497. MatrixXd M_Solve;
  498. double timer0_start = get_seconds_hires();
  499. bool use_lu = data.effective_dim != 2;
  500. //use_lu = false;
  501. //printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
  502. min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
  503. double timer0_end = get_seconds_hires();
  504. verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
  505. // Precompute full solve matrix:
  506. const int fsRows = data.m * data.dim * (data.dim + 1); // 12 * number_of_bones
  507. const int fsCols1 = data.M_KG.cols(); // 9 * number_of_posConstraints
  508. const int fsCols2 = A_eq.rows(); // number_of_posConstraints
  509. data.M_FullSolve.resize(fsRows, fsCols1 + fsCols2);
  510. // note the magical multiplicative constant "-0.5", I've no idea why it has
  511. // to be there :)
  512. data.M_FullSolve <<
  513. (-0.5 * M_Solve.block(0, 0, fsRows, fsRows) * data.M_KG).template cast<SSCALAR>(),
  514. M_Solve.block(0, fsRows, fsRows, fsCols2).template cast<SSCALAR>();
  515. if(data.with_dynamics)
  516. {
  517. printf(
  518. "---------------------------------------------------------------------\n"
  519. "\n\n\nWITH DYNAMICS recomputation\n\n\n"
  520. "---------------------------------------------------------------------\n"
  521. );
  522. // Also need to save Π1 before it gets multiplied by Ktilde (aka M_KG)
  523. data.Pi_1 = M_Solve.block(0, 0, fsRows, fsRows).template cast<SSCALAR>();
  524. }
  525. // Precompute condensed matrices,
  526. // first CSM:
  527. std::vector<MatrixXS> CSM_M_SSCALAR;
  528. CSM_M_SSCALAR.resize(data.dim);
  529. for (int i=0; i<data.dim; i++) CSM_M_SSCALAR[i] = data.CSM_M[i].template cast<SSCALAR>();
  530. SSCALAR maxErr1 = condense_CSM(CSM_M_SSCALAR, data.m, data.dim, data.CSM);
  531. verbose("condense_CSM maxErr = %.15f (this should be close to zero)\n", maxErr1);
  532. assert(fabs(maxErr1) < 1e-5);
  533. // and then solveBlock1:
  534. // number of groups
  535. const int k = data.CSM_M[0].rows()/data.dim;
  536. MatrixXS SolveBlock1 = data.M_FullSolve.block(0, 0, data.M_FullSolve.rows(), data.dim * data.dim * k);
  537. SSCALAR maxErr2 = condense_Solve1(SolveBlock1, data.m, k, data.dim, data.CSolveBlock1);
  538. verbose("condense_Solve1 maxErr = %.15f (this should be close to zero)\n", maxErr2);
  539. assert(fabs(maxErr2) < 1e-5);
  540. return true;
  541. }
  542. template <typename LbsMatrixType, typename SSCALAR>
  543. IGL_INLINE bool igl::arap_dof_update(
  544. const ArapDOFData<LbsMatrixType, SSCALAR> & data,
  545. const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
  546. const Eigen::MatrixXd & L0,
  547. const int max_iters,
  548. const double
  549. #ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  550. tol,
  551. #else
  552. /*tol*/,
  553. #endif
  554. Eigen::MatrixXd & L
  555. )
  556. {
  557. using namespace Eigen;
  558. typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
  559. #ifdef ARAP_GLOBAL_TIMING
  560. double timer_start = get_seconds_hires();
  561. #endif
  562. // number of dimensions
  563. assert((int)data.CSM_M.size() == data.dim);
  564. assert((int)L0.size() == (data.m)*data.dim*(data.dim+1));
  565. assert(max_iters >= 0);
  566. assert(tol >= 0);
  567. // timing variables
  568. double
  569. sec_start,
  570. sec_covGather,
  571. sec_fitRotations,
  572. //sec_rhs,
  573. sec_prepMult,
  574. sec_solve, sec_end;
  575. assert(L0.cols() == 1);
  576. #ifdef EXTREME_VERBOSE
  577. cout<<"dim="<<data.dim<<";"<<endl;
  578. cout<<"m="<<data.m<<";"<<endl;
  579. #endif
  580. // number of groups
  581. const int k = data.CSM_M[0].rows()/data.dim;
  582. for(int i = 0;i<data.dim;i++)
  583. {
  584. assert(data.CSM_M[i].rows()/data.dim == k);
  585. }
  586. #ifdef EXTREME_VERBOSE
  587. cout<<"k="<<k<<";"<<endl;
  588. #endif
  589. // resize output and initialize with initial guess
  590. L = L0;
  591. #ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  592. // Keep track of last solution
  593. MatrixXS L_prev;
  594. #endif
  595. // We will be iterating on L_SSCALAR, only at the end we convert back to double
  596. MatrixXS L_SSCALAR = L.cast<SSCALAR>();
  597. int iters = 0;
  598. #ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  599. double max_diff = tol+1;
  600. #endif
  601. MatrixXS S(k*data.dim,data.dim);
  602. MatrixXS R(data.dim,data.dim*k);
  603. Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
  604. Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
  605. Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR;
  606. Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
  607. slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR);
  608. //MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
  609. MatrixXS Lsep(data.m*(data.dim + 1), 3);
  610. const MatrixXS L_part2 =
  611. data.M_FullSolve.block(0, Rcol.rows(), data.M_FullSolve.rows(), B_eq_SSCALAR.rows()) * B_eq_SSCALAR;
  612. const MatrixXS L_part3 =
  613. data.M_FullSolve.block(0, Rcol.rows() + B_eq_SSCALAR.rows(), data.M_FullSolve.rows(), B_eq_fix_SSCALAR.rows()) * B_eq_fix_SSCALAR;
  614. MatrixXS L_part2and3 = L_part2 + L_part3;
  615. // preallocate workspace variables:
  616. MatrixXS Rxyz(k*data.dim, data.dim);
  617. MatrixXS L_part1xyz((data.dim + 1) * data.m, data.dim);
  618. MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1);
  619. #ifdef ARAP_GLOBAL_TIMING
  620. double timer_prepFinished = get_seconds_hires();
  621. #endif
  622. #ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  623. while(iters < max_iters)
  624. #else
  625. while(iters < max_iters && max_diff > tol)
  626. #endif
  627. {
  628. if(data.print_timings)
  629. {
  630. sec_start = get_seconds_hires();
  631. }
  632. #ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  633. L_prev = L_SSCALAR;
  634. #endif
  635. ///////////////////////////////////////////////////////////////////////////
  636. // Local step: Fix positions, fit rotations
  637. ///////////////////////////////////////////////////////////////////////////
  638. // Gather covariance matrices
  639. splitColumns(L_SSCALAR, data.m, data.dim, data.dim + 1, Lsep);
  640. S = data.CSM * Lsep;
  641. // interestingly, this doesn't seem to be so slow, but
  642. //MKL is still 2x faster (probably due to AVX)
  643. //#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
  644. // MKL_matMatMult_double(S, data.CSM, Lsep);
  645. //#else
  646. // MKL_matMatMult_single(S, data.CSM, Lsep);
  647. //#endif
  648. if(data.print_timings)
  649. {
  650. sec_covGather = get_seconds_hires();
  651. }
  652. #ifdef EXTREME_VERBOSE
  653. cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
  654. #endif
  655. // Fit rotations to covariance matrices
  656. if(data.effective_dim == 2)
  657. {
  658. fit_rotations_planar(S,R);
  659. }else
  660. {
  661. #ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
  662. fit_rotations_SSE(S,R);
  663. #else
  664. fit_rotations(S,false,R);
  665. #endif
  666. }
  667. #ifdef EXTREME_VERBOSE
  668. cout<<"R=["<<endl<<R<<endl<<"];"<<endl;
  669. #endif
  670. if(data.print_timings)
  671. {
  672. sec_fitRotations = get_seconds_hires();
  673. }
  674. ///////////////////////////////////////////////////////////////////////////
  675. // "Global" step: fix rotations per mesh vertex, solve for
  676. // linear transformations at handles
  677. ///////////////////////////////////////////////////////////////////////////
  678. // all this shuffling is retarded and not completely negligible time-wise;
  679. // TODO: change fit_rotations_XXX so it returns R in the format ready for
  680. // CSolveBlock1 multiplication
  681. columnize(R, k, 2, Rcol);
  682. #ifdef EXTREME_VERBOSE
  683. cout<<"Rcol=["<<endl<<Rcol<<endl<<"];"<<endl;
  684. #endif
  685. splitColumns(Rcol, k, data.dim, data.dim, Rxyz);
  686. if(data.print_timings)
  687. {
  688. sec_prepMult = get_seconds_hires();
  689. }
  690. L_part1xyz = data.CSolveBlock1 * Rxyz;
  691. //#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
  692. // MKL_matMatMult_double(L_part1xyz, data.CSolveBlock1, Rxyz);
  693. //#else
  694. // MKL_matMatMult_single(L_part1xyz, data.CSolveBlock1, Rxyz);
  695. //#endif
  696. mergeColumns(L_part1xyz, data.m, data.dim, data.dim + 1, L_part1);
  697. if(data.with_dynamics)
  698. {
  699. // Consider reordering or precomputing matrix multiplications
  700. MatrixXS L_part1_dyn(data.dim * (data.dim + 1) * data.m, 1);
  701. // Eigen can't parse this:
  702. //L_part1_dyn =
  703. // -(2.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.L0 +
  704. // (1.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.Lm1;
  705. // -1.0 because we've moved these linear terms to the right hand side
  706. //MatrixXS temp = -1.0 *
  707. // ((-2.0/(data.h*data.h)) * data.L0.array() +
  708. // (1.0/(data.h*data.h)) * data.Lm1.array()).matrix();
  709. //MatrixXS temp = -1.0 *
  710. // ( (-1.0/(data.h*data.h)) * data.L0.array() +
  711. // (1.0/(data.h*data.h)) * data.Lm1.array()
  712. // (-1.0/(data.h*data.h)) * data.L0.array() +
  713. // ).matrix();
  714. //Lvel0 = (1.0/(data.h)) * data.Lm1.array() - data.L0.array();
  715. MatrixXS temp = -1.0 *
  716. ( (-1.0/(data.h*data.h)) * data.L0.array() +
  717. (1.0/(data.h)) * data.Lvel0.array()
  718. ).matrix();
  719. MatrixXd temp_d = temp.template cast<double>();
  720. MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
  721. assert(data.fext.rows() == temp_g.rows());
  722. assert(data.fext.cols() == temp_g.cols());
  723. MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
  724. MatrixXS temp2_f = temp2.template cast<SSCALAR>();
  725. L_part1_dyn = data.Pi_1 * temp2_f;
  726. L_part1.array() = L_part1.array() + L_part1_dyn.array();
  727. }
  728. //L_SSCALAR = L_part1 + L_part2and3;
  729. assert(L_SSCALAR.rows() == L_part1.rows() && L_SSCALAR.rows() == L_part2and3.rows());
  730. for (int i=0; i<L_SSCALAR.rows(); i++)
  731. {
  732. L_SSCALAR(i, 0) = L_part1(i, 0) + L_part2and3(i, 0);
  733. }
  734. #ifdef EXTREME_VERBOSE
  735. cout<<"L=["<<endl<<L<<endl<<"];"<<endl;
  736. #endif
  737. if(data.print_timings)
  738. {
  739. sec_solve = get_seconds_hires();
  740. }
  741. #ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
  742. // Compute maximum absolute difference with last iteration's solution
  743. max_diff = (L_SSCALAR-L_prev).eval().array().abs().matrix().maxCoeff();
  744. #endif
  745. iters++;
  746. if(data.print_timings)
  747. {
  748. sec_end = get_seconds_hires();
  749. #ifndef WIN32
  750. // trick to get sec_* variables to compile without warning on mac
  751. if(false)
  752. #endif
  753. printf(
  754. "\ntotal iteration time = %f "
  755. "[local: covGather = %f, "
  756. "fitRotations = %f, "
  757. "global: prep = %f, "
  758. "solve = %f, "
  759. "error = %f [ms]]\n",
  760. (sec_end - sec_start)*1000.0,
  761. (sec_covGather - sec_start)*1000.0,
  762. (sec_fitRotations - sec_covGather)*1000.0,
  763. (sec_prepMult - sec_fitRotations)*1000.0,
  764. (sec_solve - sec_prepMult)*1000.0,
  765. (sec_end - sec_solve)*1000.0 );
  766. }
  767. }
  768. L = L_SSCALAR.template cast<double>();
  769. assert(L.cols() == 1);
  770. #ifdef ARAP_GLOBAL_TIMING
  771. double timer_finito = get_seconds_hires();
  772. printf(
  773. "ARAP preparation = %f, "
  774. "all %i iterations = %f [ms]\n",
  775. (timer_prepFinished - timer_start)*1000.0,
  776. max_iters,
  777. (timer_finito - timer_prepFinished)*1000.0);
  778. #endif
  779. return true;
  780. }
  781. #ifdef IGL_STATIC_LIBRARY
  782. // Explicit instanciation
  783. template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
  784. template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
  785. template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
  786. template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
  787. template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
  788. template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
  789. #endif