Significant Change.

Removed old quality from geodesic function. Use the Geodesic class that has a singleCall wrapper doing the same in a eventually better way. 
Added a number of RequireXXX at the beginning. To be completed...
This commit is contained in:
Paolo Cignoni 2013-07-24 12:00:47 +00:00
parent ac7b0c1bb1
commit f9db54196b
1 changed files with 70 additions and 153 deletions

View File

@ -8,7 +8,7 @@
* \ * * \ *
* All rights reserved. * * All rights reserved. *
* * * *
* This program is free software; you can redistribute it and/or modify * * 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 * * it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or * * the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. * * (at your option) any later version. *
@ -33,11 +33,11 @@
namespace vcg { namespace vcg {
namespace tri { namespace tri {
/// \ingroup trimesh /// \ingroup trimesh
/// \headerfile quality.h vcg/complex/algorithms/update/quality.h /// \headerfile quality.h vcg/complex/algorithms/update/quality.h
/// \brief Generation of per-vertex and per-face qualities. /// \brief Generation of per-vertex and per-face qualities.
/** /**
It works according to various strategy, like geodesic distance from the border (UpdateQuality::VertexGeodesicFromBorder) or curvature ecc. It works according to various strategy, like geodesic distance from the border (UpdateQuality::VertexGeodesicFromBorder) or curvature ecc.
This class is templated over the mesh and (like all other Update* classes) has only static members; Typical usage: This class is templated over the mesh and (like all other Update* classes) has only static members; Typical usage:
@ -51,7 +51,7 @@ template <class UpdateMeshType>
class UpdateQuality class UpdateQuality
{ {
public: public:
typedef UpdateMeshType MeshType; typedef UpdateMeshType MeshType;
typedef typename MeshType::ScalarType ScalarType; typedef typename MeshType::ScalarType ScalarType;
typedef typename MeshType::VertexType VertexType; typedef typename MeshType::VertexType VertexType;
typedef typename MeshType::VertexPointer VertexPointer; typedef typename MeshType::VertexPointer VertexPointer;
@ -60,133 +60,22 @@ public:
typedef typename MeshType::FacePointer FacePointer; typedef typename MeshType::FacePointer FacePointer;
typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::FaceIterator FaceIterator;
class VQualityHeap
{
public:
float q;
VertexPointer p;
inline VQualityHeap( VertexPointer np )
{
q = np->Q();
p = np;
}
// Attenzione il minore e' maggiore
inline bool operator < ( const VQualityHeap & vq ) const { return q > vq.q; }
inline bool operator == ( const VQualityHeap & vq ) const { return q == vq.q; }
inline bool operator > ( const VQualityHeap & vq ) const { return q < vq.q; }
inline bool operator != ( const VQualityHeap & vq ) const { return q != vq.q; }
inline bool operator <= ( const VQualityHeap & vq ) const { return q >= vq.q; }
inline bool operator >= ( const VQualityHeap & vq ) const { return q <= vq.q; }
inline bool is_valid() const { return q==p->Q(); }
};
// *** IMPORTANT REQUIREMENTS
// VF topology
// Border FLags
// tri::UpdateTopology<SMesh>::VertexFace(sm);
// tri::UpdateFlags<SMesh>::FaceBorderFromVF(sm);
//
// Calcola la qualita' come distanza geodesica dal bordo della mesh.
// Robusta funziona anche per mesh non manifold.
// La qualita' memorizzata indica la distanza assoluta dal bordo della mesh.
// Nota prima del 13/11/03 in alcuni casi rari SPT andava in loop perche' poteva capitare
// che per approx numeriche ben strane pw->Q() > pv->Q()+d ma durante la memorizzazione
// della nuova distanza essa rimanesse uguale a prima. Patchato rimettendo i vertici nello
// heap solo se migliorano la distanza di un epsilon == 1/100000 della mesh diag.
/// \brief Compute, for each vertex of the mesh the geodesic distance from the border of the mesh itself.
/**
It uses the classical Dijkstra Shortest Path Tree algorithm.
The geodesic distance is approximated by allowing to walk only along edges of the mesh.
\warning VF topology, Per Vertex Quality and border flags already computed (see UpdateFlags::FaceBorderFromVF and UpdateTopology::VertexFace);
*/
static void VertexGeodesicFromBorder(MeshType &m) // R1
{
//Requirements
assert(HasPerVertexVFAdjacency(m) && HasPerFaceVFAdjacency(m));
assert(HasPerVertexQuality(m));
std::vector< VQualityHeap > heap;
VertexIterator v;
FaceIterator f;
int j;
for(v=m.vert.begin();v!=m.vert.end();++v)
(*v).Q() = -1;
for(f=m.face.begin();f!=m.face.end();++f) // Inserisco nell'heap i v di bordo
if(!(*f).IsD())
for(j=0;j<3;++j)
if( (*f).IsB(j) )
{
for(int k=0;k<2;++k)
{
VertexPointer pv = (*f).V((j+k)%3);
if( pv->Q()==-1 )
{
pv->Q() = 0;
heap.push_back(VQualityHeap(pv));
}
}
}
const ScalarType loc_eps=m.bbox.Diag()/ScalarType(100000);
while( heap.size()!=0 ) // Shortest path tree
{
VertexPointer pv;
std::pop_heap(heap.begin(),heap.end());
if( ! heap.back().is_valid() )
{
heap.pop_back();
continue;
}
pv = heap.back().p;
heap.pop_back();
for(face::VFIterator<FaceType> vfi(pv) ; !vfi.End(); ++vfi )
{
for(int k=0;k<2;++k)
{
VertexPointer pw;
float d;
if(k==0) pw = vfi.f->V1(vfi.z);
else pw = vfi.f->V2(vfi.z);
d = Distance(pv->P(),pw->P());
if( pw->Q()==-1 || pw->Q() > pv->Q()+d + loc_eps)
{
pw->Q() = pv->Q()+d;
heap.push_back(VQualityHeap(pw));
std::push_heap(heap.begin(),heap.end());
}
}
}
}
for(v=m.vert.begin();v!=m.vert.end();++v)
if(v->Q()==-1)
v->Q() = 0;
}
/** Assign to each vertex of the mesh a constant quality value. Useful for initialization. /** Assign to each vertex of the mesh a constant quality value. Useful for initialization.
*/ */
static void VertexConstant(MeshType &m, float q) static void VertexConstant(MeshType &m, float q)
{ {
VertexIterator vi; tri::RequirePerVertexQuality(m);
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).Q()=q; (*vi).Q()=q;
} }
/** Clamp each vertex of the mesh with a range of values. /** Clamp each vertex of the mesh with a range of values.
*/ */
static void VertexClamp(MeshType &m, float qmin, float qmax) static void VertexClamp(MeshType &m, float qmin, float qmax)
{ {
VertexIterator vi; tri::RequirePerVertexQuality(m);
for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).Q()=std::min(qmax, std::max(qmin,(*vi).Q())); (*vi).Q()=std::min(qmax, std::max(qmin,(*vi).Q()));
} }
@ -194,6 +83,7 @@ static void VertexClamp(MeshType &m, float qmin, float qmax)
*/ */
static void VertexNormalize(MeshType &m, float qmin=0.0, float qmax=1.0) static void VertexNormalize(MeshType &m, float qmin=0.0, float qmax=1.0)
{ {
tri::RequirePerVertexQuality(m);
ScalarType deltaRange = qmax-qmin; ScalarType deltaRange = qmax-qmin;
std::pair<ScalarType,ScalarType> minmax = tri::Stat<MeshType>::ComputePerVertexQualityMinMax(m); std::pair<ScalarType,ScalarType> minmax = tri::Stat<MeshType>::ComputePerVertexQualityMinMax(m);
VertexIterator vi; VertexIterator vi;
@ -205,10 +95,10 @@ static void VertexNormalize(MeshType &m, float qmin=0.0, float qmax=1.0)
*/ */
static void FaceNormalize(MeshType &m, float qmin=0.0, float qmax=1.0) static void FaceNormalize(MeshType &m, float qmin=0.0, float qmax=1.0)
{ {
tri::RequirePerFaceQuality(m);
ScalarType deltaRange = qmax-qmin; ScalarType deltaRange = qmax-qmin;
std::pair<ScalarType,ScalarType> minmax = tri::Stat<MeshType>::ComputePerFaceQualityMinMax(m); std::pair<ScalarType,ScalarType> minmax = tri::Stat<MeshType>::ComputePerFaceQualityMinMax(m);
FaceIterator fi; for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
for(fi = m.face.begin(); fi != m.face.end(); ++fi)
(*fi).Q() = qmin+deltaRange*((*fi).Q() - minmax.first)/(minmax.second - minmax.first); (*fi).Q() = qmin+deltaRange*((*fi).Q() - minmax.first)/(minmax.second - minmax.first);
} }
@ -216,27 +106,54 @@ static void FaceNormalize(MeshType &m, float qmin=0.0, float qmax=1.0)
*/ */
static void FaceConstant(MeshType &m, float q) static void FaceConstant(MeshType &m, float q)
{ {
FaceIterator fi; tri::RequirePerFaceQuality(m);
for(fi=m.face.begin();fi!=m.face.end();++fi) for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
(*fi).Q()=q; (*fi).Q()=q;
} }
/** Assign to each face of the mesh its double area. /** Assign to each face of the mesh its area.
*/ */
static void FaceArea(MeshType &m) static void FaceArea(MeshType &m)
{ {
FaceIterator fi; tri::RequirePerFaceQuality(m);
for(fi=m.face.begin();fi!=m.face.end();++fi) for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
(*fi).Q()=vcg::DoubleArea(*fi)/2; (*fi).Q()=vcg::DoubleArea(*fi)/ScalarType(2.0);
}
static void VertexFromFace( MeshType &m, bool areaWeighted=true)
{
tri::RequirePerFaceQuality(m);
tri::RequirePerVertexQuality(m);
SimpleTempData<typename MeshType::VertContainer, ScalarType> TQ(m.vert,0);
SimpleTempData<typename MeshType::VertContainer, ScalarType> TCnt(m.vert,0);
for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
if(!(*fi).IsD())
{
ScalarType weight=1.0;
if(areaWeighted) weight = vcg::DoubleArea(*fi);
for(int j=0;j<3;++j)
{
TQ[(*fi).V(j)]+=(*fi).Q();
TCnt[(*fi).V(j)]+=weight;
}
}
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi)
if(!(*vi).IsD() && TCnt[*vi]>0 )
{
(*vi).Q() = TQ[*vi] / TCnt[*vi];
}
} }
static void FaceFromVertex( MeshType &m) static void FaceFromVertex( MeshType &m)
{ {
FaceIterator fi; tri::RequirePerFaceQuality(m);
for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) tri::RequirePerVertexQuality(m);
{ for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD())
(*fi).Q() = ((*fi).V(0)->Q()+(*fi).V(1)->Q()+(*fi).V(2)->Q())/3.0f; {
} (*fi).Q() = ((*fi).V(0)->Q()+(*fi).V(1)->Q()+(*fi).V(2)->Q())/3.0f;
}
} }
static void VertexFromPlane(MeshType &m, const Plane3<ScalarType> &pl) static void VertexFromPlane(MeshType &m, const Plane3<ScalarType> &pl)
@ -246,19 +163,19 @@ static void VertexFromPlane(MeshType &m, const Plane3<ScalarType> &pl)
} }
static void VertexFromGaussianCurvatureHG(MeshType &m) static void VertexFromGaussianCurvatureHG(MeshType &m)
{ {
tri::RequirePerVertexQuality(m); tri::RequirePerVertexQuality(m);
tri::RequirePerVertexCurvature(m); tri::RequirePerVertexCurvature(m);
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).Q() = (*vi).Kg(); (*vi).Q() = (*vi).Kg();
} }
static void VertexFromMeanCurvatureHG(MeshType &m) static void VertexFromMeanCurvatureHG(MeshType &m)
{ {
tri::RequirePerVertexQuality(m); tri::RequirePerVertexQuality(m);
tri::RequirePerVertexCurvature(m); tri::RequirePerVertexCurvature(m);
for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) for(VertexIterator vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD())
(*vi).Q() = (*vi).Kh(); (*vi).Q() = (*vi).Kh();
} }
static void VertexFromGaussianCurvatureDir(MeshType &m) static void VertexFromGaussianCurvatureDir(MeshType &m)
@ -278,45 +195,45 @@ static void VertexFromMeanCurvatureDir(MeshType &m)
} }
/* /*
* Absolute Curvature * Absolute Curvature
* *
* 2|H| if K >= 0 * 2|H| if K >= 0
* |k1| + |k2| = < * |k1| + |k2| = <
* 2 * sqrt(|H|^2-K) otherwise * 2 * sqrt(|H|^2-K) otherwise
* *
* defs and formulas taken from * defs and formulas taken from
* *
* Improved curvature estimation for watershed segmentation of 3-dimensional meshes * Improved curvature estimation for watershed segmentation of 3-dimensional meshes
* S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001 * S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001
* and from * and from
* Optimizing 3D triangulations using discrete curvature analysis * Optimizing 3D triangulations using discrete curvature analysis
* N Dyn, K Hormann, SJ Kim, D Levin - Mathematical Methods for Curves and Surfaces: Oslo, 2000 * N Dyn, K Hormann, SJ Kim, D Levin - Mathematical Methods for Curves and Surfaces: Oslo, 2000
*/ */
static void VertexFromAbsoluteCurvature(MeshType &m) static void VertexFromAbsoluteCurvature(MeshType &m)
{ {
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())
{ {
if((*vi).Kg() >= 0) if((*vi).Kg() >= 0)
(*vi).Q() = math::Abs( 2*(*vi).Kh() ); (*vi).Q() = math::Abs( 2*(*vi).Kh() );
else else
(*vi).Q() = 2*math::Sqrt(math::Abs( (*vi).Kh()*(*vi).Kh() - (*vi).Kg())); (*vi).Q() = 2*math::Sqrt(math::Abs( (*vi).Kh()*(*vi).Kh() - (*vi).Kg()));
} }
} }
/* /*
* RMS Curvature = sqrt(4H^2-2K) * RMS Curvature = sqrt(4H^2-2K)
* def and formula taken from * def and formula taken from
* *
* Improved curvature estimation for watershed segmentation of 3-dimensional meshes * Improved curvature estimation for watershed segmentation of 3-dimensional meshes
* S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001 * S Pulla, A Razdan, G Farin - Arizona State University, Tech. Rep, 2001
*/ */
static void VertexFromRMSCurvature(MeshType &m) static void VertexFromRMSCurvature(MeshType &m)
{ {
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())
(*vi).Q() = math::Sqrt(math::Abs( 4*(*vi).Kh()*(*vi).Kh() - 2*(*vi).Kg())); (*vi).Q() = math::Sqrt(math::Abs( 4*(*vi).Kh()*(*vi).Kh() - 2*(*vi).Kg()));
} }