From a1471cea4489376944753dee649f6b9a2c8766fd Mon Sep 17 00:00:00 2001 From: cignoni Date: Thu, 10 Oct 2013 16:02:27 +0000 Subject: [PATCH] Cleaned up a bit naming and comments and some interfaces of some bitquad functions --- vcg/complex/algorithms/bitquad_support.h | 318 ++++++------ vcg/complex/algorithms/clean.h | 636 +++++++++++------------ vcg/complex/algorithms/update/color.h | 2 +- 3 files changed, 464 insertions(+), 492 deletions(-) diff --git a/vcg/complex/algorithms/bitquad_support.h b/vcg/complex/algorithms/bitquad_support.h index a4dd9e5e..0810a096 100644 --- a/vcg/complex/algorithms/bitquad_support.h +++ b/vcg/complex/algorithms/bitquad_support.h @@ -5,6 +5,7 @@ #include #include #include +#include /** BIT-QUAD creation support: a few basic operations to work with bit-quads simplices @@ -25,30 +26,30 @@ bool RotateEdge(FaceType& f, int w0a); - rotate a quad edge (clockwise or counterclockwise, specified via template) - + bool RotateVertex(FaceType &f, int w0) - rotate around a quad vertex ("wind-mill" operation) void CollapseDiag(FaceType &f, ... p , MeshType& m) - - collapses a quad on its diagonal. - - p identifies the pos of collapsed point + - collapses a quad on its diagonal. + - p identifies the pos of collapsed point (as either the parametric pos on the diagonal, or a fresh coordtype) - + [ helper functions: ] - ScalarType quadQuality( ... ); - - returns the quality for a given quad + ScalarType quadQuality( ... ); + - returns the quality for a given quad - (should be made into a template parameter for methods using it) - currently measures how squared each angle is - + int FauxIndex(const FaceType* f); - returns index of the only faux edge of a quad (otherwise, assert) int CountBitPolygonInternalValency(const FaceType& f, int wedge) - returns valency of vertex in terms of polygons (quads, tris...) - - + + */ // these should become a parameter in the corresponding class @@ -62,7 +63,7 @@ namespace vcg{namespace tri{ -/* simple geometric-interpolation mono-function class used +/* simple geometric-interpolation mono-function class used as a default template parameter to BitQuad class */ template class GeometricInterpolator{ @@ -77,9 +78,9 @@ public: template < // first template parameter: the tri mesh (with face-edges flagged) - class _MeshType, + class _MeshType, // second template parameter: used to define interpolations between points - class Interpolator = GeometricInterpolator + class Interpolator = GeometricInterpolator > class BitQuad{ public: @@ -97,7 +98,7 @@ typedef typename MeshType::VertexPointer VertexPointer; class Pos{ FaceType *f; int e; -public: +public: enum{ PAIR, AROUND , NOTHING } mode; FaceType* &F(){return f;} FaceType* F() const {return f;} @@ -105,16 +106,16 @@ public: const VertexType* cV() const {return f->V(e);} int& E(){return e;} int E() const {return e;} - - + + Pos(){ f=NULL; e=0; mode=AROUND;} - + Pos(FaceType* _f, int _e){f=_f; e=_e;} Pos NextE()const {return Pos(f, (e+1)%3); } Pos PrevE(){return Pos(f, (e+2)%3); } bool IsF(){return f->IsF(e);} Pos FlipF(){return Pos(f->FFp(e), f->FFi(e)); } - + }; @@ -140,19 +141,19 @@ static bool RotateEdge(FaceType& f, int w0a, MeshType &m, Pos *affected=NULL){ VertexType *v0, *v1; v0= fa->V0(w0a); v1= fa->V1(w0a); - + // int w1a = (w0a+1)%3; int w2a = (w0a+2)%3; FaceType *fb = fa->FFp(w0a); - + MarkFaceF(fa); MarkFaceF(fb); - + int w0b = fa->FFi(w0a); // int w1b = (w0b+1)%3; int w2b = (w0b+2)%3; - + if (fa->IsF(w2a) == verse) { if (!CheckFlipDiag(*fa)) return false; FlipDiag(*fa); @@ -160,12 +161,12 @@ static bool RotateEdge(FaceType& f, int w0a, MeshType &m, Pos *affected=NULL){ fa = fb->FFp(w0b); w0a = fb->FFi(w0b); } - + if (fb->IsF(w2b) == verse) { if (!CheckFlipDiag(*fb)) return false; FlipDiag(*fb); } - + if (!CheckFlipEdge(*fa,w0a)) return false; FlipEdge(*fa,w0a,m); if (affected) { @@ -202,14 +203,14 @@ static void FlipDiag(FaceType &f){ } -// given a vertex (i.e. a face and a wedge), +// given a vertex (i.e. a face and a wedge), // this function tells us how the totale edge length around a vertex would change // if that vertex is rotated static ScalarType EdgeLenghtVariationIfVertexRotated(const FaceType &f, int w0) { assert(!f.IsD()); - - ScalarType + + ScalarType before=0, // sum of quad edges (originating from v) after=0; // sum of quad diag (orginating from v) int guard = 0; @@ -218,13 +219,13 @@ static ScalarType EdgeLenghtVariationIfVertexRotated(const FaceType &f, int w0) const FaceType* pf = &f; int pi = w0; int n = 0; // vertex valency - int na = 0; + int na = 0; do { ScalarType triEdge = (pf->P0(pi) - pf->P1(pi) ).Norm(); if (pf->IsF(pi)) { after += triEdge; na++;} else { before+= triEdge; n++; } if ( pf->IsF((pi+1)%3)) { after += CounterDiag( pf ).Norm(); na++; } - + const FaceType *t = pf; t = pf->FFp( pi ); if (pf == t ) return std::numeric_limits::max(); // it's a mesh border! flee! @@ -237,14 +238,14 @@ static ScalarType EdgeLenghtVariationIfVertexRotated(const FaceType &f, int w0) return (after-before); } -// given a vertex (i.e. a face and a wedge), +// given a vertex (i.e. a face and a wedge), // this function tells us how the totale edge length around a vertex would change // if that vertex is rotated static ScalarType QuadQualityVariationIfVertexRotated(const FaceType &f, int w0) { assert(!f.IsD()); - - ScalarType + + ScalarType before=0, // sum of quad quality around v after=0; // same after the collapse int guard = 0; @@ -253,20 +254,20 @@ static ScalarType QuadQualityVariationIfVertexRotated(const FaceType &f, int w0) const FaceType* pf = &f; int pi = w0; int nb = 0; // vertex valency - int na = 0; + int na = 0; std::vector s; // 1 star around v - do { + do { // ScalarType triEdge = (pf->P0(pi) - pf->P1(pi) ).Norm(); if (!pf->IsF(pi)) { if ( pf->IsF((pi+1)%3)) { s.push_back(pf->cFFp((pi+1)%3)->V2( pf->cFFi((pi+1)%3) )); } else { - s.push_back( pf->V2(pi) ); + s.push_back( pf->V2(pi) ); } - - s.push_back( pf->V1(pi) ); + + s.push_back( pf->V1(pi) ); } - + const FaceType *t = pf; t = pf->FFp( pi ); if (pf == t ) return std::numeric_limits::max(); // it's a mesh border! flee! @@ -275,7 +276,7 @@ static ScalarType QuadQualityVariationIfVertexRotated(const FaceType &f, int w0) pf = t; assert(guard++<100); } while (pf != &f); - + assert(s.size()%2==0); int N = s.size(); for (int i=0; iIsF((pi+2) % 3)) { + + if (pf->IsF((pi+2) % 3)) { pi = (pi+2)%3; // do one step back - int tmp = pf->FFi(pi); pf = pf->FFp(pi); pi = tmp; // flipF + int tmp = pf->FFi(pi); pf = pf->FFp(pi); pi = tmp; // flipF } - + const FaceType* stopA = pf; const FaceType* stopB = pf->FFp(FauxIndex(pf)); // rotate around vertex, flipping diagonals if necessary, do { bool mustFlip; - if (pf->IsF(pi)) { + if (pf->IsF(pi)) { // if next edge is faux, move on other side of quad - int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF + int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF mustFlip = false; } else { @@ -354,23 +355,23 @@ static bool RotateVertex(FaceType &f, int w0, MeshType &/*m*/, Pos *affected=NUL } FaceType *lastF = pf; - + int tmp = (pf->FFi(pi)+1)%3; pf = pf->FFp(pi); pi = tmp; // flipF - + if (mustFlip) { if (!CheckFlipDiag(*lastF)) return false; // cannot flip?? FlipDiag(*lastF); } MarkFaceF(pf); } while (pf != stopA && pf!= stopB); - + // last pass: rotate arund vertex again, changing faux status stopA=pf; do { int j = pi; - if (pf->IsF(j)) - { pf->ClearF(j); IncreaseValency(pf->V1(j)); } - else + if (pf->IsF(j)) + { pf->ClearF(j); IncreaseValency(pf->V1(j)); } + else { pf->SetF(j); DecreaseValencySimple(pf->V1(j),1); } j = (j+2)%3; @@ -409,7 +410,7 @@ static void FlipEdge(FaceType &f, int k, MeshType &m){ vcg::face::FlipEdge(*fa, k); - + // ripristinate faux flags fb->ClearAllF(); fa->ClearAllF(); @@ -419,7 +420,7 @@ static void FlipEdge(FaceType &f, int k, MeshType &m){ if (fa->FFp(k)->IsF( fa->FFi(k) )) fa->SetF(k); if (fb->FFp(k)->IsF( fb->FFi(k) )) fb->SetF(k); } - + } // check if a quad diagonal can be topologically flipped @@ -441,26 +442,26 @@ static CoordType CounterDiag(const FaceType* f){ } /* helper function: - collapses a single face along its faux edge. + collapses a single face along its faux edge. Updates FF adj of other edges. */ static void _CollapseDiagHalf(FaceType &f, int faux, MeshType& /*m*/) { int faux1 = (faux+1)%3; int faux2 = (faux+2)%3; - + FaceType* fA = f.FFp( faux1 ); FaceType* fB = f.FFp( faux2 ); - + MarkFaceF(fA); MarkFaceF(fB); int iA = f.FFi( faux1 ); int iB = f.FFi( faux2 ); - - if (fA==&f && fB==&f) { + + if (fA==&f && fB==&f) { // both non-faux edges are borders: tri-face disappears, just remove the vertex //if (DELETE_VERTICES) - //if (GetValency(f.V(faux2))==0) Allocator::DeleteVertex(m,*(f.V(faux2))); + //if (GetValency(f.V(faux2))==0) Allocator::DeleteVertex(m,*(f.V(faux2))); } else { if (fA==&f) { fB->FFp(iB) = fB; fB->FFi(iB) = iB; @@ -475,8 +476,8 @@ static void _CollapseDiagHalf(FaceType &f, int faux, MeshType& /*m*/) } } - - //DecreaseValency(&f,faux2,m); // update valency + + //DecreaseValency(&f,faux2,m); // update valency //Allocator::DeleteFace(m,f); } @@ -500,9 +501,9 @@ static void RemoveDoublet(FaceType &f, int wedge, MeshType& m, Pos* affected=NUL static void RemoveSinglet(FaceType &f, int wedge, MeshType& m, Pos* affected=NULL){ if (affected) affected->mode = Pos::NOTHING; // singlets leave nothing to update behind - + if (f.V(wedge)->IsB()) return; // hack: lets detect - + FaceType *fa, *fb; // these will die FaceType *fc, *fd; // their former neight fa = & f; @@ -511,10 +512,10 @@ static void RemoveSinglet(FaceType &f, int wedge, MeshType& m, Pos* affected=NUL int wa1 = (wa0+1)%3 ; int wa2 = (wa0+2)%3 ; int wb0 = (fa->FFi(wa0)+1)%3; - int wb1 = (wb0+1)%3 ; + int wb1 = (wb0+1)%3 ; // int wb2 = (wb0+2)%3 ; assert (fb == fa->FFp( wa2 ) ); // otherwise, not a singlet - + // valency decrease DecreaseValency(fa, wa1, m); DecreaseValency(fa, wa2, m); @@ -523,9 +524,9 @@ static void RemoveSinglet(FaceType &f, int wedge, MeshType& m, Pos* affected=NUL } else { DecreaseValency(fa,wa1,m); // double decrease of valency on wa1 } - + // no need to MarkFaceF ! - + fc = fa->FFp(wa1); fd = fb->FFp(wb1); int wc = fa->FFi(wa1); @@ -537,12 +538,12 @@ static void RemoveSinglet(FaceType &f, int wedge, MeshType& m, Pos* affected=NUL // faux status of survivors: unchanged assert( ! ( fc->IsF( wc) ) ); assert( ! ( fd->IsF( wd) ) ); - + Allocator::DeleteFace( m,*fa ); Allocator::DeleteFace( m,*fb ); - + DecreaseValency(fa,wedge,m ); - //if (DELETE_VERTICES) + //if (DELETE_VERTICES) //if (GetValency(fa->V(wedge))==0) Allocator::DeleteVertex( m,*fa->V(wedge) ); } @@ -646,22 +647,22 @@ static bool CollapseEdgeDirect(FaceType &f, int w0, MeshType& m){ FaceType * f0 = &f; assert( !f0->IsF(w0) ); - + VertexType *v0, *v1; v0 = f0->V0(w0); v1 = f0->V1(w0); - + if (!RotateVertex(*f0,w0,m)) return false; // quick hack: recover original wedge if (f0->V(0) == v0) w0 = 0; else if (f0->V(1) == v0) w0 = 1; - else if (f0->V(2) == v0) w0 = 2; + else if (f0->V(2) == v0) w0 = 2; else assert(0); - + assert( f0->V1(w0) == v1 ); assert( f0->IsF(w0) ); - + return CollapseDiag(*f0,PosOnDiag(*f0,false), m); } @@ -669,7 +670,7 @@ static bool CollapseEdgeDirect(FaceType &f, int w0, MeshType& m){ static bool CollapseEdge(FaceType &f, int w0, MeshType& m, Pos *affected=NULL){ FaceTypeP f0 = &f; assert(!f0->IsF(w0)); // don't use this method to collapse diag. - + if (IsDoubletOrSinglet(f,w0)) return false; //{ RemoveDoubletOrSinglet(f,w0,m, affected); return true;} if (IsDoubletOrSinglet(f,(w0+1)%3)) return false; //{ RemoveDoubletOrSinglet(f,(w0+1)%3,m, affected); return true;} @@ -678,30 +679,30 @@ static bool CollapseEdge(FaceType &f, int w0, MeshType& m, Pos *affected=NULL){ affected->F() = f0->FFp(w1); affected->E() = (f0->FFi(w1)+2+w1-FauxIndex(f0))%3; } - - FaceTypeP f1 = f0->FFp(w0); - int w1 = f0->FFi(w0); - + + FaceTypeP f1 = f0->FFp(w0); + int w1 = f0->FFi(w0); + assert(f0!=f1); // can't collapse border edges! - + // choose: rotate around V0 or around V1? if ( EdgeLenghtVariationIfVertexRotated(*f0,w0) < EdgeLenghtVariationIfVertexRotated(*f1,w1) - ) return CollapseEdgeDirect(*f0,w0,m); + ) return CollapseEdgeDirect(*f0,w0,m); else return CollapseEdgeDirect(*f1,w1,m); } -/** collapses a quad diagonal a-b +/** collapses a quad diagonal a-b forming the new vertex in between the two old vertices. if k == 0, new vertex is in a if k == 1, new vertex is in b if k == 0.5, new vertex in the middle, etc */ -static bool CollapseCounterDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* affected=NULL){ +static bool CollapseCounterDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* affected=NULL){ if (!CheckFlipDiag(f)) return false; FlipDiag(f); return CollapseDiag(f,interpol,m,affected); @@ -722,12 +723,12 @@ public: if (pos.mode==Pos::AROUND) { if (start.F()->IsF((start.E()+2)%3)) { - int i = start.F()->FFi( start.E() ); - start.F() = start.F()->FFp( start.E() ); - start.E() = (i+1)%3; + int i = start.F()->FFi( start.E() ); + start.F() = start.F()->FFp( start.E() ); + start.E() = (i+1)%3; } } - cur=start; + cur=start; over = false; } bool End() const { @@ -742,14 +743,14 @@ public: } else { if (cur.F()->IsF(cur.E())) { // jump over faux diag - int i = cur.F()->FFi( cur.E() ); + int i = cur.F()->FFi( cur.E() ); cur.F() = cur.F()->FFp( cur.E() ); cur.E() = (i+1)%3; } // jump over real edge FaceType *f =cur.F()->FFp( cur.E() ); if (f==cur.F()) over=true; // border found - cur.E() = (cur.F()->FFi( cur.E() ) +1 )%3; + cur.E() = (cur.F()->FFi( cur.E() ) +1 )%3; cur.F() = f; if (cur.F()==start.F()) over=true; } @@ -757,11 +758,11 @@ public: Pos GetPos(){ return cur; - } + } }; static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* affected=NULL){ - + FaceType* fa = &f; // fa lives int fauxa = FauxIndex(fa); @@ -784,10 +785,10 @@ static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* aff FaceType* fb = fa->FFp(fauxa); // fb dies assert (fb!=fa); // otherwise, its a singlet int fauxb = FauxIndex(fb); - + VertexType* va = fa->V(fauxa); // va lives VertexType* vb = fb->V(fauxb); // vb dies - + Interpolator::Apply( *(f.V0(fauxa)), *(f.V1(fauxa)), interpol, *va); bool border = false; @@ -798,11 +799,11 @@ static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* aff // rotate around vb, (same-sense-as-face)-wise int pi = fauxb; FaceType* pf = fb; /* pf, pi could be put in a Pos p(pb, fauxb) */ - do { + do { //pf->V(pi) = va; if (((pf->V2(pi) == va)||(pf->V1(pi) == va)) - &&(pf!=fa)&&(pf!=fb)) - return false; + &&(pf!=fa)&&(pf!=fb)) + return false; pi=(pi+2)%3; FaceType *t = pf->FFp(pi); if (t==pf) { border= true; break; } @@ -815,7 +816,7 @@ static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* aff do { pf->V(pi) = va; - + pi=(pi+2)%3; FaceType *t = pf->FFp(pi); if (t==pf) { border= true; break; } @@ -823,7 +824,7 @@ static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* aff pi = pf->FFi(pi); pf = t; } while (pf!=fb); - + // of found a border, also rotate around vb, (counter-sense-as-face)-wise if (border) { val++; @@ -839,54 +840,54 @@ static bool CollapseDiag(FaceType &f, ScalarType interpol, MeshType& m, Pos* aff pf = t; } while (pf!=fb); } - + // update FF, delete faces _CollapseDiagHalf(*fb, fauxb, m); _CollapseDiagHalf(*fa, fauxa, m); SetValency(va, GetValency(va)+val-2); - DecreaseValency(fb,(fauxb+2)%3,m); // update valency - DecreaseValency(fa,(fauxa+2)%3,m); // update valency + DecreaseValency(fb,(fauxb+2)%3,m); // update valency + DecreaseValency(fa,(fauxa+2)%3,m); // update valency Allocator::DeleteFace(m,*fa); Allocator::DeleteFace(m,*fb); //assert(val == GetValency(vb)); - DecreaseValencyNoSingletTest(vb, val, m); + DecreaseValencyNoSingletTest(vb, val, m); // note: don't directly kill vb. In non-twomanifold, it could still be referecned - // but: don't hunt for doublets either. + // but: don't hunt for doublets either. - assert(GetValency(vb)!=1 || vb->IsB()); - // if this asserts, you are in trouble. - // It means that the vertex that was supposed to die is still attached + assert(GetValency(vb)!=1 || vb->IsB()); + // if this asserts, you are in trouble. + // It means that the vertex that was supposed to die is still attached // somewhere else (non-twomanifold) // BUT in its other attachments it is a singlet, and that singlet cannot be // found now (would require VF) - - + + return true; -} +} // helper function: find a good position on a diag to collapse a point -// currently, it is point in the middle, +// currently, it is point in the middle, // unless a mixed border-non border edge is collapsed, then it is an exreme static ScalarType PosOnDiag(const FaceType& f, bool counterDiag){ bool b0, b1, b2, b3; // which side of the quads are border - + const FaceType* fa=&f; int ia = FauxIndex(fa); - const FaceType* fb=fa->cFFp(ia); + const FaceType* fb=fa->cFFp(ia); int ib = fa->cFFi(ia); - + b0 = fa->FFp((ia+1)%3) == fa; b1 = fa->FFp((ia+2)%3) == fa; b2 = fb->FFp((ib+1)%3) == fb; b3 = fb->FFp((ib+2)%3) == fb; - + if (counterDiag) { if ( (b0||b1) && !(b2||b3) ) return 1; if ( !(b0||b1) && (b2||b3) ) return 0; @@ -936,7 +937,7 @@ static void DecreaseValency(FaceType *f, int wedge, MeshType &m){ VertexType *v = f->V(wedge); int val = GetValency(v)-1; SetValency( v, val ); - if (val==0) Allocator::DeleteVertex(m,*v); + if (val==0) Allocator::DeleteVertex(m,*v); if (val==1) // singlet! RemoveSinglet(*f,wedge,m); // this could be recursive... } @@ -946,7 +947,7 @@ static void DecreaseValencyNoSingletTest(VertexType *v, int dv, MeshType &m){ int val = GetValency(v)-dv; SetValency( v, val ); if (DELETE_VERTICES) - if (val==0) Allocator::DeleteVertex(m,*v); + if (val==0) Allocator::DeleteVertex(m,*v); } static void DecreaseValencySimple(VertexType *v, int dv){ @@ -959,48 +960,45 @@ static void UpdateValencyInFlags(MeshType& m){ SetValency(&*vi,0); } for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int w=0; w<3; w++) + for (int w=0; w<3; w++) if (!fi->IsF(w)) - IncreaseValency( fi->V(w)); + IncreaseValency( fi->V(w)); } } static void UpdateValencyInQuality(MeshType& m){ - for (VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); vi++) if (!vi->IsD()) { - vi->Q() = 0; - } + tri::UpdateQuality::VertexConstant(m,0); for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { - for (int w=0; w<3; w++) - fi->V(w)->Q() += (fi->IsF(w)||fi->IsF((w+2)%3) )? 0.5f:1; + for (int w=0; w<3; w++) + fi->V(w)->Q() += (fi->IsF(w)||fi->IsF((w+2)%3) )? 0.5f:1; } } static bool HasConsistentValencyFlag(MeshType &m) { UpdateValencyInQuality(m); - bool isok=true; + bool isok=true; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { for (int k=0; k<3; k++) - if (GetValency(fi->V(k))!=fi->V(k)->Q()){ - MarkFaceF(&*fi); - isok=false; - } + if (GetValency(fi->V(k))!=fi->V(k)->Q()){ + MarkFaceF(&*fi); + isok=false; + } } return isok; } // helper function: // returns quality of a given (potential) quad -static ScalarType quadQuality(FaceType *f, int edge){ - - CoordType - a = f->V0(edge)->P(), - b = f->FFp(edge)->V2( f->FFi(edge) )->P(), - c = f->V1(edge)->P(), - d = f->V2(edge)->P(); - - return quadQuality(a,b,c,d); +static ScalarType quadQuality(FaceType *f, int edgeInd){ + CoordType + a = f->V0(edgeInd)->P(), + b = f->FFp(edgeInd)->V2( f->FFi(edgeInd) )->P(), + c = f->V1(edgeInd)->P(), + d = f->V2(edgeInd)->P(); + + return quadQuality(a,b,c,d); } /** @@ -1020,10 +1018,10 @@ static int TestEdgeRotation(const FaceType &f, int w0, ScalarType *gain=NULL) CoordType v0,v1,v2,v3,v4,v5; int w1 = (w0+1)%3; int w2 = (w0+2)%3; - + v0 = fa->P(w0); v3 = fa->P(w1); - + if (fa->IsF(w2) ) { v1 = fa->cFFp(w2)->V2( fa->cFFi(w2) )->P(); v2 = fa->P(w2); @@ -1031,10 +1029,10 @@ static int TestEdgeRotation(const FaceType &f, int w0, ScalarType *gain=NULL) v1 = fa->P(w2); v2 = fa->cFFp(w1)->V2( fa->cFFi(w1) )->P(); } - + const FaceType *fb = fa->cFFp(w0); w0 = fa->cFFi(w0); - + w1 = (w0+1)%3; w2 = (w0+2)%3; if (fb->IsF(w2) ) { @@ -1044,17 +1042,17 @@ static int TestEdgeRotation(const FaceType &f, int w0, ScalarType *gain=NULL) v4 = fb->P(w2); v5 = fb->cFFp(w1)->V2( fb->cFFi(w1) )->P(); } - - + + #if (!LENGTH_CRITERION) // max overall CONFORMAL quality criterion: q0 = quadQuality(v0,v1,v2,v3) + quadQuality(v3,v4,v5,v0); // keep as is? q1 = quadQuality(v1,v2,v3,v4) + quadQuality(v4,v5,v0,v1); // rotate CW? q2 = quadQuality(v5,v0,v1,v2) + quadQuality(v2,v3,v4,v5); // rotate CCW? - + if (q0>=q1 && q0>=q2) return 0; if (q1>=q2) return 1; - + #else // min distance (shortcut criterion) q0 = (v0 - v3).SquaredNorm(); @@ -1067,38 +1065,38 @@ static int TestEdgeRotation(const FaceType &f, int w0, ScalarType *gain=NULL) //static int go=0; //if ((stop+go)%100==99) printf("Stop: %4.1f%%\n",(stop*100.0/(stop+go)) ); - if (q1<=q2) { + if (q1<=q2) { if (gain) *gain = sqrt(q1)-sqrt(q0); // test: two diagonals should become shorter (the other two reamin the same) - if ( + if ( (v0-v2).SquaredNorm() < (v4-v2).SquaredNorm() || - (v3-v5).SquaredNorm() < (v1-v5).SquaredNorm() + (v3-v5).SquaredNorm() < (v1-v5).SquaredNorm() ) { //stop++; return 0; } //go++; return 1; - } + } { if (gain) *gain = sqrt(q2)-sqrt(q0); // diagonal test, as above: - if ( + if ( (v0-v4).SquaredNorm() < (v2-v4).SquaredNorm() || - (v3-v1).SquaredNorm() < (v5-v1).SquaredNorm() + (v3-v1).SquaredNorm() < (v5-v1).SquaredNorm() ) { //stop++; return 0; } //go++; - return -1; + return -1; } #endif } private: - + // helper function: // returns quality of a quad formed by points a,b,c,d // quality is computed as "how squared angles are" @@ -1115,12 +1113,12 @@ static ScalarType quadQuality(const CoordType &a, const CoordType &b, const Coor private: - + // helper function: // cos of angle abc. This should probably go elsewhere static ScalarType Cos(const CoordType &a, const CoordType &b, const CoordType &c ) { - CoordType + CoordType e0 = b - a, e1 = b - c; ScalarType d = (e0.Norm()*e1.Norm()); diff --git a/vcg/complex/algorithms/clean.h b/vcg/complex/algorithms/clean.h index a9c6a3d0..dd0c18bc 100644 --- a/vcg/complex/algorithms/clean.h +++ b/vcg/complex/algorithms/clean.h @@ -44,108 +44,102 @@ #include #include - namespace vcg { - namespace tri{ -template -class ConnectedIterator -{ - public: - typedef ConnectedMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; +namespace tri{ +template +class ConnectedComponentIterator +{ +public: + typedef ConnectedMeshType MeshType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FacePointer FacePointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::ConstFaceIterator ConstFaceIterator; + typedef typename MeshType::FaceContainer FaceContainer; public: - void operator ++() - { + void operator ++() + { FacePointer fpt=sf.top(); - sf.pop(); + sf.pop(); for(int j=0;j<3;++j) - if( !face::IsBorder(*fpt,j) ) - { - FacePointer l=fpt->FFp(j); + if( !face::IsBorder(*fpt,j) ) + { + FacePointer l=fpt->FFp(j); if( !tri::IsMarked(*mp,l) ) - { + { tri::Mark(*mp,l); - sf.push(l); - } - } -} + sf.push(l); + } + } + } - void start(MeshType &m, FacePointer p) - { - mp=&m; - while(!sf.empty()) sf.pop(); - UnMarkAll(m); - assert(p); - assert(!p->IsD()); - tri::Mark(m,p); + void start(MeshType &m, FacePointer p) + { + mp=&m; + while(!sf.empty()) sf.pop(); + UnMarkAll(m); + assert(p); + assert(!p->IsD()); + tri::Mark(m,p); sf.push(p); - } - bool completed() { - return sf.empty(); - } + } - FacePointer operator *() - { - return sf.top(); - } + bool completed() { + return sf.empty(); + } + + FacePointer operator *() + { + return sf.top(); + } private: std::stack sf; MeshType *mp; }; - /// - /** \addtogroup trimesh */ - /*@{*/ - /// Class of static functions to clean//restore meshs. - template - class Clean - { +/// +/** \addtogroup trimesh */ +/*@{*/ +/// Class of static functions to clean//restore meshs. +template +class Clean +{ - public: - typedef CleanMeshType MeshType; - typedef typename MeshType::VertexType VertexType; - typedef typename MeshType::VertexPointer VertexPointer; - typedef typename MeshType::VertexIterator VertexIterator; - typedef typename MeshType::ConstVertexIterator ConstVertexIterator; - typedef typename MeshType::EdgeIterator EdgeIterator; - typedef typename MeshType::EdgePointer EdgePointer; - typedef typename MeshType::CoordType CoordType; - typedef typename MeshType::ScalarType ScalarType; - typedef typename MeshType::FaceType FaceType; - typedef typename MeshType::FacePointer FacePointer; - typedef typename MeshType::FaceIterator FaceIterator; - typedef typename MeshType::ConstFaceIterator ConstFaceIterator; - typedef typename MeshType::FaceContainer FaceContainer; - typedef typename vcg::Box3 Box3Type; +public: + typedef CleanMeshType MeshType; + typedef typename MeshType::VertexType VertexType; + typedef typename MeshType::VertexPointer VertexPointer; + typedef typename MeshType::VertexIterator VertexIterator; + typedef typename MeshType::ConstVertexIterator ConstVertexIterator; + typedef typename MeshType::EdgeIterator EdgeIterator; + typedef typename MeshType::EdgePointer EdgePointer; + typedef typename MeshType::CoordType CoordType; + typedef typename MeshType::ScalarType ScalarType; + typedef typename MeshType::FaceType FaceType; + typedef typename MeshType::FacePointer FacePointer; + typedef typename MeshType::FaceIterator FaceIterator; + typedef typename MeshType::ConstFaceIterator ConstFaceIterator; + typedef typename MeshType::FaceContainer FaceContainer; + typedef typename vcg::Box3 Box3Type; - typedef GridStaticPtr TriMeshGrid; - typedef Point3 Point3x; + typedef GridStaticPtr TriMeshGrid; + typedef Point3 Point3x; - //TriMeshGrid gM; - //FaceIterator fi; - //FaceIterator gi; - //vcg::face::Pos he; - //vcg::face::Pos hei; - - /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ - class RemoveDuplicateVert_Compare{ - public: - inline bool operator()(VertexPointer const &a, VertexPointer const &b) - { - return (*a).cP() < (*b).cP(); - } - }; + /* classe di confronto per l'algoritmo di eliminazione vertici duplicati*/ + class RemoveDuplicateVert_Compare{ + public: + inline bool operator()(VertexPointer const &a, VertexPointer const &b) + { + return (*a).cP() < (*b).cP(); + } + }; /** This function removes all duplicate vertices of the mesh by looking only at their spatial positions. @@ -627,7 +621,7 @@ private: static bool IsBitQuadOnly(const MeshType &m) { typedef typename MeshType::FaceType F; - if (!HasPerFaceFlags(m)) return false; + tri::RequirePerFaceFlags(m); for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { unsigned int tmp = fi->Flags()&(F::FAUX0|F::FAUX1|F::FAUX2); if ( tmp != F::FAUX0 && tmp != F::FAUX1 && tmp != F::FAUX2) return false; @@ -636,207 +630,187 @@ private: } - /** - * Is the mesh only composed by triangles? (non polygonal faces) - */ - static bool IsBitTriOnly(const MeshType &m) - { - if (!HasPerFaceFlags(m)) return true; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { - if ( - !fi->IsD() && fi->IsAnyF() - ) return false; - } - return true; - } + /** +* Is the mesh only composed by triangles? (non polygonal faces) +*/ + static bool IsBitTriOnly(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) { + if ( !fi->IsD() && fi->IsAnyF() ) return false; + } + return true; + } - static bool IsBitPolygonal(const MeshType &m){ - return !IsBitTriOnly(m); - } + static bool IsBitPolygonal(const MeshType &m){ + return !IsBitTriOnly(m); + } - /** - * Is the mesh only composed by quadrilaterals and triangles? (no pentas, etc) - */ - static bool IsBitTriQuadOnly(const MeshType &m) - { - typedef typename MeshType::FaceType F; - if (!HasPerFaceFlags(m)) return false; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp!=F::FAUX0 && tmp!=F::FAUX1 && tmp!=F::FAUX2 && tmp!=0 ) return false; - } - return true; - } + /** + * Is the mesh only composed by quadrilaterals and triangles? (no pentas, etc) + * It assumes that the bits are consistent. In that case there can be only a single faux edge. + */ + static bool IsBitTriQuadOnly(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + typedef typename MeshType::FaceType F; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); + if ( tmp!=F::FAUX0 && tmp!=F::FAUX1 && tmp!=F::FAUX2 && tmp!=0 ) return false; + } + return true; + } - /** - * How many quadrilaterals? - */ - static int CountBitQuads(const MeshType &m) - { - if (!HasPerFaceFlags(m)) return 0; - typedef typename MeshType::FaceType F; - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); - if ( tmp==F::FAUX0 || tmp==F::FAUX1 || tmp==F::FAUX2) count++; - } - return count / 2; - } + /** + * How many quadrilaterals? + * It assumes that the bits are consistent. In that case we count the tris with a single faux edge and divide by two. + */ + static int CountBitQuads(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + typedef typename MeshType::FaceType F; + int count=0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + unsigned int tmp = fi->cFlags()&(F::FAUX0|F::FAUX1|F::FAUX2); + if ( tmp==F::FAUX0 || tmp==F::FAUX1 || tmp==F::FAUX2) count++; + } + return count / 2; + } - /** - * How many triangles? (non polygonal faces) - */ - static int CountBitTris(const MeshType &m) - { - if (!HasPerFaceFlags(m)) return m.fn; - int count=0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (!(fi->IsAnyF())) count++; - } - return count; - } + /** + * How many triangles? (non polygonal faces) + */ + static int CountBitTris(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + int count=0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + if (!(fi->IsAnyF())) count++; + } + return count; + } - /** - * How many polygons of any kind? (including triangles) - */ - static int CountBitPolygons(const MeshType &m) - { - if (!HasPerFaceFlags(m)) return m.fn; - typedef typename MeshType::FaceType F; - int count = 0; - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { - if (fi->IsF(0)) count++; - if (fi->IsF(1)) count++; - if (fi->IsF(2)) count++; - } - return m.fn - count/2; - } + /** + * How many polygons of any kind? (including triangles) + * it assumes that there are no faux vertexes (e.g vertices completely surrounded by faux edges) + */ + static int CountBitPolygons(const MeshType &m) + { + tri::RequirePerFaceFlags(m); + int count = 0; + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if (!fi->IsD()) { + if (fi->IsF(0)) count++; + if (fi->IsF(1)) count++; + if (fi->IsF(2)) count++; + } + return m.fn - count/2; + } - /** - * The number of polygonal faces is - * FN - EN_f (each faux edge hides exactly one triangular face or in other words a polygon of n edges has n-3 faux edges.) - * In the general case where a The number of polygonal faces is - * FN - EN_f + VN_f - * where: - * EN_f is the number of faux edges. - * VN_f is the number of faux vertices (e.g vertices completely surrounded by faux edges) - * as a intuitive proof think to a internal vertex that is collapsed onto a border of a polygon: - * it deletes 2 faces, 1 faux edges and 1 vertex so to keep the balance you have to add back the removed vertex. - */ - static int CountBitLargePolygons(MeshType &m) - { - - UpdateFlags::VertexSetV(m); - // First loop Clear all referenced vertices - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) - for(int i=0;i<3;++i) fi->V(i)->ClearV(); + /** + * The number of polygonal faces is + * FN - EN_f (each faux edge hides exactly one triangular face or in other words a polygon of n edges has n-3 faux edges.) + * In the general case where a The number of polygonal faces is + * FN - EN_f + VN_f + * where: + * EN_f is the number of faux edges. + * VN_f is the number of faux vertices (e.g vertices completely surrounded by faux edges) + * as a intuitive proof think to a internal vertex that is collapsed onto a border of a polygon: + * it deletes 2 faces, 1 faux edges and 1 vertex so to keep the balance you have to add back the removed vertex. + */ + static int CountBitLargePolygons(MeshType &m) + { + tri::RequirePerFaceFlags(m); + UpdateFlags::VertexSetV(m); + // First loop Clear all referenced vertices + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if (!fi->IsD()) + for(int i=0;i<3;++i) fi->V(i)->ClearV(); - // Second Loop, count (twice) faux edges and mark all vertices touched by non faux edges (e.g vertexes on the boundary of a polygon) - if (!HasPerFaceFlags(m)) return m.fn; - typedef typename MeshType::FaceType F; - int countE = 0; - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if (!fi->IsD()) { - for(int i=0;i<3;++i) - { - if (fi->IsF(i)) - countE++; - else - { - fi->V0(i)->SetV(); - fi->V1(i)->SetV(); - } - } - } - // Third Loop, count the number of referenced vertexes that are completely surrounded by faux edges. - - int countV = 0; - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) - if (!vi->IsD() && !vi->IsV()) countV++; - - return m.fn - countE/2 + countV ; - } - - - /** - * Checks that the mesh has consistent per-face faux edges - * (the ones that merges triangles into larger polygons). - * A border edge should never be faux, and faux edges should always be - * reciprocated by another faux edges. - * It requires FF adjacency. - */ - static bool HasConsistentPerFaceFauxFlag(const MeshType &m) - { - RequireFFAdjacency(m); - RequirePerFaceFlags(m); - - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for (int k=0; k<3; k++) - if( fi->IsF(k) != fi->cFFp(k)->IsF(fi->cFFi(k)) ) { - return false; - } - // non-reciprocal faux edge! - // (OR: border faux edge, which is likewise inconsistent) - - return true; - } - - static bool HasConsistentEdges(const MeshType &m) - { - RequirePerFaceFlags(m); - - for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - for (int k=0; k<3; k++) - { - VertexType *v0=(*fi).V(0); - VertexType *v1=(*fi).V(1); - VertexType *v2=(*fi).V(2); - if ((v0==v1)||(v0==v2)||(v1==v2)) - return false; - } - - return true; - } - - /** - * Count the number of non manifold edges in a polylinemesh, e.g. the edges where there are more than 2 incident faces. - * - */ - static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false) - { - assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh... - RequireEEAdjacency(m); - tri::UpdateTopology::EdgeEdge(m); - - if(SelectFlag) UpdateSelection::VertexClear(m); - - int nonManifoldCnt=0; - SimpleTempData TD(m.vert,0); - - // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. - EdgeIterator ei; - for (ei = m.edge.begin(); ei != m.edge.end(); ++ei) if (!ei->IsD()) + // Second Loop, count (twice) faux edges and mark all vertices touched by non faux edges + // (e.g vertexes on the boundary of a polygon) + int countE = 0; + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if (!fi->IsD()) { + for(int i=0;i<3;++i) { - TD[(*ei).V(0)]++; - TD[(*ei).V(1)]++; - } - - tri::UpdateFlags::VertexClearV(m); - // Second Loop, Check that each vertex have been seen 1 or 2 times. - for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if (!vi->IsD()) - { - if( TD[vi] >2 ) + if (fi->IsF(i)) + countE++; + else { - if(SelectFlag) (*vi).SetS(); - nonManifoldCnt++; + fi->V0(i)->SetV(); + fi->V1(i)->SetV(); } } - return nonManifoldCnt; } + // Third Loop, count the number of referenced vertexes that are completely surrounded by faux edges. + + int countV = 0; + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) + if (!vi->IsD() && !vi->IsV()) countV++; + + return m.fn - countE/2 + countV ; + } + + + /** + * Checks that the mesh has consistent per-face faux edges + * (the ones that merges triangles into larger polygons). + * A border edge should never be faux, and faux edges should always be + * reciprocated by another faux edges. + * It requires FF adjacency. + */ + static bool HasConsistentPerFaceFauxFlag(const MeshType &m) + { + RequireFFAdjacency(m); + RequirePerFaceFlags(m); + + for (ConstFaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + for (int k=0; k<3; k++) + if( ( fi->IsF(k) != fi->cFFp(k)->IsF(fi->cFFi(k)) ) || + ( fi->IsF(k) && face::IsBorder(*fi,k)) ) + { + return false; + } + return true; + } + + /** + * Count the number of non manifold edges in a polylinemesh, e.g. the edges where there are more than 2 incident faces. + * + */ + static int CountNonManifoldEdgeEE( MeshType & m, bool SelectFlag=false) + { + assert(m.fn == 0 && m.en >0); // just to be sure we are using an edge mesh... + RequireEEAdjacency(m); + tri::UpdateTopology::EdgeEdge(m); + + if(SelectFlag) UpdateSelection::VertexClear(m); + + int nonManifoldCnt=0; + SimpleTempData TD(m.vert,0); + + // First Loop, just count how many faces are incident on a vertex and store it in the TemporaryData Counter. + EdgeIterator ei; + for (ei = m.edge.begin(); ei != m.edge.end(); ++ei) if (!ei->IsD()) + { + TD[(*ei).V(0)]++; + TD[(*ei).V(1)]++; + } + + tri::UpdateFlags::VertexClearV(m); + // Second Loop, Check that each vertex have been seen 1 or 2 times. + for (VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi) if (!vi->IsD()) + { + if( TD[vi] >2 ) + { + if(SelectFlag) (*vi).SetS(); + nonManifoldCnt++; + } + } + return nonManifoldCnt; + } /** * Count the number of non manifold edges in a mesh, e.g. the edges where there are more than 2 incident faces. @@ -1572,7 +1546,7 @@ private: */ static bool HasConsistentPerWedgeTexCoord(MeshType &m) { - if(!HasPerWedgeTexCoord(m)) return false; + tri::RequirePerFaceWedgeTexCoord(m); for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) if(!(*fi).IsD()) @@ -1585,20 +1559,20 @@ private: return true; } - /** - Simple check that there are no face with all collapsed tex coords. - */ - static bool HasZeroTexCoordFace(MeshType &m) - { - if(!HasPerWedgeTexCoord(m)) return false; + /** + Simple check that there are no face with all collapsed tex coords. + */ + static bool HasZeroTexCoordFace(MeshType &m) + { + tri::RequirePerFaceWedgeTexCoord(m); - for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) - if(!(*fi).IsD()) - { - if( (*fi).WT(0).P() == (*fi).WT(1).P() && (*fi).WT(0).P() == (*fi).WT(2).P() ) return false; - } - return true; - } + for (FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi) + if(!(*fi).IsD()) + { + if( (*fi).WT(0).P() == (*fi).WT(1).P() && (*fi).WT(0).P() == (*fi).WT(2).P() ) return false; + } + return true; + } /** @@ -1642,51 +1616,51 @@ private: /** - This function merge all the vertices that are closer than the given radius + This function merge all the vertices that are closer than the given radius */ -static int MergeCloseVertex(MeshType &m, const ScalarType radius) - { - int mergedCnt=0; - mergedCnt = ClusterVertex(m,radius); - RemoveDuplicateVertex(m,true); - return mergedCnt; - } + static int MergeCloseVertex(MeshType &m, const ScalarType radius) + { + int mergedCnt=0; + mergedCnt = ClusterVertex(m,radius); + RemoveDuplicateVertex(m,true); + return mergedCnt; + } -static int ClusterVertex(MeshType &m, const ScalarType radius) - { - if(m.vn==0) return 0; - // some spatial indexing structure does not work well with deleted vertices... - tri::Allocator::CompactVertexVector(m); - typedef vcg::SpatialHashTable SampleSHT; - SampleSHT sht; - tri::VertTmark markerFunctor; - typedef vcg::vertex::PointDistanceFunctor VDistFunct; - std::vector closests; - int mergedCnt=0; - sht.Set(m.vert.begin(), m.vert.end()); - UpdateFlags::VertexClearV(m); - for(VertexIterator viv = m.vert.begin(); viv!= m.vert.end(); ++viv) - if(!(*viv).IsD() && !(*viv).IsV()) - { - (*viv).SetV(); - Point3 p = viv->cP(); - Box3 bb(p-Point3(radius,radius,radius),p+Point3(radius,radius,radius)); - GridGetInBox(sht, markerFunctor, bb, closests); - // qDebug("Vertex %i has %i closest", &*viv - &*m.vert.begin(),closests.size()); - for(size_t i=0; icP()); - if(dist < radius && !closests[i]->IsV()) - { -// printf("%f %f \n",dist,radius); - mergedCnt++; - closests[i]->SetV(); - closests[i]->P()=p; - } - } - } - return mergedCnt; - } + static int ClusterVertex(MeshType &m, const ScalarType radius) + { + if(m.vn==0) return 0; + // some spatial indexing structure does not work well with deleted vertices... + tri::Allocator::CompactVertexVector(m); + typedef vcg::SpatialHashTable SampleSHT; + SampleSHT sht; + tri::VertTmark markerFunctor; + typedef vcg::vertex::PointDistanceFunctor VDistFunct; + std::vector closests; + int mergedCnt=0; + sht.Set(m.vert.begin(), m.vert.end()); + UpdateFlags::VertexClearV(m); + for(VertexIterator viv = m.vert.begin(); viv!= m.vert.end(); ++viv) + if(!(*viv).IsD() && !(*viv).IsV()) + { + (*viv).SetV(); + Point3 p = viv->cP(); + Box3 bb(p-Point3(radius,radius,radius),p+Point3(radius,radius,radius)); + GridGetInBox(sht, markerFunctor, bb, closests); + // qDebug("Vertex %i has %i closest", &*viv - &*m.vert.begin(),closests.size()); + for(size_t i=0; icP()); + if(dist < radius && !closests[i]->IsV()) + { + // printf("%f %f \n",dist,radius); + mergedCnt++; + closests[i]->SetV(); + closests[i]->P()=p; + } + } + } + return mergedCnt; + } static std::pair RemoveSmallConnectedComponentsSize(MeshType &m, int maxCCSize) @@ -1695,7 +1669,7 @@ static std::pair RemoveSmallConnectedComponentsSize(MeshType &m, int m int TotalCC=ConnectedComponents(m, CCV); int DeletedCC=0; - ConnectedIterator ci; + ConnectedComponentIterator ci; for(unsigned int i=0;i FPV; @@ -1721,7 +1695,7 @@ static std::pair RemoveSmallConnectedComponentsDiameter(MeshType &m, Sc std::vector< std::pair > CCV; int TotalCC=ConnectedComponents(m, CCV); int DeletedCC=0; - tri::ConnectedIterator ci; + tri::ConnectedComponentIterator ci; for(unsigned int i=0;i RemoveHugeConnectedComponentsDiameter(MeshType &m, Sca std::vector< std::pair > CCV; int TotalCC=ConnectedComponents(m, CCV); int DeletedCC=0; - tri::ConnectedIterator ci; + tri::ConnectedComponentIterator ci; for(unsigned int i=0;i > CCV; int ScatterSize= std::min (100,tri::Clean::ConnectedComponents(m, CCV)); // number of random color to be used. Never use too many. - ConnectedIterator ci; + ConnectedComponentIterator ci; for(unsigned int i=0;i