/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef __VCG_IMPLICIT_SMOOTHER #define __VCG_IMPLICIT_SMOOTHER #include #include #include #include #define PENALTY 10000 namespace vcg{ template class ImplicitSmoother { typedef typename MeshType::FaceType FaceType; typedef typename MeshType::VertexType VertexType; typedef typename MeshType::CoordType CoordType; typedef typename MeshType::ScalarType ScalarType; typedef typename Eigen::Matrix MatrixXm; public: struct FaceConstraint { int numF; std::vector > BarycentricW; CoordType TargetPos; ScalarType Weight; FaceConstraint() { numF=-1; Weight=0; } FaceConstraint(int _numF,const std::vector > &_BarycentricW, const CoordType &_TargetPos,ScalarType _Weight) { numF=_numF; BarycentricW= std::vector > (_BarycentricW.begin(),_BarycentricW.end()); TargetPos=_TargetPos; Weight=_Weight; } }; struct Parameter { //the amount of smoothness, useful only if we set the mass matrix ScalarType lambda; //the use of mass matrix to keep the mesh close to its original position //(weighted per area distributed on vertices) bool useMassMatrix; //this bool is used to fix the border vertices of the mesh or not bool fixBorder; //this bool is used to set if cotangent weight is used, this flag to false means uniform laplacian bool useCotWeight; //the set of fixed vertices std::vector FixedV; //the set of faces for barycentric constraints std::vector ConstrainedF; Parameter() { lambda=0.2; useMassMatrix=true; fixBorder=false; useCotWeight=false; } }; 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) { assert(Index.size()==Values.size()); std::vector > IJV; IJV.reserve(Index.size()); for(size_t i= 0;i(row,col,val)); } X.resize(m,n); 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) { std::vector To_Fix; //collect fixed vert if (SParam.fixBorder) { //add penalization constra for (int i=0;i::iterator it= std::unique (To_Fix.begin(), To_Fix.end()); To_Fix.resize( std::distance(To_Fix.begin(),it) ); for (size_t i=0;i(IndexV,IndexV)); WeightC.push_back((ScalarType)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; //initialize the mass matrix std::vector > IndexM; std::vector ValuesM; //add the entries for mass matrix if (SParam.useMassMatrix) MeshToMatrix::MassMatrixEntry(mesh,IndexM,ValuesM); //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); //get the entries for laplacian matrix std::vector > IndexL; std::vector ValuesL; MeshToMatrix::GetLaplacianMatrix(mesh,IndexL,ValuesL,false);//SParam.useCotWeight); //initialize sparse laplacian matrix InitSparse(IndexL,ValuesL,mesh.vert.size()*3,mesh.vert.size()*3,L); //then solve the system Eigen::SparseMatrix S = (M + SParam.lambda*L); //SimplicialLDLT Eigen::SimplicialLDLT > solver(S); printf("output %d \n",solver.info()); fflush(stdout); assert(solver.info() == Eigen::Success); int size=mesh.vert.size()*3; MatrixXm V(size,1); for (size_t i=0;i