diff --git a/vcg/complex/trimesh/smooth.h b/vcg/complex/trimesh/smooth.h new file mode 100644 index 00000000..5d0a1aa7 --- /dev/null +++ b/vcg/complex/trimesh/smooth.h @@ -0,0 +1,499 @@ +/**************************************************************************** +* VCGLib o o * +* Visual and Computer Graphics Library o o * +* _ O _ * +* Copyright(C) 2004 \/)\/ * +* Visual Computing Lab /\/| * +* ISTI - Italian National Research Council | * +* \ * +* All rights reserved. * +* * +* This program is free software; you can redistribute it and/or modify * +* it under the terms of the GNU General Public License as published by * +* the Free Software Foundation; either version 2 of the License, or * +* (at your option) any later version. * +* * +* This program is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * +* for more details. * +* * +****************************************************************************/ +/**************************************************************************** + History +$Log: not supported by cvs2svn $ + +/****************************************************************************/ + + +#ifndef __VCGLIB__SMOOTH +#define __VCGLIB__SMOOTH + +#include +#include +#include + +namespace vcg +{ + +template +class ScaleLaplacianInfo +{ +public: + Point3 PntSum; + FLT LenSum; +}; + +// Scale dependent laplacian smoothing [fujimori 95] +// Nuova versione, l'idea e'quella di usare anche gli angoli delle facce per pesare lo spostamento. +// +// in pratica si sposta solo lungo la componente che e' parallela alla normale al vertice +// (che si suppone esserci!!) + + +// Non ha bisogno della topologia +// Non fa assunzioni sull'ordinamento delle facce, ma vuole che i border flag ci siano! +// +// + +template +void ScaleLaplacianSmooth(MESH_TYPE &m, int step, typename MESH_TYPE::ScalarType delta) +{ + SimpleTempData > TD(m.vert); + ScaleLaplacianInfo lpz; + lpz.PntSum=typename MESH_TYPE::CoordType(0,0,0); + lpz.LenSum=0; + TD.Start(lpz); + typename MESH_TYPE::FaceIterator fi; + for(int i=0;iP() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0; + typename MESH_TYPE::CoordType e0=((*fi).V(0)->P() - (*fi).V(1)->P()).Normalize(); + typename MESH_TYPE::CoordType e1=((*fi).V(1)->P() - (*fi).V(2)->P()).Normalize(); + typename MESH_TYPE::CoordType e2=((*fi).V(2)->P() - (*fi).V(0)->P()).Normalize(); + + a[0]=AngleN(-e0,e2); + a[1]=AngleN(-e1,e0); + a[2]=AngleN(-e2,e1); + //assert(fabs(M_PI -a[0] -a[1] -a[2])<0.0000001); + + for(int j=0;j<3;++j){ + typename MESH_TYPE::CoordType dir= (mp-(*fi).V(j)->P()).Normalize(); + TD[(*fi).V(j)].PntSum+=dir*a[j]; + TD[(*fi).V(j)].LenSum+=a[j]; + } + } + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].LenSum>0 ) + (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum ) * delta; + + } + TD.Stop(); +}; + +// Scale dependent laplacian smoothing [fujimori 95] +// Non ha bisogno della topologia +// Non fa assunzioni sull'ordinamento delle facce, ma vuole che i border flag ci siano! +// +// +template +void ScaleLaplacianSmoothOld(MESH_TYPE &m, int step, typename MESH_TYPE::ScalarType delta) +{ + SimpleTempData > TD(m.vert); + ScaleLaplacianInfo lpz; + lpz.PntSum=typename MESH_TYPE::CoordType(0,0,0); + lpz.LenSum=0; + TD.Start(lpz); + typename MESH_TYPE::FaceIterator fi; + for(int i=0;iP() -(*fi).V(j)->P(); + typename MESH_TYPE::ScalarType len=Norm(edge); + edge/=len; + TD[(*fi).V(j)].PntSum+=edge; + TD[(*fi).V1(j)].PntSum-=edge; + TD[(*fi).V(j)].LenSum+=len; + TD[(*fi).V1(j)].LenSum+=len; + } + + for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) + for(int j=0;j<3;++j) + // se l'edge j e' di bordo si riazzera tutto e si riparte + if((*fi).IsB(j)) { + TD[(*fi).V(j)].PntSum=typename MESH_TYPE::CoordType(0,0,0); + TD[(*fi).V1(j)].PntSum=typename MESH_TYPE::CoordType(0,0,0); + TD[(*fi).V(j)].LenSum=0; + TD[(*fi).V1(j)].LenSum=0; + } + + + for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + typename MESH_TYPE::CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P(); + typename MESH_TYPE::ScalarType len=Norm(edge); + edge/=len; + TD[(*fi).V(j)].PntSum+=edge; + TD[(*fi).V1(j)].PntSum-=edge; + TD[(*fi).V(j)].LenSum+=len; + TD[(*fi).V1(j)].LenSum+=len; + } + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].LenSum>0 ) + (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum)*delta; + } + TD.Stop(); +}; + + +template +class LaplacianInfo +{ +public: + Point3 sum; + FLT cnt; +}; + +template +void LaplacianSmooth(MESH_TYPE &m, int step,bool SmoothSelected=false) +{ + SimpleTempData > TD(m.vert); + LaplacianInfo lpz; + lpz.sum=typename MESH_TYPE::CoordType(0,0,0); + lpz.cnt=0; + TD.Start(lpz); + for(int i=0;iP(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + // si azzaera i dati per i vertici di bordo + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)]=lpz; + TD[(*fi).V1(j)]=lpz; + } + + // se l'edge j e' di bordo si deve mediare solo con gli adiacenti + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].cnt>0 ) + if(!SmoothSelected || (*vi).IsS()) + (*vi).P()=TD[*vi].sum/TD[*vi].cnt; + } + + TD.Stop(); +}; + + +template +class HCSmoothInfo +{ +public: + Point3 dif; + Point3 sum; + int cnt; +}; +template +void HCSmooth(MESH_TYPE &m, int step) +{ + typename MESH_TYPE::ScalarType beta=0.5; + SimpleTempData > TD(m.vert); + HCSmoothInfo lpz; + lpz.sum=typename MESH_TYPE::CoordType(0,0,0); + lpz.dif=typename MESH_TYPE::CoordType(0,0,0); + lpz.cnt=0; + TD.Start(lpz); + // First Loop compute the laplacian + typename MESH_TYPE::FaceIterator fi; + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + for(int j=0;j<3;++j) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + // se l'edge j e' di bordo si deve sommare due volte + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->P(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + } + } + typename MESH_TYPE::VertexIterator vi; + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + TD[*vi].sum/=(float)TD[*vi].cnt; + + // Second Loop compute average difference + for(fi=m.face.begin();fi!=m.face.end();++fi) + { + for(int j=0;j<3;++j) + { + TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P(); + TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P(); + // se l'edge j e' di bordo si deve sommare due volte + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].dif +=TD[(*fi).V1(j)].sum-(*fi).V1(j)->P(); + TD[(*fi).V1(j)].dif+=TD[(*fi).V(j)].sum-(*fi).V(j)->P(); + } + } + } + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + { + TD[*vi].dif/=(float)TD[*vi].cnt; + (*vi).P()=TD[*vi].sum -((TD[*vi].sum-(*vi).P()*beta) + TD[*vi].dif)*(1.f-beta); + } + + TD.Stop(); +}; + + +template +class QualitySmoothInfo +{ +public: + FLT sum; + int cnt; +}; + +template +void LaplacianSmoothQuality(MESH_TYPE &m, int step,bool SmoothSelected=false) +{ + SimpleTempData > TD(m.vert); + QualitySmoothInfo lpz; + lpz.sum=0; + lpz.cnt=0; + TD.Start(lpz); + for(int i=0;iQ(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + // si azzaera i dati per i vertici di bordo + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)]=lpz; + TD[(*fi).V1(j)]=lpz; + } + + // se l'edge j e' di bordo si deve mediare solo con gli adiacenti + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->Q(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->Q(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + //typename MESH_TYPE::VertexIterator vi; + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].cnt>0 ) + if(!SmoothSelected || (*vi).IsS()) + (*vi).Q()=TD[*vi].sum/TD[*vi].cnt; + } + + TD.Stop(); +}; +template +void LaplacianSmoothNormals(MESH_TYPE &m, int step,bool SmoothSelected=false) +{ + SimpleTempData > TD(m.vert); + LaplacianInfo lpz; + lpz.sum=typename MESH_TYPE::CoordType(0,0,0); + lpz.cnt=0; + TD.Start(lpz); + for(int i=0;iN(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->N(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + // si azzaera i dati per i vertici di bordo + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)]=lpz; + TD[(*fi).V1(j)]=lpz; + } + + // se l'edge j e' di bordo si deve mediare solo con gli adiacenti + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->N(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->N(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + //typename MESH_TYPE::VertexIterator vi; + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].cnt>0 ) + if(!SmoothSelected || (*vi).IsS()) + (*vi).N()=TD[*vi].sum/TD[*vi].cnt; + } + + TD.Stop(); +}; + +// Smooth solo lungo la direzione di vista + // alpha e' compreso fra 0(no smoot) e 1 (tutto smoot) + // Nota che se smootare il bordo puo far fare bandierine. +template +void DepthSmooth(MESH_TYPE &m, + const typename MESH_TYPE::CoordType & viewpoint, + const typename MESH_TYPE::ScalarType alpha, + int step, bool SmoothBorder=false ) +{ + typedef typename MESH_TYPE::CoordType v_type; + typedef typename MESH_TYPE::ScalarType s_type; + + + //const typename MESH_TYPE::CoordType viewpoint; + //const typename MESH_TYPE::ScalarType alpha; + + SimpleTempData > TD(m.vert); + LaplacianInfo lpz; + lpz.sum=typename MESH_TYPE::CoordType(0,0,0); + lpz.cnt=0; + TD.Start(lpz); + for(int i=0;iSupervisor_P(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->Supervisor_P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + // si azzaera i dati per i vertici di bordo + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)]=lpz; + TD[(*fi).V1(j)]=lpz; + } + + // se l'edge j e' di bordo si deve mediare solo con gli adiacenti + if(SmoothBorder) + for(fi=m.face.begin();fi!=m.face.end();++fi) + if(!(*fi).IsD()) + for(int j=0;j<3;++j) + if((*fi).IsB(j)) + { + TD[(*fi).V(j)].sum+=(*fi).V1(j)->Supervisor_P(); + TD[(*fi).V1(j)].sum+=(*fi).V(j)->Supervisor_P(); + ++TD[(*fi).V(j)].cnt; + ++TD[(*fi).V1(j)].cnt; + } + + for(vi=m.vert.begin();vi!=m.vert.end();++vi) + if(!(*vi).IsD() && TD[*vi].cnt>0 ) + { + v_type np = TD[*vi].sum/TD[*vi].cnt; + v_type d = (*vi).Supervisor_P() - viewpoint; d.Normalize(); + s_type s = d * ( np - (*vi).Supervisor_P() ); + (*vi).Supervisor_P() += d * (s*alpha); + } + } + + TD.Stop(); +} + +} // End namespace vcg + +#endif // VCG_SMOOTH \ No newline at end of file