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 &paraMesh, 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