int main(int argc, char *argv[]) { using namespace Eigen; using namespace std; // Load a quad mesh generated by a conjugate field igl::readOFF(TUTORIAL_SHARED_PATH "/inspired_mesh_quads_Conjugate.off", VQC, FQC); // Convert it in a triangle mesh FQCtri.resize(2*FQC.rows(), 3); FQCtri << FQC.col(0),FQC.col(1),FQC.col(2), FQC.col(2),FQC.col(3),FQC.col(0); igl::slice( VQC, FQC.col(0).eval(), 1, PQC0); igl::slice( VQC, FQC.col(1).eval(), 1, PQC1); igl::slice( VQC, FQC.col(2).eval(), 1, PQC2); igl::slice( VQC, FQC.col(3).eval(), 1, PQC3); // Planarize it igl::planarize_quad_mesh(VQC, FQC, 100, 0.005, VQCplan); // Convert the planarized mesh to triangles igl::slice( VQCplan, FQC.col(0).eval(), 1, PQC0plan); igl::slice( VQCplan, FQC.col(1).eval(), 1, PQC1plan); igl::slice( VQCplan, FQC.col(2).eval(), 1, PQC2plan); igl::slice( VQCplan, FQC.col(3).eval(), 1, PQC3plan); // Launch the viewer igl::viewer::Viewer viewer; key_down(viewer,'2',0); viewer.data.invert_normals = true; viewer.data.show_lines = false; viewer.callback_key_down = &key_down; viewer.launch(); }
int NuTo::Structure::ElementsCreate(int rInterpolationTypeId, const Eigen::MatrixXi& rNodeNumbers) { std::vector<int> newElementIds; // go through the elements for (int iNode = 0; iNode < rNodeNumbers.cols(); ++iNode) { auto column = rNodeNumbers.col(iNode); std::vector<int> incidence(column.data(), column.data() + column.size()); int newElementId = ElementCreate(rInterpolationTypeId, incidence); newElementIds.push_back(newElementId); } bool showTime = mShowTime; mShowTime = false; // create element group containing the new elements int newElementGroup = GroupCreate(eGroupId::Elements); for (int newElementId : newElementIds) GroupAddElement(newElementGroup, newElementId); mShowTime = showTime; return newElementGroup; }
IGL_INLINE bool igl::arap_dof_precomputation( const Eigen::MatrixXd & V, const Eigen::MatrixXi & F, const LbsMatrixType & M, const Eigen::Matrix<int,Eigen::Dynamic,1> & G, ArapDOFData<LbsMatrixType, SSCALAR> & data) { using namespace Eigen; typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS; // number of mesh (domain) vertices int n = V.rows(); // cache problem size data.n = n; // dimension of mesh data.dim = V.cols(); assert(data.dim == M.rows()/n); assert(data.dim*n == M.rows()); if(data.dim == 3) { // Check if z-coordinate is all zeros if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0) { data.effective_dim = 2; } }else { data.effective_dim = data.dim; } // Number of handles data.m = M.cols()/data.dim/(data.dim+1); assert(data.m*data.dim*(data.dim+1) == M.cols()); //assert(m == C.rows()); //printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m); // Build cotangent laplacian SparseMatrix<double> Lcot; //printf("cotmatrix()\n"); cotmatrix(V,F,Lcot); // Discrete laplacian (should be minus matlab version) SparseMatrix<double> Lapl = -2.0*Lcot; #ifdef EXTREME_VERBOSE cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<< endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<< Lapl.rows()<<","<<Lapl.cols()<<");"<<endl; #endif // Get group sum scatter matrix, when applied sums all entries of the same // group according to G SparseMatrix<double> G_sum; if(G.size() == 0) { speye(n,G_sum); }else { // groups are defined per vertex, convert to per face using mode Eigen::Matrix<int,Eigen::Dynamic,1> GG; if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS) { MatrixXi GF(F.rows(),F.cols()); for(int j = 0;j<F.cols();j++) { Matrix<int,Eigen::Dynamic,1> GFj; slice(G,F.col(j),GFj); GF.col(j) = GFj; } mode<int>(GF,2,GG); }else { GG=G; } //printf("group_sum_matrix()\n"); group_sum_matrix(GG,G_sum); } #ifdef EXTREME_VERBOSE cout<<"G_sumIJV=["<<endl;print_ijv(G_sum,1);cout<<endl<<"];"<< endl<<"G_sum=sparse(G_sumIJV(:,1),G_sumIJV(:,2),G_sumIJV(:,3),"<< G_sum.rows()<<","<<G_sum.cols()<<");"<<endl; #endif // Get covariance scatter matrix, when applied collects the covariance matrices // used to fit rotations to during optimization SparseMatrix<double> CSM; //printf("covariance_scatter_matrix()\n"); covariance_scatter_matrix(V,F,data.energy,CSM); #ifdef EXTREME_VERBOSE cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<< endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<< CSM.rows()<<","<<CSM.cols()<<");"<<endl; #endif // Build the covariance matrix "constructor". This is a set of *scatter* // matrices that when multiplied on the right by column of the transformation // matrix entries (the degrees of freedom) L, we get a stack of dim by 1 // covariance matrix column, with a column in the stack for each rotation // *group*. The output is a list of matrices because we construct each column // in the stack of covariance matrices with an independent matrix-vector // multiplication. // // We want to build S which is a stack of dim by dim covariance matrices. // Thus S is dim*g by dim, where dim is the number of dimensions and g is the // number of groups. We can precompute dim matrices CSM_M such that column i // in S is computed as S(:,i) = CSM_M{i} * L, where L is a column of the // skinning transformation matrix values. To be clear, the covariance matrix // for group k is then given as the dim by dim matrix pulled from the stack: // S((k-1)*dim + 1:dim,:) // Apply group sum to each dimension's block of covariance scatter matrix SparseMatrix<double> G_sum_dim; repdiag(G_sum,data.dim,G_sum_dim); CSM = G_sum_dim * CSM; #ifdef EXTREME_VERBOSE cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<< endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<< CSM.rows()<<","<<CSM.cols()<<");"<<endl; #endif //printf("CSM_M()\n"); // Precompute CSM times M for each dimension data.CSM_M.resize(data.dim); #ifdef EXTREME_VERBOSE cout<<"data.CSM_M = cell("<<data.dim<<",1);"<<endl; #endif // span of integers from 0 to n-1 Eigen::Matrix<int,Eigen::Dynamic,1> span_n(n); for(int i = 0;i<n;i++) { span_n(i) = i; } // span of integers from 0 to M.cols()-1 Eigen::Matrix<int,Eigen::Dynamic,1> span_mlbs_cols(M.cols()); for(int i = 0;i<M.cols();i++) { span_mlbs_cols(i) = i; } // number of groups int k = CSM.rows()/data.dim; for(int i = 0;i<data.dim;i++) { //printf("CSM_M(): Mi\n"); LbsMatrixType M_i; //printf("CSM_M(): slice\n"); slice(M,(span_n.array()+i*n).matrix(),span_mlbs_cols,M_i); LbsMatrixType M_i_dim; data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1)); assert(data.CSM_M[i].cols() == M.cols()); for(int j = 0;j<data.dim;j++) { SparseMatrix<double> CSMj; //printf("CSM_M(): slice\n"); slice( CSM, colon<int>(j*k,(j+1)*k-1), colon<int>(j*n,(j+1)*n-1), CSMj); assert(CSMj.rows() == k); assert(CSMj.cols() == n); LbsMatrixType CSMjM_i = CSMj * M_i; if(is_sparse(CSMjM_i)) { // Convert to full MatrixXd CSMjM_ifull; //printf("CSM_M(): full\n"); full(CSMjM_i,CSMjM_ifull); // printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols()); // printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(), // data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(), // data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols()); // printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols()); // printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols()); data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull; }else { data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i; } } #ifdef EXTREME_VERBOSE cout<<"CSM_Mi=["<<endl<<data.CSM_M[i]<<endl<<"];"<<endl; #endif } // precompute arap_rhs matrix //printf("arap_rhs()\n"); SparseMatrix<double> K; arap_rhs(V,F,V.cols(),data.energy,K); //#ifdef EXTREME_VERBOSE // cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<< // endl<<"K=sparse(KIJV(:,1),KIJV(:,2),KIJV(:,3),"<< // K.rows()<<","<<K.cols()<<");"<<endl; //#endif // Precompute left muliplication by M and right multiplication by G_sum SparseMatrix<double> G_sumT = G_sum.transpose(); SparseMatrix<double> G_sumT_dim_dim; repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim); LbsMatrixType MT = M.transpose(); // If this is a bottle neck then consider reordering matrix multiplication data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim)); //#ifdef EXTREME_VERBOSE // cout<<"data.M_KGIJV=["<<endl;print_ijv(data.M_KG,1);cout<<endl<<"];"<< // endl<<"data.M_KG=sparse(data.M_KGIJV(:,1),data.M_KGIJV(:,2),data.M_KGIJV(:,3),"<< // data.M_KG.rows()<<","<<data.M_KG.cols()<<");"<<endl; //#endif // Precompute system matrix //printf("A()\n"); SparseMatrix<double> A; repdiag(Lapl,data.dim,A); data.Q = MT * (A * M); //#ifdef EXTREME_VERBOSE // cout<<"QIJV=["<<endl;print_ijv(data.Q,1);cout<<endl<<"];"<< // endl<<"Q=sparse(QIJV(:,1),QIJV(:,2),QIJV(:,3),"<< // data.Q.rows()<<","<<data.Q.cols()<<");"<<endl; //#endif // Always do dynamics precomputation so we can hot-switch //if(data.with_dynamics) //{ // Build cotangent laplacian SparseMatrix<double> Mass; //printf("massmatrix()\n"); massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass); //cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<< // endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<< // Mass.rows()<<","<<Mass.cols()<<");"<<endl; //speye(data.n,Mass); SparseMatrix<double> Mass_rep; repdiag(Mass,data.dim,Mass_rep); // Multiply either side by weights matrix (should be dense) data.Mass_tilde = MT * Mass_rep * M; MatrixXd ones(data.dim*data.n,data.dim); for(int i = 0;i<data.n;i++) { for(int d = 0;d<data.dim;d++) { ones(i+d*data.n,d) = 1; } } data.fgrav = MT * (Mass_rep * ones); data.fext = MatrixXS::Zero(MT.rows(),1); //data.fgrav = MT * (ones); //} // This may/should be superfluous //printf("is_symmetric()\n"); if(!is_symmetric(data.Q)) { //printf("Fixing symmetry...\n"); // "Fix" symmetry LbsMatrixType QT = data.Q.transpose(); LbsMatrixType Q_copy = data.Q; data.Q = 0.5*(Q_copy+QT); // Check that ^^^ this really worked. It doesn't always //assert(is_symmetric(*Q)); } //printf("arap_dof_precomputation() succeeded... so far...\n"); verbose("Number of handles: %i\n", data.m); return true; }