smooth.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 
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 // This is precisely what curvature flow does.
00070 // Curvature flow smoothes the surface by moving along the surface
00071 // normal n with a speed equal to the mean curvature
00072 void VertexCoordLaplacianCurvatureFlow(MeshType &/*m*/, int /*step*/, ScalarType /*delta*/)
00073 {
00074 
00075 }
00076 
00077 // Another Laplacian smoothing variant,
00078 // here we sum the baricenter of the faces incidents on each vertex weighting them with the angle
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             //assert(fabs(M_PI -a[0] -a[1] -a[2])<0.0000001);
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]; // well, it should be named angleSum
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 // Scale dependent laplacian smoothing [Fujiwara 95]
00119 // as described in
00120 // Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow
00121 // Mathieu Desbrun, Mark Meyer, Peter Schroeder, Alan H. Barr
00122 // SIGGRAPH 99
00123 // REQUIREMENTS: Border Flags.
00124 //
00125 // Note the delta parameter is in a absolute unit
00126 // to get stability it should be a small percentage of the shortest edge.
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                     // se l'edge j e' di bordo si riazzera tutto e si riparte
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   // The fundamental part:
00177     // We move the new point of a quantity
00178     //
00179     //  L(M) = 1/Sum(edgelen) * Sum(Normalized edges)
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 // Classical Laplacian Smoothing. Each vertex can be moved onto the average of the adjacent vertices.
00199 // Can smooth only the selected vertices and weight the smoothing according to the quality
00200 // In the latter case 0 means that the vertex is not moved and 1 means that the vertex is moved onto the computed position.
00201 //
00202 // From the Taubin definition "A signal proc approach to fair surface design"
00203 // We define the discrete Laplacian of a discrete surface signal by weighted averages over the neighborhoods
00204 //          \delta xi  = \Sum wij (xj - xi) ;
00205 // where xj are the adjacent vertices of xi and wij is usually 1/n_adj
00206 //
00207 // This function simply accumulate over a TempData all the positions of the ajacent vertices
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             // si azzaera i dati per i vertici di bordo
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             // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
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 // Same of above but moves only the vertices that do not change FaceOrientation more that the given threshold
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         }// end step
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 /* a couple of notes about the lambda mu values
00354 We assume that 0 < lambda , and mu  is a negative scale factor such that mu < - lambda.
00355 Holds mu+lambda < 0 (e.g in absolute value mu is greater)
00356 
00357 let kpb be the pass-band frequency, taubin says that:
00358             kpb = 1/lambda + 1/mu >0
00359 
00360 Values of kpb from 0.01 to 0.1 produce good results according to the original paper.
00361 
00362 kpb * mu - mu/lambda = 1
00363 mu = 1/(kpb-1/lambda )
00364 
00365 So if
00366 * lambda == 0.5, kpb==0.1  -> mu = 1/(0.1 - 2)  = -0.526
00367 * lambda == 0.5, kpb==0.01 -> mu = 1/(0.01 - 2) = -0.502
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             } // end for step
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         } // end for
00421 };
00422 
00423 /*
00424   Improved Laplacian Smoothing of Noisy Surface Meshes
00425   J. Vollmer, R. Mencl, and H. M�ller
00426   EUROGRAPHICS Volume 18 (1999), Number 3
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             // First Loop compute the laplacian
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                         // se l'edge j e' di bordo si deve sommare due volte
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             // Second Loop compute average difference
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                         // se l'edge j e' di bordo si deve sommare due volte
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         } // end for step
00494 };
00495 
00496 // Laplacian smooth of the quality.
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         // si azzaera i dati per i vertici di bordo
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         // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
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     } // end for step
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     } // end for step
00620 };
00621 
00622 // Laplacian smooth of the quality.
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     //TD.Start(lpz);
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             // si azzaera i dati per i vertici di bordo
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             // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
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     //VertexIterator vi;
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     //TD.Stop();
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             // si azzaera i dati per i vertici di bordo
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             // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
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     //VertexIterator vi;
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 // Smooth solo lungo la direzione di vista
00789     // alpha e' compreso fra 0(no smoot) e 1 (tutto smoot)
00790   // Nota che se smootare il bordo puo far fare bandierine.
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             // si azzaera i dati per i vertici di bordo
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             // se l'edge j e' di bordo si deve mediare solo con gli adiacenti
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 // Paso Double Smoothing
00857 //  The proposed
00858 // approach is a two step method where  in the first step the face normals
00859 // are adjusted and then, in a second phase, the vertex positions are updated.
00860 // Ref:
00861 // A. Belyaev and Y. Ohtake, A Comparison of Mesh Smoothing Methods, Proc. Israel-Korea Bi-Nat"l Conf. Geometric Modeling and Computer Graphics, pp. 83-87, 2003.
00862 
00863 /****************************************************************************************************************/
00864 /****************************************************************************************************************/
00865 // Classi di info
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 // Paso Doble Step 1 compute the smoothed normals
00883 /***************************************************************************/
00884 // Requirements:
00885 // VF Topology
00886 // Normalized Face Normals
00887 //
00888 // This is the Normal Smoothing approach of Shen and Berner
00889 // Fuzzy Vector Median-Based Surface Smoothing TVCG 2004
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     // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
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     // 1) Effectively average the normals weighting them with
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 // Replace the normal of the face with the average of normals of the vertex adijacent faces.
00942 // Normals are weighted with face area.
00943 // It assumes that:
00944 // VF adjacency is present.
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     // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
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     // 2) Effectively average the normals
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 // Replace the normal of the face with the average of normals of the face adijacent faces.
00989 // Normals are weighted with face area.
00990 // It assumes that:
00991 // Normals are normalized:
00992 // FF adjacency is present.
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 // Paso Doble Step 1 compute the smoothed normals
01025 /***************************************************************************/
01026 // Requirements:
01027 // VF Topology
01028 // Normalized Face Normals
01029 //
01030 // This is the Normal Smoothing approach based on a angle thresholded weighting
01031 // sigma is in the 0 .. 1 range, it represent the cosine of a threshold angle.
01032 // sigma == 0 All the normals are averaged
01033 // sigma == 1 Nothing is averaged.
01034 // Only within the specified range are averaged toghether. The averagin is weighted with the
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     // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
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     // 1) Effectively average the normals weighting them with the squared difference of the angle similarity
01052     // sigma is the cosine of a threshold angle. sigma \in 0..1
01053     // sigma == 0 All the normals are averaged
01054     // sigma == 1 Nothing is averaged.
01055     // The averaging is weighted with the difference between normals. more similar the normal more important they are.
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           // Note that if two faces form an angle larger than 90 deg, their contribution should be very very small.
01067           // Without this clamping
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);   // similar normals have a cosang very close to 1 so cosang - sigma is maximized
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 // Restituisce il gradiente dell'area del triangolo nel punto p.
01088 // Nota che dovrebbe essere sempre un vettore che giace nel piano del triangolo e perpendicolare al lato opposto al vertice p.
01089 // Ottimizzato con Maple e poi pesantemente a mano.
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 Deve Calcolare il gradiente di
01126 E(p) = A(p,p0,p1) (n - m)^2 =
01127 A(...) (2-2nm)   =
01128 (p0-p)^(p1-p)
01129 2A - 2A * ------------- m  =
01130 2A
01131 
01132 2A  -  2 (p0-p)^(p1-p) * m
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 // Paso Doble Step 2 Fitta la mesh a un dato insieme di normali
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        //SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
01177              bool OnlySelected=false)
01178 {
01179     //vcg::face::Pos<FaceType> ep;
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 // The sigma parameter affect the normal smoothing step
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 //  tree->setMaxNofNeighbors(neighborNum);
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 // grid must be a spatial index that contains all triangular faces of the target mesh gridmesh
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     // compute barycenter
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     // move vertex
01300     vp->P() = ct;
01301 
01302 
01303     vector<FacePointer> faces2 = HalfEdgeTopology<MeshType>::get_incident_faces(vp);
01304 
01305     // estimate normal
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     // reproject
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; // discard: inverse normal;
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 }; //end Smooth class
01371 
01372 }               // End namespace tri
01373 }               // End namespace vcg
01374 
01375 #endif //  VCG_SMOOTH


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