diff --git a/vcg/complex/algorithms/implicit_smooth.h b/vcg/complex/algorithms/implicit_smooth.h index 4eb6bc38..3bf26015 100644 --- a/vcg/complex/algorithms/implicit_smooth.h +++ b/vcg/complex/algorithms/implicit_smooth.h @@ -48,23 +48,21 @@ public: struct FaceConstraint { int numF; - std::vector > BarycentricW; + std::vector BarycentricW; CoordType TargetPos; - ScalarType Weight; FaceConstraint() { numF=-1; - Weight=0; } - FaceConstraint(int _numF,const std::vector > &_BarycentricW, - const CoordType &_TargetPos,ScalarType _Weight) + FaceConstraint(int _numF, + const std::vector &_BarycentricW, + const CoordType &_TargetPos) { numF=_numF; - BarycentricW= std::vector > (_BarycentricW.begin(),_BarycentricW.end()); + BarycentricW= std::vector (_BarycentricW.begin(),_BarycentricW.end()); TargetPos=_TargetPos; - Weight=_Weight; } }; @@ -83,9 +81,12 @@ public: std::vector FixedV; //the set of faces for barycentric constraints std::vector ConstrainedF; + //the degree of laplacian + int degree; Parameter() { + degree=1; lambda=0.2; useMassMatrix=true; fixBorder=false; @@ -95,39 +96,12 @@ public: private: - // void GetMassMatrix(MeshType &mesh, - // std::vector > &index, - // std::vector &entry) - // { - // entry.clear(); - // index.clear(); - - // //calculate area - // vcg::tri::UpdateQuality::FaceArea(mesh); - // //then distribute per vertex - // vcg::tri::UpdateQuality::VertexFromFace(mesh); - - // //3, one per coordinate - // index.resize(mesh.vert.size()*3,-1); - // entry.resize(mesh.vert.size()*3,0); - - // //store the index and the scalar for the sparse matrix - // for (size_t i=0;i > &Index, - const std::vector &Values, - const size_t m, - const size_t n, - Eigen::SparseMatrix& X) + const std::vector &Values, + const size_t m, + const size_t n, + Eigen::SparseMatrix& X) { assert(Index.size()==Values.size()); @@ -149,16 +123,10 @@ private: X.setFromTriplets(IJV.begin(),IJV.end()); } - int SystemSize(MeshType &mesh, Parameter & SParam) - { - int basic_size=mesh.vert.size(); - int constr_size=SParam.ConstrainedF.size(); - return (basic_size+constr_size); - } - void CollectHardConstraints(MeshType &mesh,const Parameter &SParam, - std::vector > &IndexC, - std::vector &WeightC) + static void CollectHardConstraints(MeshType &mesh,const Parameter &SParam, + std::vector > &IndexC, + std::vector &WeightC) { std::vector To_Fix; @@ -184,62 +152,88 @@ private: { for (int j=0;j<3;j++) { - int IndexV=(i*3)+j; + int IndexV=(To_Fix[i]*3)+j; IndexC.push_back(std::pair(IndexV,IndexV)); WeightC.push_back((ScalarType)PENALTY); } } } + static void CollectBarycentricConstraints(MeshType &mesh, + const Parameter &SParam, + std::vector > &IndexC, + std::vector &WeightC, + std::vector &IndexRhs, + std::vector &ValueRhs) + { + int baseIndex=mesh.vert.size(); + for (size_t i=0;i=0); + assert(FaceN(ComponentConstraint,IndexV)); + + WeightC.push_back(currW*PENALTY); + + IndexC.push_back(std::pair(IndexV,ComponentConstraint)); + WeightC.push_back(currW*PENALTY); + + //this to avoid the 1 on diagonal last entry of mass matrix + IndexC.push_back(std::pair(ComponentConstraint,ComponentConstraint)); + WeightC.push_back(-1); + } + } + + for (int j=0;j<3;j++) + { + //get the index of the current constraint + int ComponentConstraint=(IndexConstraint*3)+j; + + //get per component value + ScalarType ComponentV=SParam.ConstrainedF[i].TargetPos.V(j); + + //add the diagonal value + IndexRhs.push_back(ComponentConstraint); + ValueRhs.push_back(ComponentV*PENALTY); + } + + } + } + public: - - //static void Smooth - // static void SmoothLIbIGL(MeshType &mesh, - // ScalarType lambda=0.5)//0.0001) - // { - // Eigen::MatrixXi F; - // Eigen::MatrixXd V,U; - // vcg::tri::MeshToMatrix::GetTriMeshData(mesh,F,V); - // U=V; - - // Eigen::SparseMatrix L,M; - // igl::cotmatrix(V,F,L); - - // //compute the mass matrix - // static bool computed=false; - // igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_BARYCENTRIC,M); - // M.setIdentity(); - // computed=true; - - // //const auto & S = (M - 0.001*L); - // Eigen::SparseMatrix S = (M - lambda*L); - - - // Eigen::SimplicialLLT > solver(S); - // assert(solver.info() == Eigen::Success); - - // U = solver.solve(M*U).eval(); - // // Normalize to unit surface area (important for numerics) - // U.array() /= sqrt(M.diagonal().array().sum()); - - // //then assing per vertex positions - // printf("smoothed \n"); - // fflush(stdout); - // for (size_t i=0;i L,M; + Eigen::SparseMatrix L,M,B; //initialize the mass matrix std::vector > IndexM; @@ -247,44 +241,73 @@ static void Compute(MeshType &mesh, Parameter &SParam) //add the entries for mass matrix if (SParam.useMassMatrix) MeshToMatrix::MassMatrixEntry(mesh,IndexM,ValuesM); + //then add entries for lagrange mult due to barycentric constraints + for (int i=0;i(baseIndex+j,baseIndex+j)); + ValuesM.push_back(1); + } + } + //add the hard constraints + CollectHardConstraints(mesh,SParam,IndexM,ValuesM); + //initialize sparse mass matrix + InitSparse(IndexM,ValuesM,matr_size*3,matr_size*3,M); + + //initialize the barycentric matrix + std::vector > IndexB; + std::vector ValuesB; + + std::vector IndexRhs; + std::vector ValuesRhs; //then also collect hard constraints - //CollectHardConstraints(mesh,SParam,IndexM,ValuesM); - - //initialize sparse mass matrix - InitSparse(IndexM,ValuesM,mesh.vert.size()*3,mesh.vert.size()*3,M); + CollectBarycentricConstraints(mesh,SParam,IndexB,ValuesB,IndexRhs,ValuesRhs); + //initialize sparse constraint matrix + InitSparse(IndexB,ValuesB,matr_size*3,matr_size*3,B); //get the entries for laplacian matrix std::vector > IndexL; std::vector ValuesL; - MeshToMatrix::GetLaplacianMatrix(mesh,IndexL,ValuesL,false);//SParam.useCotWeight); + MeshToMatrix::GetLaplacianMatrix(mesh,IndexL,ValuesL,SParam.useCotWeight); //initialize sparse laplacian matrix - InitSparse(IndexL,ValuesL,mesh.vert.size()*3,mesh.vert.size()*3,L); + InitSparse(IndexL,ValuesL,matr_size*3,matr_size*3,L); + + for (int i=0;i<(SParam.degree-1);i++)L=L*L; //then solve the system - Eigen::SparseMatrix S = (M + SParam.lambda*L); + Eigen::SparseMatrix S = (M + B + SParam.lambda*L); //SimplicialLDLT - Eigen::SimplicialLDLT > solver(S); - printf("output %d \n",solver.info()); - fflush(stdout); + Eigen::SimplicialCholesky > solver(S); assert(solver.info() == Eigen::Success); - int size=mesh.vert.size()*3; - MatrixXm V(size,1); + MatrixXm V(matr_size*3,1); + //set the first part of the matrix with vertex values for (size_t i=0;i