From 2daa4cdd9be630590f4fde84732f88d582306b17 Mon Sep 17 00:00:00 2001 From: cnr-isti-vclab Date: Fri, 6 Oct 2006 15:28:14 +0000 Subject: [PATCH] first working implementationof "EAR HOLE FILLING". --- vcg/complex/trimesh/hole.h | 1265 +++++++++++++++++++----------------- 1 file changed, 685 insertions(+), 580 deletions(-) diff --git a/vcg/complex/trimesh/hole.h b/vcg/complex/trimesh/hole.h index 7c14da15..2081583b 100644 --- a/vcg/complex/trimesh/hole.h +++ b/vcg/complex/trimesh/hole.h @@ -21,9 +21,12 @@ * * ****************************************************************************/ /**************************************************************************** - History +History $Log: not supported by cvs2svn $ +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 . . . @@ -43,245 +46,261 @@ Questa Classe serve per gestire la non duplicazione degli edge durante la chiusu di un buco. */ namespace vcg { -namespace tri { + namespace tri { -template -class SimpleEdge -{ - public: - typename MESH::VertexType v[2]; - SimpleEdge() - {} - - SimpleEdge(typename MESH::VertexType v0, typename MESH::VertexType v1) + template + class SimpleEdge { - 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;} - } + public: + typename MESH::VertexType v[2]; + SimpleEdge() + {} - SimpleEdge(face::Pos &ep) { - //*this=SimpleEdge(*ep.VFlip(), *ep.v); + 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(face::Pos &ep) { + //*this=SimpleEdge(*ep.VFlip(), *ep.v); 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;} - } - + 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) + 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 { - p=pHole; - size=pHoleSize; - bb=pHoleBB; - } - typename face::Pos p; - int size; - vcg::Box3 bb; + public: + HoleInfo(){} + HoleInfo(face::Pos const &pHole, int const pHoleSize, vcg::Box3 &pHoleBB) + { + p=pHole; + size=pHoleSize; + bb=pHoleBB; + } - bool operator < (const HoleInfo & hh) const {return size < hh.size;} - bool operator > (const HoleInfo & hh) const {return size > hh.size;} - bool operator == (const HoleInfo & hh) const {return size == hh.size;} - bool operator != (const HoleInfo & hh) const {return size != hh.size;} - bool operator >= (const HoleInfo & hh) const {return size >= hh.size;} - bool operator <= (const HoleInfo & hh) const {return size <= hh.size;} + HoleInfo(face::Pos const &pHole, int const pHoleSize, vcg::Box3 &pHoleBB, int FI) + { + p=pHole; + size=pHoleSize; + bb=pHoleBB; + faceindex = FI; + } -typename MESH::ScalarType Perimeter() + + typename face::Pos p; + int size; + vcg::Box3 bb; + int faceindex; + + void Refresh(MESH &m) + { + p.f = (MESH::FacePointer)(faceindex + &(*(m.face.begin()))); + } + + bool operator < (const HoleInfo & hh) const {return size < hh.size;} + bool operator > (const HoleInfo & hh) const {return size > hh.size;} + bool operator == (const HoleInfo & hh) const {return size == hh.size;} + bool operator != (const HoleInfo & hh) const {return size != hh.size;} + bool operator >= (const HoleInfo & hh) const {return size >= hh.size;} + bool operator <= (const HoleInfo & hh) const {return size <= hh.size;} + + typename MESH::ScalarType Perimeter() + { + MESH::ScalarType sum=0; + face::Pos ip = p; + do + { + sum+=Distance(ip.v->cP(),ip.VFlip()->cP()); + ip.NextB(); + } + while (ip != p); + 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) { - MESH::ScalarType sum=0; - face::Pos ip = p; - do - { - sum+=Distance(ip.v->cP(),ip.VFlip()->cP()); - ip.NextB(); - } - while (ip != p); - return sum; - } + if(!ep.IsBorder()) return; + int holesize = 0; - 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 + Box3 hbox; + if(ep.v->IsR()) hbox.Add(ep.v->cP()); + face::Pos init; + init = ep; 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)); + ep.NextB(); + ep.f->SetV(); + if(ep.v->IsR()) hbox.Add(ep.v->cP()); + ++holesize; } - while(!ip.f->IsB(ip.z)); - ip.FlipV(); - ++tsz; + while (ep != init); + h=HoleInfo(ep,holesize,hbox); } - 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) -{ - 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) + template + void FindHole(MESH &m, STL_CONTAINER_HOLES & H) { - if( !(*pf).IsD() && !(*pf).IsS() && (*pf).IsR() ) + 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) { - 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 + if( !(*pf).IsD() && !(*pf).IsS() && (*pf).IsR() ) + { + for(int j=0; j<3; ++j) + if( (*pf).IsB(j) && !(*pf).IsS() && (*pf).IsR() ) { - ep.NextB(); - ep.f->SetS(); + (*pf).SetS(); + ep.Set(&*pf, j, (*pf).V(j)); + holesize = 0; + + Box3 hbox; if(ep.v->IsR()) hbox.Add(ep.v->cP()); - ++holesize; + 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; } - while (ep != init); - H.push_back(HoleInfo(ep,holesize,hbox)); - break; - } + } } - } -}; + }; -/* -Un ear e' identificato da due hedge pos. + /* + Un ear e' identificato da due hedge pos. - i vertici dell'ear sono - e0.FlipV().v - e0.v - e1.v + i vertici dell'ear sono + e0.FlipV().v + e0.v + e1.v - Vale che e1== e0.NextB(); - e che e1.FlipV() == e0; + Vale che e1== e0.NextB(); + e che e1.FlipV() == e0; -Situazioni ear non manifold, e degeneri (buco triangolare) + 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 -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 + 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: - face::Pos e0; // - face::Pos e1; // - typename MSH_TYPE::ScalarType quality; - TrivialEar(){} - TrivialEar(const face::Pos & ep) - { - e0=ep; - assert(e0.IsBorder()); - e1=e0; - e1.NextB(); - ComputeQuality(); - } + */ + template class TrivialEar + { + public: + face::Pos e0; // + face::Pos e1; // + typename MSH_TYPE::ScalarType quality; + TrivialEar(){} + TrivialEar(const face::Pos & ep) + { + e0=ep; + assert(e0.IsBorder()); + e1=e0; + e1.NextB(); + ComputeQuality(); + } - // Nota: minori invertiti - inline bool operator < ( const TrivialEar & c ) const { return quality > c.quality; } - inline bool operator > ( const TrivialEar & c ) const { return quality < c.quality; } - inline bool operator == ( const TrivialEar & c ) const { return quality == c.quality; } - inline bool operator != ( const TrivialEar & c ) const { return quality != c.quality; } - inline bool operator >= ( const TrivialEar & c ) const { return quality <= c.quality; } - inline bool operator <= ( const TrivialEar & c ) const { return quality >= c.quality; } + // Nota: minori invertiti + inline bool operator < ( const TrivialEar & c ) const { return quality > c.quality; } + inline bool operator > ( const TrivialEar & c ) const { return quality < c.quality; } + inline bool operator == ( const TrivialEar & c ) const { return quality == c.quality; } + inline bool operator != ( const TrivialEar & c ) const { return quality != c.quality; } + inline bool operator >= ( const TrivialEar & c ) const { return quality <= c.quality; } + 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(){ quality = Distance(e0.VFlip()->P(),e1.v->P());}; //metodo vecchio per il calcolo della qualita - void ComputeQuality() - { - - MSH_TYPE::ScalarType qt; - MSH_TYPE::ScalarType k0 = e0.VFlip()->P().X()*e1.v->P().X(); - MSH_TYPE::ScalarType k1 = e0.VFlip()->P().Y()*e1.v->P().Y(); - MSH_TYPE::ScalarType k2 = e0.VFlip()->P().Z()*e1.v->P().Z(); + bool IsNull(){return e0.IsNull() || e1.IsNull();} + void SetNull(){e0.SetNull();e1.SetNull();} + //void ComputeQuality(){ quality = Distance(e0.VFlip()->P(),e1.v->P());}; //metodo vecchio per il calcolo della qualita + void ComputeQuality() + { + + MSH_TYPE::ScalarType qt; + MSH_TYPE::ScalarType k0 = e0.VFlip()->P().X()*e1.v->P().X(); + MSH_TYPE::ScalarType k1 = e0.VFlip()->P().Y()*e1.v->P().Y(); + MSH_TYPE::ScalarType k2 = e0.VFlip()->P().Z()*e1.v->P().Z(); int exp0,exp1,exp2; @@ -291,427 +310,513 @@ template class TrivialEar if( exp0P(),e1.v->P()); - - - };//dovrebbe - bool IsUpToDate() {return (e0.IsBorder() && e1.IsBorder());}; + quality = qt * Distance(e0.VFlip()->P(),e1.v->P()); - bool Degen() + + };//dovrebbe + bool IsUpToDate() {return (e0.IsBorder() && e1.IsBorder());}; + + 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(TrivialEar &ne0, TrivialEar &ne1, typename MSH_TYPE::FaceType * f) + { + // simple topological check + if(e0.f==e1.f) { + //TRACE("Avoided bad ear"); + 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) + { + //TRACE("Closing the last triangle"); + 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) + { + //TRACE("Ear Non manif A\n"); + 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=TrivialEar(ep); + ne1=TrivialEar(en); + } + // Caso ear non manifold b + else if(ep.VFlip()==e1.v) + { + //TRACE("Ear Non manif B\n"); + 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=TrivialEar(ep); + ne1=TrivialEar(en); + } + else // caso standard + // Now compute the new ears; + { + ne0=TrivialEar(ep); + ne1=TrivialEar(face::Pos(f,2,e1.v)); + } + + 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) { - face::Pos ep=e0; ep.FlipV(); ep.NextB(); ep.FlipV(); // he precedente a e0 - face::Pos en=e1; en.NextB(); // he successivo a e1 + int holesize=0; - // caso ear degenere per buco triangolare - if(ep==en) return true; - // Caso ear non manifold a - if(ep.v==en.v) return true; - // Caso ear non manifold b - if(ep.VFlip()==e1.v) return true; + Box3 hbox; + hbox.Add(sp.v->cP()); - return false; + 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 ); } - bool Close(TrivialEar &ne0, TrivialEar &ne1, typename MSH_TYPE::FaceType * f) - { - // simple topological check - if(e0.f==e1.f) { - //TRACE("Avoided bad ear"); - printf("Avoided bad ear"); - return false; + + + template + void refreshHole(MESH &m, VECTOR_EAR &ve, face::Pos &fp, std::vector &vv) + { + face::Pos ff = fp; + + do{ + ve.push_back(EAR(fp)); + vv.push_back(*fp.v); + fp.NextB();//semmai da provare a sostituire il codice della NextB(); + assert(fp.IsBorder()); + }while(fp!=ff); + } - //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) + template + void fillHoleEar(MESH &m, tri::HoleInfo &h ,int UBIT) { - //TRACE("Closing the last triangle"); - 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) - { - //TRACE("Ear Non manif A\n"); - 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=TrivialEar(ep); - ne1=TrivialEar(en); - } - // Caso ear non manifold b - else if(ep.VFlip()==e1.v) - { - //TRACE("Ear Non manif B\n"); - 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=TrivialEar(ep); - ne1=TrivialEar(en); - } - else // caso standard - // Now compute the new ears; - { - ne0=TrivialEar(ep); - ne1=TrivialEar(face::Pos(f,2,e1.v)); - } + //Aggiungo le facce e aggiorno il puntatore alla faccia! + std::vector app; + app.push_back( &h.p.f ); - return true; - } -}; + assert(h.p.IsBorder()); + MESH::FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); + h.Refresh(m); //rinfresco il puntatore tramite l'indice precedentemente salvato. + assert(h.p.IsBorder());//test fondamentale altrimenti qualcosa s'e' rotto! + std::vector vv; //vettore di vertici -// 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. -// -// Attenzione: se per riaggiungere facce deve riallocare il vettore non funge!!!! -// -template -typename MESH::FaceIterator CloseHole(MESH &m, HoleInfo &h) -{ + std::vector H; //vettore di orecchie - std::vector > ES; - //set > ES; // vettore con tutti gli edge adiacenti al buco. - - h.CollectEdges(ES); - vector H; // Heap delle ear da chiudere - H.reserve(h.size); - std::vector app; - app.push_back( &h.p.f ); - MESH::FaceIterator f = tri::Allocator::AddFaces(m, h.size-2, app); - h.CollectEdges(ES); + H.reserve(h.size); - assert(h.p.IsBorder()); + //prendo le informazioni sul buco + refreshHole >(m,H,h.p,vv); - face::Pos ep=h.p; + bool fitted = false; + int cnt=h.size; + MESH::FaceIterator tmp; - do { - H.push_back(EAR(ep)); - ep.f->SetS(); - ep.NextB(); + while( cnt > 2 && !H.empty() ) //finche' il buco non e' chiuso o non ci sono piu' orecchie da analizzare + { + //ordino il vettore di orecchie + //sort(H.begin(), H.end(), greater() );//descending + sort(H.begin(), H.end(), less() ); //ascending - assert(ep.IsBorder()); - } while(ep!=h.p); - + EAR en0,en1; - make_heap(H.begin(),H.end()); - int cnt=h.size; - EAR en0,en1; + MESH::VertexType vfit = *H.back().e0.v; + std::vector::iterator it; + it = vv.begin(); + while( it != vv.end() && (vfit.P() != ((MESH::VertexType )(*it)).P() ) ) + {it++; } - MESH::FaceIterator firstf = f; + MESH::FaceIterator Fadd = f; - //SimpleEdge se(); - while(cnt > 2 && !H.empty()) - { - //pop_heap(H.begin(),H.end()); - - SimpleEdge se( *(H.back().e0.VFlip()) , *(H.back().e1.v)); - - // se.v = p.v; -// se.v[1] = p.v[1]; - - //Sostituito la funzione find con la ricerca manuale - std::vector >::iterator it; - it = ES.begin(); - while( it != ES.end() && - se != ((SimpleEdge )(*it)) ) - {it++; } - //per far funzionare il test sottostante. - - if(H.back().IsUpToDate()) - { - - if(H.back().Degen() && it != ES.end()){ + if(H.back().IsUpToDate()) + { + if(H.back().Degen() && it != vv.end()){ // 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(it == ES.end()) + } + else + { + if(H.back().Close(en0,en1,&*f)) { - //H.back().Close(en0,en1,&*f); - int i = H.size(); + //ES.insert(se); + /* ES.push_back(se); + 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; + tmp = f; + ++f; + fitted = true; } - else - if(H.back().Close(en0,en1,&*f)) - { - //ES.insert(se); - ES.push_back(se); - 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; - + } + } + if(cnt == 3 && !fitted) + {//ultimo buco o unico buco + if(H.back().Close(en0,en1,&*f)) + { + --cnt; + tmp = f; + ++f; + fitted = true; + } + } + if(fitted && cnt >2) + { + face::Pos ff( &(*tmp) ,2); + //ho inserito il triangolo e devo aggiornare le strutture dati + H.clear(); + vv.clear(); + tmp->SetUserBit(UBIT); + //ri-prendo le informazioni sul buco + refreshHole >(m,H,ff,vv); + fitted = false; + } + else + { + //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) + { + MESH::FaceIterator fi; + std::vector > vinfo; + int UBIT = fi->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!!! + + std::vector >::iterator ith; + tri::HoleInfo app; + for(ith = vinfo.begin(); ith!= vinfo.end(); ++ith) + { + app=(tri::HoleInfo)*ith; + if(app.size < sizeHole){ + //app.Refresh(m);//non so se serve + fillHoleEar >(m, app,UBIT); } + } + + for(fi = m.face.begin(); fi!=m.face.end(); ++fi) + { + if(!(*fi).IsD()) + (*fi).ClearUserBit(UBIT); + } } - if((cnt == 3) && ( H.back().e0.IsBorder() ) ) + + + /* + Trivial Ear con preferred Normal + */ + template class TrivialEarN : public TrivialEar { - //dovrebbe mancare un triangolo da tappare - if(H.back().Close(en0,en1,&*f)) + public: + + TrivialEarN(){} + TrivialEarN(const face::Pos & ep) + { + e0=ep; + assert(e0.IsBorder()); + e1=e0; + e1.NextB(); + ComputeQuality(); + } + + + static typename MSH_TYPE::VertexType &PreferredNormal() + { + static MSH_TYPE::VertexType nn; + return nn; + } + + void ComputeQuality(){ + Point3d nn= -Normal( e0.VFlip()->P(), e0.v->P(), e1.v->P()); + quality = Distance(e0.VFlip()->P(),e1.v->P()); + if(nn*PreferredNormal() < -0.1) + quality*=1000000; + + }; + + }; + + /* 2d Triangulation Code */ + class Triangulate2D + { + + static double Area(const vector &contour) + { + int n = contour.size(); + + double A=0.0f; + + for(int p=n-1,q=0; q= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); + }; + + static bool Snip(const vector &contour,int u,int v,int w,int n,int *V) + { + int p; + double Ax, Ay, Bx, By, Cx, Cy, Px, Py; + const double epsilon =1e-2; + + Ax = contour[V[u]].X(); + Ay = contour[V[u]].Y(); + + Bx = contour[V[v]].X(); + By = contour[V[v]].Y(); + + Cx = contour[V[w]].X(); + Cy = contour[V[w]].Y(); + + if ( epsilon> (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false; + + for (p=0;p &contour,vector &result) + { + /* allocate and initialize list of Vertices in polygon */ -/* -Trivial Ear con preferred Normal -*/ -template class TrivialEarN : public TrivialEar -{ - public: + int n = contour.size(); + double area=Area(contour); + if ( n < 3 ) return false; - TrivialEarN(){} - TrivialEarN(const face::Pos & ep) - { - e0=ep; - assert(e0.IsBorder()); - e1=e0; - e1.NextB(); - ComputeQuality(); - } + int *V = new int[n]; + /* we want a counter-clockwise polygon in V */ - static typename MSH_TYPE::VertexType &PreferredNormal() - { - static MSH_TYPE::VertexType nn; - return nn; - } - - void ComputeQuality(){ - Point3d nn= -Normal( e0.VFlip()->P(), e0.v->P(), e1.v->P()); - quality = Distance(e0.VFlip()->P(),e1.v->P()); - if(nn*PreferredNormal() < -0.1) - quality*=1000000; - - }; - -}; - -/* 2d Triangulation Code */ -class Triangulate2D -{ - -static double Area(const vector &contour) -{ - int n = contour.size(); - - double A=0.0f; - - for(int p=n-1,q=0; q= 0.0f) && (bCROSScp >= 0.0f) && (cCROSSap >= 0.0f)); -}; - -static bool Snip(const vector &contour,int u,int v,int w,int n,int *V) -{ - int p; - double Ax, Ay, Bx, By, Cx, Cy, Px, Py; - const double epsilon =1e-2; - - Ax = contour[V[u]].X(); - Ay = contour[V[u]].Y(); - - Bx = contour[V[v]].X(); - By = contour[V[v]].Y(); - - Cx = contour[V[w]].X(); - Cy = contour[V[w]].Y(); - - if ( epsilon> (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) ) return false; - - for (p=0;p &contour,vector &result) -{ - /* allocate and initialize list of Vertices in polygon */ - - int n = contour.size(); - double area=Area(contour); - if ( n < 3 ) return false; - - int *V = new int[n]; - - /* we want a counter-clockwise polygon in V */ - - if ( 0.0f < area ) for (int v=0; v2; ) - { - count--; - /* if we loop, it is probably a non-simple polygon */ - if( count<0) - { - CurrBest*=1.3; - count = 2*nv; - - if(CurrBest > sqrt(area)*2) - return false; - } - - /* three consecutive vertices in current polygon, */ - int u = v ; if (nv <= u) u = 0; /* previous */ - v = u+1; if (nv <= v) v = 0; /* new v */ - int w = v+1; if (nv <= w) w = 0; /* next */ - - if(Distance(contour[u],contour[w]) < CurrBest) - if ( Snip(contour,u,v,w,nv,V) ) - { - int a,b,c,s,t; - - /* true names of the vertices */ - a = V[u]; b = V[v]; c = V[w]; - - /* output Triangle */ - result.push_back( a ); - result.push_back( b ); - result.push_back( c ); - - m++; - - /* remove v from remaining polygon */ - for(s=v,t=v+1;t2; ) + { + count--; + /* if we loop, it is probably a non-simple polygon */ + if( count<0) + { + CurrBest*=1.3; + count = 2*nv; + + if(CurrBest > sqrt(area)*2) + return false; + } + + /* three consecutive vertices in current polygon, */ + int u = v ; if (nv <= u) u = 0; /* previous */ + v = u+1; if (nv <= v) v = 0; /* new v */ + int w = v+1; if (nv <= w) w = 0; /* next */ + + if(Distance(contour[u],contour[w]) < CurrBest) + if ( Snip(contour,u,v,w,nv,V) ) + { + int a,b,c,s,t; + + /* true names of the vertices */ + a = V[u]; b = V[v]; c = V[w]; + + /* output Triangle */ + result.push_back( a ); + result.push_back( b ); + result.push_back( c ); + + m++; + + /* remove v from remaining polygon */ + for(s=v,t=v+1;t