Developer Documentation
PLYReader.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 #define LINE_LEN 4096
43 
44 //== INCLUDES =================================================================
45 
46 // OpenMesh
49 #include <OpenMesh/Core/IO/reader/PLYReader.hh>
50 #include <OpenMesh/Core/IO/IOManager.hh>
51 #include <OpenMesh/Core/Utils/color_cast.hh>
52 
53 //STL
54 #include <fstream>
55 #include <iostream>
56 #include <memory>
57 
58 #ifndef WIN32
59 #endif
60 
61 //=== NAMESPACES ==============================================================
62 
63 
64 namespace OpenMesh {
65 namespace IO {
66 
67 //=============================================================================
68 
69 //=== INSTANCIATE =============================================================
70 
71 
73 _PLYReader_& PLYReader() {
74  return __PLYReaderInstance;
75 }
76 
77 //=== IMPLEMENTATION ==========================================================
78 
79 
80 _PLYReader_::_PLYReader_() {
81  IOManager().register_module(this);
82 
83  // Store sizes in byte of each property type
84  scalar_size_[ValueTypeINT8] = 1;
85  scalar_size_[ValueTypeUINT8] = 1;
86  scalar_size_[ValueTypeINT16] = 2;
87  scalar_size_[ValueTypeUINT16] = 2;
88  scalar_size_[ValueTypeINT32] = 4;
89  scalar_size_[ValueTypeUINT32] = 4;
90  scalar_size_[ValueTypeFLOAT32] = 4;
91  scalar_size_[ValueTypeFLOAT64] = 8;
92 
93  scalar_size_[ValueTypeCHAR] = 1;
94  scalar_size_[ValueTypeUCHAR] = 1;
95  scalar_size_[ValueTypeSHORT] = 2;
96  scalar_size_[ValueTypeUSHORT] = 2;
97  scalar_size_[ValueTypeINT] = 4;
98  scalar_size_[ValueTypeUINT] = 4;
99  scalar_size_[ValueTypeFLOAT] = 4;
100  scalar_size_[ValueTypeDOUBLE] = 8;
101 }
102 
103 //-----------------------------------------------------------------------------
104 
105 
106 bool _PLYReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) {
107 
108  std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) );
109 
110  if (!in.is_open() || !in.good()) {
111  omerr() << "[PLYReader] : cannot not open file " << _filename << std::endl;
112  return false;
113  }
114 
115  bool result = read(in, _bi, _opt);
116 
117  in.close();
118  return result;
119 }
120 
121 //-----------------------------------------------------------------------------
122 
123 
124 bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) {
125 
126  if (!_in.good()) {
127  omerr() << "[PLYReader] : cannot not use stream" << std::endl;
128  return false;
129  }
130 
131  // Reparse the header
132  if (!can_u_read(_in)) {
133  omerr() << "[PLYReader] : Unable to parse header\n";
134  return false;
135  }
136 
137 
138 
139  // filter relevant options for reading
140  bool swap = _opt.check(Options::Swap);
141 
142  userOptions_ = _opt;
143 
144  // build options to be returned
145  _opt.clear();
146 
147  if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) {
148  _opt += Options::VertexNormal;
149  }
150  if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) {
151  _opt += Options::VertexTexCoord;
152  }
153  if (options_.vertex_has_color() && userOptions_.vertex_has_color()) {
154  _opt += Options::VertexColor;
155  }
156  if (options_.face_has_color() && userOptions_.face_has_color()) {
157  _opt += Options::FaceColor;
158  }
159  if (options_.is_binary()) {
160  _opt += Options::Binary;
161  }
162  if (options_.color_is_float()) {
163  _opt += Options::ColorFloat;
164  }
165  if (options_.check(Options::Custom) && userOptions_.check(Options::Custom)) {
166  _opt += Options::Custom;
167  }
168 
169  // //force user-choice for the alpha value when reading binary
170  // if ( options_.is_binary() && userOptions_.color_has_alpha() )
171  // options_ += Options::ColorAlpha;
172 
173  return (options_.is_binary() ? read_binary(_in, _bi, swap, _opt) : read_ascii(_in, _bi, _opt));
174 
175 }
176 
177 template<typename T, typename Handle>
178 struct Handle2Prop;
179 
180 template<typename T>
182 {
184 };
185 
186 template<typename T>
188 {
190 };
191 
192 //read and assign custom properties with the given type. Also creates property, if not exist
193 template<bool binary, typename T, typename Handle>
194 void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listType) const
195 {
196  if (_listType == Unsupported) //no list type defined -> property is not a list
197  {
198  //get/add property
199  typename Handle2Prop<T,Handle>::PropT prop;
200  if (!_bi.kernel()->get_property_handle(prop,_propName))
201  {
202  _bi.kernel()->add_property(prop,_propName);
203  _bi.kernel()->property(prop).set_persistent(true);
204  }
205 
206  //read and assign
207  T in;
208  read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type<binary>());
209  _bi.kernel()->property(prop,_h) = in;
210  }
211  else
212  {
213  //get/add property
214  typename Handle2Prop<std::vector<T>,Handle>::PropT prop;
215  if (!_bi.kernel()->get_property_handle(prop,_propName))
216  {
217  _bi.kernel()->add_property(prop,_propName);
218  _bi.kernel()->property(prop).set_persistent(true);
219  }
220 
221  //init vector
222  unsigned int numberOfValues;
223  readInteger(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type<binary>());
224  std::vector<T> vec(numberOfValues);
225  //read and assign
226  for (unsigned int i = 0; i < numberOfValues; ++i)
227  {
228  read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type<binary>());
229  }
230  _bi.kernel()->property(prop,_h) = vec;
231  }
232 }
233 
234 template<bool binary, typename Handle>
235 void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const
236 {
237  switch (_valueType)
238  {
239  case ValueTypeINT8:
240  case ValueTypeCHAR:
241  readCreateCustomProperty<binary,signed char>(_in,_bi,_h,_propName,_valueType,_listIndexType);
242  break;
243  case ValueTypeUINT8:
244  case ValueTypeUCHAR:
245  readCreateCustomProperty<binary,unsigned char>(_in,_bi,_h,_propName,_valueType,_listIndexType);
246  break;
247  case ValueTypeINT16:
248  case ValueTypeSHORT:
249  readCreateCustomProperty<binary,short>(_in,_bi,_h,_propName,_valueType,_listIndexType);
250  break;
251  case ValueTypeUINT16:
252  case ValueTypeUSHORT:
253  readCreateCustomProperty<binary,unsigned short>(_in,_bi,_h,_propName,_valueType,_listIndexType);
254  break;
255  case ValueTypeINT32:
256  case ValueTypeINT:
257  readCreateCustomProperty<binary,int>(_in,_bi,_h,_propName,_valueType,_listIndexType);
258  break;
259  case ValueTypeUINT32:
260  case ValueTypeUINT:
261  readCreateCustomProperty<binary,unsigned int>(_in,_bi,_h,_propName,_valueType,_listIndexType);
262  break;
263  case ValueTypeFLOAT32:
264  case ValueTypeFLOAT:
265  readCreateCustomProperty<binary,float>(_in,_bi,_h,_propName,_valueType,_listIndexType);
266  break;
267  case ValueTypeFLOAT64:
268  case ValueTypeDOUBLE:
269  readCreateCustomProperty<binary,double>(_in,_bi,_h,_propName,_valueType,_listIndexType);
270  break;
271  default:
272  std::cerr << "unsupported type" << std::endl;
273  break;
274  }
275 }
276 
277 
278 //-----------------------------------------------------------------------------
279 
280 bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const {
281 
282  unsigned int i, j, k, l, idx;
283  unsigned int nV;
284  OpenMesh::Vec3f v, n;
285  std::string trash;
286  OpenMesh::Vec2f t;
287  OpenMesh::Vec4i c;
288  float tmp;
289  BaseImporter::VHandles vhandles;
290  VertexHandle vh;
291 
292  _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_);
293 
294  if (vertexDimension_ != 3) {
295  omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl;
296  return false;
297  }
298 
299  const bool err_enabled = omerr().is_enabled();
300  size_t complex_faces = 0;
301  if (err_enabled)
302  omerr().disable();
303 
304  for (std::vector<ElementInfo>::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it)
305  {
306  if (_in.eof()) {
307  if (err_enabled)
308  omerr().enable();
309 
310  omerr() << "Unexpected end of file while reading." << std::endl;
311  return false;
312  }
313 
314  if (e_it->element_== VERTEX)
315  {
316  // read vertices:
317  for (i = 0; i < e_it->count_ && !_in.eof(); ++i) {
318  vh = _bi.add_vertex();
319 
320  v[0] = 0.0;
321  v[1] = 0.0;
322  v[2] = 0.0;
323 
324  n[0] = 0.0;
325  n[1] = 0.0;
326  n[2] = 0.0;
327 
328  t[0] = 0.0;
329  t[1] = 0.0;
330 
331  c[0] = 0;
332  c[1] = 0;
333  c[2] = 0;
334  c[3] = 255;
335 
336  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) {
337  PropertyInfo prop = e_it->properties_[propertyIndex];
338  switch (prop.property) {
339  case XCOORD:
340  _in >> v[0];
341  break;
342  case YCOORD:
343  _in >> v[1];
344  break;
345  case ZCOORD:
346  _in >> v[2];
347  break;
348  case XNORM:
349  _in >> n[0];
350  break;
351  case YNORM:
352  _in >> n[1];
353  break;
354  case ZNORM:
355  _in >> n[2];
356  break;
357  case TEXX:
358  _in >> t[0];
359  break;
360  case TEXY:
361  _in >> t[1];
362  break;
363  case COLORRED:
364  if (prop.value == ValueTypeFLOAT32 ||
365  prop.value == ValueTypeFLOAT) {
366  _in >> tmp;
367  c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
368  }
369  else
370  _in >> c[0];
371  break;
372  case COLORGREEN:
373  if (prop.value == ValueTypeFLOAT32 ||
374  prop.value == ValueTypeFLOAT) {
375  _in >> tmp;
376  c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
377  }
378  else
379  _in >> c[1];
380  break;
381  case COLORBLUE:
382  if (prop.value == ValueTypeFLOAT32 ||
383  prop.value == ValueTypeFLOAT) {
384  _in >> tmp;
385  c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
386  }
387  else
388  _in >> c[2];
389  break;
390  case COLORALPHA:
391  if (prop.value == ValueTypeFLOAT32 ||
392  prop.value == ValueTypeFLOAT) {
393  _in >> tmp;
394  c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
395  }
396  else
397  _in >> c[3];
398  break;
399  case CUSTOM_PROP:
400  if (_opt.check(Options::Custom))
401  readCustomProperty<false>(_in, _bi, vh, prop.name, prop.value, prop.listIndexType);
402  else
403  _in >> trash;
404  break;
405  default:
406  _in >> trash;
407  break;
408  }
409  }
410 
411  _bi.set_point(vh, v);
412  if (_opt.vertex_has_normal())
413  _bi.set_normal(vh, n);
414  if (_opt.vertex_has_texcoord())
415  _bi.set_texcoord(vh, t);
416  if (_opt.vertex_has_color())
417  _bi.set_color(vh, Vec4uc(c));
418  }
419  }
420  else if (e_it->element_ == FACE)
421  {
422  // faces
423  for (i = 0; i < faceCount_ && !_in.eof(); ++i) {
424  FaceHandle fh;
425 
426  c[0] = 0;
427  c[1] = 0;
428  c[2] = 0;
429  c[3] = 255;
430 
431  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) {
432  PropertyInfo prop = e_it->properties_[propertyIndex];
433  switch (prop.property) {
434 
435  case VERTEX_INDICES:
436  // nV = number of Vertices for current face
437  _in >> nV;
438 
439  if (nV == 3) {
440  vhandles.resize(3);
441  _in >> j;
442  _in >> k;
443  _in >> l;
444 
445  vhandles[0] = VertexHandle(j);
446  vhandles[1] = VertexHandle(k);
447  vhandles[2] = VertexHandle(l);
448  }
449  else {
450  vhandles.clear();
451  for (j = 0; j < nV; ++j) {
452  _in >> idx;
453  vhandles.push_back(VertexHandle(idx));
454  }
455  }
456 
457  fh = _bi.add_face(vhandles);
458  if (!fh.is_valid())
459  ++complex_faces;
460  break;
461 
462  case COLORRED:
463  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
464  _in >> tmp;
465  c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
466  } else
467  _in >> c[0];
468  break;
469 
470  case COLORGREEN:
471  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
472  _in >> tmp;
473  c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
474  } else
475  _in >> c[1];
476  break;
477 
478  case COLORBLUE:
479  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
480  _in >> tmp;
481  c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
482  } else
483  _in >> c[2];
484  break;
485 
486  case COLORALPHA:
487  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
488  _in >> tmp;
489  c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
490  } else
491  _in >> c[3];
492  break;
493 
494  case CUSTOM_PROP:
495  if (_opt.check(Options::Custom) && fh.is_valid())
496  readCustomProperty<false>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
497  else
498  _in >> trash;
499  break;
500 
501  default:
502  _in >> trash;
503  break;
504  }
505  }
506  if (_opt.face_has_color())
507  _bi.set_color(fh, Vec4uc(c));
508  }
509  }
510  else
511  {
512  // other elements
513  for (i = 0; i < e_it->count_ && !_in.eof(); ++i) {
514  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex)
515  {
516  // just skip the values
517  _in >> trash;
518  }
519  }
520  }
521 
522  if(e_it->element_== FACE)
523  // stop reading after the faces since additional elements are not preserved anyway
524  break;
525  }
526 
527  if (err_enabled)
528  omerr().enable();
529 
530  if (complex_faces)
531  omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n";
532 
533  // File was successfully parsed.
534  return true;
535 }
536 
537 //-----------------------------------------------------------------------------
538 
539 bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/, const Options& _opt) const {
540 
541  OpenMesh::Vec3f v, n; // Vertex
542  OpenMesh::Vec2f t; // TexCoords
543  BaseImporter::VHandles vhandles;
544  VertexHandle vh;
545  OpenMesh::Vec4i c; // Color
546  float tmp;
547 
548  _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_);
549 
550  const bool err_enabled = omerr().is_enabled();
551  size_t complex_faces = 0;
552  if (err_enabled)
553  omerr().disable();
554 
555  for (std::vector<ElementInfo>::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it)
556  {
557  if (e_it->element_ == VERTEX)
558  {
559  // read vertices:
560  for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) {
561  vh = _bi.add_vertex();
562 
563  v[0] = 0.0;
564  v[1] = 0.0;
565  v[2] = 0.0;
566 
567  n[0] = 0.0;
568  n[1] = 0.0;
569  n[2] = 0.0;
570 
571  t[0] = 0.0;
572  t[1] = 0.0;
573 
574  c[0] = 0;
575  c[1] = 0;
576  c[2] = 0;
577  c[3] = 255;
578 
579  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) {
580  PropertyInfo prop = e_it->properties_[propertyIndex];
581  switch (prop.property) {
582  case XCOORD:
583  readValue(prop.value, _in, v[0]);
584  break;
585  case YCOORD:
586  readValue(prop.value, _in, v[1]);
587  break;
588  case ZCOORD:
589  readValue(prop.value, _in, v[2]);
590  break;
591  case XNORM:
592  readValue(prop.value, _in, n[0]);
593  break;
594  case YNORM:
595  readValue(prop.value, _in, n[1]);
596  break;
597  case ZNORM:
598  readValue(prop.value, _in, n[2]);
599  break;
600  case TEXX:
601  readValue(prop.value, _in, t[0]);
602  break;
603  case TEXY:
604  readValue(prop.value, _in, t[1]);
605  break;
606  case COLORRED:
607  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
608  readValue(prop.value, _in, tmp);
609 
610  c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
611  }
612  else
613  readInteger(prop.value, _in, c[0]);
614 
615  break;
616  case COLORGREEN:
617  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
618  readValue(prop.value, _in, tmp);
619  c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
620  }
621  else
622  readInteger(prop.value, _in, c[1]);
623 
624  break;
625  case COLORBLUE:
626  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
627  readValue(prop.value, _in, tmp);
628  c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
629  }
630  else
631  readInteger(prop.value, _in, c[2]);
632 
633  break;
634  case COLORALPHA:
635  if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) {
636  readValue(prop.value, _in, tmp);
637  c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
638  }
639  else
640  readInteger(prop.value, _in, c[3]);
641 
642  break;
643  case CUSTOM_PROP:
644  if (_opt.check(Options::Custom))
645  readCustomProperty<true>(_in, _bi, vh, prop.name, prop.value, prop.listIndexType);
646  else
647  consume_input(_in, scalar_size_[prop.value]);
648  break;
649  default:
650  // Read unsupported property
651  consume_input(_in, scalar_size_[prop.value]);
652  break;
653  }
654 
655  }
656 
657  _bi.set_point(vh, v);
658  if (_opt.vertex_has_normal())
659  _bi.set_normal(vh, n);
660  if (_opt.vertex_has_texcoord())
661  _bi.set_texcoord(vh, t);
662  if (_opt.vertex_has_color())
663  _bi.set_color(vh, Vec4uc(c));
664  }
665  }
666  else if (e_it->element_ == FACE) {
667  for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) {
668  FaceHandle fh;
669 
670  c[0] = 0;
671  c[1] = 0;
672  c[2] = 0;
673  c[3] = 255;
674 
675  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex)
676  {
677  PropertyInfo prop = e_it->properties_[propertyIndex];
678  switch (prop.property) {
679 
680  case VERTEX_INDICES:
681  // nV = number of Vertices for current face
682  unsigned int nV;
683  readInteger(prop.listIndexType, _in, nV);
684 
685  if (nV == 3) {
686  vhandles.resize(3);
687  unsigned int j, k, l;
688  readInteger(prop.value, _in, j);
689  readInteger(prop.value, _in, k);
690  readInteger(prop.value, _in, l);
691 
692  vhandles[0] = VertexHandle(j);
693  vhandles[1] = VertexHandle(k);
694  vhandles[2] = VertexHandle(l);
695  }
696  else {
697  vhandles.clear();
698  for (unsigned j = 0; j < nV; ++j) {
699  unsigned int idx;
700  readInteger(prop.value, _in, idx);
701  vhandles.push_back(VertexHandle(idx));
702  }
703  }
704 
705  fh = _bi.add_face(vhandles);
706  if (!fh.is_valid())
707  ++complex_faces;
708  break;
709  case COLORRED:
710  if (prop.value == ValueTypeFLOAT32 ||
711  prop.value == ValueTypeFLOAT) {
712  readValue(prop.value, _in, tmp);
713  c[0] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
714  } else
715  readInteger(prop.value, _in, c[0]);
716  break;
717  case COLORGREEN:
718  if (prop.value == ValueTypeFLOAT32 ||
719  prop.value == ValueTypeFLOAT) {
720  readValue(prop.value, _in, tmp);
721  c[1] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
722  } else
723  readInteger(prop.value, _in, c[1]);
724  break;
725  case COLORBLUE:
726  if (prop.value == ValueTypeFLOAT32 ||
727  prop.value == ValueTypeFLOAT) {
728  readValue(prop.value, _in, tmp);
729  c[2] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
730  } else
731  readInteger(prop.value, _in, c[2]);
732  break;
733  case COLORALPHA:
734  if (prop.value == ValueTypeFLOAT32 ||
735  prop.value == ValueTypeFLOAT) {
736  readValue(prop.value, _in, tmp);
737  c[3] = static_cast<OpenMesh::Vec4i::value_type> (tmp * 255.0f);
738  } else
739  readInteger(prop.value, _in, c[3]);
740  break;
741  case CUSTOM_PROP:
742  if (_opt.check(Options::Custom) && fh.is_valid())
743  readCustomProperty<true>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
744  else
745  consume_input(_in, scalar_size_[prop.value]);
746  break;
747 
748  default:
749  consume_input(_in, scalar_size_[prop.value]);
750  break;
751  }
752  }
753  if (_opt.face_has_color())
754  _bi.set_color(fh, Vec4uc(c));
755  }
756  }
757  else {
758  for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i)
759  {
760  for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex)
761  {
762  PropertyInfo prop = e_it->properties_[propertyIndex];
763  // skip element values
764  consume_input(_in, scalar_size_[prop.value]);
765  }
766  }
767  }
768 
769  if (_in.eof()) {
770  if (err_enabled)
771  omerr().enable();
772 
773  omerr() << "Unexpected end of file while reading." << std::endl;
774  return false;
775  }
776 
777  if (e_it->element_ == FACE)
778  // stop reading after the faces since additional elements are not preserved anyway
779  break;
780  }
781  if (err_enabled)
782  omerr().enable();
783 
784  if (complex_faces)
785  omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n";
786 
787 
788  return true;
789 }
790 
791 
792 //-----------------------------------------------------------------------------
793 
794 
795 void _PLYReader_::readValue(ValueType _type, std::istream& _in, float& _value) const {
796 
797  switch (_type) {
798  case ValueTypeFLOAT32:
799  case ValueTypeFLOAT:
800  float32_t tmp;
801  restore(_in, tmp, options_.check(Options::MSB));
802  _value = tmp;
803  break;
804  case ValueTypeDOUBLE:
805  case ValueTypeFLOAT64:
806  double dtmp;
807  readValue(_type, _in, dtmp);
808  _value = static_cast<float>(dtmp);
809  break;
810  default:
811  _value = 0.0;
812  std::cerr << "unsupported conversion type to float: " << _type << std::endl;
813  break;
814  }
815 }
816 
817 
818 //-----------------------------------------------------------------------------
819 
820 
821 void _PLYReader_::readValue(ValueType _type, std::istream& _in, double& _value) const {
822 
823  switch (_type) {
824 
825  case ValueTypeFLOAT64:
826 
827  case ValueTypeDOUBLE:
828 
829  float64_t tmp;
830  restore(_in, tmp, options_.check(Options::MSB));
831  _value = tmp;
832 
833  break;
834 
835  default:
836 
837  _value = 0.0;
838  std::cerr << "unsupported conversion type to double: " << _type << std::endl;
839 
840  break;
841  }
842 }
843 
844 
845 //-----------------------------------------------------------------------------
846 
847 void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned char& _value) const{
848  unsigned int tmp;
849  readValue(_type,_in,tmp);
850  _value = tmp;
851 }
852 
853 //-----------------------------------------------------------------------------
854 
855 void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned short& _value) const{
856  unsigned int tmp;
857  readValue(_type,_in,tmp);
858  _value = tmp;
859 }
860 
861 //-----------------------------------------------------------------------------
862 
863 void _PLYReader_::readValue(ValueType _type, std::istream& _in, signed char& _value) const{
864  int tmp;
865  readValue(_type,_in,tmp);
866  _value = tmp;
867 }
868 
869 //-----------------------------------------------------------------------------
870 
871 void _PLYReader_::readValue(ValueType _type, std::istream& _in, short& _value) const{
872  int tmp;
873  readValue(_type,_in,tmp);
874  _value = tmp;
875 }
876 
877 
878 //-----------------------------------------------------------------------------
879 void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned int& _value) const {
880 
881  uint32_t tmp_uint32_t;
882  uint16_t tmp_uint16_t;
883  uint8_t tmp_uchar;
884 
885  switch (_type) {
886 
887  case ValueTypeUINT:
888 
889  case ValueTypeUINT32:
890 
891  restore(_in, tmp_uint32_t, options_.check(Options::MSB));
892  _value = tmp_uint32_t;
893 
894  break;
895 
896  case ValueTypeUSHORT:
897 
898  case ValueTypeUINT16:
899 
900  restore(_in, tmp_uint16_t, options_.check(Options::MSB));
901  _value = tmp_uint16_t;
902 
903  break;
904 
905  case ValueTypeUCHAR:
906 
907  case ValueTypeUINT8:
908 
909  restore(_in, tmp_uchar, options_.check(Options::MSB));
910  _value = tmp_uchar;
911 
912  break;
913 
914  default:
915 
916  _value = 0;
917  std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl;
918 
919  break;
920  }
921 }
922 
923 
924 //-----------------------------------------------------------------------------
925 
926 
927 void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) const {
928 
929  int32_t tmp_int32_t;
930  int16_t tmp_int16_t;
931  int8_t tmp_char;
932 
933  switch (_type) {
934 
935  case ValueTypeINT:
936 
937  case ValueTypeINT32:
938 
939  restore(_in, tmp_int32_t, options_.check(Options::MSB));
940  _value = tmp_int32_t;
941 
942  break;
943 
944  case ValueTypeSHORT:
945 
946  case ValueTypeINT16:
947 
948  restore(_in, tmp_int16_t, options_.check(Options::MSB));
949  _value = tmp_int16_t;
950 
951  break;
952 
953  case ValueTypeCHAR:
954 
955  case ValueTypeINT8:
956 
957  restore(_in, tmp_char, options_.check(Options::MSB));
958  _value = tmp_char;
959 
960  break;
961 
962  default:
963 
964  _value = 0;
965  std::cerr << "unsupported conversion type to int: " << _type << std::endl;
966 
967  break;
968  }
969 }
970 
971 
972 //-----------------------------------------------------------------------------
973 
974 template<typename T>
975 void _PLYReader_::readInteger(ValueType _type, std::istream& _in, T& _value) const {
976 
977  static_assert(std::is_integral<T>::value, "Integral required.");
978 
979  int16_t tmp_int16_t;
980  uint16_t tmp_uint16_t;
981  int32_t tmp_int32_t;
982  uint32_t tmp_uint32_t;
983  int8_t tmp_char;
984  uint8_t tmp_uchar;
985 
986  switch (_type) {
987 
988  case ValueTypeINT16:
989 
990  case ValueTypeSHORT:
991  restore(_in, tmp_int16_t, options_.check(Options::MSB));
992  _value = tmp_int16_t;
993 
994  break;
995 
996  case ValueTypeUINT16:
997 
998  case ValueTypeUSHORT:
999  restore(_in, tmp_uint16_t, options_.check(Options::MSB));
1000  _value = tmp_uint16_t;
1001 
1002  break;
1003 
1004  case ValueTypeINT:
1005 
1006  case ValueTypeINT32:
1007 
1008  restore(_in, tmp_int32_t, options_.check(Options::MSB));
1009  _value = tmp_int32_t;
1010 
1011  break;
1012 
1013  case ValueTypeUINT:
1014 
1015  case ValueTypeUINT32:
1016 
1017  restore(_in, tmp_uint32_t, options_.check(Options::MSB));
1018  _value = tmp_uint32_t;
1019 
1020  break;
1021 
1022  case ValueTypeCHAR:
1023 
1024  case ValueTypeINT8:
1025 
1026  restore(_in, tmp_char, options_.check(Options::MSB));
1027  _value = tmp_char;
1028 
1029  break;
1030 
1031  case ValueTypeUCHAR:
1032 
1033  case ValueTypeUINT8:
1034 
1035  restore(_in, tmp_uchar, options_.check(Options::MSB));
1036  _value = tmp_uchar;
1037 
1038  break;
1039 
1040  default:
1041 
1042  _value = 0;
1043  std::cerr << "unsupported conversion type to integral: " << _type << std::endl;
1044 
1045  break;
1046  }
1047 }
1048 
1049 //------------------------------------------------------------------------------
1050 
1051 
1052 bool _PLYReader_::can_u_read(const std::string& _filename) const {
1053 
1054  // !!! Assuming BaseReader::can_u_parse( std::string& )
1055  // does not call BaseReader::read_magic()!!!
1056 
1057  if (BaseReader::can_u_read(_filename)) {
1058  std::ifstream ifs(_filename.c_str());
1059  if (ifs.is_open() && can_u_read(ifs)) {
1060  ifs.close();
1061  return true;
1062  }
1063  }
1064  return false;
1065 }
1066 
1067 
1068 
1069 //-----------------------------------------------------------------------------
1070 
1071 std::string get_property_name(std::string _string1, std::string _string2) {
1072 
1073  if (_string1 == "float32" || _string1 == "float64" || _string1 == "float" || _string1 == "double" ||
1074  _string1 == "int8" || _string1 == "uint8" || _string1 == "char" || _string1 == "uchar" ||
1075  _string1 == "int32" || _string1 == "uint32" || _string1 == "int" || _string1 == "uint" ||
1076  _string1 == "int16" || _string1 == "uint16" || _string1 == "short" || _string1 == "ushort")
1077  return _string2;
1078 
1079  if (_string2 == "float32" || _string2 == "float64" || _string2 == "float" || _string2 == "double" ||
1080  _string2 == "int8" || _string2 == "uint8" || _string2 == "char" || _string2 == "uchar" ||
1081  _string2 == "int32" || _string2 == "uint32" || _string2 == "int" || _string2 == "uint" ||
1082  _string2 == "int16" || _string2 == "uint16" || _string2 == "short" || _string2 == "ushort")
1083  return _string1;
1084 
1085 
1086  std::cerr << "Unsupported entry type" << std::endl;
1087  return "Unsupported";
1088 }
1089 
1090 //-----------------------------------------------------------------------------
1091 
1092 _PLYReader_::ValueType get_property_type(std::string& _string1, std::string& _string2) {
1093 
1094  if (_string1 == "float32" || _string2 == "float32")
1095 
1096  return _PLYReader_::ValueTypeFLOAT32;
1097 
1098  else if (_string1 == "float64" || _string2 == "float64")
1099 
1100  return _PLYReader_::ValueTypeFLOAT64;
1101 
1102  else if (_string1 == "float" || _string2 == "float")
1103 
1104  return _PLYReader_::ValueTypeFLOAT;
1105 
1106  else if (_string1 == "double" || _string2 == "double")
1107 
1108  return _PLYReader_::ValueTypeDOUBLE;
1109 
1110  else if (_string1 == "int8" || _string2 == "int8")
1111 
1112  return _PLYReader_::ValueTypeINT8;
1113 
1114  else if (_string1 == "uint8" || _string2 == "uint8")
1115 
1116  return _PLYReader_::ValueTypeUINT8;
1117 
1118  else if (_string1 == "char" || _string2 == "char")
1119 
1120  return _PLYReader_::ValueTypeCHAR;
1121 
1122  else if (_string1 == "uchar" || _string2 == "uchar")
1123 
1124  return _PLYReader_::ValueTypeUCHAR;
1125 
1126  else if (_string1 == "int32" || _string2 == "int32")
1127 
1128  return _PLYReader_::ValueTypeINT32;
1129 
1130  else if (_string1 == "uint32" || _string2 == "uint32")
1131 
1132  return _PLYReader_::ValueTypeUINT32;
1133 
1134  else if (_string1 == "int" || _string2 == "int")
1135 
1136  return _PLYReader_::ValueTypeINT;
1137 
1138  else if (_string1 == "uint" || _string2 == "uint")
1139 
1140  return _PLYReader_::ValueTypeUINT;
1141 
1142  else if (_string1 == "int16" || _string2 == "int16")
1143 
1144  return _PLYReader_::ValueTypeINT16;
1145 
1146  else if (_string1 == "uint16" || _string2 == "uint16")
1147 
1148  return _PLYReader_::ValueTypeUINT16;
1149 
1150  else if (_string1 == "short" || _string2 == "short")
1151 
1152  return _PLYReader_::ValueTypeSHORT;
1153 
1154  else if (_string1 == "ushort" || _string2 == "ushort")
1155 
1156  return _PLYReader_::ValueTypeUSHORT;
1157 
1158  return _PLYReader_::Unsupported;
1159 }
1160 
1161 
1162 //-----------------------------------------------------------------------------
1163 
1164 bool _PLYReader_::can_u_read(std::istream& _is) const {
1165 
1166  // Clear per file options
1167  options_.cleanup();
1168 
1169  // clear element list
1170  elements_.clear();
1171 
1172  // read 1st line
1173  std::string line;
1174  std::getline(_is, line);
1175  trim(line);
1176 
1177  // Handle '\r\n' newlines
1178  const size_t s = line.size();
1179  if( s > 0 && line[s - 1] == '\r') line.resize(s - 1);
1180 
1181  //Check if this file is really a ply format
1182  if (line != "PLY" && line != "ply")
1183  return false;
1184 
1185  vertexCount_ = 0;
1186  faceCount_ = 0;
1187  vertexDimension_ = 0;
1188 
1189  unsigned int elementCount = 0;
1190 
1191  std::string keyword;
1192  std::string fileType;
1193  std::string elementName = "";
1194  std::string propertyName;
1195  std::string listIndexType;
1196  std::string listEntryType;
1197  float version;
1198 
1199  _is >> keyword;
1200  _is >> fileType;
1201  _is >> version;
1202 
1203  if (_is.bad()) {
1204  omerr() << "Defect PLY header detected" << std::endl;
1205  return false;
1206  }
1207 
1208  if (fileType == "ascii") {
1210  } else if (fileType == "binary_little_endian") {
1213  //if (Endian::local() == Endian::MSB)
1214 
1215  // options_ += Options::Swap;
1216  } else if (fileType == "binary_big_endian") {
1219  //if (Endian::local() == Endian::LSB)
1220 
1221  // options_ += Options::Swap;
1222  } else {
1223  omerr() << "Unsupported PLY format: " << fileType << std::endl;
1224  return false;
1225  }
1226 
1227  std::streamoff streamPos = _is.tellg();
1228  _is >> keyword;
1229  while (keyword != "end_header") {
1230 
1231  if (keyword == "comment") {
1232  std::getline(_is, line);
1233  } else if (keyword == "element") {
1234  _is >> elementName;
1235  _is >> elementCount;
1236 
1237  ElementInfo element;
1238  element.name_ = elementName;
1239  element.count_ = elementCount;
1240 
1241  if (elementName == "vertex") {
1242  vertexCount_ = elementCount;
1243  element.element_ = VERTEX;
1244  } else if (elementName == "face") {
1245  faceCount_ = elementCount;
1246  element.element_ = FACE;
1247  } else {
1248  omerr() << "PLY header unsupported element type: " << elementName << std::endl;
1249  element.element_ = UNKNOWN;
1250  }
1251 
1252  elements_.push_back(element);
1253  } else if (keyword == "property") {
1254  std::string tmp1;
1255  std::string tmp2;
1256 
1257  // Read first keyword, as it might be a list
1258  _is >> tmp1;
1259 
1260  if (tmp1 == "list") {
1261  _is >> listIndexType;
1262  _is >> listEntryType;
1263  _is >> propertyName;
1264 
1265  ValueType indexType = Unsupported;
1266  ValueType entryType = Unsupported;
1267 
1268  if (listIndexType == "uint8") {
1269  indexType = ValueTypeUINT8;
1270  } else if (listIndexType == "uint16") {
1271  indexType = ValueTypeUINT16;
1272  } else if (listIndexType == "uchar") {
1273  indexType = ValueTypeUCHAR;
1274  } else if (listIndexType == "int") {
1275  indexType = ValueTypeINT;
1276  } else {
1277  omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
1278  return false;
1279  }
1280 
1281  entryType = get_property_type(listEntryType, listEntryType);
1282 
1283  if (entryType == Unsupported) {
1284  omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl;
1285  }
1286 
1287  PropertyInfo property(CUSTOM_PROP, entryType, propertyName);
1288  property.listIndexType = indexType;
1289 
1290  if (elementName == "face")
1291  {
1292  // special case for vertex indices
1293  if (propertyName == "vertex_index" || propertyName == "vertex_indices")
1294  {
1295  property.property = VERTEX_INDICES;
1296 
1297  if (!elements_.back().properties_.empty())
1298  {
1299  omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl;
1300  elements_.back().properties_.clear();
1301  }
1302  } else {
1304  }
1305 
1306  }
1307  else
1308  omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl;
1309 
1310  elements_.back().properties_.push_back(property);
1311 
1312  } else {
1313  // as this is not a list property, read second value of property
1314  _is >> tmp2;
1315 
1316 
1317  // Extract name and type of property
1318  // As the order seems to be different in some files, autodetect it.
1319  ValueType valueType = get_property_type(tmp1, tmp2);
1320  propertyName = get_property_name(tmp1, tmp2);
1321 
1322  PropertyInfo entry;
1323 
1324  //special treatment for some vertex properties.
1325  if (elementName == "vertex") {
1326  if (propertyName == "x") {
1327  entry = PropertyInfo(XCOORD, valueType);
1328  vertexDimension_++;
1329  } else if (propertyName == "y") {
1330  entry = PropertyInfo(YCOORD, valueType);
1331  vertexDimension_++;
1332  } else if (propertyName == "z") {
1333  entry = PropertyInfo(ZCOORD, valueType);
1334  vertexDimension_++;
1335  } else if (propertyName == "nx") {
1336  entry = PropertyInfo(XNORM, valueType);
1338  } else if (propertyName == "ny") {
1339  entry = PropertyInfo(YNORM, valueType);
1341  } else if (propertyName == "nz") {
1342  entry = PropertyInfo(ZNORM, valueType);
1344  } else if (propertyName == "u" || propertyName == "s") {
1345  entry = PropertyInfo(TEXX, valueType);
1347  } else if (propertyName == "v" || propertyName == "t") {
1348  entry = PropertyInfo(TEXY, valueType);
1350  } else if (propertyName == "red") {
1351  entry = PropertyInfo(COLORRED, valueType);
1353  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1355  } else if (propertyName == "green") {
1356  entry = PropertyInfo(COLORGREEN, valueType);
1358  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1360  } else if (propertyName == "blue") {
1361  entry = PropertyInfo(COLORBLUE, valueType);
1363  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1365  } else if (propertyName == "diffuse_red") {
1366  entry = PropertyInfo(COLORRED, valueType);
1368  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1370  } else if (propertyName == "diffuse_green") {
1371  entry = PropertyInfo(COLORGREEN, valueType);
1373  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1375  } else if (propertyName == "diffuse_blue") {
1376  entry = PropertyInfo(COLORBLUE, valueType);
1378  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1380  } else if (propertyName == "alpha") {
1381  entry = PropertyInfo(COLORALPHA, valueType);
1384  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1386  }
1387  }
1388  else if (elementName == "face") {
1389  if (propertyName == "red") {
1390  entry = PropertyInfo(COLORRED, valueType);
1392  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1394  } else if (propertyName == "green") {
1395  entry = PropertyInfo(COLORGREEN, valueType);
1397  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1399  } else if (propertyName == "blue") {
1400  entry = PropertyInfo(COLORBLUE, valueType);
1402  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1404  } else if (propertyName == "alpha") {
1405  entry = PropertyInfo(COLORALPHA, valueType);
1408  if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1410  }
1411  }
1412 
1413  //not a special property, load as custom
1414  if (entry.value == Unsupported){
1415  Property prop = CUSTOM_PROP;
1417  entry = PropertyInfo(prop, valueType, propertyName);
1418  }
1419 
1420  if (entry.property != UNSUPPORTED)
1421  {
1422  elements_.back().properties_.push_back(entry);
1423  }
1424  }
1425 
1426  } else {
1427  omlog() << "Unsupported keyword : " << keyword << std::endl;
1428  }
1429 
1430  streamPos = _is.tellg();
1431  _is >> keyword;
1432  if (_is.bad()) {
1433  omerr() << "Error while reading PLY file header" << std::endl;
1434  return false;
1435  }
1436  }
1437 
1438  // As the binary data is directy after the end_header keyword
1439  // and the stream removes too many bytes, seek back to the right position
1440  if (options_.is_binary()) {
1441  _is.seekg(streamPos);
1442 
1443  char c1 = 0;
1444  char c2 = 0;
1445  _is.get(c1);
1446  _is.get(c2);
1447 
1448  if (c1 == 0x0D && c2 == 0x0A) {
1449  _is.seekg(streamPos + 14);
1450  }
1451  else {
1452  _is.seekg(streamPos + 12);
1453  }
1454  }
1455 
1456  return true;
1457 }
1458 
1459 //=============================================================================
1460 } // namespace IO
1461 } // namespace OpenMesh
1462 //=============================================================================
Swap byte order in binary mode.
Definition: Options.hh:103
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:77
Handle for a face entity.
Definition: Handles.hh:141
signed char int8_t
Definition: SR_types.hh:80
Assume big endian byte ordering.
Definition: Options.hh:101
short int16_t
Definition: SR_types.hh:81
Has (r) / store (w) vertex colors.
Definition: Options.hh:105
void clear(void)
Clear all bits.
Definition: Options.hh:147
Has (r) / store (w) face colors.
Definition: Options.hh:109
Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) ...
Definition: Options.hh:112
float float32_t
Definition: SR_types.hh:92
double float64_t
Definition: SR_types.hh:93
Handle for a vertex entity.
Definition: Handles.hh:120
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt) override
Definition: PLYReader.cc:106
bool get_property_handle(VPropHandleT< T > &_ph, const std::string &_name) const
Definition: BaseKernel.hh:254
bool is_valid() const
The handle is valid iff the index is not negative.
Definition: Handles.hh:72
Options userOptions_
Options that the user wants to read.
Definition: PLYReader.hh:156
Has (r) / store (w) alpha values for colors.
Definition: Options.hh:111
bool can_u_read(const std::string &_filename) const override
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
Definition: PLYReader.cc:1052
bool register_module(BaseReader *_bl)
Definition: IOManager.hh:217
Has (r) custom properties (currently only implemented in PLY Reader ASCII version) ...
Definition: Options.hh:113
unsigned short uint16_t
Definition: SR_types.hh:81
Cellection of information about a property.
Definition: Utils.hh:109
void consume_input(std::istream &_in, int _count) const
Read unsupported properties in PLY file.
Definition: PLYReader.hh:146
unsigned char uint8_t
Definition: SR_types.hh:80
void cleanup(void)
Restore state after default constructor.
Definition: Options.hh:143
unsigned int uint32_t
Definition: SR_types.hh:85
Set options for reader/writer modules.
Definition: Options.hh:90
PropertyT< T > & property(VPropHandleT< T > _ph)
Definition: BaseKernel.hh:310
Has (r) / store (w) vertex normals.
Definition: Options.hh:104
_IOManager_ & IOManager()
Definition: IOManager.cc:72
Options options_
Available per file options for reading.
Definition: PLYReader.hh:153
_PLYReader_ __PLYReaderInstance
Declare the single entity of the PLY reader.
Definition: PLYReader.cc:72
Set binary mode for r/w.
Definition: Options.hh:100
Assume little endian byte ordering.
Definition: Options.hh:102
void add_property(VPropHandleT< T > &_ph, const std::string &_name="<vprop>")
Definition: BaseKernel.hh:141
Has (r) / store (w) texture coordinates.
Definition: Options.hh:106
std::map< ValueType, int > scalar_size_
Stores sizes of property types.
Definition: PLYReader.hh:172