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

@ -42,8 +42,8 @@ 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
template <class TRIMESH_TYPE, class MYTYPE> class PlanarEdgeFlip :
public LocalOptimization< TRIMESH_TYPE>::LocModType
{
protected:
typedef typename TRIMESH_TYPE::FaceType FaceType;
@ -81,13 +81,14 @@ namespace vcg
return im;
}
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
*/
@ -158,48 +168,64 @@ namespace vcg
virtual bool IsFeasible()
{
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
*/
/*
1
/|\
/ | \
2 | 3
\ | /
\|/
0
/|\
/ | \
1 | 3
\ | /
\|/
2
*/
virtual ScalarType ComputePriority()
{
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,29 +287,23 @@ 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();
poss.FlipV(); poss.FlipE();
if(!poss.IsBorder())
{
heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) );
}
heap.push_back(HeapElem(new MYTYPE(poss, 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();
poss.FlipF(); 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();
if(!poss.IsBorder())
heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
std::push_heap(heap.begin(),heap.end());
}
@ -345,48 +353,54 @@ 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()
{
/*
1
/|\
/ | \
2 | 3
\ | /
\|/
0
/|\
/ | \
1 | 3
\ | /
\|/
2
*/
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;
}