diff --git a/vcg/complex/trimesh/bitquad_optimization.h b/vcg/complex/trimesh/bitquad_optimization.h index 73c8c080..1704e973 100644 --- a/vcg/complex/trimesh/bitquad_optimization.h +++ b/vcg/complex/trimesh/bitquad_optimization.h @@ -1,6 +1,228 @@ namespace vcg{namespace tri{ +// helper function: mark a quadface, setting Q at 0, and neight at .75, 0.5... +template +void MarkFace(typename Mesh::FaceType* f, Mesh &m){ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + fi->Q() = 1; + } + + for (int i=0; i<3; i++) { + for (int j=0; j<3; j++) f->FFp(i)->FFp(j)->Q() = 0.75; + } + for (int i=0; i<3; i++) { + f->FFp(i)->Q() = 0.50; + } + f->Q() = 0; + +} + +// helper function: mark a quadface, setting Q at 0, and neight at .75, 0.5... +template +void MarkVertex(typename Mesh::FaceType* f, int wedge, Mesh &m){ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + typedef typename Mesh::VertexType VertexType; + VertexType *v = f->V(wedge); + + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + if (fi->V0(0)==v || fi->V1(0)==v ||fi->V2(0)==v ) fi->Q() = 0; + // else fi->Q() = 1; + } + +} + +template +bool MarkSmallestEdge(Mesh &m, bool perform) +{ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + typedef typename Mesh::ScalarType ScalarType; + ScalarType min = std::numeric_limits::max(); + + FaceType *fa=NULL; int w=0; + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) + for (int k=0; k<3; k++) { + FaceType *f=&*fi; + + if (f->IsF(k)) continue; + if (f->FFp(k) == f ) continue; // skip borders + + ScalarType score; + + score = (f->P0(k) - f->P1(k)).Norm(); + if (scoreQ()=0.0; + fa->FFp(w)->Q()=0.0; + return true; + } + } + return false; +} + +// returns: 0 if fail. 1 if edge. 2 if diag. +template +int MarkSmallestEdgeOrDiag(Mesh &m, typename Mesh::ScalarType edgeMult, bool perform) +{ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + typedef typename Mesh::ScalarType ScalarType; + ScalarType min = std::numeric_limits::max(); + + FaceType *fa=NULL; int w=0; bool counterDiag = false; + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) + for (int k=0; k<3; k++) { + FaceType *f=&*fi; + + if (f->FFp(k) >= f ) continue; // skip borders (==), and do it one per edge + + ScalarType score; + + score = (f->P0(k) - f->P1(k)).Norm(); + + if (!f->IsF(k)) score*=edgeMult; // edges are supposed to be smaller! + + if (scoreIsF(k)) { // for diag faces, test counterdiag too + score = CounterDiag(f).Norm(); + if (scoreIsF(w)) { + if (counterDiag) { + CollapseQuadCounterDiag(*fa, PosOnDiag(*fa,true), m ); return 2; + } else { + CollapseQuadDiag(*fa, PosOnDiag(*fa,false), m ); return 2; + } + } else { + if (CollapseQuadEdge(*fa,w,m)) return 1; + } + } else { + fa->Q()=0.0; + fa->FFp(w)->Q()=0.0; + if (fa->IsF(w)) return 2; else return 1; + } + } + return 0; +} + + +template +void MarkSmallestDiag(Mesh &m) +{ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + typedef typename Mesh::ScalarType ScalarType; + ScalarType min = std::numeric_limits::max(); + + FaceType *fa=NULL; + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + FaceType *f=&*fi; + + ScalarType score; + + score = Diag(f).Norm(); + if (scoreQ()=0.0; + fa->FFp(FauxIndex(fa))->Q()=0.0; + } + +} + +template +bool IdentifyAndCollapseSmallestDiag(Mesh &m){ + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + typedef typename Mesh::ScalarType ScalarType; + ScalarType min = std::numeric_limits::max(); + + FaceType *fa=NULL; bool flip; + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + FaceType *f=&*fi; + + ScalarType score; + + score = Diag(f).Norm(); + if (scoreFFp(k),(fa->FFi(k)+2)%3, m )) return true; + + if (flip) { + if (!CheckFlipBitQuadDiag(*fa) ) { + // I can't collapse (why?) + MarkFace(fa,m); + return false; + } else + CollapseQuadCounterDiag(*fa, PosOnDiag(*fa,true), m ); + } + else { + CollapseQuadDiag(*fa, PosOnDiag(*fa,false), m ); + } + return true; +} + + + /* seeks and removes all doublets (a pair of quads sharing two consecutive edges) by merging them into a single quad (thus removing one vertex and two tri faces)- @@ -25,6 +247,71 @@ int BitQuadRemoveDoublets(Mesh &m) return res; } +/* +marks (Quality=0) and approx. counts profitable vertex rotations +(vertex rotations which make edge shorter +*/ +template +int BitQuadMarkVertexRotations(Mesh &m) +{ + int res=0; + typedef typename Mesh::VertexIterator VertexIterator; + typedef typename Mesh::VertexType VertexType; + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + for (VertexIterator vi = m.vert.begin(); vi!=m.vert.end(); vi++) if (!vi->IsD()) vi->ClearV(); + if (!perform) + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) fi->Q()=1.0; + + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + + for (int k=0; k<3; k++) { + if (fi->V(k)->IsV()) continue; + if (TestBitQuadVertexRotation(*fi,k)) { + res++; + fi->V(k)->SetV(); + if (!perform) + MarkVertex(&*fi, k, m); //fi->Q()=0; + else { + RotateBitQuadVertex(*fi, k); //fi->Q()=0; + return 1; + } + } + } + } + return res; +} + +// mark (and count) all edges that are worth rotating +// if perform == true, actually rotate them +template +int BitQuadMarkEdgeRotations(Mesh &m) +{ + int count = 0; + typedef typename Mesh::FaceIterator FaceIterator; + typedef typename Mesh::FaceType FaceType; + + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) fi->Q()=1; + + for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { + //if (count>0) break; + for (int k=0; k<3; k++) { + if (fi->IsF(k)) continue; + if (fi->FFp(k)<= &*fi) continue; // only once per real (non faux) edge, and only for non border ones + int best = TestBitQuadEdgeRotation(*fi, k); + if (perform) { + if (best==+1) if (RotateBitQuadEdge(*fi, k)) count++; + if (best==-1) if (RotateBitQuadEdge(*fi, k)) count++; + } + else { + if (best!=0) { fi->Q()=0; fi->FFp(k)->Q()=0; count++; } + } + } + } + + return count; +} + /* marks (Quality=0) and approx. counts doublets (a pair of quads sharing two consecutive edges) */