/**************************************************************************** * VCGLib o o * * Visual and Computer Graphics Library o o * * _ O _ * * Copyright(C) 2004-2016 \/)\/ * * Visual Computing Lab /\/| * * ISTI - Italian National Research Council | * * \ * * All rights reserved. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * * for more details. * * * ****************************************************************************/ #ifndef VORONOI_ATLAS_H #define VORONOI_ATLAS_H #include #include #include #include #include #include #include #include //#include namespace vcg { namespace tri { template class VoronoiAtlas { //private: public: class VoroEdge; class VoroFace; class VoroVertex; struct VoroUsedTypes : public UsedTypes< Use ::template AsVertexType, Use ::template AsEdgeType, Use ::template AsFaceType>{}; class VoroVertex : public Vertex< VoroUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::TexCoord2f, vertex::VFAdj , vertex::Qualityf, vertex::Color4b, vertex::BitFlags >{}; class VoroFace : public Face< VoroUsedTypes, face::VertexRef, face::BitFlags, face::FFAdj ,face::VFAdj , face::CurvatureDirf,face::WedgeTexCoord2f> {}; class VoroEdge : public Edge< VoroUsedTypes>{}; class VoroMesh : public tri::TriMesh< std::vector, std::vector , std::vector > {}; typedef typename VoroMesh::FaceIterator FaceIterator; typedef typename VoroMesh::VertexType VertexType; typedef typename VoroMesh::FaceType FaceType; static void CollectUVBorder(VoroMesh *rm, std::vector &uvBorder) { tri::UpdateTopology::FaceFace(*rm); tri::UpdateFlags::FaceClearV(*rm); for(FaceIterator fi=rm->face.begin();fi!=rm->face.end();++fi) { for(int j=0;j<3;++j) if(face::IsBorder(*fi,j) && !(fi->IsV())) { face::Pos pp(&*fi,j,fi->V(j)); assert(pp.IsBorder()); face::Pos startPos = pp; do { uvBorder.push_back( pp.F()->WT(pp.VInd()).P() ); pp.F()->SetV(); pp.NextB(); } while(pp != startPos); } } } // take a mesh and rescale its uv so that they are in the 0..1 range static void RegularizeTexArea(VoroMesh &m) { float areaTex=0; float areaGeo=0; vcg::Box2f UVBox = tri::UV_Utils::PerWedgeUVBox(m); for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) { areaTex+= fabs((fi->WT(1).P() - fi->WT(0).P()) ^ (fi->WT(2).P() - fi->WT(0).P())) ; areaGeo+= DoubleArea(*fi); } float ratio = sqrt(areaGeo/areaTex); for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) { for(int j=0;j<3;++j) fi->WT(j).P() = (fi->WT(j).P()-UVBox.min) *ratio; } } public: struct VoronoiAtlasParam { VoronoiAtlasParam() { maxIterNum = 5; sampleNum=10; overlap=false; } struct Stat { void clear() { iterNum=totalTime=unwrapTime=voronoiTime=samplingTime=0;} int totalTime; int unwrapTime; int voronoiTime; int samplingTime; int regionNum; int iterNum; }; int sampleNum; bool overlap; Stat vas; int maxIterNum; CallBackPos *cb=vcg::CErrCallBackPos; }; // Main parametrization function: // it takes a startMesh, copy it and static void Build( MeshType &startMesh, MeshType ¶Mesh, VoronoiAtlasParam &pp) { pp.vas.clear(); int t0=clock(); VoroMesh m; // the mesh used for the processing is a copy of the passed one. tri::Append::Mesh(m, startMesh); tri::Clean::RemoveUnreferencedVertex(m); tri::Allocator::CompactVertexVector(m); tri::Allocator::CompactFaceVector(m); tri::UpdateBounding::Box(m); std::vector meshRegionVec; std::vector< std::vector > uvBorders; // Main processing loop do { // qDebug("************ ITERATION %i sampling mesh of %i with %i ************",pp.vas.iterNum,m.fn,pp.sampleNum); int st0=clock(); std::vector PoissonSamples; float diskRadius=0; tri::PoissonSampling(m,PoissonSamples,pp.sampleNum,diskRadius); int st1=clock(); pp.vas.samplingTime+= st1-st0; pp.cb(50,StrFormat("Sampling created a new mesh of %lu points\n",PoissonSamples.size())); EuclideanDistance edFunc; std::vector seedVec; tri::VoronoiProcessing::SeedToVertexConversion(m,PoissonSamples,seedVec); tri::UpdateTopology::VertexFace(m); tri::VoronoiProcessing::ComputePerVertexSources(m,seedVec,edFunc); tri::VoronoiProcessing::FaceAssociateRegion(m); tri::VoronoiProcessing::VoronoiColoring(m,true); std::vector badRegionVec; int st2=clock(); pp.vas.voronoiTime+=st2-st1; for(size_t i=0; i::FaceSelectAssociateRegion(m,seedVec[i]); pp.cb(50,StrFormat("Region %i of %i faces",i,selCnt)); if(selCnt==0) continue; assert(selCnt>0); if(pp.overlap){ tri::UpdateSelection::VertexFromFaceLoose(m); tri::UpdateSelection::FaceFromVertexLoose(m); } tri::Append::Mesh(*rm, m, true); int tp0=clock(); tri::PoissonSolver PS(*rm); tri::UpdateBounding::Box(*rm); if(PS.IsFeasible()) { PS.Init(); PS.FixDefaultVertices(); PS.SolvePoisson(false); tri::UpdateTexture::WedgeTexFromVertexTex(*rm); RegularizeTexArea(*rm); std::vector uvBorder; CollectUVBorder(rm,uvBorder); meshRegionVec.push_back(rm); uvBorders.push_back(uvBorder); int foldedCnt = tri::Distortion::FoldedNum(*rm); if( foldedCnt > rm->fn/10) { badRegionVec.push_back(rm); // qDebug("-- region %i Parametrized but with %i fold on %i!",i,foldedCnt,rm->fn); } // else qDebug("-- region %i Parametrized!",i); } else { // qDebug("-- region %i is NOT homeomorphic to a disk\n",i); badRegionVec.push_back(rm); } int tp1=clock(); pp.vas.unwrapTime +=tp1-tp0; ++pp.vas.iterNum; } // qDebug("\n -- Completed (%i bad regions) -- \n", badRegionVec.size()); VoroMesh *rm = new VoroMesh(); tri::VoronoiProcessing::FaceSelectAssociateRegion(m,0); tri::Append::Mesh(*rm, m, true); if(rm->fn>0) { // qDebug("ACH - unreached faces %i fn\n",rm->fn); badRegionVec.push_back(rm); } m.Clear(); pp.sampleNum = 10; if(!badRegionVec.empty()) { for(size_t i=0;ifn>50) tri::Append::Mesh(m, *badRegionVec[i], false); tri::Clean::RemoveDuplicateFace(m); tri::Clean::RemoveUnreferencedVertex(m); tri::Allocator::CompactVertexVector(m); tri::Allocator::CompactFaceVector(m); } } while (m.fn>0); std::vector trVec; Point2f finalSize; //PolyPacker::WritePolyVec(uvBorders,"borders.poly"); PolyPacker::PackAsObjectOrientedRect(uvBorders,Point2i(1024,1024),trVec,finalSize); // RasterizedOutline2Packer::Parameters prp; // RasterizedOutline2Packer::Pack(uvBorders,Point2i(1024,1024),trVec,prp); // loop again over all the patches pp.vas.regionNum=meshRegionVec.size(); for(size_t i=0; iface.begin();fi!=rm->face.end();++fi) { for(int j=0;j<3;++j) { Point2f pp(fi->WT(j).U(),fi->WT(j).V()); Point2f newpp=trVec[i]*pp; fi->WT(j).U()=newpp[0]/1024.0f; fi->WT(j).V()=newpp[1]/1024.0f; } } tri::Append::Mesh(paraMesh, *rm, false); } int t2=clock(); pp.vas.totalTime=t2-t0; } }; //end } // end namespace vcg } // end namespace tri #endif // VORONOI_ATLAS_H