/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2014 \/)\/ * * 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 SMOOTHER_FIELD_H #define SMOOTHER_FIELD_H //eigen stuff #include //vcg stuff #include #include #include #include //igl related stuff #include #include #include #ifdef COMISO_FIELD #include #endif namespace vcg { namespace tri { enum SmoothMethod{SMMiq,SMNPoly}; template class FieldSmoother { 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;i1)NMax=1; if (NMax<-1)NMax=-1; if (NMin>1)NMin=1; if (NMin<-1)NMin=-1; ScalarType CurvAni=(NMax-NMin)/2; mesh.vert[i].Q()=CurvAni; } vcg::tri::UpdateQuality::FaceFromVertex(mesh); } 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(); } //hard constraints have selected face static void CollectHardConstraints( MeshType & mesh, Eigen::VectorXi &HardI, Eigen::MatrixXd &HardD, SmoothMethod SMethod, int Ndir) { //count number of hard constraints int numS=vcg::tri::UpdateSelection::FaceCount(mesh); HardI=Eigen::MatrixXi(numS,1); if ((Ndir==2)||(SMethod==SMMiq)) HardD=Eigen::MatrixXd(numS,3); else HardD=Eigen::MatrixXd(numS,6); //then update them int curr_index=0; for (size_t i=0;i::FaceCount(mesh); numS=mesh.fn-numS; //allocate eigen matrix SoftI=Eigen::MatrixXi(numS,1); SoftD=Eigen::MatrixXd(numS,3); SoftW=Eigen::MatrixXd(numS,1); //then update them int curr_index=0; for (size_t i=0;i::GetTriMeshData(mesh,F,V); Eigen::MatrixXd output_field; Eigen::VectorXd output_sing; igl::copyleft::comiso::nrosy(V,F,HardI,HardD,SoftI,SoftW,SoftD,Ndir,alpha_soft,output_field,output_sing); //finally update the principal directions for (size_t i=0;i::GetTriMeshData(mesh,F,V); Eigen::MatrixXd output_field; Eigen::VectorXd output_sing; igl::n_polyvector(V,F,HardI,HardD,output_field); //finally update the principal directions for (size_t i=0;iN(); dirN.Normalize(); Dir=CoordType(1,0,0); if (fabs(Dir*dirN)>0.9) Dir=CoordType(0,1,0); if (fabs(Dir*dirN)>0.9) Dir=CoordType(0,0,1); Dir=dirN^Dir; Dir.Normalize(); } public: struct SmoothParam { //the 90° rotation independence while smoothing the direction field int Ndir; //the weight of curvature if doing the smoothing keeping the field close to the original one ScalarType alpha_curv; //align the field to border or not bool align_borders; //threshold to consider some edge as sharp feature and to use as hard constraint (0, not use) ScalarType sharp_thr; //threshold to consider some edge as high curvature anisotropyand to use as hard constraint (0, not use) ScalarType curv_thr; //the method used to smooth MIQ or "Designing N-PolyVector Fields with Complex Polynomials" SmoothMethod SmoothM; //the number of faces of the ring used ot esteem the curvature int curvRing; //this are additional hard constraints std::vector > AddConstr; SmoothParam() { Ndir=4; curvRing=2; alpha_curv=0.0; align_borders=false; SmoothM=SMMiq; sharp_thr=0.0; curv_thr=0.4; } }; static void SelectConstraints(MeshType &mesh,SmoothParam &SParam) { //clear all selected faces vcg::tri::UpdateFlags::FaceClear(mesh); //add curvature hard constraints //ScalarType Ratio=mesh.bbox.Diag()*0.01; if (SParam.curv_thr>0) AddCurvatureConstraints(mesh,SParam.curv_thr);///Ratio); //add alignment to sharp features if (SParam.sharp_thr>0) AddSharpEdgesConstraints(mesh,SParam.sharp_thr); //add border constraints if (SParam.align_borders) AddBorderConstraints(mesh); //aff final constraints for (size_t i=0;i::MakeDirectionFaceCoherent(mesh,true); } static void InitByCurvature(MeshType & mesh, unsigned Nring, bool UpdateFaces=true) { tri::RequirePerVertexCurvatureDir(mesh); Eigen::MatrixXi F; Eigen::MatrixXd V; Eigen::MatrixXd PD1,PD2,PV1,PV2; MeshToMatrix::GetTriMeshData(mesh,F,V); igl::principal_curvature(V,F,PD1,PD2,PV1,PV2,Nring,true); //then copy curvature per vertex for (size_t i=0;i::SetFaceCrossVectorFromVert(mesh); InitQualityByAnisotropyDir(mesh); } static void SmoothDirections(MeshType &mesh, int Ndir, SmoothMethod SMethod=SMNPoly, bool HardAsS=true, ScalarType alphaSoft=0) { Eigen::VectorXi HardI; //hard constraints Eigen::MatrixXd HardD; //hard directions Eigen::VectorXi SoftI; //soft constraints Eigen::VectorXd SoftW; //weight of soft constraints Eigen::MatrixXd SoftD; //soft directions if (HardAsS) CollectHardConstraints(mesh,HardI,HardD,SMethod,Ndir); //collect soft constraints , miw only one that allows for soft constraints if ((alphaSoft>0)&&(SMethod==SMMiq)) CollectSoftConstraints(mesh,SoftI,SoftD,SoftW); //add some hard constraints if are not present int numC=3; if ((SoftI.rows()==0)&&(HardI.rows()==0)) { printf("Add Forced Constraints \n"); fflush(stdout); HardI=Eigen::MatrixXi(numC,1); if ((Ndir==4)&&(SMethod==SMNPoly)) HardD=Eigen::MatrixXd(numC,6); else HardD=Eigen::MatrixXd(numC,3); for (int i=0;i0)|| (SParam.sharp_thr>0)|| (SParam.curv_thr>0)) { InitByCurvature(mesh,SParam.curvRing); SelectConstraints(mesh,SParam); } else { SelectConstraints(mesh,SParam); vcg::tri::CrossField::PropagateFromSelF(mesh); } //then do the actual smooth SmoothDirections(mesh,SParam.Ndir,SParam.SmoothM,true,SParam.alpha_curv); } }; } // end namespace tri } // end namespace vcg #endif // SMOOTHER_FIELD_H