00001 #ifndef HALFEDGEQUADCLEAN_H
00002 #define HALFEDGEQUADCLEAN_H
00003
00004 #include <vcg/complex/algorithms/update/halfedge_topology.h>
00005 #include <queue>
00006 #include <set>
00007 #include<vcg/math/base.h>
00008 #include<valarray>
00009 #include<cmath>
00010
00011
00012 namespace vcg
00013 {
00014 namespace tri
00015 {
00021 template<class MeshType> class HalfedgeQuadClean
00022 {
00023
00024 protected:
00025
00026 typedef typename MeshType::VertexPointer VertexPointer;
00027 typedef typename MeshType::EdgePointer EdgePointer;
00028 typedef typename MeshType::HEdgePointer HEdgePointer;
00029 typedef typename MeshType::FacePointer FacePointer;
00030
00031 typedef typename MeshType::VertexIterator VertexIterator;
00032 typedef typename MeshType::EdgeIterator EdgeIterator;
00033 typedef typename MeshType::HEdgeIterator HEdgeIterator;
00034 typedef typename MeshType::FaceIterator FaceIterator;
00035
00042 static void add_faces(queue<FacePointer> &q, VertexPointer vp)
00043 {
00044 vector<FacePointer> faces = HalfEdgeTopology<MeshType>::get_incident_faces(vp);
00045
00046 for(typename vector<FacePointer>::iterator fi = faces.begin(); fi != faces.end(); ++fi)
00047 {
00048 if(*fi)
00049 q.push(*fi);
00050 }
00051 }
00052
00060 static void remove_doublets(MeshType &m, set<FacePointer> &faces, queue<FacePointer> &q)
00061 {
00062
00063 while(!q.empty())
00064 {
00065 FacePointer fp = q.front();
00066 q.pop();
00067
00068 if( !fp->IsD() )
00069 {
00070 faces.insert(remove_doublet(m,fp, &q));
00071 }
00072 }
00073 }
00074
00083 static FacePointer remove_doublet(MeshType &m, FacePointer fp, queue<FacePointer> *q = NULL)
00084 {
00085 vector<HEdgePointer> hedges = HalfEdgeTopology<MeshType>::find_doublet_hedges_quad(fp);
00086
00087 assert(hedges.size() <= 4);
00088
00089 switch(hedges.size())
00090 {
00091
00092 case 0:
00093 return NULL;
00094
00095
00096 case 1:
00097 if(q)
00098 {
00099 add_faces(*q, hedges[0]->HNp()->HVp());
00100
00101 add_faces(*q, hedges[0]->HPp()->HVp());
00102 }
00103
00104 return HalfEdgeTopology<MeshType>::doublet_remove_quad(m, hedges[0]->HVp());
00105
00106
00107 case 2:
00108 {
00109
00110 if(q)
00111 {
00112 add_faces(*q, hedges[0]->HNp()->HVp());
00113
00114 add_faces(*q, hedges[0]->HPp()->HVp());
00115 }
00116
00117 FacePointer fp1 = HalfEdgeTopology<MeshType>::doublet_remove_quad(m, hedges[0]->HVp());
00118
00119
00120 if(HalfEdgeTopology<MeshType>::is_singlet_quad(fp1))
00121 {
00122
00123 HEdgePointer hp = HalfEdgeTopology<MeshType>::singlet_remove_quad(m, fp1);
00124
00125 if(hp)
00126 {
00127 if(q)
00128 {
00129 if(hp->HFp())
00130 q->push(hp->HFp());
00131 if(hp->HOp()->HFp())
00132 q->push(hp->HOp()->HFp());
00133 }
00134
00135 int valence1, valence2;
00136
00137 valence1 = HalfEdgeTopology<MeshType>::vertex_valence(hp->HVp());
00138 valence2 = HalfEdgeTopology<MeshType>::vertex_valence(hp->HOp()->HVp());
00139
00140
00141 while(valence1 == 1 || valence2 == 1)
00142 {
00143
00144 assert(! (valence1 == 1 && valence2 == 1));
00145
00146 FacePointer singlet_pointer;
00147
00148 if(valence1 == 1 )
00149 singlet_pointer = hp->HFp();
00150 else
00151 singlet_pointer = hp->HOp()->HFp();
00152
00153 hp = HalfEdgeTopology<MeshType>::singlet_remove_quad(m, singlet_pointer);
00154
00155 if(!hp)
00156 break;
00157
00158 if(q)
00159 {
00160 if(hp->HFp())
00161 q->push(hp->HFp());
00162 if(hp->HOp()->HFp())
00163 q->push(hp->HOp()->HFp());
00164 }
00165
00166 valence1 = HalfEdgeTopology<MeshType>::vertex_valence(hp->HVp());
00167 valence2 = HalfEdgeTopology<MeshType>::vertex_valence(hp->HOp()->HVp());
00168
00169 }
00170 }
00171 }
00172
00173 return fp1;
00174 }
00175
00176
00177 case 4:
00178 HalfEdgeTopology<MeshType>::remove_face(m,fp->FHp()->HOp()->HFp());
00179 return fp;
00180
00181 default:
00182 assert(0);
00183 }
00184 }
00185
00186
00187
00188
00189 public:
00190
00198 static void remove_doublets(MeshType &m, set<FacePointer> &faces, vector<VertexPointer> vertices)
00199 {
00200 queue<FacePointer> q;
00201
00202 for(typename vector<VertexPointer>::iterator vi = vertices.begin(); vi != vertices.end(); ++vi)
00203 {
00204 vector<FacePointer> inc_faces = HalfEdgeTopology<MeshType>::get_incident_faces(*vi);
00205
00206 for(typename vector<FacePointer>::iterator fi = inc_faces.begin(); fi != inc_faces.end(); ++fi)
00207 {
00208 if(*fi)
00209 if( !((*fi)->IsD()) )
00210 q.push(*fi);
00211 }
00212 }
00213
00214 remove_doublets(m, faces, q);
00215 }
00216
00223 static void remove_doublets(MeshType &m, vector<VertexPointer> vertices)
00224 {
00225 set<FacePointer> faces;
00226
00227 remove_doublets(m,faces,vertices);
00228 }
00229
00236 static void remove_doublets(MeshType &m, set<FacePointer> &faces)
00237 {
00238
00239 queue<FacePointer> q;
00240
00241 for(typename set<FacePointer>::iterator fi = faces.begin(); fi != faces.end(); ++fi)
00242 {
00243 if(*fi)
00244 if( !((*fi)->IsD()) )
00245 q.push(*fi);
00246 }
00247
00248 remove_doublets(m, faces, q);
00249
00250 }
00251
00252
00259 static int remove_doublets(MeshType &m)
00260 {
00261 int count;
00262 int removed = 0;
00263 do
00264 {
00265 count = 0;
00266 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00267 {
00268 if( !((*fi).IsD()) )
00269 {
00270 if(remove_doublet(m, &(*fi)))
00271 count++;
00272 }
00273 }
00274
00275 removed += count;
00276
00277 }while(count != 0);
00278
00279 return removed;
00280 }
00281
00288 static int remove_singlets(MeshType &m)
00289 {
00290 int removed = 0;
00291 int count;
00292 do
00293 {
00294 count = 0;
00295 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00296 {
00297 if( !((*fi).IsD()) )
00298 {
00299 if( HalfEdgeTopology<MeshType>::is_singlet_quad(&(*fi)) )
00300 {
00301 HalfEdgeTopology<MeshType>::singlet_remove_quad(m, &(*fi));
00302 count++;
00303 }
00304 }
00305 }
00306
00307 removed += count;
00308
00309 }while(count != 0);
00310
00311 return removed;
00312 }
00313
00320 static bool has_singlets(MeshType &m)
00321 {
00322
00323 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00324 {
00325 if( !((*fi).IsD()) )
00326 {
00327 if( HalfEdgeTopology<MeshType>::is_singlet_quad(&(*fi)) )
00328 return true;
00329 }
00330 }
00331
00332 return false;
00333 }
00334
00341 static bool has_doublets(MeshType &m)
00342 {
00343
00344 for(FaceIterator fi = m.face.begin(); fi != m.face.end(); ++fi)
00345 {
00346 if( !((*fi).IsD()) )
00347 {
00348 if( HalfEdgeTopology<MeshType>::has_doublet_quad(&(*fi)) )
00349 return true;
00350 }
00351 }
00352
00353 return false;
00354 }
00355
00364 template<class PriorityType>
00365 static void flip_edges(MeshType &m, vector<HEdgePointer> &hedges, set<FacePointer> &faces)
00366 {
00367
00368 for(typename vector<HEdgePointer>::iterator hi = hedges.begin(); hi != hedges.end(); ++hi)
00369 {
00370
00371 if((*hi)->HFp() && (*hi)->HOp()->HFp())
00372 {
00373 if(!(*hi)->IsD() && !(*hi)->HFp()->IsD() && !(*hi)->HOp()->HFp()->IsD())
00374 {
00375 typename PriorityType::FlipType fliptype = PriorityType::best_flip( *hi );
00376
00377 if(fliptype != PriorityType::NO_FLIP)
00378 {
00379
00380 vector<VertexPointer> vertices;
00381
00382
00383 vertices.push_back((*hi)->HVp());
00384 vertices.push_back((*hi)->HOp()->HVp());
00385
00386
00387 faces.insert((*hi)->HFp());
00388 faces.insert((*hi)->HOp()->HFp());
00389
00390 bool cw = (fliptype == PriorityType::CW_FLIP);
00391 HalfEdgeTopology<MeshType>::edge_rotate_quad((*hi),cw);
00392
00393
00394 remove_doublets(m, faces, vertices);
00395
00396 }
00397 }
00398 }
00399 }
00400 }
00401
00408 template <class PriorityType>
00409 static int flip_edges(MeshType &m)
00410 {
00411 int count;
00412 int ret=0;
00413 do
00414 {
00415 count = 0;
00416 for(typename MeshType::EdgeIterator ei = m.edge.begin(); ei != m.edge.end(); ++ei)
00417 {
00418
00419 if( !(ei->IsD()) )
00420 {
00421 HEdgePointer hp = ei->EHp();
00422
00423 if(hp->HFp() && hp->HOp()->HFp())
00424 {
00425 typename PriorityType::FlipType fliptype = PriorityType::best_flip( hp );
00426
00427 if(fliptype != PriorityType::NO_FLIP)
00428 {
00429 vector<VertexPointer> vertices;
00430
00431
00432 vertices.push_back(hp->HVp());
00433 vertices.push_back(hp->HOp()->HVp());
00434
00435 bool cw = (fliptype == PriorityType::CW_FLIP);
00436 HalfEdgeTopology<MeshType>::edge_rotate_quad(hp,cw);
00437
00438
00439 remove_doublets(m, vertices);
00440
00441 count++;
00442 }
00443 }
00444
00445 }
00446 }
00447
00448 ret+=count;
00449
00450 }while(count != 0);
00451
00452 return ret;
00453 }
00454
00455 };
00456
00457
00462 template <class MeshType> class EdgeFlipPriority
00463 {
00464 public:
00465 typedef typename MeshType::HEdgePointer HEdgePointer;
00466
00468 enum FlipType { NO_FLIP, CW_FLIP, CCW_FLIP};
00469
00477 static FlipType best_flip( HEdgePointer hp);
00478 };
00479
00484 template <class MeshType> class VertReg: public EdgeFlipPriority<MeshType>
00485 {
00486
00487 public:
00488
00489 typedef typename MeshType::VertexPointer VertexPointer;
00490 typedef typename MeshType::EdgePointer EdgePointer;
00491 typedef typename MeshType::HEdgePointer HEdgePointer;
00492 typedef typename MeshType::FacePointer FacePointer;
00493
00494 typedef EdgeFlipPriority<MeshType> Base;
00495 typedef typename Base::FlipType FlipType;
00496
00498 VertReg(){}
00499
00500 ~VertReg(){}
00501
00509 static FlipType best_flip( HEdgePointer hp)
00510 {
00511 assert(hp);
00512 assert(!hp->IsD());
00513
00514 vector<VertexPointer> vps1 = HalfEdgeTopology<MeshType>::getVertices(hp->HFp(), hp);
00515
00516 vector<VertexPointer> vps2 = HalfEdgeTopology<MeshType>::getVertices(hp->HOp()->HFp(), hp->HOp());
00517
00518 valarray<double> valences(6);
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536 for(int i=0; i<4; i++)
00537 valences[i] = HalfEdgeTopology<MeshType>::vertex_valence(vps1[i]) - 4 ;
00538
00539 valences[4] = HalfEdgeTopology<MeshType>::vertex_valence(vps2[2]) - 4;
00540 valences[5] = HalfEdgeTopology<MeshType>::vertex_valence(vps2[3]) - 4;
00541
00542
00543
00544 vector<int> sums;
00545
00546
00547
00548
00549
00550
00551
00552 sums.push_back( pow(valences, 2.0).sum() );
00553
00554
00555 valences[0]--;
00556 valences[1]--;
00557 valences[2]++;
00558 valences[4]++;
00559
00560 sums.push_back( pow(valences, 2.0).sum() );
00561
00562
00563 valences[2]--;
00564 valences[4]--;
00565 valences[3]++;
00566 valences[5]++;
00567
00568 sums.push_back( pow(valences, 2.0).sum() );
00569
00570
00571 if( sums[2]<= sums[1] && sums[2]< sums[0] )
00572 return Base::CW_FLIP;
00573
00574 else if( sums[1]< sums[2] && sums[1]< sums[0] )
00575 return Base::CCW_FLIP;
00576
00577 return Base::NO_FLIP;
00578
00579 }
00580
00581 };
00582
00587 template <class MeshType> class Homeometry: public EdgeFlipPriority<MeshType>
00588 {
00589
00590 public:
00591
00592 typedef typename MeshType::VertexPointer VertexPointer;
00593 typedef typename MeshType::EdgePointer EdgePointer;
00594 typedef typename MeshType::HEdgePointer HEdgePointer;
00595 typedef typename MeshType::FacePointer FacePointer;
00596
00597
00598 typedef EdgeFlipPriority<MeshType> Base;
00599 typedef typename Base::FlipType FlipType;
00600
00602 Homeometry(){}
00603
00604 ~Homeometry(){}
00605
00613 static FlipType best_flip( HEdgePointer hp)
00614 {
00615 assert(hp);
00616 assert(!hp->IsD());
00617
00618 vector<VertexPointer> face1 = HalfEdgeTopology<MeshType>::getVertices(hp->HFp(), hp);
00619 vector<VertexPointer> face2 = HalfEdgeTopology<MeshType>::getVertices(hp->HOp()->HFp(), hp->HOp());
00620
00621
00622 vector<int> sums;
00623
00624
00625
00626
00627
00628
00629
00630 sums.push_back( distance_from_homeometry(face1, face2, 0) );
00631
00632
00633 face1[1] = face2[2];
00634 face2[1] = face1[2];
00635
00636 sums.push_back( distance_from_homeometry(face1, face2, 1) );
00637
00638
00639 face1[2] = face2[3];
00640 face2[2] = face1[3];
00641
00642 sums.push_back( distance_from_homeometry(face1, face2, 2) );
00643
00644
00645 if( sums[2]<= sums[1] && sums[2]< sums[0] )
00646 return Base::CW_FLIP;
00647
00648 else if( sums[1]< sums[2] && sums[1]< sums[0] )
00649 return Base::CCW_FLIP;
00650
00651 return Base::NO_FLIP;
00652
00653 }
00654
00655 protected:
00656
00664 static float area(vector<VertexPointer> &vertices)
00665 {
00666
00667 assert(vertices.size() == 4);
00668
00669 float tri1 = Norm( (vertices[1]->cP() - vertices[0]->cP()) ^ (vertices[2]->cP() - vertices[0]->cP()) );
00670 float tri2 = Norm( (vertices[2]->cP() - vertices[0]->cP()) ^ (vertices[3]->cP() - vertices[0]->cP()) );
00671
00672 return (tri1+tri2) / 2;
00673 }
00674
00684 static float distance_from_homeometry(vector<VertexPointer> &face1, vector<VertexPointer> &face2, int i)
00685 {
00686
00687 float mu = sqrt( (area(face1) + area(face2)) / 2 );
00688
00689
00690 float edge_length = Distance( face1[i]->cP(), face1[i+1]->cP() );
00691
00692
00693 valarray<float> diagonals(4);
00694
00695 diagonals[0] = Distance( face1[0]->cP(), face1[2]->cP() );
00696 diagonals[1] = Distance( face1[1]->cP(), face1[3]->cP() );
00697 diagonals[2] = Distance( face2[0]->cP(), face2[2]->cP() );
00698 diagonals[3] = Distance( face2[1]->cP(), face2[3]->cP() );
00699
00700
00701 float ideal_diag_length = SQRT_TWO*mu;
00702
00703 float sum_diagonals = pow(diagonals - ideal_diag_length, 2.0).sum();
00704
00705 return (pow (edge_length - mu , static_cast<float>(2.0)) + sum_diagonals);
00706 }
00707
00708 };
00709
00710 }
00711 }
00712 #endif // HALFEDGEQUADCLEAN_H