From 44f41b7c4ca3fbdabd930bacf71e331086ce386c Mon Sep 17 00:00:00 2001 From: nicopietroni Date: Thu, 3 Jul 2014 15:52:05 +0000 Subject: [PATCH] first release version --- vcg/complex/algorithms/smooth_field.h | 1065 +++++++++++++++++++++++++ 1 file changed, 1065 insertions(+) create mode 100644 vcg/complex/algorithms/smooth_field.h diff --git a/vcg/complex/algorithms/smooth_field.h b/vcg/complex/algorithms/smooth_field.h new file mode 100644 index 00000000..ba160149 --- /dev/null +++ b/vcg/complex/algorithms/smooth_field.h @@ -0,0 +1,1065 @@ +#ifndef SMOOTHER_FIELD_H +#define SMOOTHER_FIELD_H + +#include +#include +#include +#include "mesh_to_matrix.h" +#include +#include "NRosyField.h" + +using namespace std; +#define Delta 10e-6 + +template < typename TriMeshType > +class ImplicitSmoother +{ + // Temporary variable for the field + Eigen::VectorXd angles; + + // Hard constraints + Eigen::VectorXd hard; + std::vector isHard; + + // Soft constraints + Eigen::VectorXd soft; + Eigen::VectorXd wSoft; + double softAlpha; + + // Face Topology + Eigen::MatrixXi TT, TTi; + + // Edge Topology + Eigen::MatrixXi EV, FE, EF; + std::vector isBorderEdge; + + // Per Edge information + // Angle between two reference frames + Eigen::VectorXd k; + + // Jumps + Eigen::VectorXi p; + std::vector pFixed; + + // Mesh + Eigen::MatrixXd V; + Eigen::MatrixXi F; + + // Normals per face + Eigen::MatrixXd N; + + // Singularity index + Eigen::VectorXd singularityIndex; + + // Reference frame per triangle + std::vector TPs; + + // System stuff + Eigen::SparseMatrix A; + Eigen::VectorXd b; + Eigen::VectorXi tag_t; + Eigen::VectorXi tag_p; + + // define types + typedef typename TriMeshType::CoordType CoordType; + typedef typename TriMeshType::VertexType VertexType; + typedef typename TriMeshType::ScalarType ScalarType; + + TriMeshType &mesh; + + void computek() + { + // For every non-border edge + for (unsigned eid=0; eid(); + + assert(tmp(0) - ref1(0) < 10^10); + assert(tmp(1) - ref1(1) < 10^10); + + k[eid] = ktemp; + } + } + } + + void resetConstraints() + { + isHard.resize(F.rows()); + for(unsigned i=0; i::GetTriMeshData(mesh,F,V); + vcg::MeshToMatrix::GetTriFFAdjacency(mesh,TT,TTi); + vcg::MeshToMatrix::GetTriEdgeAdjacency(mesh,EV,FE,EF); + + // Flag border edges + isBorderEdge.resize(EV.rows()); + for(unsigned i=0; i::GetNormalData(mesh,NV,N); + + // Generate reference frames + for(unsigned fid=0; fid debug; + + // debug + // MatrixXd B(F.rows(),3); + // for(unsigned i=0; i visited(EV.rows()); + for(unsigned i=0; i starting(EV.rows()); + for(unsigned i=0; i q; + for(unsigned i=0; i id_t; + int count = 0; + for(unsigned i=0; i id_p; + for(unsigned i=0; i > T; + T.reserve(3 * 4 * count_p); + + for(unsigned r=0; r(row,tag_t[i] , 2 )); + if (isFixed_j) b(row) += 2 * hard[j]; else T.push_back(Eigen::Triplet(row,tag_t[j] ,-2 )); + if (isFixed_p) b(row) += -((4 * M_PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet(row,tag_p[eid],((4 * M_PI)/Nd))); + b(row) += -2 * k[eid]; + assert(hard[i] == hard[i]); + assert(hard[j] == hard[j]); + assert(p[eid] == p[eid]); + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + // (j)+1 -th row: t_j [ -2 2 -4pi/N -2 ] + if (!isFixed_j) + { + row = tag_t[j]; + if (isFixed_i) b(row) += 2 * hard[i]; else T.push_back(Eigen::Triplet(row,tag_t[i] , -2 )); + if (isFixed_j) b(row) += -2 * hard[j]; else T.push_back(Eigen::Triplet(row,tag_t[j] , 2 )); + if (isFixed_p) b(row) += ((4 * M_PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet(row,tag_p[eid],-((4 * M_PI)/Nd))); + b(row) += 2 * k[eid]; + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + // (r*3)+2 -th row: pij [ 4pi/N -4pi/N 2*(2pi/N)^2 4pi/N ] + if (!isFixed_p) + { + row = tag_p[eid]; + if (isFixed_i) b(row) += -(4 * M_PI)/Nd * hard[i]; else T.push_back(Eigen::Triplet(row,tag_t[i] , (4 * M_PI)/Nd )); + if (isFixed_j) b(row) += (4 * M_PI)/Nd * hard[j]; else T.push_back(Eigen::Triplet(row,tag_t[j] , -(4 * M_PI)/Nd )); + if (isFixed_p) b(row) += -(2 * pow(((2*M_PI)/Nd),2)) * p[eid] ; else T.push_back(Eigen::Triplet(row,tag_p[eid], (2 * pow(((2*M_PI)/Nd),2)))); + b(row) += - (4 * M_PI)/Nd * k[eid]; + assert(k[eid] == k[eid]); + assert(b(row) == b(row)); + } + + } + + A = Eigen::SparseMatrix(count_t + count_p, count_t + count_p); + A.setFromTriplets(T.begin(), T.end()); + + // Soft constraints + bool addSoft = false; + + for(unsigned i=0; i > TSoft; + TSoft.reserve(2 * count_p); + + for(unsigned i=0; i(varid,varid,wSoft[i])); + bSoft[varid] += wSoft[i] * soft[i]; + } + } + Eigen::SparseMatrix ASoft(count_t + count_p, count_t + count_p); + ASoft.setFromTriplets(TSoft.begin(), TSoft.end()); + + // ofstream s("./As.txt"); + // for(unsigned i=0; i Atmp (count_t + count_p, count_t + count_p); + Eigen::SparseMatrix Atmp2(count_t + count_p, count_t + count_p); + Eigen::SparseMatrix Atmp3(count_t + count_p, count_t + count_p); + + // Merge the two part of the energy + Atmp = (1.0 - softAlpha)*A; + Atmp2 = softAlpha * ASoft; + Atmp3 = Atmp+Atmp2; + + A = Atmp3; + b = b*(1.0 - softAlpha) + bSoft * softAlpha; + } + + // ofstream s("./A.txt"); + // for (int k=0; k::InnerIterator it(A,k); it; ++it) + // { + // s << it.row() << " " << it.col() << " " << it.value() << endl; + // } + // s.close(); + // + // ofstream s2("./b.txt"); + // for(unsigned i=0; i > gmm_A; + std::vector gmm_b; + std::vector ids_to_round; + std::vector x; + + gmm_A.resize(n,n); + gmm_b.resize(n); + x.resize(n); + + // Copy A + for (int k=0; k::InnerIterator it(A,k); it; ++it) + { + gmm_A(it.row(),it.col()) += it.value(); + } + + // Copy b + for(unsigned i=0; i > gmm_C(0, n); + + COMISO::ConstrainedSolver cs; + //print_miso_settings(cs.misolver()); + cs.solve(gmm_C, gmm_A, x, gmm_b, ids_to_round, 0.0, false, true); + + // Copy the result back + for(unsigned i=0; i > solver; + solver.compute(A); + Eigen::VectorXd x = solver.solve(b); + + // Copy the result back + for(unsigned i=0; i= 0 && alpha < 1); + softAlpha = alpha; + } + + void setConstraintSoft(const int fid, const double w, const CoordType &v) + { + // create eigen vector + Eigen::Vector3d c=vcg::MeshToMatrix::VectorFromCoord(v); + + // // copy coordinates + // for (int i = 0; i < 3; i++) + // c(i) = v[i]; + + // // set smoother soft constraint + // smoother->setConstraintSoft(fid, w, c); + + wSoft(fid) = w; + soft(fid) = convert3DtoLocal(fid, c); + } + + + void setConstraintHard(const int fid, const CoordType &v) + { + Eigen::Vector3d c=vcg::MeshToMatrix::VectorFromCoord(v); + + isHard[fid] = true; + hard(fid) = convert3DtoLocal(fid, c); + } + + + + void solve(const int N) + { + // Reduce the search space by fixing matchings + reduceSpace(); + + // Build the system + prepareSystemMatrix(N); + +#ifdef USECOMISO + // Solve with integer roundings + solveRoundings(); +#else + // Solve with no roundings + solveNoRoundings(); + + // Round all p and fix them + roundAndFix(); + + // Build the system + prepareSystemMatrix(N); + + // Solve with no roundings (they are all fixed) + solveNoRoundings(); +#endif + + // Find the cones + findCones(N); + } + + + void getFieldPerFace(vector &fields) + { + //assert(smoother); + + // get fields + //Eigen::MatrixXd fs = smoother->getFieldPerFace(); + + Eigen::MatrixXd fs(F.rows(),3); + for(unsigned i=0; i > &ffields) + { + // get fields + //Eigen::MatrixXd ffs = smoother->getFFieldPerFace(); + + Eigen::MatrixXd ffs(F.rows(),6); + for(unsigned i=0; i &sings) + { + // get fields + //Eigen::VectorXd s = smoother->getSingularityIndexPerVertex(); + + // reset output vector of singularities + sings.clear(); + + // resize output vector of singularities + sings.resize(singularityIndex.rows()); + + // copy fields in output vector + for (int i = 0; i < singularityIndex.rows(); i++) + sings[i] = singularityIndex(i); + } + + + void getSingularitiesIndexPerVertexList(list &sIndexes, const ScalarType t = ScalarType(0)) + { + + // get singularities vector + vector sings; + getSingularityIndexPerVertex(sings); + + // reset output list of indexes + sIndexes.clear(); + + // search for indexes with singularty greater than or equal to t + for (unsigned long i = 0; i < sings.size(); i++) + if (sings[i] >= t) + sIndexes.push_back(i); + } + +}; + + +template +class FieldSmoother0 +{ + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::CoordType CoordType; + + + static void InitQualityByAnisotropyDir(MeshType &mesh) + { + std::vector QVal; + for (size_t i=0;i::VertexClamp(mesh,trimDown,trimUp); + vcg::tri::UpdateQuality::FaceFromVertex(mesh); + vcg::tri::UpdateColor::PerFaceQualityGray(mesh,trimUp,trimDown); + } + + static void SetEdgeDirection(FaceType *f,int edge) + { + CoordType dir=f->P0(edge)-f->P1(edge); + dir.Normalize(); + ScalarType prod1=fabs(dir*f->PD1()); + ScalarType prod2=fabs(dir*f->PD2()); + if (prod1>prod2) + { + f->PD1()=dir; + f->PD2()=f->N()^dir; + }else + { + f->PD2()=dir; + f->PD1()=f->N()^dir; + } + } + + static void AddSharpEdgesConstraints(MeshType & mesh, + const ScalarType &thr=0.2) + { + for (size_t i=0;iFFp(j); + if (f0==f1)continue; + CoordType N0=f0->N(); + CoordType N1=f1->N(); + if ((N0*N1)>thr)continue; + SetEdgeDirection(f0,j); + f0->SetS(); + } + } + + static void AddBorderConstraints(MeshType & mesh) + { + for (size_t i=0;iFFp(j); + assert(f1!=NULL); + if (f0!=f1)continue; + SetEdgeDirection(f0,j); + f0->SetS(); + } + } + + static void AddCurvatureConstraints(MeshType & mesh,const ScalarType &thr=0.5) + { + for (size_t i=0;ithr)mesh.face[i].SetS(); + } + +public: + + struct SmoothParam + { + int Ndir; + + ScalarType alpha_soft; + + bool soft_weight; + bool align_borders; + bool align_sharp; + bool hard_curvature; + + ScalarType sharp_thr; + ScalarType curv_thr; + + SmoothParam() + { + Ndir=4; + alpha_soft=0.0; + soft_weight=false; + + align_borders=false; + align_sharp=false; + hard_curvature=false; + + sharp_thr=0.1; + curv_thr=0.8; + } + + }; + + static void InitByCurvature(MeshType & mesh) + { + + vcg::tri::UpdateCurvatureFitting::computeCurvature(mesh); + vcg::tri::CrossField::SetFaceCrossVectorFromVert(mesh); + InitQualityByAnisotropyDir(mesh); + } + + static void GloballyOrient(MeshType &mesh) + { + vcg::tri::CrossField::MakeDirectionFaceCoherent(mesh,true); + } + + static void SmoothDirections(MeshType &mesh, + SmoothParam SParam=SmoothParam()) + { + + //calculathe the maximim weight if needed + ScalarType MaxQ=-1; + if (SParam.soft_weight) + { + std::pair MinMax=vcg::tri::Stat::ComputePerFaceQualityMinMax(mesh); + MaxQ=MinMax.second; + } + + assert(SParam.alpha_soft>=0); + + ImplicitSmoother SmoothW(mesh); + //SmoothW.initializeSmoother(); + + //if alpha==0 then do not consider initial constraints and set to a value by default + SmoothW.setSoftAlpha(0.001); + + if (SParam.alpha_soft>0) + SmoothW.setSoftAlpha(SParam.alpha_soft); + + //set hard constraints if needed + vcg::tri::UpdateFlags::FaceClearS(mesh); + + if (SParam.align_borders) + AddBorderConstraints(mesh); + if (SParam.align_sharp) + AddSharpEdgesConstraints(mesh,SParam.sharp_thr); + if (SParam.hard_curvature) + AddCurvatureConstraints(mesh,SParam.curv_thr); + + //then set hard constraints + int num_fixed=0; + for (size_t i=0;i0 + if (SParam.alpha_soft>0) + { + for (size_t i=0;i0.9) + dir1=CoordType(0,1,0); + if (fabs(dir1*dirN)>0.9) + dir1=CoordType(0,0,1); + + dir1=dirN^dir1; + dir1.Normalize(); + + SmoothW.setConstraintHard(0,dir1); + } + + //solve + SmoothW.solve(SParam.Ndir); + + ///assign back to vertices + std::vector Field; + SmoothW.getFieldPerFace(Field); + for (size_t i=0;i