1 /**************************************************************************** 2 * VCGLib o o * 3 * Visual and Computer Graphics Library o o * 4 * _ O _ * 5 * Copyright(C) 2004-2016 \/)\/ * 6 * Visual Computing Lab /\/| * 7 * ISTI - Italian National Research Council | * 8 * \ * 9 * All rights reserved. * 10 * * 11 * This program is free software; you can redistribute it and/or modify * 12 * it under the terms of the GNU General Public License as published by * 13 * the Free Software Foundation; either version 2 of the License, or * 14 * (at your option) any later version. * 15 * * 16 * This program is distributed in the hope that it will be useful, * 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 19 * GNU General Public License (http://www.gnu.org/licenses/gpl.txt) * 20 * for more details. * 21 * * 22 ****************************************************************************/ 23 #ifndef VORONOI_ATLAS_H 24 #define VORONOI_ATLAS_H 25 26 #include<vcg/complex/algorithms/parametrization/poisson_solver.h> 27 #include<vcg/complex/algorithms/parametrization/uv_utils.h> 28 #include<vcg/complex/algorithms/parametrization/distortion.h> 29 #include<vcg/space/outline2_packer.h> 30 #include<vcg/space/rasterized_outline2_packer.h> 31 #include<vcg/complex/algorithms/update/texture.h> 32 #include<vcg/complex/algorithms/point_sampling.h> 33 #include<vcg/complex/algorithms/voronoi_processing.h> 34 35 //#include<wrap/qt/outline2_rasterizer.h> 36 37 namespace vcg { 38 namespace tri { 39 40 template <class MeshType> 41 class VoronoiAtlas 42 { 43 //private: 44 public: 45 class VoroEdge; 46 class VoroFace; 47 class VoroVertex; 48 struct VoroUsedTypes : public UsedTypes< Use<VoroVertex> ::template AsVertexType, 49 Use<VoroEdge> ::template AsEdgeType, 50 Use<VoroFace> ::template AsFaceType>{}; 51 52 class VoroVertex : public Vertex< VoroUsedTypes, vertex::Coord3f, vertex::Normal3f, vertex::TexCoord2f, vertex::VFAdj , vertex::Qualityf, vertex::Color4b, vertex::BitFlags >{}; 53 class VoroFace : public Face< VoroUsedTypes, face::VertexRef, face::BitFlags, face::FFAdj ,face::VFAdj , face::CurvatureDirf,face::WedgeTexCoord2f> {}; 54 class VoroEdge : public Edge< VoroUsedTypes>{}; 55 class VoroMesh : public tri::TriMesh< std::vector<VoroVertex>, std::vector<VoroFace> , std::vector<VoroEdge> > {}; 56 57 typedef typename VoroMesh::FaceIterator FaceIterator; 58 typedef typename VoroMesh::VertexType VertexType; 59 typedef typename VoroMesh::FaceType FaceType; 60 CollectUVBorder(VoroMesh * rm,std::vector<Point2f> & uvBorder)61 static void CollectUVBorder(VoroMesh *rm, std::vector<Point2f> &uvBorder) 62 { 63 tri::UpdateTopology<VoroMesh>::FaceFace(*rm); 64 tri::UpdateFlags<VoroMesh>::FaceClearV(*rm); 65 for(FaceIterator fi=rm->face.begin();fi!=rm->face.end();++fi) 66 { 67 for(int j=0;j<3;++j) 68 if(face::IsBorder(*fi,j) && !(fi->IsV())) 69 { 70 face::Pos<FaceType> pp(&*fi,j,fi->V(j)); 71 assert(pp.IsBorder()); 72 face::Pos<FaceType> startPos = pp; 73 do 74 { 75 uvBorder.push_back( pp.F()->WT(pp.VInd()).P() ); 76 pp.F()->SetV(); 77 pp.NextB(); 78 } while(pp != startPos); 79 } 80 } 81 } 82 83 // take a mesh and rescale its uv so that they are in the 0..1 range RegularizeTexArea(VoroMesh & m)84 static void RegularizeTexArea(VoroMesh &m) 85 { 86 float areaTex=0; 87 float areaGeo=0; 88 89 vcg::Box2f UVBox = tri::UV_Utils<VoroMesh>::PerWedgeUVBox(m); 90 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) 91 { 92 areaTex+= fabs((fi->WT(1).P() - fi->WT(0).P()) ^ (fi->WT(2).P() - fi->WT(0).P())) ; 93 areaGeo+= DoubleArea(*fi); 94 } 95 96 float ratio = sqrt(areaGeo/areaTex); 97 98 for(FaceIterator fi=m.face.begin();fi!=m.face.end();++fi) 99 { 100 for(int j=0;j<3;++j) 101 fi->WT(j).P() = (fi->WT(j).P()-UVBox.min) *ratio; 102 } 103 } 104 105 106 public: 107 struct VoronoiAtlasParam 108 { VoronoiAtlasParamVoronoiAtlasParam109 VoronoiAtlasParam() 110 { 111 maxIterNum = 5; 112 sampleNum=10; 113 overlap=false; 114 } 115 116 struct Stat 117 { clearVoronoiAtlasParam::Stat118 void clear() { iterNum=totalTime=unwrapTime=voronoiTime=samplingTime=0;} 119 int totalTime; 120 int unwrapTime; 121 int voronoiTime; 122 int samplingTime; 123 124 int regionNum; 125 int iterNum; 126 }; 127 128 int sampleNum; 129 bool overlap; 130 Stat vas; 131 int maxIterNum; 132 CallBackPos *cb=vcg::CErrCallBackPos; 133 }; 134 135 // Main parametrization function: 136 // it takes a startMesh, copy it and 137 Build(MeshType & startMesh,MeshType & paraMesh,VoronoiAtlasParam & pp)138 static void Build( MeshType &startMesh, MeshType ¶Mesh, VoronoiAtlasParam &pp) 139 { 140 pp.vas.clear(); 141 int t0=clock(); 142 VoroMesh m; // the mesh used for the processing is a copy of the passed one. 143 tri::Append<VoroMesh, MeshType>::Mesh(m, startMesh); 144 tri::Clean<VoroMesh>::RemoveUnreferencedVertex(m); 145 tri::Allocator<VoroMesh>::CompactVertexVector(m); 146 tri::Allocator<VoroMesh>::CompactFaceVector(m); 147 148 tri::UpdateBounding<VoroMesh>::Box(m); 149 std::vector<VoroMesh *> meshRegionVec; 150 std::vector< std::vector<Point2f> > uvBorders; 151 152 // Main processing loop 153 do 154 { 155 // qDebug("************ ITERATION %i sampling mesh of %i with %i ************",pp.vas.iterNum,m.fn,pp.sampleNum); 156 int st0=clock(); 157 std::vector<Point3f> PoissonSamples; 158 float diskRadius=0; 159 tri::PoissonSampling(m,PoissonSamples,pp.sampleNum,diskRadius); 160 int st1=clock(); 161 pp.vas.samplingTime+= st1-st0; 162 pp.cb(50,StrFormat("Sampling created a new mesh of %lu points\n",PoissonSamples.size())); 163 EuclideanDistance<VoroMesh> edFunc; 164 std::vector<VertexType *> seedVec; 165 tri::VoronoiProcessing<VoroMesh>::SeedToVertexConversion(m,PoissonSamples,seedVec); 166 tri::UpdateTopology<VoroMesh>::VertexFace(m); 167 tri::VoronoiProcessing<VoroMesh>::ComputePerVertexSources(m,seedVec,edFunc); 168 tri::VoronoiProcessing<VoroMesh>::FaceAssociateRegion(m); 169 tri::VoronoiProcessing<VoroMesh>::VoronoiColoring(m,true); 170 std::vector<VoroMesh *> badRegionVec; 171 int st2=clock(); 172 pp.vas.voronoiTime+=st2-st1; 173 for(size_t i=0; i<seedVec.size();++i) 174 { 175 VoroMesh *rm = new VoroMesh(); 176 int selCnt = tri::VoronoiProcessing<VoroMesh>::FaceSelectAssociateRegion(m,seedVec[i]); 177 pp.cb(50,StrFormat("Region %i of %i faces",i,selCnt)); 178 if(selCnt==0) continue; 179 assert(selCnt>0); 180 if(pp.overlap){ 181 tri::UpdateSelection<VoroMesh>::VertexFromFaceLoose(m); 182 tri::UpdateSelection<VoroMesh>::FaceFromVertexLoose(m); 183 } 184 tri::Append<VoroMesh,VoroMesh>::Mesh(*rm, m, true); 185 int tp0=clock(); 186 tri::PoissonSolver<VoroMesh> PS(*rm); 187 tri::UpdateBounding<VoroMesh>::Box(*rm); 188 if(PS.IsFeasible()) 189 { 190 PS.Init(); 191 PS.FixDefaultVertices(); 192 PS.SolvePoisson(false); 193 tri::UpdateTexture<VoroMesh>::WedgeTexFromVertexTex(*rm); 194 RegularizeTexArea(*rm); 195 196 std::vector<Point2f> uvBorder; 197 CollectUVBorder(rm,uvBorder); 198 meshRegionVec.push_back(rm); 199 uvBorders.push_back(uvBorder); 200 int foldedCnt = tri::Distortion<VoroMesh,false>::FoldedNum(*rm); 201 if( foldedCnt > rm->fn/10) 202 { 203 badRegionVec.push_back(rm); 204 // qDebug("-- region %i Parametrized but with %i fold on %i!",i,foldedCnt,rm->fn); 205 } 206 // else qDebug("-- region %i Parametrized!",i); 207 208 } else 209 { 210 // qDebug("-- region %i is NOT homeomorphic to a disk\n",i); 211 badRegionVec.push_back(rm); 212 } 213 int tp1=clock(); 214 pp.vas.unwrapTime +=tp1-tp0; 215 ++pp.vas.iterNum; 216 } 217 // qDebug("\n -- Completed (%i bad regions) -- \n", badRegionVec.size()); 218 VoroMesh *rm = new VoroMesh(); 219 tri::VoronoiProcessing<VoroMesh>::FaceSelectAssociateRegion(m,0); 220 tri::Append<VoroMesh,VoroMesh>::Mesh(*rm, m, true); 221 222 if(rm->fn>0) 223 { 224 // qDebug("ACH - unreached faces %i fn\n",rm->fn); 225 badRegionVec.push_back(rm); 226 } 227 m.Clear(); 228 pp.sampleNum = 10; 229 if(!badRegionVec.empty()) 230 { 231 for(size_t i=0;i<badRegionVec.size();++i) 232 if(badRegionVec[i]->fn>50) 233 tri::Append<VoroMesh,VoroMesh>::Mesh(m, *badRegionVec[i], false); 234 235 tri::Clean<VoroMesh>::RemoveDuplicateFace(m); 236 tri::Clean<VoroMesh>::RemoveUnreferencedVertex(m); 237 tri::Allocator<VoroMesh>::CompactVertexVector(m); 238 tri::Allocator<VoroMesh>::CompactFaceVector(m); 239 } 240 } while (m.fn>0); 241 242 std::vector<Similarity2f> trVec; 243 Point2f finalSize; 244 //PolyPacker<float>::WritePolyVec(uvBorders,"borders.poly"); 245 PolyPacker<float>::PackAsObjectOrientedRect(uvBorders,Point2i(1024,1024),trVec,finalSize); 246 // RasterizedOutline2Packer<float,QtOutline2Rasterizer>::Parameters prp; 247 // RasterizedOutline2Packer<float,QtOutline2Rasterizer>::Pack(uvBorders,Point2i(1024,1024),trVec,prp); 248 // loop again over all the patches 249 pp.vas.regionNum=meshRegionVec.size(); 250 for(size_t i=0; i<meshRegionVec.size();++i) 251 { 252 VoroMesh *rm = meshRegionVec[i]; 253 for(FaceIterator fi=rm->face.begin();fi!=rm->face.end();++fi) 254 { 255 for(int j=0;j<3;++j) 256 { 257 Point2f pp(fi->WT(j).U(),fi->WT(j).V()); 258 Point2f newpp=trVec[i]*pp; 259 fi->WT(j).U()=newpp[0]/1024.0f; 260 fi->WT(j).V()=newpp[1]/1024.0f; 261 } 262 } 263 tri::Append<MeshType,VoroMesh>::Mesh(paraMesh, *rm, false); 264 } 265 int t2=clock(); 266 pp.vas.totalTime=t2-t0; 267 } 268 }; //end 269 270 271 } // end namespace vcg 272 } // end namespace tri 273 274 275 #endif // VORONOI_ATLAS_H 276