27 #ifndef VCGLIB_UPDATE_CURVATURE_FITTING
28 #define VCGLIB_UPDATE_CURVATURE_FITTING
30 #include <vcg/space/index/grid_static_ptr.h>
31 #include <vcg/simplex/face/topology.h>
32 #include <vcg/simplex/face/pos.h>
33 #include <vcg/simplex/face/jumping_pos.h>
34 #include <vcg/container/simple_temporary_data.h>
35 #include <vcg/complex/algorithms/update/normal.h>
36 #include <vcg/complex/algorithms/point_sampling.h>
37 #include <vcg/complex/algorithms/intersection.h>
38 #include <vcg/complex/algorithms/inertia.h>
39 #include <vcg/complex/algorithms/nring.h>
45 #include <Eigen/Eigenvalues>
60 template <
class MeshType>
65 typedef typename MeshType::FaceType FaceType;
66 typedef typename MeshType::FacePointer FacePointer;
67 typedef typename MeshType::FaceIterator FaceIterator;
68 typedef typename MeshType::VertexIterator VertexIterator;
69 typedef typename MeshType::VertContainer VertContainer;
70 typedef typename MeshType::VertexType VertexType;
71 typedef typename MeshType::VertexPointer VertexPointer;
72 typedef typename MeshType::VertexPointer VertexTypeP;
73 typedef vcg::face::VFIterator<FaceType> VFIteratorType;
74 typedef typename MeshType::CoordType CoordType;
75 typedef typename CoordType::ScalarType ScalarType;
81 Quadric(
double av,
double bv,
double cv,
double dv,
double ev)
90 double& a() {
return data[0];}
91 double& b() {
return data[1];}
92 double& c() {
return data[2];}
93 double& d() {
return data[3];}
94 double& e() {
return data[4];}
98 double evaluate(
double u,
double v)
100 return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
103 double du(
double u,
double v)
105 return 2.0*a()*u + b()*v + d();
108 double dv(
double u,
double v)
110 return 2.0*c()*v + b()*u + e();
113 double duv(
double ,
double )
118 double duu(
double ,
double )
123 double dvv(
double ,
double )
128 static Quadric fit(std::vector<CoordType> VV)
130 assert(VV.size() >= 5);
131 Eigen::MatrixXf A(VV.size(),5);
132 Eigen::MatrixXf b(VV.size(),1);
133 Eigen::MatrixXf sol(VV.size(),1);
135 for(
unsigned int c=0; c < VV.size(); ++c)
137 double u = VV[c].X();
138 double v = VV[c].Y();
139 double n = VV[c].Z();
150 sol = ((A.transpose()*A).inverse()*A.transpose())*b;
151 return Quadric(sol(0,0),sol(1,0),sol(2,0),sol(3,0),sol(4,0));
155 static CoordType project(VertexType* v, VertexType* vp)
157 return vp->P() - (v->N() * ((vp->P() - v->P()) * v->N()));
161 static std::vector<CoordType> computeReferenceFrames(VertexTypeP vi)
163 vcg::face::VFIterator<FaceType> vfi(vi);
165 int i = (vfi.I()+1)%3;
166 VertexTypeP vp = vfi.F()->V(i);
168 CoordType x = (project(&*vi,vp) - vi->P()).Normalize();
171 std::vector<CoordType> res(3);
174 res[1] = (vi->N() ^ res[0]).Normalize();
175 res[2] = (vi->N())/(vi->N()).Norm();
180 static std::set<CoordType> getSecondRing(VertexTypeP v)
182 std::set<VertexTypeP> ris;
183 std::set<CoordType> coords;
185 vcg::face::VFIterator<FaceType> vvi(v);
186 for(;!vvi.End();++vvi)
188 vcg::face::VFIterator<FaceType> vvi2(vvi.F()->V((vvi.I()+1)%3));
189 for(;!vvi2.End();++vvi2)
191 ris.insert(vvi2.F()->V((vvi2.I()+1)%3));
194 typename std::set<VertexTypeP>::iterator it;
195 for(it = ris.begin(); it != ris.end(); ++it)
196 coords.insert((*it)->P());
201 static Quadric fitQuadric(VertexTypeP v, std::vector<CoordType>& ref)
203 std::set<CoordType> ring = getSecondRing(v);
205 return Quadric(1,1,1,1,1);
206 std::vector<CoordType> points;
208 typename std::set<CoordType>::iterator b = ring.begin();
209 typename std::set<CoordType>::iterator e = ring.end();
214 CoordType vTang = *b - v->P();
216 double x = vTang * ref[0];
217 double y = vTang * ref[1];
218 double z = vTang * ref[2];
219 points.push_back(CoordType(x,y,z));
222 return Quadric::fit(points);
226 static void computeCurvature(MeshType & m)
229 tri::RequireCompactness(m);
230 tri::RequireVFAdjacency(m);
239 for(vi = m.vert.begin(); vi!=m.vert.end(); ++vi )
241 std::vector<CoordType> ref = computeReferenceFrames(&*vi);
243 Quadric q = fitQuadric(&*vi,ref);
250 double E = 1.0 + d*d;
252 double G = 1.0 + e*e;
254 CoordType n = CoordType(-d,-e,1.0).Normalize();
256 vi->N() = ref[0] * n[0] + ref[1] * n[1] + ref[2] * n[2];
258 double L = 2.0 * a * n.Z();
259 double M = b * n.Z();
260 double N = 2 * c * n.Z();
264 m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
266 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
268 Eigen::Vector2d c_val = eig.eigenvalues();
269 Eigen::Matrix2d c_vec = eig.eigenvectors();
288 CoordType v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2];
289 CoordType v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2];
291 v1global.Normalize();
292 v2global.Normalize();
294 if (c_val[0] > c_val[1])
296 (*vi).PD1().Import(v1global);
297 (*vi).PD2().Import(v2global);
298 (*vi).K1() = c_val[0];
299 (*vi).K2() = c_val[1];
303 (*vi).PD1().Import(v2global);
304 (*vi).PD2().Import(v1global);
305 (*vi).K1() = c_val[1];
306 (*vi).K2() = c_val[0];
320 a() = b() = c() = d() = e() = 1.0;
323 QuadricLocal (
double av,
double bv,
double cv,
double dv,
double ev)
332 double& a() {
return data[0];}
333 double& b() {
return data[1];}
334 double& c() {
return data[2];}
335 double& d() {
return data[3];}
336 double& e() {
return data[4];}
340 double evaluate(
double u,
double v)
342 return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
345 double du(
double u,
double v)
347 return 2.0*a()*u + b()*v + d();
350 double dv(
double u,
double v)
352 return 2.0*c()*v + b()*u + e();
355 double duv(
double ,
double )
360 double duu(
double ,
double )
365 double dvv(
double ,
double )
371 static QuadricLocal fit(std::vector<CoordType> &VV,
bool svdRes,
bool detCheck)
373 assert(VV.size() >= 5);
374 Eigen::MatrixXd A(VV.size(),5);
375 Eigen::VectorXd b(VV.size());
376 Eigen::VectorXd sol(5);
378 for(
unsigned int c=0; c < VV.size(); ++c)
380 double u = VV[c].X();
381 double v = VV[c].Y();
382 double n = VV[c].Z();
394 static int count = 0, index = 0;
395 double min = 0.000000000001;
401 if (detCheck && ((A.transpose()*A).determinant() < min && (A.transpose()*A).determinant() > -min))
405 printf(
"Quadric: unsolvable vertex %d %d\n", count, ++index);
408 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A);
410 return QuadricLocal(sol[0],sol[1],sol[2],sol[3],sol[4]);
418 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A);
423 sol = ((A.transpose()*A).inverse()*A.transpose())*b;
427 return QuadricLocal(sol[0],sol[1],sol[2],sol[3],sol[4]);
431 static void expandMaxLocal (MeshType & mesh, VertexType *v,
int max, std::vector<VertexType*> *vv)
433 Nring<MeshType> rw = Nring<MeshType> (v, &mesh);
434 do rw.expand ();
while (rw.allV.size() < max+1);
436 printf (
"rw.allV[0] != *v\n");
437 vv->reserve ((
size_t)max);
438 for (
int i = 1; i < max+1; i++)
439 vv->push_back(rw.allV[i]);
445 static void expandSphereLocal (MeshType & mesh, VertexType *v,
float r,
int min, std::vector<VertexType*> *vv)
447 Nring<MeshType> rw = Nring<MeshType> (v, &mesh);
449 bool isInside =
true;
453 vv->reserve(rw.allV.size());
455 typename std::vector<VertexType*>::iterator b = rw.lastV.begin();
456 typename std::vector<VertexType*>::iterator e = rw.lastV.end();
460 if (((*b)->P() - v->P()).Norm() < r)
471 if (vv->size() < min)
474 expandMaxLocal (mesh, v, min, vv);
479 static void getAverageNormal (VertexType *vp, std::vector<VertexType*> &vv, CoordType *ppn)
481 *ppn = CoordType (0,0,0);
482 for (
typename std::vector<VertexType*>::iterator vpi = vv.begin(); vpi != vv.end(); ++vpi)
485 *ppn /= vv.size() + 1;
490 static void applyProjOnPlane (CoordType ppn, std::vector<VertexType*> &vin, std::vector<VertexType*> *vout)
492 for (
typename std::vector<VertexType*>::iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
493 if ((*vpi)->N() * ppn > 0.0f)
494 vout->push_back (*vpi);
497 static CoordType projectLocal(VertexType* v, VertexType* vp, CoordType ppn)
499 return vp->P() - (ppn * ((vp->P() - v->P()) * ppn));
503 static void computeReferenceFramesLocal (VertexType *v, CoordType ppn, std::vector<CoordType> *ref)
505 vcg::face::VFIterator<FaceType> vfi (v);
507 int i = (vfi.I() + 1) % 3;
508 VertexTypeP vp = vfi.F()->V(i);
510 CoordType x = (projectLocal (v, vp, ppn) - v->P()).Normalize();
512 assert(fabs(x * ppn) < 0.1);
514 *ref = std::vector<CoordType>(3);
517 (*ref)[1] = (ppn ^ (*ref)[0]).Normalize();
518 (*ref)[2] = ppn.Normalize();
522 static void fitQuadricLocal (VertexType *v, std::vector<CoordType> ref, std::vector<VertexType*> &vv, QuadricLocal *q)
524 bool svdResolution =
false;
525 bool zeroDeterminantCheck =
false;
527 std::vector<CoordType> points;
528 points.reserve (vv.size());
530 typename std::vector<VertexType*>::iterator b = vv.begin();
531 typename std::vector<VertexType*>::iterator e = vv.end();
535 CoordType cp = (*b)->P();
538 CoordType vTang = cp - v->P();
540 double x = vTang * ref[0];
541 double y = vTang * ref[1];
542 double z = vTang * ref[2];
543 points.push_back(CoordType(x,y,z));
547 *q = QuadricLocal::fit (points, svdResolution, zeroDeterminantCheck);
551 static void finalEigenStuff (VertexType *v, std::vector<CoordType> ref, QuadricLocal q)
559 double E = 1.0 + d*d;
561 double G = 1.0 + e*e;
563 CoordType n = CoordType(-d,-e,1.0).Normalize();
565 v->N() = ref[0] * n[0] + ref[1] * n[1] + ref[2] * n[2];
567 double L = 2.0 * a * n.Z();
568 double M = b * n.Z();
569 double N = 2 * c * n.Z();
573 m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
575 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
577 Eigen::Vector2d c_val = eig.eigenvalues();
578 Eigen::Matrix2d c_vec = eig.eigenvectors();
585 v1[2] = d * v1[0] + e * v1[1];
589 v2[2] = d * v2[0] + e * v2[1];
594 CoordType v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2];
595 CoordType v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2];
597 v1global.Normalize();
598 v2global.Normalize();
600 v1global *= c_val[0];
601 v2global *= c_val[1];
603 if (c_val[0] > c_val[1])
605 (*v).PD1() = v1global;
606 (*v).PD2() = v2global;
607 (*v).K1() = c_val[0];
608 (*v).K2() = c_val[1];
612 (*v).PD1() = v2global;
613 (*v).PD2() = v1global;
614 (*v).K1() = c_val[1];
615 (*v).K2() = c_val[0];
622 static void updateCurvatureLocal (MeshType & mesh,
float radiusSphere, vcg::CallBackPos * cb = NULL)
625 bool projectionPlaneCheck =
true;
626 int vertexesPerFit = 0;
630 for(vi = mesh.vert.begin(); vi != mesh.vert.end(); ++vi, i++)
632 std::vector<VertexType*> vv;
633 std::vector<VertexType*> vvtmp;
634 if (cb && ((i%1024)==00)) {
635 (*cb)(int(100.0f * (
float)i / (
float)mesh.vn),
"Vertices Analysis");
637 expandSphereLocal (mesh, &*vi, radiusSphere, 5, &vv);
639 assert (vv.size() >= 5);
642 getAverageNormal (&*vi, vv, &ppn);
644 if (projectionPlaneCheck)
646 vvtmp.reserve (vv.size ());
647 applyProjOnPlane (ppn, vv, &vvtmp);
648 if (vvtmp.size() >= 5)
653 assert (vv.size() >= 5);
655 std::vector<CoordType> ref;
656 computeReferenceFramesLocal (&*vi, ppn, &ref);
658 vertexesPerFit += vv.size();
661 fitQuadricLocal (&*vi, ref, vv, &q);
663 finalEigenStuff (&*vi, ref, q);
668 printf (
"average vertex num in each fit: %f\n", ((
float) vertexesPerFit) / mesh.vn);
static void CompactVertexVector(MeshType &m, PointerUpdater< VertexPointer > &pu)
Compact vector of vertices removing deleted elements. Deleted elements are put to the end of the vect...
Definition: allocate.h:1084
Definition: curvature_fitting.h:315
Definition: curvature_fitting.h:78
Computation of per-vertex directions and values of curvature.
Definition: curvature_fitting.h:62
Management, updating and computation of per-vertex and per-face flags (like border flags).
Definition: flag.h:44
static void NormalizePerVertex(ComputeMeshType &m)
Normalize the length of the vertex normals.
Definition: normal.h:239
static void PerVertexAngleWeighted(ComputeMeshType &m)
Calculates the vertex normal as an angle weighted average. It does not need or exploit current face n...
Definition: normal.h:124
static void VertexFace(MeshType &m)
Update the Vertex-Face topological relation.
Definition: topology.h:467
Definition: namespaces.dox:6