tri_edge_flip.h
Go to the documentation of this file.
00001 /****************************************************************************
00002  * VCGLib                                                            o o     *
00003  * Visual and Computer Graphics Library                            o     o   *
00004  *                                                                _   O  _   *
00005  * Copyright(C) 2004                                                \/)\/    *
00006  * Visual Computing Lab                                            /\/|      *
00007  * ISTI - Italian National Research Council                           |      *
00008  *                                                                    \      *
00009  * All rights reserved.                                                      *
00010  *                                                                           *
00011  * This program is free software; you can redistribute it and/or modify      *
00012  * it under the terms of the GNU General Public License as published by      *
00013  * the Free Software Foundation; either version 2 of the License, or         *
00014  * (at your option) any later version.                                       *
00015  *                                                                           *
00016  * This program is distributed in the hope that it will be useful,           *
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of            *
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
00019  * GNU General Public License (http://www.gnu.org/licenses/gpl.txt)          *
00020  * for more details.                                                         *
00021  *                                                                           *
00022  ****************************************************************************/
00023 
00024 #ifndef __VCG_DECIMATION_TRIFLIP
00025 #define __VCG_DECIMATION_TRIFLIP
00026 
00027 #include <vcg/complex/algorithms/local_optimization.h>
00028 #include <vcg/simplex/face/topology.h>
00029 #include <vcg/space/triangle3.h>
00030 
00031 namespace vcg
00032 {
00033 namespace tri
00034 {
00036 /* @{ */
00037 
00038 class PlanarEdgeFlipParameter : public BaseParameterClass
00039 {
00040 public:
00041   PlanarEdgeFlipParameter() {SetDefaultParams();}
00042   void SetDefaultParams()
00043   {
00044     CoplanarAngleThresholdDeg=0.1f;
00045   }
00046 
00047   float CoplanarAngleThresholdDeg;
00048 };
00049 
00059 template <class TRIMESH_TYPE, class MYTYPE,
00060             typename TRIMESH_TYPE::ScalarType (*QualityFunc)(
00061                     Point3<typename TRIMESH_TYPE::ScalarType> const & p0,
00062                     Point3<typename TRIMESH_TYPE::ScalarType> const & p1,
00063                     Point3<typename TRIMESH_TYPE::ScalarType> const & p2) = Quality>
00064 class PlanarEdgeFlip :
00065     public LocalOptimization< TRIMESH_TYPE>::LocModType
00066 {
00067 protected:
00068     typedef typename TRIMESH_TYPE::FaceType FaceType;
00069     typedef typename TRIMESH_TYPE::FacePointer FacePointer;
00070     typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
00071     typedef typename TRIMESH_TYPE::VertexType VertexType;
00072     typedef typename TRIMESH_TYPE::ScalarType ScalarType;
00073     typedef typename TRIMESH_TYPE::VertexPointer VertexPointer;
00074     typedef typename TRIMESH_TYPE::CoordType CoordType;
00075     typedef vcg::face::Pos<FaceType> PosType;
00076     typedef typename LocalOptimization<TRIMESH_TYPE>::HeapElem HeapElem;
00077     typedef typename LocalOptimization<TRIMESH_TYPE>::HeapType HeapType;
00078 
00082     PosType _pos;
00083 
00087     ScalarType _priority;
00088 
00092     int _localMark;
00093 
00097     static int& GlobalMark()
00098     {
00099         static int im = 0;
00100         return im;
00101     }
00102 
00103   static void Insert(HeapType& heap, PosType& p, int mark, BaseParameterClass *pp)
00104     {
00105         if(!p.IsBorder() && p.F()->IsW() && p.FFlip()->IsW()) {
00106       MYTYPE* newflip = new MYTYPE(p, mark,pp);
00107             heap.push_back(HeapElem(newflip));
00108             std::push_heap(heap.begin(), heap.end());
00109         }
00110     }
00111 
00112 public:
00116     inline PlanarEdgeFlip()
00117     {
00118     }
00119 
00120 
00124   inline PlanarEdgeFlip(PosType pos, int mark,BaseParameterClass *pp)
00125     {
00126         _pos = pos;
00127         _localMark = mark;
00128     _priority = this->ComputePriority(pp);
00129     }
00130 
00131 
00135     inline PlanarEdgeFlip(const PlanarEdgeFlip &par)
00136     {
00137         _pos = par.GetPos();
00138         _localMark = par.GetMark();
00139         _priority = par.Priority();
00140     }
00141 
00142 
00145     ~PlanarEdgeFlip()
00146     {
00147     }
00148 
00149 
00154     inline PosType GetPos() const
00155     {
00156         return _pos;
00157     }
00158 
00159     inline int GetMark()const
00160     {
00161         return _localMark;
00162     }
00163 
00164 
00168     ModifierType IsOfType()
00169     {
00170         return TriEdgeFlipOp;
00171     }
00172 
00173 
00177   bool IsUpToDate() const
00178     {
00179     int lastMark = _pos.F()->cV(0)->IMark();
00180     lastMark = std::max<int>(lastMark, _pos.F()->V(1)->IMark());
00181     lastMark = std::max<int>(lastMark, _pos.F()->V(2)->IMark());
00182 
00183         return ( _localMark >= lastMark );
00184     }
00185 
00191   virtual bool IsFeasible(BaseParameterClass *_pp)
00192     {
00193     PlanarEdgeFlipParameter *pp=(PlanarEdgeFlipParameter *)_pp;
00194         if(!vcg::face::CheckFlipEdge(*this->_pos.F(), this->_pos.E()))
00195             return false;
00196 
00197     if( math::ToDeg( Angle(_pos.FFlip()->cN(), _pos.F()->cN()) ) > pp->CoplanarAngleThresholdDeg )
00198             return false;
00199 
00200         CoordType v0, v1, v2, v3;
00201         int i = _pos.E();
00202 
00203         v0 = _pos.F()->P0(i);
00204         v1 = _pos.F()->P1(i);
00205         v2 = _pos.F()->P2(i);
00206         v3 = _pos.F()->FFp(i)->P2(_pos.F()->FFi(i));
00207 
00208         // Take the parallelogram formed by the adjacent faces of edge
00209         // If a corner of the parallelogram on extreme of edge to flip is >= 180
00210         // the flip produce two identical faces - avoid this
00211         if( (Angle(v2 - v0, v1 - v0) + Angle(v3 - v0, v1 - v0) >= M_PI) ||
00212             (Angle(v2 - v1, v0 - v1) + Angle(v3 - v1, v0 - v1) >= M_PI))
00213             return false;
00214 
00215         // if any of two faces adj to edge in non writable, the flip is unfeasible
00216         if(!_pos.F()->IsW() || !_pos.F()->FFp(i)->IsW())
00217             return false;
00218 
00219         return true;
00220     }
00221 
00225     /*
00226          1
00227         /|\
00228        / | \
00229       2  |  3
00230        \ | /
00231         \|/
00232          0
00233      */
00234   ScalarType ComputePriority(BaseParameterClass *)
00235     {
00236         CoordType v0, v1, v2, v3;
00237         int i = _pos.E();
00238         v0 = _pos.F()->P0(i);
00239         v1 = _pos.F()->P1(i);
00240         v2 = _pos.F()->P2(i);
00241         v3 = _pos.F()->FFp(i)->P2(_pos.F()->FFi(i));
00242 
00243         ScalarType Qa = QualityFunc(v0, v1, v2);
00244         ScalarType Qb = QualityFunc(v0, v3, v1);
00245 
00246         ScalarType QaAfter = QualityFunc(v1, v2, v3);
00247         ScalarType QbAfter = QualityFunc(v0, v3, v2);
00248 
00249         // < 0 if the average quality of faces improves after flip
00250         _priority = (Qa + Qb - QaAfter - QbAfter) / (ScalarType)2.0;
00251 
00252         return _priority;
00253     }
00254 
00258     virtual ScalarType Priority() const
00259     {
00260         return _priority;
00261     }
00262 
00266   void Execute(TRIMESH_TYPE &m, BaseParameterClass *)
00267     {
00268         int i = _pos.E();
00269         int j = _pos.F()->FFi(i);
00270         FacePointer f1 = _pos.F();
00271         FacePointer f2 = _pos.F()->FFp(i);
00272 
00273         vcg::face::FlipEdge(*_pos.F(), _pos.E());
00274 
00275         // avoid texture coordinates swap after flip
00276         if(tri::HasPerWedgeTexCoord(m)) {
00277             f2->WT((j + 1) % 3) = f1->WT((i + 2) % 3);
00278             f1->WT((i + 1) % 3) = f2->WT((j + 2) % 3);
00279         }
00280     }
00281 
00284     const char* Info(TRIMESH_TYPE &m)
00285     {
00286         static char dump[60];
00287         sprintf(dump,"%lu -> %lu %g\n", tri::Index(m,_pos.F()->V(0)), tri::Index(m,_pos.F()->V(1)),-_priority);
00288         return dump;
00289     }
00290 
00293   static void Init(TRIMESH_TYPE &mesh, HeapType &heap, BaseParameterClass *pp)
00294     {
00295         heap.clear();
00296         FaceIterator fi;
00297         for(fi = mesh.face.begin(); fi != mesh.face.end(); ++fi) {
00298             if(!(*fi).IsD() && (*fi).IsW()) {
00299                 for(unsigned int i = 0; i < 3; i++) {
00300                     if( !(*fi).IsB(i) && !((*fi).FFp(i)->IsD()) && (*fi).FFp(i)->IsW() ) {
00301                         if((*fi).V1(i) - (*fi).V0(i) > 0) {
00302                             PosType p(&*fi, i);
00303               Insert(heap, p,  IMark(mesh),pp);
00304                         }
00305                             //heap.push_back( HeapElem( new MYTYPE(PosType(&*fi, i), mesh.IMark() )) );
00306                     } //endif
00307                 } //endfor
00308             }
00309         } //endfor
00310     }
00311 
00314   virtual void UpdateHeap(HeapType &heap, BaseParameterClass *pp)
00315     {
00316         GlobalMark()++;
00317 
00318         // after flip, the new edge just created is the next edge
00319         int flipped = (_pos.E() + 1) % 3;
00320 
00321         PosType pos(_pos.F(), flipped);
00322 
00323         pos.F()->V(0)->IMark() = GlobalMark();
00324         pos.F()->V(1)->IMark() = GlobalMark();
00325         pos.F()->V(2)->IMark() = GlobalMark();
00326         pos.F()->FFp(flipped)->V2(pos.F()->FFi(flipped))->IMark() = GlobalMark();
00327 
00328         pos.FlipF(); pos.FlipE();
00329     Insert(heap, pos, GlobalMark(),pp);
00330 
00331         pos.FlipV(); pos.FlipE();
00332     Insert(heap, pos, GlobalMark(),pp);
00333 
00334         pos.FlipV(); pos.FlipE();
00335         pos.FlipF(); pos.FlipE();
00336     Insert(heap, pos, GlobalMark(),pp);
00337 
00338         pos.FlipV(); pos.FlipE();
00339     Insert(heap, pos, GlobalMark(),pp);
00340     }
00341 }; // end of PlanarEdgeFlip class
00342 
00343 
00344 template <class TRIMESH_TYPE, class MYTYPE>
00345 class TriEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE>
00346 {
00347 protected:
00348     typedef typename TRIMESH_TYPE::FaceType FaceType;
00349     typedef typename TRIMESH_TYPE::ScalarType ScalarType;
00350     typedef typename TRIMESH_TYPE::CoordType CoordType;
00351     typedef vcg::face::Pos<FaceType> PosType;
00352 
00353 public:
00357     inline TriEdgeFlip() {}
00358 
00362   inline TriEdgeFlip(const PosType pos, int mark, BaseParameterClass *pp)
00363     {
00364         this->_pos = pos;
00365         this->_localMark = mark;
00366     this->_priority = ComputePriority(pp);
00367     }
00368 
00372     inline TriEdgeFlip(const TriEdgeFlip &par)
00373     {
00374         this->_pos = par.GetPos();
00375         this->_localMark = par.GetMark();
00376         this->_priority = par.Priority();
00377     }
00378 
00379 
00380   ScalarType ComputePriority(BaseParameterClass *)
00381     {
00382         /*
00383              1
00384             /|\
00385            / | \
00386           2  |  3
00387            \ | /
00388             \|/
00389              0
00390          */
00391         CoordType v0, v1, v2, v3;
00392         int i = this->_pos.E();
00393         v0 = this->_pos.F()->P0(i);
00394         v1 = this->_pos.F()->P1(i);
00395         v2 = this->_pos.F()->P2(i);
00396         v3 = this->_pos.F()->FFp(i)->P2(this->_pos.F()->FFi(i));
00397 
00398         // if the sum of angles in v2 e v3 is > 180, then the triangle
00399         // pair is not a delaunay triangulation
00400         ScalarType alpha = math::Abs(Angle(v0 - v2, v1 - v2));
00401         ScalarType beta = math::Abs(Angle(v0 - v3, v1 - v3));
00402         this->_priority = 180 - math::ToDeg((alpha + beta));
00403         return this->_priority;
00404     }
00405 };
00406 
00407 
00408 // This kind of flip minimize the variance of number of incident faces
00409 // on the vertices of two faces involved in the flip
00410 template <class TRIMESH_TYPE, class MYTYPE>
00411 class TopoEdgeFlip : public PlanarEdgeFlip<TRIMESH_TYPE, MYTYPE>
00412 {
00413 protected:
00414     typedef typename TRIMESH_TYPE::VertexPointer VertexPointer;
00415 
00416     typedef typename TRIMESH_TYPE::FaceType FaceType;
00417     typedef typename TRIMESH_TYPE::FacePointer FacePointer;
00418     typedef typename TRIMESH_TYPE::ScalarType ScalarType;
00419     typedef typename TRIMESH_TYPE::CoordType CoordType;
00420     typedef vcg::face::Pos<FaceType> PosType;
00421 
00422     typedef typename LocalOptimization<TRIMESH_TYPE>::HeapElem HeapElem;
00423     typedef typename LocalOptimization<TRIMESH_TYPE>::HeapType HeapType;
00424 
00425     typedef typename TRIMESH_TYPE::FaceIterator FaceIterator;
00426     typedef typename TRIMESH_TYPE::VertexIterator VertexIterator;
00427 
00428 public:
00432     inline TopoEdgeFlip() {}
00433 
00437   inline TopoEdgeFlip(const PosType pos, int mark, BaseParameterClass *pp)
00438     {
00439         this->_pos = pos;
00440         this->_localMark = mark;
00441     this->_priority = ComputePriority(pp);
00442     }
00443 
00447     inline TopoEdgeFlip(const TopoEdgeFlip &par)
00448     {
00449         this->_pos = par.GetPos();
00450         this->_localMark = par.GetMark();
00451         this->_priority = par.Priority();
00452     }
00453 
00454 
00455   ScalarType ComputePriority(BaseParameterClass *)
00456     {
00457         /*
00458              1
00459             /|\
00460            / | \
00461           2  |  3
00462            \ | /
00463             \|/
00464              0
00465          */
00466         VertexPointer v0, v1, v2, v3;
00467         int i = this->_pos.E();
00468         v0 = this->_pos.F()->V0(i);
00469         v1 = this->_pos.F()->V1(i);
00470         v2 = this->_pos.F()->V2(i);
00471         v3 = this->_pos.F()->FFp(i)->V2(this->_pos.F()->FFi(i));
00472 
00473         // This kind of flip minimize the variance of number of incident faces
00474         // on the vertices of two faces involved in the flip
00475 
00476         ScalarType avg = (v0->Q() + v1->Q() + v2->Q() + v3->Q()) / 4.0;
00477 
00478         ScalarType varbefore = (powf(v0->Q() - avg, 2.0) +
00479                                 powf(v1->Q() - avg, 2.0) +
00480                                 powf(v2->Q() - avg, 2.0) +
00481                                 powf(v3->Q() - avg, 2.0)) / 4.0;
00482 
00483         ScalarType varafter = (powf(v0->Q() - 1 - avg, 2.0) +
00484                                powf(v1->Q() - 1 - avg, 2.0) +
00485                                powf(v2->Q() + 1 - avg, 2.0) +
00486                                powf(v3->Q() + 1 - avg, 2.0)) / 4.0;
00487 
00488         this->_priority = varafter - varbefore;
00489         return this->_priority;
00490     }
00491 
00492 
00496     void Execute(TRIMESH_TYPE &m, BaseParameterClass *)
00497     {
00498         int i = this->_pos.E();
00499         FacePointer f1 = this->_pos.F();
00500         FacePointer f2 = f1->FFp(i);
00501         int j = f1->FFi(i);
00502 
00503         // update the number of faces adjacent to vertices
00504         f1->V0(i)->Q()--;
00505         f1->V1(i)->Q()--;
00506         f1->V2(i)->Q()++;
00507         f2->V2(j)->Q()++;
00508 
00509         // do the flip
00510         vcg::face::FlipEdge(*this->_pos.F(), this->_pos.E());
00511 
00512         // avoid texture coordinates swap after flip
00513         if (tri::HasPerWedgeTexCoord(m)) {
00514             f2->WT((j + 1) % 3) = f1->WT((i + 2) % 3);
00515             f1->WT((i + 1) % 3) = f2->WT((j + 2) % 3);
00516         }
00517     }
00518 
00519 
00520   static void Init(TRIMESH_TYPE &m, HeapType &heap,BaseParameterClass *pp)
00521     {
00522         // reset quality field for each vertex
00523         VertexIterator vi;
00524         for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00525             if(!(*vi).IsD())
00526                 (*vi).Q() = 0;
00527 
00528         // for each vertex, put the number of incident faces in quality field
00529         FaceIterator fi;
00530         for(fi = m.face.begin(); fi != m.face.end(); ++fi)
00531             if(!(*fi).IsD())
00532                 for(int i = 0; i < 3; i++)
00533                     (*fi).V(i)->Q()++;
00534 
00535     TriEdgeFlip<TRIMESH_TYPE, MYTYPE>::Init(m, heap, pp);
00536     }
00537 
00538 
00539     void UpdateHeap(HeapType &heap, BaseParameterClass *pp)
00540     {
00541         this->GlobalMark()++;
00542 
00543         VertexPointer v0, v1, v2, v3;
00544         int flipped = (this->_pos.E() + 1) % 3;
00545         FacePointer f1 = this->_pos.F();
00546         FacePointer f2 = this->_pos.F()->FFp(flipped);
00547 
00548         v0 = f1->V0(flipped);
00549         v1 = f1->V1(flipped);
00550         v2 = f1->V2(flipped);
00551         v3 = f2->V2(f1->FFi(flipped));
00552 
00553         v0->IMark() = this->GlobalMark();
00554         v1->IMark() = this->GlobalMark();
00555         v2->IMark() = this->GlobalMark();
00556         v3->IMark() = this->GlobalMark();
00557 
00558         // edges of the first face, except the flipped edge
00559         for(int i = 0; i < 3; i++) if(i != flipped) {
00560             PosType newpos(f1, i);
00561             this->Insert(heap, newpos, this->GlobalMark(),pp);
00562         }
00563 
00564         // edges of the second face, except the flipped edge
00565         for(int i = 0; i < 3; i++) if(i != f1->FFi(flipped)) {
00566             PosType newpos(f2, i);
00567             this->Insert(heap, newpos, this->GlobalMark(),pp);
00568         }
00569 
00570         // every edge with v0, v1 v3 of f1
00571         for(int i = 0; i < 3; i++) {
00572             PosType startpos(f1, i);
00573             PosType pos(startpos);
00574 
00575             do { // go to the first border (if there is one)
00576                 pos.NextE();
00577             } while(pos != startpos && !pos.IsBorder());
00578 
00579             // if a border is reached, set startpos here
00580             if(pos.IsBorder())
00581                 startpos = pos;
00582 
00583             do {
00584                 VertexPointer v = pos.VFlip();
00585                 if(v != v0 && v != v1 && v != v2 && v != v3)
00586                 this->Insert(heap, pos, this->GlobalMark(),pp);
00587 
00588                 pos.NextE();
00589             } while(pos != startpos && !pos.IsBorder());
00590         }
00591 
00592         PosType startpos(f2, (f1->FFi(flipped) + 2) % 3);
00593         PosType pos(startpos);
00594 
00595         do { // go to the first border (if there is one)
00596             pos.NextE();
00597         } while(pos != startpos && !pos.IsBorder());
00598 
00599         // if a border is reached, set startpos here
00600         if(pos.IsBorder())
00601             startpos = pos;
00602 
00603         do {
00604             VertexPointer v = pos.VFlip();
00605             if(v != v0 && v != v1 && v != v2 && v != v3)
00606             this->Insert(heap, pos, this->GlobalMark(),pp);
00607 
00608             pos.NextE();
00609         } while(pos != startpos && !pos.IsBorder());
00610     }
00611 };
00612 
00613 
00614 } // end of namespace tri
00615 } // end of namespace vcg
00616 
00617 #endif


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:37:50