00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00209
00210
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
00216 if(!_pos.F()->IsW() || !_pos.F()->FFp(i)->IsW())
00217 return false;
00218
00219 return true;
00220 }
00221
00225
00226
00227
00228
00229
00230
00231
00232
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
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
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
00306 }
00307 }
00308 }
00309 }
00310 }
00311
00314 virtual void UpdateHeap(HeapType &heap, BaseParameterClass *pp)
00315 {
00316 GlobalMark()++;
00317
00318
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 };
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
00384
00385
00386
00387
00388
00389
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
00399
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
00409
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
00459
00460
00461
00462
00463
00464
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
00474
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
00504 f1->V0(i)->Q()--;
00505 f1->V1(i)->Q()--;
00506 f1->V2(i)->Q()++;
00507 f2->V2(j)->Q()++;
00508
00509
00510 vcg::face::FlipEdge(*this->_pos.F(), this->_pos.E());
00511
00512
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
00523 VertexIterator vi;
00524 for(vi = m.vert.begin(); vi != m.vert.end(); ++vi)
00525 if(!(*vi).IsD())
00526 (*vi).Q() = 0;
00527
00528
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
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
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
00571 for(int i = 0; i < 3; i++) {
00572 PosType startpos(f1, i);
00573 PosType pos(startpos);
00574
00575 do {
00576 pos.NextE();
00577 } while(pos != startpos && !pos.IsBorder());
00578
00579
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 {
00596 pos.NextE();
00597 } while(pos != startpos && !pos.IsBorder());
00598
00599
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 }
00615 }
00616
00617 #endif