Developer Documentation
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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  * $Revision$ *
45  * $Date$ *
46  * *
47 \*===========================================================================*/
48 
49 #include <iostream>
50 #include <iterator>
51 #include <fstream>
52 #include <string>
53 //
54 #include <OpenMesh/Core/IO/MeshIO.hh>
55 #include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
58 #include <OpenMesh/Tools/Utils/getopt.h>
59 
60 
61 struct MyTraits : public OpenMesh::DefaultTraits
62 {
63  VertexAttributes ( OpenMesh::Attributes::Normal |
66  HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
67  FaceAttributes ( OpenMesh::Attributes::Normal |
69 };
70 
71 
73 
74 void usage_and_exit(int xcode)
75 {
76  using std::cout;
77  using std::endl;
78 
79  cout << "\nUsage: mconvert [option] <input> [<output>]\n\n";
80  cout << " Convert from one 3D geometry format to another.\n"
81  << " Or simply display some information about the object\n"
82  << " stored in <input>.\n"
83  << endl;
84  cout << "Options:\n"
85  << endl;
86  cout << " -b\tUse binary mode if supported by target format.\n" << endl;
87  cout << " -l\tStore least significant bit first (LSB, little endian).\n" << endl;
88  cout << " -m\tStore most significant bit first (MSB, big endian).\n" << endl;
89  cout << " -s\tSwap byte order.\n" << endl;
90  cout << " -B\tUse binary mode if supported by source format.\n" << endl;
91  cout << " -S\tSwap byte order of input data.\n" << endl;
92  cout << " -c\tCopy vertex color if provided by input.\n" << endl;
93  cout << " -d\tCopy face color if provided by input.\n" << endl;
94  cout << " -C\tTranslate object in its center-of-gravity.\n" << endl;
95  cout << " -n\tCopy vertex normals if provided by input. Else compute normals.\n" << endl;
96  cout << " -N\tReverse normal directions.\n" << endl;
97  cout << " -t\tCopy vertex texture coordinates if provided by input file.\n" << endl;
98  cout << " -T \"x y z\"\tTranslate object by vector (x, y, z)'\"\n"
99  << std::endl;
100  cout << endl;
101 
102  exit(xcode);
103 }
104 
105 // ----------------------------------------------------------------------------
106 
107 template <typename T> struct Option : std::pair< T, bool >
108 {
109  typedef std::pair< T, bool > Base;
110 
111  Option()
112  { Base::second = false; }
113 
114  bool is_valid() const { return Base::second; }
115  bool is_empty() const { return !Base::second; }
116 
117  operator T& () { return Base::first; }
118  operator const T& () const { return Base::first; }
119 
120  Option& operator = ( const T& _rhs )
121  { Base::first = _rhs; Base::second=true; return *this; }
122 
123  bool operator == ( const T& _rhs ) const
124  { return Base::first == _rhs; }
125 
126  bool operator != ( const T& _rhs ) const
127  { return Base::first != _rhs; }
128 };
129 
130 template <typename T>
131 std::ostream& operator << (std::ostream& _os, const Option<T>& _opt )
132 {
133  if (_opt.second) _os << _opt.first; else _os << "<null>";
134  return _os;
135 }
136 
137 template <typename T>
138 std::istream& operator >> (std::istream& _is, Option<T>& _opt )
139 {
140  _is >> _opt.first; _opt.second = true;
141  return _is;
142 }
143 
144 // ----------------------------------------------------------------------------
145 
146 int main(int argc, char *argv[] )
147 {
148  // ------------------------------------------------------------ command line
149 
150  int c;
151  std::string ifname, ofname;
152  bool rev_normals = false;
153  bool obj_center = false;
154  OpenMesh::IO::Options opt, ropt;
155 
157 
158  while ( (c=getopt(argc, argv, "bBcdCi:hlmnNo:sStT:"))!=-1 )
159  {
160  switch(c)
161  {
162  case 'b': opt += OpenMesh::IO::Options::Binary; break;
163  case 'B': ropt += OpenMesh::IO::Options::Binary; break;
164  case 'l': opt += OpenMesh::IO::Options::LSB; break;
165  case 'm': opt += OpenMesh::IO::Options::MSB; break;
166  case 's': opt += OpenMesh::IO::Options::Swap; break;
167  case 'S': ropt += OpenMesh::IO::Options::Swap; break;
168  case 'n': opt += OpenMesh::IO::Options::VertexNormal; break;
169  case 'N': rev_normals = true; break;
170  case 'C': obj_center = true; break;
171  case 'c': opt += OpenMesh::IO::Options::VertexColor; break;
172  case 'd': opt += OpenMesh::IO::Options::FaceColor; break;
173  case 't': opt += OpenMesh::IO::Options::VertexTexCoord; break;
174  case 'T':
175  {
176  std::cout << optarg << std::endl;
177  std::stringstream str; str << optarg;
178  str >> tvec;
179  std::cout << tvec << std::endl;
180  break;
181  }
182  case 'i': ifname = optarg; break;
183  case 'o': ofname = optarg; break;
184  case 'h':
185  usage_and_exit(0);
186  case '?':
187  default:
188  usage_and_exit(1);
189  }
190  }
191 
192  if (ifname.empty())
193  {
194  if (optind < argc)
195  ifname = argv[optind++];
196  else
197  usage_and_exit(1);
198  }
199 
200  MyMesh mesh;
202 
203  // ------------------------------------------------------------ read
204 
205  std::cout << "reading.." << std::endl;
206  {
207  bool rc;
208  timer.start();
209  rc = OpenMesh::IO::read_mesh( mesh, ifname, ropt );
210  timer.stop();
211  if (rc)
212  std::cout << " read in " << timer.as_string() << std::endl;
213  else
214  {
215  std::cout << " read failed\n" << std::endl;
216  return 1;
217  }
218  timer.reset();
219  }
220 
221 
222  // ---------------------------------------- some information about input
223  std::cout << (ropt.check(OpenMesh::IO::Options::Binary)
224  ? " source is binary\n"
225  : " source is ascii\n");
226 
227  std::cout << " #V " << mesh.n_vertices() << std::endl;
228  std::cout << " #E " << mesh.n_edges() << std::endl;
229  std::cout << " #F " << mesh.n_faces() << std::endl;
230 
231  if (ropt.vertex_has_texcoord())
232  std::cout << " has texture coordinates" << std::endl;
233 
234  if (ropt.vertex_has_normal())
235  std::cout << " has vertex normals" << std::endl;
236 
237  if (ropt.vertex_has_color())
238  std::cout << " has vertex colors" << std::endl;
239 
240  if (ropt.face_has_normal())
241  std::cout << " has face normals" << std::endl;
242 
243  if (ropt.face_has_color())
244  std::cout << " has face colors" << std::endl;
245 
246  //
247  if (ofname.empty())
248  {
249  if ( optind < argc )
250  ofname = argv[optind++];
251  else
252  return 0;
253  }
254 
255  // ------------------------------------------------------------ features
256 
257  // ---------------------------------------- compute normal feature
258  if ( opt.vertex_has_normal() && !ropt.vertex_has_normal())
259  {
260  std::cout << "compute normals" << std::endl;
261 
262  timer.start();
263  mesh.update_face_normals();
264  timer.stop();
265  std::cout << " " << mesh.n_faces()
266  << " face normals in " << timer.as_string() << std::endl;
267  timer.reset();
268 
269  timer.start();
270  mesh.update_vertex_normals();
271  timer.stop();
272  std::cout << " " << mesh.n_vertices()
273  << " vertex normals in " << timer.as_string() << std::endl;
274  timer.reset();
275  }
276 
277 
278  // ---------------------------------------- reverse normal feature
279  if ( rev_normals && ropt.vertex_has_normal() )
280  {
281  std::cout << "reverse normal directions" << std::endl;
282  timer.start();
283  MyMesh::VertexIter vit = mesh.vertices_begin();
284  for (; vit != mesh.vertices_end(); ++vit)
285  mesh.set_normal( *vit, -mesh.normal( *vit ) );
286  timer.stop();
287  std::cout << " " << mesh.n_vertices()
288  << " vertex normals in " << timer.as_string() << std::endl;
289  timer.reset();
290 
291  }
292 
293 
294  // ---------------------------------------- centering feature
295  if ( obj_center )
296  {
297  OpenMesh::Vec3f cog(0,0,0);
298  size_t nv;
299  std::cout << "center object" << std::endl;
300  timer.start();
301  MyMesh::VertexIter vit = mesh.vertices_begin();
302  for (; vit != mesh.vertices_end(); ++vit)
303  cog += mesh.point( *vit );
304  timer.stop();
305  nv = mesh.n_vertices();
306  cog *= 1.0f/mesh.n_vertices();
307  std::cout << " cog = [" << cog << "]'" << std::endl;
308  if (cog.sqrnorm() > 0.8) // actually one should consider the size of object
309  {
310  vit = mesh.vertices_begin();
311  timer.cont();
312  for (; vit != mesh.vertices_end(); ++vit)
313  mesh.set_point( *vit , mesh.point( *vit )-cog );
314  timer.stop();
315  nv += mesh.n_vertices();
316  }
317  else
318  std::cout << " already centered!" << std::endl;
319  std::cout << " visited " << nv
320  << " vertices in " << timer.as_string() << std::endl;
321  timer.reset();
322  }
323 
324 
325  // ---------------------------------------- translate feature
326  if ( tvec.is_valid() )
327  {
328  std::cout << "Translate object by " << tvec << std::endl;
329 
330  timer.start();
331  MyMesh::VertexIter vit = mesh.vertices_begin();
332  for (; vit != mesh.vertices_end(); ++vit)
333  mesh.set_point( *vit , mesh.point( *vit ) + tvec.first );
334  timer.stop();
335  std::cout << " moved " << mesh.n_vertices()
336  << " vertices in " << timer.as_string() << std::endl;
337  }
338 
339  // ---------------------------------------- color vertices feature
340  if ( opt.check( OpenMesh::IO::Options::VertexColor ) &&
341  !ropt.check( OpenMesh::IO::Options::VertexColor ) )
342  {
343  std::cout << "Color vertices" << std::endl;
344 
345  double d = 256.0/double(mesh.n_vertices());
346  double d2 = d/2.0;
347  double r = 0.0, g = 0.0, b = 255.0;
348  timer.start();
349  MyMesh::VertexIter vit = mesh.vertices_begin();
350  for (; vit != mesh.vertices_end(); ++vit)
351  {
352  mesh.set_color( *vit , MyMesh::Color( std::min((int)(r+0.5),255),
353  std::min((int)(g+0.5),255),
354  std::max((int)(b+0.5),0) ) );
355  r += d;
356  g += d2;
357  b -= d;
358  }
359  timer.stop();
360  std::cout << " colored " << mesh.n_vertices()
361  << " vertices in " << timer.as_string() << std::endl;
362  }
363 
364  // ---------------------------------------- color faces feature
365  if ( opt.check( OpenMesh::IO::Options::FaceColor ) &&
366  !ropt.check( OpenMesh::IO::Options::FaceColor ) )
367  {
368  std::cout << "Color faces" << std::endl;
369 
370  double d = 256.0/double(mesh.n_faces());
371  double d2 = d/2.0;
372  double r = 0.0, g = 50.0, b = 255.0;
373  timer.start();
374  MyMesh::FaceIter it = mesh.faces_begin();
375  for (; it != mesh.faces_end(); ++it)
376  {
377  mesh.set_color( *it , MyMesh::Color( std::min((int)(r+0.5),255),
378  std::min((int)(g+0.5),255),
379  std::max((int)(b+0.5),0) ) );
380  r += d2;
381 // g += d2;
382  b -= d;
383  }
384  timer.stop();
385  std::cout << " colored " << mesh.n_faces()
386  << " faces in " << timer.as_string() << std::endl;
387  }
388 
389  // ------------------------------------------------------------ write
390 
391  std::cout << "writing.." << std::endl;
392  {
393  bool rc;
394  timer.start();
395  rc = OpenMesh::IO::write_mesh( mesh, ofname, opt );
396  timer.stop();
397 
398  if (!rc)
399  {
400  std::cerr << " error writing mesh!" << std::endl;
401  return 1;
402  }
403 
404  // -------------------------------------- write output and some info
405  if ( opt.check(OpenMesh::IO::Options::Binary) )
406  {
407  std::cout << " "
408  << OpenMesh::IO::binary_size(mesh, ofname, opt)
409  << std::endl;
410  }
411  if ( opt.vertex_has_normal() )
412  std::cout << " with vertex normals" << std::endl;
413  if ( opt.vertex_has_color() )
414  std::cout << " with vertex colors" << std::endl;
415  if ( opt.vertex_has_texcoord() )
416  std::cout << " with vertex texcoord" << std::endl;
417  if ( opt.face_has_normal() )
418  std::cout << " with face normals" << std::endl;
419  if ( opt.face_has_color() )
420  std::cout << " with face colors" << std::endl;
421  std::cout << " wrote in " << timer.as_string() << std::endl;
422  timer.reset();
423  }
424 
425  return 0;
426 }
Add colors to mesh item (vertices/faces/edges)
Definition: Attributes.hh:88
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:104
void stop(void)
Stop measurement.
Kernel::Color Color
Color type.
Definition: PolyMeshT.hh:119
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
size_t binary_size(const Mesh &_mesh, const std::string &_ext, Options _opt=Options::Default)
Get binary size of data.
Definition: MeshIO.hh:260
Assume big endian byte ordering.
Definition: Options.hh:106
Has (r) / store (w) face colors.
Definition: Options.hh:114
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
Set options for reader/writer modules.
Definition: Options.hh:95
std::string as_string(Format format=Automatic)
Add 2D texture coordinates (vertices, halfedges)
Definition: Attributes.hh:92
void update_vertex_normals()
Update normal vectors for all vertices.
Definition: PolyMeshT.cc:448
void reset(void)
Reset the timer.
void update_face_normals()
Update normal vectors for all faces.
Definition: PolyMeshT.cc:259
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
Definition: Attributes.hh:89
void start(void)
Start measurement.
Add normals to mesh item (vertices/faces)
Definition: Attributes.hh:87
Set binary mode for r/w.
Definition: Options.hh:105
Swap byte order in binary mode.
Definition: Options.hh:108
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
Assume little endian byte ordering.
Definition: Options.hh:107
void cont(void)
Continue measurement.
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:199