2004-12-11 15:53:19 +01:00
|
|
|
|
/****************************************************************************
|
|
|
|
|
* 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 $
|
2008-05-16 19:44:06 +02:00
|
|
|
|
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)
|
|
|
|
|
|
2008-05-09 01:50:44 +02:00
|
|
|
|
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.
|
|
|
|
|
|
2008-05-02 11:43:25 +02:00
|
|
|
|
Revision 1.17 2008/04/18 17:48:29 cignoni
|
|
|
|
|
added facenormal smoothing
|
|
|
|
|
|
2008-04-18 19:48:29 +02:00
|
|
|
|
Revision 1.16 2008/02/07 10:24:51 cignoni
|
|
|
|
|
added a missing IsD() check
|
|
|
|
|
|
2008-02-07 11:24:51 +01:00
|
|
|
|
Revision 1.15 2007/11/05 23:47:20 cignoni
|
|
|
|
|
added selection to the pasodoble smoothing
|
|
|
|
|
|
2007-11-06 00:47:20 +01:00
|
|
|
|
Revision 1.14 2007/03/27 09:40:47 cignoni
|
|
|
|
|
Changed use of selected to visited flags. Improved variable namings and comments
|
|
|
|
|
|
2007-03-27 11:40:47 +02:00
|
|
|
|
Revision 1.13 2006/11/07 15:13:56 zifnab1974
|
|
|
|
|
Necessary changes for compilation with gcc 3.4.6. Especially the hash function is a problem
|
|
|
|
|
|
2006-11-07 16:13:57 +01:00
|
|
|
|
Revision 1.12 2006/11/07 11:28:02 cignoni
|
|
|
|
|
Added Quality weighted laplacian smoothing
|
|
|
|
|
|
2006-11-07 12:28:02 +01:00
|
|
|
|
Revision 1.11 2006/10/19 07:33:03 cignoni
|
|
|
|
|
Corrected Laplacian, Added selection to HCSmooth
|
|
|
|
|
|
2006-10-19 09:33:03 +02:00
|
|
|
|
Revision 1.10 2006/09/25 09:41:41 cignoni
|
|
|
|
|
Added new version of pasodoble smoothing
|
|
|
|
|
|
2006-09-25 11:41:41 +02:00
|
|
|
|
Revision 1.9 2006/02/06 10:45:47 cignoni
|
|
|
|
|
Added missing typenames
|
|
|
|
|
|
2006-01-30 09:03:45 +01:00
|
|
|
|
Revision 1.7 2006/01/24 13:23:22 pietroni
|
|
|
|
|
used template types instead of point3f and float inside function calls
|
|
|
|
|
|
2006-01-24 14:23:22 +01:00
|
|
|
|
Revision 1.6 2005/12/06 17:55:16 pietroni
|
|
|
|
|
1 bug corrected
|
|
|
|
|
|
2005-12-06 18:55:16 +01:00
|
|
|
|
Revision 1.5 2005/12/02 16:24:56 pietroni
|
|
|
|
|
corrected 1 bug in Cross Prod Gradient
|
|
|
|
|
|
2005-12-02 17:24:56 +01:00
|
|
|
|
Revision 1.4 2005/11/23 16:24:44 pietroni
|
|
|
|
|
corrected CrossProdGradient( )
|
|
|
|
|
|
2005-11-23 17:24:44 +01:00
|
|
|
|
Revision 1.3 2005/07/11 13:12:05 cignoni
|
|
|
|
|
small gcc-related compiling issues (typenames,ending cr, initialization order)
|
|
|
|
|
|
2005-07-11 15:16:34 +02:00
|
|
|
|
Revision 1.2 2005/03/16 16:14:12 spinelli
|
|
|
|
|
aggiunta funzione PasoDobleSmooth e relative:
|
|
|
|
|
|
|
|
|
|
- FitMesh
|
|
|
|
|
- FaceErrorGrad
|
|
|
|
|
- CrossProdGradient
|
|
|
|
|
- TriAreaGradient
|
|
|
|
|
- NormalSmooth
|
|
|
|
|
|
|
|
|
|
e le classi:
|
|
|
|
|
|
|
|
|
|
- PDVertInfo
|
|
|
|
|
- PDFaceInfo
|
|
|
|
|
|
|
|
|
|
necessarie per utilizzare SimpleTempData
|
|
|
|
|
|
2005-03-16 17:14:12 +01:00
|
|
|
|
Revision 1.1 2004/12/11 14:53:19 ganovelli
|
|
|
|
|
first partial porting: compiled gcc,intel and msvc
|
|
|
|
|
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
2005-07-11 15:16:34 +02:00
|
|
|
|
****************************************************************************/
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef __VCGLIB__SMOOTH
|
|
|
|
|
#define __VCGLIB__SMOOTH
|
|
|
|
|
|
2008-09-29 12:12:38 +02:00
|
|
|
|
#include <wrap/callback.h>
|
2004-12-11 15:53:19 +01:00
|
|
|
|
#include <vcg/space/point3.h>
|
|
|
|
|
#include <vcg/space/line3.h>
|
|
|
|
|
#include <vcg/container/simple_temporary_data.h>
|
2005-07-11 15:16:34 +02:00
|
|
|
|
#include <vcg/complex/trimesh/update/normal.h>
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
|
|
|
|
namespace vcg
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
namespace tri
|
|
|
|
|
{
|
|
|
|
|
///
|
|
|
|
|
/** \addtogroup trimesh */
|
|
|
|
|
/*@{*/
|
|
|
|
|
/// Class of static functions to smooth and fair meshes and their attributes.
|
|
|
|
|
|
|
|
|
|
template <class SmoothMeshType>
|
|
|
|
|
class Smooth
|
|
|
|
|
{
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
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;
|
|
|
|
|
|
2004-12-11 15:53:19 +01:00
|
|
|
|
class ScaleLaplacianInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType PntSum;
|
|
|
|
|
ScalarType LenSum;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
};
|
|
|
|
|
|
2008-05-02 11:43:25 +02:00
|
|
|
|
// This is precisely what curvature flow does.
|
|
|
|
|
// Curvature flow smoothes the surface by moving along the surface
|
|
|
|
|
// normal n with a speed equal to the mean curvature
|
2008-05-16 19:44:06 +02:00
|
|
|
|
void VertexCoordLaplacianCurvatureFlow(MeshType &m, int step, ScalarType delta)
|
2008-05-02 11:43:25 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
2008-05-02 11:43:25 +02:00
|
|
|
|
// Another Laplacian smoothing variant,
|
|
|
|
|
// here we sum the baricenter of the faces incidents on each vertex weighting them with the angle
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void VertexCoordLaplacianAngleWeighted(MeshType &m, int step, ScalarType delta)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScaleLaplacianInfo lpz;
|
|
|
|
|
lpz.PntSum=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.LenSum=0;
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert,lpz);
|
|
|
|
|
FaceIterator fi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=lpz;
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScalarType a[3];
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType mp=((*fi).V(0)->P() + (*fi).V(1)->P() + (*fi).V(2)->P())/3.0;
|
|
|
|
|
CoordType e0=((*fi).V(0)->P() - (*fi).V(1)->P()).Normalize();
|
|
|
|
|
CoordType e1=((*fi).V(1)->P() - (*fi).V(2)->P()).Normalize();
|
|
|
|
|
CoordType e2=((*fi).V(2)->P() - (*fi).V(0)->P()).Normalize();
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
|
|
|
|
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){
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType dir= (mp-(*fi).V(j)->P()).Normalize();
|
2004-12-11 15:53:19 +01:00
|
|
|
|
TD[(*fi).V(j)].PntSum+=dir*a[j];
|
2008-05-02 11:43:25 +02:00
|
|
|
|
TD[(*fi).V(j)].LenSum+=a[j]; // well, it should be named angleSum
|
2004-12-11 15:53:19 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2008-05-02 11:43:25 +02:00
|
|
|
|
// Scale dependent laplacian smoothing [Fujiwara 95]
|
|
|
|
|
// as described in
|
|
|
|
|
// Implicit Fairing of Irregular Meshes using Diffusion and Curvature Flow
|
|
|
|
|
// Mathieu Desbrun, Mark Meyer, Peter Schroeder, Alan H. Barr
|
|
|
|
|
// SIGGRAPH 99
|
|
|
|
|
// REQUIREMENTS: Border Flags.
|
2004-12-11 15:53:19 +01:00
|
|
|
|
//
|
2008-05-02 11:43:25 +02:00
|
|
|
|
// Note the delta parameter is in a absolute unit
|
2008-06-18 01:05:25 +02:00
|
|
|
|
// to get stability it should be a small percentage of the shortest edge.
|
2008-05-02 11:43:25 +02:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void VertexCoordScaleDependentLaplacian_Fujiwara(MeshType &m, int step, ScalarType delta)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer, ScaleLaplacianInfo > TD(m.vert);
|
|
|
|
|
ScaleLaplacianInfo lpz;
|
|
|
|
|
lpz.PntSum=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.LenSum=0;
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=lpz;
|
|
|
|
|
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
|
if(!(*fi).IsB(j)) {
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
|
|
|
|
|
ScalarType len=Norm(edge);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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)) {
|
2008-05-16 19:44:06 +02:00
|
|
|
|
TD[(*fi).V(j)].PntSum=CoordType(0,0,0);
|
|
|
|
|
TD[(*fi).V1(j)].PntSum=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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))
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType edge= (*fi).V1(j)->P() -(*fi).V(j)->P();
|
|
|
|
|
ScalarType len=Norm(edge);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
2008-05-02 11:43:25 +02:00
|
|
|
|
// The fundamental part:
|
|
|
|
|
// We move the new point of a quantity
|
|
|
|
|
//
|
|
|
|
|
// L(M) = 1/Sum(edgelen) * Sum(Normalized edges)
|
|
|
|
|
//
|
|
|
|
|
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class LaplacianInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-07-04 02:32:48 +02:00
|
|
|
|
LaplacianInfo(const CoordType &_p, const int _n):sum(_p),cnt(_n) {}
|
|
|
|
|
LaplacianInfo() {}
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType sum;
|
|
|
|
|
ScalarType cnt;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
};
|
|
|
|
|
|
2006-11-07 12:28:02 +01:00
|
|
|
|
// 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
|
|
|
|
|
// In the latter case 0 means that the vertex is not moved and 1 means that the vertex is moved onto the computed position.
|
2008-07-04 02:32:48 +02:00
|
|
|
|
//
|
|
|
|
|
// From the Taubin definition "A signal proc approach to fair surface design"
|
|
|
|
|
// We define the discrete Laplacian of a discrete surface signal by weighted averages over the neighborhoods
|
|
|
|
|
// \delta xi = \Sum wij (xj - xi) ;
|
|
|
|
|
// where xj are the adjacent vertices of xi and wij is usually 1/n_adj
|
|
|
|
|
//
|
|
|
|
|
// This function simply accumulate over a TempData all the positions of the ajacent vertices
|
|
|
|
|
//
|
|
|
|
|
static void AccumulateLaplacianInfo(MeshType &m, SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > &TD)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-07-04 02:32:48 +02:00
|
|
|
|
FaceIterator fi;
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
{
|
|
|
|
|
if(!(*fi).IsD())
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
|
if(!(*fi).IsB(j))
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
|
|
|
|
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;
|
2008-07-04 02:32:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-11 15:53:19 +01:00
|
|
|
|
// si azzaera i dati per i vertici di bordo
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
2004-12-11 15:53:19 +01:00
|
|
|
|
if(!(*fi).IsD())
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
|
if((*fi).IsB(j))
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
|
|
|
|
TD[(*fi).V0(j)].sum=(*fi).P0(j);
|
|
|
|
|
TD[(*fi).V1(j)].sum=(*fi).P1(j);
|
|
|
|
|
TD[(*fi).V0(j)].cnt=1;
|
|
|
|
|
TD[(*fi).V1(j)].cnt=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2004-12-11 15:53:19 +01:00
|
|
|
|
// se l'edge j e' di bordo si deve mediare solo con gli adiacenti
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
2004-12-11 15:53:19 +01:00
|
|
|
|
if(!(*fi).IsD())
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
|
if((*fi).IsB(j))
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
|
|
|
|
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;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
}
|
2008-07-04 02:32:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-05 07:49:57 +02:00
|
|
|
|
static void VertexCoordLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
|
|
|
|
VertexIterator vi;
|
|
|
|
|
LaplacianInfo lpz(CoordType(0,0,0),0);
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-07-05 07:49:57 +02:00
|
|
|
|
if(cb)cb(100*i/step, "Classic Laplacian Smoothing");
|
2008-07-04 02:32:48 +02:00
|
|
|
|
TD.Init(lpz);
|
|
|
|
|
AccumulateLaplacianInfo(m,TD);
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
{
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
(*vi).P() = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-15 09:10:31 +02:00
|
|
|
|
// Same of above but moves only the vertices that do not change FaceOrientation more that the given threshold
|
|
|
|
|
static void VertexCoordPlanarLaplacian(MeshType &m, int step, float AngleThrRad = math::ToRad(1.0), bool SmoothSelected=false, vcg::CallBackPos * cb=0)
|
|
|
|
|
{
|
|
|
|
|
VertexIterator vi;
|
|
|
|
|
FaceIterator fi;
|
|
|
|
|
LaplacianInfo lpz(CoordType(0,0,0),0);
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
|
|
|
|
if(cb)cb(100*i/step, "Planar Laplacian Smoothing");
|
|
|
|
|
TD.Init(lpz);
|
|
|
|
|
AccumulateLaplacianInfo(m,TD);
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
{
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
TD[*vi].sum = ( (*vi).P() + TD[*vi].sum)/(TD[*vi].cnt+1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi){
|
|
|
|
|
if(!(*fi).IsD()){
|
|
|
|
|
for (int j = 0; j < 3; ++j) {
|
|
|
|
|
if(Angle( NormalizedNormal(TD[(*fi).V0(j)].sum, (*fi).P1(j), (*fi).P2(j) ),
|
|
|
|
|
NormalizedNormal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad )
|
|
|
|
|
TD[(*fi).V0(j)].sum = (*fi).P0(j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi){
|
|
|
|
|
if(!(*fi).IsD()){
|
|
|
|
|
for (int j = 0; j < 3; ++j) {
|
|
|
|
|
if(Angle( NormalizedNormal(TD[(*fi).V0(j)].sum, TD[(*fi).V1(j)].sum, (*fi).P2(j) ),
|
|
|
|
|
NormalizedNormal( (*fi).P0(j) , (*fi).P1(j), (*fi).P2(j) ) ) > AngleThrRad )
|
|
|
|
|
{
|
|
|
|
|
TD[(*fi).V0(j)].sum = (*fi).P0(j);
|
|
|
|
|
TD[(*fi).V1(j)].sum = (*fi).P1(j);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
(*vi).P()= TD[*vi].sum;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}// end step
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2008-07-04 02:32:48 +02:00
|
|
|
|
static void VertexCoordLaplacianBlend(MeshType &m, int step, float alpha, bool SmoothSelected=false)
|
|
|
|
|
{
|
|
|
|
|
VertexIterator vi;
|
|
|
|
|
LaplacianInfo lpz(CoordType(0,0,0),0);
|
|
|
|
|
assert (alpha<= 1.0);
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert);
|
|
|
|
|
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
|
|
|
|
TD.Init(lpz);
|
|
|
|
|
AccumulateLaplacianInfo(m,TD);
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
{
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
{
|
|
|
|
|
CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
|
|
|
|
|
(*vi).P() = (*vi).P() + Delta*alpha;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* a couple of notes about the lambda mu values
|
|
|
|
|
We assume that 0 < lambda , and mu is a negative scale factor such that mu < - lambda.
|
|
|
|
|
Holds mu+lambda < 0 (e.g in absolute value mu is greater)
|
|
|
|
|
|
|
|
|
|
let kpb be the pass-band frequency, taubin says that:
|
|
|
|
|
kpb = 1/lambda + 1/mu >0
|
|
|
|
|
|
|
|
|
|
Values of kpb from 0.01 to 0.1 produce good results according to the original paper.
|
|
|
|
|
|
|
|
|
|
kpb * mu - mu/lambda = 1
|
|
|
|
|
mu = 1/(kpb-1/lambda )
|
|
|
|
|
|
2008-07-05 07:49:57 +02:00
|
|
|
|
So if
|
|
|
|
|
* lambda == 0.5, kpb==0.1 -> mu = 1/(0.1 - 2) = -0.526
|
|
|
|
|
* lambda == 0.5, kpb==0.01 -> mu = 1/(0.01 - 2) = -0.502
|
2008-07-04 02:32:48 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
2008-07-05 07:49:57 +02:00
|
|
|
|
static void VertexCoordTaubin(MeshType &m, int step, float lambda, float mu, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
|
2008-07-04 02:32:48 +02:00
|
|
|
|
{
|
|
|
|
|
LaplacianInfo lpz(CoordType(0,0,0),0);
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
|
|
|
|
|
VertexIterator vi;
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-07-05 07:49:57 +02:00
|
|
|
|
if(cb) cb(100*i/step, "Taubin Smoothing");
|
2008-07-04 02:32:48 +02:00
|
|
|
|
TD.Init(lpz);
|
|
|
|
|
AccumulateLaplacianInfo(m,TD);
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
{
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
{
|
|
|
|
|
CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
|
|
|
|
|
(*vi).P() = (*vi).P() + Delta*lambda ;
|
|
|
|
|
}
|
|
|
|
|
}
|
2008-07-05 07:49:57 +02:00
|
|
|
|
TD.Init(lpz);
|
|
|
|
|
AccumulateLaplacianInfo(m,TD);
|
2008-07-04 02:32:48 +02:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
{
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
{
|
|
|
|
|
CoordType Delta = TD[*vi].sum/TD[*vi].cnt - (*vi).P();
|
2008-07-05 07:49:57 +02:00
|
|
|
|
(*vi).P() = (*vi).P() + Delta*mu ;
|
2008-07-04 02:32:48 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} // end for step
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void VertexCoordLaplacianQuality(MeshType &m, int step, bool SmoothSelected=false)
|
|
|
|
|
{
|
|
|
|
|
LaplacianInfo lpz;
|
|
|
|
|
lpz.sum=CoordType(0,0,0);
|
|
|
|
|
lpz.cnt=1;
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
|
|
|
|
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
|
2008-05-02 11:43:25 +02:00
|
|
|
|
if(!(*vi).IsD() && TD[*vi].cnt>0 )
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
{
|
|
|
|
|
float q=(*vi).Q();
|
|
|
|
|
(*vi).P()=(*vi).P()*q + (TD[*vi].sum/TD[*vi].cnt)*(1.0-q);
|
|
|
|
|
}
|
2008-07-04 02:32:48 +02:00
|
|
|
|
} // end for
|
2004-12-11 15:53:19 +01:00
|
|
|
|
};
|
|
|
|
|
|
2006-10-19 09:33:03 +02:00
|
|
|
|
/*
|
|
|
|
|
Improved Laplacian Smoothing of Noisy Surface Meshes
|
2008-10-27 20:35:17 +01:00
|
|
|
|
J. Vollmer, R. Mencl, and H. M<EFBFBD>ller
|
2006-10-19 09:33:03 +02:00
|
|
|
|
EUROGRAPHICS Volume 18 (1999), Number 3
|
|
|
|
|
*/
|
2004-12-11 15:53:19 +01:00
|
|
|
|
|
|
|
|
|
class HCSmoothInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType dif;
|
|
|
|
|
CoordType sum;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
int cnt;
|
|
|
|
|
};
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
static void VertexCoordLaplacianHC(MeshType &m, int step, bool SmoothSelected=false )
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScalarType beta=0.5;
|
|
|
|
|
HCSmoothInfo lpz;
|
|
|
|
|
lpz.sum=CoordType(0,0,0);
|
|
|
|
|
lpz.dif=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.cnt=0;
|
2009-06-12 01:56:06 +02:00
|
|
|
|
for(int i=0;i<step;++i)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2009-06-12 01:56:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,HCSmoothInfo > TD(m.vert,lpz);
|
|
|
|
|
// First Loop compute the laplacian
|
|
|
|
|
FaceIterator fi;
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)if(!(*fi).IsD())
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-11 15:53:19 +01:00
|
|
|
|
}
|
2009-06-12 01:56:06 +02:00
|
|
|
|
VertexIterator vi;
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
|
|
|
|
|
TD[*vi].sum/=(float)TD[*vi].cnt;
|
|
|
|
|
|
|
|
|
|
// Second Loop compute average difference
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
|
|
|
|
{
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
}
|
2004-12-11 15:53:19 +01:00
|
|
|
|
}
|
|
|
|
|
|
2009-06-12 01:56:06 +02:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
{
|
|
|
|
|
TD[*vi].dif/=(float)TD[*vi].cnt;
|
|
|
|
|
if(!SmoothSelected || (*vi).IsS())
|
|
|
|
|
(*vi).P()= TD[*vi].sum - (TD[*vi].sum - (*vi).P())*beta + (TD[*vi].dif)*(1.f-beta);
|
|
|
|
|
}
|
|
|
|
|
} // end for step
|
2004-12-11 15:53:19 +01:00
|
|
|
|
};
|
|
|
|
|
|
2006-11-07 12:28:02 +01:00
|
|
|
|
// Laplacian smooth of the quality.
|
|
|
|
|
|
2008-05-02 11:43:25 +02:00
|
|
|
|
|
|
|
|
|
class ColorSmoothInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
unsigned int r;
|
|
|
|
|
unsigned int g;
|
|
|
|
|
unsigned int b;
|
|
|
|
|
unsigned int a;
|
|
|
|
|
int cnt;
|
|
|
|
|
};
|
|
|
|
|
|
2008-07-15 09:10:31 +02:00
|
|
|
|
static void VertexColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
|
2008-05-02 11:43:25 +02:00
|
|
|
|
{
|
|
|
|
|
ColorSmoothInfo csi;
|
|
|
|
|
csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer, ColorSmoothInfo> TD(m.vert,csi);
|
2008-05-02 11:43:25 +02:00
|
|
|
|
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-07-15 09:10:31 +02:00
|
|
|
|
if(cb) cb(100*i/step, "Vertex Color Laplacian Smoothing");
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2008-05-02 11:43:25 +02:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=csi;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2008-05-02 11:43:25 +02:00
|
|
|
|
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)].r+=(*fi).V1(j)->C()[0];
|
|
|
|
|
TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1];
|
|
|
|
|
TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2];
|
|
|
|
|
TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3];
|
|
|
|
|
|
|
|
|
|
TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0];
|
|
|
|
|
TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1];
|
|
|
|
|
TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2];
|
|
|
|
|
TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3];
|
|
|
|
|
|
|
|
|
|
++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)]=csi;
|
|
|
|
|
TD[(*fi).V1(j)]=csi;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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)].r+=(*fi).V1(j)->C()[0];
|
|
|
|
|
TD[(*fi).V(j)].g+=(*fi).V1(j)->C()[1];
|
|
|
|
|
TD[(*fi).V(j)].b+=(*fi).V1(j)->C()[2];
|
|
|
|
|
TD[(*fi).V(j)].a+=(*fi).V1(j)->C()[3];
|
|
|
|
|
|
|
|
|
|
TD[(*fi).V1(j)].r+=(*fi).V(j)->C()[0];
|
|
|
|
|
TD[(*fi).V1(j)].g+=(*fi).V(j)->C()[1];
|
|
|
|
|
TD[(*fi).V1(j)].b+=(*fi).V(j)->C()[2];
|
|
|
|
|
TD[(*fi).V1(j)].a+=(*fi).V(j)->C()[3];
|
|
|
|
|
|
|
|
|
|
++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).C()[0] = (unsigned int) ceil((double) (TD[*vi].r / TD[*vi].cnt));
|
|
|
|
|
(*vi).C()[1] = (unsigned int) ceil((double) (TD[*vi].g / TD[*vi].cnt));
|
|
|
|
|
(*vi).C()[2] = (unsigned int) ceil((double) (TD[*vi].b / TD[*vi].cnt));
|
|
|
|
|
(*vi).C()[3] = (unsigned int) ceil((double) (TD[*vi].a / TD[*vi].cnt));
|
|
|
|
|
}
|
2008-06-18 01:05:25 +02:00
|
|
|
|
} // end for step
|
2008-05-02 11:43:25 +02:00
|
|
|
|
};
|
|
|
|
|
|
2008-07-28 10:20:22 +02:00
|
|
|
|
static void FaceColorLaplacian(MeshType &m, int step, bool SmoothSelected=false, vcg::CallBackPos * cb=0)
|
|
|
|
|
{
|
|
|
|
|
ColorSmoothInfo csi;
|
|
|
|
|
csi.r=0; csi.g=0; csi.b=0; csi.cnt=0;
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer, ColorSmoothInfo> TD(m.face,csi);
|
|
|
|
|
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
|
|
|
|
if(cb) cb(100*i/step, "Face Color Laplacian Smoothing");
|
|
|
|
|
FaceIterator fi;
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
TD[*fi]=csi;
|
|
|
|
|
|
|
|
|
|
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].r+=(*fi).FFp(j)->C()[0];
|
|
|
|
|
TD[*fi].g+=(*fi).FFp(j)->C()[1];
|
|
|
|
|
TD[*fi].b+=(*fi).FFp(j)->C()[2];
|
|
|
|
|
TD[*fi].a+=(*fi).FFp(j)->C()[3];
|
|
|
|
|
++TD[*fi].cnt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
if(!(*fi).IsD() && TD[*fi].cnt>0 )
|
|
|
|
|
if(!SmoothSelected || (*fi).IsS())
|
|
|
|
|
{
|
|
|
|
|
(*fi).C()[0] = (unsigned int) ceil((float) (TD[*fi].r / TD[*fi].cnt));
|
|
|
|
|
(*fi).C()[1] = (unsigned int) ceil((float) (TD[*fi].g / TD[*fi].cnt));
|
|
|
|
|
(*fi).C()[2] = (unsigned int) ceil((float) (TD[*fi].b / TD[*fi].cnt));
|
|
|
|
|
(*fi).C()[3] = (unsigned int) ceil((float) (TD[*fi].a / TD[*fi].cnt));
|
|
|
|
|
}
|
|
|
|
|
} // end for step
|
|
|
|
|
};
|
2008-05-02 11:43:25 +02:00
|
|
|
|
|
|
|
|
|
// Laplacian smooth of the quality.
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
2004-12-11 15:53:19 +01:00
|
|
|
|
class QualitySmoothInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScalarType sum;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
int cnt;
|
|
|
|
|
};
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
static void VertexQualityLaplacian(MeshType &m, int step=1, bool SmoothSelected=false)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
QualitySmoothInfo lpz;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.sum=0;
|
|
|
|
|
lpz.cnt=0;
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,QualitySmoothInfo> TD(m.vert,lpz);
|
|
|
|
|
//TD.Start(lpz);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=lpz;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
//VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
//TD.Stop();
|
2004-12-11 15:53:19 +01:00
|
|
|
|
};
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
static void VertexNormalLaplacian(MeshType &m, int step,bool SmoothSelected=false)
|
2004-12-11 15:53:19 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert);
|
|
|
|
|
LaplacianInfo lpz;
|
|
|
|
|
lpz.sum=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.cnt=0;
|
|
|
|
|
TD.Start(lpz);
|
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=lpz;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
//VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
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.
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void VertexCoordViewDepth(MeshType &m,
|
|
|
|
|
const CoordType & viewpoint,
|
|
|
|
|
const ScalarType alpha,
|
2004-12-11 15:53:19 +01:00
|
|
|
|
int step, bool SmoothBorder=false )
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
LaplacianInfo lpz;
|
|
|
|
|
lpz.sum=CoordType(0,0,0);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
lpz.cnt=0;
|
2009-03-20 01:27:07 +01:00
|
|
|
|
SimpleTempData<typename MeshType::VertContainer,LaplacianInfo > TD(m.vert,lpz);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
VertexIterator vi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
TD[*vi]=lpz;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2004-12-11 15:53:19 +01:00
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
if(!(*fi).IsD())
|
|
|
|
|
for(int j=0;j<3;++j)
|
|
|
|
|
if(!(*fi).IsB(j))
|
|
|
|
|
{
|
2009-03-20 01:27:07 +01:00
|
|
|
|
TD[(*fi).V(j)].sum+=(*fi).V1(j)->cP();
|
|
|
|
|
TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP();
|
2004-12-11 15:53:19 +01:00
|
|
|
|
++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))
|
|
|
|
|
{
|
2009-03-20 01:27:07 +01:00
|
|
|
|
TD[(*fi).V(j)].sum+=(*fi).V1(j)->cP();
|
|
|
|
|
TD[(*fi).V1(j)].sum+=(*fi).V(j)->cP();
|
2004-12-11 15:53:19 +01:00
|
|
|
|
++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 )
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType np = TD[*vi].sum/TD[*vi].cnt;
|
2009-03-20 01:27:07 +01:00
|
|
|
|
CoordType d = (*vi).cP() - viewpoint; d.Normalize();
|
|
|
|
|
ScalarType s = d * ( np - (*vi).cP() );
|
|
|
|
|
(*vi).P() += d * (s*alpha);
|
2004-12-11 15:53:19 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
// Paso Double Smoothing
|
2006-09-25 11:41:41 +02:00
|
|
|
|
// The proposed
|
|
|
|
|
// approach is a two step method where in the first step the face normals
|
|
|
|
|
// are adjusted and then, in a second phase, the vertex positions are updated.
|
2005-03-16 17:14:12 +01:00
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
// Classi di info
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
2005-03-16 17:14:12 +01:00
|
|
|
|
class PDVertInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType np;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
};
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
2005-03-16 17:14:12 +01:00
|
|
|
|
class PDFaceInfo
|
|
|
|
|
{
|
|
|
|
|
public:
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType m;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
};
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
// Paso Doble Step 1 compute the smoothed normals
|
|
|
|
|
/***************************************************************************/
|
2006-09-25 11:41:41 +02:00
|
|
|
|
// Requirements:
|
|
|
|
|
// VF Topology
|
|
|
|
|
// Normalized Face Normals
|
|
|
|
|
//
|
|
|
|
|
// This is the Normal Smoothing approach of Shen and Berner
|
|
|
|
|
// Fuzzy Vector Median-Based Surface Smoothing TVCG 2004
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
void FaceNormalFuzzyVectorSB(MeshType &m,
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo > &TD,
|
|
|
|
|
ScalarType sigma)
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
|
|
|
|
int i;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
2005-03-16 17:14:12 +01:00
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
{
|
2006-01-24 14:23:22 +01:00
|
|
|
|
CoordType bc=(*fi).Barycenter();
|
2007-03-27 11:40:47 +02:00
|
|
|
|
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi
|
2005-03-16 17:14:12 +01:00
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
vcg::face::VFIterator<FaceType> ep(&*fi,i);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
while (!ep.End())
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
2007-03-27 11:40:47 +02:00
|
|
|
|
ep.f->ClearV();
|
2005-11-23 17:24:44 +01:00
|
|
|
|
++ep;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2006-09-25 11:41:41 +02:00
|
|
|
|
// 1) Effectively average the normals weighting them with
|
2007-03-27 11:40:47 +02:00
|
|
|
|
(*fi).SetV();
|
2006-01-24 14:23:22 +01:00
|
|
|
|
CoordType mm=CoordType(0,0,0);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
vcg::face::VFIterator<FaceType> ep(&*fi,i);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
while (!ep.End())
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
2007-03-27 11:40:47 +02:00
|
|
|
|
if(! (*ep.f).IsV() )
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
|
|
|
|
if(sigma>0)
|
|
|
|
|
{
|
2006-01-24 14:23:22 +01:00
|
|
|
|
ScalarType dd=SquaredDistance(ep.f->Barycenter(),bc);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
ScalarType ang=AngleN(ep.f->N(),(*fi).N());
|
|
|
|
|
mm+=ep.f->N()*exp((-sigma)*ang*ang/dd);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
else mm+=ep.f->N();
|
2007-03-27 11:40:47 +02:00
|
|
|
|
(*ep.f).SetV();
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
2005-11-23 17:24:44 +01:00
|
|
|
|
++ep;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mm.Normalize();
|
|
|
|
|
TD[*fi].m=mm;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-18 19:48:29 +02:00
|
|
|
|
// Replace the normal of the face with the average of normals of the vertex adijacent faces.
|
|
|
|
|
// Normals are weighted with face area.
|
|
|
|
|
// It assumes that:
|
|
|
|
|
// Normals are normalized:
|
|
|
|
|
// VF adjacency is present.
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void FaceNormalLaplacianVF(MeshType &m)
|
2008-04-18 19:48:29 +02:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face);
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
PDFaceInfo lpzf;
|
|
|
|
|
lpzf.m=CoordType(0,0,0);
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
|
|
|
|
assert(tri::HasVFAdjacency(m));
|
|
|
|
|
TDF.Start(lpzf);
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceIterator fi;
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
tri::UpdateNormals<MeshType>::AreaNormalizeFace(m);
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType bc=Barycenter<FaceType>(*fi);
|
2008-04-18 19:48:29 +02:00
|
|
|
|
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi
|
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
|
|
|
|
VFLocalIterator ep(&*fi,i);
|
|
|
|
|
for (;!ep.End();++ep)
|
|
|
|
|
ep.f->ClearV();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2) Effectively average the normals
|
|
|
|
|
CoordType normalSum=(*fi).N();
|
|
|
|
|
|
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
|
|
|
|
VFLocalIterator ep(&*fi,i);
|
|
|
|
|
for (;!ep.End();++ep)
|
|
|
|
|
{
|
|
|
|
|
if(! (*ep.f).IsV() )
|
|
|
|
|
{
|
|
|
|
|
normalSum += ep.f->N();
|
|
|
|
|
(*ep.f).SetV();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
normalSum.Normalize();
|
|
|
|
|
TDF[*fi].m=normalSum;
|
|
|
|
|
}
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
(*fi).N()=TDF[*fi].m;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
tri::UpdateNormals<MeshType>::NormalizeFace(m);
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
|
|
|
|
TDF.Stop();
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-09 01:50:44 +02:00
|
|
|
|
// Replace the normal of the face with the average of normals of the face adijacent faces.
|
|
|
|
|
// Normals are weighted with face area.
|
|
|
|
|
// It assumes that:
|
|
|
|
|
// Normals are normalized:
|
|
|
|
|
// FF adjacency is present.
|
|
|
|
|
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void FaceNormalLaplacianFF(MeshType &m, int step=1, bool SmoothSelected=false )
|
|
|
|
|
{
|
|
|
|
|
PDFaceInfo lpzf;
|
|
|
|
|
lpzf.m=CoordType(0,0,0);
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
|
2008-05-09 01:50:44 +02:00
|
|
|
|
assert(tri::HasFFAdjacency(m));
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
FaceIterator fi;
|
|
|
|
|
tri::UpdateNormals<MeshType>::AreaNormalizeFace(m);
|
2008-05-09 01:50:44 +02:00
|
|
|
|
for(int i=0;i<step;++i)
|
|
|
|
|
{
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
|
|
|
|
{
|
|
|
|
|
CoordType normalSum=(*fi).N();
|
|
|
|
|
|
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
normalSum+=(*fi).FFp(i)->N();
|
|
|
|
|
|
|
|
|
|
TDF[*fi].m=normalSum;
|
|
|
|
|
}
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
if(!SmoothSelected || (*fi).IsS())
|
|
|
|
|
(*fi).N()=TDF[*fi].m;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
tri::UpdateNormals<MeshType>::NormalizeFace(m);
|
2008-05-09 01:50:44 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-04-18 19:48:29 +02:00
|
|
|
|
|
2006-09-25 11:41:41 +02:00
|
|
|
|
/***************************************************************************/
|
|
|
|
|
// Paso Doble Step 1 compute the smoothed normals
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
// Requirements:
|
|
|
|
|
// VF Topology
|
|
|
|
|
// Normalized Face Normals
|
|
|
|
|
//
|
|
|
|
|
// This is the Normal Smoothing approach bsased on a angle thresholded weighting
|
2007-03-27 11:40:47 +02:00
|
|
|
|
// sigma is in the 0 .. 1 range, it represent the cosine of a threshold angle.
|
2008-04-18 19:48:29 +02:00
|
|
|
|
// sigma == 0 All the normals are averaged
|
|
|
|
|
// sigma == 1 Nothing is averaged.
|
2007-03-27 11:40:47 +02:00
|
|
|
|
// Only within the specified range are averaged toghether. The averagin is weighted with the
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
static void FaceNormalAngleThreshold(MeshType &m,
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer,PDFaceInfo> &TD,
|
|
|
|
|
ScalarType sigma)
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
FaceIterator fi;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
2008-02-07 11:24:51 +01:00
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType bc=Barycenter<FaceType>(*fi);
|
2007-03-27 11:40:47 +02:00
|
|
|
|
// 1) Clear all the visited flag of faces that are vertex-adjacent to fi
|
2006-09-25 11:41:41 +02:00
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
|
|
|
|
VFLocalIterator ep(&*fi,i);
|
|
|
|
|
for (;!ep.End();++ep)
|
2007-03-27 11:40:47 +02:00
|
|
|
|
ep.f->ClearV();
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2007-03-27 11:40:47 +02:00
|
|
|
|
// 1) Effectively average the normals weighting them with the squared difference of the angle similarity
|
|
|
|
|
// sigma is the cosine of a threshold angle. sigma \in 0..1
|
|
|
|
|
// sigma == 0 All the normals are averaged
|
|
|
|
|
// sigma == 1 Nothing is averaged.
|
|
|
|
|
// The averaging is weighted with the difference between normals. more similar the normal more important they are.
|
|
|
|
|
|
|
|
|
|
CoordType normalSum=CoordType(0,0,0);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
for(i=0;i<3;++i)
|
|
|
|
|
{
|
|
|
|
|
VFLocalIterator ep(&*fi,i);
|
|
|
|
|
for (;!ep.End();++ep)
|
|
|
|
|
{
|
2007-03-27 11:40:47 +02:00
|
|
|
|
if(! (*ep.f).IsV() )
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
2008-10-27 20:35:17 +01:00
|
|
|
|
ScalarType cosang=ep.f->N().dot((*fi).N());
|
2009-06-12 01:56:06 +02:00
|
|
|
|
// Note that if two faces form an angle larger than 90 deg, their contribution should be very very small.
|
|
|
|
|
// Without this clamping
|
|
|
|
|
cosang = math::Clamp(cosang,0.0001f,1.f);
|
2007-03-27 11:40:47 +02:00
|
|
|
|
if(cosang >= sigma)
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
|
|
|
|
ScalarType w = cosang-sigma;
|
2007-03-27 11:40:47 +02:00
|
|
|
|
normalSum += ep.f->N()*(w*w); // similar normals have a cosang very close to 1 so cosang - sigma is maximized
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
2007-03-27 11:40:47 +02:00
|
|
|
|
(*ep.f).SetV();
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2007-03-27 11:40:47 +02:00
|
|
|
|
normalSum.Normalize();
|
|
|
|
|
TD[*fi].m=normalSum;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
|
|
|
|
for(fi=m.face.begin();fi!=m.face.end();++fi)
|
|
|
|
|
(*fi).N()=TD[*fi].m;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
// 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.
|
|
|
|
|
// Ottimizzato con Maple e poi pesantemente a mano.
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
CoordType TriAreaGradient(CoordType &p,CoordType &p0,CoordType &p1)
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType dd = p1-p0;
|
|
|
|
|
CoordType d0 = p-p0;
|
|
|
|
|
CoordType d1 = p-p1;
|
|
|
|
|
CoordType grad;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScalarType t16 = d0[1]* d1[2] - d0[2]* d1[1];
|
|
|
|
|
ScalarType t5 = -d0[2]* d1[0] + d0[0]* d1[2];
|
|
|
|
|
ScalarType t4 = -d0[0]* d1[1] + d0[1]* d1[0];
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
ScalarType delta= sqrtf(t4*t4 + t5*t5 +t16*t16);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
grad[0]= (t5 * (-dd[2]) + t4 * ( dd[1]))/delta;
|
|
|
|
|
grad[1]= (t16 * (-dd[2]) + t4 * (-dd[0]))/delta;
|
|
|
|
|
grad[2]= (t16 * ( dd[1]) + t5 * ( dd[0]))/delta;
|
|
|
|
|
|
|
|
|
|
return grad;
|
|
|
|
|
}
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
template <class ScalarType>
|
|
|
|
|
CoordType CrossProdGradient(CoordType &p, CoordType &p0, CoordType &p1, CoordType &m)
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType grad;
|
|
|
|
|
CoordType p00=p0-p;
|
|
|
|
|
CoordType p01=p1-p;
|
2005-12-06 18:55:16 +01:00
|
|
|
|
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[2] = (-p00[1] + p01[1])*m[0] + (-p01[0] + p00[0])*m[1];
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
return grad;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
Deve Calcolare il gradiente di
|
|
|
|
|
E(p) = A(p,p0,p1) (n - m)^2 =
|
|
|
|
|
A(...) (2-2nm) =
|
|
|
|
|
(p0-p)^(p1-p)
|
|
|
|
|
2A - 2A * ------------- m =
|
|
|
|
|
2A
|
|
|
|
|
|
|
|
|
|
2A - 2 (p0-p)^(p1-p) * m
|
|
|
|
|
*/
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
CoordType FaceErrorGrad(CoordType &p,CoordType &p0,CoordType &p1, CoordType &m)
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
|
|
|
|
return TriAreaGradient(p,p0,p1) *2.0f
|
|
|
|
|
- CrossProdGradient(p,p0,p1,m) *2.0f ;
|
|
|
|
|
}
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
// Paso Doble Step 2 Fitta la mesh a un dato insieme di normali
|
|
|
|
|
/***************************************************************************/
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
void FitMesh(MeshType &m,
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
|
2005-03-16 17:14:12 +01:00
|
|
|
|
float lambda)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
//vcg::face::Pos<FaceType> ep;
|
|
|
|
|
vcg::face::VFIterator<FaceType> ep;
|
|
|
|
|
VertexIterator vi;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
{
|
2006-01-24 14:23:22 +01:00
|
|
|
|
CoordType ErrGrad=CoordType(0,0,0);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
ep.f=(*vi).VFp();
|
|
|
|
|
ep.z=(*vi).VFi();
|
|
|
|
|
while (!ep.End())
|
|
|
|
|
{
|
|
|
|
|
ErrGrad+=FaceErrorGrad(ep.f->V(ep.z)->P(),ep.f->V1(ep.z)->P(),ep.f->V2(ep.z)->P(),TDF[ep.f].m);
|
2005-11-23 17:24:44 +01:00
|
|
|
|
++ep;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
2006-01-24 14:23:22 +01:00
|
|
|
|
TDV[*vi].np=(*vi).P()-ErrGrad*(ScalarType)lambda;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
(*vi).P()=TDV[*vi].np;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
/****************************************************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
|
|
|
|
|
static void FastFitMesh(MeshType &m,
|
|
|
|
|
SimpleTempData<typename MeshType::VertContainer, PDVertInfo> &TDV,
|
|
|
|
|
SimpleTempData<typename MeshType::FaceContainer, PDFaceInfo> &TDF,
|
2007-11-06 00:47:20 +01:00
|
|
|
|
bool OnlySelected=false)
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
//vcg::face::Pos<FaceType> ep;
|
|
|
|
|
vcg::face::VFIterator<FaceType> ep;
|
|
|
|
|
VertexIterator vi;
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2006-09-25 11:41:41 +02:00
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
{
|
|
|
|
|
CoordType Sum(0,0,0);
|
|
|
|
|
ScalarType cnt=0;
|
|
|
|
|
VFLocalIterator ep(&*vi);
|
|
|
|
|
for (;!ep.End();++ep)
|
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
CoordType bc=Barycenter<FaceType>(*ep.F());
|
2008-10-27 20:35:17 +01:00
|
|
|
|
Sum += ep.F()->N()*(ep.F()->N().dot(bc - (*vi).P()));
|
2006-09-25 11:41:41 +02:00
|
|
|
|
++cnt;
|
|
|
|
|
}
|
|
|
|
|
TDV[*vi].np=(*vi).P()+ Sum*(1.0/cnt);
|
|
|
|
|
}
|
|
|
|
|
|
2007-11-06 00:47:20 +01:00
|
|
|
|
if(OnlySelected)
|
|
|
|
|
{
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
|
|
|
|
if((*vi).IsS()) (*vi).P()=TDV[*vi].np;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
for(vi=m.vert.begin();vi!=m.vert.end();++vi)
|
2006-09-25 11:41:41 +02:00
|
|
|
|
(*vi).P()=TDV[*vi].np;
|
2007-11-06 00:47:20 +01:00
|
|
|
|
}
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
static void VertexCoordPasoDoble(MeshType &m, int step, typename MeshType::ScalarType Sigma=0, int FitStep=10, typename MeshType::ScalarType FitLambda=0.05)
|
2005-03-16 17:14:12 +01:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert);
|
|
|
|
|
SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face);
|
|
|
|
|
PDVertInfo lpzv;
|
2005-07-11 15:16:34 +02:00
|
|
|
|
lpzv.np=CoordType(0,0,0);
|
2008-05-16 19:44:06 +02:00
|
|
|
|
PDFaceInfo lpzf;
|
2005-07-11 15:16:34 +02:00
|
|
|
|
lpzf.m=CoordType(0,0,0);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
|
|
|
|
assert(m.HasVFTopology());
|
|
|
|
|
m.HasVFTopology();
|
|
|
|
|
TDV.Start(lpzv);
|
|
|
|
|
TDF.Start(lpzf);
|
|
|
|
|
for(int j=0;j<step;++j)
|
|
|
|
|
{
|
|
|
|
|
|
2005-07-11 15:16:34 +02:00
|
|
|
|
vcg::tri::UpdateNormals<MeshType>::PerFace(m);
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceNormalAngleThreshold(m,TDF,Sigma);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
for(int k=0;k<FitStep;k++)
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FitMesh(m,TDV,TDF,FitLambda);
|
2005-03-16 17:14:12 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TDF.Stop();
|
|
|
|
|
TDV.Stop();
|
|
|
|
|
|
|
|
|
|
}
|
2007-03-27 11:40:47 +02:00
|
|
|
|
|
|
|
|
|
// The sigma parameter affect the normal smoothing step
|
|
|
|
|
|
2009-06-12 01:56:06 +02:00
|
|
|
|
static void VertexCoordPasoDobleFast(MeshType &m, int NormalSmoothStep, typename MeshType::ScalarType Sigma=0, int FitStep=50, bool SmoothSelected =false)
|
2006-09-25 11:41:41 +02:00
|
|
|
|
{
|
2008-05-16 19:44:06 +02:00
|
|
|
|
PDVertInfo lpzv;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
lpzv.np=CoordType(0,0,0);
|
2008-05-16 19:44:06 +02:00
|
|
|
|
PDFaceInfo lpzf;
|
2006-09-25 11:41:41 +02:00
|
|
|
|
lpzf.m=CoordType(0,0,0);
|
|
|
|
|
|
2009-06-12 01:56:06 +02:00
|
|
|
|
assert(HasVFAdjacency(m));
|
2008-05-16 19:44:06 +02:00
|
|
|
|
SimpleTempData< typename MeshType::VertContainer, PDVertInfo> TDV(m.vert,lpzv);
|
|
|
|
|
SimpleTempData< typename MeshType::FaceContainer, PDFaceInfo> TDF(m.face,lpzf);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
2009-06-12 01:56:06 +02:00
|
|
|
|
for(int j=0;j<NormalSmoothStep;++j)
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FaceNormalAngleThreshold(m,TDF,Sigma);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
|
|
|
|
|
for(int j=0;j<FitStep;++j)
|
2008-05-16 19:44:06 +02:00
|
|
|
|
FastFitMesh(m,TDV,TDF,SmoothSelected);
|
2006-09-25 11:41:41 +02:00
|
|
|
|
}
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
}; //end Smooth class
|
2005-03-16 17:14:12 +01:00
|
|
|
|
|
2008-05-16 19:44:06 +02:00
|
|
|
|
} // End namespace tri
|
2004-12-11 15:53:19 +01:00
|
|
|
|
} // End namespace vcg
|
|
|
|
|
|
2005-07-11 15:16:34 +02:00
|
|
|
|
#endif // VCG_SMOOTH
|