DiscreteShellsTraits.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // This file is part of libhedra, a library for polyhedral mesh processing
  2. //
  3. // Copyright (C) 2016 Amir Vaxman <avaxman@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. #ifndef HEDRA_DISCRETE_SHELLS_TRAITS_H
  9. #define HEDRA_DISCRETE_SHELLS_TRAITS_H
  10. #include <igl/igl_inline.h>
  11. #include <igl/harmonic.h>
  12. #include <Eigen/Core>
  13. #include <string>
  14. #include <vector>
  15. #include <cstdio>
  16. #include <set>
  17. namespace hedra { namespace optimization {
  18. //this class is a traits class for optimization of discrete shells deformation by given positional constraints. It is an implementation on [Froehlich and Botsch 2012] for general polyhedral meshes, using a triangulation of them
  19. //the solution vector is assumed to be arranged as xyzxyzxyz... where each triplet is a coordinate of the free vertices.
  20. class DiscreteShellsTraits{
  21. public:
  22. //Requisites of the traits class
  23. Eigen::VectorXi JRows, JCols; //rows and column indices for the jacobian matrix
  24. Eigen::VectorXd JVals; //values for the jacobian matrix.
  25. int xSize; //size of the solution
  26. Eigen::VectorXd EVec; //energy vector
  27. //These are for the the full Jacobian matrix without removing the handles
  28. Eigen::VectorXi fullJRows, fullJCols;
  29. Eigen::VectorXd fullJVals;
  30. Eigen::MatrixXi flapVertexIndices; //vertices (i,j,k,l) of a flap on edge e=(k,i) where the triangles are f=(i,j,k) and g=(i,k,l)
  31. Eigen::MatrixXi EV;
  32. Eigen::VectorXi h; //list of handles
  33. Eigen::MatrixXd qh; //#h by 3 positions
  34. Eigen::VectorXi a2x; //from the entire set of variables "a" to the free variables in the optimization "x".
  35. Eigen::VectorXi colMap; //raw map of a2x into the columns from fullJCols into JCols
  36. Eigen::VectorXd origLengths; //the original edge lengths.
  37. Eigen::VectorXd origDihedrals; //Original dihedral angles
  38. Eigen::MatrixXd VOrig; //original positions
  39. Eigen::MatrixXi T; //triangles
  40. Eigen::VectorXd Wd, Wl; //geometric weights for the lengths and the dihedral angles.
  41. double bendCoeff, lengthCoeff; //coefficients for the different terms
  42. //Eigen::VectorXd x0; //the initial solution to the optimization
  43. Eigen::MatrixXd fullSolution; //The final solution of the last optimization
  44. void init(const Eigen::MatrixXd& _VOrig,
  45. const Eigen::MatrixXi& _T,
  46. const Eigen::VectorXi& _h,
  47. const Eigen::MatrixXi& _EV,
  48. const Eigen::MatrixXi& ET,
  49. const Eigen::MatrixXi& ETi,
  50. const Eigen::VectorXi& innerEdges){
  51. using namespace std;
  52. using namespace Eigen;
  53. std::set<pair<int, int> > edgeIndicesList;
  54. VOrig=_VOrig;
  55. T=_T;
  56. h=_h;
  57. EV=_EV;
  58. lengthCoeff=10.0;
  59. bendCoeff=1.0;
  60. //lengths of edges and diagonals
  61. flapVertexIndices.resize(innerEdges.size(),4);
  62. //dihedral angles
  63. for (int i=0;i<innerEdges.size();i++){
  64. int f=ET(innerEdges(i),0);
  65. int g=ET(innerEdges(i),1);
  66. int vi=EV(innerEdges(i), 1);
  67. int vj=T(f,(ETi(innerEdges(i),0)+2)%3);
  68. int vk=EV(innerEdges(i),0);
  69. int vl=T(g,(ETi(innerEdges(i),1)+2)%3);
  70. flapVertexIndices.row(i)<<vi,vj,vk,vl;
  71. }
  72. //across edges
  73. EVec.resize(EV.rows()+flapVertexIndices.rows());
  74. origLengths.resize(EV.rows());
  75. origDihedrals.resize(flapVertexIndices.rows());
  76. Wl.resize(EV.rows());
  77. Wd.resize(flapVertexIndices.rows());
  78. for (int i=0;i<EV.rows();i++){
  79. origLengths(i)=(VOrig.row(EV(i,1))-VOrig.row(EV(i,0))).norm();
  80. Wl(i)=1.0/origLengths(i);
  81. }
  82. for (int i=0;i<flapVertexIndices.rows();i++){
  83. RowVector3d eji=VOrig.row(flapVertexIndices(i,0))-VOrig.row(flapVertexIndices(i,1));
  84. RowVector3d ejk=VOrig.row(flapVertexIndices(i,2))-VOrig.row(flapVertexIndices(i,1));
  85. RowVector3d eli=VOrig.row(flapVertexIndices(i,0))-VOrig.row(flapVertexIndices(i,3));
  86. RowVector3d elk=VOrig.row(flapVertexIndices(i,2))-VOrig.row(flapVertexIndices(i,3));
  87. RowVector3d eki=VOrig.row(flapVertexIndices(i,0))-VOrig.row(flapVertexIndices(i,2));
  88. RowVector3d n1 = (ejk.cross(eji));
  89. RowVector3d n2 = (eli.cross(elk));
  90. double sign=((n1.cross(n2)).dot(eki) >= 0 ? 1.0 : -1.0);
  91. double sinHalf=sign*sqrt((1.0-n1.normalized().dot(n2.normalized()))/2.0);
  92. origDihedrals(i)=2.0*asin(sinHalf);
  93. double areaSum=(n1.norm()+n2.norm())/2.0;
  94. Wd(i)=eki.norm()/sqrt(areaSum);
  95. }
  96. //creating the Jacobian pattern
  97. xSize=3*(VOrig.rows()-h.size());
  98. fullJRows.resize(6*EV.rows()+12*flapVertexIndices.rows());
  99. fullJCols.resize(6*EV.rows()+12*flapVertexIndices.rows());
  100. fullJVals.resize(6*EV.rows()+12*flapVertexIndices.rows());
  101. //Jacobian indices for edge lengths
  102. for (int i=0;i<EV.rows();i++){
  103. fullJRows.segment(6*i,6).setConstant(i);
  104. fullJCols.segment(6*i,3)<<3*EV(i,0),3*EV(i,0)+1,3*EV(i,0)+2;
  105. fullJCols.segment(6*i+3,3)<<3*EV(i,1),3*EV(i,1)+1,3*EV(i,1)+2;
  106. }
  107. //Jacobian indices for dihedral angles
  108. for (int i=0;i<flapVertexIndices.rows();i++){
  109. fullJRows.segment(6*EV.rows()+12*i,12).setConstant(EV.rows()+i);
  110. for (int k=0;k<4;k++)
  111. fullJCols.segment(6*EV.rows()+12*i+3*k,3)<<3*flapVertexIndices(i,k),3*flapVertexIndices(i,k)+1,3*flapVertexIndices(i,k)+2;
  112. }
  113. a2x=Eigen::VectorXi::Zero(VOrig.rows());
  114. int CurrIndex=0;
  115. for (int i=0;i<h.size();i++)
  116. a2x(h(i))=-1;
  117. for (int i=0;i<VOrig.rows();i++)
  118. if (a2x(i)!=-1)
  119. a2x(i)=CurrIndex++;
  120. colMap.resize(3*VOrig.rows());
  121. for (int i=0;i<VOrig.rows();i++)
  122. if (a2x(i)!=-1)
  123. colMap.segment(3*i,3)<<3*a2x(i),3*a2x(i)+1,3*a2x(i)+2;
  124. else
  125. colMap.segment(3*i,3)<<-1,-1,-1;
  126. //setting up the Jacobian rows and columns
  127. int actualGradCounter=0;
  128. for (int i=0;i<fullJCols.size();i++){
  129. if (colMap(fullJCols(i))!=-1) //not a removed variable
  130. actualGradCounter++;
  131. }
  132. JRows.resize(actualGradCounter);
  133. JCols.resize(actualGradCounter);
  134. JVals.resize(actualGradCounter);
  135. actualGradCounter=0;
  136. for (int i=0;i<fullJCols.size();i++){
  137. if (colMap(fullJCols(i))!=-1){ //not a removed variable
  138. JRows(actualGradCounter)=fullJRows(i);
  139. JCols(actualGradCounter++)=colMap(fullJCols(i));
  140. }
  141. }
  142. }
  143. //provide the initial solution to the solver
  144. void initial_solution(Eigen::VectorXd& x0){
  145. //using biharmonic deformation fields
  146. Eigen::MatrixXd origHandlePoses(qh.rows(),3);
  147. for (int i=0;i<qh.rows();i++)
  148. origHandlePoses.row(i)=VOrig.row(h(i));
  149. Eigen::MatrixXd D;
  150. Eigen::MatrixXd D_bc = qh - origHandlePoses;
  151. igl::harmonic(VOrig,T,h,D_bc,2,D);
  152. Eigen::MatrixXd V0 = VOrig+D;
  153. for (int i=0;i<VOrig.rows();i++)
  154. if (a2x(i)!=-1)
  155. x0.segment(3*a2x(i),3)<<V0.row(i).transpose();
  156. }
  157. void pre_iteration(const Eigen::VectorXd& prevx){}
  158. bool post_iteration(const Eigen::VectorXd& x){return false; /*never stop after an iteration*/}
  159. //updating the energy vector for a given current solution
  160. void update_energy(const Eigen::VectorXd& x){
  161. using namespace std;
  162. using namespace Eigen;
  163. MatrixXd fullx(xSize+h.size(),3);
  164. for (int i=0;i<a2x.size();i++)
  165. if (a2x(i)!=-1)
  166. fullx.row(i)<<x.segment(3*a2x(i),3).transpose();
  167. for (int i=0;i<h.size();i++)
  168. fullx.row(h(i))=qh.row(i);
  169. fullJVals.setZero();
  170. for (int i=0;i<EV.rows();i++)
  171. EVec(i)=((fullx.row(EV(i,1))-fullx.row(EV(i,0))).norm()-origLengths(i))*Wl(i)*lengthCoeff;
  172. for (int i=0;i<flapVertexIndices.rows();i++){
  173. RowVector3d eji=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,1));
  174. RowVector3d ejk=fullx.row(flapVertexIndices(i,2))-fullx.row(flapVertexIndices(i,1));
  175. RowVector3d eli=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,3));
  176. RowVector3d elk=fullx.row(flapVertexIndices(i,2))-fullx.row(flapVertexIndices(i,3));
  177. RowVector3d eki=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,2));
  178. RowVector3d n1 = (ejk.cross(eji));
  179. RowVector3d n2 = (eli.cross(elk));
  180. double sign=((n1.cross(n2)).dot(eki) >= 0 ? 1.0 : -1.0);
  181. double dotn1n2=1.0-n1.normalized().dot(n2.normalized());
  182. if (dotn1n2<0.0) dotn1n2=0.0; //sanitizing
  183. double sinHalf=sign*sqrt(dotn1n2/2.0);
  184. if (sinHalf>1.0) sinHalf=1.0; if (sinHalf<-1.0) sinHalf=-1.0;
  185. EVec(EV.rows()+i)=(2.0*asin(sinHalf)-origDihedrals(i))*Wd(i)*bendCoeff;
  186. }
  187. for (int i=0;i<EVec.size();i++)
  188. if (isnan(EVec(i)))
  189. cout<<"nan in EVec("<<i<<")"<<endl;
  190. }
  191. //update the jacobian values for a given current solution
  192. void update_jacobian(const Eigen::VectorXd& x){
  193. using namespace std;
  194. using namespace Eigen;
  195. MatrixXd fullx(xSize+h.size(),3);
  196. for (int i=0;i<a2x.size();i++)
  197. if (a2x(i)!=-1)
  198. fullx.row(i)<<x.segment(3*a2x(i),3).transpose();
  199. for (int i=0;i<h.size();i++)
  200. fullx.row(h(i))=qh.row(i);
  201. fullJVals.setZero();
  202. for (int i=0;i<EV.rows();i++){
  203. RowVector3d normedEdgeVector=(fullx.row(EV(i,1))-fullx.row(EV(i,0))).normalized();
  204. fullJVals.segment(6*i,3)<<-normedEdgeVector.transpose()*Wl(i)*lengthCoeff;
  205. fullJVals.segment(6*i+3,3)<<normedEdgeVector.transpose()*Wl(i)*lengthCoeff;
  206. }
  207. for (int i=0;i<flapVertexIndices.rows();i++){
  208. RowVector3d eji=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,1));
  209. RowVector3d ejk=fullx.row(flapVertexIndices(i,2))-fullx.row(flapVertexIndices(i,1));
  210. RowVector3d eli=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,3));
  211. RowVector3d elk=fullx.row(flapVertexIndices(i,2))-fullx.row(flapVertexIndices(i,3));
  212. RowVector3d eki=fullx.row(flapVertexIndices(i,0))-fullx.row(flapVertexIndices(i,2));
  213. RowVector3d n1 = (ejk.cross(eji));
  214. RowVector3d n2 = (eli.cross(elk));
  215. double sign=((n1.cross(n2)).dot(eki) >= 0 ? 1.0 : -1.0);
  216. double dotn1n2=1.0-n1.normalized().dot(n2.normalized());
  217. if (dotn1n2<0.0) dotn1n2=0.0; //sanitizing
  218. double sinHalf=sign*sqrt(dotn1n2/2.0);
  219. if (sinHalf>1.0) sinHalf=1.0; if (sinHalf<-1.0) sinHalf=-1.0;
  220. fullJVals.segment(6*EV.rows()+12*i,3)<<(Wd(i)*((ejk.dot(-eki)/(n1.squaredNorm()*eki.norm()))*n1+(elk.dot(-eki)/(n2.squaredNorm()*eki.norm()))*n2)).transpose()*bendCoeff;
  221. fullJVals.segment(6*EV.rows()+12*i+3,3)<<(Wd(i)*(-eki.norm()/n1.squaredNorm())*n1).transpose()*bendCoeff;
  222. fullJVals.segment(6*EV.rows()+12*i+6,3)<<(Wd(i)*((eji.dot(eki)/(n1.squaredNorm()*eki.norm()))*n1+(eli.dot(eki)/(n2.squaredNorm()*eki.norm()))*n2)).transpose()*bendCoeff;
  223. fullJVals.segment(6*EV.rows()+12*i+9,3)<<(Wd(i)*(-eki.norm()/n2.squaredNorm())*n2).transpose()*bendCoeff;
  224. }
  225. int actualGradCounter=0;
  226. for (int i=0;i<fullJCols.size();i++)
  227. if (colMap(fullJCols(i))!=-1) //not a removed variable
  228. JVals(actualGradCounter++)=fullJVals(i);
  229. for (int i=0;i<JVals.size();i++)
  230. if (isnan(JVals(i)))
  231. cout<<"nan in JVals("<<i<<")"<<endl;
  232. }
  233. bool post_optimization(const Eigen::VectorXd& x){
  234. fullSolution.conservativeResize(a2x.size(),3);
  235. for (int i=0;i<a2x.size();i++)
  236. if (a2x(i)!=-1)
  237. fullSolution.row(i)<<x.segment(3*a2x(i),3).transpose();
  238. for (int i=0;i<h.size();i++)
  239. fullSolution.row(h(i))=qh.row(i);
  240. return true; //stop optimization after this
  241. }
  242. DiscreteShellsTraits(){}
  243. ~DiscreteShellsTraits(){}
  244. };
  245. } }
  246. #endif