// This file is part of libigl, a simple c++ geometry processing library. // // Copyright (C) 2013 Alec Jacobson // // This Source Code Form is subject to the terms of the Mozilla Public License // v. 2.0. If a copy of the MPL was not distributed with this file, You can // obtain one at http://mozilla.org/MPL/2.0/. #include "arap.h" #include #include #include #include #include #include #include #include #include #include #include #include #include template < typename DerivedV, typename DerivedF, typename Derivedb> IGL_INLINE bool igl::arap_precomputation( const Eigen::PlainObjectBase & V, const Eigen::PlainObjectBase & F, const Eigen::PlainObjectBase & b, ARAPData & data) { using namespace igl; using namespace Eigen; typedef typename DerivedV::Scalar Scalar; // number of vertices const int n = V.rows(); data.n = n; assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds"); assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds"); // remember b data.b = b; assert(F.cols() == 3 && "For now only triangles"); // dimension const int dim = V.cols(); assert(dim == 3 && "Only 3d supported"); // Defaults data.f_ext = Eigen::MatrixXd::Zero(n,dim); SparseMatrix L; cotmatrix(V,F,L); ARAPEnergyType eff_energy = data.energy; if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT) { switch(F.cols()) { case 3: if(dim == 3) { eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS; }else { eff_energy = ARAP_ENERGY_TYPE_ELEMENTS; } break; case 4: eff_energy = ARAP_ENERGY_TYPE_ELEMENTS; default: assert(false); } } // Get covariance scatter matrix, when applied collects the covariance matrices // used to fit rotations to during optimization covariance_scatter_matrix(V,F,eff_energy,data.CSM); // Get group sum scatter matrix, when applied sums all entries of the same // group according to G SparseMatrix G_sum; if(data.G.size() == 0) { speye(n,G_sum); }else { // groups are defined per vertex, convert to per face using mode Eigen::Matrix GG; if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS) { MatrixXi GF(F.rows(),F.cols()); for(int j = 0;j GFj; slice(data.G,F.col(j),GFj); GF.col(j) = GFj; } mode(GF,2,GG); }else { GG=data.G; } //printf("group_sum_matrix()\n"); group_sum_matrix(GG,G_sum); } SparseMatrix G_sum_dim; repdiag(G_sum,dim,G_sum_dim); data.CSM = (G_sum_dim * data.CSM).eval(); arap_rhs(V,F,eff_energy,data.K); SparseMatrix Q = (-0.5*L).eval(); return min_quad_with_fixed_precompute( Q,b,SparseMatrix(),true,data.solver_data); } template < typename Derivedbc, typename DerivedU> IGL_INLINE bool igl::arap_solve( const Eigen::PlainObjectBase & bc, ARAPData & data, Eigen::PlainObjectBase & U) { using namespace igl; using namespace Eigen; using namespace std; assert(data.b.size() == bc.rows()); const int dim = bc.cols(); const int n = data.n; int iter = 0; if(U.size() == 0) { // terrible initial guess.. should at least copy input mesh U = MatrixXd::Zero(data.n,dim); } MatrixXd U_prev = U; while(iter < data.max_iter) { U_prev = U; // enforce boundary conditions exactly for(int bi = 0;bi, Eigen::Matrix, Eigen::Matrix >(Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, Eigen::PlainObjectBase > const&, igl::ARAPData&); template bool igl::arap_solve, Eigen::Matrix >(Eigen::PlainObjectBase > const&, igl::ARAPData&, Eigen::PlainObjectBase >&); #endif