updated to the new temporary data structure and heavily restructured in a big class with uniform naming

This commit is contained in:
Paolo Cignoni 2008-05-16 17:44:06 +00:00
parent cf7f2af2a9
commit 634b5c4f63
1 changed files with 191 additions and 232 deletions

View File

@ -23,6 +23,10 @@
/**************************************************************************** /****************************************************************************
History History
$Log: not supported by cvs2svn $ $Log: not supported by cvs2svn $
Revision 1.19 2008/05/08 23:50:44 cignoni
renamed vertex quality smoothing
added face normal smoothing FF (and added a VF to the previous face normal smoothing)
Revision 1.18 2008/05/02 09:43:25 cignoni Revision 1.18 2008/05/02 09:43:25 cignoni
Added color smoothing, scale dependent laplacian changed a SD_old into SD fujumori, improved comments. Added color smoothing, scale dependent laplacian changed a SD_old into SD fujumori, improved comments.
@ -101,20 +105,42 @@ first partial porting: compiled gcc,intel and msvc
namespace vcg namespace vcg
{ {
namespace tri
{
///
/** \addtogroup trimesh */
/*@{*/
/// Class of static functions to smooth and fair meshes and their attributes.
template <class SmoothMeshType>
class Smooth
{
public:
typedef SmoothMeshType MeshType;
typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexType::CoordType CoordType;
typedef typename MeshType::VertexPointer VertexPointer;
typedef typename MeshType::VertexIterator VertexIterator;
typedef typename MeshType::ScalarType ScalarType;
typedef typename MeshType::FaceType FaceType;
typedef typename MeshType::FacePointer FacePointer;
typedef typename MeshType::FaceIterator FaceIterator;
typedef typename MeshType::FaceContainer FaceContainer;
typedef typename vcg::Box3<ScalarType> Box3Type;
typedef typename vcg::face::VFIterator<FaceType> VFLocalIterator;
template<class FLT>
class ScaleLaplacianInfo class ScaleLaplacianInfo
{ {
public: public:
Point3<FLT> PntSum; CoordType PntSum;
FLT LenSum; ScalarType LenSum;
}; };
// This is precisely what curvature flow does. // This is precisely what curvature flow does.
// Curvature flow smoothes the surface by moving along the surface // Curvature flow smoothes the surface by moving along the surface
// normal n with a speed equal to the mean curvature // normal n with a speed equal to the mean curvature
template<class MESH_TYPE> void VertexCoordLaplacianCurvatureFlow(MeshType &m, int step, ScalarType delta)
void LaplacianSmooth_CurvatureFlow(MESH_TYPE &m, int step, typename MESH_TYPE::ScalarType delta)
{ {
} }
@ -122,27 +148,25 @@ void LaplacianSmooth_CurvatureFlow(MESH_TYPE &m, int step, typename MESH_TYPE::
// Another Laplacian smoothing variant, // Another Laplacian smoothing variant,
// here we sum the baricenter of the faces incidents on each vertex weighting them with the angle // here we sum the baricenter of the faces incidents on each vertex weighting them with the angle
template<class MESH_TYPE> static void VertexCoordLaplacianAngleWeighted(MeshType &m, int step, ScalarType delta)
void LaplacianSmooth_AngleWeighted(MESH_TYPE &m, int step, typename MESH_TYPE::ScalarType delta)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer, ScaleLaplacianInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); ScaleLaplacianInfo lpz;
ScaleLaplacianInfo<typename MESH_TYPE::ScalarType> lpz; lpz.PntSum=CoordType(0,0,0);
lpz.PntSum=typename MESH_TYPE::CoordType(0,0,0);
lpz.LenSum=0; lpz.LenSum=0;
TD.Start(lpz); SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert,lpz);
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=lpz; TD[*vi]=lpz;
typename MESH_TYPE::ScalarType a[3]; ScalarType a[3];
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
{ {
typename MESH_TYPE::CoordType mp=((*fi).V(0)->P() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0; CoordType mp=((*fi).V(0)->P() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0;
typename MESH_TYPE::CoordType e0=((*fi).V(0)->P() - (*fi).V(1)->P()).Normalize(); 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(); 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(); CoordType e2=((*fi).V(2)->P() - (*fi).V(0)->P()).Normalize();
a[0]=AngleN(-e0,e2); a[0]=AngleN(-e0,e2);
a[1]=AngleN(-e1,e0); a[1]=AngleN(-e1,e0);
@ -150,7 +174,7 @@ void LaplacianSmooth_AngleWeighted(MESH_TYPE &m, int step, typename MESH_TYPE::
//assert(fabs(M_PI -a[0] -a[1] -a[2])<0.0000001); //assert(fabs(M_PI -a[0] -a[1] -a[2])<0.0000001);
for(int j=0;j<3;++j){ for(int j=0;j<3;++j){
typename MESH_TYPE::CoordType dir= (mp-(*fi).V(j)->P()).Normalize(); CoordType dir= (mp-(*fi).V(j)->P()).Normalize();
TD[(*fi).V(j)].PntSum+=dir*a[j]; TD[(*fi).V(j)].PntSum+=dir*a[j];
TD[(*fi).V(j)].LenSum+=a[j]; // well, it should be named angleSum TD[(*fi).V(j)].LenSum+=a[j]; // well, it should be named angleSum
} }
@ -160,7 +184,6 @@ void LaplacianSmooth_AngleWeighted(MESH_TYPE &m, int step, typename MESH_TYPE::
(*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum ) * delta; (*vi).P() = (*vi).P() + (TD[*vi].PntSum/TD[*vi].LenSum ) * delta;
} }
TD.Stop();
}; };
// Scale dependent laplacian smoothing [Fujiwara 95] // Scale dependent laplacian smoothing [Fujiwara 95]
@ -173,26 +196,25 @@ void LaplacianSmooth_AngleWeighted(MESH_TYPE &m, int step, typename MESH_TYPE::
// Note the delta parameter is in a absolute unit // Note the delta parameter is in a absolute unit
// it should be a small percentage of the shortest edge. // it should be a small percentage of the shortest edge.
template<class MESH_TYPE> static void VertexCoordScaleDependentLaplacian_Fujiwara(MeshType &m, int step, ScalarType delta)
void ScaleDependentLaplacianSmooth_Fujiwara(MESH_TYPE &m, int step, typename MESH_TYPE::ScalarType delta)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer, ScaleLaplacianInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert);
ScaleLaplacianInfo<typename MESH_TYPE::ScalarType> lpz; ScaleLaplacianInfo lpz;
lpz.PntSum=typename MESH_TYPE::CoordType(0,0,0); lpz.PntSum=CoordType(0,0,0);
lpz.LenSum=0; lpz.LenSum=0;
TD.Start(lpz); TD.Start(lpz);
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=lpz; TD[*vi]=lpz;
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
if(!(*fi).IsB(j)) { if(!(*fi).IsB(j)) {
typename MESH_TYPE::CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P(); CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
typename MESH_TYPE::ScalarType len=Norm(edge); ScalarType len=Norm(edge);
edge/=len; edge/=len;
TD[(*fi).V(j)].PntSum+=edge; TD[(*fi).V(j)].PntSum+=edge;
TD[(*fi).V1(j)].PntSum-=edge; TD[(*fi).V1(j)].PntSum-=edge;
@ -204,8 +226,8 @@ void ScaleDependentLaplacianSmooth_Fujiwara(MESH_TYPE &m, int step, typename ME
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
// se l'edge j e' di bordo si riazzera tutto e si riparte // se l'edge j e' di bordo si riazzera tutto e si riparte
if((*fi).IsB(j)) { if((*fi).IsB(j)) {
TD[(*fi).V(j)].PntSum=typename MESH_TYPE::CoordType(0,0,0); TD[(*fi).V(j)].PntSum=CoordType(0,0,0);
TD[(*fi).V1(j)].PntSum=typename MESH_TYPE::CoordType(0,0,0); TD[(*fi).V1(j)].PntSum=CoordType(0,0,0);
TD[(*fi).V(j)].LenSum=0; TD[(*fi).V(j)].LenSum=0;
TD[(*fi).V1(j)].LenSum=0; TD[(*fi).V1(j)].LenSum=0;
} }
@ -215,8 +237,8 @@ void ScaleDependentLaplacianSmooth_Fujiwara(MESH_TYPE &m, int step, typename ME
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
if((*fi).IsB(j)) if((*fi).IsB(j))
{ {
typename MESH_TYPE::CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P(); CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
typename MESH_TYPE::ScalarType len=Norm(edge); ScalarType len=Norm(edge);
edge/=len; edge/=len;
TD[(*fi).V(j)].PntSum+=edge; TD[(*fi).V(j)].PntSum+=edge;
TD[(*fi).V1(j)].PntSum-=edge; TD[(*fi).V1(j)].PntSum-=edge;
@ -237,33 +259,30 @@ void ScaleDependentLaplacianSmooth_Fujiwara(MESH_TYPE &m, int step, typename ME
}; };
template<class FLT>
class LaplacianInfo class LaplacianInfo
{ {
public: public:
Point3<FLT> sum; CoordType sum;
FLT cnt; ScalarType cnt;
}; };
// Classical Laplacian Smoothing. Each vertex can be moved onto the average of the adjacent vertices. // Classical Laplacian Smoothing. Each vertex can be moved onto the average of the adjacent vertices.
// Can smooth only the selected vertices and weight the smoothing according to the quality // Can smooth only the selected vertices and weight the smoothing according to the quality
// In the latter case 0 means that the vertex is not moved and 1 means that the vertex is moved onto the computed position. // In the latter case 0 means that the vertex is not moved and 1 means that the vertex is moved onto the computed position.
template<class MESH_TYPE> static void VertexCoordLaplacian(MeshType &m, int step, bool SmoothSelected=false, float QualityWeight=0)
void LaplacianSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false, float QualityWeight=0)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer,LaplacianInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); LaplacianInfo lpz;
LaplacianInfo<typename MESH_TYPE::ScalarType> lpz; lpz.sum=CoordType(0,0,0);
lpz.sum=typename MESH_TYPE::CoordType(0,0,0);
lpz.cnt=1; lpz.cnt=1;
TD.Start(lpz); SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi].sum=(*vi).P(); TD[*vi].sum=(*vi).P();
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -321,8 +340,6 @@ void LaplacianSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false, float Qu
(*vi).P()=TD[*vi].sum/TD[*vi].cnt; (*vi).P()=TD[*vi].sum/TD[*vi].cnt;
} }
} // end for } // end for
TD.Stop();
}; };
/* /*
@ -331,26 +348,24 @@ void LaplacianSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false, float Qu
EUROGRAPHICS Volume 18 (1999), Number 3 EUROGRAPHICS Volume 18 (1999), Number 3
*/ */
template<class FLT>
class HCSmoothInfo class HCSmoothInfo
{ {
public: public:
Point3<FLT> dif; CoordType dif;
Point3<FLT> sum; CoordType sum;
int cnt; int cnt;
}; };
template<class MESH_TYPE>
void HCSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false ) static void VertexCoordLaplacianHC(MeshType &m, int step, bool SmoothSelected=false )
{ {
typename MESH_TYPE::ScalarType beta=0.5; ScalarType beta=0.5;
SimpleTempData<typename MESH_TYPE::VertContainer,HCSmoothInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); HCSmoothInfo lpz;
HCSmoothInfo<typename MESH_TYPE::ScalarType> lpz; lpz.sum=CoordType(0,0,0);
lpz.sum=typename MESH_TYPE::CoordType(0,0,0); lpz.dif=CoordType(0,0,0);
lpz.dif=typename MESH_TYPE::CoordType(0,0,0);
lpz.cnt=0; lpz.cnt=0;
TD.Start(lpz); SimpleTempData<typename MeshType::VertContainer,HCSmoothInfo > TD(m.vert,lpz);
// First Loop compute the laplacian // First Loop compute the laplacian
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
{ {
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -369,7 +384,7 @@ void HCSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false )
} }
} }
} }
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
TD[*vi].sum/=(float)TD[*vi].cnt; TD[*vi].sum/=(float)TD[*vi].cnt;
@ -395,8 +410,6 @@ void HCSmooth(MESH_TYPE &m, int step, bool SmoothSelected=false )
if(!SmoothSelected || (*vi).IsS()) if(!SmoothSelected || (*vi).IsS())
(*vi).P()= TD[*vi].sum - (TD[*vi].sum - (*vi).P())*beta + (TD[*vi].dif)*(1.f-beta); (*vi).P()= TD[*vi].sum - (TD[*vi].sum - (*vi).P())*beta + (TD[*vi].dif)*(1.f-beta);
} }
TD.Stop();
}; };
// Laplacian smooth of the quality. // Laplacian smooth of the quality.
@ -412,20 +425,19 @@ public:
int cnt; int cnt;
}; };
template<class MESH_TYPE> void LaplacianSmoothColor(MESH_TYPE &m, int step, bool SmoothSelected=false) static void VertexColorLaplacian(MeshType &m, int step, bool SmoothSelected=false)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer, ColorSmoothInfo> TD(m.vert);
ColorSmoothInfo csi; ColorSmoothInfo csi;
csi.r=0; csi.g=0; csi.b=0; csi.cnt=0; csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
SimpleTempData<typename MeshType::VertContainer, ColorSmoothInfo> TD(m.vert,csi);
TD.Start(csi);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=csi; TD[*vi]=csi;
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -485,35 +497,33 @@ template<class MESH_TYPE> void LaplacianSmoothColor(MESH_TYPE &m, int step, bool
(*vi).C()[3] = (unsigned int) ceil((double) (TD[*vi].a / TD[*vi].cnt)); (*vi).C()[3] = (unsigned int) ceil((double) (TD[*vi].a / TD[*vi].cnt));
} }
} }
TD.Stop();
}; };
// Laplacian smooth of the quality. // Laplacian smooth of the quality.
template<class FLT>
class QualitySmoothInfo class QualitySmoothInfo
{ {
public: public:
FLT sum; ScalarType sum;
int cnt; int cnt;
}; };
template<class MESH_TYPE>
void VertexQualitySmooth(MESH_TYPE &m, int step=1, bool SmoothSelected=false) static void VertexQualityLaplacian(MeshType &m, int step=1, bool SmoothSelected=false)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer,QualitySmoothInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); QualitySmoothInfo lpz;
QualitySmoothInfo<typename MESH_TYPE::ScalarType> lpz;
lpz.sum=0; lpz.sum=0;
lpz.cnt=0; lpz.cnt=0;
TD.Start(lpz); SimpleTempData<typename MeshType::VertContainer,QualitySmoothInfo> TD(m.vert,lpz);
//TD.Start(lpz);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=lpz; TD[*vi]=lpz;
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -547,30 +557,30 @@ void VertexQualitySmooth(MESH_TYPE &m, int step=1, bool SmoothSelected=false)
++TD[(*fi).V1(j)].cnt; ++TD[(*fi).V1(j)].cnt;
} }
//typename MESH_TYPE::VertexIterator vi; //VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TD[*vi].cnt>0 ) if(!(*vi).IsD() && TD[*vi].cnt>0 )
if(!SmoothSelected || (*vi).IsS()) if(!SmoothSelected || (*vi).IsS())
(*vi).Q()=TD[*vi].sum/TD[*vi].cnt; (*vi).Q()=TD[*vi].sum/TD[*vi].cnt;
} }
TD.Stop(); //TD.Stop();
}; };
template<class MESH_TYPE>
void LaplacianSmoothNormals(MESH_TYPE &m, int step,bool SmoothSelected=false) static void VertexNormalLaplacian(MeshType &m, int step,bool SmoothSelected=false)
{ {
SimpleTempData<typename MESH_TYPE::VertContainer,LaplacianInfo<typename MESH_TYPE::ScalarType> > TD(m.vert); SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert);
LaplacianInfo<typename MESH_TYPE::ScalarType> lpz; LaplacianInfo lpz;
lpz.sum=typename MESH_TYPE::CoordType(0,0,0); lpz.sum=CoordType(0,0,0);
lpz.cnt=0; lpz.cnt=0;
TD.Start(lpz); TD.Start(lpz);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=lpz; TD[*vi]=lpz;
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -604,7 +614,7 @@ void LaplacianSmoothNormals(MESH_TYPE &m, int step,bool SmoothSelected=false)
++TD[(*fi).V1(j)].cnt; ++TD[(*fi).V1(j)].cnt;
} }
//typename MESH_TYPE::VertexIterator vi; //VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TD[*vi].cnt>0 ) if(!(*vi).IsD() && TD[*vi].cnt>0 )
if(!SmoothSelected || (*vi).IsS()) if(!SmoothSelected || (*vi).IsS())
@ -617,31 +627,23 @@ void LaplacianSmoothNormals(MESH_TYPE &m, int step,bool SmoothSelected=false)
// Smooth solo lungo la direzione di vista // Smooth solo lungo la direzione di vista
// alpha e' compreso fra 0(no smoot) e 1 (tutto smoot) // alpha e' compreso fra 0(no smoot) e 1 (tutto smoot)
// Nota che se smootare il bordo puo far fare bandierine. // Nota che se smootare il bordo puo far fare bandierine.
template<class MESH_TYPE> static void VertexCoordViewDepth(MeshType &m,
void DepthSmooth(MESH_TYPE &m, const CoordType & viewpoint,
const typename MESH_TYPE::CoordType & viewpoint, const ScalarType alpha,
const typename MESH_TYPE::ScalarType alpha,
int step, bool SmoothBorder=false ) int step, bool SmoothBorder=false )
{ {
typedef typename MESH_TYPE::CoordType v_type; SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert);
typedef typename MESH_TYPE::ScalarType s_type; LaplacianInfo lpz;
lpz.sum=CoordType(0,0,0);
//const typename MESH_TYPE::CoordType viewpoint;
//const typename MESH_TYPE::ScalarType alpha;
SimpleTempData<typename MESH_TYPE::VertContainer,LaplacianInfo<typename MESH_TYPE::ScalarType> > TD(m.vert);
LaplacianInfo<typename MESH_TYPE::ScalarType> lpz;
lpz.sum=typename MESH_TYPE::CoordType(0,0,0);
lpz.cnt=0; lpz.cnt=0;
TD.Start(lpz); TD.Start(lpz);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
TD[*vi]=lpz; TD[*vi]=lpz;
typename MESH_TYPE::FaceIterator fi; FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD()) if(!(*fi).IsD())
for(int j=0;j<3;++j) for(int j=0;j<3;++j)
@ -679,9 +681,9 @@ void DepthSmooth(MESH_TYPE &m,
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TD[*vi].cnt>0 ) if(!(*vi).IsD() && TD[*vi].cnt>0 )
{ {
v_type np = TD[*vi].sum/TD[*vi].cnt; CoordType np = TD[*vi].sum/TD[*vi].cnt;
v_type d = (*vi).Supervisor_P() - viewpoint; d.Normalize(); CoordType d = (*vi).Supervisor_P() - viewpoint; d.Normalize();
s_type s = d * ( np - (*vi).Supervisor_P() ); ScalarType s = d * ( np - (*vi).Supervisor_P() );
(*vi).Supervisor_P() += d * (s*alpha); (*vi).Supervisor_P() += d * (s*alpha);
} }
} }
@ -700,18 +702,18 @@ void DepthSmooth(MESH_TYPE &m,
/****************************************************************************************************************/ /****************************************************************************************************************/
/****************************************************************************************************************/ /****************************************************************************************************************/
// Classi di info // Classi di info
template<class FLT>
class PDVertInfo class PDVertInfo
{ {
public: public:
Point3<FLT> np; CoordType np;
}; };
template<class FLT>
class PDFaceInfo class PDFaceInfo
{ {
public: public:
Point3<FLT> m; CoordType m;
}; };
/***************************************************************************/ /***************************************************************************/
// Paso Doble Step 1 compute the smoothed normals // Paso Doble Step 1 compute the smoothed normals
@ -723,16 +725,14 @@ public:
// This is the Normal Smoothing approach of Shen and Berner // This is the Normal Smoothing approach of Shen and Berner
// Fuzzy Vector Median-Based Surface Smoothing TVCG 2004 // Fuzzy Vector Median-Based Surface Smoothing TVCG 2004
template<class MESH_TYPE>
void NormalSmoothSB(MESH_TYPE &m, void FaceNormalFuzzyVectorSB(MeshType &m,
SimpleTempData<typename MESH_TYPE::FaceContainer,PDFaceInfo< typename MESH_TYPE::ScalarType > > &TD, SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo > &TD,
typename MESH_TYPE::ScalarType sigma) ScalarType sigma)
{ {
int i; int i;
typedef typename MESH_TYPE::CoordType CoordType; FaceIterator fi;
typedef typename MESH_TYPE::ScalarType ScalarType;
typename MESH_TYPE::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
{ {
@ -740,7 +740,7 @@ void NormalSmoothSB(MESH_TYPE &m,
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
for(i=0;i<3;++i) for(i=0;i<3;++i)
{ {
vcg::face::VFIterator<typename MESH_TYPE::FaceType> ep(&*fi,i); vcg::face::VFIterator<FaceType> ep(&*fi,i);
while (!ep.End()) while (!ep.End())
{ {
ep.f->ClearV(); ep.f->ClearV();
@ -753,7 +753,7 @@ void NormalSmoothSB(MESH_TYPE &m,
CoordType mm=CoordType(0,0,0); CoordType mm=CoordType(0,0,0);
for(i=0;i<3;++i) for(i=0;i<3;++i)
{ {
vcg::face::VFIterator<typename MESH_TYPE::FaceType> ep(&*fi,i); vcg::face::VFIterator<FaceType> ep(&*fi,i);
while (!ep.End()) while (!ep.End())
{ {
if(! (*ep.f).IsV() ) if(! (*ep.f).IsV() )
@ -781,28 +781,24 @@ void NormalSmoothSB(MESH_TYPE &m,
// Normals are normalized: // Normals are normalized:
// VF adjacency is present. // VF adjacency is present.
template<class MESH_TYPE> static void FaceNormalLaplacianVF(MeshType &m)
void FaceNormalSmoothVF(MESH_TYPE &m)
{ {
SimpleTempData<typename MESH_TYPE::FaceContainer, PDFaceInfo< typename MESH_TYPE::ScalarType > > TDF(m.face); SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face);
PDFaceInfo<typename MESH_TYPE::ScalarType> lpzf; PDFaceInfo lpzf;
lpzf.m=typename MESH_TYPE::CoordType(0,0,0); lpzf.m=CoordType(0,0,0);
assert(tri::HasVFAdjacency(m)); assert(tri::HasVFAdjacency(m));
TDF.Start(lpzf); TDF.Start(lpzf);
int i; int i;
typedef typename MESH_TYPE::CoordType CoordType; FaceIterator fi;
typedef typename MESH_TYPE::ScalarType ScalarType;
typedef typename vcg::face::VFIterator<typename MESH_TYPE::FaceType> VFLocalIterator;
typename MESH_TYPE::FaceIterator fi;
tri::UpdateNormals<MESH_TYPE>::AreaNormalizeFace(m); tri::UpdateNormals<MeshType>::AreaNormalizeFace(m);
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{ {
CoordType bc=Barycenter<typename MESH_TYPE::FaceType>(*fi); CoordType bc=Barycenter<FaceType>(*fi);
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
for(i=0;i<3;++i) for(i=0;i<3;++i)
{ {
@ -832,7 +828,7 @@ void FaceNormalSmoothVF(MESH_TYPE &m)
for(fi=m.face.begin();fi!=m.face.end();++fi) for(fi=m.face.begin();fi!=m.face.end();++fi)
(*fi).N()=TDF[*fi].m; (*fi).N()=TDF[*fi].m;
tri::UpdateNormals<MESH_TYPE>::NormalizeFace(m); tri::UpdateNormals<MeshType>::NormalizeFace(m);
TDF.Stop(); TDF.Stop();
} }
@ -843,24 +839,16 @@ void FaceNormalSmoothVF(MESH_TYPE &m)
// Normals are normalized: // Normals are normalized:
// FF adjacency is present. // FF adjacency is present.
template<class MESH_TYPE>
void FaceNormalSmoothFF(MESH_TYPE &m, int step=1, bool SmoothSelected=false ) static void FaceNormalLaplacianFF(MeshType &m, int step=1, bool SmoothSelected=false )
{ {
SimpleTempData<typename MESH_TYPE::FaceContainer, PDFaceInfo< typename MESH_TYPE::ScalarType > > TDF(m.face); PDFaceInfo lpzf;
lpzf.m=CoordType(0,0,0);
PDFaceInfo<typename MESH_TYPE::ScalarType> lpzf; SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
lpzf.m=typename MESH_TYPE::CoordType(0,0,0);
assert(tri::HasFFAdjacency(m)); assert(tri::HasFFAdjacency(m));
TDF.Start(lpzf);
int i;
typedef typename MESH_TYPE::CoordType CoordType; FaceIterator fi;
// typedef typename MESH_TYPE::ScalarType ScalarType; tri::UpdateNormals<MeshType>::AreaNormalizeFace(m);
// typedef typename vcg::face::VFIterator<typename MESH_TYPE::FaceType> VFLocalIterator;
typename MESH_TYPE::FaceIterator fi;
tri::UpdateNormals<MESH_TYPE>::AreaNormalizeFace(m);
for(int i=0;i<step;++i) for(int i=0;i<step;++i)
{ {
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
@ -876,9 +864,8 @@ void FaceNormalSmoothFF(MESH_TYPE &m, int step=1, bool SmoothSelected=false )
if(!SmoothSelected || (*fi).IsS()) if(!SmoothSelected || (*fi).IsS())
(*fi).N()=TDF[*fi].m; (*fi).N()=TDF[*fi].m;
tri::UpdateNormals<MESH_TYPE>::NormalizeFace(m); tri::UpdateNormals<MeshType>::NormalizeFace(m);
} }
TDF.Stop();
} }
@ -895,21 +882,19 @@ void FaceNormalSmoothFF(MESH_TYPE &m, int step=1, bool SmoothSelected=false )
// sigma == 1 Nothing is averaged. // sigma == 1 Nothing is averaged.
// Only within the specified range are averaged toghether. The averagin is weighted with the // Only within the specified range are averaged toghether. The averagin is weighted with the
template<class MESH_TYPE>
void NormalSmooth(MESH_TYPE &m, static void FaceNormalAngleThreshold(MeshType &m,
SimpleTempData<typename MESH_TYPE::FaceContainer,PDFaceInfo< typename MESH_TYPE::ScalarType > > &TD, SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo> &TD,
typename MESH_TYPE::ScalarType sigma) ScalarType sigma)
{ {
int i; int i;
typedef typename MESH_TYPE::CoordType CoordType;
typedef typename MESH_TYPE::ScalarType ScalarType; FaceIterator fi;
typedef typename vcg::face::VFIterator<typename MESH_TYPE::FaceType> VFLocalIterator;
typename MESH_TYPE::FaceIterator fi;
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
{ {
CoordType bc=Barycenter<typename MESH_TYPE::FaceType>(*fi); CoordType bc=Barycenter<FaceType>(*fi);
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi // 1) Clear all the visited flag of faces that are vertex-adjacent to fi
for(i=0;i<3;++i) for(i=0;i<3;++i)
{ {
@ -954,19 +939,19 @@ void NormalSmooth(MESH_TYPE &m,
// Restituisce il gradiente dell'area del triangolo nel punto p. // Restituisce il gradiente dell'area del triangolo nel punto p.
// Nota che dovrebbe essere sempre un vettore che giace nel piano del triangolo e perpendicolare al lato opposto al vertice p. // Nota che dovrebbe essere sempre un vettore che giace nel piano del triangolo e perpendicolare al lato opposto al vertice p.
// Ottimizzato con Maple e poi pesantemente a mano. // Ottimizzato con Maple e poi pesantemente a mano.
template <class FLT>
Point3<FLT> TriAreaGradient(Point3<FLT> &p,Point3<FLT> &p0,Point3<FLT> &p1) CoordType TriAreaGradient(CoordType &p,CoordType &p0,CoordType &p1)
{ {
Point3<FLT> dd = p1-p0; CoordType dd = p1-p0;
Point3<FLT> d0 = p-p0; CoordType d0 = p-p0;
Point3<FLT> d1 = p-p1; CoordType d1 = p-p1;
Point3<FLT> grad; CoordType grad;
FLT t16 = d0[1]* d1[2] - d0[2]* d1[1]; ScalarType t16 = d0[1]* d1[2] - d0[2]* d1[1];
FLT t5 = -d0[2]* d1[0] + d0[0]* d1[2]; ScalarType t5 = -d0[2]* d1[0] + d0[0]* d1[2];
FLT t4 = -d0[0]* d1[1] + d0[1]* d1[0]; ScalarType t4 = -d0[0]* d1[1] + d0[1]* d1[0];
FLT delta= sqrtf(t4*t4 + t5*t5 +t16*t16); ScalarType delta= sqrtf(t4*t4 + t5*t5 +t16*t16);
grad[0]= (t5 * (-dd[2]) + t4 * ( dd[1]))/delta; grad[0]= (t5 * (-dd[2]) + t4 * ( dd[1]))/delta;
grad[1]= (t16 * (-dd[2]) + t4 * (-dd[0]))/delta; grad[1]= (t16 * (-dd[2]) + t4 * (-dd[0]))/delta;
@ -975,12 +960,12 @@ Point3<FLT> TriAreaGradient(Point3<FLT> &p,Point3<FLT> &p0,Point3<FLT> &p1)
return grad; return grad;
} }
template <class FLT> template <class ScalarType>
Point3<FLT> CrossProdGradient(Point3<FLT> &p, Point3<FLT> &p0, Point3<FLT> &p1, Point3<FLT> &m) CoordType CrossProdGradient(CoordType &p, CoordType &p0, CoordType &p1, CoordType &m)
{ {
Point3<FLT> grad; CoordType grad;
Point3<FLT> p00=p0-p; CoordType p00=p0-p;
Point3<FLT> p01=p1-p; CoordType p01=p1-p;
grad[0] = (-p00[2] + p01[2])*m[1] + (-p01[1] + p00[1])*m[2]; grad[0] = (-p00[2] + p01[2])*m[1] + (-p01[1] + p00[1])*m[2];
grad[1] = (-p01[2] + p00[2])*m[0] + (-p00[0] + p01[0])*m[2]; grad[1] = (-p01[2] + p00[2])*m[0] + (-p00[0] + p01[0])*m[2];
grad[2] = (-p00[1] + p01[1])*m[0] + (-p01[0] + p00[0])*m[1]; grad[2] = (-p00[1] + p01[1])*m[0] + (-p01[0] + p00[0])*m[1];
@ -998,8 +983,8 @@ A(...) (2-2nm) =
2A - 2 (p0-p)^(p1-p) * m 2A - 2 (p0-p)^(p1-p) * m
*/ */
template <class FLT>
Point3<FLT> FaceErrorGrad(Point3<FLT> &p,Point3<FLT> &p0,Point3<FLT> &p1, Point3<FLT> &m) CoordType FaceErrorGrad(CoordType &p,CoordType &p0,CoordType &p1, CoordType &m)
{ {
return TriAreaGradient(p,p0,p1) *2.0f return TriAreaGradient(p,p0,p1) *2.0f
- CrossProdGradient(p,p0,p1,m) *2.0f ; - CrossProdGradient(p,p0,p1,m) *2.0f ;
@ -1008,17 +993,15 @@ Point3<FLT> FaceErrorGrad(Point3<FLT> &p,Point3<FLT> &p0,Point3<FLT> &p1, Point3
// Paso Doble Step 2 Fitta la mesh a un dato insieme di normali // Paso Doble Step 2 Fitta la mesh a un dato insieme di normali
/***************************************************************************/ /***************************************************************************/
template<class MESH_TYPE>
void FitMesh(MESH_TYPE &m, void FitMesh(MeshType &m,
SimpleTempData<typename MESH_TYPE::VertContainer, PDVertInfo<typename MESH_TYPE::ScalarType> > &TDV, SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
SimpleTempData<typename MESH_TYPE::FaceContainer, PDFaceInfo<typename MESH_TYPE::ScalarType> > &TDF, SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
float lambda) float lambda)
{ {
//vcg::face::Pos<typename MESH_TYPE::FaceType> ep; //vcg::face::Pos<FaceType> ep;
vcg::face::VFIterator<typename MESH_TYPE::FaceType> ep; vcg::face::VFIterator<FaceType> ep;
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
typedef typename MESH_TYPE::ScalarType ScalarType;
typedef typename MESH_TYPE::CoordType CoordType;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
{ {
CoordType ErrGrad=CoordType(0,0,0); CoordType ErrGrad=CoordType(0,0,0);
@ -1040,18 +1023,15 @@ void FitMesh(MESH_TYPE &m,
/****************************************************************************************************************/ /****************************************************************************************************************/
template<class MESH_TYPE>
void FastFitMesh(MESH_TYPE &m, static void FastFitMesh(MeshType &m,
SimpleTempData<typename MESH_TYPE::VertContainer, PDVertInfo<typename MESH_TYPE::ScalarType> > &TDV, SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
SimpleTempData<typename MESH_TYPE::FaceContainer, PDFaceInfo<typename MESH_TYPE::ScalarType> > &TDF, SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
bool OnlySelected=false) bool OnlySelected=false)
{ {
//vcg::face::Pos<typename MESH_TYPE::FaceType> ep; //vcg::face::Pos<FaceType> ep;
vcg::face::VFIterator<typename MESH_TYPE::FaceType> ep; vcg::face::VFIterator<FaceType> ep;
typename MESH_TYPE::VertexIterator vi; VertexIterator vi;
typedef typename MESH_TYPE::ScalarType ScalarType;
typedef typename MESH_TYPE::CoordType CoordType;
typedef typename vcg::face::VFIterator<typename MESH_TYPE::FaceType> VFLocalIterator;
for(vi=m.vert.begin();vi!=m.vert.end();++vi) for(vi=m.vert.begin();vi!=m.vert.end();++vi)
{ {
@ -1060,7 +1040,7 @@ void FastFitMesh(MESH_TYPE &m,
VFLocalIterator ep(&*vi); VFLocalIterator ep(&*vi);
for (;!ep.End();++ep) for (;!ep.End();++ep)
{ {
CoordType bc=Barycenter<typename MESH_TYPE::FaceType>(*ep.F()); CoordType bc=Barycenter<FaceType>(*ep.F());
Sum += ep.F()->N()*(ep.F()->N()*(bc - (*vi).P())); Sum += ep.F()->N()*(ep.F()->N()*(bc - (*vi).P()));
++cnt; ++cnt;
} }
@ -1081,21 +1061,13 @@ void FastFitMesh(MESH_TYPE &m,
static void VertexCoordPasoDoble(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=10, typename MeshType::ScalarType FitLambda=0.05)
template<class MeshType>
void PasoDobleSmooth(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=10, typename MeshType::ScalarType FitLambda=0.05)
{ {
typedef typename MeshType::ScalarType ScalarType; SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert);
typedef typename MeshType::CoordType CoordType; SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face);
PDVertInfo lpzv;
SimpleTempData< typename MeshType::VertContainer, PDVertInfo<ScalarType> > TDV(m.vert);
SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo<ScalarType> > TDF(m.face);
PDVertInfo<ScalarType> lpzv;
lpzv.np=CoordType(0,0,0); lpzv.np=CoordType(0,0,0);
PDFaceInfo<ScalarType> lpzf; PDFaceInfo lpzf;
lpzf.m=CoordType(0,0,0); lpzf.m=CoordType(0,0,0);
assert(m.HasVFTopology()); assert(m.HasVFTopology());
@ -1106,9 +1078,9 @@ void PasoDobleSmooth(MeshType &m, int step, typename MeshType::ScalarType Sigma=
{ {
vcg::tri::UpdateNormals<MeshType>::PerFace(m); vcg::tri::UpdateNormals<MeshType>::PerFace(m);
NormalSmooth<MeshType>(m,TDF,Sigma); FaceNormalAngleThreshold(m,TDF,Sigma);
for(int k=0;k<FitStep;k++) for(int k=0;k<FitStep;k++)
FitMesh<MeshType>(m,TDV,TDF,FitLambda); FitMesh(m,TDV,TDF,FitLambda);
} }
TDF.Stop(); TDF.Stop();
@ -1118,41 +1090,28 @@ void PasoDobleSmooth(MeshType &m, int step, typename MeshType::ScalarType Sigma=
// The sigma parameter affect the normal smoothing step // The sigma parameter affect the normal smoothing step
static void VertexCoordPasoDobleFast(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=50, bool SmoothSelected =false)
template<class MeshType>
void PasoDobleSmoothFast(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=50, bool SmoothSelected =false)
{ {
typedef typename MeshType::ScalarType ScalarType; PDVertInfo lpzv;
typedef typename MeshType::CoordType CoordType;
SimpleTempData< typename MeshType::VertContainer, PDVertInfo<ScalarType> > TDV(m.vert);
SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo<ScalarType> > TDF(m.face);
PDVertInfo<ScalarType> lpzv;
lpzv.np=CoordType(0,0,0); lpzv.np=CoordType(0,0,0);
PDFaceInfo<ScalarType> lpzf; PDFaceInfo lpzf;
lpzf.m=CoordType(0,0,0); lpzf.m=CoordType(0,0,0);
assert(m.HasVFTopology()); assert(m.HasVFTopology());
m.HasVFTopology(); m.HasVFTopology();
TDV.Start(lpzv); SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert,lpzv);
TDF.Start(lpzf); SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
for(int j=0;j<step;++j) for(int j=0;j<step;++j)
NormalSmooth<MeshType>(m,TDF,Sigma); FaceNormalAngleThreshold(m,TDF,Sigma);
for(int j=0;j<FitStep;++j) for(int j=0;j<FitStep;++j)
FastFitMesh<MeshType>(m,TDV,TDF,SmoothSelected); FastFitMesh(m,TDV,TDF,SmoothSelected);
TDF.Stop();
TDV.Stop();
} }
}; //end Smooth class
} // End namespace tri
} // End namespace vcg } // End namespace vcg
#endif // VCG_SMOOTH #endif // VCG_SMOOTH