IGL_INLINE void igl::jet( const Eigen::PlainObjectBase<DerivedZ> & Z, const bool normalize, Eigen::PlainObjectBase<DerivedC> & C) { const double min_z = (normalize?Z.minCoeff():0); const double max_z = (normalize?Z.maxCoeff():-1); return jet(Z,min_z,max_z,C); }
IGL_INLINE void igl::slice( const Eigen::PlainObjectBase<DerivedX> & X, const Eigen::PlainObjectBase<DerivedR> & R, const Eigen::PlainObjectBase<DerivedC> & C, Eigen::PlainObjectBase<DerivedY> & Y) { #ifndef NDEBUG int xm = X.rows(); int xn = X.cols(); #endif int ym = R.size(); int yn = C.size(); // special case when R or C is empty if(ym == 0 || yn == 0) { Y.resize(ym,yn); return; } assert(R.minCoeff() >= 0); assert(R.maxCoeff() < xm); assert(C.minCoeff() >= 0); assert(C.maxCoeff() < xn); // Resize output Y.resize(ym,yn); // loop over output rows, then columns for(int i = 0;i<ym;i++) { for(int j = 0;j<yn;j++) { Y(i,j) = X(R(i),C(j)); } } }
IGL_INLINE bool igl::arap_precomputation( const Eigen::PlainObjectBase<DerivedV> & V, const Eigen::PlainObjectBase<DerivedF> & F, const int dim, const Eigen::PlainObjectBase<Derivedb> & b, ARAPData & data) { using namespace std; 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 || dim ==2) && "dim should be 2 or 3"); data.dim = dim; //assert(dim == 3 && "Only 3d supported"); // Defaults data.f_ext = MatrixXd::Zero(n,data.dim); assert(data.dim <= V.cols() && "solve dim should be <= embedding"); bool flat = (V.cols() - data.dim)==1; DerivedV plane_V; DerivedF plane_F; typedef SparseMatrix<Scalar> SparseMatrixS; SparseMatrixS ref_map,ref_map_dim; if(flat) { project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map); repdiag(ref_map,dim,ref_map_dim); } const PlainObjectBase<DerivedV>& ref_V = (flat?plane_V:V); const PlainObjectBase<DerivedF>& ref_F = (flat?plane_F:F); SparseMatrixS L; cotmatrix(V,F,L); ARAPEnergyType eff_energy = data.energy; if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT) { switch(F.cols()) { case 3: if(data.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; break; default: assert(false); } } // Get covariance scatter matrix, when applied collects the covariance // matrices used to fit rotations to during optimization covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM); if(flat) { data.CSM = (data.CSM * ref_map_dim.transpose()).eval(); } assert(data.CSM.cols() == V.rows()*data.dim); // Get group sum scatter matrix, when applied sums all entries of the same // group according to G SparseMatrix<double> G_sum; if(data.G.size() == 0) { if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS) { speye(F.rows(),G_sum); } else { speye(n,G_sum); } } else { // groups are defined per vertex, convert to per face using mode if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS) { Eigen::Matrix<int,Eigen::Dynamic,1> GG; MatrixXi GF(F.rows(),F.cols()); for(int j = 0; j<F.cols(); j++) { Matrix<int,Eigen::Dynamic,1> GFj; slice(data.G,F.col(j),GFj); GF.col(j) = GFj; } mode<int>(GF,2,GG); data.G=GG; } //printf("group_sum_matrix()\n"); group_sum_matrix(data.G,G_sum); } SparseMatrix<double> G_sum_dim; repdiag(G_sum,data.dim,G_sum_dim); assert(G_sum_dim.cols() == data.CSM.rows()); data.CSM = (G_sum_dim * data.CSM).eval(); arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K); if(flat) { data.K = (ref_map_dim * data.K).eval(); } assert(data.K.rows() == data.n*data.dim); SparseMatrix<double> Q = (-L).eval(); if(data.with_dynamics) { const double h = data.h; assert(h != 0); SparseMatrix<double> M; massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M); const double dw = (1./data.ym)*(h*h); SparseMatrix<double> DQ = dw * 1./(h*h)*data.M; Q += DQ; // Dummy external forces data.f_ext = MatrixXd::Zero(n,data.dim); data.vel = MatrixXd::Zero(n,data.dim); } return min_quad_with_fixed_precompute( Q,b,SparseMatrix<double>(),true,data.solver_data); }