curvature.h
Go to the documentation of this file.
00001 /****************************************************************************
00002 * VCGLib                                                            o o     *
00003 * Visual and Computer Graphics Library                            o     o   *
00004 *                                                                _   O  _   *
00005 * Copyright(C) 2004                                                \/)\/    *
00006 * Visual Computing Lab                                            /\/|      *
00007 * ISTI - Italian National Research Council                           |      *
00008 *                                                                    \      *
00009 * All rights reserved.                                                      *
00010 *                                                                           *
00011 * This program is free software; you can redistribute it and/or modify      *
00012 * it under the terms of the GNU General Public License as published by      *
00013 * the Free Software Foundation; either version 2 of the License, or         *
00014 * (at your option) any later version.                                       *
00015 *                                                                           *
00016 * This program is distributed in the hope that it will be useful,           *
00017 * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020 * for more details.                                                         *
00021 *                                                                           *
00022 ****************************************************************************/
00023 
00024 #ifndef VCGLIB_UPDATE_CURVATURE_
00025 #define VCGLIB_UPDATE_CURVATURE_
00026 
00027 #include <vcg/space/index/grid_static_ptr.h>
00028 #include <vcg/simplex/face/topology.h>
00029 #include <vcg/simplex/face/pos.h>
00030 #include <vcg/simplex/face/jumping_pos.h>
00031 #include <vcg/complex/algorithms/update/normal.h>
00032 #include <vcg/complex/algorithms/point_sampling.h>
00033 #include <vcg/complex/algorithms/intersection.h>
00034 #include <vcg/complex/algorithms/inertia.h>
00035 #include <eigenlib/Eigen/Core>
00036 
00037 namespace vcg {
00038 namespace tri {
00039 
00041 
00043 
00045 
00049 template <class MeshType>
00050 class UpdateCurvature
00051 {
00052 
00053 public:
00054     typedef typename MeshType::FaceType FaceType;
00055     typedef typename MeshType::FacePointer FacePointer;
00056     typedef typename MeshType::FaceIterator FaceIterator;
00057     typedef typename MeshType::VertexIterator VertexIterator;
00058     typedef typename MeshType::VertContainer VertContainer;
00059     typedef typename MeshType::VertexType VertexType;
00060     typedef typename MeshType::VertexPointer VertexPointer;
00061     typedef vcg::face::VFIterator<FaceType> VFIteratorType;
00062     typedef typename MeshType::CoordType CoordType;
00063     typedef typename CoordType::ScalarType ScalarType;
00064     typedef typename MeshType::VertexType::CurScalarType CurScalarType;
00065     typedef typename MeshType::VertexType::CurVecType CurVecType;
00066 
00067 
00068 private:
00069   // aux data struct used by PrincipalDirections
00070   struct AdjVertex {
00071     VertexType * vert;
00072     float doubleArea;
00073     bool isBorder;
00074   };
00075 
00076 
00077 public:
00079 
00080 /*
00081     Compute principal direction and magniuto of curvature as describe in the paper:
00082     @InProceedings{bb33922,
00083   author =      "G. Taubin",
00084   title =       "Estimating the Tensor of Curvature of a Surface from a
00085          Polyhedral Approximation",
00086   booktitle =   "International Conference on Computer Vision",
00087   year =        "1995",
00088   pages =       "902--907",
00089   URL =         "http://dx.doi.org/10.1109/ICCV.1995.466840",
00090   bibsource =   "http://www.visionbib.com/bibliography/describe440.html#TT32253",
00091     */
00092   static void PrincipalDirections(MeshType &m)
00093   {
00094     tri::RequireVFAdjacency(m);
00095     vcg::tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
00096     vcg::tri::UpdateNormal<MeshType>::NormalizePerVertex(m);
00097 
00098     for (VertexIterator vi =m.vert.begin(); vi !=m.vert.end(); ++vi) {
00099       if ( ! (*vi).IsD() && (*vi).VFp() != NULL) {
00100 
00101         VertexType * central_vertex = &(*vi);
00102 
00103         std::vector<float> weights;
00104         std::vector<AdjVertex> vertices;
00105 
00106         vcg::face::JumpingPos<FaceType> pos((*vi).VFp(), central_vertex);
00107 
00108         // firstV is the first vertex of the 1ring neighboorhood
00109         VertexType* firstV = pos.VFlip();
00110         VertexType* tempV;
00111         float totalDoubleAreaSize = 0.0f;
00112 
00113         // compute the area of each triangle around the central vertex as well as their total area
00114         do
00115         {
00116           // this bring the pos to the next triangle  counterclock-wise
00117           pos.FlipF();
00118           pos.FlipE();
00119 
00120           // tempV takes the next vertex in the 1ring neighborhood
00121           tempV = pos.VFlip();
00122           assert(tempV!=central_vertex);
00123           AdjVertex v;
00124 
00125           v.isBorder = pos.IsBorder();
00126           v.vert = tempV;
00127           v.doubleArea = vcg::DoubleArea(*pos.F());
00128           totalDoubleAreaSize += v.doubleArea;
00129 
00130           vertices.push_back(v);
00131         }
00132         while(tempV != firstV);
00133 
00134         // compute the weights for the formula computing matrix M
00135         for (size_t i = 0; i < vertices.size(); ++i) {
00136           if (vertices[i].isBorder) {
00137             weights.push_back(vertices[i].doubleArea / totalDoubleAreaSize);
00138           } else {
00139             weights.push_back(0.5f * (vertices[i].doubleArea + vertices[(i-1)%vertices.size()].doubleArea) / totalDoubleAreaSize);
00140           }
00141           assert(weights.back() < 1.0f);
00142         }
00143 
00144         // compute I-NN^t to be used for computing the T_i's
00145         Matrix33<ScalarType> Tp;
00146         for (int i = 0; i < 3; ++i)
00147           Tp[i][i] = 1.0f - powf(central_vertex->cN()[i],2);
00148         Tp[0][1] = Tp[1][0] = -1.0f * (central_vertex->N()[0] * central_vertex->cN()[1]);
00149         Tp[1][2] = Tp[2][1] = -1.0f * (central_vertex->cN()[1] * central_vertex->cN()[2]);
00150         Tp[0][2] = Tp[2][0] = -1.0f * (central_vertex->cN()[0] * central_vertex->cN()[2]);
00151 
00152         // for all neighbors vi compute the directional curvatures k_i and the T_i
00153         // compute M by summing all w_i k_i T_i T_i^t
00154         Matrix33<ScalarType> tempMatrix;
00155         Matrix33<ScalarType> M;
00156         M.SetZero();
00157         for (size_t i = 0; i < vertices.size(); ++i) {
00158           CoordType edge = (central_vertex->cP() - vertices[i].vert->cP());
00159           float curvature = (2.0f * (central_vertex->cN().dot(edge)) ) / edge.SquaredNorm();
00160           CoordType T = (Tp*edge).normalized();
00161           tempMatrix.ExternalProduct(T,T);
00162           M += tempMatrix * weights[i] * curvature ;
00163         }
00164 
00165         // compute vector W for the Householder matrix
00166         CoordType W;
00167         CoordType e1(1.0f,0.0f,0.0f);
00168         if ((e1 - central_vertex->cN()).SquaredNorm() > (e1 + central_vertex->cN()).SquaredNorm())
00169           W = e1 - central_vertex->cN();
00170         else
00171           W = e1 + central_vertex->cN();
00172         W.Normalize();
00173 
00174         // compute the Householder matrix I - 2WW^t
00175         Matrix33<ScalarType> Q;
00176         Q.SetIdentity();
00177         tempMatrix.ExternalProduct(W,W);
00178         Q -= tempMatrix * 2.0f;
00179 
00180         // compute matrix Q^t M Q
00181         Matrix33<ScalarType> QtMQ = (Q.transpose() * M * Q);
00182 
00183 //        CoordType bl = Q.GetColumn(0);
00184         CoordType T1 = Q.GetColumn(1);
00185         CoordType T2 = Q.GetColumn(2);
00186 
00187         // find sin and cos for the Givens rotation
00188         float s,c;
00189         // Gabriel Taubin hint and Valentino Fiorin impementation
00190         float alpha = QtMQ[1][1]-QtMQ[2][2];
00191         float beta  = QtMQ[2][1];
00192 
00193         float h[2];
00194         float delta = sqrtf(4.0f*powf(alpha, 2) +16.0f*powf(beta, 2));
00195         h[0] = (2.0f*alpha + delta) / (2.0f*beta);
00196         h[1] = (2.0f*alpha - delta) / (2.0f*beta);
00197 
00198         float t[2];
00199         float best_c, best_s;
00200         float min_error = std::numeric_limits<ScalarType>::infinity();
00201         for (int i=0; i<2; i++)
00202         {
00203           delta = sqrtf(powf(h[i], 2) + 4.0f);
00204           t[0] = (h[i]+delta) / 2.0f;
00205           t[1] = (h[i]-delta) / 2.0f;
00206 
00207           for (int j=0; j<2; j++)
00208           {
00209             float squared_t = powf(t[j], 2);
00210             float denominator = 1.0f + squared_t;
00211             s = (2.0f*t[j])             / denominator;
00212             c = (1-squared_t) / denominator;
00213 
00214             float approximation = c*s*alpha + (powf(c, 2) - powf(s, 2))*beta;
00215             float angle_similarity = fabs(acosf(c)/asinf(s));
00216             float error = fabs(1.0f-angle_similarity)+fabs(approximation);
00217             if (error<min_error)
00218             {
00219               min_error = error;
00220               best_c = c;
00221               best_s = s;
00222             }
00223           }
00224         }
00225         c = best_c;
00226         s = best_s;
00227 
00228         Eigen::Matrix2f minor2x2;
00229         Eigen::Matrix2f S;
00230 
00231 
00232         // diagonalize M
00233         minor2x2(0,0) = QtMQ[1][1];
00234         minor2x2(0,1) = QtMQ[1][2];
00235         minor2x2(1,0) = QtMQ[2][1];
00236         minor2x2(1,1) = QtMQ[2][2];
00237 
00238         S(0,0) = S(1,1) = c;
00239         S(0,1) = s;
00240         S(1,0) = -1.0f * s;
00241 
00242         Eigen::Matrix2f StMS = S.transpose() * minor2x2 * S;
00243 
00244         // compute curvatures and curvature directions
00245         float Principal_Curvature1 = (3.0f * StMS(0,0)) - StMS(1,1);
00246         float Principal_Curvature2 = (3.0f * StMS(1,1)) - StMS(0,0);
00247 
00248         CoordType Principal_Direction1 = T1 * c - T2 * s;
00249         CoordType Principal_Direction2 = T1 * s + T2 * c;
00250 
00251         (*vi).PD1().Import(Principal_Direction1);
00252         (*vi).PD2().Import(Principal_Direction2);
00253         (*vi).K1() =  Principal_Curvature1;
00254         (*vi).K2() =  Principal_Curvature2;
00255       }
00256     }
00257   }
00258 
00259 
00260 
00261 
00262   class AreaData
00263   {
00264   public:
00265     float A;
00266   };
00267 
00275   typedef vcg::GridStaticPtr	<FaceType, ScalarType >            MeshGridType;
00276   typedef vcg::GridStaticPtr	<VertexType, ScalarType >          PointsGridType;
00277 
00278   static void PrincipalDirectionsPCA(MeshType &m, ScalarType r, bool pointVSfaceInt = true,vcg::CallBackPos * cb = NULL)
00279   {
00280     std::vector<VertexType*> closests;
00281     std::vector<ScalarType> distances;
00282     std::vector<CoordType> points;
00283     VertexIterator vi;
00284     ScalarType area;
00285     MeshType tmpM;
00286     typename std::vector<CoordType>::iterator ii;
00287     vcg::tri::TrivialSampler<MeshType> vs;
00288     tri::UpdateNormal<MeshType>::PerVertexAngleWeighted(m);
00289     tri::UpdateNormal<MeshType>::NormalizePerVertex(m);
00290 
00291     MeshGridType mGrid;
00292     PointsGridType pGrid;
00293 
00294     // Fill the grid used
00295     if(pointVSfaceInt)
00296     {
00297       area = Stat<MeshType>::ComputeMeshArea(m);
00298       vcg::tri::SurfaceSampling<MeshType,vcg::tri::TrivialSampler<MeshType> >::Montecarlo(m,vs,1000 * area / (2*M_PI*r*r ));
00299       vi = vcg::tri::Allocator<MeshType>::AddVertices(tmpM,m.vert.size());
00300       for(size_t y  = 0; y <  m.vert.size(); ++y,++vi)  (*vi).P() =  m.vert[y].P();
00301       pGrid.Set(tmpM.vert.begin(),tmpM.vert.end());
00302     }
00303     else
00304     {
00305       mGrid.Set(m.face.begin(),m.face.end());
00306     }
00307 
00308     int jj = 0;
00309     for(vi  = m.vert.begin(); vi != m.vert.end(); ++vi)
00310     {
00311       vcg::Matrix33<ScalarType> A, eigenvectors;
00312       vcg::Point3<ScalarType> bp, eigenvalues;
00313 //      int nrot;
00314 
00315       // sample the neighborhood
00316       if(pointVSfaceInt)
00317       {
00318         vcg::tri::GetInSphereVertex<
00319             MeshType,
00320             PointsGridType,std::vector<VertexType*>,
00321             std::vector<ScalarType>,
00322             std::vector<CoordType> >(tmpM,pGrid,  (*vi).cP(),r ,closests,distances,points);
00323 
00324         A.Covariance(points,bp);
00325         A*=area*area/1000;
00326       }
00327       else{
00328         IntersectionBallMesh<MeshType,ScalarType>( m ,vcg::Sphere3<ScalarType>((*vi).cP(),r),tmpM );
00329         vcg::Point3<ScalarType> _bary;
00330         vcg::tri::Inertia<MeshType>::Covariance(tmpM,_bary,A);
00331       }
00332 
00333 //      Eigen::Matrix3f AA; AA=A;
00334 //      Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eig(AA);
00335 //      Eigen::Vector3f c_val = eig.eigenvalues();
00336 //      Eigen::Matrix3f c_vec = eig.eigenvectors();
00337 
00338 //      Jacobi(A,  eigenvalues , eigenvectors, nrot);
00339 
00340       Eigen::Matrix3d AA;
00341       A.ToEigenMatrix(AA);
00342       Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(AA);
00343       Eigen::Vector3d c_val = eig.eigenvalues();
00344       Eigen::Matrix3d c_vec = eig.eigenvectors(); // eigenvector are stored as columns.
00345       eigenvectors.FromEigenMatrix(c_vec);
00346       eigenvalues.FromEigenVector(c_val);
00347 //        EV.transposeInPlace();
00348 //        ev.FromEigenVector(c_val);
00349 
00350       // get the estimate of curvatures from eigenvalues and eigenvectors
00351       // find the 2 most tangent eigenvectors (by finding the one closest to the normal)
00352       int best = 0; ScalarType bestv = fabs( (*vi).cN().dot(eigenvectors.GetColumn(0).normalized()) );
00353       for(int i  = 1 ; i < 3; ++i){
00354         ScalarType prod = fabs((*vi).cN().dot(eigenvectors.GetColumn(i).normalized()));
00355         if( prod > bestv){bestv = prod; best = i;}
00356       }
00357 
00358       (*vi).PD1().Import(eigenvectors.GetColumn( (best+1)%3).normalized());
00359       (*vi).PD2().Import(eigenvectors.GetColumn( (best+2)%3).normalized());
00360 
00361       // project them to the plane identified by the normal
00362       vcg::Matrix33<CurScalarType> rot;
00363       CurVecType NN = CurVecType::Construct((*vi).N());
00364       CurScalarType angle;
00365       angle = acos((*vi).PD1().dot(NN));
00366       rot.SetRotateRad(  - (M_PI*0.5 - angle),(*vi).PD1()^NN);
00367       (*vi).PD1() = rot*(*vi).PD1();
00368       angle = acos((*vi).PD2().dot(NN));
00369       rot.SetRotateRad(  - (M_PI*0.5 - angle),(*vi).PD2()^NN);
00370       (*vi).PD2() = rot*(*vi).PD2();
00371 
00372 
00373       // copmutes the curvature values
00374       const ScalarType r5 = r*r*r*r*r;
00375       const ScalarType r6 = r*r5;
00376       (*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);
00377       (*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);
00378       if((*vi).K1() < (*vi).K2())       {       std::swap((*vi).K1(),(*vi).K2());
00379         std::swap((*vi).PD1(),(*vi).PD2());
00380         if (cb)
00381         {
00382           (*cb)(int(100.0f * (float)jj / (float)m.vn),"Vertices Analysis");
00383           ++jj;
00384         }                                                                                                       }
00385     }
00386 
00387 
00388   }
00389 
00391 
00402 static void MeanAndGaussian(MeshType & m)
00403 {
00404   tri::RequireFFAdjacency(m);
00405 
00406   float area0, area1, area2, angle0, angle1, angle2;
00407   FaceIterator fi;
00408   VertexIterator vi;
00409   typename MeshType::CoordType  e01v ,e12v ,e20v;
00410 
00411   SimpleTempData<VertContainer, AreaData> TDAreaPtr(m.vert);
00412   SimpleTempData<VertContainer, typename MeshType::CoordType> TDContr(m.vert);
00413 
00414   vcg::tri::UpdateNormal<MeshType>::PerVertexNormalized(m);
00415   //Compute AreaMix in H (vale anche per K)
00416   for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(!(*vi).IsD())
00417   {
00418     (TDAreaPtr)[*vi].A = 0.0;
00419     (TDContr)[*vi]  =typename MeshType::CoordType(0.0,0.0,0.0);
00420     (*vi).Kh() = 0.0;
00421     (*vi).Kg() = (float)(2.0 * M_PI);
00422   }
00423 
00424   for(fi=m.face.begin();fi!=m.face.end();++fi) if( !(*fi).IsD())
00425   {
00426     // angles
00427     angle0 = math::Abs(Angle(   (*fi).P(1)-(*fi).P(0),(*fi).P(2)-(*fi).P(0) ));
00428     angle1 = math::Abs(Angle(   (*fi).P(0)-(*fi).P(1),(*fi).P(2)-(*fi).P(1) ));
00429     angle2 = M_PI-(angle0+angle1);
00430 
00431     if((angle0 < M_PI/2) && (angle1 < M_PI/2) && (angle2 < M_PI/2))  // triangolo non ottuso
00432     {
00433       float e01 = SquaredDistance( (*fi).V(1)->cP() , (*fi).V(0)->cP() );
00434       float e12 = SquaredDistance( (*fi).V(2)->cP() , (*fi).V(1)->cP() );
00435       float e20 = SquaredDistance( (*fi).V(0)->cP() , (*fi).V(2)->cP() );
00436 
00437       area0 = ( e20*(1.0/tan(angle1)) + e01*(1.0/tan(angle2)) ) / 8.0;
00438       area1 = ( e01*(1.0/tan(angle2)) + e12*(1.0/tan(angle0)) ) / 8.0;
00439       area2 = ( e12*(1.0/tan(angle0)) + e20*(1.0/tan(angle1)) ) / 8.0;
00440 
00441       (TDAreaPtr)[(*fi).V(0)].A  += area0;
00442       (TDAreaPtr)[(*fi).V(1)].A  += area1;
00443       (TDAreaPtr)[(*fi).V(2)].A  += area2;
00444 
00445     }
00446     else // obtuse
00447     {
00448       if(angle0 >= M_PI/2)
00449       {
00450         (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
00451         (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00452         (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00453       }
00454       else if(angle1 >= M_PI/2)
00455       {
00456         (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00457         (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
00458         (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00459       }
00460       else
00461       {
00462         (TDAreaPtr)[(*fi).V(0)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00463         (TDAreaPtr)[(*fi).V(1)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 8.0;
00464         (TDAreaPtr)[(*fi).V(2)].A += vcg::DoubleArea<typename MeshType::FaceType>((*fi)) / 4.0;
00465       }
00466     }
00467   }
00468 
00469 
00470   for(fi=m.face.begin();fi!=m.face.end();++fi) if( !(*fi).IsD() )
00471   {
00472     angle0 = math::Abs(Angle(   (*fi).P(1)-(*fi).P(0),(*fi).P(2)-(*fi).P(0) ));
00473     angle1 = math::Abs(Angle(   (*fi).P(0)-(*fi).P(1),(*fi).P(2)-(*fi).P(1) ));
00474     angle2 = M_PI-(angle0+angle1);
00475 
00476     // Skip degenerate triangles.
00477     if(angle0==0 || angle1==0 || angle1==0) continue;
00478 
00479     e01v = ( (*fi).V(1)->cP() - (*fi).V(0)->cP() ) ;
00480     e12v = ( (*fi).V(2)->cP() - (*fi).V(1)->cP() ) ;
00481     e20v = ( (*fi).V(0)->cP() - (*fi).V(2)->cP() ) ;
00482 
00483     TDContr[(*fi).V(0)] += ( e20v * (1.0/tan(angle1)) - e01v * (1.0/tan(angle2)) ) / 4.0;
00484     TDContr[(*fi).V(1)] += ( e01v * (1.0/tan(angle2)) - e12v * (1.0/tan(angle0)) ) / 4.0;
00485     TDContr[(*fi).V(2)] += ( e12v * (1.0/tan(angle0)) - e20v * (1.0/tan(angle1)) ) / 4.0;
00486 
00487     (*fi).V(0)->Kg() -= angle0;
00488     (*fi).V(1)->Kg() -= angle1;
00489     (*fi).V(2)->Kg() -= angle2;
00490 
00491 
00492     for(int i=0;i<3;i++)
00493     {
00494       if(vcg::face::IsBorder((*fi), i))
00495       {
00496         CoordType e1,e2;
00497         vcg::face::Pos<FaceType> hp(&*fi, i, (*fi).V(i));
00498         vcg::face::Pos<FaceType> hp1=hp;
00499 
00500         hp1.FlipV();
00501         e1=hp1.v->cP() - hp.v->cP();
00502         hp1.FlipV();
00503         hp1.NextB();
00504         e2=hp1.v->cP() - hp.v->cP();
00505         (*fi).V(i)->Kg() -= math::Abs(Angle(e1,e2));
00506       }
00507     }
00508   }
00509 
00510   for(vi=m.vert.begin(); vi!=m.vert.end(); ++vi) if(!(*vi).IsD() /*&& !(*vi).IsB()*/)
00511   {
00512     if((TDAreaPtr)[*vi].A<=std::numeric_limits<ScalarType>::epsilon())
00513     {
00514       (*vi).Kh() = 0;
00515       (*vi).Kg() = 0;
00516     }
00517     else
00518     {
00519       (*vi).Kh()  = (((TDContr)[*vi].dot((*vi).cN())>0)?1.0:-1.0)*((TDContr)[*vi] / (TDAreaPtr) [*vi].A).Norm();
00520       (*vi).Kg() /= (TDAreaPtr)[*vi].A;
00521     }
00522   }
00523 }
00524 
00525 
00527 
00534     static float ComputeSingleVertexCurvature(VertexPointer v, bool norm = true)
00535     {
00536         VFIteratorType vfi(v);
00537         float A = 0;
00538 
00539         v->Kh() = 0;
00540         v->Kg() = 2 * M_PI;
00541 
00542         while (!vfi.End()) {
00543             if (!vfi.F()->IsD()) {
00544                 FacePointer f = vfi.F();
00545                 int i = vfi.I();
00546                 VertexPointer v0 = f->V0(i), v1 = f->V1(i), v2 = f->V2(i);
00547 
00548                 float ang0 = math::Abs(Angle(v1->P() - v0->P(), v2->P() - v0->P() ));
00549                 float ang1 = math::Abs(Angle(v0->P() - v1->P(), v2->P() - v1->P() ));
00550                 float ang2 = M_PI - ang0 - ang1;
00551 
00552                 float s01 = SquaredDistance(v1->P(), v0->P());
00553                 float s02 = SquaredDistance(v2->P(), v0->P());
00554 
00555                 // voronoi cell of current vertex
00556                 if (ang0 >= M_PI/2)
00557                     A += (0.5f * DoubleArea(*f) - (s01 * tan(ang1) + s02 * tan(ang2)) / 8.0 );
00558                 else if (ang1 >= M_PI/2)
00559                     A += (s01 * tan(ang0)) / 8.0;
00560                 else if (ang2 >= M_PI/2)
00561                     A += (s02 * tan(ang0)) / 8.0;
00562                 else  // non obctuse triangle
00563                     A += ((s02 / tan(ang1)) + (s01 / tan(ang2))) / 8.0;
00564 
00565                 // gaussian curvature update
00566                 v->Kg() -= ang0;
00567 
00568                 // mean curvature update
00569                 ang1 = math::Abs(Angle(f->N(), v1->N()));
00570                 ang2 = math::Abs(Angle(f->N(), v2->N()));
00571                 v->Kh() += ( (math::Sqrt(s01) / 2.0) * ang1 +
00572                              (math::Sqrt(s02) / 2.0) * ang2 );
00573             }
00574 
00575             ++vfi;
00576         }
00577 
00578         v->Kh() /= 4.0f;
00579 
00580         if(norm) {
00581             if(A <= std::numeric_limits<float>::epsilon()) {
00582                 v->Kh() = 0;
00583                 v->Kg() = 0;
00584             }
00585             else {
00586                 v->Kh() /= A;
00587                 v->Kg() /= A;
00588             }
00589         }
00590 
00591         return A;
00592     }
00593 
00594     static void PerVertex(MeshType & m)
00595     {
00596       tri::RequireVFAdjacency(m);
00597 
00598       for(VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00599         ComputeSingleVertexCurvature(&*vi,false);
00600     }
00601 
00602 
00603 
00604 /*
00605     Compute principal curvature directions and value with normal cycle:
00606     @inproceedings{CohMor03,
00607     author = {Cohen-Steiner, David   and Morvan, Jean-Marie  },
00608     booktitle = {SCG '03: Proceedings of the nineteenth annual symposium on Computational geometry},
00609     title - {Restricted delaunay triangulations and normal cycle}
00610     year = {2003}
00611 }
00612     */
00613 
00614     static void PrincipalDirectionsNormalCycle(MeshType & m){
00615       tri::RequireVFAdjacency(m);
00616       tri::RequireFFAdjacency(m);
00617       tri::RequirePerFaceNormal(m);
00618 
00619         typename MeshType::VertexIterator vi;
00620 
00621         for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00622         if(!((*vi).IsD())){
00623             vcg::Matrix33<ScalarType> m33;m33.SetZero();
00624             face::JumpingPos<typename MeshType::FaceType> p((*vi).VFp(),&(*vi));
00625             p.FlipE();
00626             typename MeshType::VertexType * firstv = p.VFlip();
00627             assert(p.F()->V(p.VInd())==&(*vi));
00628 
00629             do{
00630                 if( p.F() != p.FFlip()){
00631                     Point3<ScalarType> normalized_edge = p.F()->V(p.F()->Next(p.VInd()))->cP() - (*vi).P();
00632                     ScalarType edge_length = normalized_edge.Norm();
00633                     normalized_edge/=edge_length;
00634                     Point3<ScalarType> n1 = p.F()->cN();n1.Normalize();
00635                     Point3<ScalarType> n2 = p.FFlip()->cN();n2.Normalize();
00636                     ScalarType n1n2 = (n1 ^ n2).dot(normalized_edge);
00637                     n1n2 = std::max(std::min( ScalarType(1.0),n1n2),ScalarType(-1.0));
00638                     ScalarType beta = math::Asin(n1n2);
00639                     m33[0][0] += beta*edge_length*normalized_edge[0]*normalized_edge[0];
00640                     m33[0][1] += beta*edge_length*normalized_edge[1]*normalized_edge[0];
00641                     m33[1][1] += beta*edge_length*normalized_edge[1]*normalized_edge[1];
00642                     m33[0][2] += beta*edge_length*normalized_edge[2]*normalized_edge[0];
00643                     m33[1][2] += beta*edge_length*normalized_edge[2]*normalized_edge[1];
00644                     m33[2][2] += beta*edge_length*normalized_edge[2]*normalized_edge[2];
00645                 }
00646                 p.NextFE();
00647             }while(firstv != p.VFlip());
00648 
00649             if(m33.Determinant()==0.0){ // degenerate case
00650                 (*vi).K1() = (*vi).K2() = 0.0; continue;}
00651 
00652             m33[1][0] = m33[0][1];
00653             m33[2][0] = m33[0][2];
00654             m33[2][1] = m33[1][2];
00655 
00656             Eigen::Matrix3d it;
00657             m33.ToEigenMatrix(it);
00658             Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> eig(it);
00659             Eigen::Vector3d c_val = eig.eigenvalues();
00660             Eigen::Matrix3d c_vec = eig.eigenvectors();
00661 
00662             Point3<ScalarType> lambda;
00663             Matrix33<ScalarType> vect;
00664             vect.FromEigenMatrix(c_vec);
00665             lambda.FromEigenVector(c_val);
00666 
00667             ScalarType bestNormal = 0;
00668             int bestNormalIndex = -1;
00669             for(int i = 0; i < 3; ++i)
00670             {
00671               float agreeWithNormal =  fabs((*vi).N().Normalize().dot(vect.GetColumn(i)));
00672                 if( agreeWithNormal > bestNormal )
00673                 {
00674                     bestNormal= agreeWithNormal;
00675                     bestNormalIndex = i;
00676                 }
00677             }
00678             int maxI = (bestNormalIndex+2)%3;
00679             int minI = (bestNormalIndex+1)%3;
00680             if(fabs(lambda[maxI]) < fabs(lambda[minI])) std::swap(maxI,minI);
00681 
00682             (*vi).PD1().Import(vect.GetColumn(maxI));
00683             (*vi).PD2().Import(vect.GetColumn(minI));
00684             (*vi).K1() = lambda[2];
00685             (*vi).K2() = lambda[1];
00686         }
00687     }
00688 
00689     static void PerVertexBasicRadialCrossField(MeshType &m, float anisotropyRatio = 1.0 )
00690     {
00691       tri::RequirePerVertexCurvatureDir(m);
00692       CoordType c=m.bbox.Center();
00693       float maxRad = m.bbox.Diag()/2.0f;
00694 
00695       for(size_t i=0;i<m.vert.size();++i) {
00696         CoordType dd = m.vert[i].P()-c;
00697         dd.Normalize();
00698         m.vert[i].PD1().Import(dd^m.vert[i].N());
00699         m.vert[i].PD1().Normalize();
00700         m.vert[i].PD2().Import(m.vert[i].N()^CoordType::Construct(m.vert[i].PD1()));
00701         m.vert[i].PD2().Normalize();
00702         // Now the anisotropy
00703         // the idea is that the ratio between the two direction is at most <anisotropyRatio>
00704         // eg  |PD1|/|PD2| < ratio
00705         // and |PD1|^2 + |PD2|^2 == 1
00706 
00707         float q =Distance(m.vert[i].P(),c) / maxRad;  // it is in the 0..1 range
00708         const float minRatio = 1.0f/anisotropyRatio;
00709         const float maxRatio = anisotropyRatio;
00710         const float curRatio = minRatio + (maxRatio-minRatio)*q;
00711         float pd1Len = sqrt(1.0/(1+curRatio*curRatio));
00712         float pd2Len = curRatio * pd1Len;
00713 //        assert(fabs(curRatio - pd2Len/pd1Len)<0.0000001);
00714 //        assert(fabs(pd1Len*pd1Len + pd2Len*pd2Len - 1.0f)<0.0001);
00715         m.vert[i].PD1() *= pd1Len;
00716         m.vert[i].PD2() *= pd2Len;
00717       }
00718     }
00719 
00720 };
00721 
00722 } // end namespace tri
00723 } // end namespace vcg
00724 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:30:16