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
|
* 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;
|
||||||
|
|
@ -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
|
||||||
*/
|
*/
|
||||||
|
|
@ -158,48 +168,64 @@ 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
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
|
1
|
||||||
|
/|\
|
||||||
|
/ | \
|
||||||
|
2 | 3
|
||||||
|
\ | /
|
||||||
|
\|/
|
||||||
0
|
0
|
||||||
/|\
|
|
||||||
/ | \
|
|
||||||
1 | 3
|
|
||||||
\ | /
|
|
||||||
\|/
|
|
||||||
2
|
|
||||||
*/
|
*/
|
||||||
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,29 +287,23 @@ 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())
|
if(!poss.IsBorder())
|
||||||
{
|
heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark())));
|
||||||
heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
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() ) ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
pos.FlipE(); pos.FlipV(); pos.FlipE();
|
poss.FlipV(); poss.FlipE();
|
||||||
|
poss.FlipF(); 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();
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
|
@ -345,48 +353,54 @@ 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()
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
1
|
||||||
|
/|\
|
||||||
|
/ | \
|
||||||
|
2 | 3
|
||||||
|
\ | /
|
||||||
|
\|/
|
||||||
0
|
0
|
||||||
/|\
|
|
||||||
/ | \
|
|
||||||
1 | 3
|
|
||||||
\ | /
|
|
||||||
\|/
|
|
||||||
2
|
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue