vcglib/wrap/miq/MIQ.h

352 lines
10 KiB
C++

#ifndef __MIQ__
#define __MIQ__
#define SIZEQUADS 512
#define V_SIZE 1
#define SIZEPARA 1024
#include <iostream>
#include <vector>
#include "mesh_type.h"
#include "quadrangulator.h"
#include "poisson_solver.h"
#include "param_stats.h"
#include "seams_initializer.h"
#include "vertex_indexing.h"
#include <wrap/io_trimesh/import.h>
#include <wrap/io_trimesh/export.h>
#define USECOMISO
template <class ScalarType>
ScalarType Gauss(ScalarType &value)
{
const ScalarType E_NEPER=2.71828;
const ScalarType den=sqrt(2.0*M_PI);
ScalarType exponent=-0.5*pow(value,2);
ScalarType res=((1.0/den)*pow(E_NEPER,exponent));
return res;
}
template <class MeshType,class PolyMesh>
class MIQ{
public:
typename MeshType::template PerFaceAttributeHandle<float> Handle_Stiffness;
// Different stiffening mode
enum StiffMode{NO_STIFF = 0,GAUSSIAN = 1,ITERATIVE = 2};
// Init
MIQ(MeshType &_mesh):mesh(_mesh),PSolver(mesh){};
// Load a mesh from file
bool LoadMesh(const std::string PathMesh)
{
int position=PathMesh.find(".ply");
int err;
if (position==-1)
{
position=PathMesh.find(".obj");
//vcg::tri::io::ImporterOBJ<CMesh>::Info objInf;
int mask;
vcg::tri::io::ImporterOBJ<CMesh>::LoadMask(PathMesh.c_str(),mask);
err=vcg::tri::io::ImporterOBJ<CMesh>::Open(mesh,PathMesh.c_str(),mask);
assert(position!=-1);
if (err!=0)return false;
}
else
{
err=vcg::tri::io::ImporterPLY<CMesh>::Open(mesh,PathMesh.c_str());
if (err!=ply::E_NOERROR)return false;
}
///UPDATE MESH STUFF
vcg::tri::UpdateBounding<CMesh>::Box(mesh);
vcg::tri::UpdateNormal<CMesh>::PerVertexNormalizedPerFace(mesh);
vcg::tri::UpdateNormal<CMesh>::PerFaceNormalized(mesh);
vcg::tri::UpdateTopology<CMesh>::FaceFace(mesh);
vcg::tri::UpdateTopology<CMesh>::VertexFace(mesh);
vcg::tri::UpdateFlags<CMesh>::FaceBorderFromFF(mesh);
vcg::tri::UpdateFlags<CMesh>::VertexBorderFromFace(mesh);
return true;
}
// Load a field from file
bool LoadField(const std::string PathFField,const std::string PathMesh=NULL)
{
SInit.Init(&mesh);
///FIELD LOADING
int position=PathFField.find(".ffield");
if (position==-1)
{
position=PathFField.find(".grad");
assert(position!=-1);
SInit.InitFromGradOBJ(PathFField,PathMesh);
}
else
SInit.InitFromFField(PathFField);
VInd.Init(&mesh);
//mesh.ScaleToUnitBox();
VInd.InitMapping();
VInd.InitFaceIntegerVal();
VInd.InitSeamInfo();
return true;
}
// Load a mesh and a field from file
bool LoadMeshField(const std::string PathMesh, const std::string PathFField)
{
bool loaded=LoadMesh(PathMesh);
if (!loaded)return false;
LoadField(PathFField,PathMesh);
return true;
}
// Parametrize the mesh
void Solve(StiffMode stiffMode, double Stiffness = 5.0,
double GradientSize = 30.0, bool DirectRound = false,
int iter = 5, int localIter = 5, bool DoRound = true)
{
if (mesh.fn==0)return;
InitDefaultStiffening();
if (stiffMode==GAUSSIAN)
{
AddGaussStiffening(Stiffness);
PSolver.SolvePoisson(GradientSize,1.f,DirectRound,localIter,DoRound);
}
else
if (stiffMode==ITERATIVE)
{
for (int i=0;i<iter;i++)
{
PSolver.SolvePoisson(GradientSize,1.f,DirectRound,localIter,DoRound);
int nflips=NumFlips(mesh);
ScaleGLtoInt();
bool folded=updateStiffening(GradientSize);
ScaleInttoGL();
printf("ITERATION %d FLIPS %d \n",i,nflips);
if (!folded)break;
}
}
else
if (stiffMode==NO_STIFF)
{
PSolver.SolvePoisson(GradientSize,1.f,DirectRound,localIter,DoRound);
}
int nflips=NumFlips(mesh);
printf("**** END OPTIMIZING #FLIPS %d ****\n",nflips);
fflush(stdout);
SelectFlippedFaces(mesh);
UpdateUVBox();
}
// Generate a quad mesh starting from the parametrization
void Quadrangulate(PolyMesh &poly,double factor = 1)
{
Quad.Quadrangulate(mesh,poly,factor);
}
// void removeDuplicateVertices(std::vector<std::vector<double> >& V, std::vector< std::vector<int > >& F);
// void exportQuadMesh(std::string out);
//bool LoadData(std::string PathMesh,
// std::string PathFField);
// Bounding box of the param domain
vcg::Box2<double> UVBox;
void ScaleGLtoInt()
{
double factor=(double)SIZEPARA/(double)SIZEQUADS;
for (unsigned int i=0;i<mesh.face.size();i++)
{
if (mesh.face[i].IsD())continue;
mesh.face[i].WT(0).P()*=factor;
mesh.face[i].WT(1).P()*=factor;
mesh.face[i].WT(2).P()*=factor;
}
}
void ScaleInttoGL()
{
double factor=(double)SIZEQUADS/(double)SIZEPARA;
for (unsigned int i=0;i<mesh.face.size();i++)
{
if (mesh.face[i].IsD())continue;
mesh.face[i].WT(0).P()*=factor;
mesh.face[i].WT(1).P()*=factor;
mesh.face[i].WT(2).P()*=factor;
}
}
void UpdateUVBox()
{
UVBox.SetNull();
for (unsigned int i=0;i<mesh.face.size();i++)
{
UVBox.Add((mesh.face[i].WT(0).P()));
UVBox.Add((mesh.face[i].WT(1).P()));
UVBox.Add((mesh.face[i].WT(2).P()));
}
}
// Quadrangulator
Quadrangulator<CMesh,PolyMesh> Quad;
void colorByStiffening(typename MeshType::ScalarType MaxVal=16)
{
bool hasStiffness = vcg::tri::HasPerFaceAttribute(mesh,std::string("Stiffness"));
assert(hasStiffness);
for (unsigned int i=0;i<mesh.face.size();i++)
{
//CMesh::ScalarType val=MaxVal-mesh.face[i].stiffening+1;
CMesh::ScalarType val=MaxVal-Handle_Stiffness[i]+1;
if (val<1)val=1;
mesh.face[i].C()=vcg::Color4b::ColorRamp(1.0,MaxVal,val);
}
}
private:
void AddStiffening(typename MeshType::ScalarType C,int radius=4)
{
bool hasStiffness = vcg::tri::HasPerFaceAttribute(mesh,std::string("Stiffness"));
if(!hasStiffness)
Handle_Stiffness=vcg::tri::Allocator<CMesh>::AddPerFaceAttribute<float>(mesh,std::string("Stiffness"));
bool hasSingular = vcg::tri::HasPerVertexAttribute(mesh,std::string("Singular"));
assert(hasSingular);
CMesh::PerVertexAttributeHandle<bool> Handle_Singular;
Handle_Singular=vcg::tri::Allocator<CMesh>::GetPerVertexAttribute<bool>(mesh,std::string("Singular"));
std::vector<CMesh::VertexType*> to_stiff;
for(unsigned int i=0;i<mesh.vert.size();i++)
{
CMesh::VertexType *v=&mesh.vert[i];
if (v->IsD())continue;
//if (!v->IsSingular())continue;
if (!Handle_Singular[v])continue;
to_stiff.push_back(v);
}
for(unsigned int i=0;i<mesh.face.size();i++)
{
CMesh::FaceType *f=&(mesh.face[i]);
if (f->IsD())continue;
if (!f->IsV())continue;
to_stiff.push_back(f->V(0));
to_stiff.push_back(f->V(1));
to_stiff.push_back(f->V(2));
}
std::sort(to_stiff.begin(),to_stiff.end());
std::vector<CMesh::VertexType*>::iterator new_end=std::unique(to_stiff.begin(),to_stiff.end());
int dist=distance(to_stiff.begin(),new_end);
to_stiff.resize(dist);
for (unsigned int i=0;i<to_stiff.size();i++)
{
CMesh::VertexType *v=to_stiff[i];
for (int r=0;r<radius;r++)
{
CMesh::ScalarType stiffVal=((CMesh::ScalarType)r)/(CMesh::ScalarType)radius;//((ScalarType)(radius-r))/(ScalarType)radius;
stiffVal*=3.0;
stiffVal=Gauss(stiffVal)/0.4;
stiffVal=1+(stiffVal*C);
std::vector<CMesh::FaceType*> ring;
//mesh.GetConnectedFaces(v,r,ring);
VFExtendedStarVF(v,r,ring);
///then set stiffening
for (unsigned int k=0;k<ring.size();k++)
{
CMesh::FaceType* f=ring[k];
//if (f->stiffening<stiffVal)
// f->stiffening=stiffVal;
if (Handle_Stiffness[f]<stiffVal)
Handle_Stiffness[f]=stiffVal;
}
}
}
}
bool updateStiffening(typename MeshType::ScalarType grad_size)
{
bool hasStiffness = vcg::tri::HasPerFaceAttribute(mesh,std::string("Stiffness"));
if(!hasStiffness)
Handle_Stiffness=vcg::tri::Allocator<CMesh>::AddPerFaceAttribute<float>(mesh,std::string("Stiffness"));
bool flipped = NumFlips(mesh)>0;
//if (h == 0.0)
// return flipped;
//
//assert(h != 0.0);
if (!flipped)
return false;
CMesh::ScalarType maxL=0;
CMesh::ScalarType maxD=0;
if (flipped)
{
const double c = 1.0;
const double d = 5.0;
for (unsigned int i = 0; i < mesh.face.size(); ++i)
{
CMesh::ScalarType dist=Distortion(mesh.face[i],grad_size);
if (dist>maxD)maxD=dist;
CMesh::ScalarType absLap=fabs(LaplaceDistortion(mesh.face[i], grad_size));
if (absLap>maxL)maxL=absLap;
CMesh::ScalarType stiffDelta = std::min(c * absLap, d);
//mesh.face[i].stiffening+=stiffDelta;
Handle_Stiffness[i]+=stiffDelta;
}
}
printf("Maximum Distorsion %4.4f \n",maxD);
printf("Maximum Laplacian %4.4f \n",maxL);
return flipped;
}
void InitDefaultStiffening()
{
bool hasStiffness = vcg::tri::HasPerFaceAttribute(mesh,std::string("Stiffness"));
if(!hasStiffness)
Handle_Stiffness=vcg::tri::Allocator<CMesh>::AddPerFaceAttribute<float>(mesh,std::string("Stiffness"));
for(unsigned int i=0;i<mesh.face.size();i++)
{
CMesh::FaceType *f=&(mesh.face[i]);
//f->stiffening=1;
Handle_Stiffness[f]=1;
}
}
void AddGaussStiffening(typename MeshType::ScalarType C)
{
int radius=floor(C);
if (C<4)radius=4;
AddStiffening(C,radius);
}
// Mesh class
MeshType &mesh;
// Quad mesh class
//CMesh quadmesh;
///seams initializer
SeamsInitializer<MeshType> SInit;
// Vertex indexing class used for the solver
VertexIndexing<MeshType> VInd;
// Poisson solver
PoissonSolver<MeshType> PSolver;
};
#endif