24 #ifndef VCGLIB_UPDATE_CURVATURE_
25 #define VCGLIB_UPDATE_CURVATURE_
27 #include <vcg/space/index/grid_static_ptr.h>
28 #include <vcg/simplex/face/jumping_pos.h>
29 #include <vcg/complex/algorithms/update/normal.h>
30 #include <vcg/complex/algorithms/point_sampling.h>
31 #include <vcg/complex/algorithms/intersection.h>
32 #include <vcg/complex/algorithms/inertia.h>
47 template <
class MeshType>
52 typedef typename MeshType::FaceType FaceType;
53 typedef typename MeshType::FacePointer FacePointer;
54 typedef typename MeshType::FaceIterator FaceIterator;
55 typedef typename MeshType::VertexIterator VertexIterator;
56 typedef typename MeshType::VertContainer VertContainer;
57 typedef typename MeshType::VertexType VertexType;
58 typedef typename MeshType::VertexPointer VertexPointer;
59 typedef vcg::face::VFIterator<FaceType> VFIteratorType;
60 typedef typename MeshType::CoordType CoordType;
61 typedef typename CoordType::ScalarType ScalarType;
62 typedef typename MeshType::VertexType::CurScalarType CurScalarType;
63 typedef typename MeshType::VertexType::CurVecType CurVecType;
92 tri::RequireVFAdjacency(m);
96 for (VertexIterator vi =m.vert.begin(); vi !=m.vert.end(); ++vi) {
97 if ( ! (*vi).IsD() && (*vi).VFp() != NULL) {
99 VertexType * central_vertex = &(*vi);
101 std::vector<float> weights;
102 std::vector<AdjVertex> vertices;
104 vcg::face::JumpingPos<FaceType> pos((*vi).VFp(), central_vertex);
107 VertexType* firstV = pos.VFlip();
109 float totalDoubleAreaSize = 0.0f;
120 assert(tempV!=central_vertex);
123 v.isBorder = pos.IsBorder();
125 v.doubleArea = vcg::DoubleArea(*pos.F());
126 totalDoubleAreaSize += v.doubleArea;
128 vertices.push_back(v);
130 while(tempV != firstV);
133 for (
size_t i = 0; i < vertices.size(); ++i) {
134 if (vertices[i].isBorder) {
135 weights.push_back(vertices[i].doubleArea / totalDoubleAreaSize);
137 weights.push_back(0.5f * (vertices[i].doubleArea + vertices[(i-1)%vertices.size()].doubleArea) / totalDoubleAreaSize);
139 assert(weights.back() < 1.0f);
143 Matrix33<ScalarType> Tp;
144 for (
int i = 0; i < 3; ++i)
145 Tp[i][i] = 1.0f - powf(central_vertex->cN()[i],2);
146 Tp[0][1] = Tp[1][0] = -1.0f * (central_vertex->N()[0] * central_vertex->cN()[1]);
147 Tp[1][2] = Tp[2][1] = -1.0f * (central_vertex->cN()[1] * central_vertex->cN()[2]);
148 Tp[0][2] = Tp[2][0] = -1.0f * (central_vertex->cN()[0] * central_vertex->cN()[2]);
152 Matrix33<ScalarType> tempMatrix;
153 Matrix33<ScalarType> M;
155 for (
size_t i = 0; i < vertices.size(); ++i) {
156 CoordType edge = (central_vertex->cP() - vertices[i].vert->cP());
157 float curvature = (2.0f * (central_vertex->cN().dot(edge)) ) / edge.SquaredNorm();
158 CoordType T = (Tp*edge).normalized();
159 tempMatrix.ExternalProduct(T,T);
160 M += tempMatrix * weights[i] * curvature ;
165 CoordType e1(1.0f,0.0f,0.0f);
166 if ((e1 - central_vertex->cN()).SquaredNorm() > (e1 + central_vertex->cN()).SquaredNorm())
167 W = e1 - central_vertex->cN();
169 W = e1 + central_vertex->cN();
173 Matrix33<ScalarType> Q;
175 tempMatrix.ExternalProduct(W,W);
176 Q -= tempMatrix * 2.0f;
179 Matrix33<ScalarType> QtMQ = (Q.transpose() * M * Q);
182 CoordType T1 = Q.GetColumn(1);
183 CoordType T2 = Q.GetColumn(2);
188 float alpha = QtMQ[1][1]-QtMQ[2][2];
189 float beta = QtMQ[2][1];
192 float delta = sqrtf(4.0f*powf(alpha, 2) +16.0f*powf(beta, 2));
193 h[0] = (2.0f*alpha + delta) / (2.0f*beta);
194 h[1] = (2.0f*alpha - delta) / (2.0f*beta);
197 float best_c, best_s;
198 float min_error = std::numeric_limits<ScalarType>::infinity();
199 for (
int i=0; i<2; i++)
201 delta = sqrtf(powf(h[i], 2) + 4.0f);
202 t[0] = (h[i]+delta) / 2.0f;
203 t[1] = (h[i]-delta) / 2.0f;
205 for (
int j=0; j<2; j++)
207 float squared_t = powf(t[j], 2);
208 float denominator = 1.0f + squared_t;
209 s = (2.0f*t[j]) / denominator;
210 c = (1-squared_t) / denominator;
212 float approximation = c*s*alpha + (powf(c, 2) - powf(s, 2))*beta;
213 float angle_similarity = fabs(acosf(c)/asinf(s));
214 float error = fabs(1.0f-angle_similarity)+fabs(approximation);
226 Eigen::Matrix2f minor2x2;
231 minor2x2(0,0) = QtMQ[1][1];
232 minor2x2(0,1) = QtMQ[1][2];
233 minor2x2(1,0) = QtMQ[2][1];
234 minor2x2(1,1) = QtMQ[2][2];
240 Eigen::Matrix2f StMS = S.transpose() * minor2x2 * S;
243 float Principal_Curvature1 = (3.0f * StMS(0,0)) - StMS(1,1);
244 float Principal_Curvature2 = (3.0f * StMS(1,1)) - StMS(0,0);
246 CoordType Principal_Direction1 = T1 * c - T2 * s;
247 CoordType Principal_Direction2 = T1 * s + T2 * c;
249 (*vi).PD1().Import(Principal_Direction1);
250 (*vi).PD2().Import(Principal_Direction2);
251 (*vi).K1() = Principal_Curvature1;
252 (*vi).K2() = Principal_Curvature2;
274 typedef vcg::GridStaticPtr <VertexType, ScalarType > PointsGridType;
276 static void PrincipalDirectionsPCA(MeshType &m, ScalarType r,
bool pointVSfaceInt =
true,vcg::CallBackPos * cb = NULL)
278 std::vector<VertexType*> closests;
279 std::vector<ScalarType> distances;
280 std::vector<CoordType> points;
284 typename std::vector<CoordType>::iterator ii;
290 PointsGridType pGrid;
295 area = Stat<MeshType>::ComputeMeshArea(m);
298 for(
size_t y = 0; y < m.vert.size(); ++y,++vi) (*vi).P() = m.vert[y].P();
299 pGrid.Set(tmpM.vert.begin(),tmpM.vert.end());
303 mGrid.Set(m.face.begin(),m.face.end());
307 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
309 vcg::Matrix33<ScalarType> A, eigenvectors;
316 vcg::tri::GetInSphereVertex<
318 PointsGridType,std::vector<VertexType*>,
319 std::vector<ScalarType>,
320 std::vector<CoordType> >(tmpM,pGrid, (*vi).cP(),r ,closests,distances,points);
322 A.Covariance(points,bp);
326 IntersectionBallMesh<MeshType,ScalarType>( m ,vcg::Sphere3<ScalarType>((*vi).cP(),r),tmpM );
340 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(AA);
341 Eigen::Vector3d c_val = eig.eigenvalues();
342 Eigen::Matrix3d c_vec = eig.eigenvectors();
343 eigenvectors.FromEigenMatrix(c_vec);
344 eigenvalues.FromEigenVector(c_val);
350 int best = 0; ScalarType bestv = fabs( (*vi).cN().dot(eigenvectors.GetColumn(0).normalized()) );
351 for(
int i = 1 ; i < 3; ++i){
352 ScalarType prod = fabs((*vi).cN().dot(eigenvectors.GetColumn(i).normalized()));
353 if( prod > bestv){bestv = prod; best = i;}
356 (*vi).PD1().Import(eigenvectors.GetColumn( (best+1)%3).normalized());
357 (*vi).PD2().Import(eigenvectors.GetColumn( (best+2)%3).normalized());
360 vcg::Matrix33<CurScalarType> rot;
361 CurVecType NN = CurVecType::Construct((*vi).N());
363 angle = acos((*vi).PD1().dot(NN));
364 rot.SetRotateRad( - (M_PI*0.5 - angle),(*vi).PD1()^NN);
365 (*vi).PD1() = rot*(*vi).PD1();
366 angle = acos((*vi).PD2().dot(NN));
367 rot.SetRotateRad( - (M_PI*0.5 - angle),(*vi).PD2()^NN);
368 (*vi).PD2() = rot*(*vi).PD2();
372 const ScalarType r5 = r*r*r*r*r;
373 const ScalarType r6 = r*r5;
374 (*vi).K1() = (2.0/5.0) * (4.0*M_PI*r5 + 15*eigenvalues[(best+2)%3]-45.0*eigenvalues[(best+1)%3])/(M_PI*r6);
375 (*vi).K2() = (2.0/5.0) * (4.0*M_PI*r5 + 15*eigenvalues[(best+1)%3]-45.0*eigenvalues[(best+2)%3])/(M_PI*r6);
376 if((*vi).K1() < (*vi).K2()) { std::swap((*vi).K1(),(*vi).K2());
377 std::swap((*vi).PD1(),(*vi).PD2());
380 (*cb)(int(100.0f * (
float)jj / (
float)m.vn),
"Vertices Analysis");
402 tri::RequireFFAdjacency(m);
404 float area0, area1, area2, angle0, angle1, angle2;
407 typename MeshType::CoordType e01v ,e12v ,e20v;
409 SimpleTempData<VertContainer, AreaData> TDAreaPtr(m.vert);
410 SimpleTempData<VertContainer, typename MeshType::CoordType> TDContr(m.vert);
417 for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi)
if(!(*vi).IsD())
419 (TDAreaPtr)[*vi].A = 0.0;
420 (TDContr)[*vi] =
typename MeshType::CoordType(0.0,0.0,0.0);
422 KG[*vi] = (ScalarType)(2.0 * M_PI);
425 for(fi=m.face.begin();fi!=m.face.end();++fi)
if( !(*fi).IsD())
428 angle0 = math::Abs(Angle( (*fi).P(1)-(*fi).P(0),(*fi).P(2)-(*fi).P(0) ));
429 angle1 = math::Abs(Angle( (*fi).P(0)-(*fi).P(1),(*fi).P(2)-(*fi).P(1) ));
430 angle2 = M_PI-(angle0+angle1);
432 if((angle0 < M_PI/2) && (angle1 < M_PI/2) && (angle2 < M_PI/2))
434 float e01 = SquaredDistance( (*fi).V(1)->cP() , (*fi).V(0)->cP() );
435 float e12 = SquaredDistance( (*fi).V(2)->cP() , (*fi).V(1)->cP() );
436 float e20 = SquaredDistance( (*fi).V(0)->cP() , (*fi).V(2)->cP() );
438 area0 = ( e20*(1.0/tan(angle1)) + e01*(1.0/tan(angle2)) ) / 8.0;
439 area1 = ( e01*(1.0/tan(angle2)) + e12*(1.0/tan(angle0)) ) / 8.0;
440 area2 = ( e12*(1.0/tan(angle0)) + e20*(1.0/tan(angle1)) ) / 8.0;
442 (TDAreaPtr)[(*fi).V(0)].A += area0;
443 (TDAreaPtr)[(*fi).V(1)].A += area1;
444 (TDAreaPtr)[(*fi).V(2)].A += area2;
451 (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
452 (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
453 (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
455 else if(angle1 >= M_PI/2)
457 (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
458 (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
459 (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
463 (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
464 (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
465 (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
471 for(fi=m.face.begin();fi!=m.face.end();++fi)
if( !(*fi).IsD() )
473 angle0 = math::Abs(Angle( (*fi).P(1)-(*fi).P(0),(*fi).P(2)-(*fi).P(0) ));
474 angle1 = math::Abs(Angle( (*fi).P(0)-(*fi).P(1),(*fi).P(2)-(*fi).P(1) ));
475 angle2 = M_PI-(angle0+angle1);
478 if(angle0==0 || angle1==0 || angle2==0)
continue;
480 e01v = ( (*fi).V(1)->cP() - (*fi).V(0)->cP() ) ;
481 e12v = ( (*fi).V(2)->cP() - (*fi).V(1)->cP() ) ;
482 e20v = ( (*fi).V(0)->cP() - (*fi).V(2)->cP() ) ;
484 TDContr[(*fi).V(0)] += ( e20v * (1.0/tan(angle1)) - e01v * (1.0/tan(angle2)) ) / 4.0;
485 TDContr[(*fi).V(1)] += ( e01v * (1.0/tan(angle2)) - e12v * (1.0/tan(angle0)) ) / 4.0;
486 TDContr[(*fi).V(2)] += ( e12v * (1.0/tan(angle0)) - e20v * (1.0/tan(angle1)) ) / 4.0;
488 KG[(*fi).V(0)] -= angle0;
489 KG[(*fi).V(1)] -= angle1;
490 KG[(*fi).V(2)] -= angle2;
498 vcg::face::Pos<FaceType> hp(&*fi, i, (*fi).V(i));
499 vcg::face::Pos<FaceType> hp1=hp;
502 e1=hp1.v->cP() - hp.v->cP();
505 e2=hp1.v->cP() - hp.v->cP();
506 KG[(*fi).V(i)] -= math::Abs(Angle(e1,e2));
511 for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi)
if(!(*vi).IsD() )
513 if((TDAreaPtr)[*vi].A<=std::numeric_limits<ScalarType>::epsilon())
520 KH[(*vi)] = (((TDContr)[*vi].dot((*vi).cN())>0)?1.0:-1.0)*((TDContr)[*vi] / (TDAreaPtr) [*vi].A).Norm();
521 KG[(*vi)] /= (TDAreaPtr)[*vi].A;
538 tri::RequireVFAdjacency(m);
539 tri::RequireCompactness(m);
540 const bool areaNormalize =
true;
541 const bool barycentricArea=
false;
545 for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
547 VertexPointer v=&*vi;
548 VFIteratorType vfi(v);
552 ScalarType AngleDefect = (ScalarType)(2.0 * M_PI);;
556 FacePointer f = vfi.F();
557 CoordType nf = TriangleNormal(*f);
559 VertexPointer v0 = f->V0(i), v1 = f->V1(i), v2 = f->V2(i);
562 ScalarType ang0 = math::Abs(Angle(v1->P() - v0->P(), v2->P() - v0->P() ));
563 ScalarType ang1 = math::Abs(Angle(v0->P() - v1->P(), v2->P() - v1->P() ));
564 ScalarType ang2 = M_PI - ang0 - ang1;
566 ScalarType s01 = SquaredDistance(v1->P(), v0->P());
567 ScalarType s02 = SquaredDistance(v2->P(), v0->P());
571 A+=vcg::DoubleArea(*f)/6.0;
575 A += (0.5f * DoubleArea(*f) - (s01 * tan(ang1) + s02 * tan(ang2)) / 8.0 );
576 else if (ang1 >= M_PI/2)
577 A += (s01 * tan(ang0)) / 8.0;
578 else if (ang2 >= M_PI/2)
579 A += (s02 * tan(ang0)) / 8.0;
581 A += ((s02 / tan(ang1)) + (s01 / tan(ang2))) / 8.0;
591 ang1 = math::Abs(Angle(nf, v1->N()+v0->N()));
592 ang2 = math::Abs(Angle(nf, v2->N()+v0->N()));
593 KH[v] += math::Sqrt(s01)*ang1 + math::Sqrt(s02)*ang2 ;
600 if(A <= std::numeric_limits<float>::epsilon()) {
606 KG[v] = AngleDefect / A;
624 static void PrincipalDirectionsNormalCycle(MeshType & m){
625 tri::RequireVFAdjacency(m);
626 tri::RequireFFAdjacency(m);
628 typename MeshType::VertexIterator vi;
630 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
632 vcg::Matrix33<ScalarType> m33;m33.SetZero();
633 face::JumpingPos<typename MeshType::FaceType> p((*vi).VFp(),&(*vi));
635 typename MeshType::VertexType * firstv = p.VFlip();
636 assert(p.F()->V(p.VInd())==&(*vi));
639 if( p.F() != p.FFlip()){
640 Point3<ScalarType> normalized_edge = p.F()->V(p.F()->Next(p.VInd()))->cP() - (*vi).P();
641 ScalarType edge_length = normalized_edge.Norm();
642 normalized_edge/=edge_length;
645 ScalarType n1n2 = (n1 ^ n2).dot(normalized_edge);
646 n1n2 = std::max(std::min( ScalarType(1.0),n1n2),ScalarType(-1.0));
647 ScalarType beta = math::Asin(n1n2);
648 m33[0][0] += beta*edge_length*normalized_edge[0]*normalized_edge[0];
649 m33[0][1] += beta*edge_length*normalized_edge[1]*normalized_edge[0];
650 m33[1][1] += beta*edge_length*normalized_edge[1]*normalized_edge[1];
651 m33[0][2] += beta*edge_length*normalized_edge[2]*normalized_edge[0];
652 m33[1][2] += beta*edge_length*normalized_edge[2]*normalized_edge[1];
653 m33[2][2] += beta*edge_length*normalized_edge[2]*normalized_edge[2];
656 }
while(firstv != p.VFlip());
658 if(m33.Determinant()==0.0){
659 (*vi).K1() = (*vi).K2() = 0.0;
continue;}
661 m33[1][0] = m33[0][1];
662 m33[2][0] = m33[0][2];
663 m33[2][1] = m33[1][2];
666 m33.ToEigenMatrix(it);
667 Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(it);
668 Eigen::Vector3d c_val = eig.eigenvalues();
669 Eigen::Matrix3d c_vec = eig.eigenvectors();
671 Point3<ScalarType> lambda;
672 Matrix33<ScalarType> vect;
673 vect.FromEigenMatrix(c_vec);
674 lambda.FromEigenVector(c_val);
676 ScalarType bestNormal = 0;
677 int bestNormalIndex = -1;
678 for(
int i = 0; i < 3; ++i)
680 float agreeWithNormal = fabs((*vi).N().Normalize().dot(vect.GetColumn(i)));
681 if( agreeWithNormal > bestNormal )
683 bestNormal= agreeWithNormal;
687 int maxI = (bestNormalIndex+2)%3;
688 int minI = (bestNormalIndex+1)%3;
689 if(fabs(lambda[maxI]) < fabs(lambda[minI])) std::swap(maxI,minI);
691 (*vi).PD1().Import(vect.GetColumn(maxI));
692 (*vi).PD2().Import(vect.GetColumn(minI));
693 (*vi).K1() = lambda[2];
694 (*vi).K2() = lambda[1];
698 static void PerVertexBasicRadialCrossField(MeshType &m,
float anisotropyRatio = 1.0 )
700 tri::RequirePerVertexCurvatureDir(m);
701 CoordType c=m.bbox.Center();
702 float maxRad = m.bbox.Diag()/2.0f;
704 for(
size_t i=0;i<m.vert.size();++i) {
705 CoordType dd = m.vert[i].P()-c;
707 m.vert[i].PD1().Import(dd^m.vert[i].N());
708 m.vert[i].PD1().Normalize();
709 m.vert[i].PD2().Import(m.vert[i].N()^CoordType::Construct(m.vert[i].PD1()));
710 m.vert[i].PD2().Normalize();
716 float q =Distance(m.vert[i].P(),c) / maxRad;
717 const float minRatio = 1.0f/anisotropyRatio;
718 const float maxRatio = anisotropyRatio;
719 const float curRatio = minRatio + (maxRatio-minRatio)*q;
720 float pd1Len = sqrt(1.0/(1+curRatio*curRatio));
721 float pd2Len = curRatio * pd1Len;
724 m.vert[i].PD1() *= pd1Len;
725 m.vert[i].PD2() *= pd2Len;
Class to safely add and delete elements in a mesh.
Definition: allocate.h:97
static VertexIterator AddVertices(MeshType &m, size_t n, PointerUpdater< VertexPointer > &pu)
Add n vertices to the mesh. Function to add n vertices to the mesh. The elements are added always to ...
Definition: allocate.h:189
static void Covariance(const MeshType &m, vcg::Point3< ScalarType > &bary, vcg::Matrix33< ScalarType > &C)
Definition: inertia.h:318
Main Class of the Sampling framework.
Definition: point_sampling.h:467
A basic sampler class that show the required interface used by the SurfaceSampling class.
Definition: point_sampling.h:72
Definition: curvature.h:261
Management, updating and computation of per-vertex and per-face normals.
Definition: curvature.h:49
vcg::GridStaticPtr< FaceType, ScalarType > MeshGridType
Definition: curvature.h:273
static void PerVertexAbsoluteMeanAndGaussian(MeshType &m)
Update the mean and the gaussian curvature of a vertex.
Definition: curvature.h:536
static void PrincipalDirections(MeshType &m)
Compute principal direction and magnitudo of curvature.
Definition: curvature.h:90
static void MeanAndGaussian(MeshType &m)
Computes the discrete mean gaussian curvature.
Definition: curvature.h:400
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 PerVertexNormalized(ComputeMeshType &m)
Equivalent to PerVertex() and NormalizePerVertex()
Definition: normal.h:269
bool IsBorder(FaceType const &f, const int j)
Definition: topology.h:55
Definition: namespaces.dox:6