00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef __VCGLIB__SMOOTH
00026 #define __VCGLIB__SMOOTH
00027
00028 #include <vcg/space/ray3.h>
00029 #include <vcg/complex/algorithms/update/normal.h>
00030 #include <vcg/complex/algorithms/update/halfedge_topology.h>
00031 #include <vcg/complex/algorithms/closest.h>
00032 #include <vcg/space/index/kdtree/kdtree.h>
00033
00034
00035 namespace vcg
00036 {
00037 namespace tri
00038 {
00040
00042
00043
00044 template <class SmoothMeshType>
00045 class Smooth
00046 {
00047
00048 public:
00049 typedef SmoothMeshType MeshType;
00050 typedef typename MeshType::VertexType VertexType;
00051 typedef typename MeshType::VertexType::CoordType CoordType;
00052 typedef typename MeshType::VertexPointer VertexPointer;
00053 typedef typename MeshType::VertexIterator VertexIterator;
00054 typedef typename MeshType::ScalarType ScalarType;
00055 typedef typename MeshType::FaceType FaceType;
00056 typedef typename MeshType::FacePointer FacePointer;
00057 typedef typename MeshType::FaceIterator FaceIterator;
00058 typedef typename MeshType::FaceContainer FaceContainer;
00059 typedef typename vcg::Box3<ScalarType> Box3Type;
00060 typedef typename vcg::face::VFIterator<FaceType> VFLocalIterator;
00061
00062 class ScaleLaplacianInfo
00063 {
00064 public:
00065 CoordType PntSum;
00066 ScalarType LenSum;
00067 };
00068
00069
00070
00071
00072 void VertexCoordLaplacianCurvatureFlow(MeshType &, int , ScalarType )
00073 {
00074
00075 }
00076
00077
00078
00079
00080 static void VertexCoordLaplacianAngleWeighted(MeshType &m, int step, ScalarType delta)
00081 {
00082 ScaleLaplacianInfo lpz;
00083 lpz.PntSum=CoordType(0,0,0);
00084 lpz.LenSum=0;
00085 SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert,lpz);
00086 FaceIterator fi;
00087 for(int i=0;i<step;++i)
00088 {
00089 VertexIterator vi;
00090 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00091 TD[*vi]=lpz;
00092 ScalarType a[3];
00093 for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
00094 {
00095 CoordType mp=((*fi).V(0)->P() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0;
00096 CoordType e0=((*fi).V(0)->P() - (*fi).V(1)->P()).Normalize();
00097 CoordType e1=((*fi).V(1)->P() - (*fi).V(2)->P()).Normalize();
00098 CoordType e2=((*fi).V(2)->P() - (*fi).V(0)->P()).Normalize();
00099
00100 a[0]=AngleN(-e0,e2);
00101 a[1]=AngleN(-e1,e0);
00102 a[2]=AngleN(-e2,e1);
00103
00104
00105 for(int j=0;j<3;++j){
00106 CoordType dir= (mp-(*fi).V(j)->P()).Normalize();
00107 TD[(*fi).V(j)].PntSum+=dir*a[j];
00108 TD[(*fi).V(j)].LenSum+=a[j];
00109 }
00110 }
00111 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00112 if(!(*vi).IsD() && TD[*vi].LenSum>0 )
00113 (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum ) * delta;
00114
00115 }
00116 };
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128 static void VertexCoordScaleDependentLaplacian_Fujiwara(MeshType &m, int step, ScalarType delta)
00129 {
00130 SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert);
00131 ScaleLaplacianInfo lpz;
00132 lpz.PntSum=CoordType(0,0,0);
00133 lpz.LenSum=0;
00134 FaceIterator fi;
00135 for(int i=0;i<step;++i)
00136 {
00137 VertexIterator vi;
00138 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00139 TD[*vi]=lpz;
00140
00141 for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
00142 for(int j=0;j<3;++j)
00143 if(!(*fi).IsB(j)) {
00144 CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
00145 ScalarType len=Norm(edge);
00146 edge/=len;
00147 TD[(*fi).V(j)].PntSum+=edge;
00148 TD[(*fi).V1(j)].PntSum-=edge;
00149 TD[(*fi).V(j)].LenSum+=len;
00150 TD[(*fi).V1(j)].LenSum+=len;
00151 }
00152
00153 for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
00154 for(int j=0;j<3;++j)
00155
00156 if((*fi).IsB(j)) {
00157 TD[(*fi).V(j)].PntSum=CoordType(0,0,0);
00158 TD[(*fi).V1(j)].PntSum=CoordType(0,0,0);
00159 TD[(*fi).V(j)].LenSum=0;
00160 TD[(*fi).V1(j)].LenSum=0;
00161 }
00162
00163
00164 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00165 for(int j=0;j<3;++j)
00166 if((*fi).IsB(j))
00167 {
00168 CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
00169 ScalarType len=Norm(edge);
00170 edge/=len;
00171 TD[(*fi).V(j)].PntSum+=edge;
00172 TD[(*fi).V1(j)].PntSum-=edge;
00173 TD[(*fi).V(j)].LenSum+=len;
00174 TD[(*fi).V1(j)].LenSum+=len;
00175 }
00176
00177
00178
00179
00180
00181
00182 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00183 if(!(*vi).IsD() && TD[*vi].LenSum>0 )
00184 (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum)*delta;
00185 }
00186 };
00187
00188
00189 class LaplacianInfo
00190 {
00191 public:
00192 LaplacianInfo(const CoordType &_p, const int _n):sum(_p),cnt(_n) {}
00193 LaplacianInfo() {}
00194 CoordType sum;
00195 ScalarType cnt;
00196 };
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 static void AccumulateLaplacianInfo(MeshType &m, SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > &TD, bool cotangentFlag=false)
00210 {
00211 float weight =1.0f;
00212 FaceIterator fi;
00213 for(fi=m.face.begin();fi!=m.face.end();++fi)
00214 {
00215 if(!(*fi).IsD())
00216 for(int j=0;j<3;++j)
00217 if(!(*fi).IsB(j))
00218 {
00219 if(cotangentFlag) {
00220 float angle = Angle(fi->P1(j)-fi->P2(j),fi->P0(j)-fi->P2(j));
00221 weight = tan((M_PI*0.5) - angle);
00222 }
00223
00224 TD[(*fi).V0(j)].sum+=(*fi).P1(j)*weight;
00225 TD[(*fi).V1(j)].sum+=(*fi).P0(j)*weight;
00226 TD[(*fi).V0(j)].cnt+=weight;
00227 TD[(*fi).V1(j)].cnt+=weight;
00228 }
00229 }
00230
00231 for(fi=m.face.begin();fi!=m.face.end();++fi)
00232 {
00233 if(!(*fi).IsD())
00234 for(int j=0;j<3;++j)
00235 if((*fi).IsB(j))
00236 {
00237 TD[(*fi).V0(j)].sum=(*fi).P0(j);
00238 TD[(*fi).V1(j)].sum=(*fi).P1(j);
00239 TD[(*fi).V0(j)].cnt=1;
00240 TD[(*fi).V1(j)].cnt=1;
00241 }
00242 }
00243
00244
00245 for(fi=m.face.begin();fi!=m.face.end();++fi)
00246 {
00247 if(!(*fi).IsD())
00248 for(int j=0;j<3;++j)
00249 if((*fi).IsB(j))
00250 {
00251 TD[(*fi).V(j)].sum+=(*fi).V1(j)->P();
00252 TD[(*fi).V1(j)].sum+=(*fi).V(j)->P();
00253 ++TD[(*fi).V(j)].cnt;
00254 ++TD[(*fi).V1(j)].cnt;
00255 }
00256 }
00257 }
00258
00259 static void VertexCoordLaplacian(MeshType &m, int step, bool SmoothSelected=false, bool cotangentWeight=false, vcg::CallBackPos * cb=0)
00260 {
00261 VertexIterator vi;
00262 LaplacianInfo lpz(CoordType(0,0,0),0);
00263 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00264 for(int i=0;i<step;++i)
00265 {
00266 if(cb)cb(100*i/step, "Classic Laplacian Smoothing");
00267 TD.Init(lpz);
00268 AccumulateLaplacianInfo(m,TD,cotangentWeight);
00269 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00270 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00271 {
00272 if(!SmoothSelected || (*vi).IsS())
00273 (*vi).P() = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1);
00274 }
00275 }
00276 }
00277
00278
00279 static void VertexCoordPlanarLaplacian(MeshType &m, int step, float AngleThrRad = math::ToRad(1.0), bool SmoothSelected=false, vcg::CallBackPos * cb=0)
00280 {
00281 VertexIterator vi;
00282 FaceIterator fi;
00283 LaplacianInfo lpz(CoordType(0,0,0),0);
00284 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00285 for(int i=0;i<step;++i)
00286 {
00287 if(cb)cb(100*i/step, "Planar Laplacian Smoothing");
00288 TD.Init(lpz);
00289 AccumulateLaplacianInfo(m,TD);
00290 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00291 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00292 {
00293 if(!SmoothSelected || (*vi).IsS())
00294 TD[*vi].sum = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1);
00295 }
00296
00297 for(fi=m.face.begin();fi!=m.face.end();++fi){
00298 if(!(*fi).IsD()){
00299 for (int j = 0; j < 3; ++j) {
00300 if(Angle( Normal(TD[(*fi).V0(j)].sum, (*fi).P1(j), (*fi).P2(j) ),
00301 Normal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad )
00302 TD[(*fi).V0(j)].sum = (*fi).P0(j);
00303 }
00304 }
00305 }
00306 for(fi=m.face.begin();fi!=m.face.end();++fi){
00307 if(!(*fi).IsD()){
00308 for (int j = 0; j < 3; ++j) {
00309 if(Angle( Normal(TD[(*fi).V0(j)].sum, TD[(*fi).V1(j)].sum, (*fi).P2(j) ),
00310 Normal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad )
00311 {
00312 TD[(*fi).V0(j)].sum = (*fi).P0(j);
00313 TD[(*fi).V1(j)].sum = (*fi).P1(j);
00314 }
00315 }
00316 }
00317 }
00318
00319 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00320 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00321 (*vi).P()= TD[*vi].sum;
00322
00323
00324
00325 }
00326
00327
00328 }
00329
00330 static void VertexCoordLaplacianBlend(MeshType &m, int step, float alpha, bool SmoothSelected=false)
00331 {
00332 VertexIterator vi;
00333 LaplacianInfo lpz(CoordType(0,0,0),0);
00334 assert (alpha<= 1.0);
00335 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert);
00336
00337 for(int i=0;i<step;++i)
00338 {
00339 TD.Init(lpz);
00340 AccumulateLaplacianInfo(m,TD);
00341 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00342 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00343 {
00344 if(!SmoothSelected || (*vi).IsS())
00345 {
00346 CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
00347 (*vi).P() = (*vi).P() + Delta*alpha;
00348 }
00349 }
00350 }
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371 static void VertexCoordTaubin(MeshType &m, int step, float lambda, float mu, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
00372 {
00373 LaplacianInfo lpz(CoordType(0,0,0),0);
00374 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00375 VertexIterator vi;
00376 for(int i=0;i<step;++i)
00377 {
00378 if(cb) cb(100*i/step, "Taubin Smoothing");
00379 TD.Init(lpz);
00380 AccumulateLaplacianInfo(m,TD);
00381 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00382 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00383 {
00384 if(!SmoothSelected || (*vi).IsS())
00385 {
00386 CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
00387 (*vi).P() = (*vi).P() + Delta*lambda ;
00388 }
00389 }
00390 TD.Init(lpz);
00391 AccumulateLaplacianInfo(m,TD);
00392 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00393 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00394 {
00395 if(!SmoothSelected || (*vi).IsS())
00396 {
00397 CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
00398 (*vi).P() = (*vi).P() + Delta*mu ;
00399 }
00400 }
00401 }
00402 }
00403
00404
00405 static void VertexCoordLaplacianQuality(MeshType &m, int step, bool SmoothSelected=false)
00406 {
00407 LaplacianInfo lpz;
00408 lpz.sum=CoordType(0,0,0);
00409 lpz.cnt=1;
00410 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00411 for(int i=0;i<step;++i)
00412 {
00413 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
00414 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00415 if(!SmoothSelected || (*vi).IsS())
00416 {
00417 float q=(*vi).Q();
00418 (*vi).P()=(*vi).P()*q + (TD[*vi].sum/TD[*vi].cnt)*(1.0-q);
00419 }
00420 }
00421 };
00422
00423
00424
00425
00426
00427
00428
00429 class HCSmoothInfo
00430 {
00431 public:
00432 CoordType dif;
00433 CoordType sum;
00434 int cnt;
00435 };
00436
00437 static void VertexCoordLaplacianHC(MeshType &m, int step, bool SmoothSelected=false )
00438 {
00439 ScalarType beta=0.5;
00440 HCSmoothInfo lpz;
00441 lpz.sum=CoordType(0,0,0);
00442 lpz.dif=CoordType(0,0,0);
00443 lpz.cnt=0;
00444 for(int i=0;i<step;++i)
00445 {
00446 SimpleTempData<typename MeshType::VertContainer,HCSmoothInfo > TD(m.vert,lpz);
00447
00448 FaceIterator fi;
00449 for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
00450 {
00451 for(int j=0;j<3;++j)
00452 {
00453 TD[(*fi).V(j)].sum+=(*fi).V1(j)->P();
00454 TD[(*fi).V1(j)].sum+=(*fi).V(j)->P();
00455 ++TD[(*fi).V(j)].cnt;
00456 ++TD[(*fi).V1(j)].cnt;
00457
00458 if((*fi).IsB(j))
00459 {
00460 TD[(*fi).V(j)].sum+=(*fi).V1(j)->P();
00461 TD[(*fi).V1(j)].sum+=(*fi).V(j)->P();
00462 ++TD[(*fi).V(j)].cnt;
00463 ++TD[(*fi).V1(j)].cnt;
00464 }
00465 }
00466 }
00467 VertexIterator vi;
00468 for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
00469 TD[*vi].sum/=(float)TD[*vi].cnt;
00470
00471
00472 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00473 {
00474 for(int j=0;j<3;++j)
00475 {
00476 TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P();
00477 TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P();
00478
00479 if((*fi).IsB(j))
00480 {
00481 TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P();
00482 TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P();
00483 }
00484 }
00485 }
00486
00487 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00488 {
00489 TD[*vi].dif/=(float)TD[*vi].cnt;
00490 if(!SmoothSelected || (*vi).IsS())
00491 (*vi).P()= TD[*vi].sum - (TD[*vi].sum - (*vi).P())*beta + (TD[*vi].dif)*(1.f-beta);
00492 }
00493 }
00494 };
00495
00496
00497
00498
00499 class ColorSmoothInfo
00500 {
00501 public:
00502 unsigned int r;
00503 unsigned int g;
00504 unsigned int b;
00505 unsigned int a;
00506 int cnt;
00507 };
00508
00509 static void VertexColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
00510 {
00511 ColorSmoothInfo csi;
00512 csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
00513 SimpleTempData<typename MeshType::VertContainer, ColorSmoothInfo> TD(m.vert,csi);
00514
00515 for(int i=0;i<step;++i)
00516 {
00517 if(cb) cb(100*i/step, "Vertex Color Laplacian Smoothing");
00518 VertexIterator vi;
00519 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00520 TD[*vi]=csi;
00521
00522 FaceIterator fi;
00523 for(fi=m.face.begin();fi!=m.face.end();++fi)
00524 if(!(*fi).IsD())
00525 for(int j=0;j<3;++j)
00526 if(!(*fi).IsB(j))
00527 {
00528 TD[(*fi).V(j)].r+=(*fi).V1(j)->C()[0];
00529 TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1];
00530 TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2];
00531 TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3];
00532
00533 TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0];
00534 TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1];
00535 TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2];
00536 TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3];
00537
00538 ++TD[(*fi).V(j)].cnt;
00539 ++TD[(*fi).V1(j)].cnt;
00540 }
00541
00542
00543 for(fi=m.face.begin();fi!=m.face.end();++fi)
00544 if(!(*fi).IsD())
00545 for(int j=0;j<3;++j)
00546 if((*fi).IsB(j))
00547 {
00548 TD[(*fi).V(j)]=csi;
00549 TD[(*fi).V1(j)]=csi;
00550 }
00551
00552
00553 for(fi=m.face.begin();fi!=m.face.end();++fi)
00554 if(!(*fi).IsD())
00555 for(int j=0;j<3;++j)
00556 if((*fi).IsB(j))
00557 {
00558 TD[(*fi).V(j)].r+=(*fi).V1(j)->C()[0];
00559 TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1];
00560 TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2];
00561 TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3];
00562
00563 TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0];
00564 TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1];
00565 TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2];
00566 TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3];
00567
00568 ++TD[(*fi).V(j)].cnt;
00569 ++TD[(*fi).V1(j)].cnt;
00570 }
00571
00572 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00573 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00574 if(!SmoothSelected || (*vi).IsS())
00575 {
00576 (*vi).C()[0] = (unsigned int) ceil((double) (TD[*vi].r / TD[*vi].cnt));
00577 (*vi).C()[1] = (unsigned int) ceil((double) (TD[*vi].g / TD[*vi].cnt));
00578 (*vi).C()[2] = (unsigned int) ceil((double) (TD[*vi].b / TD[*vi].cnt));
00579 (*vi).C()[3] = (unsigned int) ceil((double) (TD[*vi].a / TD[*vi].cnt));
00580 }
00581 }
00582 };
00583
00584 static void FaceColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
00585 {
00586 ColorSmoothInfo csi;
00587 csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
00588 SimpleTempData<typename MeshType::FaceContainer, ColorSmoothInfo> TD(m.face,csi);
00589
00590 for(int i=0;i<step;++i)
00591 {
00592 if(cb) cb(100*i/step, "Face Color Laplacian Smoothing");
00593 FaceIterator fi;
00594 for(fi=m.face.begin();fi!=m.face.end();++fi)
00595 TD[*fi]=csi;
00596
00597 for(fi=m.face.begin();fi!=m.face.end();++fi)
00598 {
00599 if(!(*fi).IsD())
00600 for(int j=0;j<3;++j)
00601 if(!(*fi).IsB(j))
00602 {
00603 TD[*fi].r+=(*fi).FFp(j)->C()[0];
00604 TD[*fi].g+=(*fi).FFp(j)->C()[1];
00605 TD[*fi].b+=(*fi).FFp(j)->C()[2];
00606 TD[*fi].a+=(*fi).FFp(j)->C()[3];
00607 ++TD[*fi].cnt;
00608 }
00609 }
00610 for(fi=m.face.begin();fi!=m.face.end();++fi)
00611 if(!(*fi).IsD() && TD[*fi].cnt>0 )
00612 if(!SmoothSelected || (*fi).IsS())
00613 {
00614 (*fi).C()[0] = (unsigned int) ceil((float) (TD[*fi].r / TD[*fi].cnt));
00615 (*fi).C()[1] = (unsigned int) ceil((float) (TD[*fi].g / TD[*fi].cnt));
00616 (*fi).C()[2] = (unsigned int) ceil((float) (TD[*fi].b / TD[*fi].cnt));
00617 (*fi).C()[3] = (unsigned int) ceil((float) (TD[*fi].a / TD[*fi].cnt));
00618 }
00619 }
00620 };
00621
00622
00623
00624 class QualitySmoothInfo
00625 {
00626 public:
00627 ScalarType sum;
00628 int cnt;
00629 };
00630
00631 static void PointCloudQualityAverage(MeshType &m, int neighbourSize=8, int iter=1)
00632 {
00633 tri::RequireCompactness(m);
00634 VertexConstDataWrapper<MeshType> ww(m);
00635 KdTree<ScalarType> kt(ww);
00636 typename KdTree<ScalarType>::PriorityQueue pq;
00637 for(int k=0;k<iter;++k)
00638 {
00639 std::vector<ScalarType> newQVec(m.vn);
00640 for(int i=0;i<m.vn;++i)
00641 {
00642 kt.doQueryK(m.vert[i].P(),neighbourSize,pq);
00643 float qAvg=0;
00644 for(int j=0;j<pq.getNofElements();++j)
00645 qAvg+= m.vert[pq.getIndex(j)].Q();
00646 newQVec[i]=qAvg/float(pq.getNofElements());
00647 }
00648
00649 for(int i=0;i<m.vn;++i)
00650 m.vert[i].Q() = newQVec[i];
00651 }
00652 }
00653
00654 static void PointCloudQualityMedian(MeshType &m, int medianSize=8)
00655 {
00656 tri::RequireCompactness(m);
00657 VertexConstDataWrapper<MeshType> ww(m);
00658 KdTree<ScalarType> kt(ww);
00659 typename KdTree<ScalarType>::PriorityQueue pq;
00660 std::vector<ScalarType> newQVec(m.vn);
00661 for(int i=0;i<m.vn;++i)
00662 {
00663 kt.doQueryK(m.vert[i].P(),medianSize,pq);
00664 std::vector<ScalarType> qVec(pq.getNofElements());
00665 for(int j=0;j<pq.getNofElements();++j)
00666 qVec[j]=m.vert[pq.getIndex(j)].Q();
00667 std::sort(qVec.begin(),qVec.end());
00668 newQVec[i]=qVec[qVec.size()/2];
00669 }
00670
00671 for(int i=0;i<m.vn;++i)
00672 m.vert[i].Q() = newQVec[i];
00673
00674 }
00675
00676 static void VertexQualityLaplacian(MeshType &m, int step=1, bool SmoothSelected=false)
00677 {
00678 QualitySmoothInfo lpz;
00679 lpz.sum=0;
00680 lpz.cnt=0;
00681 SimpleTempData<typename MeshType::VertContainer,QualitySmoothInfo> TD(m.vert,lpz);
00682
00683 for(int i=0;i<step;++i)
00684 {
00685 VertexIterator vi;
00686 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00687 TD[*vi]=lpz;
00688
00689 FaceIterator fi;
00690 for(fi=m.face.begin();fi!=m.face.end();++fi)
00691 if(!(*fi).IsD())
00692 for(int j=0;j<3;++j)
00693 if(!(*fi).IsB(j))
00694 {
00695 TD[(*fi).V(j)].sum+=(*fi).V1(j)->Q();
00696 TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q();
00697 ++TD[(*fi).V(j)].cnt;
00698 ++TD[(*fi).V1(j)].cnt;
00699 }
00700
00701
00702 for(fi=m.face.begin();fi!=m.face.end();++fi)
00703 if(!(*fi).IsD())
00704 for(int j=0;j<3;++j)
00705 if((*fi).IsB(j))
00706 {
00707 TD[(*fi).V(j)]=lpz;
00708 TD[(*fi).V1(j)]=lpz;
00709 }
00710
00711
00712 for(fi=m.face.begin();fi!=m.face.end();++fi)
00713 if(!(*fi).IsD())
00714 for(int j=0;j<3;++j)
00715 if((*fi).IsB(j))
00716 {
00717 TD[(*fi).V(j)].sum+=(*fi).V1(j)->Q();
00718 TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q();
00719 ++TD[(*fi).V(j)].cnt;
00720 ++TD[(*fi).V1(j)].cnt;
00721 }
00722
00723
00724 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00725 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00726 if(!SmoothSelected || (*vi).IsS())
00727 (*vi).Q()=TD[*vi].sum/TD[*vi].cnt;
00728 }
00729
00730
00731 };
00732
00733 static void VertexNormalLaplacian(MeshType &m, int step,bool SmoothSelected=false)
00734 {
00735 LaplacianInfo lpz;
00736 lpz.sum=CoordType(0,0,0);
00737 lpz.cnt=0;
00738 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00739 for(int i=0;i<step;++i)
00740 {
00741 VertexIterator vi;
00742 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00743 TD[*vi]=lpz;
00744
00745 FaceIterator fi;
00746 for(fi=m.face.begin();fi!=m.face.end();++fi)
00747 if(!(*fi).IsD())
00748 for(int j=0;j<3;++j)
00749 if(!(*fi).IsB(j))
00750 {
00751 TD[(*fi).V(j)].sum+=(*fi).V1(j)->N();
00752 TD[(*fi).V1(j)].sum+=(*fi).V(j)->N();
00753 ++TD[(*fi).V(j)].cnt;
00754 ++TD[(*fi).V1(j)].cnt;
00755 }
00756
00757
00758 for(fi=m.face.begin();fi!=m.face.end();++fi)
00759 if(!(*fi).IsD())
00760 for(int j=0;j<3;++j)
00761 if((*fi).IsB(j))
00762 {
00763 TD[(*fi).V(j)]=lpz;
00764 TD[(*fi).V1(j)]=lpz;
00765 }
00766
00767
00768 for(fi=m.face.begin();fi!=m.face.end();++fi)
00769 if(!(*fi).IsD())
00770 for(int j=0;j<3;++j)
00771 if((*fi).IsB(j))
00772 {
00773 TD[(*fi).V(j)].sum+=(*fi).V1(j)->N();
00774 TD[(*fi).V1(j)].sum+=(*fi).V(j)->N();
00775 ++TD[(*fi).V(j)].cnt;
00776 ++TD[(*fi).V1(j)].cnt;
00777 }
00778
00779
00780 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00781 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00782 if(!SmoothSelected || (*vi).IsS())
00783 (*vi).N()=TD[*vi].sum/TD[*vi].cnt;
00784 }
00785
00786 };
00787
00788
00789
00790
00791 static void VertexCoordViewDepth(MeshType &m,
00792 const CoordType & viewpoint,
00793 const ScalarType alpha,
00794 int step, bool SmoothBorder=false )
00795 {
00796 LaplacianInfo lpz;
00797 lpz.sum=CoordType(0,0,0);
00798 lpz.cnt=0;
00799 SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
00800 for(int i=0;i<step;++i)
00801 {
00802 VertexIterator vi;
00803 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00804 TD[*vi]=lpz;
00805
00806 FaceIterator fi;
00807 for(fi=m.face.begin();fi!=m.face.end();++fi)
00808 if(!(*fi).IsD())
00809 for(int j=0;j<3;++j)
00810 if(!(*fi).IsB(j))
00811 {
00812 TD[(*fi).V(j)].sum+=(*fi).V1(j)->cP();
00813 TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP();
00814 ++TD[(*fi).V(j)].cnt;
00815 ++TD[(*fi).V1(j)].cnt;
00816 }
00817
00818
00819 for(fi=m.face.begin();fi!=m.face.end();++fi)
00820 if(!(*fi).IsD())
00821 for(int j=0;j<3;++j)
00822 if((*fi).IsB(j))
00823 {
00824 TD[(*fi).V(j)]=lpz;
00825 TD[(*fi).V1(j)]=lpz;
00826 }
00827
00828
00829 if(SmoothBorder)
00830 for(fi=m.face.begin();fi!=m.face.end();++fi)
00831 if(!(*fi).IsD())
00832 for(int j=0;j<3;++j)
00833 if((*fi).IsB(j))
00834 {
00835 TD[(*fi).V(j)].sum+=(*fi).V1(j)->cP();
00836 TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP();
00837 ++TD[(*fi).V(j)].cnt;
00838 ++TD[(*fi).V1(j)].cnt;
00839 }
00840
00841 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
00842 if(!(*vi).IsD() && TD[*vi].cnt>0 )
00843 {
00844 CoordType np = TD[*vi].sum/TD[*vi].cnt;
00845 CoordType d = (*vi).cP() - viewpoint; d.Normalize();
00846 ScalarType s = d .dot ( np - (*vi).cP() );
00847 (*vi).P() += d * (s*alpha);
00848 }
00849 }
00850 }
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867 class PDVertInfo
00868 {
00869 public:
00870 CoordType np;
00871 };
00872
00873
00874 class PDFaceInfo
00875 {
00876 public:
00877 PDFaceInfo(){}
00878 PDFaceInfo(const CoordType &_m):m(_m){}
00879 CoordType m;
00880 };
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892 void FaceNormalFuzzyVectorSB(MeshType &m,
00893 SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo > &TD,
00894 ScalarType sigma)
00895 {
00896 int i;
00897
00898 FaceIterator fi;
00899
00900 for(fi=m.face.begin();fi!=m.face.end();++fi)
00901 {
00902 CoordType bc=(*fi).Barycenter();
00903
00904 for(i=0;i<3;++i)
00905 {
00906 vcg::face::VFIterator<FaceType> ep(&*fi,i);
00907 while (!ep.End())
00908 {
00909 ep.f->ClearV();
00910 ++ep;
00911 }
00912 }
00913
00914
00915 (*fi).SetV();
00916 CoordType mm=CoordType(0,0,0);
00917 for(i=0;i<3;++i)
00918 {
00919 vcg::face::VFIterator<FaceType> ep(&*fi,i);
00920 while (!ep.End())
00921 {
00922 if(! (*ep.f).IsV() )
00923 {
00924 if(sigma>0)
00925 {
00926 ScalarType dd=SquaredDistance(ep.f->Barycenter(),bc);
00927 ScalarType ang=AngleN(ep.f->N(),(*fi).N());
00928 mm+=ep.f->N()*exp((-sigma)*ang*ang/dd);
00929 }
00930 else mm+=ep.f->N();
00931 (*ep.f).SetV();
00932 }
00933 ++ep;
00934 }
00935 }
00936 mm.Normalize();
00937 TD[*fi].m=mm;
00938 }
00939 }
00940
00941
00942
00943
00944
00945
00946 static void FaceNormalLaplacianVF(MeshType &m)
00947 {
00948 tri::RequireVFAdjacency(m);
00949 PDFaceInfo lpzf(CoordType(0,0,0));
00950 SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
00951
00952 tri::UpdateNormal<MeshType>::NormalizePerFaceByArea(m);
00953
00954 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
00955 {
00956
00957 for(int i=0;i<3;++i)
00958 {
00959 VFLocalIterator ep(&*fi,i);
00960 for (;!ep.End();++ep)
00961 ep.f->ClearV();
00962 }
00963
00964
00965 CoordType normalSum=(*fi).N();
00966
00967 for(int i=0;i<3;++i)
00968 {
00969 VFLocalIterator ep(&*fi,i);
00970 for (;!ep.End();++ep)
00971 {
00972 if(! (*ep.f).IsV() )
00973 {
00974 normalSum += ep.f->N();
00975 (*ep.f).SetV();
00976 }
00977 }
00978 }
00979 normalSum.Normalize();
00980 TDF[*fi].m=normalSum;
00981 }
00982 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
00983 (*fi).N()=TDF[*fi].m;
00984
00985 tri::UpdateNormal<MeshType>::NormalizePerFace(m);
00986 }
00987
00988
00989
00990
00991
00992
00993
00994
00995 static void FaceNormalLaplacianFF(MeshType &m, int step=1, bool SmoothSelected=false )
00996 {
00997 PDFaceInfo lpzf(CoordType(0,0,0));
00998 SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
00999 tri::RequireFFAdjacency(m);
01000
01001 FaceIterator fi;
01002 tri::UpdateNormal<MeshType>::NormalizePerFaceByArea(m);
01003 for(int iStep=0;iStep<step;++iStep)
01004 {
01005 for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
01006 {
01007 CoordType normalSum=(*fi).N();
01008
01009 for(int i=0;i<3;++i)
01010 normalSum+=(*fi).FFp(i)->N();
01011
01012 TDF[*fi].m=normalSum;
01013 }
01014 for(fi=m.face.begin();fi!=m.face.end();++fi)
01015 if(!SmoothSelected || (*fi).IsS())
01016 (*fi).N()=TDF[*fi].m;
01017
01018 tri::UpdateNormal<MeshType>::NormalizePerFace(m);
01019 }
01020 }
01021
01022
01023
01024
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037 static void FaceNormalAngleThreshold(MeshType &m,
01038 SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo> &TD,
01039 ScalarType sigma)
01040 {
01041 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
01042 {
01043
01044 for(int i=0;i<3;++i)
01045 {
01046 VFLocalIterator ep(&*fi,i);
01047 for (;!ep.End();++ep)
01048 ep.f->ClearV();
01049 }
01050
01051
01052
01053
01054
01055
01056
01057 CoordType normalSum=CoordType(0,0,0);
01058 for(int i=0;i<3;++i)
01059 {
01060 VFLocalIterator ep(&*fi,i);
01061 for (;!ep.End();++ep)
01062 {
01063 if(! (*ep.f).IsV() )
01064 {
01065 ScalarType cosang=ep.f->N().dot((*fi).N());
01066
01067
01068 cosang = math::Clamp(cosang,ScalarType(0.0001),ScalarType(1.f));
01069 if(cosang >= sigma)
01070 {
01071 ScalarType w = cosang-sigma;
01072 normalSum += ep.f->N()*(w*w);
01073 }
01074 (*ep.f).SetV();
01075 }
01076 }
01077 }
01078 normalSum.Normalize();
01079 TD[*fi].m=normalSum;
01080 }
01081
01082 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
01083 (*fi).N()=TD[*fi].m;
01084 }
01085
01086
01087
01088
01089
01090
01091 static CoordType TriAreaGradient(CoordType &p,CoordType &p0,CoordType &p1)
01092 {
01093 CoordType dd = p1-p0;
01094 CoordType d0 = p-p0;
01095 CoordType d1 = p-p1;
01096 CoordType grad;
01097
01098 ScalarType t16 = d0[1]* d1[2] - d0[2]* d1[1];
01099 ScalarType t5 = -d0[2]* d1[0] + d0[0]* d1[2];
01100 ScalarType t4 = -d0[0]* d1[1] + d0[1]* d1[0];
01101
01102 ScalarType delta= sqrtf(t4*t4 + t5*t5 +t16*t16);
01103
01104 grad[0]= (t5 * (-dd[2]) + t4 * ( dd[1]))/delta;
01105 grad[1]= (t16 * (-dd[2]) + t4 * (-dd[0]))/delta;
01106 grad[2]= (t16 * ( dd[1]) + t5 * ( dd[0]))/delta;
01107
01108 return grad;
01109 }
01110
01111 template <class ScalarType>
01112 static CoordType CrossProdGradient(CoordType &p, CoordType &p0, CoordType &p1, CoordType &m)
01113 {
01114 CoordType grad;
01115 CoordType p00=p0-p;
01116 CoordType p01=p1-p;
01117 grad[0] = (-p00[2] + p01[2])*m[1] + (-p01[1] + p00[1])*m[2];
01118 grad[1] = (-p01[2] + p00[2])*m[0] + (-p00[0] + p01[0])*m[2];
01119 grad[2] = (-p00[1] + p01[1])*m[0] + (-p01[0] + p00[0])*m[1];
01120
01121 return grad;
01122 }
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135 static CoordType FaceErrorGrad(CoordType &p,CoordType &p0,CoordType &p1, CoordType &m)
01136 {
01137 return TriAreaGradient(p,p0,p1) *2.0f
01138 - CrossProdGradient(p,p0,p1,m) *2.0f ;
01139 }
01140
01141
01142
01143
01144
01145 static void FitMesh(MeshType &m,
01146 SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
01147 SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
01148 float lambda)
01149 {
01150 vcg::face::VFIterator<FaceType> ep;
01151 VertexIterator vi;
01152 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
01153 {
01154 CoordType ErrGrad=CoordType(0,0,0);
01155
01156 ep.f=(*vi).VFp();
01157 ep.z=(*vi).VFi();
01158 while (!ep.End())
01159 {
01160 ErrGrad+=FaceErrorGrad(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P(),ep.f->V2(ep.z)->P(),TDF[ep.f].m);
01161 ++ep;
01162 }
01163 TDV[*vi].np=(*vi).P()-ErrGrad*(ScalarType)lambda;
01164 }
01165
01166 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
01167 (*vi).P()=TDV[*vi].np;
01168
01169 }
01170
01171
01172
01173
01174 static void FastFitMesh(MeshType &m,
01175 SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
01176
01177 bool OnlySelected=false)
01178 {
01179
01180 vcg::face::VFIterator<FaceType> ep;
01181 VertexIterator vi;
01182
01183 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
01184 {
01185 CoordType Sum(0,0,0);
01186 ScalarType cnt=0;
01187 VFLocalIterator ep(&*vi);
01188 for (;!ep.End();++ep)
01189 {
01190 CoordType bc=Barycenter<FaceType>(*ep.F());
01191 Sum += ep.F()->N()*(ep.F()->N().dot(bc - (*vi).P()));
01192 ++cnt;
01193 }
01194 TDV[*vi].np=(*vi).P()+ Sum*(1.0/cnt);
01195 }
01196
01197 if(OnlySelected)
01198 {
01199 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
01200 if((*vi).IsS()) (*vi).P()=TDV[*vi].np;
01201 }
01202 else
01203 {
01204 for(vi=m.vert.begin();vi!=m.vert.end();++vi)
01205 (*vi).P()=TDV[*vi].np;
01206 }
01207 }
01208
01209
01210
01211
01212
01213 static void VertexCoordPasoDoble(MeshType &m, int NormalSmoothStep, typename MeshType::ScalarType Sigma=0, int FitStep=50, bool SmoothSelected =false)
01214 {
01215 tri::RequireCompactness(m);
01216 tri::RequireVFAdjacency(m);
01217 PDVertInfo lpzv;
01218 lpzv.np=CoordType(0,0,0);
01219 PDFaceInfo lpzf(CoordType(0,0,0));
01220
01221 assert(HasPerVertexVFAdjacency(m) && HasPerFaceVFAdjacency(m));
01222 SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert,lpzv);
01223 SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
01224
01225 for(int j=0;j<NormalSmoothStep;++j)
01226 FaceNormalAngleThreshold(m,TDF,Sigma);
01227
01228 for(int j=0;j<FitStep;++j)
01229 FastFitMesh(m,TDV,SmoothSelected);
01230 }
01231
01232
01233 static void VertexNormalPointCloud(MeshType &m, int neighborNum, int iterNum, KdTree<ScalarType> *tp=0)
01234 {
01235 SimpleTempData<typename MeshType::VertContainer,CoordType > TD(m.vert,CoordType(0,0,0));
01236 VertexConstDataWrapper<MeshType> ww(m);
01237 KdTree<ScalarType> *tree=0;
01238 if(tp==0) tree = new KdTree<ScalarType>(ww);
01239 else tree=tp;
01240 typename KdTree<ScalarType>::PriorityQueue nq;
01241
01242
01243 for(int ii=0;ii<iterNum;++ii)
01244 {
01245 for (VertexIterator vi = m.vert.begin();vi!=m.vert.end();++vi)
01246 {
01247 tree->doQueryK(vi->cP(),neighborNum,nq);
01248 int neighbours = nq.getNofElements();
01249 for (int i = 0; i < neighbours; i++)
01250 {
01251 int neightId = nq.getIndex(i);
01252 if(m.vert[neightId].cN()*vi->cN()>0)
01253 TD[vi]+= m.vert[neightId].cN();
01254 else
01255 TD[vi]-= m.vert[neightId].cN();
01256 }
01257 }
01258 for (VertexIterator vi = m.vert.begin();vi!=m.vert.end();++vi)
01259 {
01260 vi->N()=TD[vi];
01261 TD[vi]=CoordType(0,0,0);
01262 }
01263 tri::UpdateNormal<MeshType>::NormalizePerVertex(m);
01264 }
01265
01266 if(tp==0) delete tree;
01267 }
01268
01270
01271 template<class GRID, class MeshTypeTri>
01272 static void VertexCoordLaplacianReproject(MeshType& m, GRID& grid, MeshTypeTri& gridmesh)
01273 {
01274 for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
01275 {
01276 if(! (*vi).IsD())
01277 VertexCoordLaplacianReproject(m,grid,gridmesh,&*vi);
01278 }
01279 }
01280
01281
01282 template<class GRID, class MeshTypeTri>
01283 static void VertexCoordLaplacianReproject(MeshType& m, GRID& grid, MeshTypeTri& gridmesh, typename MeshType::VertexType* vp)
01284 {
01285 assert(MeshType::HEdgeType::HasHVAdjacency());
01286
01287
01288 typedef std::vector<VertexPointer> VertexSet;
01289 VertexSet verts;
01290 verts = HalfEdgeTopology<MeshType>::getVertices(vp);
01291
01292 typename MeshType::CoordType ct(0,0,0);
01293 for(typename VertexSet::iterator it = verts.begin(); it != verts.end(); ++it)
01294 {
01295 ct += (*it)->P();
01296 }
01297 ct /= verts.size();
01298
01299
01300 vp->P() = ct;
01301
01302
01303 vector<FacePointer> faces2 = HalfEdgeTopology<MeshType>::get_incident_faces(vp);
01304
01305
01306 typename MeshType::CoordType avgn(0,0,0);
01307
01308 for(unsigned int i = 0;i< faces2.size();i++)
01309 if(faces2[i])
01310 {
01311 vector<VertexPointer> vertices = HalfEdgeTopology<MeshType>::getVertices(faces2[i]);
01312
01313 assert(vertices.size() == 4);
01314
01315 avgn += vcg::Normal<typename MeshType::CoordType>(vertices[0]->cP(), vertices[1]->cP(), vertices[2]->cP());
01316 avgn += vcg::Normal<typename MeshType::CoordType>(vertices[2]->cP(), vertices[3]->cP(), vertices[0]->cP());
01317
01318 }
01319 avgn.Normalize();
01320
01321
01322 ScalarType diag = m.bbox.Diag();
01323 typename MeshType::CoordType raydir = avgn;
01324 Ray3<typename MeshType::ScalarType> ray;
01325
01326 ray.SetOrigin(vp->P());
01327 ScalarType t;
01328 typename MeshTypeTri::FaceType* f = 0;
01329 typename MeshTypeTri::FaceType* fr = 0;
01330
01331 vector<typename MeshTypeTri::CoordType> closests;
01332 vector<typename MeshTypeTri::ScalarType> minDists;
01333 vector<typename MeshTypeTri::FaceType*> faces;
01334 ray.SetDirection(-raydir);
01335 f = vcg::tri::DoRay<MeshTypeTri,GRID>(gridmesh, grid, ray, diag/4.0, t);
01336
01337 if (f)
01338 {
01339 closests.push_back(ray.Origin() + ray.Direction()*t);
01340 minDists.push_back(fabs(t));
01341 faces.push_back(f);
01342 }
01343 ray.SetDirection(raydir);
01344 fr = vcg::tri::DoRay<MeshTypeTri,GRID>(gridmesh, grid, ray, diag/4.0, t);
01345 if (fr)
01346 {
01347 closests.push_back(ray.Origin() + ray.Direction()*t);
01348 minDists.push_back(fabs(t));
01349 faces.push_back(fr);
01350 }
01351
01352 if (fr) if (fr->N()*raydir<0) fr=0;
01353 typename MeshType::CoordType newPos;
01354 if (minDists.size() == 0)
01355 {
01356 newPos = vp->P();
01357 f = 0;
01358 }
01359 else
01360 {
01361 int minI = std::min_element(minDists.begin(),minDists.end()) - minDists.begin();
01362 newPos = closests[minI];
01363 f = faces[minI];
01364 }
01365
01366 if (f)
01367 vp->P() = newPos;
01368 }
01369
01370 };
01371
01372 }
01373 }
01374
01375 #endif // VCG_SMOOTH