halfedge_quad_clean.h
Go to the documentation of this file.
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                     // No doublets
00092                     case 0:
00093                         return NULL;
00094 
00095                     // A single doublet
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                     // Two doublets on the same face
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                            // Removal of the doublet may generate a singlet
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                                     // Check if the removal of the singlet generated other singlets, then iteratively remove them
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                      // Four doublets: simply remove one of the two faces
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                     // edge must be shared by two faces
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                                 // Record old vertices for future removal of doublets
00383                                 vertices.push_back((*hi)->HVp());
00384                                 vertices.push_back((*hi)->HOp()->HVp());
00385 
00386                                 // Add modified faces into the set of faces
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                                 // After a rotation doublets may have generated
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                                     // Record old vertices for future removal of doublets
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                                     // After a rotation doublets may have generated
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                  Indices of vertices into vector valences:
00522 
00523                   3-------2
00524                   |       |
00525                   |  f1   |
00526                   |       |
00527                   0-------1
00528                   |       |
00529                   |  f2   |
00530                   |       |
00531                   4-------5
00532 
00533                   */
00534 
00535                 // Compute valencies of vertices
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                 // Vector containing sums of the valencies in all the possible cases: no rotation, ccw rotation, cw rotation
00544                 vector<int> sums;
00545 
00546                 // positions:
00547                 // sums[0]: now (No rotation)
00548                 // sums[1]: flipping ccw
00549                 // sums[2]: flipping cw
00550 
00551                 // No rotation
00552                 sums.push_back( pow(valences, 2.0).sum() );
00553 
00554                 // CCW
00555                 valences[0]--;
00556                 valences[1]--;
00557                 valences[2]++;
00558                 valences[4]++;
00559 
00560                 sums.push_back( pow(valences, 2.0).sum() );
00561 
00562                 // CW
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                 // Vector containing sums of the valencies in all the possible cases: no rotation, ccw rotation, cw rotation
00622                 vector<int> sums;
00623 
00624                 // positions:
00625                 // sums[0]: now (No rotation)
00626                 // sums[1]: flipping ccw
00627                 // sums[2]: flipping cw
00628 
00629                 // No rotation
00630                 sums.push_back( distance_from_homeometry(face1, face2, 0) );
00631 
00632                 // CCW
00633                 face1[1] = face2[2];
00634                 face2[1] = face1[2];
00635 
00636                 sums.push_back( distance_from_homeometry(face1, face2, 1) );
00637 
00638                 // CW
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                 // Ideal edge length
00687                 float mu = sqrt( (area(face1) + area(face2)) / 2 );
00688 
00689                 // Length of the i-th edge (the edge changed with a rotation)
00690                 float edge_length = Distance( face1[i]->cP(), face1[i+1]->cP() );
00691 
00692                 // Length of the diagonals
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                 // Ideal diagonal length
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


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