diff --git a/vcg/complex/algorithms/hole.h b/vcg/complex/algorithms/hole.h index dc4a8887..ba28d65f 100644 --- a/vcg/complex/algorithms/hole.h +++ b/vcg/complex/algorithms/hole.h @@ -19,120 +19,6 @@ * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * -****************************************************************************/ -/**************************************************************************** -History - -$Log: not supported by cvs2svn $ -Revision 1.34 2007/01/31 15:25:49 giec -Remove some usless code in Minimum Weight Triangulation. - -Revision 1.33 2007/01/31 11:46:12 giec -Bug fix - -Revision 1.32 2007/01/18 18:15:14 cignoni -added missing typenames - -Revision 1.31 2007/01/18 11:17:43 giec -The minimum weight algorithm keep the topology consistent. - -Revision 1.30 2007/01/10 12:07:54 giec -Bugfixed ComputeDihedralAngle function - -Revision 1.29 2006/12/27 15:09:52 giec -Bug fix on ComputeDihedralAngle function - -Revision 1.28 2006/12/12 11:14:51 cignoni -Commented some variant of the quality measure of weighted ears - -Revision 1.27 2006/12/07 00:40:18 cignoni -Added many this-> for gcc compiling - -Revision 1.26 2006/12/06 13:03:59 cignoni -Corrected bugs on selfintersection - -Revision 1.25 2006/12/06 00:12:53 cignoni -Heavily restructured and corrected. Now a single Close ear function -Corrected Hole search function, and management of double non manifold vertex in a hole -Changed priority strategy in the heap, now a mix of quality and dihedral angle. -Changed but still untested IntersectionEar - -Revision 1.24 2006/12/01 21:24:16 cignoni -Corrected bug in the search of holes. Removed output prints - -Revision 1.23 2006/12/01 08:53:55 cignoni -Corrected pop_heap vs pop_back issue in heap usage - -Revision 1.22 2006/12/01 00:11:17 cignoni -Added Callback, Corrected some spelling errors (adiacense -> adjacency). -Added Validity Check function for hole loops - -Revision 1.21 2006/11/30 11:49:20 cignoni -small gcc compiling issues - -Revision 1.20 2006/11/29 16:21:45 cignoni -Made static exposed funtions of the class - -Revision 1.19 2006/11/29 15:25:22 giec -Removed limit. - -Revision 1.18 2006/11/29 15:18:49 giec -Code refactory and bugfix. - -Revision 1.17 2006/11/24 10:42:39 mariolatronico -Now compiles on gcc under linux. - -Revision 1.16 2006/11/22 13:43:28 giec -Code refactory and added minimum weight triangolation. - -Revision 1.15 2006/11/13 10:11:38 giec -Clear some useless code - -Revision 1.14 2006/11/07 15:13:56 zifnab1974 -Necessary changes for compilation with gcc 3.4.6. Especially the hash function is a problem - -Revision 1.13 2006/11/07 11:47:11 cignoni -gcc compiling issues - -Revision 1.12 2006/11/07 07:56:43 cignoni -Added missing std:: - -Revision 1.11 2006/11/06 16:12:29 giec -Leipa ear now compute max dihedral angle. - -Revision 1.10 2006/10/31 11:30:41 ganovelli -changed access throught iterator with static call to comply 2005 compiler - -Revision 1.9 2006/10/20 07:44:45 cignoni -Added missing std:: - -Revision 1.8 2006/10/18 15:06:47 giec -New policy for compute quality in TrivialEar. -Bugfixed LeipaEar. -Added new algorithm "selfintersection" with test for self intersection. - -Revision 1.7 2006/10/10 09:12:02 giec -Bugfix and added a new type of ear (Liepa like) - -Revision 1.6 2006/10/09 10:07:07 giec -Optimized version of "EAR HOLE FILLING", the Ear is selected according to its dihedral angle. - -Revision 1.5 2006/10/06 15:28:14 giec -first working implementationof "EAR HOLE FILLING". - -Revision 1.4 2006/10/02 12:06:40 giec -BugFix - -Revision 1.3 2006/09/27 15:33:32 giec -It close one simple hole . . . - -Revision 1.2 2006/09/27 09:29:53 giec -Frist working release whit a few bugs. -It almost fills the hole ... - -Revision 1.1 2006/09/25 09:17:44 cignoni -First Non working Version - ****************************************************************************/ #ifndef __VCG_TRI_UPDATE_HOLE #define __VCG_TRI_UPDATE_HOLE @@ -140,301 +26,282 @@ First Non working Version #include #include #include -#include -#include #include +// This file contains three Ear Classes +// - TrivialEar +// - MinimumWeightEar +// - SelfIntersectionEar +// and a static class Hole for filling holes that is templated on the ear class + + + namespace vcg { namespace tri { - /* - Un ear e' identificato da due hedge pos. - i vertici dell'ear sono - e0.VFlip().v - e0.v - e1.v - Vale che e1== e0.NextB(); - e che e1.FlipV() == e0; - Situazioni ear non manifold, e degeneri (buco triangolare) + /* + An ear is identified by TWO pos. + The Three vertexes of an Ear are: + e0.VFlip().v + e0.v + e1.v + Invariants: + e1 == e0.NextB(); + e1.FlipV() == e0; - T XXXXXXXXXXXXX A /XXXXX B en/XXXXX - /XXXXXXXXXXXXXXX /XXXXXX /XXXXXX - XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX - XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX - XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX - XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX - XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX - XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX - XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX - */ - template class TrivialEar - { - public: - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename face::Pos PosType; - typedef typename MESH::ScalarType ScalarType; - typedef typename MESH::CoordType CoordType; + Situazioni ear non manifold, e degeneri (buco triangolare) - PosType e0; - PosType e1; - CoordType n; // the normal of the face defined by the ear - const char * Dump() {return 0;} - const CoordType &cP(int i) const {return P(i);} - const CoordType &P(int i) const { - switch(i) { - case 0 : return e0.v->cP(); - case 1 : return e1.v->cP(); - case 2 : return e0.VFlip()->cP(); - default: assert(0); - } - return e0.v->cP(); - } + T XXXXXXXXXXXXX A /XXXXX B en/XXXXX + /XXXXXXXXXXXXXXX /XXXXXX /XXXXXX + XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX + XXXXXX ----/| XX ------ ----/| XX ------ ----/|XXX + XXXXXX| /e1 XX XXXXXX| /e1 XX XXXXXX| o/e0 XX + XXXXXX| /XXXXXX XXXXXX| /XXXXXX XXXXXX| /XXXXXX + XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX + XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX + XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX + */ +template class TrivialEar +{ +public: + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FacePointer FacePointer; + typedef typename face::Pos PosType; + typedef typename MESH::ScalarType ScalarType; + typedef typename MESH::CoordType CoordType; - ScalarType quality; - ScalarType angle; - //std::vector* vf; - TrivialEar(){} - TrivialEar(const PosType & ep) - { - e0=ep; - assert(e0.IsBorder()); - e1=e0; - e1.NextB(); - n=vcg::Normal(*this); - ComputeQuality(); - ComputeAngle(); - } + PosType e0; + PosType e1; + CoordType n; // the normal of the face defined by the ear + const char * Dump() {return 0;} + // The following members are useful to consider the Ear as a generic + // with p0 the 'center' of the ear. + const CoordType &cP(int i) const {return P(i);} + const CoordType &P(int i) const { + switch(i) { + case 0 : return e0.v->cP(); + case 1 : return e1.v->cP(); + case 2 : return e0.VFlip()->cP(); + default: assert(0); + } + return e0.v->cP(); + } - /// Compute the angle of the two edges of the ear. - // it tries to make the computation in a precision safe way. - // the angle computation takes into account the case of reversed ears - void ComputeAngle() - { - angle=Angle(cP(2)-cP(0), cP(1)-cP(0)); - ScalarType flipAngle = n.dot(e0.v->N()); - if(flipAngle<0) angle = (2.0 *(float)M_PI) - angle; - } + ScalarType quality; + ScalarType angleRad; + TrivialEar(){} + TrivialEar(const PosType & ep) + { + e0=ep; + assert(e0.IsBorder()); + e1=e0; + e1.NextB(); + n=vcg::Normal(*this); + ComputeQuality(); + ComputeAngle(); + } - virtual inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; } + /// Compute the angle of the two edges of the ear. + // it tries to make the computation in a precision safe way. + // the angle computation takes into account the case of reversed ears + void ComputeAngle() + { + angleRad=Angle(cP(2)-cP(0), cP(1)-cP(0)); + ScalarType flipAngle = n.dot(e0.v->N()); + if(flipAngle<0) angleRad = (2.0 *(ScalarType)M_PI) - angleRad; + } - bool IsNull(){return e0.IsNull() || e1.IsNull();} - void SetNull(){e0.SetNull();e1.SetNull();} - virtual void ComputeQuality() { quality = QualityFace(*this) ; }; - bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());}; - // An ear is degenerated if both of its two endpoints are non manifold. - bool IsDegen(const int nonManifoldBit) + virtual inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; } + + bool IsNull(){return e0.IsNull() || e1.IsNull();} + void SetNull(){e0.SetNull();e1.SetNull();} + virtual void ComputeQuality() { quality = QualityFace(*this) ; } + bool IsUpToDate() {return ( e0.IsBorder() && e1.IsBorder());} + // An ear is degenerated if both of its two endpoints are non manifold. + bool IsDegen(const int nonManifoldBit) + { + if(e0.VFlip()->IsUserBit(nonManifoldBit) && e1.V()->IsUserBit(nonManifoldBit)) + return true; + else return false; + } + bool IsConcave() const {return(angleRad > (float)M_PI);} + + virtual bool Close(PosType &np0, PosType &np1, FaceType * f) + { + // simple topological check + if(e0.f==e1.f) { + //printf("Avoided bad ear"); + return false; + } + + //usato per generare una delle due nuove orecchie. + PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 + PosType en=e1; en.NextB(); // he successivo a e1 + + (*f).V(0) = e0.VFlip(); + (*f).V(1) = e0.v; + (*f).V(2) = e1.v; + ComputeNormal(*f); + + face::FFAttachManifold(f,0,e0.f,e0.z); + face::FFAttachManifold(f,1,e1.f,e1.z); + face::FFSetBorder(f,2); + + // caso ear degenere per buco triangolare + if(ep==en) + { + //printf("Closing the last triangle"); + face::FFAttachManifold(f,2,en.f,en.z); + np0.SetNull(); + np1.SetNull(); + } + // Caso ear non manifold a + else if(ep.v==en.v) + { + //printf("Ear Non manif A\n"); + PosType enold=en; + en.NextB(); + face::FFAttachManifold(f,2,enold.f,enold.z); + np0=ep; + np1=en; + } + // Caso ear non manifold b + else if(ep.VFlip()==e1.v) + { + //printf("Ear Non manif B\n"); + PosType epold=ep; + ep.FlipV(); ep.NextB(); ep.FlipV(); + face::FFAttachManifold(f,2,epold.f,epold.z); + np0=ep; // assign the two new + np1=en; // pos that denote the ears + } + else // caso standard // Now compute the new ears; + { + np0=ep; + np1=PosType(f,2,e1.v); + } + + return true; + } + +}; // end TrivialEar Class + +//Ear with FillHoleMinimumWeight's quality policy +template class MinimumWeightEar : public TrivialEar +{ +public: + static float &DiedralWeight() { static float _dw=0.1; return _dw;} + typedef TrivialEar TE; + typename MESH::ScalarType dihedralRad; + typename MESH::ScalarType aspectRatio; + const char * Dump() { + static char buf[200]; + if(this->IsConcave()) sprintf(buf,"Dihedral -(deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); + else sprintf(buf,"Dihedral (deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); + return buf; + } + + MinimumWeightEar(){} + MinimumWeightEar(const typename face::Pos& ep) : TrivialEar(ep) + { + ComputeQuality(); + } + + // In the heap, by default, we retrieve the LARGEST value, + // so if we need the ear with minimal dihedral angle, we must reverse the sign of the comparison. + // The concave elements must be all in the end of the heap, sorted accordingly, + // So if only one of the two ear is Concave that one is always the minimum one. + // the pow function is here just to give a way to play with different weighting schemas, balancing in a different way + + virtual inline bool operator < ( const MinimumWeightEar & c ) const + { + if(TE::IsConcave() && ! c.IsConcave() ) return true; + if(!TE::IsConcave() && c.IsConcave() ) return false; + + return aspectRatio - (dihedralRad/M_PI)*DiedralWeight() < c.aspectRatio -(c.dihedralRad/M_PI)*DiedralWeight(); + +// return (pow((float)dihedralRad,(float)DiedralWeight())/aspectRatio) > (pow((float)c.dihedralRad,(float)DiedralWeight())/c.aspectRatio); + } + + // the real core of the whole hole filling strategy. + virtual void ComputeQuality() + { + //compute quality by (dihedral ancgle, area/sum(edge^2) ) + typename MESH::CoordType n1=TE::e0.FFlip()->cN(); + typename MESH::CoordType n2=TE::e1.FFlip()->cN(); + + dihedralRad = std::max(Angle(TE::n,n1),Angle(TE::n,n2)); + aspectRatio = QualityFace(*this); + } + +}; // end class MinimumWeightEar + + +//Ear for selfintersection algorithm +template class SelfIntersectionEar : public MinimumWeightEar +{ +public: + typedef typename MESH::FaceType FaceType; + typedef typename MESH::FacePointer FacePointer; + typedef typename face::Pos PosType; + typedef typename MESH::ScalarType ScalarType; + typedef typename MESH::CoordType CoordType; + + static std::vector &AdjacencyRing() + { + static std::vector ar; + return ar; + } + + SelfIntersectionEar(){} + SelfIntersectionEar(const PosType & ep):MinimumWeightEar(ep){} + + virtual bool Close(PosType &np0, PosType &np1, FacePointer f) + { + PosType ep=this->e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 + PosType en=this->e1; en.NextB(); // he successivo a e1 +// bool triangularHole = false; +// if(en==ep || en-) triangularHole=true; + + + //costruisco la faccia e poi testo, o copio o butto via. + (*f).V(0) = this->e0.VFlip(); + (*f).V(1) = this->e0.v; + (*f).V(2) = this->e1.v; + face::FFSetBorder(f,0); + face::FFSetBorder(f,1); + face::FFSetBorder(f,2); + + typename std::vector< FacePointer >::iterator it; + for(it = this->AdjacencyRing().begin();it!= this->AdjacencyRing().end();++it) + { + if(!(*it)->IsD()) { - if(e0.VFlip()->IsUserBit(nonManifoldBit) && e1.V()->IsUserBit(nonManifoldBit)) - return true; - else return false; - } - bool IsConcave() const {return(angle > (float)M_PI);} - - virtual bool Close(PosType &np0, PosType &np1, FaceType * f) - { - // simple topological check - if(e0.f==e1.f) { - //printf("Avoided bad ear"); - return false; - } - - //usato per generare una delle due nuove orecchie. - PosType ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - PosType en=e1; en.NextB(); // he successivo a e1 - - (*f).V(0) = e0.VFlip(); - (*f).V(1) = e0.v; - (*f).V(2) = e1.v; - ComputeNormal(*f); - - (*f).FFp(0) = e0.f; - (*f).FFi(0) = e0.z; - (*f).FFp(1) = e1.f; - (*f).FFi(1) = e1.z; - (*f).FFp(2) = f; - (*f).FFi(2) = 2; - - e0.f->FFp(e0.z)=f; - e0.f->FFi(e0.z)=0; - - e1.f->FFp(e1.z)=f; - e1.f->FFi(e1.z)=1; - - // caso ear degenere per buco triangolare - if(ep==en) - { - //printf("Closing the last triangle"); - f->FFp(2)=en.f; - f->FFi(2)=en.z; - en.f->FFp(en.z)=f; - en.f->FFi(en.z)=2; - np0.SetNull(); - np1.SetNull(); - } - // Caso ear non manifold a - else if(ep.v==en.v) - { - //printf("Ear Non manif A\n"); - PosType enold=en; - en.NextB(); - f->FFp(2)=enold.f; - f->FFi(2)=enold.z; - enold.f->FFp(enold.z)=f; - enold.f->FFi(enold.z)=2; - np0=ep; - np1=en; - } - // Caso ear non manifold b - else if(ep.VFlip()==e1.v) - { - //printf("Ear Non manif B\n"); - PosType epold=ep; - ep.FlipV(); ep.NextB(); ep.FlipV(); - f->FFp(2)=epold.f; - f->FFi(2)=epold.z; - epold.f->FFp(epold.z)=f; - epold.f->FFi(epold.z)=2; - np0=ep; // assign the two new - np1=en; // pos that denote the ears - } - else // caso standard // Now compute the new ears; - { - np0=ep; - np1=PosType(f,2,e1.v); - } - - return true; - } - }; - - //Ear with FillHoleMinimumWeight's quality policy - template class MinimumWeightEar : public TrivialEar - { - public: - static float &DiedralWeight() { static float _dw=1.0; return _dw;} - typedef TrivialEar TE; - typename MESH::ScalarType dihedralRad; - typename MESH::ScalarType aspectRatio; - const char * Dump() { - static char buf[200]; - if(this->IsConcave()) sprintf(buf,"Dihedral -(deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); - else sprintf(buf,"Dihedral (deg) %6.2f Quality %6.2f\n",math::ToDeg(dihedralRad),aspectRatio); - return buf; - } - - MinimumWeightEar(){} - //MinimumWeightEar(const PosType & ep) : TrivialEar(ep) - MinimumWeightEar(const typename face::Pos& ep) : TrivialEar(ep) - { - ComputeQuality(); - } - - // In the heap, by default, we retrieve the LARGEST value, - // so if we need the ear with minimal dihedral angle, we must reverse the sign of the comparison. - // The concave elements must be all in the end of the heap, sorted accordingly, - // So if only one of the two ear is Concave that one is always the minimum one. - // the pow function is here just to give a way to play with different weighting schemas, balancing in a different way - - virtual inline bool operator < ( const MinimumWeightEar & c ) const - { - if(TE::IsConcave() == c.IsConcave()) + if( tri::Clean::TestFaceFaceIntersection(f,*it)) + return false; + // We must also check that the newly created face does not have any edge in common with other existing surrounding faces + // Only the two faces of the ear can share an edge with the new face + if(face::CountSharedVertex(f,*it)==2) { - return (pow((float)dihedralRad,(float)DiedralWeight())/aspectRatio) > (pow((float)c.dihedralRad,(float)DiedralWeight())/c.aspectRatio); + int e0,e1; + bool ret=face::FindSharedEdge(f,*it,e0,e1); + assert(ret); + if(!face::IsBorder(**it,e1)) + return false; } - if(TE::IsConcave()) return true; - // assert(c.IsConcave()); - return false; - } - - // the real core of the whole hole filling strategy. - virtual void ComputeQuality() - { - //compute quality by (dihedral ancgle, area/sum(edge^2) ) - typename MESH::CoordType n1=TE::e0.FFlip()->cN(); - typename MESH::CoordType n2=TE::e1.FFlip()->cN(); - - dihedralRad = std::max(Angle(TE::n,n1),Angle(TE::n,n2)); - aspectRatio = QualityFace(*this); - } - - }; - //Ear for selfintersection algorithm - template class SelfIntersectionEar : public MinimumWeightEar - { - public: - typedef typename MESH::FaceType FaceType; - typedef typename MESH::FacePointer FacePointer; - typedef typename face::Pos PosType; - typedef typename MESH::ScalarType ScalarType; - typedef typename MESH::CoordType CoordType; - - static std::vector &AdjacencyRing() - { - static std::vector ar; - return ar; } + } + bool ret=TrivialEar::Close(np0,np1,f); + if(ret) AdjacencyRing().push_back(f); + return ret; + } +}; // end class SelfIntersectionEar - SelfIntersectionEar(){} - SelfIntersectionEar(const PosType & ep):MinimumWeightEar(ep){} - - virtual bool Close(PosType &np0, PosType &np1, FacePointer f) - { - PosType ep=this->e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - PosType en=this->e1; en.NextB(); // he successivo a e1 - //costruisco la faccia e poi testo, o copio o butto via. - (*f).V(0) = this->e0.VFlip(); - (*f).V(1) = this->e0.v; - (*f).V(2) = this->e1.v; - - (*f).FFp(0) = this->e0.f; - (*f).FFi(0) = this->e0.z; - (*f).FFp(1) = this->e1.f; - (*f).FFi(1) = this->e1.z; - (*f).FFp(2) = f; - (*f).FFi(2) = 2; - - int a1, a2; - a1= this->e0.z; - a2= this->e1.z; - - this->e0.f->FFp(this->e0.z)=f; - this->e0.f->FFi(this->e0.z)=0; - - this->e1.f->FFp(this->e1.z)=f; - this->e1.f->FFi(this->e1.z)=1; - typename std::vector< FacePointer >::iterator it; - for(it = this->AdjacencyRing().begin();it!= this->AdjacencyRing().end();++it) - { - if(!(*it)->IsD()) - if( tri::Clean::TestFaceFaceIntersection(&(*f),*it)) - { - this->e0.f->FFp(this->e0.z)= this->e0.f; - this->e0.f->FFi(this->e0.z)=a1; - - this->e1.f->FFp(this->e1.z)= this->e1.f; - this->e1.f->FFi(this->e1.z)=a2; - return false; - } - } - //return ((TrivialEar *)this)->Close(np0,np1,f); - this->e0.f->FFp(this->e0.z)= this->e0.f; - this->e0.f->FFi(this->e0.z)=a1; - - this->e1.f->FFp(this->e1.z)=this->e1.f; - this->e1.f->FFi(this->e1.z)=a2; - - bool ret=TrivialEar::Close(np0,np1,f); - if(ret) AdjacencyRing().push_back(f); - return ret; - } - }; - - // Funzione principale per chiudier un buco in maniera topologicamente corretta. - // Gestisce situazioni non manifold ragionevoli - // (tutte eccetto quelle piu' di 2 facce per 1 edge). - // Controlla che non si generino nuove situazioni non manifold chiudendo orecchie - // che sottendono un edge che gia'esiste. +// Funzione principale per chiudier un buco in maniera topologicamente corretta. +// Gestisce situazioni non manifold ragionevoli +// (tutte eccetto quelle piu' di 2 facce per 1 edge). +// Controlla che non si generino nuove situazioni non manifold chiudendo orecchie +// che sottendono un edge che gia'esiste. template class Hole @@ -500,182 +367,188 @@ public: } }; -template - static void FillHoleEar(MESH &m, Info &h ,int UBIT, std::vector &app,std::vector *vf =0) + + class EdgeToBeAvoided { - //Aggiungo le facce e aggiorno il puntatore alla faccia! - FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); - assert(h.p.f >= &*m.face.begin()); - assert(h.p.f <= &m.face.back()); - assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! - std::vector< EAR > H; - H.reserve(h.size); - int nmBit= VertexType::NewBitFlag(); // non manifoldness bit + VertexPointer v0,v1; + EdgeToBeAvoided(VertexPointer _v0, VertexPointer _v1):v0(_v0),v1(_v1) + { + if(v0>v1) swap(v0,v1); + } + bool operator < (const EdgeToBeAvoided &e) + { + if(this->v0!=e.v0) return this->v0v1ClearUserBit(nmBit); - ip.V()->ClearV(); - ip.NextB(); - } while(ip!=h.p); +template + static void FillHoleEar(MESH &m, // The mesh to be filled + Info &h, // the particular hole to be filled + std::vector &facePointersToBeUpdated) + { + //Aggiungo le facce e aggiorno il puntatore alla faccia! + FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, facePointersToBeUpdated); - ip = h.p; // Re init the pos iterator for another loop (useless if everithing is ok!!) - do{ - if(!ip.V()->IsV()) - ip.V()->SetV(); // All the vertexes that are visited more than once are non manifold - else ip.V()->SetUserBit(nmBit); - ip.NextB(); - } while(ip!=h.p); + assert(h.p.f >= &*m.face.begin()); + assert(h.p.f <= &m.face.back()); + assert(h.p.IsBorder()); - PosType fp = h.p; - do{ - EAR app = EAR(fp); - H.push_back( app ); - //printf("Adding ear %s ",app.Dump()); - fp.NextB(); - assert(fp.IsBorder()); - }while(fp!=h.p); + std::vector< EAR > EarHeap; + EarHeap.reserve(h.size); + int nmBit= VertexType::NewBitFlag(); // non manifoldness bit - int cnt=h.size; - - make_heap(H.begin(), H.end()); - - //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare. - while( cnt > 2 && !H.empty() ) - { - //printf("Front of the heap is %s", H.front().Dump()); - pop_heap(H.begin(), H.end()); // retrieve the MAXIMUM value and put in the back; - PosType ep0,ep1; - EAR BestEar=H.back(); - H.pop_back(); - if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit)) - { - if((*f).HasPolyInfo()) (*f).Alloc(3); - if(BestEar.Close(ep0,ep1,&*f)) - { - if(!ep0.IsNull()){ - H.push_back(EAR(ep0)); - push_heap( H.begin(), H.end()); - } - if(!ep1.IsNull()){ - H.push_back(EAR(ep1)); - push_heap( H.begin(), H.end()); - } - --cnt; - f->SetUserBit(UBIT); - if(vf != 0) (*vf).push_back(*f); - ++f; - } - }//is update() - }//fine del while principale. - //tolgo le facce non utilizzate. - while(f!=m.face.end()) - { - (*f).SetD(); - ++f; - m.fn--; + //First loops around the hole to mark non manifold vertices. + PosType ip = h.p; // Pos iterator + do{ + ip.V()->ClearUserBit(nmBit); + ip.V()->ClearV(); + ip.NextB(); + } while(ip!=h.p); + + ip = h.p; // Re init the pos iterator for another loop (useless if everithing is ok!!) + do{ + if(!ip.V()->IsV()) + ip.V()->SetV(); // All the vertexes that are visited more than once are non manifold + else ip.V()->SetUserBit(nmBit); + ip.NextB(); + } while(ip!=h.p); + + PosType fp = h.p; + do{ + EAR appEar = EAR(fp); + EarHeap.push_back( appEar ); + //printf("Adding ear %s ",app.Dump()); + fp.NextB(); + assert(fp.IsBorder()); + }while(fp!=h.p); + + int cnt=h.size; + + make_heap(EarHeap.begin(), EarHeap.end()); + + //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare. + while( cnt > 2 && !EarHeap.empty() ) + { + //printf("Front of the heap is %s", H.front().Dump()); + pop_heap(EarHeap.begin(), EarHeap.end()); // retrieve the MAXIMUM value and put in the back; + EAR BestEar=EarHeap.back(); + EarHeap.pop_back(); + + if(BestEar.IsUpToDate() && !BestEar.IsDegen(nmBit)) + { + if((*f).HasPolyInfo()) (*f).Alloc(3); + PosType ep0,ep1; + if(BestEar.Close(ep0,ep1,&*f)) + { + if(!ep0.IsNull()){ + EarHeap.push_back(EAR(ep0)); + push_heap( EarHeap.begin(), EarHeap.end()); } + if(!ep1.IsNull()){ + EarHeap.push_back(EAR(ep1)); + push_heap( EarHeap.begin(), EarHeap.end()); + } + --cnt; + ++f; + } + }//is update() + }//fine del while principale. + + while(f!=m.face.end()){ + tri::Allocator::DeleteFace(m,*f); + f++; + } VertexType::DeleteBitFlag(nmBit); // non manifoldness bit } template - static int EarCuttingFill(MESH &m, int sizeHole, const int UBIT, bool Selected = false, CallBackPos *cb=0) - { - std::vector< Info > vinfo; -// int UBIT = GetInfo(m, Selected,vinfo); + static int EarCuttingFill(MESH &m, int sizeHole, bool Selected = false, CallBackPos *cb=0) + { + std::vector< Info > vinfo; + GetInfo(m, Selected,vinfo); - typename std::vector::iterator ith; - //Info app; - int indCb=0; - int holeCnt=0; - std::vector vfp; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - vfp.push_back( &(*ith).p.f ); - - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - { - indCb++; - if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); - if((*ith).size < sizeHole){ - holeCnt++; - FillHoleEar< EAR >(m, *ith,UBIT,vfp); - } - } + typename std::vector::iterator ith; + int indCb=0; + int holeCnt=0; + std::vector facePtrToBeUpdated; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + facePtrToBeUpdated.push_back( &(*ith).p.f ); - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - (*fi).ClearUserBit(UBIT); - } - return holeCnt; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + { + indCb++; + if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); + if((*ith).size < sizeHole){ + holeCnt++; + FillHoleEar< EAR >(m, *ith,facePtrToBeUpdated); } + } + return holeCnt; + } -// it returns the number of created holes. +/// Main Hole Filling function. +/// Given a mesh search for all the holes smaller than a given size and fill them +/// It returns the number of filled holes. template - static int EarCuttingIntersectionFill(MESH &m, int sizeHole, const int UBIT, CallBackPos *cb=0) - { - std::vector vinfo; -// int UBIT = GetInfo(m, Selected,vinfo); - std::vector vf; - PosType sp; - PosType ap; - typename std::vector::iterator ith; - - // collect the face pointer that has to be updated by the various addfaces - std::vector vfpOrig; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - vfpOrig.push_back( &(*ith).p.f ); - - int indCb=0; - int holeCnt=0; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - { - indCb++; - if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); - if((*ith).size < sizeHole){ - std::vector vfp; - holeCnt++; - vfp=vfpOrig; - EAR::AdjacencyRing().clear(); - //Loops around the hole to collect the races . - PosType ip = (*ith).p; - do - { - PosType inp = ip; - do - { - inp.FlipE(); - inp.FlipF(); - EAR::AdjacencyRing().push_back(inp.f); - } while(!inp.IsBorder()); - ip.NextB(); - }while(ip != (*ith).p); + static int EarCuttingIntersectionFill(MESH &m, const int maxSizeHole, bool Selected, CallBackPos *cb=0) + { + std::vector vinfo; + GetInfo(m, Selected,vinfo); + typename std::vector::iterator ith; - typename std::vector::iterator fpi; - for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi) - vfp.push_back( &*fpi ); - - FillHoleEar(m, *ith,UBIT,vfp,&vf); - EAR::AdjacencyRing().clear(); - } - } - FaceIterator fi; - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) + // collect the face pointer that has to be updated by the various addfaces + std::vector vfpOrig; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + vfpOrig.push_back( &(*ith).p.f ); + + int indCb=0; + int holeCnt=0; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + { + indCb++; + if(cb) (*cb)(indCb*10/vinfo.size(),"Closing Holes"); + if((*ith).size < maxSizeHole){ + std::vector facePtrToBeUpdated; + holeCnt++; + facePtrToBeUpdated=vfpOrig; + EAR::AdjacencyRing().clear(); + //Loops around the hole to collect the faces that have to be tested for intersection. + PosType ip = (*ith).p; + do + { + PosType inp = ip; + do { - if(!(*fi).IsD()) - (*fi).ClearUserBit(UBIT); - } - return holeCnt; + inp.FlipE(); + inp.FlipF(); + EAR::AdjacencyRing().push_back(inp.f); + } while(!inp.IsBorder()); + ip.NextB(); + }while(ip != (*ith).p); + + typename std::vector::iterator fpi; + for(fpi=EAR::AdjacencyRing().begin();fpi!=EAR::AdjacencyRing().end();++fpi) + facePtrToBeUpdated.push_back( &*fpi ); + + FillHoleEar(m, *ith,facePtrToBeUpdated); + EAR::AdjacencyRing().clear(); } + } + return holeCnt; + } - static void GetInfo(MESH &m, const int UBIT, bool Selected ,std::vector& VHI) + static void GetInfo(MESH &m, bool Selected ,std::vector& VHI) { + tri::UpdateFlags::FaceClearV(m); for(FaceIterator fi = m.face.begin(); fi!=m.face.end(); ++fi) { if(!(*fi).IsD()) @@ -684,15 +557,15 @@ template { //se devo considerare solo i triangoli selezionati e //quello che sto considerando non lo e' lo marchio e vado avanti - (*fi).SetUserBit(UBIT); + (*fi).SetV(); } else { for(int j =0; j<3 ; ++j) { - if( face::IsBorder(*fi,j) && !(*fi).IsUserBit(UBIT) ) + if( face::IsBorder(*fi,j) && !(*fi).IsV() ) {//Trovato una faccia di bordo non ancora visitata. - (*fi).SetUserBit(UBIT); + (*fi).SetV(); PosType sp(&*fi, j, (*fi).V(j)); PosType fp=sp; int holesize=0; @@ -700,14 +573,14 @@ template Box3Type hbox; hbox.Add(sp.v->cP()); //printf("Looping %i : (face %i edge %i) \n", VHI.size(),sp.f-&*m.face.begin(),sp.z); - sp.f->SetUserBit(UBIT); + sp.f->SetV(); do { - sp.f->SetUserBit(UBIT); + sp.f->SetV(); hbox.Add(sp.v->cP()); ++holesize; sp.NextB(); - sp.f->SetUserBit(UBIT); + sp.f->SetV(); assert(sp.IsBorder()); }while(sp != fp); @@ -915,15 +788,14 @@ template triangulate(m,f,k,j,vi,vv); } - static void MinimumWeightFill(MESH &m, const int UBIT, int holeSize, bool Selected) + static void MinimumWeightFill(MESH &m, int holeSize, bool Selected) { - FaceIterator fi; std::vector vvi; std::vector vfp; std::vector vinfo; typename std::vector::iterator VIT; - GetInfo(m, UBIT, Selected,vinfo); + GetInfo(m, Selected,vinfo); for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT) { @@ -983,6 +855,6 @@ template };//close class Hole - } // end namespace -} +} // end namespace tri +} // end namespace vcg #endif