int main(int ,char ** ){ MyMesh m; //generate a mesh vcg::tri::Icosahedron(m); //update the face-face topology vcg::tri::UpdateTopology<MyMesh>::FaceFace(m); // Now for each face the F() members are meaningful if(face::IsBorder(m.face[0],0)) printf("Edge 0 of face 0 is a border\n"); else printf("Edge 0 of face 0 is NOT a border\n"); // always this path! vcg::face::FFDetach<MyFace>(m.face[0],0); // Detach the face [0] from the mesh vcg::face::FFDetach<MyFace>(m.face[0],1); vcg::face::FFDetach<MyFace>(m.face[0],2); if(face::IsBorder(m.face[0],0)) printf("Edge 0 of face 0 is a border\n"); // always this path! else printf("Edge 0 of face 0 is NOT a border\n"); m.face[0].SetD(); // deleting face [0] (i.e. marked as deleted) // declare an iterator on the mesh vcg::face::Pos<MyMesh::FaceType> he, hei; // Now a simple search and trace of all the border of the mesh MyMesh::FaceIterator fi; UnMarkAll(m); int BorderEdgeNum=0; int HoleNum=0; for(fi=m.face.begin();fi!=m.face.end();++fi) if(!(*fi).IsD()) { for(int j=0;j<3;j++) { if ( face::IsBorder(*fi,j) && tri::IsMarked(m,&*fi)) { tri::Mark(m,&*fi); hei.Set(&*fi,j,fi->V(j)); he=hei; do { BorderEdgeNum++; he.NextB(); // next edge along a border tri::Mark(m,he.f); } while (he.f!=hei.f); HoleNum++; } } } printf("Mesh has %i holes and %i border edges\n",HoleNum,BorderEdgeNum); return 0; }
int main(int argc,char ** argv){ if(argc<5) { printf( "\n HoleFilling ("__DATE__")\n" "Visual Computing Group I.S.T.I. C.N.R.\n" "Usage: trimesh_hole #algorithm #size filein.ply fileout.ply \n" "#algorithm: \n" " 1) Trivial Ear \n" " 2) Minimum weight Ear \n" " 3) Selfintersection Ear \n" " 4) Minimum weight \n" ); exit(0); } int algorithm = atoi(argv[1]); int holeSize = atoi(argv[2]); if(algorithm < 0 && algorithm > 4) { printf("Error in algorithm's selection %i\n",algorithm); exit(0); } MyMesh m; if(tri::io::ImporterPLY<MyMesh>::Open(m,argv[3])!=0) { printf("Error reading file %s\n",argv[2]); exit(0); } //update the face-face topology tri::UpdateTopology<MyMesh>::FaceFace(m); tri::UpdateNormals<MyMesh>::PerVertexPerFace(m); tri::UpdateFlags<MyMesh>::FaceBorderFromFF(m); assert(tri::Clean<MyMesh>::IsFFAdjacencyConsistent(m)); //compute the average of face area float AVG,sumA=0.0f; int numA=0,indice; indice = m.face.size(); MyMesh::FaceIterator fi; for(fi=m.face.begin();fi!=m.face.end();++fi) { sumA += DoubleArea(*fi)/2; numA++; for(int ind =0;ind<3;++ind) fi->V(ind)->InitIMark(); } AVG=sumA/numA; //tri::Hole<MyMesh> holeFiller; switch(algorithm) { case 1: tri::Hole<MyMesh>::EarCuttingFill<tri::TrivialEar<MyMesh> >(m,holeSize,false); break; case 2: tri::Hole<MyMesh>::EarCuttingFill<tri::MinimumWeightEar< MyMesh> >(m,holeSize,false,callback); break; case 3: tri::Hole<MyMesh>::EarCuttingIntersectionFill<tri::SelfIntersectionEar< MyMesh> >(m,holeSize,false); break; case 4: tri::Hole<MyMesh>::MinimumWeightFill(m,holeSize, false); tri::UpdateTopology<MyMesh>::FaceFace(m); break; } tri::UpdateFlags<MyMesh>::FaceBorderFromFF(m); assert(tri::Clean<MyMesh>::IsFFAdjacencyConsistent(m)); printf("\nStart refinig...\n"); /*start refining */ MyMesh::VertexIterator vi; MyMesh::FaceIterator f; std::vector<MyMesh::FacePointer> vf; f = m.face.begin(); f += indice; for(; f != m.face.end();++f) { if(!f->IsD()) { f->SetS(); } } std::vector<MyMesh::FacePointer *> FPP; std::vector<MyMesh::FacePointer> added; std::vector<MyMesh::FacePointer>::iterator vfit; int i=1; printf("\n"); for(f = m.face.begin();f!=m.face.end();++f) if(!(*f).IsD()) { if( f->IsS() ) { f->V(0)->IsW(); f->V(1)->IsW(); f->V(2)->IsW(); } else { f->V(0)->ClearW(); f->V(1)->ClearW(); f->V(2)->ClearW(); } } BaseParameterClass pp; vcg::LocalOptimization<MyMesh> Fs(m,&pp); Fs.SetTargetMetric(0.0f); Fs.Init<MyDelaunayFlip >(); Fs.DoOptimization(); do { vf.clear(); f = m.face.begin(); f += indice; for(; f != m.face.end();++f) { if(f->IsS()) { bool test= true; for(int ind =0;ind<3;++ind) f->V(ind)->InitIMark(); test = (DoubleArea<MyMesh::FaceType>(*f)/2) > AVG; if(test) { vf.push_back(&(*f)); } } } //info print printf("\r Refining [%d] - > %d",i,int(vf.size())); i++; FPP.clear(); added.clear(); for(vfit = vf.begin(); vfit!=vf.end();++vfit) { FPP.push_back(&(*vfit)); } int toadd= vf.size(); MyMesh::FaceIterator f1,f2; f2 = tri::Allocator<MyMesh>::AddFaces(m,(toadd*2),FPP); MyMesh::VertexIterator vertp = tri::Allocator<MyMesh>::AddVertices(m,toadd); std::vector<MyMesh::FacePointer> added; added.reserve(toadd); vfit=vf.begin(); for(int i = 0; i<toadd;++i,f2++,vertp++) { f1=f2; f2++; TriSplit<MyMesh,CenterPoint<MyMesh> >(vf[i],&(*f1),&(*f2),&(*vertp),CenterPoint<MyMesh>() ); f1->SetS(); f2->SetS(); for(int itr=0;itr<3;itr++) { f1->V(itr)->SetW(); f2->V(itr)->SetW(); } added.push_back( &(*f1) ); added.push_back( &(*f2) ); } BaseParameterClass pp; vcg::LocalOptimization<MyMesh> FlippingSession(m,&pp); FlippingSession.SetTargetMetric(0.0f); FlippingSession.Init<MyDelaunayFlip >(); FlippingSession.DoOptimization(); }while(!vf.empty()); vcg::LocalOptimization<MyMesh> Fiss(m,&pp); Fiss.SetTargetMetric(0.0f); Fiss.Init<MyDelaunayFlip >(); Fiss.DoOptimization(); /*end refining */ tri::io::ExporterPLY<MyMesh>::Save(m,"PreSmooth.ply",false); int UBIT = MyMesh::VertexType::LastBitFlag(); f = m.face.begin(); f += indice; for(; f != m.face.end();++f) { if(f->IsS()) { for(int ind =0;ind<3;++ind){ if(NormalTest<MyMesh>(face::Pos<MyMesh::FaceType>(&(*f),ind ))) { f->V(ind)->SetUserBit(UBIT); } } f->ClearS(); } } for(vi=m.vert.begin();vi!=m.vert.end();++vi) if(!(*vi).IsD()) { if( vi->IsUserBit(UBIT) ) { (*vi).SetS(); vi->ClearUserBit(UBIT); } } tri::Smooth<MyMesh>::VertexCoordLaplacian(m,1,true); printf("\nCompleted. Saving....\n"); tri::io::ExporterPLY<MyMesh>::Save(m,argv[4],false); return 0; }