diff --git a/vcg/complex/local_optimization/tri_edge_flip.h b/vcg/complex/local_optimization/tri_edge_flip.h index c6804473..6ba71ea0 100644 --- a/vcg/complex/local_optimization/tri_edge_flip.h +++ b/vcg/complex/local_optimization/tri_edge_flip.h @@ -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 #include @@ -28,371 +28,385 @@ namespace vcg { - namespace tri +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 + * it is responsible of updating it after a flip has been performed + * This is the simplest edge flipping class. + * It flips an edge only if two adjacent faces are coplanar and the + * quality of the faces improves after the flip. + */ +template 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; + typedef typename TRIMESH_TYPE::VertexType VertexType; + typedef typename TRIMESH_TYPE::ScalarType ScalarType; + typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; + typedef typename TRIMESH_TYPE::CoordType CoordType; + typedef vcg::face::Pos PosType; + typedef typename LocalOptimization::HeapElem HeapElem; + typedef typename LocalOptimization::HeapType HeapType; + + /*! + * the pos of the flipping + */ + PosType _pos; + + /*! + * priority in the heap + */ + ScalarType _priority; + + /*! + * Mark for updating + */ + int _localMark; + + /*! + * mark for up_dating + */ + static int& GlobalMark() { - /** \addtogroup trimesh */ - /* @{ */ + static int im = 0; + return im; + } + +public: + /*! + * Default constructor + */ + inline PlanarEdgeFlip() + { + } + + + /*! + * Constructor with pos type + */ + inline PlanarEdgeFlip(PosType pos, int mark) + { + _pos = pos; + _localMark = mark; + _priority = ComputePriority(); + } + + + /*! + * Copy Constructor + */ + inline PlanarEdgeFlip(const PlanarEdgeFlip &par) + { + _pos = par.GetPos(); + _localMark = par.GetMark(); + _priority = par.Priority(); + } + + + /*! + */ + ~PlanarEdgeFlip() + { + } + + + /*! + * Parameter + */ + static ScalarType &CoplanarAngleThresholdDeg() + { + static ScalarType _CoplanarAngleThresholdDeg = 0.01f; + return _CoplanarAngleThresholdDeg; + } + + inline PosType GetPos() + { + return _pos; + } + + inline int GetMark() + { + return _localMark; + } + + + /*! + * Return the LocalOptimization type + */ + ModifierType IsOfType() + { + return TriEdgeFlipOp; + } + + + /*! + * Check if the pos is updated + */ + bool IsUpToDate() + { + int MostRecentVertexMark = _pos.F()->V(0)->IMark(); + MostRecentVertexMark = vcg::math::Max(MostRecentVertexMark, _pos.F()->V(1)->IMark()); + MostRecentVertexMark = vcg::math::Max(MostRecentVertexMark, _pos.F()->V(2)->IMark()); - /*! - * 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 - * it is responsible of updating it after a flip has been performed - * This is the simplest edge flipping class. - * It flips an edge only if two adjacent faces are coplanar and the - * quality of the faces improves after the flip. - */ - template - 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; - typedef typename TRIMESH_TYPE::VertexType VertexType; - typedef typename TRIMESH_TYPE::ScalarType ScalarType; - typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; - typedef typename TRIMESH_TYPE::CoordType CoordType; - typedef vcg::face::Pos PosType; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; + return ( _localMark >= MostRecentVertexMark ); + } - /*! - * the pos of the flipping - */ - PosType _pos; + /*! + * + Check if this flipping operation can be performed. + It is a topological and geometrical check. + */ + virtual bool IsFeasible() + { + if( math::ToDeg( Angle( _pos.FFlip()->cN() , _pos.F()->cN() ) )> CoplanarAngleThresholdDeg() ) return false; - /*! - * priority in the heap - */ - ScalarType _priority; + 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(); - /*! - * Mark for updating - */ - int _localMark; + // 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; - /*! - * mark for up_dating - */ - static int& GlobalMark() - { - static int im = 0; - return im; - } + return vcg::face::CheckFlipEdge(*_pos.f, _pos.z); + } + /*! + * Compute the priority of this optimization + */ + /* + 1 + /|\ + / | \ + 2 | 3 + \ | / + \|/ + 0 + */ + virtual ScalarType ComputePriority() + { + 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(); - public: - /*! - * Default constructor - */ - inline PlanarEdgeFlip() - {} + ScalarType Qa = Quality(v0,v1,v2); + ScalarType Qb = Quality(v0,v3,v1); - /*! - * Constructor with pos type - */ - inline PlanarEdgeFlip(PosType pos, int mark) - { - _pos = pos; - _localMark = mark; - _priority = ComputePriority(); - } + ScalarType QaAfter = Quality(v1,v2,v3); + ScalarType QbAfter = Quality(v0,v3,v2); - /*! - * Copy Constructor - */ - inline PlanarEdgeFlip(const PlanarEdgeFlip &par) - { - _pos = par.GetPos(); - _localMark = par.GetMark(); - _priority = par.Priority(); - } + // 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(QaAfter,QbAfter) - vcg::math::Min(Qa,Qb) ; + _priority *= -1;*/ + // < 0 if the average quality of faces improves after flip + _priority = ((Qa + Qb) / 2.0) - ((QaAfter + QbAfter) / 2.0); - /*! - */ - ~PlanarEdgeFlip() - { - } + return _priority; + } + /*! + * Return the priority of this optimization + */ + virtual ScalarType Priority() const + { + return _priority; + } - /*! - * Parameter - */ - static ScalarType &CoplanarAngleThresholdDeg() - { - static ScalarType _CoplanarAngleThresholdDeg = 0.01f; - return _CoplanarAngleThresholdDeg; - } + /*! + * Execute the flipping of the edge + */ + void Execute(TRIMESH_TYPE &m) + { + int z = _pos.z; + vcg::face::FlipEdge(*_pos.f, z); + } - inline PosType GetPos() {return _pos;} + /*! + */ + const char* Info(TRIMESH_TYPE &m) + { + static char dump[60]; + sprintf(dump,"%i -> %i %g\n", _pos.F()->V(0)-&m.vert[0], _pos.F()->V(1)-&m.vert[0],-_priority); + return dump; + } - inline int GetMark(){return _localMark;} - - /*! - * Return the LocalOptimization type - */ - ModifierType IsOfType() - { - return TriEdgeFlipOp; - } - - /*! - * Check if the pos is updated - */ - bool IsUpToDate() - { - int MostRecentVertexMark = _pos.F()->V(0)->IMark(); - MostRecentVertexMark = vcg::math::Max(MostRecentVertexMark, _pos.F()->V(1)->IMark()); - MostRecentVertexMark = vcg::math::Max(MostRecentVertexMark, _pos.F()->V(2)->IMark()); - - return ( _localMark >= MostRecentVertexMark ); - } - - /*! - * - Check if this flipping operation can be performed. - It is a topological and geometrical check. - */ - virtual bool IsFeasible() - { - if( math::ToDeg( Angle( _pos.FFlip()->cN() , _pos.F()->cN() ) ) > CoplanarAngleThresholdDeg() ) return false; - return vcg::face::CheckFlipEdge(*_pos.f, _pos.z); - } - - - - /*! - * Compute the priority of this optimization - */ - /* - 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(); - - ScalarType Qa = Quality(v0,v1,v2); - ScalarType Qb = Quality(v0,v2,v3); - - ScalarType QaAfter = Quality(v0,v1,v3); - ScalarType QbAfter = Quality(v1,v2,v3); - - // 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(QaAfter,QbAfter) - vcg::math::Min(Qa,Qb) ; - _priority *=-1; - return _priority; - } - - /*! - * Return the priority of this optimization - */ - virtual ScalarType Priority() const - { - return _priority; - } - - /*! - * Execute the flipping of the edge - */ - void Execute(TRIMESH_TYPE &m) - { - int z = _pos.z; - vcg::face::FlipEdge(*_pos.f, z); - } - - /*! - */ - const char* Info(TRIMESH_TYPE &m) - { - static char dump[60]; - sprintf(dump,"%i -> %i %g\n", _pos.F()->V(0)-&m.vert[0], _pos.F()->V(1)-&m.vert[0],-_priority); - return dump; - } - - /*! - */ - 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() )) ); - } - } //endif - } //endfor - } - } // endif + /*! + */ + static void Init(TRIMESH_TYPE &mesh, HeapType &heap) + { + heap.clear(); + 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 } + } //endfor + } - /*! - */ - void UpdateHeap(HeapType &heap) - { - GlobalMark()++; - PosType pos(_pos.f, _pos.z); - pos.FlipF(); + /*! + */ + virtual void UpdateHeap(HeapType &heap) + { + GlobalMark()++; + PosType pos(_pos.f, _pos.z); + pos.FlipF(); - _pos.F()->V(0)->IMark() = GlobalMark(); - _pos.F()->V(1)->IMark() = GlobalMark(); - _pos.F()->V(2)->IMark() = GlobalMark(); - pos.F()->V(2)->IMark() = GlobalMark(); + _pos.F()->V(0)->IMark() = GlobalMark(); + _pos.F()->V(1)->IMark() = GlobalMark(); + _pos.F()->V(2)->IMark() = GlobalMark(); + 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() ) ) ); - } + PosType poss(_pos.f, _pos.z); - poss.FlipE(); poss.FlipV(); poss.FlipE(); - if(!poss.IsBorder() ) - { - heap.push_back( HeapElem( new MYTYPE( PosType(poss.f, poss.z), GlobalMark() ) ) ); - } + poss.FlipV(); poss.FlipE(); + if(!poss.IsBorder()) + heap.push_back(HeapElem(new MYTYPE(poss, GlobalMark()))); - pos.FlipE(); - if(!poss.IsBorder()) - { - 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()))); - pos.FlipE(); pos.FlipV(); pos.FlipE(); - if(!poss.IsBorder()) - { - 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()))); - std::push_heap(heap.begin(),heap.end()); - } - }; // end of PlanarEdgeFlip class + 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 - template - class TriEdgeFlip : public PlanarEdgeFlip - { - protected: - typedef typename TRIMESH_TYPE::FaceType FaceType; - typedef typename TRIMESH_TYPE::FacePointer FacePointer; - typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; - typedef typename TRIMESH_TYPE::VertexType VertexType; - typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; - typedef typename TRIMESH_TYPE::ScalarType ScalarType; - typedef typename TRIMESH_TYPE::CoordType CoordType; - typedef vcg::face::Pos PosType; - typedef typename LocalOptimization::HeapElem HeapElem; - typedef typename LocalOptimization::HeapType HeapType; - - typedef typename vcg::Triangle3 TriangleType; - - public: - /*! - * Default constructor - */ - inline TriEdgeFlip() {} - - /*! - * Constructor with pos type - */ - inline TriEdgeFlip(const PosType pos, int mark) - { - this->_pos = pos; - this->_localMark = mark; - this->_priority = ComputePriority(); - } +template +class TriEdgeFlip : public PlanarEdgeFlip +{ +protected: + typedef typename TRIMESH_TYPE::FaceType FaceType; + typedef typename TRIMESH_TYPE::FacePointer FacePointer; + typedef typename TRIMESH_TYPE::FaceIterator FaceIterator; + typedef typename TRIMESH_TYPE::VertexType VertexType; + typedef typename TRIMESH_TYPE::VertexPointer VertexPointer; + typedef typename TRIMESH_TYPE::ScalarType ScalarType; + typedef typename TRIMESH_TYPE::CoordType CoordType; + typedef vcg::face::Pos PosType; + typedef typename LocalOptimization::HeapElem HeapElem; + typedef typename LocalOptimization::HeapType HeapType; - /*! - * Copy Constructor - */ - inline TriEdgeFlip(const TriEdgeFlip &par) - { - this->_pos = par.GetPos(); - this->_localMark = par.GetMark(); - this->_priority = par.Priority(); - } + typedef typename vcg::Triangle3 TriangleType; +public: + /*! + * Default constructor + */ + inline TriEdgeFlip() {} - //only topology check - bool IsFeasible() - { - return vcg::face::CheckFlipEdge(*this->_pos.f, this->_pos.z); - } + /*! + * Constructor with pos type + */ + inline TriEdgeFlip(const PosType pos, int mark) + { + this->_pos = pos; + this->_localMark = mark; + this->_priority = ComputePriority(); + } + /*! + * Copy Constructor + */ + inline TriEdgeFlip(const TriEdgeFlip &par) + { + this->_pos = par.GetPos(); + this->_localMark = par.GetMark(); + this->_priority = par.Priority(); + } - ScalarType ComputePriority() - { - /* - 0 - /|\ - / | \ - 1 | 3 - \ | / - \|/ - 2 - */ - CoordType v0,v1,v2,v3; - PosType app = this->_pos; + //only topology check + /*bool IsFeasible() + { + return vcg::face::CheckFlipEdge(*this->_pos.f, this->_pos.z); + }*/ - 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())); + ScalarType ComputePriority() + { + /* + 1 + /|\ + / | \ + 2 | 3 + \ | / + \|/ + 0 + */ + 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(); - ScalarType Radius= Distance(v0,CircumCenter); - ScalarType Radius1= Distance(v1,CircumCenter); - ScalarType Radius2= Distance(v2,CircumCenter); + //CoordType CircumCenter = vcg::Circumcenter(*(app.F())); + CoordType circumcenter = vcg::Circumcenter(*(this->_pos.F())); - assert( fabs(Radius-Radius1) < 0.1 ); - assert( fabs(Radius-Radius2) < 0.1 ); + /*ScalarType Radius= Distance(v0,CircumCenter); + ScalarType Radius1= Distance(v1,CircumCenter); + ScalarType Radius2= Distance(v2,CircumCenter); - ///Return the difference of radius and the distance of v3 and the CircumCenter - this->_priority = (Radius - Distance(v3,CircumCenter)); - this->_priority *=-1; - - return this->_priority; - } - - }; + assert( fabs(Radius-Radius1) < 0.1 ); + assert( fabs(Radius-Radius2) < 0.1 );*/ - /*! @} */ - }; // end of namespace tri + 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 = (radius2 - Distance(v3, circumcenter)); + this->_priority *= -1;*/ + + this->_priority = (Distance(v3, circumcenter) - radius2); + + return this->_priority; + } + +}; + +/*! @} */ +}; // end of namespace tri }; // end of namespace vcg