VCG Library
Loading...
Searching...
No Matches
curvature_fitting.h
1/****************************************************************************
2* VCGLib o o *
3* Visual and Computer Graphics Library o o *
4* _ O _ *
5* Copyright(C) 2004-2016 \/)\/ *
6* Visual Computing Lab /\/| *
7* ISTI - Italian National Research Council | *
8* \ *
9* All rights reserved. *
10* *
11* This program is free software; you can redistribute it and/or modify *
12* it under the terms of the GNU General Public License as published by *
13* the Free Software Foundation; either version 2 of the License, or *
14* (at your option) any later version. *
15* *
16* This program is distributed in the hope that it will be useful, *
17* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
20* for more details. *
21* *
22****************************************************************************/
23/****************************************************************************
24
25****************************************************************************/
26
27#ifndef VCGLIB_UPDATE_CURVATURE_FITTING
28#define VCGLIB_UPDATE_CURVATURE_FITTING
29
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>
40
41#include <Eigen/Core>
42#include <Eigen/QR>
43#include <Eigen/LU>
44#include <Eigen/SVD>
45#include <Eigen/Eigenvalues>
46
47
48namespace vcg {
49namespace tri {
50
52
54
56
60template <class MeshType>
62{
63
64public:
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;
76
78{
79 public:
80
81 Quadric(double av, double bv, double cv, double dv, double ev)
82 {
83 a() = av;
84 b() = bv;
85 c() = cv;
86 d() = dv;
87 e() = ev;
88 }
89
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];}
95
96 double data[5];
97
98 double evaluate(double u, double v)
99 {
100 return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
101 }
102
103 double du(double u, double v)
104 {
105 return 2.0*a()*u + b()*v + d();
106 }
107
108 double dv(double u, double v)
109 {
110 return 2.0*c()*v + b()*u + e();
111 }
112
113 double duv(double /*u*/, double /*v*/)
114 {
115 return b();
116 }
117
118 double duu(double /*u*/, double /*v*/)
119 {
120 return 2.0*a();
121 }
122
123 double dvv(double /*u*/, double /*v*/)
124 {
125 return 2.0*c();
126 }
127
128 static Quadric fit(std::vector<CoordType> VV)
129 {
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);
134
135 for(unsigned int c=0; c < VV.size(); ++c)
136 {
137 double u = VV[c].X();
138 double v = VV[c].Y();
139 double n = VV[c].Z();
140
141 A(c,0) = u*u;
142 A(c,1) = u*v;
143 A(c,2) = v*v;
144 A(c,3) = u;
145 A(c,4) = v;
146
147 b(c,0) = n;
148 }
149
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));
152 }
153};
154
155 static CoordType project(VertexType* v, VertexType* vp)
156 {
157 return vp->P() - (v->N() * ((vp->P() - v->P()) * v->N()));
158 }
159
160
161 static std::vector<CoordType> computeReferenceFrames(VertexTypeP vi)
162 {
163 vcg::face::VFIterator<FaceType> vfi(vi);
164
165 int i = (vfi.I()+1)%3;
166 VertexTypeP vp = vfi.F()->V(i);
167
168 CoordType x = (project(&*vi,vp) - vi->P()).Normalize();
169 //assert(fabs(x * vi->N()) < 0.1);
170
171 std::vector<CoordType> res(3);
172
173 res[0] = x;
174 res[1] = (vi->N() ^ res[0]).Normalize();
175 res[2] = (vi->N())/(vi->N()).Norm();
176
177 return res;
178 }
179
180 static std::set<CoordType> getSecondRing(VertexTypeP v)
181 {
182 std::set<VertexTypeP> ris;
183 std::set<CoordType> coords;
184
185 vcg::face::VFIterator<FaceType> vvi(v);
186 for(;!vvi.End();++vvi)
187 {
188 vcg::face::VFIterator<FaceType> vvi2(vvi.F()->V((vvi.I()+1)%3));
189 for(;!vvi2.End();++vvi2)
190 {
191 ris.insert(vvi2.F()->V((vvi2.I()+1)%3));
192 }
193 }
194 typename std::set<VertexTypeP>::iterator it;
195 for(it = ris.begin(); it != ris.end(); ++it)
196 coords.insert((*it)->P());
197
198 return coords;
199 }
200
201 static Quadric fitQuadric(VertexTypeP v, std::vector<CoordType>& ref)
202 {
203 std::set<CoordType> ring = getSecondRing(v);
204 if (ring.size() < 5)
205 return Quadric(1,1,1,1,1);
206 std::vector<CoordType> points;
207
208 typename std::set<CoordType>::iterator b = ring.begin();
209 typename std::set<CoordType>::iterator e = ring.end();
210
211 while(b != e)
212 {
213 // vtang non e` il v tangente!!!
214 CoordType vTang = *b - v->P();
215
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));
220 ++b;
221 }
222 return Quadric::fit(points);
223 }
224
225
226 static void computeCurvature(MeshType & m)
227 {
229 tri::RequireCompactness(m);
230 tri::RequireVFAdjacency(m);
231
233
236
237
238 VertexIterator vi;
239 for(vi = m.vert.begin(); vi!=m.vert.end(); ++vi )
240 {
241 std::vector<CoordType> ref = computeReferenceFrames(&*vi);
242
243 Quadric q = fitQuadric(&*vi,ref);
244 double a = q.a();
245 double b = q.b();
246 double c = q.c();
247 double d = q.d();
248 double e = q.e();
249
250 double E = 1.0 + d*d;
251 double F = d*e;
252 double G = 1.0 + e*e;
253
254 CoordType n = CoordType(-d,-e,1.0).Normalize();
255
256 vi->N() = ref[0] * n[0] + ref[1] * n[1] + ref[2] * n[2];
257
258 double L = 2.0 * a * n.Z();
259 double M = b * n.Z();
260 double N = 2 * c * n.Z();
261
262 // ----------------- Eigen stuff
263 Eigen::Matrix2d m;
264 m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
265 m = m / (E*G-F*F);
266 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
267
268 Eigen::Vector2d c_val = eig.eigenvalues();
269 Eigen::Matrix2d c_vec = eig.eigenvectors();
270
271 c_val = -c_val;
272
273 CoordType v1, v2;
274 v1[0] = c_vec(0,0);
275 v1[1] = c_vec(0,1);
276 v1[2] = 0;
277
278 v2[0] = c_vec(1,0);
279 v2[1] = c_vec(1,1);
280 v2[2] = 0;
281
282 v1 = v1.Normalize();
283 v2 = v2.Normalize();
284
285 v1 = v1 * c_val[0];
286 v2 = v2 * c_val[1];
287
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];
290
291 v1global.Normalize();
292 v2global.Normalize();
293
294 if (c_val[0] > c_val[1])
295 {
296 (*vi).PD1().Import(v1global);
297 (*vi).PD2().Import(v2global);
298 (*vi).K1() = c_val[0];
299 (*vi).K2() = c_val[1];
300 }
301 else
302 {
303 (*vi).PD1().Import(v2global);
304 (*vi).PD2().Import(v1global);
305 (*vi).K1() = c_val[1];
306 (*vi).K2() = c_val[0];
307 }
308 // ---- end Eigen stuff
309 }
310 }
311
312 // GG LOCAL CURVATURE
313
315 {
316 public:
317
318 QuadricLocal ()
319 {
320 a() = b() = c() = d() = e() = 1.0;
321 }
322
323 QuadricLocal (double av, double bv, double cv, double dv, double ev)
324 {
325 a() = av;
326 b() = bv;
327 c() = cv;
328 d() = dv;
329 e() = ev;
330 }
331
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];}
337
338 double data[5];
339
340 double evaluate(double u, double v)
341 {
342 return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
343 }
344
345 double du(double u, double v)
346 {
347 return 2.0*a()*u + b()*v + d();
348 }
349
350 double dv(double u, double v)
351 {
352 return 2.0*c()*v + b()*u + e();
353 }
354
355 double duv(double /*u*/, double /*v*/)
356 {
357 return b();
358 }
359
360 double duu(double /*u*/, double /*v*/)
361 {
362 return 2.0*a();
363 }
364
365 double dvv(double /*u*/, double /*v*/)
366 {
367 return 2.0*c();
368 }
369
370
371 static QuadricLocal fit(std::vector<CoordType> &VV, bool svdRes, bool detCheck)
372 {
373 assert(VV.size() >= 5);
374 Eigen::MatrixXd A(VV.size(),5);
375 Eigen::VectorXd b(VV.size());
376 Eigen::VectorXd sol(5);
377
378 for(unsigned int c=0; c < VV.size(); ++c)
379 {
380 double u = VV[c].X();
381 double v = VV[c].Y();
382 double n = VV[c].Z();
383
384 A(c,0) = u*u;
385 A(c,1) = u*v;
386 A(c,2) = v*v;
387 A(c,3) = u;
388 A(c,4) = v;
389
390 b[c] = n;
391 }
392
393
394 static int count = 0, index = 0;
395 double min = 0.000000000001; //1.0e-12
396 /*
397 if (!count)
398 printf("GNE %e\n", min);
399 */
400
401 if (detCheck && ((A.transpose()*A).determinant() < min && (A.transpose()*A).determinant() > -min))
402 {
403 //A.svd().solve(b, &sol); A.svd().solve(b, &sol);
404 //cout << sol << endl;
405 printf("Quadric: unsolvable vertex %d %d\n", count, ++index);
406 //return Quadric (1, 1, 1, 1, 1);
407// A.svd().solve(b, &sol);
408 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A);
409 sol=svd.solve(b);
410 return QuadricLocal(sol[0],sol[1],sol[2],sol[3],sol[4]);
411 }
412 count++;
413
414 //for (int i = 0; i < 100; i++)
415 {
416 if (svdRes)
417 {
418 Eigen::JacobiSVD<Eigen::MatrixXd> svd(A);
419 sol=svd.solve(b);
420 //A.svd().solve(b, &sol);
421 }
422 else
423 sol = ((A.transpose()*A).inverse()*A.transpose())*b;
424
425 }
426
427 return QuadricLocal(sol[0],sol[1],sol[2],sol[3],sol[4]);
428 }
429 };
430
431 static void expandMaxLocal (MeshType & mesh, VertexType *v, int max, std::vector<VertexType*> *vv)
432 {
433 Nring<MeshType> rw = Nring<MeshType> (v, &mesh);
434 do rw.expand (); while (rw.allV.size() < max+1);
435 if (rw.allV[0] != v)
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]);
440
441 rw.clear();
442 }
443
444
445 static void expandSphereLocal (MeshType & mesh, VertexType *v, float r, int min, std::vector<VertexType*> *vv)
446 {
447 Nring<MeshType> rw = Nring<MeshType> (v, &mesh);
448
449 bool isInside = true;
450 while (isInside)
451 {
452 rw.expand();
453 vv->reserve(rw.allV.size());
454
455 typename std::vector<VertexType*>::iterator b = rw.lastV.begin();
456 typename std::vector<VertexType*>::iterator e = rw.lastV.end();
457 isInside = false;
458 while(b != e)
459 {
460 if (((*b)->P() - v->P()).Norm() < r)
461 {
462 vv->push_back(*b);;
463 isInside = true;
464 }
465 ++b;
466 }
467 }
468 //printf ("%d\n", vv->size());
469 rw.clear();
470
471 if (vv->size() < min)
472 {
473 vv->clear();
474 expandMaxLocal (mesh, v, min, vv);
475 }
476 }
477
478
479 static void getAverageNormal (VertexType *vp, std::vector<VertexType*> &vv, CoordType *ppn)
480 {
481 *ppn = CoordType (0,0,0);
482 for (typename std::vector<VertexType*>::iterator vpi = vv.begin(); vpi != vv.end(); ++vpi)
483 *ppn += (*vpi)->N();
484 *ppn += (*vp).N();
485 *ppn /= vv.size() + 1;
486 ppn->Normalize();
487 }
488
489
490 static void applyProjOnPlane (CoordType ppn, std::vector<VertexType*> &vin, std::vector<VertexType*> *vout)
491 {
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);
495 }
496
497 static CoordType projectLocal(VertexType* v, VertexType* vp, CoordType ppn)
498 {
499 return vp->P() - (ppn * ((vp->P() - v->P()) * ppn));
500 }
501
502
503 static void computeReferenceFramesLocal (VertexType *v, CoordType ppn, std::vector<CoordType> *ref)
504 {
505 vcg::face::VFIterator<FaceType> vfi (v);
506
507 int i = (vfi.I() + 1) % 3;
508 VertexTypeP vp = vfi.F()->V(i);
509
510 CoordType x = (projectLocal (v, vp, ppn) - v->P()).Normalize();
511
512 assert(fabs(x * ppn) < 0.1);
513
514 *ref = std::vector<CoordType>(3);
515
516 (*ref)[0] = x;
517 (*ref)[1] = (ppn ^ (*ref)[0]).Normalize();
518 (*ref)[2] = ppn.Normalize(); //ppn / ppn.Norm();
519 }
520
521
522 static void fitQuadricLocal (VertexType *v, std::vector<CoordType> ref, std::vector<VertexType*> &vv, QuadricLocal *q)
523 {
524 bool svdResolution = false;
525 bool zeroDeterminantCheck = false;
526
527 std::vector<CoordType> points;
528 points.reserve (vv.size());
529
530 typename std::vector<VertexType*>::iterator b = vv.begin();
531 typename std::vector<VertexType*>::iterator e = vv.end();
532
533 while(b != e)
534 {
535 CoordType cp = (*b)->P();
536
537 // vtang non e` il v tangente!!!
538 CoordType vTang = cp - v->P();
539
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));
544 ++b;
545 }
546
547 *q = QuadricLocal::fit (points, svdResolution, zeroDeterminantCheck);
548 }
549
550
551 static void finalEigenStuff (VertexType *v, std::vector<CoordType> ref, QuadricLocal q)
552 {
553 double a = q.a();
554 double b = q.b();
555 double c = q.c();
556 double d = q.d();
557 double e = q.e();
558
559 double E = 1.0 + d*d;
560 double F = d*e;
561 double G = 1.0 + e*e;
562
563 CoordType n = CoordType(-d,-e,1.0).Normalize();
564
565 v->N() = ref[0] * n[0] + ref[1] * n[1] + ref[2] * n[2];
566
567 double L = 2.0 * a * n.Z();
568 double M = b * n.Z();
569 double N = 2 * c * n.Z();
570
571 // ----------------- Eigen stuff
572 Eigen::Matrix2d m;
573 m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
574 m = m / (E*G-F*F);
575 Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
576
577 Eigen::Vector2d c_val = eig.eigenvalues();
578 Eigen::Matrix2d c_vec = eig.eigenvectors();
579
580 c_val = -c_val;
581
582 CoordType v1, v2;
583 v1[0] = c_vec(0);
584 v1[1] = c_vec(1);
585 v1[2] = d * v1[0] + e * v1[1];
586
587 v2[0] = c_vec(2);
588 v2[1] = c_vec(3);
589 v2[2] = d * v2[0] + e * v2[1];
590
591 v1 = v1.Normalize();
592 v2 = v2.Normalize();
593
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];
596
597 v1global.Normalize();
598 v2global.Normalize();
599
600 v1global *= c_val[0];
601 v2global *= c_val[1];
602
603 if (c_val[0] > c_val[1])
604 {
605 (*v).PD1() = v1global;
606 (*v).PD2() = v2global;
607 (*v).K1() = c_val[0];
608 (*v).K2() = c_val[1];
609 }
610 else
611 {
612 (*v).PD1() = v2global;
613 (*v).PD2() = v1global;
614 (*v).K1() = c_val[1];
615 (*v).K2() = c_val[0];
616 }
617 // ---- end Eigen stuff
618 }
619
620
621
622 static void updateCurvatureLocal (MeshType & mesh, float radiusSphere, vcg::CallBackPos * cb = NULL)
623 {
624 vcg::tri::UpdateFlags<MeshType>::FaceClear(mesh, FaceType::VISITED);
625 bool projectionPlaneCheck = true;
626 int vertexesPerFit = 0;
627
628 int i = 0;
629 VertexIterator vi;
630 for(vi = mesh.vert.begin(); vi != mesh.vert.end(); ++vi, i++)
631 {
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");
636 }
637 expandSphereLocal (mesh, &*vi, radiusSphere, 5, &vv);
638
639 assert (vv.size() >= 5);
640
641 CoordType ppn;
642 getAverageNormal (&*vi, vv, &ppn);
643
644 if (projectionPlaneCheck)
645 {
646 vvtmp.reserve (vv.size ());
647 applyProjOnPlane (ppn, vv, &vvtmp);
648 if (vvtmp.size() >= 5)
649 vv = vvtmp;
650 }
651
652 vvtmp.clear();
653 assert (vv.size() >= 5);
654
655 std::vector<CoordType> ref;
656 computeReferenceFramesLocal (&*vi, ppn, &ref);
657
658 vertexesPerFit += vv.size();
659
660 QuadricLocal q;
661 fitQuadricLocal (&*vi, ref, vv, &q);
662
663 finalEigenStuff (&*vi, ref, q);
664
665 }
666
667 if (cb)
668 printf ("average vertex num in each fit: %f\n", ((float) vertexesPerFit) / mesh.vn);
669 }
670
671};
672
673}
674}
675#endif
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: color4.h:30