00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00070 struct AdjVertex {
00071 VertexType * vert;
00072 float doubleArea;
00073 bool isBorder;
00074 };
00075
00076
00077 public:
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
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
00109 VertexType* firstV = pos.VFlip();
00110 VertexType* tempV;
00111 float totalDoubleAreaSize = 0.0f;
00112
00113
00114 do
00115 {
00116
00117 pos.FlipF();
00118 pos.FlipE();
00119
00120
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
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
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
00153
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
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
00175 Matrix33<ScalarType> Q;
00176 Q.SetIdentity();
00177 tempMatrix.ExternalProduct(W,W);
00178 Q -= tempMatrix * 2.0f;
00179
00180
00181 Matrix33<ScalarType> QtMQ = (Q.transpose() * M * Q);
00182
00183
00184 CoordType T1 = Q.GetColumn(1);
00185 CoordType T2 = Q.GetColumn(2);
00186
00187
00188 float s,c;
00189
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
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
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
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
00314
00315
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
00334
00335
00336
00337
00338
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();
00345 eigenvectors.FromEigenMatrix(c_vec);
00346 eigenvalues.FromEigenVector(c_val);
00347
00348
00349
00350
00351
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
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
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
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
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))
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
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
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() )
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
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
00563 A += ((s02 / tan(ang1)) + (s01 / tan(ang2))) / 8.0;
00564
00565
00566 v->Kg() -= ang0;
00567
00568
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
00606
00607
00608
00609
00610
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){
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
00703
00704
00705
00706
00707 float q =Distance(m.vert[i].P(),c) / maxRad;
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
00714
00715 m.vert[i].PD1() *= pd1Len;
00716 m.vert[i].PD2() *= pd2Len;
00717 }
00718 }
00719
00720 };
00721
00722 }
00723 }
00724 #endif