diff --git a/vcg/complex/algorithms/implicit_smooth.h b/vcg/complex/algorithms/implicit_smooth.h new file mode 100644 index 00000000..a07ffdbf --- /dev/null +++ b/vcg/complex/algorithms/implicit_smooth.h @@ -0,0 +1,304 @@ +/**************************************************************************** +* 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; + + MeshType &to_smooth_mesh; + +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 SmoothParam + { + //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; + + SmoothParam() + { + 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(SmoothParam & SParam) + { + int basic_size=to_smooth_mesh.vert.size(); + int constr_size=SParam.ConstrainedF.size(); + return (basic_size+constr_size); + } + + void CollectHardConstraints(const SmoothParam &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(to_smooth_mesh,IndexM,ValuesM); + + //then also collect hard constraints + //CollectHardConstraints(SParam,IndexM,ValuesM); + + //initialize sparse mass matrix + InitSparse(IndexM,ValuesM,to_smooth_mesh.vert.size()*3,to_smooth_mesh.vert.size()*3,M); + + //get the entries for laplacian matrix + std::vector > IndexL; + std::vector ValuesL; + MeshToMatrix::GetLaplacianMatrix(to_smooth_mesh,IndexL,ValuesL,false);//SParam.useCotWeight); + + //initialize sparse laplacian matrix + InitSparse(IndexL,ValuesL,to_smooth_mesh.vert.size()*3,to_smooth_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=to_smooth_mesh.vert.size()*3; + MatrixXm V(size,1); + + for (size_t i=0;i #include +#include +#include using namespace std; namespace vcg { namespace tri { -template < typename TriMeshType > +template < typename MeshType > class MeshToMatrix { // define types - typedef typename TriMeshType::FaceType FaceType; - typedef typename TriMeshType::VertexType VertexType; - typedef typename TriMeshType::CoordType CoordType; - typedef typename TriMeshType::ScalarType ScalarType; + 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; - static void GetTriEdgeAdjacency(const Eigen::MatrixXd& V, + static void GetTriEdgeAdjacency(const MatrixXm& V, const Eigen::MatrixXi& F, Eigen::MatrixXi& EV, Eigen::MatrixXi& FE, @@ -128,13 +131,13 @@ class MeshToMatrix public: // return mesh as vector of vertices and faces - static void GetTriMeshData(const TriMeshType &mesh, + static void GetTriMeshData(const MeshType &mesh, Eigen::MatrixXi &faces, - Eigen::MatrixXd &vert) + MatrixXm &vert) { tri::RequireCompactness(mesh); // create eigen matrix of vertices - vert=Eigen::MatrixXd(mesh.VN(), 3); + vert=MatrixXm(mesh.VN(), 3); // copy vertices for (int i = 0; i < mesh.VN(); i++) @@ -151,13 +154,13 @@ public: } // return normals of the mesh - static void GetNormalData(const TriMeshType &mesh, - Eigen::MatrixXd &Nvert, - Eigen::MatrixXd &Nface) + static void GetNormalData(const MeshType &mesh, + MatrixXm &Nvert, + MatrixXm &Nface) { // create eigen matrix of vertices - Nvert=Eigen::MatrixXd(mesh.VN(), 3); - Nface=Eigen::MatrixXd(mesh.FN(), 3); + Nvert=MatrixXm(mesh.VN(), 3); + Nface=MatrixXm(mesh.FN(), 3); // per vertices normals for (int i = 0; i < mesh.VN(); i++) @@ -171,11 +174,11 @@ public: } // get face to face adjacency - static void GetTriFFAdjacency(TriMeshType &mesh, + static void GetTriFFAdjacency(MeshType &mesh, Eigen::MatrixXi &FFp, Eigen::MatrixXi &FFi) { - tri::UpdateTopology::FaceFace(mesh); + tri::UpdateTopology::FaceFace(mesh); FFp = Eigen::MatrixXi(mesh.FN(),3); FFi = Eigen::MatrixXi(mesh.FN(),3); @@ -197,13 +200,13 @@ public: } // get edge to face and edge to vertex adjacency - static void GetTriEdgeAdjacency(const TriMeshType &mesh, + static void GetTriEdgeAdjacency(const MeshType &mesh, Eigen::MatrixXi& EV, Eigen::MatrixXi& FE, Eigen::MatrixXi& EF) { Eigen::MatrixXi faces; - Eigen::MatrixXd vert; + MatrixXm vert; GetTriMeshData(mesh,faces,vert); GetTriEdgeAdjacency(vert,faces,EV,FE,EF); } @@ -213,6 +216,85 @@ public: Eigen::Vector3d ret(v[0],v[1],v[2]); return ret; } + + + static void MassMatrixEntry(MeshType &mesh, + std::vector > &index, + std::vector &entry) + { + //calculate area + UpdateQuality::FaceArea(mesh); + //then distribute per vertex + UpdateQuality::VertexFromFace(mesh); + + std::pair minmax=Stat::ComputePerVertexQualityMinMax(mesh); + + //store the index and the scalar for the sparse matrix + for (size_t i=0;i(currI,currI)); + entry.push_back(mesh.vert[i].Q()/(ScalarType)minmax.second); + } + } + } + + + static void GetLaplacianEntry(MeshType &mesh, + FaceType &f, + std::vector > &index, + std::vector &entry, + bool cotangent) + { + for (int i=0;i<3;i++) + { + + ScalarType weight = 1; + if (cotangent) + { + weight=Harmonic::template CotangentWeight(f,i); + } + + //get the index of the vertices + int indexV0=Index(mesh,f.V0(i)); + int indexV1=Index(mesh,f.V1(i)); + + //then assemble the matrix + for (int j=0;j<3;j++) + { + //multiply by 3 and add the component + int currI0=(indexV0*3)+j; + int currI1=(indexV1*3)+j; + + index.push_back(std::pair(currI0,currI0)); + entry.push_back(weight); + index.push_back(std::pair(currI0,currI1)); + entry.push_back(-weight); + + index.push_back(std::pair(currI1,currI1)); + entry.push_back(weight); + index.push_back(std::pair(currI1,currI0)); + entry.push_back(-weight); + + } + } + } + + + static void GetLaplacianMatrix(MeshType &mesh, + std::vector > &index, + std::vector &entry, + bool cotangent) + { + //store the index and the scalar for the sparse matrix + for (size_t i=0;i