diff --git a/vcg/complex/trimesh/update/fitmaps.h b/vcg/complex/trimesh/update/fitmaps.h new file mode 100644 index 00000000..0c29a969 --- /dev/null +++ b/vcg/complex/trimesh/update/fitmaps.h @@ -0,0 +1,489 @@ +/**************************************************************************** +* 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 FITMAPS_H +#define FITMAPS_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "vcg/complex/trimesh/update/curvature_fitting.h" + +#include +#include +#include +#include + +#include + +#include + +#include "mymesh.h" +#include + + +using namespace Eigen; + +namespace vcg { namespace tri { + +template +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 RingWalker; + + + class Bicubic + { + public: + + Bicubic() {}; + + Bicubic(vector& 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 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& VV) + { + double error = 0; + for(typename std::vector::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 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 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& ref, Bicubic& ret, std::vector& points, std::vector& ring) + { + points.clear(); + + if (ring.size() < 16) + { + return false; + } + + typename std::vector::iterator b = ring.begin(); + typename std::vector::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::computeCurvature(m); + vcg::tri::UpdateNormals::PerVertexAngleWeighted(m); + + vcg::tri::UpdateTopology::FaceFace(m); + vcg::tri::UpdateTopology::VertexFace(m); + + vcg::tri::UpdateBounding::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; iN(); + + 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::VertexQualityLaplacian(m,2); + } + + static vector gatherNeighsSurface(VertexType* vt, float sigma, MeshType& m) + { + vector current; + + RingWalker rw(vt,&m); + + bool exit = false; + + do + { + rw.expand(); + + exit = true; + + for(typename vector::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::computeCurvature(m); + vcg::tri::UpdateNormals::PerVertexAngleWeighted(m); + + vcg::tri::UpdateTopology::FaceFace(m); + vcg::tri::UpdateTopology::VertexFace(m); + + // update bounding box + vcg::tri::UpdateBounding::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 oneX; + + + for (int iteration = 0; iteration 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 pointsGlobal = gatherNeighsSurface(&*it,oneX.at(iteraz-1),m); + + vector onedimensional; + + for (int iteration = 0; iteration points; // solo quelli nel raggio + + std::vector projected; // come sopra ma in coord locali + for (typename std::vector::iterator it2 = pointsGlobal.begin(); it2 != pointsGlobal.end(); ++it2) + { + if (((*it).P() - (*it2)->P()).Norm() < oneX.at(iteration)) + points.push_back(*it2); + } + + std::vector& 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::VertexQualityLaplacian(m,1); + } + + + ~Fitmaps(){}; + +}; + +}} // END NAMESPACES + +#endif // FITMAPS_H