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:
parent
c2bec8758d
commit
3e090a41ff
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue