Developer Documentation
mconvert.cc
1 /* ========================================================================= *
2  * *
3  * OpenMesh *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openmesh.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenMesh. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40  * ========================================================================= */
41 
42 
43 
44 #include <iostream>
45 #include <iterator>
46 #include <fstream>
47 #include <string>
48 //
49 #include <OpenMesh/Core/IO/MeshIO.hh>
50 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
53 #include <OpenMesh/Tools/Utils/getopt.h>
54 
55 
56 struct MyTraits : public OpenMesh::DefaultTraits
57 {
58  VertexAttributes ( OpenMesh::Attributes::Normal |
61  HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
62  FaceAttributes ( OpenMesh::Attributes::Normal |
64 };
65 
66 
68 
69 void usage_and_exit(int xcode)
70 {
71  using std::cout;
72  using std::endl;
73 
74  cout << "\nUsage: mconvert [option] <input> [<output>]\n\n";
75  cout << " Convert from one 3D geometry format to another.\n"
76  << " Or simply display some information about the object\n"
77  << " stored in <input>.\n"
78  << endl;
79  cout << "Options:\n"
80  << endl;
81  cout << " -b\tUse binary mode if supported by target format.\n" << endl;
82  cout << " -l\tStore least significant bit first (LSB, little endian).\n" << endl;
83  cout << " -m\tStore most significant bit first (MSB, big endian).\n" << endl;
84  cout << " -s\tSwap byte order.\n" << endl;
85  cout << " -B\tUse binary mode if supported by source format.\n" << endl;
86  cout << " -S\tSwap byte order of input data.\n" << endl;
87  cout << " -c\tCopy vertex color if provided by input.\n" << endl;
88  cout << " -d\tCopy face color if provided by input.\n" << endl;
89  cout << " -C\tTranslate object in its center-of-gravity.\n" << endl;
90  cout << " -n\tCopy vertex normals if provided by input. Else compute normals.\n" << endl;
91  cout << " -N\tReverse normal directions.\n" << endl;
92  cout << " -t\tCopy vertex texture coordinates if provided by input file.\n" << endl;
93  cout << " -T \"x y z\"\tTranslate object by vector (x, y, z)'\"\n"
94  << std::endl;
95  cout << endl;
96 
97  exit(xcode);
98 }
99 
100 // ----------------------------------------------------------------------------
101 
102 template <typename T> struct Option : std::pair< T, bool >
103 {
104  typedef std::pair< T, bool > Base;
105 
106  Option()
107  { Base::second = false; }
108 
109  bool is_valid() const { return Base::second; }
110  bool is_empty() const { return !Base::second; }
111 
112  operator T& () { return Base::first; }
113  operator const T& () const { return Base::first; }
114 
115  Option& operator = ( const T& _rhs )
116  { Base::first = _rhs; Base::second=true; return *this; }
117 
118  bool operator == ( const T& _rhs ) const
119  { return Base::first == _rhs; }
120 
121  bool operator != ( const T& _rhs ) const
122  { return Base::first != _rhs; }
123 };
124 
125 template <typename T>
126 std::ostream& operator << (std::ostream& _os, const Option<T>& _opt )
127 {
128  if (_opt.second) _os << _opt.first; else _os << "<null>";
129  return _os;
130 }
131 
132 template <typename T>
133 std::istream& operator >> (std::istream& _is, Option<T>& _opt )
134 {
135  _is >> _opt.first; _opt.second = true;
136  return _is;
137 }
138 
139 // ----------------------------------------------------------------------------
140 
141 int main(int argc, char *argv[] )
142 {
143  // ------------------------------------------------------------ command line
144 
145  int c;
146  std::string ifname, ofname;
147  bool rev_normals = false;
148  bool obj_center = false;
149  OpenMesh::IO::Options opt, ropt;
150 
152 
153  while ( (c=getopt(argc, argv, "bBcdCi:hlmnNo:sStT:"))!=-1 )
154  {
155  switch(c)
156  {
157  case 'b': opt += OpenMesh::IO::Options::Binary; break;
158  case 'B': ropt += OpenMesh::IO::Options::Binary; break;
159  case 'l': opt += OpenMesh::IO::Options::LSB; break;
160  case 'm': opt += OpenMesh::IO::Options::MSB; break;
161  case 's': opt += OpenMesh::IO::Options::Swap; break;
162  case 'S': ropt += OpenMesh::IO::Options::Swap; break;
163  case 'n': opt += OpenMesh::IO::Options::VertexNormal; break;
164  case 'N': rev_normals = true; break;
165  case 'C': obj_center = true; break;
166  case 'c': opt += OpenMesh::IO::Options::VertexColor; break;
167  case 'd': opt += OpenMesh::IO::Options::FaceColor; break;
168  case 't': opt += OpenMesh::IO::Options::VertexTexCoord; break;
169  case 'T':
170  {
171  std::cout << optarg << std::endl;
172  std::stringstream str; str << optarg;
173  str >> tvec;
174  std::cout << tvec << std::endl;
175  break;
176  }
177  case 'i': ifname = optarg; break;
178  case 'o': ofname = optarg; break;
179  case 'h':
180  usage_and_exit(0);
181  break;
182  case '?':
183  default:
184  usage_and_exit(1);
185  }
186  }
187 
188  if (ifname.empty())
189  {
190  if (optind < argc)
191  ifname = argv[optind++];
192  else
193  usage_and_exit(1);
194  }
195 
196  MyMesh mesh;
198 
199  // ------------------------------------------------------------ read
200 
201  std::cout << "reading.." << std::endl;
202  {
203  bool rc;
204  timer.start();
205  rc = OpenMesh::IO::read_mesh( mesh, ifname, ropt );
206  timer.stop();
207  if (rc)
208  std::cout << " read in " << timer.as_string() << std::endl;
209  else
210  {
211  std::cout << " read failed\n" << std::endl;
212  return 1;
213  }
214  timer.reset();
215  }
216 
217 
218  // ---------------------------------------- some information about input
219  std::cout << (ropt.check(OpenMesh::IO::Options::Binary)
220  ? " source is binary\n"
221  : " source is ascii\n");
222 
223  std::cout << " #V " << mesh.n_vertices() << std::endl;
224  std::cout << " #E " << mesh.n_edges() << std::endl;
225  std::cout << " #F " << mesh.n_faces() << std::endl;
226 
227  if (ropt.vertex_has_texcoord())
228  std::cout << " has texture coordinates" << std::endl;
229 
230  if (ropt.vertex_has_normal())
231  std::cout << " has vertex normals" << std::endl;
232 
233  if (ropt.vertex_has_color())
234  std::cout << " has vertex colors" << std::endl;
235 
236  if (ropt.face_has_normal())
237  std::cout << " has face normals" << std::endl;
238 
239  if (ropt.face_has_color())
240  std::cout << " has face colors" << std::endl;
241 
242  //
243  if (ofname.empty())
244  {
245  if ( optind < argc )
246  ofname = argv[optind++];
247  else
248  return 0;
249  }
250 
251  // ------------------------------------------------------------ features
252 
253  // ---------------------------------------- compute normal feature
254  if ( opt.vertex_has_normal() && !ropt.vertex_has_normal())
255  {
256  std::cout << "compute normals" << std::endl;
257 
258  timer.start();
259  mesh.update_face_normals();
260  timer.stop();
261  std::cout << " " << mesh.n_faces()
262  << " face normals in " << timer.as_string() << std::endl;
263  timer.reset();
264 
265  timer.start();
266  mesh.update_vertex_normals();
267  timer.stop();
268  std::cout << " " << mesh.n_vertices()
269  << " vertex normals in " << timer.as_string() << std::endl;
270  timer.reset();
271  }
272 
273 
274  // ---------------------------------------- reverse normal feature
275  if ( rev_normals && ropt.vertex_has_normal() )
276  {
277  std::cout << "reverse normal directions" << std::endl;
278  timer.start();
279  MyMesh::VertexIter vit = mesh.vertices_begin();
280  for (; vit != mesh.vertices_end(); ++vit)
281  mesh.set_normal( *vit, -mesh.normal( *vit ) );
282  timer.stop();
283  std::cout << " " << mesh.n_vertices()
284  << " vertex normals in " << timer.as_string() << std::endl;
285  timer.reset();
286 
287  }
288 
289 
290  // ---------------------------------------- centering feature
291  if ( obj_center )
292  {
293  OpenMesh::Vec3f cog(0,0,0);
294  size_t nv;
295  std::cout << "center object" << std::endl;
296  timer.start();
297  MyMesh::VertexIter vit = mesh.vertices_begin();
298  for (; vit != mesh.vertices_end(); ++vit)
299  cog += mesh.point( *vit );
300  timer.stop();
301  nv = mesh.n_vertices();
302  cog *= 1.0f/mesh.n_vertices();
303  std::cout << " cog = [" << cog << "]'" << std::endl;
304  if (cog.sqrnorm() > 0.8) // actually one should consider the size of object
305  {
306  vit = mesh.vertices_begin();
307  timer.cont();
308  for (; vit != mesh.vertices_end(); ++vit)
309  mesh.set_point( *vit , mesh.point( *vit )-cog );
310  timer.stop();
311  nv += mesh.n_vertices();
312  }
313  else
314  std::cout << " already centered!" << std::endl;
315  std::cout << " visited " << nv
316  << " vertices in " << timer.as_string() << std::endl;
317  timer.reset();
318  }
319 
320 
321  // ---------------------------------------- translate feature
322  if ( tvec.is_valid() )
323  {
324  std::cout << "Translate object by " << tvec << std::endl;
325 
326  timer.start();
327  MyMesh::VertexIter vit = mesh.vertices_begin();
328  for (; vit != mesh.vertices_end(); ++vit)
329  mesh.set_point( *vit , mesh.point( *vit ) + tvec.first );
330  timer.stop();
331  std::cout << " moved " << mesh.n_vertices()
332  << " vertices in " << timer.as_string() << std::endl;
333  }
334 
335  // ---------------------------------------- color vertices feature
336  if ( opt.check( OpenMesh::IO::Options::VertexColor ) &&
337  !ropt.check( OpenMesh::IO::Options::VertexColor ) )
338  {
339  std::cout << "Color vertices" << std::endl;
340 
341  double d = 256.0/double(mesh.n_vertices());
342  double d2 = d/2.0;
343  double r = 0.0, g = 0.0, b = 255.0;
344  timer.start();
345  MyMesh::VertexIter vit = mesh.vertices_begin();
346  for (; vit != mesh.vertices_end(); ++vit)
347  {
348  mesh.set_color( *vit , MyMesh::Color( std::min((int)(r+0.5),255),
349  std::min((int)(g+0.5),255),
350  std::max((int)(b+0.5),0) ) );
351  r += d;
352  g += d2;
353  b -= d;
354  }
355  timer.stop();
356  std::cout << " colored " << mesh.n_vertices()
357  << " vertices in " << timer.as_string() << std::endl;
358  }
359 
360  // ---------------------------------------- color faces feature
361  if ( opt.check( OpenMesh::IO::Options::FaceColor ) &&
362  !ropt.check( OpenMesh::IO::Options::FaceColor ) )
363  {
364  std::cout << "Color faces" << std::endl;
365 
366  double d = 256.0/double(mesh.n_faces());
367  double d2 = d/2.0;
368  double r = 0.0, g = 50.0, b = 255.0;
369  timer.start();
370  MyMesh::FaceIter it = mesh.faces_begin();
371  for (; it != mesh.faces_end(); ++it)
372  {
373  mesh.set_color( *it , MyMesh::Color( std::min((int)(r+0.5),255),
374  std::min((int)(g+0.5),255),
375  std::max((int)(b+0.5),0) ) );
376  r += d2;
377 // g += d2;
378  b -= d;
379  }
380  timer.stop();
381  std::cout << " colored " << mesh.n_faces()
382  << " faces in " << timer.as_string() << std::endl;
383  }
384 
385  // ------------------------------------------------------------ write
386 
387  std::cout << "writing.." << std::endl;
388  {
389  bool rc;
390  timer.start();
391  rc = OpenMesh::IO::write_mesh( mesh, ofname, opt );
392  timer.stop();
393 
394  if (!rc)
395  {
396  std::cerr << " error writing mesh!" << std::endl;
397  return 1;
398  }
399 
400  // -------------------------------------- write output and some info
401  if ( opt.check(OpenMesh::IO::Options::Binary) )
402  {
403  std::cout << " "
404  << OpenMesh::IO::binary_size(mesh, ofname, opt)
405  << std::endl;
406  }
407  if ( opt.vertex_has_normal() )
408  std::cout << " with vertex normals" << std::endl;
409  if ( opt.vertex_has_color() )
410  std::cout << " with vertex colors" << std::endl;
411  if ( opt.vertex_has_texcoord() )
412  std::cout << " with vertex texcoord" << std::endl;
413  if ( opt.face_has_normal() )
414  std::cout << " with face normals" << std::endl;
415  if ( opt.face_has_color() )
416  std::cout << " with face colors" << std::endl;
417  std::cout << " wrote in " << timer.as_string() << std::endl;
418  timer.reset();
419  }
420 
421  return 0;
422 }
Has (r) / store (w) vertex colors.
Definition: Options.hh:105
Swap byte order in binary mode.
Definition: Options.hh:103
size_t binary_size(const Mesh &_mesh, const std::string &_ext, Options _opt=Options::Default)
Get binary size of data.
Definition: MeshIO.hh:268
decltype(std::declval< S >() *std::declval< S >()) sqrnorm() const
compute squared euclidean norm
Definition: Vector11T.hh:397
Assume little endian byte ordering.
Definition: Options.hh:102
Kernel::Color Color
Color type.
Definition: PolyMeshT.hh:116
Has (r) / store (w) face colors.
Definition: Options.hh:109
void reset(void)
Reset the timer.
bool write_mesh(const Mesh &_mesh, const std::string &_filename, Options _opt=Options::Default, std::streamsize _precision=6)
Write a mesh to the file _filename.
Definition: MeshIO.hh:207
std::string as_string(Format format=Automatic)
Add colors to mesh item (vertices/faces/edges)
Definition: Attributes.hh:83
void update_vertex_normals()
Update normal vectors for all vertices.
Has (r) / store (w) texture coordinates.
Definition: Options.hh:106
Add 2D texture coordinates (vertices, halfedges)
Definition: Attributes.hh:87
Set options for reader/writer modules.
Definition: Options.hh:90
Set binary mode for r/w.
Definition: Options.hh:100
Has (r) / store (w) vertex normals.
Definition: Options.hh:104
void update_face_normals()
Update normal vectors for all faces.
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
Definition: Attributes.hh:84
void start(void)
Start measurement.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:112
Add normals to mesh item (vertices/faces)
Definition: Attributes.hh:82
void cont(void)
Continue measurement.
Assume big endian byte ordering.
Definition: Options.hh:101
void stop(void)
Stop measurement.