VCG Library
polygonmesh_quadsimpl.cpp
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 
24 #include <sstream>
25 
26 #include <vcg/complex/complex.h>
27 
28 #include <vcg/complex/algorithms/clean.h>
29 
30 #include <wrap/io_trimesh/import.h>
31 #include <wrap/io_trimesh/export_off.h>
32 #include <vcg/complex/algorithms/polygon_support.h>
33 #include <vcg/complex/algorithms/local_optimization/quad_diag_collapse.h>
34 #include <vcg/complex/algorithms/update/fitmaps.h>
35 
36 using namespace vcg;
37 using namespace std;
38 
39 // forward declarations
40 class CFace;
41 class CVertex;
42 class CHEdge;
43 class CEdge;
44 class MyPolyVertex;
45 
46 struct CUsedTypes: public vcg::UsedTypes< vcg::Use<CVertex>::AsVertexType, vcg::Use<CFace>::AsFaceType >{};
47 
48 // Mesh of triangles
49 class CVertex : public Vertex<
50  CUsedTypes,
51  vertex::BitFlags,
52  vertex::Coord3f,
53  vertex::Normal3f,
54  vertex::VFAdj,
55  vertex::Mark,
56  vcg::vertex::Curvaturef,
57  vcg::vertex::CurvatureDirf,
58  vertex::Color4b,
59  vertex::Qualityf
60  >{};
61 
62 class CFace : public Face<
63  CUsedTypes,
64  face::VertexRef,
65  face::Normal3f,
66  face::BitFlags,
67  face::FFAdj,
68  face::VFAdj,
69  face::Mark,
70  face::EdgePlane
71  > {};
72 
73 class CMesh : public vcg::tri::TriMesh< vector<CVertex>, vector<CFace> > {};
74 
75 
76 
77 
78 // Poly mesh
79 class MyPolyFace;
80 class MyPolyVertex;
81 
82 struct PolyUsedTypes: public vcg::UsedTypes<
83  vcg::Use<MyPolyVertex> ::AsVertexType,
84  vcg::Use<CEdge> ::AsEdgeType,
85  vcg::Use<CHEdge> ::AsHEdgeType,
86  vcg::Use<MyPolyFace> ::AsFaceType
87  >{};
88 
89 class MyPolyVertex:public Vertex<
90  PolyUsedTypes,
91  vertex::Coord3f,
92  vertex::Normal3f,
93  vertex::Mark,
94  vertex::BitFlags,
95  vertex::VHAdj,
96  vertex::VFAdj
97  >{};
98 
99 class CEdge : public Edge<PolyUsedTypes>{};
100 
101 class CHEdge : public HEdge<
102  PolyUsedTypes,
103  hedge::BitFlags,
104  hedge::HFAdj,
105  hedge::HOppAdj,
106  hedge::HNextAdj,
107  hedge::HVAdj,
108  hedge::HPrevAdj,
109  hedge::Mark
110  >{};
111 
112 class MyPolyFace:public Face<
113  PolyUsedTypes,
114  face::PolyInfo,
115  face::PFVAdj,
116  face::PFFAdj,
117  face::PFHAdj,
118  face::BitFlags,
119  face::Normal3f,
120  face::Mark
121  > {};
122 
123 class MyPolyMesh: public tri::TriMesh<
124  std::vector<MyPolyVertex>,
125  std::vector<MyPolyFace>,
126  std::vector<CHEdge>,
127  std::vector<CEdge>
128  >{};
129 
130 
131 
136 class MyCollapseAdaptive: public vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg<MyPolyMesh> ,vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> , vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> >
137 {
138 public:
139 
140  typedef vcg::tri::QuadDiagonalCollapse< MyPolyMesh, MyCollapseAdaptive, CMesh , vcg::tri::VertReg<MyPolyMesh>, vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> , vcg::tri::FitmapsCollapse<MyPolyMesh, CMesh> > constructor;
141 
142  MyCollapseAdaptive(HEdgePointer he, int mark):constructor(he,mark){}
143 };
144 
149 class MyCollapse: public vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg<MyPolyMesh> >
150 {
151 public:
152 
153  typedef vcg::tri::QuadDiagonalCollapseBase< MyPolyMesh, MyCollapse, CMesh , vcg::tri::VertReg<MyPolyMesh> > constructor;
154 
155  MyCollapse(HEdgePointer he, int mark):constructor(he,mark){}
156 };
157 
158 
159 typedef CMesh::FaceType TriFaceType;
160 typedef vcg::GridStaticPtr<CMesh::FaceType, TriFaceType::ScalarType> GRID;
161 
162 typedef CMesh::PerVertexAttributeHandle<float> Fitmap_attr;
163 
169 void initGrid(CMesh & m)
170 {
171 
172  GRID* grid = new GRID();
173 
175  vcg::tri::UpdateEdges<CMesh>::Set(m);
176 
177  grid->Set(m.face.begin(), m.face.end());
178 
179 // grid->ShowStats(stdout);
180  MyCollapse::grid() = grid;
181  MyCollapseAdaptive::grid() = grid;
182 
183 }
184 
192 void init_heap(MyPolyMesh &m, vcg::LocalOptimization<MyPolyMesh> &loc, bool adaptive)
193 {
194  if(adaptive)
195  MyCollapseAdaptive::Init(m, loc.h);
196  else
197  MyCollapse::Init(m,loc.h);
198 
199  std::make_heap(loc.h.begin(),loc.h.end());
200 
201  if(!loc.h.empty())
202  loc.currMetric=loc.h.front().pri;
203 }
204 
211 bool read_fitmaps(CMesh &m, const char *fn)
212 {
213  ifstream fitmaps;
214  fitmaps.open(fn);
215 
216  if(! fitmaps.is_open())
217  return false;
218 
219  Fitmap_attr S_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"S-Fitmap");
220  Fitmap_attr M_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"M-Fitmap");
221 
222  int index;
223  float S_fit, M_fit;
224  do
225  {
226  fitmaps >> index >> S_fit >> M_fit;
227  S_Fit[m.vert[index]] = S_fit;
228  M_Fit[m.vert[index]] = M_fit;
229 
230  }while(fitmaps.good());
231 
232 
233  bool eof = fitmaps.eof();
234 
235  fitmaps.close();
236  return eof;
237 
238 }
239 
246 bool store_fitmaps(CMesh &m, const char *fn)
247 {
248  ofstream fitmaps;
249  fitmaps.open(fn);
250 
251  if(! fitmaps.is_open())
252  return false;
253 
254  Fitmap_attr S_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"S-Fitmap");
255  Fitmap_attr M_Fit = tri::Allocator<CMesh>::GetPerVertexAttribute<float>(m,"M-Fitmap");
256 
257  for(unsigned int i =0; i< m.vert.size(); i++)
258  {
259  if( !(m.vert[i].IsD()) )
260  {
261  fitmaps << i << " " << S_Fit[m.vert[i]] << " " << M_Fit[m.vert[i]] << endl;
262 
263  if(!fitmaps.good())
264  {
265  fitmaps.close();
266  return false;
267  }
268  }
269  }
270 
271  fitmaps.close();
272  return true;
273 }
274 
281 void load_fitmaps(CMesh &m, char* fn)
282 {
283 
284  Fitmap_attr S_Fit = tri::Allocator<CMesh>::AddPerVertexAttribute<float> (m, string("S-Fitmap"));
285  Fitmap_attr M_Fit = tri::Allocator<CMesh>::AddPerVertexAttribute<float> (m, string("M-Fitmap"));
286 
287  string filename(fn);
288 
289  int found = filename.find_last_of("/");
290 
291  string name = filename.substr(found+1);
292 
293  string suffix = ".fmp";
294 
295  if( !read_fitmaps( m, (name + suffix).c_str()) )
296  {
297  tri::Fitmaps<CMesh>::computeSFitmap(m);
298 
299  for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
300  S_Fit[vi] = vi->Q();
301 
302  tri::Fitmaps<CMesh>::computeMFitmap(m, 5);
303 
304  for(CMesh::VertexIterator vi = m.vert.begin(); vi != m.vert.end(); ++vi)
305  M_Fit[vi] = vi->Q();
306 
307  store_fitmaps(m, ( name + suffix).c_str());
308  }
309 
310 }
311 
319 void loadMesh(CMesh & m, char* fn, bool loadFitmaps = false)
320 {
321 
322  int ret = vcg::tri::io::Importer<CMesh>::Open(m,fn);
323 
324  if(ret != 0)
325  {
326  cerr << "Error reading file " << fn << endl;
327  exit(1);
328  }
329 
334 
336 
339 
342 
343  // update bounding box
345 
346  // update Normals
347  vcg::tri::UpdateNormals<CMesh>::PerVertexNormalizedPerFace(m);
348  vcg::tri::UpdateNormals<CMesh>::PerFaceNormalized(m);
349 
350  if(loadFitmaps)
351  load_fitmaps(m,fn);
352 
353 }
354 
355 int main(int argc, char *argv[]) {
356 
357 
358  // HE mesh
359  MyPolyMesh pm;
360 
361  // Tri meshes
362  CMesh mesh,refMesh;
363 
364  char* meshfile = NULL;
365  char* trimeshfile = NULL;
366  char* outfile = "output.off";
367  int faces;
368  bool adaptive = false;
369 
370  if(argc < 2)
371  {
372  cerr << "Usage: " << argv[0] << " -meshfile filename [-trimeshfile filename] -faces num_faces [-adaptive] [-outfile filename]" << endl;
373  }
374 
375  for(int i=1; i< argc; i++)
376  {
377  string arg = string(argv[i]);
378 
379  if ( arg == "-meshfile")
380  meshfile = argv[++i];
381 
382  else if (arg == "-trimeshfile")
383  trimeshfile = argv[++i];
384 
385  else if (arg == "-faces")
386  {
387  stringstream myStream(argv[++i], stringstream::in | stringstream::out);
388  myStream >> faces;
389  }
390 
391  else if (arg == "-outfile")
392  outfile = argv[++i];
393 
394  else if (arg == "-adaptive")
395  adaptive = true;
396  }
397 
398 
399  if( !meshfile)
400  {
401  cerr << "Missing mesh filename" << endl;
402  exit(1);
403  }
404 
405  if(faces < 0)
406  {
407  cerr << "Missing faces number" << endl;
408  exit(1);
409  }
410 
411 
412  // Load the mesh to simplify
413  loadMesh(mesh, meshfile);
414 
415  // Load the reference mesh
416  if(trimeshfile)
417  loadMesh(refMesh, trimeshfile, adaptive);
418  else
419  loadMesh(refMesh, meshfile, adaptive);
420 
421  initGrid(refMesh);
422 
423  MyCollapse::refMesh() = &refMesh;
424  MyCollapseAdaptive::refMesh() = &refMesh;
425 
426 
427  vcg::tri::PolygonSupport<CMesh,MyPolyMesh>::ImportFromTriMesh(pm,mesh);
429 
430  // After loading check mesh consistency
432 
433  HalfedgeQuadClean<MyPolyMesh>::remove_singlets(pm);
434  HalfedgeQuadClean<MyPolyMesh>::remove_doublets(pm);
435 
436  vcg::LocalOptimization<MyPolyMesh> loc(pm);
437  init_heap(pm, loc, adaptive);
438 
439  loc.HeapSimplexRatio = 9;
440  loc.SetTargetSimplices(faces);
441 
442  // Perform simplification
443  loc.DoOptimization();
444 
445 
447  vcg::tri::UpdateIndexed<MyPolyMesh>::FromHalfEdges(pm );
448 
449 
450  int ret = tri::io::ExporterOFF<MyPolyMesh>::Save(pm, outfile, tri::io::Mask::IOM_BITPOLYGONAL );
451  if(ret != 0 )
452  {
453  cerr << "Error saving file" << endl;
454  exit(1);
455  }
456 
457  cout << "Simplification ended successfully!" << endl;
458 
459 }