/**************************************************************************** * 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 namespace vcg { 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 optimizatin 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 */ template class TriEdgeFlip : 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::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; /*! * 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() { static int im = 0; return im; }; public: /*! * static data to gather statistical information * about the reasons of collapse failures */ struct FailStat { static int &Volume() {static int vol=0; return vol;} static int &LinkConditionFace(){static int lkf=0; return lkf;} static int &LinkConditionEdge(){static int lke=0; return lke;} static int &LinkConditionVert(){static int lkv=0; return lkv;} static int &OutOfDate() {static int ofd=0; return ofd;} static int &Border() {static int bor=0; return bor;} static void Init() { Volume() =0; LinkConditionFace()=0; LinkConditionEdge()=0; LinkConditionVert()=0; OutOfDate() =0; Border() =0; } }; /*! * Default constructor */ inline TriEdgeFlip() {}; /*! * Constructor with pos type */ inline TriEdgeFlip(PosType pos, int mark) { _pos = pos; _localMark = mark; _priority = ComputePriority(); }; /*! */ ~TriEdgeFlip() { }; /*! * Return the LocalOptimization type */ ModifierType IsOfType() { return TriEdgeFlipOp; }; /*! * Check if the pos is updated */ bool IsUpToDate() { VertexPointer v0 = _pos.V(0); VertexPointer v1 = _pos.V(1); if ((v0->IsD()) || (v1->IsD()) || _localMark < vcg::math::Min< int >( v0->IMark(), v1->IMark())) { ++FailStat::OutOfDate(); return false; } return true; }; /*! * Check if this flipping operation can be performed */ bool IsFeasible() { return vcg::face::CheckFlipEdge(*_pos.f, _pos.z); }; /*! * Compute the priority of this optimization */ ScalarType ComputePriority() { FacePointer f = _pos.f; int z = _pos.z; const ScalarType RatioThr = 20; const ScalarType AngleThr = (ScalarType)(M_PI/3600.0); int z1 = (*f).FFi(z); FacePointer f1 = (*f).FFp(z); VertexType *vx = (*f).FFp(z)->V2(z1); // ... ->V2((*f).FFi(z)); CoordType &n0 = (*f).N(); CoordType &n1 = (*f1).N(); CoordType &n0d = (*f).FFp1(z)->N(); CoordType &n0u = (*f).FFp2(z)->N(); CoordType &n1d = (*f1).FFp1(z1)->N(); CoordType &n1u = (*f1).FFp2(z1)->N(); ScalarType a01 = AngleN((*f).N(),(*f1).N()); ScalarType e01 = vcg::Distance((*f).V(z)->cP(), (*f).V1(z)->cP() ); ScalarType e01f = vcg::Distance((*f).V2(z)->cP(), vx->cP() ); //Compute Edge Lenght Note that border edges are lenght 0 ScalarType e0d = (vcg::face::IsBorder(*f, 1)) ? 0 : Distance((*f).V1(z)->cP(), (*f).V2(z)->cP() ) ; ScalarType e0u = (vcg::face::IsBorder(*f, 2)) ? 0 : Distance((*f).V(z)->cP() , (*f).V2(z)->cP() ); ScalarType e1d = (vcg::face::IsBorder(*f1, (z1+1)%3)) ? 0 : Distance((*f).V1(z)->cP(), vx->cP() ); ScalarType e1u = (vcg::face::IsBorder(*f1, (z1+2)%3)) ? 0 : Distance((*f).V(z)->cP() , vx->cP() ); CoordType n01u = ((vx->cP() - (*f).V(z)->cP()) ^ ((*f).V2(z)->cP() - (*f).V(z)->cP())).Normalize(); CoordType n01d = (((*f).V1(z)->cP() - vx->cP()) ^ ((*f).V2(z)->cP() - vx->cP())).Normalize(); ScalarType a01f = vcg::AngleN(n01u,n01d); ScalarType af0u = vcg::AngleN(n01u,n0u); ScalarType af0d = vcg::AngleN(n01d,n0d); ScalarType af1u = vcg::AngleN(n01u,n1u); ScalarType af1d = vcg::AngleN(n01d,n1d); e01 = e01f = e0d = e1d = e0u = e1u = 1; //pezza per pesare solo gli angoli!!! ScalarType OldCurvature = math::Max(e01*a01, math::Max(e0u*vcg::AngleN(n0,n0u), math::Max( e0d*vcg::AngleN(n0,n0d), math::Max(e1u*vcg::AngleN(n1,n1u) , e1d*vcg::AngleN(n1,n1d))))); ScalarType NewCurvature = math::Max(e01f*a01f, math::Max(e0u*AngleN(n01u,n0u), math::Max( e0d*vcg::AngleN(n01d,n0d), math::Max(e1u*vcg::AngleN(n01u,n1u), e1d*vcg::AngleN(n01d,n1d))))); _priority = (NewCurvature+AngleThr) - OldCurvature; return _priority; }; /*! * Return the priority of this optimization */ ScalarType Priority() const { return _priority; }; /*! * Execute the flipping of the edge */ void Execute(TRIMESH_TYPE &m) { vcg::face::FlipEdge(*_pos.f, _pos.z); }; /*! */ const char* Info(TRIMESH_TYPE &m) { static char dump[60]; sprintf(dump,"%i -> %i %g\n", _pos.V(0)-&m.vert[0], _pos.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() ) { for (unsigned int i=0; i<3; i++) { VertexPointer v0 = (*f_iter).V(i); VertexPointer v1 = (*f_iter).V((i+1)%3); if (v1-v0 > 0) heap.push_back( HeapElem( new MYTYPE(PosType(&*f_iter, i), mesh.IMark()) ) ); } // endfor } // endif } //endfor }; /*! */ void UpdateHeap(HeapType &heap) { GlobalMark()++; PosType pos(_pos.f, _pos.z); pos.FlipF(); _pos.f->V1(_pos.z)->IMark() = GlobalMark(); _pos.f->V2(_pos.z)->IMark() = GlobalMark(); pos.f->V1(pos.z)->IMark() = GlobalMark(); pos.f->V2(pos.z)->IMark() = GlobalMark(); if (_pos.f->V2(_pos.z) - _pos.f->V1(_pos.z) > 0) heap.push_back( HeapElem( new MYTYPE( PosType(_pos.f, (_pos.z+1)%3, _pos.f->V1(_pos.z)), GlobalMark() ) ) ); if (_pos.f->V(_pos.z) - _pos.f->V2(_pos.z) >0 ) heap.push_back( HeapElem( new MYTYPE( PosType(_pos.f, (_pos.z+2)%3, _pos.f->V2(_pos.z)), GlobalMark() ) ) ); if (pos.f->V2(pos.z) - pos.f->V1(pos.z) > 0) heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, (pos.z+1)%3, pos.f->V1(pos.z)), GlobalMark() ) ) ); if (pos.f->V(pos.z) - pos.f->V2(pos.z) > 0) heap.push_back( HeapElem( new MYTYPE( PosType(pos.f, (pos.z+2)%3, pos.f->V2(pos.z)), GlobalMark() ) ) ); std::push_heap(heap.begin(),heap.end()); }; }; // end of TriEdgeFlip class /*! @} */ }; // end of namespace tri }; // end of namespace vcg