IGL_INLINE void igl::adjacency_matrix( const Eigen::PlainObjectBase<DerivedF> & F, Eigen::SparseMatrix<T>& A) { using namespace std; using namespace Eigen; typedef typename DerivedF::Scalar Index; typedef Triplet<T> IJV; vector<IJV > ijv; ijv.reserve(F.size()*2); // Loop over faces for(int i = 0;i<F.rows();i++) { // Loop over this face for(int j = 0;j<F.cols();j++) { // Get indices of edge: s --> d Index s = F(i,j); Index d = F(i,(j+1)%F.cols()); ijv.push_back(IJV(s,d,1)); ijv.push_back(IJV(d,s,1)); } } const Index n = F.maxCoeff()+1; A.resize(n,n); switch(F.cols()) { case 3: A.reserve(6*(F.maxCoeff()+1)); break; case 4: A.reserve(26*(F.maxCoeff()+1)); break; } A.setFromTriplets(ijv.begin(),ijv.end()); // Force all non-zeros to be one // Iterate over outside for(int k=0; k<A.outerSize(); ++k) { // Iterate over inside for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it) { assert(it.value() != 0); A.coeffRef(it.row(),it.col()) = 1; } } }
void LaplacianOperator::computeLaplacianOperator( Eigen::SparseMatrix<double>& laplacianOperator ) { laplacianOperator.resize(mMeshVertexCount,mMeshVertexCount); laplacianOperator.reserve(Eigen::VectorXi::Constant(mMeshVertexCount,10)); for (int i = 0; i < mMeshVertexCount; i++) { /* 如果第i个点没有邻接点,即它是一个孤立的点,那么它的laplacian坐标为0 */ if( adjacentMatrix.innerVector(i).nonZeros() == 0) { laplacianOperator.insert(i,i) = 0; continue; } laplacianOperator.insert(i,i) = 1; #ifdef MY_DEBUG int adjCount = 0; #endif for (Eigen::SparseMatrix<double>::InnerIterator it(adjacentMatrix,i); it; it++) { if(i != it.row()) { laplacianOperator.insert(i,it.row()) = -1/degreeMatrix(i); #ifdef MY_DEBUG adjCount++; if(adjCount >= 10) printf("InnerVector size should expand! CurrentMax:%d.\n",adjCount); #endif } } } }
IGL_INLINE void igl::speye(const int m, const int n, Eigen::SparseMatrix<T> & I) { // size of diagonal int d = (m<n?m:n); I = Eigen::SparseMatrix<T>(m,n); I.reserve(d); for(int i = 0;i<d;i++) { I.insert(i,i) = 1.0; } I.finalize(); }
inline void identity_operator( Eigen::SparseMatrix<double>& result, int size) { result.resize(size, size); result.reserve(size); std::vector<double_triplet_t> matrix_coeffs; matrix_coeffs.reserve(size); // #diag // diag for (int i = 0; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i, 1.)); result.setFromTriplets(matrix_coeffs.begin(), matrix_coeffs.end()); }
inline void laplace_operator_1d( Eigen::SparseMatrix<double>& result, int size) { result.resize(size, size); result.reserve(size*3-2); std::vector<double_triplet_t> matrix_coeffs; matrix_coeffs.reserve(size*3-2); // #diag + #diag(-1) + #diag(+1) // diag for (int i = 0; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i, -2.)); // diag(-1) for (int i = 1; i < size; ++i) matrix_coeffs.push_back(double_triplet_t(i,i-1, 1.)); // diag(+1) for (int i = 0; i < size-1; ++i) matrix_coeffs.push_back(double_triplet_t(i,i+1, 1.)); result.setFromTriplets(matrix_coeffs.begin(), matrix_coeffs.end()); }
IGL_INLINE void igl::cotmatrix( const Eigen::MatrixBase<DerivedV> & V, const Eigen::MatrixBase<DerivedF> & F, Eigen::SparseMatrix<Scalar>& L) { using namespace Eigen; using namespace std; L.resize(V.rows(),V.rows()); Matrix<int,Dynamic,2> edges; int simplex_size = F.cols(); // 3 for triangles, 4 for tets assert(simplex_size == 3 || simplex_size == 4); if(simplex_size == 3) { // This is important! it could decrease the comptuation time by a factor of 2 // Laplacian for a closed 2d manifold mesh will have on average 7 entries per // row L.reserve(10*V.rows()); edges.resize(3,2); edges << 1,2, 2,0, 0,1; }else if(simplex_size == 4) { L.reserve(17*V.rows()); edges.resize(6,2); edges << 1,2, 2,0, 0,1, 3,0, 3,1, 3,2; }else { return; } // Gather cotangents Matrix<Scalar,Dynamic,Dynamic> C; cotmatrix_entries(V,F,C); vector<Triplet<Scalar> > IJV; IJV.reserve(F.rows()*edges.rows()*4); // Loop over triangles for(int i = 0; i < F.rows(); i++) { // loop over edges of element for(int e = 0;e<edges.rows();e++) { int source = F(i,edges(e,0)); int dest = F(i,edges(e,1)); IJV.push_back(Triplet<Scalar>(source,dest,C(i,e))); IJV.push_back(Triplet<Scalar>(dest,source,C(i,e))); IJV.push_back(Triplet<Scalar>(source,source,-C(i,e))); IJV.push_back(Triplet<Scalar>(dest,dest,-C(i,e))); } } L.setFromTriplets(IJV.begin(),IJV.end()); }
IGL_INLINE void igl::arap_linear_block_spokes( const MatV & V, const MatF & F, const int d, Eigen::SparseMatrix<Scalar> & Kd) { using namespace std; using namespace Eigen; // simplex size (3: triangles, 4: tetrahedra) int simplex_size = F.cols(); // Number of elements int m = F.rows(); // Temporary output Matrix<int,Dynamic,2> edges; Kd.resize(V.rows(), V.rows()); vector<Triplet<Scalar> > Kd_IJV; if(simplex_size == 3) { // triangles Kd.reserve(7*V.rows()); Kd_IJV.reserve(7*V.rows()); edges.resize(3,2); edges << 1,2, 2,0, 0,1; }else if(simplex_size == 4) { // tets Kd.reserve(17*V.rows()); Kd_IJV.reserve(17*V.rows()); edges.resize(6,2); edges << 1,2, 2,0, 0,1, 3,0, 3,1, 3,2; } // gather cotangent weights Matrix<Scalar,Dynamic,Dynamic> C; cotmatrix_entries(V,F,C); // should have weights for each edge assert(C.cols() == edges.rows()); // loop over elements for(int i = 0;i<m;i++) { // loop over edges of element for(int e = 0;e<edges.rows();e++) { int source = F(i,edges(e,0)); int dest = F(i,edges(e,1)); double v = 0.5*C(i,e)*(V(source,d)-V(dest,d)); Kd_IJV.push_back(Triplet<Scalar>(source,dest,v)); Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v)); Kd_IJV.push_back(Triplet<Scalar>(source,source,v)); Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v)); } } Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end()); Kd.makeCompressed(); }
IGL_INLINE void igl::slice_tets( const Eigen::PlainObjectBase<DerivedV>& V, const Eigen::PlainObjectBase<DerivedT>& T, const Eigen::PlainObjectBase<Derivedplane> & plane, Eigen::PlainObjectBase<DerivedU>& U, Eigen::PlainObjectBase<DerivedG>& G, Eigen::PlainObjectBase<DerivedJ>& J, Eigen::SparseMatrix<BCType> & BC) { using namespace Eigen; using namespace std; assert(V.cols() == 3 && "V should be #V by 3"); assert(T.cols() == 4 && "T should be #T by 4"); assert(plane.size() == 4 && "Plane equation should be 4 coefficients"); // number of tets const size_t m = T.rows(); typedef typename DerivedV::Scalar Scalar; typedef typename DerivedT::Scalar Index; typedef Matrix<Scalar,Dynamic,1> VectorXS; typedef Matrix<Scalar,Dynamic,4> MatrixX4S; typedef Matrix<Scalar,Dynamic,3> MatrixX3S; typedef Matrix<Scalar,Dynamic,2> MatrixX2S; typedef Matrix<Index,Dynamic,4> MatrixX4I; typedef Matrix<Index,Dynamic,3> MatrixX3I; typedef Matrix<Index,Dynamic,1> VectorXI; typedef Matrix<bool,Dynamic,1> VectorXb; // Value of plane's implicit function at all vertices VectorXS IV = (V.col(0)*plane(0) + V.col(1)*plane(1) + V.col(2)*plane(2)).array() + plane(3); MatrixX4S IT(m,4); for(size_t t = 0;t<m;t++) { for(size_t c = 0;c<4;c++) { IT(t,c) = IV(T(t,c)); } } const auto & extract_rows = []( const PlainObjectBase<DerivedT> & T, const MatrixX4S & IT, const VectorXb & I, MatrixX4I & TI, MatrixX4S & ITI, VectorXI & JI) { const Index num_I = std::count(I.data(),I.data()+I.size(),true); TI.resize(num_I,4); ITI.resize(num_I,4); JI.resize(num_I,1); { size_t k = 0; for(size_t t = 0;t<(size_t)T.rows();t++) { if(I(t)) { TI.row(k) = T.row(t); ITI.row(k) = IT.row(t); JI(k) = t; k++; } } assert(k == num_I); } }; VectorXb I13 = (IT.array()<0).rowwise().count()==1; VectorXb I31 = (IT.array()>0).rowwise().count()==1; VectorXb I22 = (IT.array()<0).rowwise().count()==2; MatrixX4I T13,T31,T22; MatrixX4S IT13,IT31,IT22; VectorXI J13,J31,J22; extract_rows(T,IT,I13,T13,IT13,J13); extract_rows(T,IT,I31,T31,IT31,J31); extract_rows(T,IT,I22,T22,IT22,J22); const auto & apply_sort = [] ( const MatrixX4I & T, const MatrixX4I & sJ, MatrixX4I & sT) { sT.resize(T.rows(),4); for(size_t t = 0;t<(size_t)T.rows();t++) { for(size_t c = 0;c<4;c++) { sT(t,c) = T(t,sJ(t,c)); } } }; const auto & one_below = [&V,&apply_sort]( const MatrixX4I & T, const MatrixX4S & IT, MatrixX3I & G, SparseMatrix<BCType> & BC) { // Number of tets const size_t m = T.rows(); MatrixX4S sIT; MatrixX4I sJ; sort(IT,2,true,sIT,sJ); MatrixX4I sT; apply_sort(T,sJ,sT); MatrixX3S lambda = sIT.rightCols(3).array() / (sIT.rightCols(3).colwise()-sIT.col(0)).array(); vector<Triplet<BCType> > IJV; IJV.reserve(m*3*2); for(size_t c = 0;c<3;c++) { for(size_t t = 0;t<(size_t)m;t++) { IJV.push_back(Triplet<BCType>(c*m+t, sT(t,0), lambda(t,c))); IJV.push_back(Triplet<BCType>(c*m+t,sT(t,c+1),1-lambda(t,c))); } } BC.resize(m*3,V.rows()); BC.reserve(m*3*2); BC.setFromTriplets(IJV.begin(),IJV.end()); G.resize(m,3); for(size_t c = 0;c<3;c++) { G.col(c).setLinSpaced(m,0+c*m,(m-1)+c*m); } }; const auto & two_below = [&V,&apply_sort]( const MatrixX4I & T, const MatrixX4S & IT, MatrixX3I & G, SparseMatrix<BCType> & BC) { // Number of tets const size_t m = T.rows(); MatrixX4S sIT; MatrixX4I sJ; sort(IT,2,true,sIT,sJ); MatrixX4I sT; apply_sort(T,sJ,sT); MatrixX2S lambda = sIT.rightCols(2).array() / (sIT.rightCols(2).colwise()-sIT.col(0)).array(); MatrixX2S gamma = sIT.rightCols(2).array() / (sIT.rightCols(2).colwise()-sIT.col(1)).array(); vector<Triplet<BCType> > IJV; IJV.reserve(m*4*2); for(size_t c = 0;c<2;c++) { for(size_t t = 0;t<(size_t)m;t++) { IJV.push_back(Triplet<BCType>(0*2*m+c*m+t, sT(t,0), lambda(t,c))); IJV.push_back(Triplet<BCType>(0*2*m+c*m+t,sT(t,c+2),1-lambda(t,c))); IJV.push_back(Triplet<BCType>(1*2*m+c*m+t, sT(t,1), gamma(t,c))); IJV.push_back(Triplet<BCType>(1*2*m+c*m+t,sT(t,c+2),1- gamma(t,c))); } } BC.resize(m*4,V.rows()); BC.reserve(m*4*2); BC.setFromTriplets(IJV.begin(),IJV.end()); G.resize(2*m,3); G.block(0,0,m,1) = VectorXI::LinSpaced(m,0+0*m,(m-1)+0*m); G.block(0,1,m,1) = VectorXI::LinSpaced(m,0+1*m,(m-1)+1*m); G.block(0,2,m,1) = VectorXI::LinSpaced(m,0+3*m,(m-1)+3*m); G.block(m,0,m,1) = VectorXI::LinSpaced(m,0+0*m,(m-1)+0*m); G.block(m,1,m,1) = VectorXI::LinSpaced(m,0+3*m,(m-1)+3*m); G.block(m,2,m,1) = VectorXI::LinSpaced(m,0+2*m,(m-1)+2*m); }; MatrixX3I G13,G31,G22; SparseMatrix<BCType> BC13,BC31,BC22; one_below(T13,IT13,G13,BC13); one_below(T31,-IT31,G31,BC31); two_below(T22,IT22,G22,BC22); BC = cat(1,cat(1,BC13,BC31),BC22); U = BC*V; G.resize(G13.rows()+G31.rows()+G22.rows(),3); G<<G13,(G31.array()+BC13.rows()),(G22.array()+BC13.rows()+BC31.rows()); MatrixX3S N; per_face_normals(U,G,N); Matrix<Scalar,1,3> planeN(plane(0),plane(1),plane(2)); VectorXb flip = (N.array().rowwise() * planeN.array()).rowwise().sum()<0; for(size_t g = 0;g<(size_t)G.rows();g++) { if(flip(g)) { G.row(g) = G.row(g).reverse().eval(); } } J.resize(G.rows()); J<<J13,J31,J22,J22; }