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