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 *
* 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. *
* *
****************************************************************************/
* 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. *
* *
****************************************************************************/
#include <vcg/complex/local_optimization.h>
#include <vcg/simplex/face/topology.h>
@ -28,12 +28,12 @@
namespace vcg
{
namespace tri
{
/** \addtogroup trimesh */
/* @{ */
namespace tri
{
/** \addtogroup trimesh */
/* @{ */
/*!
/*!
* This Class is specialization of LocalModification for the edge flip
* 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
@ -42,10 +42,10 @@ namespace vcg
* It flips an edge only if two adjacent faces are coplanar and the
* quality of the faces improves after the flip.
*/
template <class TRIMESH_TYPE, class MYTYPE>
class PlanarEdgeFlip : public LocalOptimization< TRIMESH_TYPE >::LocModType
{
protected:
template <class TRIMESH_TYPE, class MYTYPE> class PlanarEdgeFlip :
public LocalOptimization< TRIMESH_TYPE>::LocModType
{
protected:
typedef typename TRIMESH_TYPE::FaceType FaceType;
typedef typename TRIMESH_TYPE::FacePointer FacePointer;
typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
@ -81,13 +81,14 @@ namespace vcg
return im;
}
public:
public:
/*!
* Default constructor
*/
inline PlanarEdgeFlip()
{}
{
}
/*!
* Constructor with <I>pos</I> type
@ -99,6 +100,7 @@ namespace vcg
_priority = ComputePriority();
}
/*!
* Copy Constructor
*/
@ -126,9 +128,16 @@ namespace vcg
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
@ -138,6 +147,7 @@ namespace vcg
return TriEdgeFlipOp;
}
/*!
* Check if the pos is updated
*/
@ -157,49 +167,65 @@ namespace vcg
*/
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);
}
/*!
* Compute the priority of this optimization
*/
/*
0
1
/|\
/ | \
1 | 3
2 | 3
\ | /
\|/
2
0
*/
virtual ScalarType ComputePriority()
{
CoordType v0,v1,v2,v3;
CoordType v0, v1, v2, v3;
PosType app = _pos;
v0 = app.v->P();
app.FlipE(); app.FlipV();
v1 = app.v->P();
app.FlipE(); app.FlipV();
v2 = app.v->P();
app.FlipE(); app.FlipF(); app.FlipE(); app.FlipV();
v3 = app.v->P();
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();
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 QbAfter = Quality(v1,v2,v3);
ScalarType QaAfter = Quality(v1,v2,v3);
ScalarType QbAfter = Quality(v0,v3,v2);
// higher the quality better the triangle.
// swaps that improve the worst quality more are performed before
// (e.g. they have an higher priority)
_priority = vcg::math::Max<ScalarType>(QaAfter,QbAfter) - vcg::math::Min<ScalarType>(Qa,Qb) ;
_priority *=-1;
/*_priority = vcg::math::Max<ScalarType>(QaAfter,QbAfter) - vcg::math::Min<ScalarType>(Qa,Qb) ;
_priority *= -1;*/
// < 0 if the average quality of faces improves after flip
_priority = ((Qa + Qb) / 2.0) - ((QaAfter + QbAfter) / 2.0);
return _priority;
}
@ -234,34 +260,22 @@ namespace vcg
static void Init(TRIMESH_TYPE &mesh, HeapType &heap)
{
heap.clear();
FaceIterator f_iter;
for (f_iter = mesh.face.begin(); f_iter!=mesh.face.end(); ++f_iter)
{
if (! (*f_iter).IsD() )
{
//if(!(Selected && !(*f_iter).IsS()))
if( (*f_iter).V(0)->IsW() && (*f_iter).V(1)->IsW() && (*f_iter).V(2)->IsW())
{
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() )) );
}
FaceIterator fi;
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()) {
for(unsigned int i = 0; i < 3; i++) {
if( !(*fi).IsB(i) && (*fi).FFp(i)->V2((*fi).FFi(i))->IsW() ) {
if((*fi).V1(i) - (*fi).V0(i) > 0)
heap.push_back( HeapElem( new MYTYPE(PosType(&*fi, i), mesh.IMark() )) );
} //endif
} //endfor
}
} // endif
} //endfor
}
/*!
*/
void UpdateHeap(HeapType &heap)
virtual void UpdateHeap(HeapType &heap)
{
GlobalMark()++;
PosType pos(_pos.f, _pos.z);
@ -273,39 +287,33 @@ namespace vcg
pos.F()->V(2)->IMark() = GlobalMark();
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();
if(!poss.IsBorder() )
{
heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) );
}
pos.FlipE();
poss.FlipV(); poss.FlipE();
if(!poss.IsBorder())
{
heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, pos.z), GlobalMark() ) ) );
}
heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
pos.FlipE(); pos.FlipV(); pos.FlipE();
poss.FlipV(); poss.FlipE();
if(!poss.IsBorder())
{
heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, pos.z), GlobalMark() ) ) );
}
heap.push_back(HeapElem(new MYTYPE(poss, 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());
}
}; // end of PlanarEdgeFlip class
}; // end of PlanarEdgeFlip class
template <class TRIMESH_TYPE, class MYTYPE>
class TriEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE>
{
protected:
template <class TRIMESH_TYPE, class MYTYPE>
class TriEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE>
{
protected:
typedef typename TRIMESH_TYPE::FaceType FaceType;
typedef typename TRIMESH_TYPE::FacePointer FacePointer;
typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
@ -319,7 +327,7 @@ namespace vcg
typedef typename vcg::Triangle3<ScalarType> TriangleType;
public:
public:
/*!
* Default constructor
*/
@ -345,54 +353,60 @@ namespace vcg
this->_priority = par.Priority();
}
//only topology check
bool IsFeasible()
/*bool IsFeasible()
{
return vcg::face::CheckFlipEdge(*this->_pos.f, this->_pos.z);
}
}*/
ScalarType ComputePriority()
{
/*
0
1
/|\
/ | \
1 | 3
2 | 3
\ | /
\|/
2
0
*/
CoordType v0,v1,v2,v3;
CoordType v0, v1, v2, v3;
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();
app.FlipE(); app.FlipV();
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()));
CoordType circumcenter = vcg::Circumcenter(*(this->_pos.F()));
CoordType CircumCenter = vcg::Circumcenter(*(app.F()));
ScalarType Radius= Distance(v0,CircumCenter);
/*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 );
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
this->_priority = (Radius - Distance(v3,CircumCenter));
this->_priority *=-1;
/*this->_priority = (radius2 - Distance(v3, circumcenter));
this->_priority *= -1;*/
this->_priority = (Distance(v3, circumcenter) - radius2);
return this->_priority;
}
};
};
/*! @} */
}; // end of namespace tri
/*! @} */
}; // end of namespace tri
}; // end of namespace vcg