#include #include #include #include #include #include #include #include #include #include #include #include // topology computation #include #include #include // half edge iterators #include // input output #include #include using namespace vcg; using namespace std; class MyFace; class MyVertex; struct MyUsedTypes : public UsedTypes< Use ::AsVertexType, Use ::AsFaceType>{}; class MyVertex : public Vertex< MyUsedTypes, vertex::Coord3f, vertex::BitFlags, vertex::Normal3f, vertex::Mark, vertex::Color4b >{}; class MyFace : public Face < MyUsedTypes, face::VertexRef,face::FFAdj, face::Mark, face::BitFlags, face::Normal3f> {}; class MyMesh : public tri::TriMesh< vector, vector >{}; //Delaunay class MyDelaunayFlip: public vcg::tri::TriEdgeFlip< MyMesh, MyDelaunayFlip > { public: typedef vcg::tri::TriEdgeFlip< MyMesh, MyDelaunayFlip > TEF; inline MyDelaunayFlip( const TEF::PosType &p, int i) :TEF(p,i){} }; bool callback(int percent, const char *str) { cout << "str: " << str << " " << percent << "%\r"; return true; } template bool NormalTest(typename face::Pos pos) { //giro intorno al vertice e controllo le normali float accum=0; typename MESH::ScalarType thr = 0.0f; typename MESH::CoordType NdP = Normal(*pos.f); typename MESH::CoordType tmp, oop, soglia = typename MESH::CoordType(thr,thr,thr); face::Pos aux=pos; do{ aux.FlipF(); aux.FlipE(); oop = Abs(tmp - Normal(*pos.f)); if(oop < soglia )return false; }while(aux != pos && !aux.IsBorder()); return true; } 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\n",algorithm); exit(0); } MyMesh m; if(tri::io::ImporterPLY::Open(m,argv[3])!=0) { printf("Error reading file %s\n",argv[2]); exit(0); } //update the face-face topology tri::UpdateTopology::FaceFace(m); tri::UpdateNormals::PerVertexPerFace(m); tri::UpdateFlags::FaceBorderFromFF(m); assert(tri::Clean::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 holeFiller; switch(algorithm) { case 1: tri::Hole::EarCuttingFill >(m,holeSize,false); break; case 2: tri::Hole::EarCuttingFill >(m,holeSize,false,callback); break; case 3: tri::Hole::EarCuttingIntersectionFill >(m,holeSize,false); break; case 4: tri::Hole::MinimumWeightFill(m,holeSize, false); tri::UpdateTopology::FaceFace(m); break; } tri::UpdateFlags::FaceBorderFromFF(m); assert(tri::Clean::IsFFAdjacencyConsistent(m)); printf("\nStart refinig...\n"); /*start refining */ MyMesh::VertexIterator vi; MyMesh::FaceIterator f; std::vector vf; f = m.face.begin(); f += indice; for(; f != m.face.end();++f) { if(!f->IsD()) { f->SetS(); } } std::vector FPP; std::vector added; std::vector::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(); } } vcg::LocalOptimization Fs(m); Fs.SetTargetMetric(0.0f); Fs.Init(); 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(*f)/2) > AVG; if(test) { vf.push_back(&(*f)); } } } //info print printf("\r Raffino [%d] - > %d",i,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::AddFaces(m,(toadd*2),FPP); MyMesh::VertexIterator vertp = tri::Allocator::AddVertices(m,toadd); std::vector added; added.reserve(toadd); vfit=vf.begin(); for(int i = 0; i >(vf[i],&(*f1),&(*f2),&(*vertp),CenterPoint() ); 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) ); } vcg::LocalOptimization FlippingSession(m); FlippingSession.SetTargetMetric(0.0f); FlippingSession.Init(); FlippingSession.DoOptimization(); }while(!vf.empty()); vcg::LocalOptimization Fiss(m); Fiss.SetTargetMetric(0.0f); Fiss.Init(); Fiss.DoOptimization(); /*end refining */ tri::io::ExporterPLY::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(face::Pos(&(*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::VertexCoordLaplacian(m,1,true); printf("\nCompleted. Saving....\n"); tri::io::ExporterPLY::Save(m,argv[4],false); return 0; }