Developer Documentation
OFFReader.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 
50 #define LINE_LEN 4096
51 
52 
53 //== INCLUDES =================================================================
54 
55 // OpenMesh
58 #include <OpenMesh/Core/IO/reader/OFFReader.hh>
59 #include <OpenMesh/Core/IO/IOManager.hh>
60 #include <OpenMesh/Core/Utils/color_cast.hh>
61 // #include <OpenMesh/Core/IO/BinaryHelper.hh>
62 
63 //STL
64 #include <iostream>
65 #include <fstream>
66 #include <memory>
67 #include <cstring>
68 
69 #if defined(OM_CC_MIPS)
70 # include <ctype.h>
72 #elif defined(_STLPORT_VERSION) && (_STLPORT_VERSION==0x460)
73 # include <cctype>
74 #else
75 using std::isspace;
76 #endif
77 
78 #ifndef WIN32
79 #endif
80 
81 //=== NAMESPACES ==============================================================
82 
83 
84 namespace OpenMesh {
85 namespace IO {
86 
87 
88 //=============================================================================
89 
90 //=== INSTANCIATE =============================================================
91 
92 
94 _OFFReader_& OFFReader() { return __OFFReaderInstance; }
95 
96 
97 //=== IMPLEMENTATION ==========================================================
98 
99 
100 
101 _OFFReader_::_OFFReader_()
102 {
103  IOManager().register_module(this);
104 }
105 
106 
107 //-----------------------------------------------------------------------------
108 
109 
110 bool
111 _OFFReader_::read(const std::string& _filename, BaseImporter& _bi,
112  Options& _opt)
113 {
114  std::ifstream ifile(_filename.c_str(), (options_.is_binary() ? std::ios::binary | std::ios::in
115  : std::ios::in) );
116 
117  if (!ifile.is_open() || !ifile.good())
118  {
119  omerr() << "[OFFReader] : cannot not open file "
120  << _filename
121  << std::endl;
122 
123  return false;
124  }
125 
126  assert(ifile);
127 
128  bool result = read(ifile, _bi, _opt);
129 
130  ifile.close();
131  return result;
132 }
133 
134 //-----------------------------------------------------------------------------
135 
136 
137 bool
138 _OFFReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt )
139 {
140  if (!_in.good())
141  {
142  omerr() << "[OMReader] : cannot not use stream "
143  << std::endl;
144  return false;
145  }
146 
147  // filter relevant options for reading
148  bool swap = _opt.check( Options::Swap );
149 
150 
151  userOptions_ = _opt;
152 
153  // build options to be returned
154  _opt.clear();
155 
156  if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) _opt += Options::VertexNormal;
157  if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) _opt += Options::VertexTexCoord;
158  if (options_.vertex_has_color() && userOptions_.vertex_has_color()) _opt += Options::VertexColor;
159  if (options_.face_has_color() && userOptions_.face_has_color()) _opt += Options::FaceColor;
160  if (options_.is_binary()) _opt += Options::Binary;
161 
162  //force user-choice for the alpha value when reading binary
163  if ( options_.is_binary() && userOptions_.color_has_alpha() )
164  options_ += Options::ColorAlpha;
165 
166  return (options_.is_binary() ?
167  read_binary(_in, _bi, _opt, swap) :
168  read_ascii(_in, _bi, _opt));
169 
170 }
171 
172 
173 
174 //-----------------------------------------------------------------------------
175 
176 bool
177 _OFFReader_::read_ascii(std::istream& _in, BaseImporter& _bi, Options& _opt) const
178 {
179 
180 
181  unsigned int i, j, k, l, idx;
182  unsigned int nV, nF, dummy;
183  OpenMesh::Vec3f v, n;
184  OpenMesh::Vec2f t;
185  OpenMesh::Vec3i c3;
186  OpenMesh::Vec3f c3f;
187  OpenMesh::Vec4i c4;
188  OpenMesh::Vec4f c4f;
189  BaseImporter::VHandles vhandles;
190  VertexHandle vh;
191  std::stringstream stream;
192  std::string trash;
193 
194  // read header line
195  std::string header;
196  std::getline(_in,header);
197 
198  // + #Vertice, #Faces, #Edges
199  _in >> nV;
200  _in >> nF;
201  _in >> dummy;
202 
203  _bi.reserve(nV, 3*nV, nF);
204 
205  // read vertices: coord [hcoord] [normal] [color] [texcoord]
206  for (i=0; i<nV && !_in.eof(); ++i)
207  {
208  // Always read VERTEX
209  _in >> v[0]; _in >> v[1]; _in >> v[2];
210 
211  vh = _bi.add_vertex(v);
212 
213  //perhaps read NORMAL
214  if ( options_.vertex_has_normal() ){
215 
216  _in >> n[0]; _in >> n[1]; _in >> n[2];
217 
218  if ( userOptions_.vertex_has_normal() )
219  _bi.set_normal(vh, n);
220  }
221 
222  //take the rest of the line and check how colors are defined
223  std::string line;
224  std::getline(_in,line);
225 
226  int colorType = getColorType(line, options_.vertex_has_texcoord() );
227 
228  stream.str(line);
229  stream.clear();
230 
231  //perhaps read COLOR
232  if ( options_.vertex_has_color() ){
233 
234  switch (colorType){
235  case 0 : break; //no color
236  case 1 : stream >> trash; break; //one int (isn't handled atm)
237  case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore)
238  // rgb int
239  case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2];
240  if ( userOptions_.vertex_has_color() )
241  _bi.set_color( vh, Vec3uc( c3 ) );
242  break;
243  // rgba int
244  case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3];
245  if ( userOptions_.vertex_has_color() )
246  _bi.set_color( vh, Vec4uc( c4 ) );
247  break;
248  // rgb floats
249  case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2];
250  if ( userOptions_.vertex_has_color() ) {
251  _bi.set_color( vh, c3f );
252  _opt += Options::ColorFloat;
253  }
254  break;
255  // rgba floats
256  case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3];
257  if ( userOptions_.vertex_has_color() ) {
258  _bi.set_color( vh, c4f );
259  _opt += Options::ColorFloat;
260  }
261  break;
262 
263  default:
264  std::cerr << "Error in file format (colorType = " << colorType << ")\n";
265  break;
266  }
267  }
268  //perhaps read TEXTURE COORDs
269  if ( options_.vertex_has_texcoord() ){
270  stream >> t[0]; stream >> t[1];
271  if ( userOptions_.vertex_has_texcoord() )
272  _bi.set_texcoord(vh, t);
273  }
274  }
275 
276  // faces
277  // #N <v1> <v2> .. <v(n-1)> [color spec]
278  for (i=0; i<nF; ++i)
279  {
280  // nV = number of Vertices for current face
281  _in >> nV;
282 
283  if (nV == 3)
284  {
285  vhandles.resize(3);
286  _in >> j;
287  _in >> k;
288  _in >> l;
289 
290  vhandles[0] = VertexHandle(j);
291  vhandles[1] = VertexHandle(k);
292  vhandles[2] = VertexHandle(l);
293  }
294  else
295  {
296  vhandles.clear();
297  for (j=0; j<nV; ++j)
298  {
299  _in >> idx;
300  vhandles.push_back(VertexHandle(idx));
301  }
302  }
303 
304  FaceHandle fh = _bi.add_face(vhandles);
305 
306  //perhaps read face COLOR
307  if ( options_.face_has_color() ){
308 
309  //take the rest of the line and check how colors are defined
310  std::string line;
311  std::getline(_in,line);
312 
313  int colorType = getColorType(line, false );
314 
315  stream.str(line);
316  stream.clear();
317 
318  switch (colorType){
319  case 0 : break; //no color
320  case 1 : stream >> trash; break; //one int (isn't handled atm)
321  case 2 : stream >> trash; stream >> trash; break; //corrupt format (ignore)
322  // rgb int
323  case 3 : stream >> c3[0]; stream >> c3[1]; stream >> c3[2];
324  if ( userOptions_.face_has_color() )
325  _bi.set_color( fh, Vec3uc( c3 ) );
326  break;
327  // rgba int
328  case 4 : stream >> c4[0]; stream >> c4[1]; stream >> c4[2]; stream >> c4[3];
329  if ( userOptions_.face_has_color() )
330  _bi.set_color( fh, Vec4uc( c4 ) );
331  break;
332  // rgb floats
333  case 5 : stream >> c3f[0]; stream >> c3f[1]; stream >> c3f[2];
334  if ( userOptions_.face_has_color() ) {
335  _bi.set_color( fh, c3f );
336  _opt += Options::ColorFloat;
337  }
338  break;
339  // rgba floats
340  case 6 : stream >> c4f[0]; stream >> c4f[1]; stream >> c4f[2]; stream >> c4f[3];
341  if ( userOptions_.face_has_color() ) {
342  _bi.set_color( fh, c4f );
343  _opt += Options::ColorFloat;
344  }
345  break;
346 
347  default:
348  std::cerr << "Error in file format (colorType = " << colorType << ")\n";
349  break;
350  }
351  }
352  }
353 
354  // File was successfully parsed.
355  return true;
356 }
357 
358 
359 //-----------------------------------------------------------------------------
360 
361 int _OFFReader_::getColorType(std::string& _line, bool _texCoordsAvailable) const
362 {
363 /*
364  0 : no Color
365  1 : one int (e.g colormap index)
366  2 : two items (error!)
367  3 : 3 ints
368  4 : 3 ints
369  5 : 3 floats
370  6 : 4 floats
371 
372 */
373  // Check if we have any additional information here
374  if ( _line.size() < 1 )
375  return 0;
376 
377  //first remove spaces at start/end of the line
378  while (_line.size() > 0 && std::isspace(_line[0]))
379  _line = _line.substr(1);
380  while (_line.size() > 0 && std::isspace(_line[ _line.length()-1 ]))
381  _line = _line.substr(0, _line.length()-1);
382 
383  //count the remaining items in the line
384  size_t found;
385  int count = 0;
386 
387  found=_line.find_first_of(" ");
388  while (found!=std::string::npos){
389  count++;
390  found=_line.find_first_of(" ",found+1);
391  }
392 
393  if (!_line.empty()) count++;
394 
395  if (_texCoordsAvailable) count -= 2;
396 
397  if (count == 3 || count == 4){
398  //get first item
399  found = _line.find(" ");
400  std::string c1 = _line.substr (0,found);
401 
402  if (c1.find(".") != std::string::npos){
403  if (count == 3)
404  count = 5;
405  else
406  count = 6;
407  }
408  }
409  return count;
410 }
411 
412 void _OFFReader_::readValue(std::istream& _in, float& _value) const{
413  float32_t tmp;
414 
415  restore( _in , tmp, false ); //assuming LSB byte order
416  _value = tmp;
417 }
418 
419 void _OFFReader_::readValue(std::istream& _in, int& _value) const{
420  uint32_t tmp;
421 
422  restore( _in , tmp, false ); //assuming LSB byte order
423  _value = tmp;
424 }
425 
426 void _OFFReader_::readValue(std::istream& _in, unsigned int& _value) const{
427  uint32_t tmp;
428 
429  restore( _in , tmp, false ); //assuming LSB byte order
430  _value = tmp;
431 }
432 
433 bool
434 _OFFReader_::read_binary(std::istream& _in, BaseImporter& _bi, Options& _opt, bool /*_swap*/) const
435 {
436  unsigned int i, j, k, l, idx;
437  unsigned int nV, nF, dummy;
438  OpenMesh::Vec3f v, n;
439  OpenMesh::Vec3i c;
440  OpenMesh::Vec4i cA;
441  OpenMesh::Vec3f cf;
442  OpenMesh::Vec4f cAf;
443  OpenMesh::Vec2f t;
444  BaseImporter::VHandles vhandles;
445  VertexHandle vh;
446 
447  // read header line
448  std::string header;
449  std::getline(_in,header);
450 
451  // + #Vertice, #Faces, #Edges
452  readValue(_in, nV);
453  readValue(_in, nF);
454  readValue(_in, dummy);
455 
456  _bi.reserve(nV, 3*nV, nF);
457 
458  // read vertices: coord [hcoord] [normal] [color] [texcoord]
459  for (i=0; i<nV && !_in.eof(); ++i)
460  {
461  // Always read Vertex
462  readValue(_in, v[0]);
463  readValue(_in, v[1]);
464  readValue(_in, v[2]);
465 
466  vh = _bi.add_vertex(v);
467 
468  if ( options_.vertex_has_normal() ) {
469  readValue(_in, n[0]);
470  readValue(_in, n[1]);
471  readValue(_in, n[2]);
472 
473  if ( userOptions_.vertex_has_normal() )
474  _bi.set_normal(vh, n);
475  }
476 
477  if ( options_.vertex_has_color() ) {
478  if ( userOptions_.color_is_float() ) {
479  _opt += Options::ColorFloat;
480  //with alpha
481  if ( options_.color_has_alpha() ){
482  readValue(_in, cAf[0]);
483  readValue(_in, cAf[1]);
484  readValue(_in, cAf[2]);
485  readValue(_in, cAf[3]);
486 
487  if ( userOptions_.vertex_has_color() )
488  _bi.set_color( vh, cAf );
489  }else{
490 
491  //without alpha
492  readValue(_in, cf[0]);
493  readValue(_in, cf[1]);
494  readValue(_in, cf[2]);
495 
496  if ( userOptions_.vertex_has_color() )
497  _bi.set_color( vh, cf );
498  }
499  } else {
500  //with alpha
501  if ( options_.color_has_alpha() ){
502  readValue(_in, cA[0]);
503  readValue(_in, cA[1]);
504  readValue(_in, cA[2]);
505  readValue(_in, cA[3]);
506 
507  if ( userOptions_.vertex_has_color() )
508  _bi.set_color( vh, Vec4uc( cA ) );
509  }else{
510  //without alpha
511  readValue(_in, c[0]);
512  readValue(_in, c[1]);
513  readValue(_in, c[2]);
514 
515  if ( userOptions_.vertex_has_color() )
516  _bi.set_color( vh, Vec3uc( c ) );
517  }
518  }
519  }
520 
521  if ( options_.vertex_has_texcoord()) {
522  readValue(_in, t[0]);
523  readValue(_in, t[1]);
524 
525  if ( userOptions_.vertex_has_texcoord() )
526  _bi.set_texcoord(vh, t);
527  }
528  }
529 
530  // faces
531  // #N <v1> <v2> .. <v(n-1)> [color spec]
532  // So far color spec is unsupported!
533  for (i=0; i<nF; ++i)
534  {
535  readValue(_in, nV);
536 
537  if (nV == 3)
538  {
539  vhandles.resize(3);
540  readValue(_in, j);
541  readValue(_in, k);
542  readValue(_in, l);
543 
544  vhandles[0] = VertexHandle(j);
545  vhandles[1] = VertexHandle(k);
546  vhandles[2] = VertexHandle(l);
547  } else {
548  vhandles.clear();
549  for (j=0; j<nV; ++j)
550  {
551  readValue(_in, idx);
552  vhandles.push_back(VertexHandle(idx));
553  }
554  }
555 
556  FaceHandle fh = _bi.add_face(vhandles);
557 
558  //face color
559  if ( _opt.face_has_color() ) {
560  if ( userOptions_.color_is_float() ) {
561  _opt += Options::ColorFloat;
562  //with alpha
563  if ( options_.color_has_alpha() ){
564  readValue(_in, cAf[0]);
565  readValue(_in, cAf[1]);
566  readValue(_in, cAf[2]);
567  readValue(_in, cAf[3]);
568 
569  if ( userOptions_.face_has_color() )
570  _bi.set_color( fh , cAf );
571  }else{
572  //without alpha
573  readValue(_in, cf[0]);
574  readValue(_in, cf[1]);
575  readValue(_in, cf[2]);
576 
577  if ( userOptions_.face_has_color() )
578  _bi.set_color( fh, cf );
579  }
580  } else {
581  //with alpha
582  if ( options_.color_has_alpha() ){
583  readValue(_in, cA[0]);
584  readValue(_in, cA[1]);
585  readValue(_in, cA[2]);
586  readValue(_in, cA[3]);
587 
588  if ( userOptions_.face_has_color() )
589  _bi.set_color( fh , Vec4uc( cA ) );
590  }else{
591  //without alpha
592  readValue(_in, c[0]);
593  readValue(_in, c[1]);
594  readValue(_in, c[2]);
595 
596  if ( userOptions_.face_has_color() )
597  _bi.set_color( fh, Vec3uc( c ) );
598  }
599  }
600  }
601 
602  }
603 
604  // File was successfully parsed.
605  return true;
606 
607 }
608 
609 
610 //-----------------------------------------------------------------------------
611 
612 
613 bool _OFFReader_::can_u_read(const std::string& _filename) const
614 {
615  // !!! Assuming BaseReader::can_u_parse( std::string& )
616  // does not call BaseReader::read_magic()!!!
617  if (BaseReader::can_u_read(_filename))
618  {
619  std::ifstream ifs(_filename.c_str());
620  if (ifs.is_open() && can_u_read(ifs))
621  {
622  ifs.close();
623  return true;
624  }
625  }
626  return false;
627 }
628 
629 
630 //-----------------------------------------------------------------------------
631 
632 
633 bool _OFFReader_::can_u_read(std::istream& _is) const
634 {
635  options_.cleanup();
636 
637  // read 1st line
638  char line[LINE_LEN], *p;
639  _is.getline(line, LINE_LEN);
640  p = line;
641 
642  std::streamsize remainingChars = _is.gcount();
643 
644  bool vertexDimensionTooHigh = false;
645 
646  // check header: [ST][C][N][4][n]OFF BINARY
647 
648  if ( ( remainingChars > 1 ) && ( p[0] == 'S' && p[1] == 'T') )
649  { options_ += Options::VertexTexCoord; p += 2; remainingChars -= 2; }
650 
651  if ( ( remainingChars > 0 ) && ( p[0] == 'C') )
652  { options_ += Options::VertexColor;
653  options_ += Options::FaceColor; ++p; --remainingChars; }
654 
655  if ( ( remainingChars > 0 ) && ( p[0] == 'N') )
656  { options_ += Options::VertexNormal; ++p; --remainingChars; }
657 
658  if ( ( remainingChars > 0 ) && (p[0] == '4' ) )
659  { vertexDimensionTooHigh = true; ++p; --remainingChars; }
660 
661  if ( ( remainingChars > 0 ) && ( p[0] == 'n') )
662  { vertexDimensionTooHigh = true; ++p; --remainingChars; }
663 
664  if ( ( remainingChars < 3 ) || (!(p[0] == 'O' && p[1] == 'F' && p[2] == 'F') ) )
665  return false;
666 
667  p += 4;
668 
669  // Detect possible garbage and make sure, we don't have an underflow
670  if ( remainingChars >= 4 )
671  remainingChars -= 4;
672  else
673  remainingChars = 0;
674 
675  if ( ( remainingChars >= 6 ) && ( strncmp(p, "BINARY", 6) == 0 ) )
676  options_+= Options::Binary;
677 
678  // vertex Dimensions != 3 are currently not supported
679  if (vertexDimensionTooHigh)
680  return false;
681 
682  return true;
683 }
684 
685 
686 //=============================================================================
687 } // namespace IO
688 } // namespace OpenMesh
689 //=============================================================================
virtual bool can_u_read(const std::string &_filename) const
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
Definition: BaseReader.cc:82
Has (r) / store (w) texture coordinates.
Definition: Options.hh:111
Has (r) / store (w) alpha values for colors.
Definition: Options.hh:116
Set binary mode for r/w.
Definition: Options.hh:105
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
_OFFReader_ __OFFReaderInstance
Declare the single entity of the OFF reader.
Definition: OFFReader.cc:93
void clear(void)
Clear all bits.
Definition: Options.hh:151
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt)
Definition: OFFReader.cc:111
bool can_u_read(const std::string &_filename) const
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
Definition: OFFReader.cc:613
Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) ...
Definition: Options.hh:117
Set options for reader/writer modules.
Definition: Options.hh:95
Handle for a vertex entity.
Definition: Handles.hh:125
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:222
Swap byte order in binary mode.
Definition: Options.hh:108
Handle for a face entity.
Definition: Handles.hh:146
Has (r) / store (w) face colors.
Definition: Options.hh:114
unsigned int uint32_t
Definition: SR_types.hh:90
void cleanup(void)
Restore state after default constructor.
Definition: Options.hh:147
Has (r) / store (w) vertex colors.
Definition: Options.hh:110
_IOManager_ & IOManager()
Definition: IOManager.cc:77
float float32_t
Definition: SR_types.hh:97