// Copyright 2013 - Christian Schüller 2013, schuellc@inf.ethz.ch // Interactive Geometry Lab - ETH Zurich #include "LGARAP_LIMSolver2D.h" #include "TriangleMesh.h" #define IGL_HEADER_ONLY #include "igl/cotmatrix_entries.h" LGARAP_LIMSolver2D::LGARAP_LIMSolver2D() { } LGARAP_LIMSolver2D::~LGARAP_LIMSolver2D() { } int LGARAP_LIMSolver2D::Solve() { computeLocalStep(); return LIMSolver2D::Solve(); } void LGARAP_LIMSolver2D::computeLocalStep() { const int numVertices = mesh->InitalVertices->rows(); const int numTriangles = mesh->Triangles->rows(); Eigen::MatrixXd uu, CovMat; Eigen::Matrix2d rot; Eigen::Matrix3d cc; cc.fill(0); uu.resize(3,2); CovMat.resize(2,2); Eigen::RowVector2d u0,u1,u2; Eigen::Vector2d u[3]; R.resize(4*numTriangles); // local step: Compute best rigid transformations for (int t=0;tTriangles->row(t); for(int i=0;i<3;i++) u[i] = mesh->DeformedVertices->block<1,2>(indices(i),0); for(int i=0;i<3;i++) uu.row(i) = u[TriEdgeVertices[i][1]]-u[TriEdgeVertices[i][0]]; cc(0,0) = CotanWeights(t,0); cc(1,1) = CotanWeights(t,1); cc(2,2) = CotanWeights(t,2); CovMat = RestPoseEdges.block<2,3>(2*t,0) * cc * uu; Eigen::JacobiSVD svdOfCovMat(CovMat, Eigen::ComputeThinU | Eigen::ComputeThinV); Eigen::Matrix2d u = svdOfCovMat.matrixU(); Eigen::Vector2d s = svdOfCovMat.singularValues(); Eigen::Matrix2d v = svdOfCovMat.matrixV(); rot = v * u.transpose(); if (rot.determinant() < 0) { if (s(0,0) < s(1,0)) u.col(0) = -u.col(0); else u.col(1) = -u.col(1); rot = v * u.transpose(); } const int idx = 4*t; R(idx) = rot(0,0); R(idx+1) = rot(1,0); R(idx+2) = rot(0,1); R(idx+3) = rot(1,1); } } void LGARAP_LIMSolver2D::debugOutput(std::stringstream& info) { std::cout << "AR:" << info.str() << "\n"; } void LGARAP_LIMSolver2D::prepareProblemData(std::vector& hessRowIdx, std::vector& hessColIdx) { const int numVertices = mesh->InitalVertices->rows(); const int numTriangles = mesh->Triangles->rows(); CotanWeights.resize(numTriangles,3); igl::cotmatrix_entries(*mesh->InitalVertices,*mesh->Triangles,CotanWeights); // Create matrices L, K Eigen::SparseMatrix B, tempL, tempK, restV; tempL.resize(numVertices,numVertices); tempK.resize(2*numTriangles,numVertices); std::vector > BTriplets, KTriplets, VTriplets, LTriplets; for(int t=0;tTriangles->coeff(t,idx0); const int vIdx1 = mesh->Triangles->coeff(t,idx1); // Create incident matrix B_i for i'th triangle BTriplets.push_back(Eigen::Triplet(vIdx0,i,1)); BTriplets.push_back(Eigen::Triplet(vIdx1,i,-1)); // Create 3D tet rest pose vertex matrix Eigen::Vector2d v0, v1; if(mesh->IsCorotatedTriangles) { v0 = mesh->CorotatedTriangles->block<1,2>(t,2*idx0); v1 = mesh->CorotatedTriangles->block<1,2>(t,2*idx1); } else { v0 = mesh->InitalVertices->row(mesh->Triangles->coeff(t,idx0)).block<1,2>(0,0); v1 = mesh->InitalVertices->row(mesh->Triangles->coeff(t,idx1)).block<1,2>(0,0); } VTriplets.push_back(Eigen::Triplet(vIdx0,0,v0(0))); VTriplets.push_back(Eigen::Triplet(vIdx0,1,v0(1))); VTriplets.push_back(Eigen::Triplet(vIdx1,0,v1(0))); VTriplets.push_back(Eigen::Triplet(vIdx1,1,v1(1))); } B.setFromTriplets(BTriplets.begin(),BTriplets.end()); restV.setFromTriplets(VTriplets.begin(),VTriplets.end()); Eigen::SparseMatrix Cm(3,3); Cm.insert(0,0) = CotanWeights(t,0); Cm.insert(1,1) = CotanWeights(t,1); Cm.insert(2,2) = CotanWeights(t,2); // Create B*C*B' Eigen::SparseMatrix BCBT = B*Cm*B.transpose(); // Stack up K temp matrix Eigen::SparseMatrix tempK = 0.5*restV.transpose()*BCBT; for (int k=0;k::InnerIterator it(tempK,k);it;++it) { KTriplets.push_back(Eigen::Triplet(2*t+it.row(),it.col(),it.value())); } } // Sum up L temp matrix for (int k=0;k::InnerIterator it(BCBT,k);it;++it) { int row = 2*it.row(); int col = 2*it.col(); LTriplets.push_back(Eigen::Triplet(row,col,it.value())); LTriplets.push_back(Eigen::Triplet(row+1,col+1,it.value())); } } } // Create L matrix L.resize(numVariables,numVariables); L.setFromTriplets(LTriplets.begin(),LTriplets.end()); // Create K matrix tempK.setFromTriplets(KTriplets.begin(),KTriplets.end()); K.resize(4*numTriangles,2*numVertices); KTriplets.clear(); for (int k=0;k::InnerIterator it(tempK,k);it;++it) { const int row = 2*it.row(); const int col = 2*it.col(); KTriplets.push_back(Eigen::Triplet(row,col,it.value())); KTriplets.push_back(Eigen::Triplet(row+1,col+1,it.value())); } } K.setFromTriplets(KTriplets.begin(), KTriplets.end()); RestPoseEdges.resize(3*numTriangles,3); Eigen::RowVector2d p[3]; for (int t=0;tIsCorotatedTriangles) { p[0] = mesh->CorotatedTriangles->block<1,2>(t,0); p[1] = mesh->CorotatedTriangles->block<1,2>(t,2); p[2] = mesh->CorotatedTriangles->block<1,2>(t,4); } else { p[0] = mesh->InitalVertices->row(mesh->Triangles->coeff(t,0)).block<1,2>(0,0); p[1] = mesh->InitalVertices->row(mesh->Triangles->coeff(t,1)).block<1,2>(0,0); p[2] = mesh->InitalVertices->row(mesh->Triangles->coeff(t,2)).block<1,2>(0,0); } for(int i=0;i<3;i++) RestPoseEdges.block<2,1>(2*t,i) = p[TriEdgeVertices[i][1]]-p[TriEdgeVertices[i][0]]; } for (int k=0;k::InnerIterator it(L,k);it;++it) { int row = it.row(); int col = it.col(); // std::sort for upper triangule matrix if(row <= col) { hessRowIdx.push_back(row); hessColIdx.push_back(col); } } } // compute constant energy bias for restpose int numVariables = numVertices*2; Eigen::Matrix restPose(numVariables); for(int n=0;nInitalVertices->coeff(n,i); } constantEnergyPart = 0.5*restPose.transpose()*L*restPose; } double LGARAP_LIMSolver2D::computeFunction(const Eigen::Matrix& x) { // ARAP global step energy double xTLx = x.transpose()*L*x; double KTRx = R.transpose()*K*x; return 0.5*xTLx - KTRx + constantEnergyPart; } void LGARAP_LIMSolver2D::computeGradient(const Eigen::Matrix& x, Eigen::Matrix& grad) { // ARAP global step grad = L*x - K.transpose()*R; } void LGARAP_LIMSolver2D::computeHessian(const Eigen::Matrix& x, const Eigen::Matrix& hess) { // ARAP global step int numElem = 0; for (int k=0;k::InnerIterator it(L,k);it;++it) { if(it.row() <= it.col()) *hess[numElem++] = it.value(); } } }