Added a test to avoid degenerative flip which produce two identical overlapping faces.

Little code refactoring.
The planar swap now try to improve the average quality of faces, instead of improving the quality of the worst face.
This commit is contained in:
Paolo Cignoni 2008-03-20 15:45:54 +00:00
parent c2bec8758d
commit 3e090a41ff
1 changed files with 365 additions and 351 deletions

View File

@ -1,25 +1,25 @@
/**************************************************************************** /****************************************************************************
* VCGLib o o * * VCGLib o o *
* Visual and Computer Graphics Library o o * * Visual and Computer Graphics Library o o *
* _ O _ * * _ O _ *
* Copyright(C) 2004 \/)\/ * * Copyright(C) 2004 \/)\/ *
* Visual Computing Lab /\/| * * Visual Computing Lab /\/| *
* ISTI - Italian National Research Council | * * ISTI - Italian National Research Council | *
* \ * * \ *
* 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. *
* * * *
* This program is distributed in the hope that it will be useful, * * This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of * * but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
* for more details. * * for more details. *
* * * *
****************************************************************************/ ****************************************************************************/
#include <vcg/complex/local_optimization.h> #include <vcg/complex/local_optimization.h>
#include <vcg/simplex/face/topology.h> #include <vcg/simplex/face/topology.h>
@ -28,12 +28,12 @@
namespace vcg namespace vcg
{ {
namespace tri namespace tri
{ {
/** \addtogroup trimesh */ /** \addtogroup trimesh */
/* @{ */ /* @{ */
/*! /*!
* This Class is specialization of LocalModification for the edge flip * This Class is specialization of LocalModification for the edge flip
* It wraps the atomic operation EdgeFlip to be used in a optimization routine. * It wraps the atomic operation EdgeFlip to be used in a optimization routine.
* Note that it has knowledge of the heap of the class LocalOptimization because * Note that it has knowledge of the heap of the class LocalOptimization because
@ -42,10 +42,10 @@ namespace vcg
* It flips an edge only if two adjacent faces are coplanar and the * It flips an edge only if two adjacent faces are coplanar and the
* quality of the faces improves after the flip. * quality of the faces improves after the flip.
*/ */
template <class TRIMESH_TYPE, class MYTYPE> template <class TRIMESH_TYPE, class MYTYPE> class PlanarEdgeFlip :
class PlanarEdgeFlip : public LocalOptimization< TRIMESH_TYPE >::LocModType public LocalOptimization< TRIMESH_TYPE>::LocModType
{ {
protected: protected:
typedef typename TRIMESH_TYPE::FaceType FaceType; typedef typename TRIMESH_TYPE::FaceType FaceType;
typedef typename TRIMESH_TYPE::FacePointer FacePointer; typedef typename TRIMESH_TYPE::FacePointer FacePointer;
typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
@ -81,13 +81,14 @@ namespace vcg
return im; return im;
} }
public:
public:
/*! /*!
* Default constructor * Default constructor
*/ */
inline PlanarEdgeFlip() inline PlanarEdgeFlip()
{} {
}
/*! /*!
* Constructor with <I>pos</I> type * Constructor with <I>pos</I> type
@ -99,6 +100,7 @@ namespace vcg
_priority = ComputePriority(); _priority = ComputePriority();
} }
/*! /*!
* Copy Constructor * Copy Constructor
*/ */
@ -126,9 +128,16 @@ namespace vcg
return _CoplanarAngleThresholdDeg; return _CoplanarAngleThresholdDeg;
} }
inline PosType GetPos() {return _pos;} inline PosType GetPos()
{
return _pos;
}
inline int GetMark()
{
return _localMark;
}
inline int GetMark(){return _localMark;}
/*! /*!
* Return the LocalOptimization type * Return the LocalOptimization type
@ -138,6 +147,7 @@ namespace vcg
return TriEdgeFlipOp; return TriEdgeFlipOp;
} }
/*! /*!
* Check if the pos is updated * Check if the pos is updated
*/ */
@ -157,49 +167,65 @@ namespace vcg
*/ */
virtual bool IsFeasible() virtual bool IsFeasible()
{ {
if( math::ToDeg( Angle( _pos.FFlip()->cN() , _pos.F()->cN() ) ) > CoplanarAngleThresholdDeg() ) return false; if( math::ToDeg( Angle( _pos.FFlip()->cN() , _pos.F()->cN() ) )> CoplanarAngleThresholdDeg() ) return false;
CoordType v0, v1, v2, v3;
PosType app = _pos;
int i = _pos.I();
v0 = app.F()->V0(i)->P();
v1 = app.F()->V1(i)->P();
v2 = app.F()->V2(i)->P();
app.FlipF(); app.FlipE(); app.FlipV();
v3 = app.V()->P();
// Take the parallelogram formed by the adjacent faces of edge
// If a corner of the parallelogram on extreme of edge to flip is >= 180
// the flip produce two identical faces - avoid this
if( (Angle(v2 - v0, v1 - v0) + Angle(v3 - v0, v1 - v0) >= M_PI) ||
(Angle(v2 - v1, v0 - v1) + Angle(v3 - v1, v0 - v1) >= M_PI))
return false;
return vcg::face::CheckFlipEdge(*_pos.f, _pos.z); return vcg::face::CheckFlipEdge(*_pos.f, _pos.z);
} }
/*! /*!
* Compute the priority of this optimization * Compute the priority of this optimization
*/ */
/* /*
0 1
/|\ /|\
/ | \ / | \
1 | 3 2 | 3
\ | / \ | /
\|/ \|/
2 0
*/ */
virtual ScalarType ComputePriority() virtual ScalarType ComputePriority()
{ {
CoordType v0, v1, v2, v3;
CoordType v0,v1,v2,v3;
PosType app = _pos; PosType app = _pos;
int i = _pos.I();
v0 = app.v->P(); v0 = app.F()->V0(i)->P();
app.FlipE(); app.FlipV(); v1 = app.F()->V1(i)->P();
v1 = app.v->P(); v2 = app.F()->V2(i)->P();
app.FlipE(); app.FlipV(); app.FlipF(); app.FlipE(); app.FlipV();
v2 = app.v->P(); v3 = app.V()->P();
app.FlipE(); app.FlipF(); app.FlipE(); app.FlipV();
v3 = app.v->P();
ScalarType Qa = Quality(v0,v1,v2); ScalarType Qa = Quality(v0,v1,v2);
ScalarType Qb = Quality(v0,v2,v3); ScalarType Qb = Quality(v0,v3,v1);
ScalarType QaAfter = Quality(v0,v1,v3); ScalarType QaAfter = Quality(v1,v2,v3);
ScalarType QbAfter = Quality(v1,v2,v3); ScalarType QbAfter = Quality(v0,v3,v2);
// higher the quality better the triangle. // higher the quality better the triangle.
// swaps that improve the worst quality more are performed before // swaps that improve the worst quality more are performed before
// (e.g. they have an higher priority) // (e.g. they have an higher priority)
_priority = vcg::math::Max<ScalarType>(QaAfter,QbAfter) - vcg::math::Min<ScalarType>(Qa,Qb) ; /*_priority = vcg::math::Max<ScalarType>(QaAfter,QbAfter) - vcg::math::Min<ScalarType>(Qa,Qb) ;
_priority *=-1; _priority *= -1;*/
// < 0 if the average quality of faces improves after flip
_priority = ((Qa + Qb) / 2.0) - ((QaAfter + QbAfter) / 2.0);
return _priority; return _priority;
} }
@ -234,34 +260,22 @@ namespace vcg
static void Init(TRIMESH_TYPE &mesh, HeapType &heap) static void Init(TRIMESH_TYPE &mesh, HeapType &heap)
{ {
heap.clear(); heap.clear();
FaceIterator f_iter; FaceIterator fi;
for (f_iter = mesh.face.begin(); f_iter!=mesh.face.end(); ++f_iter) for(fi = mesh.face.begin(); fi != mesh.face.end(); ++fi) {
{ if(!(*fi).IsD() && (*fi).V(0)->IsW() && (*fi).V(1)->IsW() && (*fi).V(2)->IsW()) {
if (! (*f_iter).IsD() ) for(unsigned int i = 0; i < 3; i++) {
{ if( !(*fi).IsB(i) && (*fi).FFp(i)->V2((*fi).FFi(i))->IsW() ) {
//if(!(Selected && !(*f_iter).IsS())) if((*fi).V1(i) - (*fi).V0(i) > 0)
if( (*f_iter).V(0)->IsW() && (*f_iter).V(1)->IsW() && (*f_iter).V(2)->IsW()) heap.push_back( HeapElem( new MYTYPE(PosType(&*fi, i), mesh.IMark() )) );
{
for (unsigned int i=0; i<3; i++)
{
if( !(*f_iter).IsB(i) && (*f_iter).FFp(i)->V2((*f_iter).FFi(i) )->IsW() )
{
VertexPointer v0 = (*f_iter).V0(i);
VertexPointer v1 = (*f_iter).V1(i);
if (v1-v0 > 0)
{
heap.push_back( HeapElem( new MYTYPE(PosType(&*f_iter, i), mesh.IMark() )) );
}
} //endif } //endif
} //endfor } //endfor
} }
} // endif
} //endfor } //endfor
} }
/*! /*!
*/ */
void UpdateHeap(HeapType &heap) virtual void UpdateHeap(HeapType &heap)
{ {
GlobalMark()++; GlobalMark()++;
PosType pos(_pos.f, _pos.z); PosType pos(_pos.f, _pos.z);
@ -273,39 +287,33 @@ namespace vcg
pos.F()->V(2)->IMark() = GlobalMark(); pos.F()->V(2)->IMark() = GlobalMark();
PosType poss(_pos.f, _pos.z); PosType poss(_pos.f, _pos.z);
poss.FlipE();
if(!poss.IsBorder())
{
heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) );
}
poss.FlipE(); poss.FlipV(); poss.FlipE(); poss.FlipV(); poss.FlipE();
if(!poss.IsBorder() )
{
heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) );
}
pos.FlipE();
if(!poss.IsBorder()) if(!poss.IsBorder())
{ heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, pos.z), GlobalMark() ) ) );
}
pos.FlipE(); pos.FlipV(); pos.FlipE(); poss.FlipV(); poss.FlipE();
if(!poss.IsBorder()) if(!poss.IsBorder())
{ heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, pos.z), GlobalMark() ) ) );
} poss.FlipV(); poss.FlipE();
poss.FlipF(); poss.FlipE();
if(!poss.IsBorder())
heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
poss.FlipV(); poss.FlipE();
if(!poss.IsBorder())
heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
std::push_heap(heap.begin(),heap.end()); std::push_heap(heap.begin(),heap.end());
} }
}; // end of PlanarEdgeFlip class }; // end of PlanarEdgeFlip class
template <class TRIMESH_TYPE, class MYTYPE> template <class TRIMESH_TYPE, class MYTYPE>
class TriEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE> class TriEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE>
{ {
protected: protected:
typedef typename TRIMESH_TYPE::FaceType FaceType; typedef typename TRIMESH_TYPE::FaceType FaceType;
typedef typename TRIMESH_TYPE::FacePointer FacePointer; typedef typename TRIMESH_TYPE::FacePointer FacePointer;
typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
@ -319,7 +327,7 @@ namespace vcg
typedef typename vcg::Triangle3<ScalarType> TriangleType; typedef typename vcg::Triangle3<ScalarType> TriangleType;
public: public:
/*! /*!
* Default constructor * Default constructor
*/ */
@ -345,54 +353,60 @@ namespace vcg
this->_priority = par.Priority(); this->_priority = par.Priority();
} }
//only topology check //only topology check
bool IsFeasible() /*bool IsFeasible()
{ {
return vcg::face::CheckFlipEdge(*this->_pos.f, this->_pos.z); return vcg::face::CheckFlipEdge(*this->_pos.f, this->_pos.z);
} }*/
ScalarType ComputePriority() ScalarType ComputePriority()
{ {
/* /*
0 1
/|\ /|\
/ | \ / | \
1 | 3 2 | 3
\ | / \ | /
\|/ \|/
2 0
*/ */
CoordType v0,v1,v2,v3; CoordType v0, v1, v2, v3;
PosType app = this->_pos; PosType app = this->_pos;
int i = this->_pos.I();
v0 = app.F()->V0(i)->P();
v1 = app.F()->V1(i)->P();
v2 = app.F()->V2(i)->P();
app.FlipF(); app.FlipE(); app.FlipV();
v3 = app.V()->P();
v0 = app.v->P(); //CoordType CircumCenter = vcg::Circumcenter(*(app.F()));
app.FlipE(); app.FlipV(); CoordType circumcenter = vcg::Circumcenter(*(this->_pos.F()));
v1 = app.v->P();
app.FlipE(); app.FlipV();
v2 = app.v->P();
app.FlipE(); app.FlipF(); app.FlipE(); app.FlipV();
v3 = app.v->P();
CoordType CircumCenter = vcg::Circumcenter(*(app.F())); /*ScalarType Radius= Distance(v0,CircumCenter);
ScalarType Radius= Distance(v0,CircumCenter);
ScalarType Radius1= Distance(v1,CircumCenter); ScalarType Radius1= Distance(v1,CircumCenter);
ScalarType Radius2= Distance(v2,CircumCenter); ScalarType Radius2= Distance(v2,CircumCenter);
assert( fabs(Radius-Radius1) < 0.1 ); assert( fabs(Radius-Radius1) < 0.1 );
assert( fabs(Radius-Radius2) < 0.1 ); assert( fabs(Radius-Radius2) < 0.1 );*/
ScalarType radius = Distance(v0, circumcenter);
ScalarType radius1 = Distance(v1, circumcenter);
ScalarType radius2 = Distance(v2, circumcenter);
assert( fabs(radius - radius1) < 0.1 );
assert( fabs(radius - radius2) < 0.1 );
///Return the difference of radius and the distance of v3 and the CircumCenter ///Return the difference of radius and the distance of v3 and the CircumCenter
this->_priority = (Radius - Distance(v3,CircumCenter)); /*this->_priority = (radius2 - Distance(v3, circumcenter));
this->_priority *=-1; this->_priority *= -1;*/
this->_priority = (Distance(v3, circumcenter) - radius2);
return this->_priority; return this->_priority;
} }
}; };
/*! @} */ /*! @} */
}; // end of namespace tri }; // end of namespace tri
}; // end of namespace vcg }; // end of namespace vcg