diff --git a/vcg/complex/trimesh/hole.h b/vcg/complex/trimesh/hole.h index 5a47020f..39cbf357 100644 --- a/vcg/complex/trimesh/hole.h +++ b/vcg/complex/trimesh/hole.h @@ -24,6 +24,9 @@ History $Log: not supported by cvs2svn $ +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 @@ -74,7 +77,11 @@ First Non working Version #define __VCG_TRI_UPDATE_HOLE #include +#include +#include +#include +#define FLT_MAX 3.402823466e+38F /* max float rappresentable */ /* Questa Classe serve per gestire la non duplicazione degli edge durante la chiusura di un buco. @@ -82,65 +89,19 @@ di un buco. namespace vcg { namespace tri { - template - class SimpleEdge - { - public: - typename MESH::VertexType v[2]; - SimpleEdge() - {} - - SimpleEdge(typename MESH::VertexType v0, typename MESH::VertexType v1) - { - if(v0.P().X() != v1.P().X() && - v0.P().Y() != v1.P().Y() && - v0.P().Z() != v1.P().Z()) - {v[0]=v1; v[1]=v0;} - else {v[0]=v0; v[1]=v1;} - } - - SimpleEdge(typename face::Pos &ep) { - //*this=SimpleEdge(*ep.VFlip(), *ep.v); - typename MESH::VertexType v0 ,v1; - v0 = *ep.VFlip(); - v1 = *ep.v; - if(v0.P().X() != v1.P().X() && - v0.P().Y() != v1.P().Y() && - v0.P().Z() != v1.P().Z()) - {v[0]=v1; v[1]=v0;} - else {v[0]=v0; v[1]=v1;} - } - - - bool operator < (const SimpleEdge & e) const - { - v[0] = e.v[0]; v[1]=e.v[1]; - } - - bool operator != (const SimpleEdge & e) - { - if(v[0].P().X() != e.v[0].P().X() && - v[0].P().Y() != e.v[0].P().Y() && - v[0].P().Z() != e.v[0].P().Z()) - return true; - else return false; - - } - }; - template class HoleInfo { public: HoleInfo(){} - HoleInfo(face::Pos const &pHole, int const pHoleSize, vcg::Box3 &pHoleBB) + HoleInfo(face::Pos const &pHole, int const pHoleSize, Box3 &pHoleBB) { p=pHole; size=pHoleSize; bb=pHoleBB; } - HoleInfo(face::Pos const &pHole, int const pHoleSize, vcg::Box3 &pHoleBB, int FI) + HoleInfo(face::Pos const &pHole, int const pHoleSize, Box3 &pHoleBB, int FI) { p=pHole; size=pHoleSize; @@ -151,7 +112,7 @@ namespace vcg { typename face::Pos p; int size; - vcg::Box3 bb; + Box3 bb; int faceindex; void Refresh(MESH &m) @@ -179,118 +140,18 @@ namespace vcg { return sum; } - - int CollectEdges(std::vector< SimpleEdge > &EV) - { - assert(p.IsBorder()); - EV.clear(); - int tsz=0; - face::Pos ip=p; - face::Pos tp; - - do - { - // Stesso codice della nextb - do - { - ip.NextE(); - EV.push_back(SimpleEdge(ip)); // l'edge che sto scorrendo - tp=ip; - tp.FlipV();tp.FlipE(); - EV.push_back(SimpleEdge(tp)); // l'edge della faccia su cui sono e opposto al vertice su cui ruoto - tp.FlipF(); tp.FlipE(); - EV.push_back(SimpleEdge(tp)); // gli altri due edge della faccia opposta a questa - tp.FlipE(); - EV.push_back(SimpleEdge(tp)); - } - while(!ip.f->IsB(ip.z)); - ip.FlipV(); - ++tsz; - } - while (ip != p); - assert(tsz==size); - - return EV.size(); - } }; - template - void FindHole(MESH &m, face::Pos ep, HoleInfo &h) - { - if(!ep.IsBorder()) return; - - int holesize = 0; - - Box3 hbox; - if(ep.v->IsR()) hbox.Add(ep.v->cP()); - face::Pos init; - init = ep; - do - { - ep.NextB(); - ep.f->SetV(); - if(ep.v->IsR()) hbox.Add(ep.v->cP()); - ++holesize; - } - while (ep != init); - h=HoleInfo(ep,holesize,hbox); - } - - template - void FindHole(MESH &m, STL_CONTAINER_HOLES & H) - { - typename MESH::FaceIterator pf; - int holesize; - for (pf=m.face.begin(); pf!=m.face.end(); ++pf) - if( !(*pf).IsD() && (*pf).IsW() ) - (*pf).ClearS(); - - face::Pos ep; - for (pf=m.face.begin(); pf!=m.face.end(); ++pf) - { - if( !(*pf).IsD() && !(*pf).IsS() && (*pf).IsR() ) - { - for(int j=0; j<3; ++j) - if( (*pf).IsB(j) && !(*pf).IsS() && (*pf).IsR() ) - { - (*pf).SetS(); - ep.Set(&*pf, j, (*pf).V(j)); - holesize = 0; - - Box3 hbox; - if(ep.v->IsR()) hbox.Add(ep.v->cP()); - face::Pos init; - init = ep; - do - { - ep.NextB(); - ep.f->SetS(); - if(ep.v->IsR()) hbox.Add(ep.v->cP()); - ++holesize; - } - while (ep != init); - H.push_back(HoleInfo(ep,holesize,hbox)); - break; - } - } - } - }; - - /* Un ear e' identificato da due hedge pos. - i vertici dell'ear sono e0.FlipV().v e0.v e1.v - Vale che e1== e0.NextB(); e che e1.FlipV() == e0; - Situazioni ear non manifold, e degeneri (buco triangolare) - T XXXXXXXXXXXXX A /XXXXX B en/XXXXX /XXXXXXXXXXXXXXX /XXXXXX /XXXXXX XXXXXXep==en XXX ep\ /en XXXX /e1 XXXX @@ -300,7 +161,6 @@ namespace vcg { XXX e0|o/XXXXXXX XXX e0|o/XXXXXXX XXX ep| /XXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXX \|/XXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXX - */ template class TrivialEar { @@ -310,6 +170,7 @@ namespace vcg { typedef typename MSH_TYPE::ScalarType ScalarType; ScalarType quality; ScalarType angle; + std::vector* vf; TrivialEar(){} TrivialEar(const face::Pos & ep) { @@ -321,6 +182,8 @@ namespace vcg { computeAngle(); } + void SetAdiacenseRing(std::vector* ar){vf = ar;} + void computeAngle() { Point3f p1 = e0.VFlip()->P() - e0.v->P(); @@ -343,11 +206,11 @@ namespace vcg { angle = p; } - inline bool operator < ( const TrivialEar & c ) const { return quality < c.quality; } + 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();} - void ComputeQuality() + virtual void ComputeQuality() { ScalarType ar; ar = ( (e0.VFlip()->P() - e0.v->P()) ^ ( e1.v->P() - e0.v->P()) ).Norm() ; @@ -363,7 +226,6 @@ namespace vcg { bool IsConvex(){return (angle > (float)M_PI);} - bool Degen() { face::Pos ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 @@ -379,7 +241,7 @@ namespace vcg { return false; } - bool Close(TrivialEar &ne0, TrivialEar &ne1, typename MSH_TYPE::FaceType * f) + virtual bool Close(TrivialEar &ne0, TrivialEar &ne1, typename MSH_TYPE::FaceType * f) { // simple topological check if(e0.f==e1.f) { @@ -456,18 +318,14 @@ namespace vcg { } }; - //Ear with Leipa's quality policy - template class LeipaEar + //Ear with FillHoleMinimumWeight's quality policy + template class MinimumWeightEar : public TrivialEar { public: - face::Pos e0; - face::Pos e1; - typedef typename MSH_TYPE::ScalarType ScalarType; - ScalarType angle; ScalarType dihedral; ScalarType area; - LeipaEar(){} - LeipaEar(const face::Pos & ep) + MinimumWeightEar(){} + MinimumWeightEar(const face::Pos & ep) { e0=ep; assert(e0.IsBorder()); @@ -477,38 +335,13 @@ namespace vcg { computeAngle(); } - void computeAngle() - { - Point3f p1 = e0.VFlip()->P() - e0.v->P(); - Point3f p2 = e1.v->P() - e0.v->P(); - - ScalarType w = p2.Norm()*p1.Norm(); - if(w==0) angle =90; - ScalarType p = (p2*p1); - p= p/w; - p = acos(p); - if(p < -1) p = -1; - if(p > 1) p = 1; - - Point3f t = p2^p1; - ScalarType n = t* e0.v->N(); - if(n<0) - { - p = 2.0 *(float)M_PI - p; - } - angle = p; - } - - // Nota: minori invertiti - inline bool operator < ( const LeipaEar & c ) const + virtual inline bool operator < ( const MinimumWeightEar & c ) const { if(dihedral < c.dihedral)return true; else return ((dihedral == c.dihedral) && (area < c.area)); } - bool IsNull(){return e0.IsNull() || e1.IsNull();} - void SetNull(){e0.SetNull();e1.SetNull();} - void ComputeQuality() + virtual void ComputeQuality() { //comute quality by (dihedral ancgle, area/sum(edge^2) ) Point3f n1 = (e0.v->N() + e1.v->N() + e0.VFlip()->N() ) / 3; @@ -523,119 +356,17 @@ namespace vcg { ScalarType ar; ar = ( (e0.VFlip()->P() - e0.v->P()) ^ ( e1.v->P() - e0.v->P()) ).Norm() ; - /*ScalarType l1 = Distance( e0.v->P(),e1.v->P()); - ScalarType l2 = Distance( e0.v->P(),e0.VFlip()->P()); - ScalarType l3 = Distance( e0.VFlip()->P(),e1.v->P());*/ - - - area = ar ;// ( (l1 *l1) + (l2 * l2) + (l3 * l3) ); - - - };//dovrebbe - bool IsUpToDate() {return (e0.IsBorder() && e1.IsBorder());}; - bool IsConvex(){return angle > (float)M_PI;} - bool Degen() - { - face::Pos ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - face::Pos en=e1; en.NextB(); // he successivo a e1 - - // caso ear degenere per buco triangolare - if(ep==en) return true;//provo a togliere sto controllo - // Caso ear non manifold a - if(ep.v==en.v) return true; - // Caso ear non manifold b - if(ep.VFlip()==e1.v) return true; - - return false; + area = ar ; } - bool Close(LeipaEar &ne0, LeipaEar &ne1, typename MSH_TYPE::FaceType * f) - { - // simple topological check - if(e0.f==e1.f) { - printf("Avoided bad ear"); - return false; - } - - //usato per generare una delle due nuove orecchie. - face::Pos ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - face::Pos en=e1; en.NextB(); // he successivo a e1 - - (*f).V(0) = e0.VFlip(); - (*f).V(1) = e0.v; - (*f).V(2) = e1.v; - - (*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; - ne0.SetNull(); - ne1.SetNull(); - } - // Caso ear non manifold a - else if(ep.v==en.v) - { - printf("Ear Non manif A\n"); - face::Pos 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; - ne0=LeipaEar(ep); - ne1=LeipaEar(en); - } - // Caso ear non manifold b - else if(ep.VFlip()==e1.v) - { - printf("Ear Non manif B\n"); - face::Pos 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; - ne0=LeipaEar(ep); - ne1=LeipaEar(en); - } - else // caso standard - // Now compute the new ears; - { - ne0=LeipaEar(ep); - ne1=LeipaEar(face::Pos(f,2,e1.v)); - } - - return true; - } }; //Ear for selfintersection algorithm - template class SelfIntersection + template class SelfIntersectionEar : public TrivialEar { public: - face::Pos e0; - face::Pos e1; - typedef typename MSH_TYPE::ScalarType ScalarType; - ScalarType quality; - ScalarType angle; - SelfIntersection(){} - SelfIntersection(const face::Pos & ep) + + SelfIntersectionEar(){} + SelfIntersectionEar(const face::Pos & ep) { e0=ep; assert(e0.IsBorder()); @@ -645,64 +376,7 @@ namespace vcg { computeAngle(); } - inline bool operator < ( const SelfIntersection & c ) const - { - return (quality < c.quality); - } - void computeAngle() - { - Point3f p1 = e0.VFlip()->P() - e0.v->P(); - Point3f p2 = e1.v->P() - e0.v->P(); - - ScalarType w = p2.Norm()*p1.Norm(); - if(w==0) angle =90; - ScalarType p = (p2*p1); - p= p/w; - p = acos(p); - if(p < -1) p = -1; - if(p > 1) p = 1; - - Point3f t = p2^p1; - ScalarType n = t* e0.v->N(); - if(n<0) - { - p = 2.0 *(float)M_PI - p; - } - angle = p; - } - - bool IsNull(){return e0.IsNull() || e1.IsNull();} - void SetNull(){e0.SetNull();e1.SetNull();} - void ComputeQuality() - { - ScalarType ar; - ar = ( (e0.VFlip()->P() - e0.v->P()) ^ ( e1.v->P() - e0.v->P()) ).Norm() ; - ScalarType area = (ar); - - ScalarType l1 = Distance( e0.v->P(),e1.v->P()); - ScalarType l2 = Distance( e0.v->P(),e0.VFlip()->P()); - ScalarType l3 = Distance( e0.VFlip()->P(),e1.v->P()); - - quality = area / ( (l1 *l1) + (l2 * l2) + (l3 * l3) ); - }; - bool IsUpToDate() {return (e0.IsBorder() && e1.IsBorder());}; - bool IsConvex(){ return (angle > (float)M_PI);} - bool Degen() - { - face::Pos ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - face::Pos en=e1; en.NextB(); // he successivo a e1 - - // caso ear degenere per buco triangolare - if(ep==en) return true;//provo a togliere sto controllo - // Caso ear non manifold a - if(ep.v==en.v) return true; - // Caso ear non manifold b - if(ep.VFlip()==e1.v) return true; - - return false; - } - - bool Close(SelfIntersection &ne0, SelfIntersection &ne1, typename MSH_TYPE::FaceType * f, std::vector vf) + virtual bool Close(SelfIntersectionEar &ne0, SelfIntersectionEar &ne1, typename MSH_TYPE::FaceType * f) { // simple topological check if(e0.f==e1.f) { @@ -734,19 +408,16 @@ namespace vcg { e1.f->FFp(e1.z)=f; e1.f->FFi(e1.z)=1; typename std::vector::iterator it; - for(it = vf.begin();it!= vf.end();++it) + for(it = (*vf).begin();it!= (*vf).end();++it) { if(!it->IsD()) if( tri::Clean::TestIntersection(&(*f),&(*it))) { - //rimetto a posto - e0.f->FFp(e0.z)=e0.f; e0.f->FFi(e0.z)=a1; e1.f->FFp(e1.z)=e1.f; e1.f->FFi(e1.z)=a2; - return false; } } @@ -771,8 +442,10 @@ namespace vcg { f->FFi(2)=enold.z; enold.f->FFp(enold.z)=f; enold.f->FFi(enold.z)=2; - ne0=SelfIntersection(ep); - ne1=SelfIntersection(en); + ne0=SelfIntersectionEar(ep); + ne0.SetAdiacenseRing(vf); + ne1=SelfIntersectionEar(en); + ne1.SetAdiacenseRing(vf); } // Caso ear non manifold b else if(ep.VFlip()==e1.v) @@ -784,219 +457,51 @@ namespace vcg { f->FFi(2)=epold.z; epold.f->FFp(epold.z)=f; epold.f->FFi(epold.z)=2; - ne0=SelfIntersection(ep); - ne1=SelfIntersection(en); + ne0=SelfIntersectionEar(ep); + ne0.SetAdiacenseRing(vf); + ne1=SelfIntersectionEar(en); + ne1.SetAdiacenseRing(vf); } - else // caso standard - // Now compute the new ears; + else// Now compute the new ears; { - ne0=SelfIntersection(ep); - ne1=SelfIntersection(face::Pos(f,2,e1.v)); + ne0=SelfIntersectionEar(ep); + ne0.SetAdiacenseRing(vf); + ne1=SelfIntersectionEar(face::Pos(f,2,e1.v)); + ne1.SetAdiacenseRing(vf); } return true; } }; - - // 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 - tri::HoleInfo getHoleInfo(MESH &m, face::Pos sp, - face::Pos fp, - int UBIT) + + template + void FillHoleEar(MESH &m, tri::HoleInfo &h ,int UBIT, std::vector *vf =0) { - int holesize=0; - - Box3 hbox; - hbox.Add(sp.v->cP()); - - do - { - sp.f->SetUserBit(UBIT); - hbox.Add(sp.v->cP()); - ++holesize; - sp.NextB(); - assert(sp.IsBorder()); - }while(sp != fp); - - int tmp = ((int)(sp.f - &(*(m.face.begin())))); - return tri::HoleInfo(sp,holesize,hbox, tmp ); - } - - template - void refreshHole(MESH &m, VECTOR_EAR &ve, face::Pos &fp) - { - face::Pos ff = fp; + //Aggiungo le facce e aggiorno il puntatore alla faccia! + std::vector app; + app.push_back( &h.p.f ); + typename MESH::FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); + h.Refresh(m); + assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! + std::vector H; //vettore di orecchie + H.reserve(h.size); + //prendo le informazioni sul buco + face::Pos ff = h.p; + face::Pos fp = h.p; do{ - ve.push_back(EAR(fp)); + EAR app = EAR(fp); + app.SetAdiacenseRing(vf); + H.push_back( app ); fp.NextB();//semmai da provare a sostituire il codice della NextB(); assert(fp.IsBorder()); }while(fp!=ff); - } - - template - void fillHoleEar(MESH &m, tri::HoleInfo &h ,int UBIT) - { - //Aggiungo le facce e aggiorno il puntatore alla faccia! - std::vector app; - app.push_back( &h.p.f ); - typename MESH::FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); - h.Refresh(m); - assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! - - std::vector H; //vettore di orecchie - - H.reserve(h.size); - - //prendo le informazioni sul buco - refreshHole >(m,H,h.p); - - bool fitted = false; - int cnt=h.size; - typename MESH::FaceIterator tmp; - - make_heap(H.begin(), H.end()); - - while( cnt > 2 && !H.empty() && !fitted) //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare - { - - pop_heap(H.begin(), H.end()); - - EAR en0,en1; - - typename MESH::FaceIterator Fadd = f; - - if(H.back().IsUpToDate() && !H.back().IsConvex()) - { - if(H.back().Degen()){ - // Nota che nel caso di ear degeneri si DEVE permettere la creazione di un edge che gia'esiste - printf("\n -> Evitata orecchia brutta!"); - } - else - { - - if(H.back().Close(en0,en1,&*f)) - { - if(!en0.IsNull()){ - H.push_back(en0); - push_heap( H.begin(), H.end()); - } - if(!en1.IsNull()){ - H.push_back(en1); - push_heap( H.begin(), H.end()); - } - --cnt; - f->SetUserBit(UBIT); - ++f; - fitted = true; - } - } - - if(cnt == 3 && !fitted) - {//ultimo buco o unico buco - if(H.back().Close(en0,en1,&*f)) - { - --cnt; - tmp = f; - ++f; - } - } - }//is update() - fitted = false; - //non ho messo il triangolo quindi tolgo l'orecchio e continuo - H.pop_back(); - }//fine del while principale - - while(f!=m.face.end()) - { - (*f).SetD(); - ++f; - m.fn--; - } - - } - - - template - void holeFillingEar(MESH &m, int sizeHole,bool Selected = false) - { - typename MESH::FaceIterator fi; - std::vector > vinfo; - int UBIT = MESH::FaceType::LastBitFlag(); - - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - { - if(Selected && !(*fi).IsS()) - { - //se devo considerare solo i triangoli selezionati e - //quello che sto considerando non lo e' lo marchio e vado avanti - (*fi).SetUserBit(UBIT); - } - else - { - if( !(*fi).IsUserBit(UBIT) ) - { - (*fi).SetUserBit(UBIT); - for(int j =0; j<3 ; ++j) - { - if( (*fi).IsB(j) ) - {//Trovato una faccia di bordo non ancora visitata. - face::Pos sp(&*fi, j, (*fi).V(j)); - - // if(!(*fi).IsR())return; - tri::HoleInfo HI = getHoleInfo(m,sp,sp, UBIT); - //ho recuperato l'inofrmazione su tutto il buco - vinfo.push_back(HI); - } - }//for sugli edge del triangolo - }//se e' gia stato visitato - }//S & !S - }//!IsD() - }//for principale!!! - - typename std::vector >::iterator ith; - typename tri::HoleInfo app; - for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) - { - app=(tri::HoleInfo)*ith; - if(app.size < sizeHole){ - fillHoleEar(m, app,UBIT); - } - } - - for(fi = m.face.begin(); fi!=m.face.end(); ++fi) - { - if(!(*fi).IsD()) - (*fi).ClearUserBit(UBIT); - } - } - - /* - FillHoleSelfIntersection - */ - template - void fillHoleInt(MESH &m, tri::HoleInfo &h ,int UBIT, std::vector vf) - { - //Aggiungo le facce e aggiorno il puntatore alla faccia! - std::vector app; - app.push_back( &h.p.f ); - typename MESH::FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); - h.Refresh(m); - assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! - std::vector H; //vettore di orecchie - H.reserve(h.size); - - //prendo le informazioni sul buco - tri::refreshHole >(m,H,h.p); - bool fitted = false; int cnt=h.size; typename MESH::FaceIterator tmp; @@ -1008,7 +513,7 @@ namespace vcg { pop_heap(H.begin(), H.end()); EAR en0,en1; typename MESH::FaceIterator Fadd = f; - if(H.back().IsUpToDate() && !H.back().IsConvex()) + if(H.back().IsUpToDate() && H.back().IsConvex()) { if(H.back().Degen()){ // Nota che nel caso di ear degeneri si DEVE permettere la creazione di un edge che gia'esiste. @@ -1016,7 +521,7 @@ namespace vcg { } else { - if(H.back().Close(en0,en1,&*f,vf)) + if(H.back().Close(en0,en1,&*f)) { if(!en0.IsNull()){ H.push_back(en0); @@ -1028,7 +533,7 @@ namespace vcg { } --cnt; f->SetUserBit(UBIT); - vf.push_back(*f); + if(vf != 0) (*vf).push_back(*f); ++f; fitted = true; } @@ -1036,11 +541,11 @@ namespace vcg { //ultimo buco o unico buco. if(cnt == 3 && !fitted) { - if(H.back().Close(en0,en1,&*f,vf)) + if(H.back().Close(en0,en1,&*f)) { --cnt; tmp = f; - vf.push_back(*f); + if(vf != 0)(*vf).push_back(*f); ++f; } } @@ -1056,49 +561,36 @@ namespace vcg { ++f; m.fn--; } - } - //hole filling selfintersection main algorithm template - void holeFillingIntersection(MESH &m, int sizeHole,bool Selected = false) + void holeFillingEar(MESH &m, int sizeHole,bool Selected = false) { - typename MESH::FaceIterator fi; std::vector > vinfo; - int UBIT = fi->LastBitFlag(); + int UBIT = GetHoleInfo(m, Selected,vinfo); + typename std::vector >::iterator ith; + typename tri::HoleInfo app; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + { + app=(tri::HoleInfo)*ith; + if(app.size < sizeHole){ + FillHoleEar(m, app,UBIT); + } + } + MESH::FaceIterator fi; for(fi = m.face.begin(); fi!=m.face.end(); ++fi) { if(!(*fi).IsD()) - { - if(Selected && !(*fi).IsS()) - { - //se devo considerare solo i triangoli selezionati e - //quello che sto considerando non lo e' lo marchio e vado avanti - (*fi).SetUserBit(UBIT); - } - else - { - if( !(*fi).IsUserBit(UBIT) ) - { - (*fi).SetUserBit(UBIT); - for(int j =0; j<3 ; ++j) - { - if( (*fi).IsB(j) ) - {//Trovato una faccia di bordo non ancora visitata. - face::Pos sp(&*fi, j, (*fi).V(j)); - - // if(!(*fi).IsR())return; - tri::HoleInfo HI = tri::getHoleInfo(m,sp,sp, UBIT); - //ho recuperato l'inofrmazione su tutto il buco - vinfo.push_back(HI); - } - }//for sugli edge del triangolo - }//se e' gia stato visitato - }//S & !S - }//!IsD() - }//for principale!!! + (*fi).ClearUserBit(UBIT); + } + } + template + void holeFillingIntersection(MESH &m, int sizeHole,bool Selected = false) + { + std::vector > vinfo; + int UBIT = GetHoleInfo(m, Selected,vinfo); std::vector vf; face::Possp; face::Posap; @@ -1124,16 +616,336 @@ namespace vcg { }while(sp != app.p); - fillHoleInt(m, app,UBIT,vf); + FillHoleEar(m, app,UBIT,&vf); vf.clear(); } } + MESH::FaceIterator fi; for(fi = m.face.begin(); fi!=m.face.end(); ++fi) { if(!(*fi).IsD()) (*fi).ClearUserBit(UBIT); } } + + template + int GetHoleInfo(MESH &m,bool Selected ,std::vector >& VHI) + { + MESH::FaceIterator fi; + int UBIT = MESH::FaceType::LastBitFlag(); + + for(fi = m.face.begin(); fi!=m.face.end(); ++fi) + { + if(!(*fi).IsD()) + { + if(Selected && !(*fi).IsS()) + { + //se devo considerare solo i triangoli selezionati e + //quello che sto considerando non lo e' lo marchio e vado avanti + (*fi).SetUserBit(UBIT); + } + else + { + if( !(*fi).IsUserBit(UBIT) ) + { + (*fi).SetUserBit(UBIT); + for(int j =0; j<3 ; ++j) + { + if( (*fi).IsB(j) ) + {//Trovato una faccia di bordo non ancora visitata. + face::Pos sp(&*fi, j, (*fi).V(j)); + face::Pos fp=sp; + int holesize=0; + + Box3 hbox; + hbox.Add(sp.v->cP()); + + do + { + sp.f->SetUserBit(UBIT); + hbox.Add(sp.v->cP()); + ++holesize; + sp.NextB(); + assert(sp.IsBorder()); + }while(sp != fp); + + int tmp = ((int)(sp.f - &(*(m.face.begin())))); + + //ho recuperato l'inofrmazione su tutto il buco + VHI.push_back( tri::HoleInfo(sp,holesize,hbox, tmp) ); + } + }//for sugli edge del triangolo + }//se e' gia stato visitato + }//S & !S + }//!IsD() + }//for principale!!! + return UBIT; + } + + //Minimum Weight Algorithm + class Weight + { + public: + + Weight() { ang = 180; ar = FLT_MAX ;} + Weight( float An, float Ar ) { ang=An ; ar= Ar;} + ~Weight() {} + + float angle() const { return ang; } + float area() const { return ar; } + + Weight operator+( const Weight & other ) const {return Weight( std::max( angle(), other.angle() ), area() + other.area());} + bool operator<( const Weight & rhs ) const {return ( angle() < rhs.angle() ||(angle() == rhs.angle() && area() < rhs.area())); } + + private: + float ang; + float ar; + }; + /* + \ / \/ + v1*---------*v4 + / \ / +hole/ \ / + / \ / + /ear \ / +-*---------*- +/ v3 v2\ + */ + template + float ComputeDihedralAngle(typename MESH::VertexPointer v1,typename MESH::VertexPointer v2, + typename MESH::VertexPointer v3,typename MESH::VertexPointer v4) + { + MESH::CoordType n1 = ((v1->P() - v2->P()) ^ (v3->P() - v1->P()) ).Normalize(); + MESH::CoordType n2 = ((v2->P() - v1->P()) ^ (v4->P() - v2->P()) ).Normalize(); + MESH::ScalarType t = (n1 * n2 ) ; + return ( acos(t)* 180.0 / M_PI); + } + + template + bool existEdge(face::Pos pi,face::Pos pf) + { + face::Pos app = pi; + face::Pos appF = pi; + face::Pos tmp; + assert(pi.IsBorder()); + + appF.NextB(); + appF.FlipV(); + + do + { + tmp = app; + tmp.FlipV(); + if(tmp.v == pf.v) + return true; + app.FlipE(); + app.FlipF(); + + if(app == pi)return false; + }while(app != appF); + return false; + } + + template + Weight computeWeight( int i, int j, int k, + std::vector > pv, + std::vector< std::vector< int > > v) + { + face::Pos pi = pv[i]; + face::Pos pj = pv[j]; + face::Pos pk = pv[k]; + + //test complex edge + if(existEdge(pi,pj) || existEdge(pj,pk)|| existEdge(pk,pi) ) + { + return Weight(); + } + // Return an infinite weight, if one of the neighboring patches + // could not be created. + if(v[i][j] == -1){return Weight();} + if(v[j][k] == -1){return Weight();} + + //calcolo il massimo angolo diedrale, se esiste. + float angle = 0.0f; + face::Pos px; + if(i + 1 == j) + { + px = pj; + px.FlipE(); px.FlipV(); + angle = std::max(angle , ComputeDihedralAngle(pi.v, pj.v, pk.v, px.v) ); + } + else + { + angle = std::max( angle, ComputeDihedralAngle(pi.v,pj.v, pk.v, pv[ v[i][j] ].v)); + } + + if(j + 1 == k) + { + px = pk; + px.FlipE(); px.FlipV(); + angle = std::max(angle , ComputeDihedralAngle(pj.v, pk.v, pi.v, px.v) ); + } + else + { + angle = std::max( angle, ComputeDihedralAngle(pj.v,pk.v, pi.v, pv[ v[j][k] ].v)); + } + + if( i == 0 && k == (int)v.size() - 1) + { + px = pi; + px.FlipE(); px.FlipV(); + angle = std::max(angle , ComputeDihedralAngle(pk.v, pi.v, pj.v,px.v ) ); + } + + MESH::ScalarType area = ( (pj.v->P() - pi.v->P()) ^ (pk.v->P() - pi.v->P()) ).Norm() * 0.5; + + return Weight(angle, area); + } + + template + std::vector calculateMinimumWeightTriangulation(MESH &m, std::vector > vv ) + { + std::vector< std::vector< Weight > > w; //matrice dei pesi minimali di ogni orecchio preso in conzideraione + std::vector< std::vector< int > > vi;//memorizza l'indice del terzo vertice del triangolo + + //hole size + int nv = vv.size(); + + w.clear(); + w.resize( nv, std::vector( nv, Weight() ) ); + + vi.resize( nv, std::vector( nv, 0 ) ); + + //inizializzo tutti i pesi possibili del buco + for ( int i = 0; i < nv-1; ++i ) + w[i][i+1] = Weight( 0, 0 ); + + //doppio ciclo for per calcolare di tutti i possibili triangoli i loro pesi. + for ( int j = 2; j < nv; ++j ) + { + for ( int i = 0; i + j < nv; ++i ) + { + //per ogni triangolazione mi mantengo il minimo valore del peso tra i triangoli possibili + Weight minval; + + //indice del vertice che da il peso minimo nella triangolazione corrente + int minIndex = -1; + + //ciclo tra i vertici in mezzo a i due prefissati + for ( int m = i + 1; m < i + j; ++m ) + { + Weight a = w[i][m]; + Weight b = w[m][i+j]; + Weight newval = a + b + computeWeight( i, m, i+j, vv, vi); + if ( newval < minval ) + { + minval = newval; + minIndex = m; + } + } + w[i][i+j] = minval; + vi[i][i+j] = minIndex; + } + } + + //Triangulate + int i, j; + i=0; j=nv-1; + std::vector vf; + + vf.clear(); + + triangulate(vf, i, j, vi, vv); + + return vf; + } + + template + void triangulate(std::vector &m,int i, int j, std::vector< std::vector > vi, + std::vector > vv) + { + if(i + 1 == j){return;} + if(i==j)return; + + int k = vi[i][j]; + + if(k == -1) return; + + m.push_back(vv[i].v); + m.push_back(vv[k].v); + m.push_back(vv[j].v); + + triangulate(m, i, k, vi, vv); + triangulate(m, k, j, vi, vv); + } + + template + void FillHoleMinimumWeight(MESH &m, bool Selected) + { + MESH::FaceIterator fi; + std::vector > vvi; + std::vector vfp; + + std::vector > vinfo; + std::vector >::iterator VIT; + int UBIT = GetHoleInfo(m, Selected,vinfo); + + for(VIT = vinfo.begin(); VIT != vinfo.end();++VIT) + { + vvi.push_back(VIT->p); + } + + std::vector >::iterator ith; + std::vector >::iterator ithn; + std::vector::iterator itf; + + std::vector > app; + face::Pos ps; + std::vector tr; + std::vector vf; + + for(ith = vvi.begin(); ith!= vvi.end(); ++ith) + { + tr.clear(); + vf.clear(); + app.clear(); + vfp.clear(); + + for(ithn = vvi.begin(); ithn!= vvi.end(); ++ithn) + vfp.push_back(&(ithn->f)); + + ps = *ith; + getBoundHole(ps,app); + + vf = calculateMinimumWeightTriangulation(m, app); + + if(vf.size() == 0)continue;//non e' stata trovata la triangolazione + + MESH::FaceIterator f = tri::Allocator::AddFaces(m, app.size()-2, vfp); + + for(itf = vf.begin();itf != vf.end(); ) + { + (*f).V(0) = (*itf++); + (*f).V(1) = (*itf++); + (*f).V(2) = (*itf++); + ++f; + } + } + } + + template + void getBoundHole (face::Pos sp,std::vector >&ret) + { + face::Pos fp = sp; + //take vertex around the hole + do + { + assert(fp.IsBorder()); + ret.push_back(fp); + fp.NextB(); + }while(sp != fp); + } + } // end namespace } #endif