vcglib/vcg/complex/algorithms/update/fitmaps.h

484 lines
14 KiB
C++

/****************************************************************************
* VCGLib o o *
* Visual and Computer Graphics Library o o *
* _ O _ *
* Copyright(C) 2004-2016 \/)\/ *
* 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 FITMAPS_H
#define FITMAPS_H
#include <vcg/math/histogram.h>
#include <vcg/simplex/face/jumping_pos.h>
#include <vcg/complex/algorithms/update/flag.h>
#include <vcg/complex/algorithms/update/normal.h>
#include <vcg/complex/algorithms/update/curvature.h>
#include <vcg/complex/algorithms/update/topology.h>
#include <vcg/complex/algorithms/update/bounding.h>
#include "vcg/complex/algorithms/update/curvature_fitting.h"
#include <eigenlib/Eigen/Core>
#include <eigenlib/Eigen/QR>
#include <eigenlib/Eigen/LU>
#include <eigenlib/Eigen/SVD>
#include <vcg/complex/algorithms/nring.h>
#include <vcg/complex/algorithms/smooth.h>
using namespace Eigen;
namespace vcg { namespace tri {
template<class MeshType>
class Fitmaps
{
public:
typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::ScalarType ScalarType;
typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::CoordType CoordType;
typedef vcg::tri::Nring<MeshType> RingWalker;
class Bicubic
{
public:
Bicubic() {};
Bicubic(vector<double>& input)
{
data = input;
if (input.size() != 16)
{
assert(0);
}
}
// (u3 u2 u 1) (v3 v2 v 1)
//
// a u3 v3
// b u3 v2
// c u3 v1
// d u3 1
// e u2 v3
// f u2 v2
// g u2 v1
// h u2 1
// i u1 v3
// l u1 v2
// m u1 v1
// n u1 1
// o 1 v3
// p 1 v2
// q 1 v1
// r 1 1
double& a() { return data[0];}
double& b() { return data[1];}
double& c() { return data[2];}
double& d() { return data[3];}
double& e() { return data[4];}
double& f() { return data[5];}
double& g() { return data[6];}
double& h() { return data[7];}
double& i() { return data[8];}
double& l() { return data[9];}
double& m() { return data[10];}
double& n() { return data[11];}
double& o() { return data[12];}
double& p() { return data[13];}
double& q() { return data[14];}
double& r() { return data[15];}
vector<double> data;
double evaluate(double u, double v)
{
return
a() * u*u*u * v*v*v +
b() * u*u*u * v*v +
c() * u*u*u * v +
d() * u*u*u +
e() * u*u * v*v*v +
f() * u*u * v*v +
g() * u*u * v +
h() * u*u +
i() * u * v*v*v +
l() * u * v*v +
m() * u * v +
n() * u +
o() * v*v*v +
p() * v*v +
q() * v +
r();
}
double distanceRMS(std::vector<CoordType>& VV)
{
double error = 0;
for(typename std::vector<CoordType>::iterator it = VV.begin(); it != VV.end(); ++it)
{
double u = it->X();
double v = it->Y();
double n = it->Z();
double temp = evaluate(u,v);
error += (n - temp)*(n - temp);
}
error /= (double) VV.size();
return sqrt(error);
}
static Bicubic fit(std::vector<CoordType> VV)
{
assert(VV.size() >= 16);
Eigen::MatrixXf A(VV.size(),16);
Eigen::MatrixXf b(VV.size(),1);
Eigen::MatrixXf sol(16,1);
for(unsigned int c=0; c < VV.size(); ++c)
{
double u = VV[c].X();
double v = VV[c].Y();
double n = VV[c].Z();
A(c,0) = u*u*u * v*v*v;
A(c,1) = u*u*u * v*v;
A(c,2) = u*u*u * v;
A(c,3) = u*u*u;
A(c,4) = u*u * v*v*v;
A(c,5) = u*u * v*v;
A(c,6) = u*u * v;
A(c,7) = u*u;
A(c,8) = u * v*v*v;
A(c,9) = u * v*v;
A(c,10) = u * v;
A(c,11) = u;
A(c,12) = v*v*v;
A(c,13) = v*v;
A(c,14) = v;
A(c,15) = 1;
b[c] = n;
}
A.svd().solve(b, &sol);
vector<double> r(16);
for (int i=0; i < 16; ++i)
r.at(i) = sol[i];
return Bicubic(r);
}
};
Fitmaps()
{}
class radSorter
{
public:
radSorter(VertexType* v)
{
origin = v;
}
VertexType* origin;
bool operator() (VertexType* v1, VertexType* v2)
{
return (v1->P() - origin->P()).SquaredNorm() < (v2->P() - origin->P()).SquaredNorm();
}
};
float getMeanCurvature(VertexType* vp)
{
return (vp->K1() + vp->K2())/2.0;
}
static bool fitBicubicPoints(VertexType* v, std::vector<CoordType>& ref, Bicubic& ret, std::vector<CoordType>& points, std::vector<VertexType*>& ring)
{
points.clear();
if (ring.size() < 16)
{
return false;
}
typename std::vector<VertexType*>::iterator b = ring.begin();
typename std::vector<VertexType*>::iterator e = ring.end();
while(b != e)
{
CoordType vT = (*b)->P() - v->P();
double x = vT * ref[0];
double y = vT * ref[1];
double z = vT * ref[2];
points.push_back(CoordType(x,y,z));
++b;
}
ret = Bicubic::fit(points);
return true;
}
static double AverageEdgeLenght(MeshType& m)
{
double doubleA = 0;
for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) {
doubleA+=vcg::DoubleArea(*fi);
}
int nquads = m.fn / 2;
return sqrt( doubleA/(2*nquads) );
}
static void computeMFitmap(MeshType& m, float perc, int ringMax = 50)
{
vcg::tri::UpdateCurvatureFitting<MeshType>::computeCurvature(m);
vcg::tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
vcg::tri::UpdateTopology<MeshType>::VertexFace(m);
vcg::tri::UpdateBounding<MeshType>::Box(m);
int countTemp = 0;
RingWalker::clearFlags(&m);
for(VertexIterator it=m.vert.begin(); it!=m.vert.end();++it)
{
if ((countTemp++ % 100) == 0)
cerr << countTemp << "/" << m.vert.size() << endl;
RingWalker rw(&*it,&m);
CoordType nor = it->N();
float okfaces = 0;
float flipfaces = 0;
int count = 0;
do
{
count++;
rw.expand();
for(unsigned i=0; i<rw.lastF.size();++i)
{
CoordType vet1 = nor;
CoordType vet2 = rw.lastF[i]->N();
vet1.Normalize();
vet2.Normalize();
double scal = vet1 * vet2;
if ((scal) > 0)
okfaces += (vcg::DoubleArea(*rw.lastF[i]));
else
flipfaces += (vcg::DoubleArea(*rw.lastF[i]));
}
} while ((((flipfaces)/(okfaces + flipfaces))*100.0 < perc) && (count < ringMax));
std::sort(rw.lastV.begin(),rw.lastV.end(),radSorter(&*it));
it->Q() = ((*rw.lastV.begin())->P() - it->P()).Norm();
rw.clear();
}
vcg::tri::Smooth<MeshType>::VertexQualityLaplacian(m,2);
}
static vector<VertexType*> gatherNeighsSurface(VertexType* vt, float sigma, MeshType& m)
{
vector<VertexType*> current;
RingWalker rw(vt,&m);
bool exit = false;
do
{
rw.expand();
exit = true;
for(typename vector<VertexType*>::iterator it = rw.lastV.begin(); it != rw.lastV.end(); ++it)
{
if (((*it)->P() - vt->P()).Norm() < sigma)
{
current.push_back(*it);
exit = false;
}
}
} while (!exit);
rw.clear();
return current;
}
static void computeSFitmap(MeshType& m)//, float target = 1000)
{
vcg::tri::UpdateCurvatureFitting<MeshType>::computeCurvature(m);
vcg::tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
vcg::tri::UpdateTopology<MeshType>::FaceFace(m);
vcg::tri::UpdateTopology<MeshType>::VertexFace(m);
// update bounding box
vcg::tri::UpdateBounding<MeshType>::Box(m);
int countTemp = 0;
double e = AverageEdgeLenght(m);
int iteraz = 5; //2.0 * sqrt(m.vert.size()/target);
for(VertexIterator it=m.vert.begin(); it!=m.vert.end();++it)
{
if ((countTemp++ % 100) == 0)
cerr << countTemp << "/" << m.vert.size() << endl;
vector<float> oneX;
for (int iteration = 0; iteration<iteraz; ++iteration)
{
oneX.push_back((iteration+1)*(e));
}
std::vector<CoordType> ref(3);
ref[0] = it->PD1();
ref[1] = it->PD2();
ref[2] = it->PD1() ^ it->PD2();
ref[0].Normalize();
ref[1].Normalize();
ref[2].Normalize();
Bicubic b;
RingWalker::clearFlags(&m);
std::vector<VertexType*> pointsGlobal = gatherNeighsSurface(&*it,oneX.at(iteraz-1),m);
vector<float> onedimensional;
for (int iteration = 0; iteration<iteraz; ++iteration)
{
std::vector<VertexType*> points; // solo quelli nel raggio
std::vector<CoordType> projected; // come sopra ma in coord locali
for (typename std::vector<VertexType*>::iterator it2 = pointsGlobal.begin(); it2 != pointsGlobal.end(); ++it2)
{
if (((*it).P() - (*it2)->P()).Norm() < oneX.at(iteration))
points.push_back(*it2);
}
std::vector<VertexType*>& pointsFitting = points;
if (!fitBicubicPoints(&*it, ref, b, projected,pointsFitting))
{
onedimensional.push_back(0);
}
else
{
onedimensional.push_back(b.distanceRMS(projected));
}
}
// // vecchio fit ax^4
Eigen::MatrixXf Am(onedimensional.size(),1);
Eigen::MatrixXf bm(onedimensional.size(),1);
Eigen::MatrixXf sol(1,1);
for(unsigned int c=0; c < onedimensional.size(); ++c)
{
double x = oneX.at(c);
Am(c,0) = pow(x,4);
bm[c] = onedimensional[c];
}
Am.svd().solve(bm, &sol);
it->Q() = pow((double)sol[0],0.25);
// // nuovo fit ax^4 + b
// Eigen::MatrixXf Am(onedimensional.size()+1,2);
// Eigen::MatrixXf bm(onedimensional.size()+1,1);
// Eigen::MatrixXf sol(2,1);
//
// Am(0,0) = 0;
// Am(0,1) = 0;
// bm[0] = 0;
//
// for(unsigned int c=0; c < onedimensional.size(); ++c)
// {
// double x = oneX.at(c);
//
// Am(c,0) = pow(x,4);
// Am(c,1) = 1;
// bm[c] = onedimensional[c];
// }
//
// //sol = ((Am.transpose()*Am).inverse()*Am.transpose())*bm;
// Am.svd().solve(bm, &sol);
//
// cerr << "------" << sol[0] << " " << sol[1] << endl;
// if (sol[0] > 0)
// saliency[it] = pow((double)sol[0],0.25);
// else
// saliency[it] = 0;
}
vcg::tri::Smooth<MeshType>::VertexQualityLaplacian(m,1);
}
~Fitmaps(){};
};
}} // END NAMESPACES
#endif // FITMAPS_H