/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef _BITQUAD_OPTIMIZATION #define _BITQUAD_OPTIMIZATION namespace vcg{namespace tri{ template class BitQuadOptimization{ typedef typename BQ::MeshType MeshType; typedef typename BQ::Pos Pos; typedef typename MeshType::ScalarType ScalarType; typedef typename MeshType::CoordType CoordType; typedef typename MeshType::FaceType FaceType; typedef typename MeshType::FaceType* FaceTypeP; typedef typename MeshType::VertexType VertexType; typedef typename MeshType::FaceIterator FaceIterator; typedef typename MeshType::VertexIterator VertexIterator; //typedef BitQuad BQ; // static class to make basic quad operatins public: // helper function: mark a quadface, setting Q at 0, and neight at .75, 0.5... static void MarkFace(FaceType* f, MeshType &m){ 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... static void MarkVertex(FaceType* f, int wedge, MeshType &m){ 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; } } static bool MarkSmallestEdge(MeshType &m, bool perform) { 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; } static ScalarType Importance(const CoordType &/*p*/){ //return ::proceduralImportance(p); return 1; } // returns: 0 if fail. 1 if edge. 2 if diag. static int MarkSmallestEdgeOrDiag(MeshType &m, ScalarType edgeMult, bool perform, Pos* affected=NULL) { 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(); ScalarType imp = Importance( (f->P0(k) + f->P1(k))/2 ); score /= imp; if (!f->IsF(k)) score*=edgeMult; // edges are supposed to be smaller! if (scoreIsF(k)) { // for diag faces, test counterdiag too score = BQ::CounterDiag(f).Norm(); score /= imp; if (scoreIsF(w)) { if (counterDiag) { if (BQ::CollapseCounterDiag(*fa, BQ::PosOnDiag(*fa,true), m , affected)) return 2; } else { if (BQ::CollapseDiag(*fa, BQ::PosOnDiag(*fa,false), m ,affected)) return 2; } } else { if (BQ::CollapseEdge(*fa,w,m, affected)) return 1; } } else { fa->Q()=0.0; fa->FFp(w)->Q()=0.0; if (fa->IsF(w)) return 2; else return 1; } } return 0; } static void MarkSmallestDiag(MeshType &m) { 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 = BQ::Diag(f).Norm(); if (scoreQ()=0.0; fa->FFp(BQ::FauxIndex(fa))->Q()=0.0; } } static bool IdentifyAndCollapseSmallestDiag(MeshType &m){ 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 = BQ::Diag(f).Norm(); if (scoreFFp(k),(fa->FFi(k)+2)%3, m )) return true; if (flip) { if (!BQ::CheckFlipDiag(*fa) ) { // I can't collapse (why?) MarkFace(fa,m); return false; } else BQ::CollapseCounterDiag(*fa, BQ::PosOnDiag(*fa,true), m ); } else { BQ::CollapseDiag(*fa, BQ::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)- Returns number of removed Doublets */ static int RemoveDoublets(MeshType &m, Pos *p=NULL) { int res=0; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { fi->Q()=1; for (int k=0; k<3; k++) { if ( BQ::IsDoublet(*fi,k) ){ res++; BQ::RemoveDoublet(*fi,k,m,p); if (fi->IsD()) break; // break wedge circle, if face disappeard if (p) return res; } } } return res; } /* marks (Quality=0) and approx. counts profitable vertex rotations (vertex rotations which make edge shorter */ template static int MarkVertexRotations(MeshType &m, Pos *affected=NULL) { int res=0; 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 (BQ::TestVertexRotation(*fi,k)) { res++; fi->V(k)->SetV(); if (!perform) { res++; MarkVertex(&*fi, k, m); //fi->Q()=0; } else { if (BQ::RotateVertex(*fi, k, m, affected)) res++; //fi->Q()=0; if (affected) return res; // uncomment for only one rotation } } } } return res; } // mark (and count) all edges that are worth rotating // if perform == true, actually rotate them template static int MarkEdgeRotations(MeshType &m, Pos *p=NULL) { int count = 0; 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 = BQ::TestEdgeRotation(*fi, k); if (perform) { if (best==+1) if (BQ::template RotateEdge< true>(*fi, k, m, p)) count++; if (best==-1) if (BQ::template RotateEdge(*fi, k, m, p)) count++; if (p) if (count>0) return 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) */ static int MarkDoublets(MeshType &m) { int res=0; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { fi->Q()=1; for (int k=0; k<3; k++) { if ( BQ::IsDoublet(*fi,k) ){ res++; if (fi->IsF((k+1)%3)) res++; // counts for a quad fi->Q()=0; } } } assert (res%2==0); return res/4; // return doublet pairs (approx, as a quad could be a part of many pairs) } /* marks (Quality=0) and counts singlets (vertex B in an A-B-A-C quad) */ static int MarkSinglets(MeshType &m) { int res=0; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { fi->Q()=1; for (int k=0; k<3; k++) { if ( BQ::IsSinglet(*fi,k) ){ res++; fi->Q()=0; } } } assert (res%2==0); return res/2; // return number of singlet pairs } /* deletes singlets, reutrns number of */ static int RemoveSinglets(MeshType &m, Pos *p=NULL) { int res=0; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { for (int k=0; k<3; k++) { if ( BQ::IsSinglet(*fi,k) ){ res++; BQ::RemoveSinglet(*fi,k,m, p); if (p) return res; break; } } } return res; // return singlet pairs (approx, as a quad could be a part of many pairs) } /* returns average quad quality, and assigns it to triangle quality */ static ScalarType MeasureQuality(MeshType &m) { assert(MeshType::HasPerFaceFlags()); ScalarType res = 0; int div = 0; for (FaceIterator fi = m.face.begin(); fi!=m.face.end(); fi++) if (!fi->IsD()) { if (fi->IsAnyF()) { ScalarType q = BQ::quadQuality( &*fi, BQ::FauxIndex(&*fi) ); if (MeshType::HasPerFaceQuality()) fi->Q() = q; res += q; div++; } } if (!div) return 0; else return res / div; } }; }} // end namespace vcg::tri #endif