shapeup.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2017 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. #include <igl/shapeup.h>
  9. #include <igl/min_quad_with_fixed.h>
  10. #include <igl/igl_inline.h>
  11. #include <igl/setdiff.h>
  12. #include <igl/cat.h>
  13. #include <igl/PI.h>
  14. #include <Eigen/Core>
  15. #include <vector>
  16. namespace igl
  17. {
  18. //This projection does nothing but render points into projP. Mostly used for "echoing" the global step
  19. IGL_INLINE bool shapeup_identity_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP){
  20. projP.conservativeResize(SC.rows(), 3*SC.maxCoeff());
  21. for (int i=0;i<S.rows();i++){
  22. Eigen::RowVector3d avgCurrP=Eigen::RowVector3d::Zero();
  23. for (int j=0;j<SC(i);j++)
  24. avgCurrP+=P.row(S(i,j))/(double)(SC(i));
  25. for (int j=0;j<SC(i);j++)
  26. projP.block(i,3*j,1,3)=P.row(S(i,j))-avgCurrP;
  27. }
  28. return true;
  29. }
  30. //the projection assumes that the sets are vertices of polygons in order
  31. IGL_INLINE bool shapeup_regular_face_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP){
  32. projP.conservativeResize(SC.rows(), 3*SC.maxCoeff());
  33. for (int currRow=0;currRow<SC.rows();currRow++){
  34. //computing average
  35. int N=SC(currRow);
  36. const Eigen::RowVectorXi SRow=S.row(currRow);
  37. Eigen::RowVector3d avgCurrP=Eigen::RowVector3d::Zero();
  38. Eigen::MatrixXd targetPolygon(N, 3);
  39. Eigen::MatrixXd sourcePolygon(N, 3);
  40. for (int j=0;j<N;j++)
  41. avgCurrP+=P.row(SRow(j))/(double)(N);
  42. for (int j=0;j<N;j++)
  43. targetPolygon.row(j)=P.row(SRow(j))-avgCurrP;
  44. //creating perfectly regular source polygon
  45. for (int j=0;j<N;j++)
  46. sourcePolygon.row(j)<<cos(2*igl::PI*(double)j/(double(N))), sin(2*igl::PI*(double)j/(double(N))),0.0;
  47. //finding closest similarity transformation between source and target
  48. Eigen::MatrixXd corrMat=sourcePolygon.transpose()*targetPolygon;
  49. Eigen::JacobiSVD<Eigen::Matrix3d> svd(corrMat, Eigen::ComputeFullU | Eigen::ComputeFullV);
  50. Eigen::MatrixXd R=svd.matrixU()*svd.matrixV().transpose();
  51. //getting scale by edge length change average. TODO: by singular values
  52. Eigen::VectorXd sourceEdgeLengths(N);
  53. Eigen::VectorXd targetEdgeLengths(N);
  54. for (int j=0;j<N;j++){
  55. sourceEdgeLengths(j)=(sourcePolygon.row((j+1)%N)-sourcePolygon.row(j)).norm();
  56. targetEdgeLengths(j)=(targetPolygon.row((j+1)%N)-targetPolygon.row(j)).norm();
  57. }
  58. double scale=(targetEdgeLengths.cwiseQuotient(sourceEdgeLengths)).mean();
  59. for (int j=0;j<N;j++)
  60. projP.block(currRow,3*j,1,3)=sourcePolygon.row(j)*R*scale;
  61. }
  62. return true;
  63. }
  64. template <
  65. typename DerivedP,
  66. typename DerivedSC,
  67. typename DerivedS,
  68. typename Derivedw>
  69. IGL_INLINE bool shapeup_precomputation(const Eigen::PlainObjectBase<DerivedP>& P,
  70. const Eigen::PlainObjectBase<DerivedSC>& SC,
  71. const Eigen::PlainObjectBase<DerivedS>& S,
  72. const Eigen::PlainObjectBase<DerivedS>& E,
  73. const Eigen::PlainObjectBase<DerivedSC>& b,
  74. const Eigen::PlainObjectBase<Derivedw>& wShape,
  75. const Eigen::PlainObjectBase<Derivedw>& wSmooth,
  76. ShapeupData & sudata)
  77. {
  78. using namespace std;
  79. using namespace Eigen;
  80. sudata.P=P;
  81. sudata.SC=SC;
  82. sudata.S=S;
  83. sudata.b=b;
  84. typedef typename DerivedP::Scalar Scalar;
  85. //checking for consistency of the input
  86. assert(SC.rows()==S.rows());
  87. assert(SC.rows()==wShape.rows());
  88. assert(E.rows()==wSmooth.rows());
  89. assert(b.rows()!=0); //would lead to matrix becoming SPD
  90. sudata.DShape.conservativeResize(SC.sum(), P.rows()); //Shape matrix (integration);
  91. sudata.DClose.conservativeResize(b.rows(), P.rows()); //Closeness matrix for positional constraints
  92. sudata.DSmooth.conservativeResize(E.rows(), P.rows()); //smoothness matrix
  93. //Building shape matrix
  94. std::vector<Triplet<Scalar> > DShapeTriplets;
  95. int currRow=0;
  96. for (int i=0;i<S.rows();i++){
  97. Scalar avgCoeff=1.0/(Scalar)SC(i);
  98. for (int j=0;j<SC(i);j++){
  99. for (int k=0;k<SC(i);k++){
  100. if (j==k)
  101. DShapeTriplets.push_back(Triplet<Scalar>(currRow+j, S(i,k), (1.0-avgCoeff)));
  102. else
  103. DShapeTriplets.push_back(Triplet<Scalar>(currRow+j, S(i,k), (-avgCoeff)));
  104. }
  105. }
  106. currRow+=SC(i);
  107. }
  108. sudata.DShape.setFromTriplets(DShapeTriplets.begin(), DShapeTriplets.end());
  109. //Building closeness matrix
  110. std::vector<Triplet<Scalar> > DCloseTriplets;
  111. for (int i=0;i<b.size();i++)
  112. DCloseTriplets.push_back(Triplet<Scalar>(i,b(i), 1.0));
  113. sudata.DClose.setFromTriplets(DCloseTriplets.begin(), DCloseTriplets.end());
  114. //Building smoothness matrix
  115. std::vector<Triplet<Scalar> > DSmoothTriplets;
  116. for (int i=0; i<E.rows(); i++) {
  117. DSmoothTriplets.push_back(Triplet<Scalar>(i, E(i, 0), -1));
  118. DSmoothTriplets.push_back(Triplet<Scalar>(i, E(i, 1), 1));
  119. }
  120. SparseMatrix<Scalar> tempMat;
  121. igl::cat(1, sudata.DShape, sudata.DClose, tempMat);
  122. igl::cat(1, tempMat, sudata.DSmooth, sudata.A);
  123. //weight matrix
  124. vector<Triplet<Scalar> > WTriplets;
  125. //one weight per set in S.
  126. currRow=0;
  127. for (int i=0;i<SC.rows();i++){
  128. for (int j=0;j<SC(i);j++)
  129. WTriplets.push_back(Triplet<double>(currRow+j,currRow+j,sudata.shapeCoeff*wShape(i)));
  130. currRow+=SC(i);
  131. }
  132. for (int i=0;i<b.size();i++)
  133. WTriplets.push_back(Triplet<double>(SC.sum()+i, SC.sum()+i, sudata.closeCoeff));
  134. for (int i=0;i<E.rows();i++)
  135. WTriplets.push_back(Triplet<double>(SC.sum()+b.size()+i, SC.sum()+b.size()+i, sudata.smoothCoeff*wSmooth(i)));
  136. sudata.W.conservativeResize(SC.sum()+b.size()+E.rows(), SC.sum()+b.size()+E.rows());
  137. sudata.W.setFromTriplets(WTriplets.begin(), WTriplets.end());
  138. sudata.At=sudata.A.transpose(); //for efficieny, as we use the transpose a lot in the iteration
  139. sudata.Q=sudata.At*sudata.W*sudata.A;
  140. return min_quad_with_fixed_precompute(sudata.Q,VectorXi(),SparseMatrix<double>(),true,sudata.solver_data);
  141. }
  142. template <
  143. typename DerivedP,
  144. typename DerivedSC,
  145. typename DerivedS>
  146. IGL_INLINE bool shapeup_solve(const Eigen::PlainObjectBase<DerivedP>& bc,
  147. const std::function<bool(const Eigen::PlainObjectBase<DerivedP>&, const Eigen::PlainObjectBase<DerivedSC>&, const Eigen::PlainObjectBase<DerivedS>&, Eigen::PlainObjectBase<DerivedP>&)>& local_projection,
  148. const Eigen::PlainObjectBase<DerivedP>& P0,
  149. const ShapeupData & sudata,
  150. const bool quietIterations,
  151. Eigen::PlainObjectBase<DerivedP>& P)
  152. {
  153. using namespace Eigen;
  154. using namespace std;
  155. MatrixXd currP=P0;
  156. MatrixXd prevP=P0;
  157. MatrixXd projP;
  158. assert(bc.rows()==sudata.b.rows());
  159. MatrixXd rhs(sudata.A.rows(), 3); rhs.setZero();
  160. rhs.block(sudata.DShape.rows(), 0, sudata.b.rows(),3)=bc; //this stays constant throughout the iterations
  161. if (!quietIterations){
  162. cout<<"Shapeup Iterations, "<<sudata.DShape.rows()<<" constraints, solution size "<<P0.size()<<endl;
  163. cout<<"**********************************************************************************************"<<endl;
  164. }
  165. projP.conservativeResize(sudata.SC.rows(), 3*sudata.SC.maxCoeff());
  166. for (int iter=0;iter<sudata.maxIterations;iter++){
  167. local_projection(currP, sudata.SC,sudata.S,projP);
  168. //constructing the projection part of the (DShape rows of the) right hand side
  169. int currRow=0;
  170. for (int i=0;i<sudata.S.rows();i++)
  171. for (int j=0;j<sudata.SC(i);j++)
  172. rhs.row(currRow++)=projP.block(i, 3*j, 1,3);
  173. DerivedP lsrhs=-sudata.At*sudata.W*rhs;
  174. MatrixXd Y(0,3), Beq(0,3); //We do not use the min_quad_solver fixed variables mechanism; they are treated with the closeness energy of ShapeUp.
  175. min_quad_with_fixed_solve(sudata.solver_data, lsrhs,Y,Beq,currP);
  176. double currChange=(currP-prevP).lpNorm<Infinity>();
  177. if (!quietIterations)
  178. cout << "Iteration "<<iter<<", integration Linf error: "<<currChange<< endl;
  179. prevP=currP;
  180. if (currChange<sudata.pTolerance){
  181. P=currP;
  182. return true;
  183. }
  184. }
  185. P=currP;
  186. return false; //we went over maxIterations
  187. }
  188. }
  189. #ifdef IGL_STATIC_LIBRARY
  190. template bool igl::shapeup_precomputation< typename Eigen::Matrix<double, -1, -1, 0, -1, -1>, typename Eigen::Matrix<int, -1, 1, 0, -1, 1>, typename Eigen::Matrix<int, -1, -1, 0, -1, -1>, typename 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::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::ShapeupData&);
  191. template bool igl::shapeup_solve<typename Eigen::Matrix<double, -1, -1, 0, -1, -1>, typename Eigen::Matrix<int, -1, 1, 0, -1, 1>, typename Eigen::Matrix<int, -1, -1, 0, -1, -1> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& bc, const std::function<bool(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& ) >& local_projection, const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& P0, const igl::ShapeupData & sudata, const bool quietIterations, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& P);
  192. #endif