From bb2f923f33dfb42efba7f6a60122f5b459933052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:13:16 +0200 Subject: [PATCH 1/9] PLY-remove-unused-readToFloatValue-member --- src/OpenMesh/Core/IO/reader/PLYReader.hh | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.hh b/src/OpenMesh/Core/IO/reader/PLYReader.hh index b1304c0c..95f90ca7 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.hh +++ b/src/OpenMesh/Core/IO/reader/PLYReader.hh @@ -130,8 +130,6 @@ private: bool read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const; bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const; - float readToFloatValue(ValueType _type , std::fstream& _in) const; - void readValue(ValueType _type , std::istream& _in, float& _value) const; void readValue(ValueType _type , std::istream& _in, double& _value) const; void readValue(ValueType _type , std::istream& _in, unsigned int& _value) const; From b15e09d1d34f455b50685c6372f9754236562228 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:14:32 +0200 Subject: [PATCH 2/9] PLY-avoid-temporary-variable-and-push_back --- src/OpenMesh/Core/IO/reader/PLYReader.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc b/src/OpenMesh/Core/IO/reader/PLYReader.cc index 03089195..62ea180b 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc @@ -221,14 +221,11 @@ void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, //init vector int numberOfValues; read(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); - std::vector vec; - vec.reserve(numberOfValues); + std::vector vec(numberOfValues); //read and assign for (int i = 0; i < numberOfValues; ++i) { - T in; - read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); - vec.push_back(in); + read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type()); } _bi.kernel()->property(prop,_h) = vec; } From d91986fc30375cd13119b3c308829978da9a6dd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:15:16 +0200 Subject: [PATCH 3/9] PLY: add support for unsigned custom property length --- src/OpenMesh/Core/IO/reader/PLYReader.cc | 6 +++--- src/OpenMesh/Core/IO/reader/PLYReader.hh | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc b/src/OpenMesh/Core/IO/reader/PLYReader.cc index 62ea180b..b14bfdf7 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc @@ -219,11 +219,11 @@ void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, } //init vector - int numberOfValues; - read(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); + unsigned int numberOfValues; + readInteger(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); std::vector vec(numberOfValues); //read and assign - for (int i = 0; i < numberOfValues; ++i) + for (unsigned int i = 0; i < numberOfValues; ++i) { read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type()); } diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.hh b/src/OpenMesh/Core/IO/reader/PLYReader.hh index 95f90ca7..3f855ac4 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.hh +++ b/src/OpenMesh/Core/IO/reader/PLYReader.hh @@ -212,6 +212,18 @@ private: _in >> _value; } + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const + { + readInteger(_type, _in, _value); + } + + template + inline void readInteger(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const + { + _in >> _value; + } + //read and assign custom properties with the given type. Also creates property, if not exist template void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const; From d28df7edcb749e7408f58cfd5626aec579e643ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:18:41 +0200 Subject: [PATCH 4/9] PLY: convert readInteger into a template --- src/OpenMesh/Core/IO/reader/PLYReader.cc | 65 +- src/OpenMesh/Core/IO/reader/PLYReader.cc.orig | 1501 +++++++++++++++++ src/OpenMesh/Core/IO/reader/PLYReader.hh | 6 +- 3 files changed, 1508 insertions(+), 64 deletions(-) create mode 100644 src/OpenMesh/Core/IO/reader/PLYReader.cc.orig diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc b/src/OpenMesh/Core/IO/reader/PLYReader.cc index b14bfdf7..d1e6898b 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc @@ -971,8 +971,10 @@ void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) con //----------------------------------------------------------------------------- +template +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, T& _value) const { -void _PLYReader_::readInteger(ValueType _type, std::istream& _in, int& _value) const { + static_assert(std::is_integral::value, "Integral required."); int32_t tmp_int32_t; uint32_t tmp_uint32_t; @@ -1020,71 +1022,12 @@ void _PLYReader_::readInteger(ValueType _type, std::istream& _in, int& _value) c default: _value = 0; - std::cerr << "unsupported conversion type to int: " << _type << std::endl; + std::cerr << "unsupported conversion type to integral: " << _type << std::endl; break; } } - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const { - - int32_t tmp_int32_t; - uint32_t tmp_uint32_t; - int8_t tmp_char; - uint8_t tmp_uchar; - - switch (_type) { - - case ValueTypeUINT: - - case ValueTypeUINT32: - - restore(_in, tmp_uint32_t, options_.check(Options::MSB)); - _value = tmp_uint32_t; - - break; - - case ValueTypeINT: - - case ValueTypeINT32: - - restore(_in, tmp_int32_t, options_.check(Options::MSB)); - _value = tmp_int32_t; - - break; - - case ValueTypeUCHAR: - - case ValueTypeUINT8: - - restore(_in, tmp_uchar, options_.check(Options::MSB)); - _value = tmp_uchar; - - break; - - case ValueTypeCHAR: - - case ValueTypeINT8: - - restore(_in, tmp_char, options_.check(Options::MSB)); - _value = tmp_char; - - break; - - default: - - _value = 0; - std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; - - break; - } -} - - //------------------------------------------------------------------------------ diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig b/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig new file mode 100644 index 00000000..b14bfdf7 --- /dev/null +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig @@ -0,0 +1,1501 @@ +/* ========================================================================= * + * * + * OpenMesh * + * Copyright (c) 2001-2015, RWTH-Aachen University * + * Department of Computer Graphics and Multimedia * + * All rights reserved. * + * www.openmesh.org * + * * + *---------------------------------------------------------------------------* + * This file is part of OpenMesh. * + *---------------------------------------------------------------------------* + * * + * Redistribution and use in source and binary forms, with or without * + * modification, are permitted provided that the following conditions * + * are met: * + * * + * 1. Redistributions of source code must retain the above copyright notice, * + * this list of conditions and the following disclaimer. * + * * + * 2. Redistributions in binary form must reproduce the above copyright * + * notice, this list of conditions and the following disclaimer in the * + * documentation and/or other materials provided with the distribution. * + * * + * 3. Neither the name of the copyright holder nor the names of its * + * contributors may be used to endorse or promote products derived from * + * this software without specific prior written permission. * + * * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * + * * + * ========================================================================= */ + +#define LINE_LEN 4096 + +//== INCLUDES ================================================================= + +// OpenMesh +#include +#include +#include +#include +#include + +//STL +#include +#include +#include + +#ifndef WIN32 +#endif + +//=== NAMESPACES ============================================================== + + +namespace OpenMesh { +namespace IO { + +//============================================================================= + +//=== INSTANCIATE ============================================================= + + +_PLYReader_ __PLYReaderInstance; +_PLYReader_& PLYReader() { + return __PLYReaderInstance; +} + +//=== IMPLEMENTATION ========================================================== + + +_PLYReader_::_PLYReader_() { + IOManager().register_module(this); + + // Store sizes in byte of each property type + scalar_size_[ValueTypeINT8] = 1; + scalar_size_[ValueTypeUINT8] = 1; + scalar_size_[ValueTypeINT16] = 2; + scalar_size_[ValueTypeUINT16] = 2; + scalar_size_[ValueTypeINT32] = 4; + scalar_size_[ValueTypeUINT32] = 4; + scalar_size_[ValueTypeFLOAT32] = 4; + scalar_size_[ValueTypeFLOAT64] = 8; + + scalar_size_[ValueTypeCHAR] = 1; + scalar_size_[ValueTypeUCHAR] = 1; + scalar_size_[ValueTypeSHORT] = 2; + scalar_size_[ValueTypeUSHORT] = 2; + scalar_size_[ValueTypeINT] = 4; + scalar_size_[ValueTypeUINT] = 4; + scalar_size_[ValueTypeFLOAT] = 4; + scalar_size_[ValueTypeDOUBLE] = 8; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { + + std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) ); + + if (!in.is_open() || !in.good()) { + omerr() << "[PLYReader] : cannot not open file " << _filename << std::endl; + return false; + } + + bool result = read(in, _bi, _opt); + + in.close(); + return result; +} + +//----------------------------------------------------------------------------- + + +bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) { + + if (!_in.good()) { + omerr() << "[PLYReader] : cannot not use stream" << std::endl; + return false; + } + + // Reparse the header + if (!can_u_read(_in)) { + omerr() << "[PLYReader] : Unable to parse header\n"; + return false; + } + + + + // filter relevant options for reading + bool swap = _opt.check(Options::Swap); + + userOptions_ = _opt; + + // build options to be returned + _opt.clear(); + + if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) { + _opt += Options::VertexNormal; + } + if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) { + _opt += Options::VertexTexCoord; + } + if (options_.vertex_has_color() && userOptions_.vertex_has_color()) { + _opt += Options::VertexColor; + } + if (options_.face_has_color() && userOptions_.face_has_color()) { + _opt += Options::FaceColor; + } + if (options_.is_binary()) { + _opt += Options::Binary; + } + if (options_.color_is_float()) { + _opt += Options::ColorFloat; + } + if (options_.check(Options::Custom) && userOptions_.check(Options::Custom)) { + _opt += Options::Custom; + } + + // //force user-choice for the alpha value when reading binary + // if ( options_.is_binary() && userOptions_.color_has_alpha() ) + // options_ += Options::ColorAlpha; + + return (options_.is_binary() ? read_binary(_in, _bi, swap, _opt) : read_ascii(_in, _bi, _opt)); + +} + +template +struct Handle2Prop; + +template +struct Handle2Prop +{ + typedef OpenMesh::VPropHandleT PropT; +}; + +template +struct Handle2Prop +{ + typedef OpenMesh::FPropHandleT PropT; +}; + +//read and assign custom properties with the given type. Also creates property, if not exist +template +void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listType) const +{ + if (_listType == Unsupported) //no list type defined -> property is not a list + { + //get/add property + typename Handle2Prop::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //read and assign + T in; + read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); + _bi.kernel()->property(prop,_h) = in; + } + else + { + //get/add property + typename Handle2Prop,Handle>::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + { + _bi.kernel()->add_property(prop,_propName); + _bi.kernel()->property(prop).set_persistent(true); + } + + //init vector + unsigned int numberOfValues; + readInteger(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); + std::vector vec(numberOfValues); + //read and assign + for (unsigned int i = 0; i < numberOfValues; ++i) + { + read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type()); + } + _bi.kernel()->property(prop,_h) = vec; + } +} + +template +void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const +{ + switch (_valueType) + { + case ValueTypeINT8: + case ValueTypeCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT8: + case ValueTypeUCHAR: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT16: + case ValueTypeSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT16: + case ValueTypeUSHORT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeINT32: + case ValueTypeINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeUINT32: + case ValueTypeUINT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + case ValueTypeFLOAT64: + case ValueTypeDOUBLE: + readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); + break; + default: + std::cerr << "unsupported type" << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const { + + unsigned int i, j, k, l, idx; + unsigned int nV; + OpenMesh::Vec3f v, n; + std::string trash; + OpenMesh::Vec2f t; + OpenMesh::Vec4i c; + float tmp; + BaseImporter::VHandles vhandles; + VertexHandle vh; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + if (vertexDimension_ != 3) { + omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl; + return false; + } + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if (e_it->element_== VERTEX) + { + // read vertices: + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + _in >> v[0]; + break; + case YCOORD: + _in >> v[1]; + break; + case ZCOORD: + _in >> v[2]; + break; + case XNORM: + _in >> n[0]; + break; + case YNORM: + _in >> n[1]; + break; + case ZNORM: + _in >> n[2]; + break; + case TEXX: + _in >> t[0]; + break; + case TEXY: + _in >> t[1]; + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[0] = static_cast (tmp * 255.0f); + } + else + _in >> c[0]; + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[1] = static_cast (tmp * 255.0f); + } + else + _in >> c[1]; + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[2] = static_cast (tmp * 255.0f); + } + else + _in >> c[2]; + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[3] = static_cast (tmp * 255.0f); + } + else + _in >> c[3]; + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + default: + _in >> trash; + break; + } + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) + { + // faces + for (i = 0; i < faceCount_ && !_in.eof(); ++i) { + FaceHandle fh; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + _in >> nV; + + if (nV == 3) { + vhandles.resize(3); + _in >> j; + _in >> k; + _in >> l; + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (j = 0; j < nV; ++j) { + _in >> idx; + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[0] = static_cast (tmp * 255.0f); + } else + _in >> c[0]; + break; + + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[1] = static_cast (tmp * 255.0f); + } else + _in >> c[1]; + break; + + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[2] = static_cast (tmp * 255.0f); + } else + _in >> c[2]; + break; + + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + _in >> tmp; + c[3] = static_cast (tmp * 255.0f); + } else + _in >> c[3]; + break; + + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + _in >> trash; + break; + + default: + _in >> trash; + break; + } + } + if (_opt.face_has_color()) + _bi.set_color(fh, Vec4uc(c)); + } + } + else + { + // other elements + for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + // just skip the values + _in >> trash; + } + } + } + + if(e_it->element_== FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + // File was successfully parsed. + return true; +} + +//----------------------------------------------------------------------------- + +bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/, const Options& _opt) const { + + OpenMesh::Vec3f v, n; // Vertex + OpenMesh::Vec2f t; // TexCoords + BaseImporter::VHandles vhandles; + VertexHandle vh; + OpenMesh::Vec4i c; // Color + float tmp; + + _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); + + const bool err_enabled = omerr().is_enabled(); + size_t complex_faces = 0; + if (err_enabled) + omerr().disable(); + + for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) + { + if (e_it->element_ == VERTEX) + { + // read vertices: + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) { + vh = _bi.add_vertex(); + + v[0] = 0.0; + v[1] = 0.0; + v[2] = 0.0; + + n[0] = 0.0; + n[1] = 0.0; + n[2] = 0.0; + + t[0] = 0.0; + t[1] = 0.0; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + case XCOORD: + readValue(prop.value, _in, v[0]); + break; + case YCOORD: + readValue(prop.value, _in, v[1]); + break; + case ZCOORD: + readValue(prop.value, _in, v[2]); + break; + case XNORM: + readValue(prop.value, _in, n[0]); + break; + case YNORM: + readValue(prop.value, _in, n[1]); + break; + case ZNORM: + readValue(prop.value, _in, n[2]); + break; + case TEXX: + readValue(prop.value, _in, t[0]); + break; + case TEXY: + readValue(prop.value, _in, t[1]); + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + + c[0] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[0]); + + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[1] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[1]); + + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[2] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[2]); + + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[3] = static_cast (tmp * 255.0f); + } + else + readInteger(prop.value, _in, c[3]); + + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom)) + readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + default: + // Read unsupported property + consume_input(_in, scalar_size_[prop.value]); + break; + } + + } + + _bi.set_point(vh, v); + if (_opt.vertex_has_normal()) + _bi.set_normal(vh, n); + if (_opt.vertex_has_texcoord()) + _bi.set_texcoord(vh, t); + if (_opt.vertex_has_color()) + _bi.set_color(vh, Vec4uc(c)); + } + } + else if (e_it->element_ == FACE) { + for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) { + FaceHandle fh; + + c[0] = 0; + c[1] = 0; + c[2] = 0; + c[3] = 255; + + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + switch (prop.property) { + + case VERTEX_INDICES: + // nV = number of Vertices for current face + unsigned int nV; + readInteger(prop.listIndexType, _in, nV); + + if (nV == 3) { + vhandles.resize(3); + unsigned int j, k, l; + readInteger(prop.value, _in, j); + readInteger(prop.value, _in, k); + readInteger(prop.value, _in, l); + + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); + } + else { + vhandles.clear(); + for (unsigned j = 0; j < nV; ++j) { + unsigned int idx; + readInteger(prop.value, _in, idx); + vhandles.push_back(VertexHandle(idx)); + } + } + + fh = _bi.add_face(vhandles); + if (!fh.is_valid()) + ++complex_faces; + break; + case COLORRED: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[0] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[0]); + break; + case COLORGREEN: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[1] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[1]); + break; + case COLORBLUE: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[2] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[2]); + break; + case COLORALPHA: + if (prop.value == ValueTypeFLOAT32 || + prop.value == ValueTypeFLOAT) { + readValue(prop.value, _in, tmp); + c[3] = static_cast (tmp * 255.0f); + } else + readInteger(prop.value, _in, c[3]); + break; + case CUSTOM_PROP: + if (_opt.check(Options::Custom) && fh.is_valid()) + readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); + else + consume_input(_in, scalar_size_[prop.value]); + break; + + default: + consume_input(_in, scalar_size_[prop.value]); + break; + } + } + if (_opt.face_has_color()) + _bi.set_color(fh, Vec4uc(c)); + } + } + else { + for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) + { + for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) + { + PropertyInfo prop = e_it->properties_[propertyIndex]; + // skip element values + consume_input(_in, scalar_size_[prop.value]); + } + } + } + + if (_in.eof()) { + if (err_enabled) + omerr().enable(); + + omerr() << "Unexpected end of file while reading." << std::endl; + return false; + } + + if (e_it->element_ == FACE) + // stop reading after the faces since additional elements are not preserved anyway + break; + } + if (err_enabled) + omerr().enable(); + + if (complex_faces) + omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; + + + return true; +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, float& _value) const { + + switch (_type) { + case ValueTypeFLOAT32: + case ValueTypeFLOAT: + float32_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + break; + case ValueTypeDOUBLE: + case ValueTypeFLOAT64: + double dtmp; + readValue(_type, _in, dtmp); + _value = static_cast(dtmp); + break; + default: + _value = 0.0; + std::cerr << "unsupported conversion type to float: " << _type << std::endl; + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, double& _value) const { + + switch (_type) { + + case ValueTypeFLOAT64: + + case ValueTypeDOUBLE: + + float64_t tmp; + restore(_in, tmp, options_.check(Options::MSB)); + _value = tmp; + + break; + + default: + + _value = 0.0; + std::cerr << "unsupported conversion type to double: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned char& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned short& _value) const{ + unsigned int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, signed char& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + +//----------------------------------------------------------------------------- + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, short& _value) const{ + int tmp; + readValue(_type,_in,tmp); + _value = tmp; +} + + +//----------------------------------------------------------------------------- +void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned int& _value) const { + + uint32_t tmp_uint32_t; + uint16_t tmp_uint16_t; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeUSHORT: + + case ValueTypeUINT16: + + restore(_in, tmp_uint16_t, options_.check(Options::MSB)); + _value = tmp_uint16_t; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) const { + + int32_t tmp_int32_t; + int16_t tmp_int16_t; + int8_t tmp_char; + + switch (_type) { + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeSHORT: + + case ValueTypeINT16: + + restore(_in, tmp_int16_t, options_.check(Options::MSB)); + _value = tmp_int16_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, int& _value) const { + + int32_t tmp_int32_t; + uint32_t tmp_uint32_t; + int8_t tmp_char; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to int: " << _type << std::endl; + + break; + } +} + + +//----------------------------------------------------------------------------- + + +void _PLYReader_::readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const { + + int32_t tmp_int32_t; + uint32_t tmp_uint32_t; + int8_t tmp_char; + uint8_t tmp_uchar; + + switch (_type) { + + case ValueTypeUINT: + + case ValueTypeUINT32: + + restore(_in, tmp_uint32_t, options_.check(Options::MSB)); + _value = tmp_uint32_t; + + break; + + case ValueTypeINT: + + case ValueTypeINT32: + + restore(_in, tmp_int32_t, options_.check(Options::MSB)); + _value = tmp_int32_t; + + break; + + case ValueTypeUCHAR: + + case ValueTypeUINT8: + + restore(_in, tmp_uchar, options_.check(Options::MSB)); + _value = tmp_uchar; + + break; + + case ValueTypeCHAR: + + case ValueTypeINT8: + + restore(_in, tmp_char, options_.check(Options::MSB)); + _value = tmp_char; + + break; + + default: + + _value = 0; + std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; + + break; + } +} + + +//------------------------------------------------------------------------------ + + +bool _PLYReader_::can_u_read(const std::string& _filename) const { + + // !!! Assuming BaseReader::can_u_parse( std::string& ) + // does not call BaseReader::read_magic()!!! + + if (BaseReader::can_u_read(_filename)) { + std::ifstream ifs(_filename.c_str()); + if (ifs.is_open() && can_u_read(ifs)) { + ifs.close(); + return true; + } + } + return false; +} + + + +//----------------------------------------------------------------------------- + +std::string get_property_name(std::string _string1, std::string _string2) { + + if (_string1 == "float32" || _string1 == "float64" || _string1 == "float" || _string1 == "double" || + _string1 == "int8" || _string1 == "uint8" || _string1 == "char" || _string1 == "uchar" || + _string1 == "int32" || _string1 == "uint32" || _string1 == "int" || _string1 == "uint" || + _string1 == "int16" || _string1 == "uint16" || _string1 == "short" || _string1 == "ushort") + return _string2; + + if (_string2 == "float32" || _string2 == "float64" || _string2 == "float" || _string2 == "double" || + _string2 == "int8" || _string2 == "uint8" || _string2 == "char" || _string2 == "uchar" || + _string2 == "int32" || _string2 == "uint32" || _string2 == "int" || _string2 == "uint" || + _string2 == "int16" || _string2 == "uint16" || _string2 == "short" || _string2 == "ushort") + return _string1; + + + std::cerr << "Unsupported entry type" << std::endl; + return "Unsupported"; +} + +//----------------------------------------------------------------------------- + +_PLYReader_::ValueType get_property_type(std::string& _string1, std::string& _string2) { + + if (_string1 == "float32" || _string2 == "float32") + + return _PLYReader_::ValueTypeFLOAT32; + + else if (_string1 == "float64" || _string2 == "float64") + + return _PLYReader_::ValueTypeFLOAT64; + + else if (_string1 == "float" || _string2 == "float") + + return _PLYReader_::ValueTypeFLOAT; + + else if (_string1 == "double" || _string2 == "double") + + return _PLYReader_::ValueTypeDOUBLE; + + else if (_string1 == "int8" || _string2 == "int8") + + return _PLYReader_::ValueTypeINT8; + + else if (_string1 == "uint8" || _string2 == "uint8") + + return _PLYReader_::ValueTypeUINT8; + + else if (_string1 == "char" || _string2 == "char") + + return _PLYReader_::ValueTypeCHAR; + + else if (_string1 == "uchar" || _string2 == "uchar") + + return _PLYReader_::ValueTypeUCHAR; + + else if (_string1 == "int32" || _string2 == "int32") + + return _PLYReader_::ValueTypeINT32; + + else if (_string1 == "uint32" || _string2 == "uint32") + + return _PLYReader_::ValueTypeUINT32; + + else if (_string1 == "int" || _string2 == "int") + + return _PLYReader_::ValueTypeINT; + + else if (_string1 == "uint" || _string2 == "uint") + + return _PLYReader_::ValueTypeUINT; + + else if (_string1 == "int16" || _string2 == "int16") + + return _PLYReader_::ValueTypeINT16; + + else if (_string1 == "uint16" || _string2 == "uint16") + + return _PLYReader_::ValueTypeUINT16; + + else if (_string1 == "short" || _string2 == "short") + + return _PLYReader_::ValueTypeSHORT; + + else if (_string1 == "ushort" || _string2 == "ushort") + + return _PLYReader_::ValueTypeUSHORT; + + return _PLYReader_::Unsupported; +} + + +//----------------------------------------------------------------------------- + +bool _PLYReader_::can_u_read(std::istream& _is) const { + + // Clear per file options + options_.cleanup(); + + // clear element list + elements_.clear(); + + // read 1st line + std::string line; + std::getline(_is, line); + trim(line); + + // Handle '\r\n' newlines + const size_t s = line.size(); + if( s > 0 && line[s - 1] == '\r') line.resize(s - 1); + + //Check if this file is really a ply format + if (line != "PLY" && line != "ply") + return false; + + vertexCount_ = 0; + faceCount_ = 0; + vertexDimension_ = 0; + + unsigned int elementCount = 0; + + std::string keyword; + std::string fileType; + std::string elementName = ""; + std::string propertyName; + std::string listIndexType; + std::string listEntryType; + float version; + + _is >> keyword; + _is >> fileType; + _is >> version; + + if (_is.bad()) { + omerr() << "Defect PLY header detected" << std::endl; + return false; + } + + if (fileType == "ascii") { + options_ -= Options::Binary; + } else if (fileType == "binary_little_endian") { + options_ += Options::Binary; + options_ += Options::LSB; + //if (Endian::local() == Endian::MSB) + + // options_ += Options::Swap; + } else if (fileType == "binary_big_endian") { + options_ += Options::Binary; + options_ += Options::MSB; + //if (Endian::local() == Endian::LSB) + + // options_ += Options::Swap; + } else { + omerr() << "Unsupported PLY format: " << fileType << std::endl; + return false; + } + + std::streamoff streamPos = _is.tellg(); + _is >> keyword; + while (keyword != "end_header") { + + if (keyword == "comment") { + std::getline(_is, line); + } else if (keyword == "element") { + _is >> elementName; + _is >> elementCount; + + ElementInfo element; + element.name_ = elementName; + element.count_ = elementCount; + + if (elementName == "vertex") { + vertexCount_ = elementCount; + element.element_ = VERTEX; + } else if (elementName == "face") { + faceCount_ = elementCount; + element.element_ = FACE; + } else { + omerr() << "PLY header unsupported element type: " << elementName << std::endl; + element.element_ = UNKNOWN; + } + + elements_.push_back(element); + } else if (keyword == "property") { + std::string tmp1; + std::string tmp2; + + // Read first keyword, as it might be a list + _is >> tmp1; + + if (tmp1 == "list") { + _is >> listIndexType; + _is >> listEntryType; + _is >> propertyName; + + ValueType indexType = Unsupported; + ValueType entryType = Unsupported; + + if (listIndexType == "uint8") { + indexType = ValueTypeUINT8; + } else if (listIndexType == "uint16") { + indexType = ValueTypeUINT16; + } else if (listIndexType == "uchar") { + indexType = ValueTypeUCHAR; + } else if (listIndexType == "int") { + indexType = ValueTypeINT; + } else { + omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl; + return false; + } + + entryType = get_property_type(listEntryType, listEntryType); + + if (entryType == Unsupported) { + omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl; + } + + PropertyInfo property(CUSTOM_PROP, entryType, propertyName); + property.listIndexType = indexType; + + if (elementName == "face") + { + // special case for vertex indices + if (propertyName == "vertex_index" || propertyName == "vertex_indices") + { + property.property = VERTEX_INDICES; + + if (!elements_.back().properties_.empty()) + { + omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl; + elements_.back().properties_.clear(); + } + } else { + options_ += Options::Custom; + } + + } + else + omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl; + + elements_.back().properties_.push_back(property); + + } else { + // as this is not a list property, read second value of property + _is >> tmp2; + + + // Extract name and type of property + // As the order seems to be different in some files, autodetect it. + ValueType valueType = get_property_type(tmp1, tmp2); + propertyName = get_property_name(tmp1, tmp2); + + PropertyInfo entry; + + //special treatment for some vertex properties. + if (elementName == "vertex") { + if (propertyName == "x") { + entry = PropertyInfo(XCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "y") { + entry = PropertyInfo(YCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "z") { + entry = PropertyInfo(ZCOORD, valueType); + vertexDimension_++; + } else if (propertyName == "nx") { + entry = PropertyInfo(XNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "ny") { + entry = PropertyInfo(YNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "nz") { + entry = PropertyInfo(ZNORM, valueType); + options_ += Options::VertexNormal; + } else if (propertyName == "u" || propertyName == "s") { + entry = PropertyInfo(TEXX, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "v" || propertyName == "t") { + entry = PropertyInfo(TEXY, valueType); + options_ += Options::VertexTexCoord; + } else if (propertyName == "red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "diffuse_blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::VertexColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "alpha") { + entry = PropertyInfo(COLORALPHA, valueType); + options_ += Options::VertexColor; + options_ += Options::ColorAlpha; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } + } + else if (elementName == "face") { + if (propertyName == "red") { + entry = PropertyInfo(COLORRED, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "green") { + entry = PropertyInfo(COLORGREEN, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "blue") { + entry = PropertyInfo(COLORBLUE, valueType); + options_ += Options::FaceColor; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } else if (propertyName == "alpha") { + entry = PropertyInfo(COLORALPHA, valueType); + options_ += Options::FaceColor; + options_ += Options::ColorAlpha; + if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) + options_ += Options::ColorFloat; + } + } + + //not a special property, load as custom + if (entry.value == Unsupported){ + Property prop = CUSTOM_PROP; + options_ += Options::Custom; + entry = PropertyInfo(prop, valueType, propertyName); + } + + if (entry.property != UNSUPPORTED) + { + elements_.back().properties_.push_back(entry); + } + } + + } else { + omlog() << "Unsupported keyword : " << keyword << std::endl; + } + + streamPos = _is.tellg(); + _is >> keyword; + if (_is.bad()) { + omerr() << "Error while reading PLY file header" << std::endl; + return false; + } + } + + // As the binary data is directy after the end_header keyword + // and the stream removes too many bytes, seek back to the right position + if (options_.is_binary()) { + _is.seekg(streamPos); + + char c1 = 0; + char c2 = 0; + _is.get(c1); + _is.get(c2); + + if (c1 == 0x0D && c2 == 0x0A) { + _is.seekg(streamPos + 14); + } + else { + _is.seekg(streamPos + 12); + } + } + + return true; +} + +//============================================================================= +} // namespace IO +} // namespace OpenMesh +//============================================================================= diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.hh b/src/OpenMesh/Core/IO/reader/PLYReader.hh index 3f855ac4..44ba7a06 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.hh +++ b/src/OpenMesh/Core/IO/reader/PLYReader.hh @@ -139,8 +139,8 @@ private: void readValue(ValueType _type , std::istream& _in, short& _value) const; void readValue(ValueType _type , std::istream& _in, signed char& _value) const; - void readInteger(ValueType _type, std::istream& _in, int& _value) const; - void readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const; + template + void readInteger(ValueType _type, std::istream& _in, T& _value) const; /// Read unsupported properties in PLY file void consume_input(std::istream& _in, int _count) const { @@ -223,7 +223,7 @@ private: { _in >> _value; } - + //read and assign custom properties with the given type. Also creates property, if not exist template void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const; From 70c0123bfe9d651730feca2be99f762e7da295d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:20:12 +0200 Subject: [PATCH 5/9] PLY: add short/ushort support to readInteger. --- src/OpenMesh/Core/IO/reader/PLYReader.cc | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc b/src/OpenMesh/Core/IO/reader/PLYReader.cc index d1e6898b..db431c14 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc @@ -976,6 +976,8 @@ void _PLYReader_::readInteger(ValueType _type, std::istream& _in, T& _value) con static_assert(std::is_integral::value, "Integral required."); + int16_t tmp_int16_t; + uint16_t tmp_uint16_t; int32_t tmp_int32_t; uint32_t tmp_uint32_t; int8_t tmp_char; @@ -983,6 +985,22 @@ void _PLYReader_::readInteger(ValueType _type, std::istream& _in, T& _value) con switch (_type) { + case ValueTypeINT16: + + case ValueTypeSHORT: + restore(_in, tmp_int16_t, options_.check(Options::MSB)); + _value = tmp_int16_t; + + break; + + case ValueTypeUINT16: + + case ValueTypeUSHORT: + restore(_in, tmp_uint16_t, options_.check(Options::MSB)); + _value = tmp_uint16_t; + + break; + case ValueTypeINT: case ValueTypeINT32: From 97a4683a1f484c55f9b07a166d6db9cdb343c677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:21:25 +0200 Subject: [PATCH 6/9] Updated changelog --- Doc/changelog.docu | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Doc/changelog.docu b/Doc/changelog.docu index 03d0d270..60ec3095 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -30,6 +30,8 @@ IO
  • PLY Reader: Fix reading doubles from PLY, missing cast (Thanks to Leo Walsh for the patch)
  • +
  • PLY Reader: Some cleanup (Thanks to Morgan Leborgne for the patch)
  • +
  • PLY Reader: Support for ushort (Thanks to Morgan Leborgne for the patch)
From e13452336ccb35fd714a044dc18b820011161e8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:22:46 +0200 Subject: [PATCH 7/9] Removed temp file --- src/OpenMesh/Core/IO/reader/PLYReader.cc.orig | 1501 ----------------- 1 file changed, 1501 deletions(-) delete mode 100644 src/OpenMesh/Core/IO/reader/PLYReader.cc.orig diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig b/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig deleted file mode 100644 index b14bfdf7..00000000 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc.orig +++ /dev/null @@ -1,1501 +0,0 @@ -/* ========================================================================= * - * * - * OpenMesh * - * Copyright (c) 2001-2015, RWTH-Aachen University * - * Department of Computer Graphics and Multimedia * - * All rights reserved. * - * www.openmesh.org * - * * - *---------------------------------------------------------------------------* - * This file is part of OpenMesh. * - *---------------------------------------------------------------------------* - * * - * Redistribution and use in source and binary forms, with or without * - * modification, are permitted provided that the following conditions * - * are met: * - * * - * 1. Redistributions of source code must retain the above copyright notice, * - * this list of conditions and the following disclaimer. * - * * - * 2. Redistributions in binary form must reproduce the above copyright * - * notice, this list of conditions and the following disclaimer in the * - * documentation and/or other materials provided with the distribution. * - * * - * 3. Neither the name of the copyright holder nor the names of its * - * contributors may be used to endorse or promote products derived from * - * this software without specific prior written permission. * - * * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER * - * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * * - * ========================================================================= */ - -#define LINE_LEN 4096 - -//== INCLUDES ================================================================= - -// OpenMesh -#include -#include -#include -#include -#include - -//STL -#include -#include -#include - -#ifndef WIN32 -#endif - -//=== NAMESPACES ============================================================== - - -namespace OpenMesh { -namespace IO { - -//============================================================================= - -//=== INSTANCIATE ============================================================= - - -_PLYReader_ __PLYReaderInstance; -_PLYReader_& PLYReader() { - return __PLYReaderInstance; -} - -//=== IMPLEMENTATION ========================================================== - - -_PLYReader_::_PLYReader_() { - IOManager().register_module(this); - - // Store sizes in byte of each property type - scalar_size_[ValueTypeINT8] = 1; - scalar_size_[ValueTypeUINT8] = 1; - scalar_size_[ValueTypeINT16] = 2; - scalar_size_[ValueTypeUINT16] = 2; - scalar_size_[ValueTypeINT32] = 4; - scalar_size_[ValueTypeUINT32] = 4; - scalar_size_[ValueTypeFLOAT32] = 4; - scalar_size_[ValueTypeFLOAT64] = 8; - - scalar_size_[ValueTypeCHAR] = 1; - scalar_size_[ValueTypeUCHAR] = 1; - scalar_size_[ValueTypeSHORT] = 2; - scalar_size_[ValueTypeUSHORT] = 2; - scalar_size_[ValueTypeINT] = 4; - scalar_size_[ValueTypeUINT] = 4; - scalar_size_[ValueTypeFLOAT] = 4; - scalar_size_[ValueTypeDOUBLE] = 8; -} - -//----------------------------------------------------------------------------- - - -bool _PLYReader_::read(const std::string& _filename, BaseImporter& _bi, Options& _opt) { - - std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) ); - - if (!in.is_open() || !in.good()) { - omerr() << "[PLYReader] : cannot not open file " << _filename << std::endl; - return false; - } - - bool result = read(in, _bi, _opt); - - in.close(); - return result; -} - -//----------------------------------------------------------------------------- - - -bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) { - - if (!_in.good()) { - omerr() << "[PLYReader] : cannot not use stream" << std::endl; - return false; - } - - // Reparse the header - if (!can_u_read(_in)) { - omerr() << "[PLYReader] : Unable to parse header\n"; - return false; - } - - - - // filter relevant options for reading - bool swap = _opt.check(Options::Swap); - - userOptions_ = _opt; - - // build options to be returned - _opt.clear(); - - if (options_.vertex_has_normal() && userOptions_.vertex_has_normal()) { - _opt += Options::VertexNormal; - } - if (options_.vertex_has_texcoord() && userOptions_.vertex_has_texcoord()) { - _opt += Options::VertexTexCoord; - } - if (options_.vertex_has_color() && userOptions_.vertex_has_color()) { - _opt += Options::VertexColor; - } - if (options_.face_has_color() && userOptions_.face_has_color()) { - _opt += Options::FaceColor; - } - if (options_.is_binary()) { - _opt += Options::Binary; - } - if (options_.color_is_float()) { - _opt += Options::ColorFloat; - } - if (options_.check(Options::Custom) && userOptions_.check(Options::Custom)) { - _opt += Options::Custom; - } - - // //force user-choice for the alpha value when reading binary - // if ( options_.is_binary() && userOptions_.color_has_alpha() ) - // options_ += Options::ColorAlpha; - - return (options_.is_binary() ? read_binary(_in, _bi, swap, _opt) : read_ascii(_in, _bi, _opt)); - -} - -template -struct Handle2Prop; - -template -struct Handle2Prop -{ - typedef OpenMesh::VPropHandleT PropT; -}; - -template -struct Handle2Prop -{ - typedef OpenMesh::FPropHandleT PropT; -}; - -//read and assign custom properties with the given type. Also creates property, if not exist -template -void _PLYReader_::readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listType) const -{ - if (_listType == Unsupported) //no list type defined -> property is not a list - { - //get/add property - typename Handle2Prop::PropT prop; - if (!_bi.kernel()->get_property_handle(prop,_propName)) - { - _bi.kernel()->add_property(prop,_propName); - _bi.kernel()->property(prop).set_persistent(true); - } - - //read and assign - T in; - read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type()); - _bi.kernel()->property(prop,_h) = in; - } - else - { - //get/add property - typename Handle2Prop,Handle>::PropT prop; - if (!_bi.kernel()->get_property_handle(prop,_propName)) - { - _bi.kernel()->add_property(prop,_propName); - _bi.kernel()->property(prop).set_persistent(true); - } - - //init vector - unsigned int numberOfValues; - readInteger(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type()); - std::vector vec(numberOfValues); - //read and assign - for (unsigned int i = 0; i < numberOfValues; ++i) - { - read(_valueType, _in, vec[i], OpenMesh::GenProg::Bool2Type()); - } - _bi.kernel()->property(prop,_h) = vec; - } -} - -template -void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const -{ - switch (_valueType) - { - case ValueTypeINT8: - case ValueTypeCHAR: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeUINT8: - case ValueTypeUCHAR: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeINT16: - case ValueTypeSHORT: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeUINT16: - case ValueTypeUSHORT: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeINT32: - case ValueTypeINT: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeUINT32: - case ValueTypeUINT: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeFLOAT32: - case ValueTypeFLOAT: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - case ValueTypeFLOAT64: - case ValueTypeDOUBLE: - readCreateCustomProperty(_in,_bi,_h,_propName,_valueType,_listIndexType); - break; - default: - std::cerr << "unsupported type" << std::endl; - break; - } -} - - -//----------------------------------------------------------------------------- - -bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options& _opt) const { - - unsigned int i, j, k, l, idx; - unsigned int nV; - OpenMesh::Vec3f v, n; - std::string trash; - OpenMesh::Vec2f t; - OpenMesh::Vec4i c; - float tmp; - BaseImporter::VHandles vhandles; - VertexHandle vh; - - _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); - - if (vertexDimension_ != 3) { - omerr() << "[PLYReader] : Only vertex dimension 3 is supported." << std::endl; - return false; - } - - const bool err_enabled = omerr().is_enabled(); - size_t complex_faces = 0; - if (err_enabled) - omerr().disable(); - - for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) - { - if (_in.eof()) { - if (err_enabled) - omerr().enable(); - - omerr() << "Unexpected end of file while reading." << std::endl; - return false; - } - - if (e_it->element_== VERTEX) - { - // read vertices: - for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { - vh = _bi.add_vertex(); - - v[0] = 0.0; - v[1] = 0.0; - v[2] = 0.0; - - n[0] = 0.0; - n[1] = 0.0; - n[2] = 0.0; - - t[0] = 0.0; - t[1] = 0.0; - - c[0] = 0; - c[1] = 0; - c[2] = 0; - c[3] = 255; - - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { - PropertyInfo prop = e_it->properties_[propertyIndex]; - switch (prop.property) { - case XCOORD: - _in >> v[0]; - break; - case YCOORD: - _in >> v[1]; - break; - case ZCOORD: - _in >> v[2]; - break; - case XNORM: - _in >> n[0]; - break; - case YNORM: - _in >> n[1]; - break; - case ZNORM: - _in >> n[2]; - break; - case TEXX: - _in >> t[0]; - break; - case TEXY: - _in >> t[1]; - break; - case COLORRED: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[0] = static_cast (tmp * 255.0f); - } - else - _in >> c[0]; - break; - case COLORGREEN: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[1] = static_cast (tmp * 255.0f); - } - else - _in >> c[1]; - break; - case COLORBLUE: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[2] = static_cast (tmp * 255.0f); - } - else - _in >> c[2]; - break; - case COLORALPHA: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[3] = static_cast (tmp * 255.0f); - } - else - _in >> c[3]; - break; - case CUSTOM_PROP: - if (_opt.check(Options::Custom)) - readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); - else - _in >> trash; - break; - default: - _in >> trash; - break; - } - } - - _bi.set_point(vh, v); - if (_opt.vertex_has_normal()) - _bi.set_normal(vh, n); - if (_opt.vertex_has_texcoord()) - _bi.set_texcoord(vh, t); - if (_opt.vertex_has_color()) - _bi.set_color(vh, Vec4uc(c)); - } - } - else if (e_it->element_ == FACE) - { - // faces - for (i = 0; i < faceCount_ && !_in.eof(); ++i) { - FaceHandle fh; - - c[0] = 0; - c[1] = 0; - c[2] = 0; - c[3] = 255; - - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { - PropertyInfo prop = e_it->properties_[propertyIndex]; - switch (prop.property) { - - case VERTEX_INDICES: - // nV = number of Vertices for current face - _in >> nV; - - if (nV == 3) { - vhandles.resize(3); - _in >> j; - _in >> k; - _in >> l; - - vhandles[0] = VertexHandle(j); - vhandles[1] = VertexHandle(k); - vhandles[2] = VertexHandle(l); - } - else { - vhandles.clear(); - for (j = 0; j < nV; ++j) { - _in >> idx; - vhandles.push_back(VertexHandle(idx)); - } - } - - fh = _bi.add_face(vhandles); - if (!fh.is_valid()) - ++complex_faces; - break; - - case COLORRED: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[0] = static_cast (tmp * 255.0f); - } else - _in >> c[0]; - break; - - case COLORGREEN: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[1] = static_cast (tmp * 255.0f); - } else - _in >> c[1]; - break; - - case COLORBLUE: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[2] = static_cast (tmp * 255.0f); - } else - _in >> c[2]; - break; - - case COLORALPHA: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - _in >> tmp; - c[3] = static_cast (tmp * 255.0f); - } else - _in >> c[3]; - break; - - case CUSTOM_PROP: - if (_opt.check(Options::Custom) && fh.is_valid()) - readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); - else - _in >> trash; - break; - - default: - _in >> trash; - break; - } - } - if (_opt.face_has_color()) - _bi.set_color(fh, Vec4uc(c)); - } - } - else - { - // other elements - for (i = 0; i < e_it->count_ && !_in.eof(); ++i) { - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) - { - // just skip the values - _in >> trash; - } - } - } - - if(e_it->element_== FACE) - // stop reading after the faces since additional elements are not preserved anyway - break; - } - - if (err_enabled) - omerr().enable(); - - if (complex_faces) - omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; - - // File was successfully parsed. - return true; -} - -//----------------------------------------------------------------------------- - -bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap*/, const Options& _opt) const { - - OpenMesh::Vec3f v, n; // Vertex - OpenMesh::Vec2f t; // TexCoords - BaseImporter::VHandles vhandles; - VertexHandle vh; - OpenMesh::Vec4i c; // Color - float tmp; - - _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_); - - const bool err_enabled = omerr().is_enabled(); - size_t complex_faces = 0; - if (err_enabled) - omerr().disable(); - - for (std::vector::iterator e_it = elements_.begin(); e_it != elements_.end(); ++e_it) - { - if (e_it->element_ == VERTEX) - { - // read vertices: - for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) { - vh = _bi.add_vertex(); - - v[0] = 0.0; - v[1] = 0.0; - v[2] = 0.0; - - n[0] = 0.0; - n[1] = 0.0; - n[2] = 0.0; - - t[0] = 0.0; - t[1] = 0.0; - - c[0] = 0; - c[1] = 0; - c[2] = 0; - c[3] = 255; - - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) { - PropertyInfo prop = e_it->properties_[propertyIndex]; - switch (prop.property) { - case XCOORD: - readValue(prop.value, _in, v[0]); - break; - case YCOORD: - readValue(prop.value, _in, v[1]); - break; - case ZCOORD: - readValue(prop.value, _in, v[2]); - break; - case XNORM: - readValue(prop.value, _in, n[0]); - break; - case YNORM: - readValue(prop.value, _in, n[1]); - break; - case ZNORM: - readValue(prop.value, _in, n[2]); - break; - case TEXX: - readValue(prop.value, _in, t[0]); - break; - case TEXY: - readValue(prop.value, _in, t[1]); - break; - case COLORRED: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - - c[0] = static_cast (tmp * 255.0f); - } - else - readInteger(prop.value, _in, c[0]); - - break; - case COLORGREEN: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[1] = static_cast (tmp * 255.0f); - } - else - readInteger(prop.value, _in, c[1]); - - break; - case COLORBLUE: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[2] = static_cast (tmp * 255.0f); - } - else - readInteger(prop.value, _in, c[2]); - - break; - case COLORALPHA: - if (prop.value == ValueTypeFLOAT32 || prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[3] = static_cast (tmp * 255.0f); - } - else - readInteger(prop.value, _in, c[3]); - - break; - case CUSTOM_PROP: - if (_opt.check(Options::Custom)) - readCustomProperty(_in, _bi, vh, prop.name, prop.value, prop.listIndexType); - else - consume_input(_in, scalar_size_[prop.value]); - break; - default: - // Read unsupported property - consume_input(_in, scalar_size_[prop.value]); - break; - } - - } - - _bi.set_point(vh, v); - if (_opt.vertex_has_normal()) - _bi.set_normal(vh, n); - if (_opt.vertex_has_texcoord()) - _bi.set_texcoord(vh, t); - if (_opt.vertex_has_color()) - _bi.set_color(vh, Vec4uc(c)); - } - } - else if (e_it->element_ == FACE) { - for (unsigned i = 0; i < e_it->count_ && !_in.eof(); ++i) { - FaceHandle fh; - - c[0] = 0; - c[1] = 0; - c[2] = 0; - c[3] = 255; - - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) - { - PropertyInfo prop = e_it->properties_[propertyIndex]; - switch (prop.property) { - - case VERTEX_INDICES: - // nV = number of Vertices for current face - unsigned int nV; - readInteger(prop.listIndexType, _in, nV); - - if (nV == 3) { - vhandles.resize(3); - unsigned int j, k, l; - readInteger(prop.value, _in, j); - readInteger(prop.value, _in, k); - readInteger(prop.value, _in, l); - - vhandles[0] = VertexHandle(j); - vhandles[1] = VertexHandle(k); - vhandles[2] = VertexHandle(l); - } - else { - vhandles.clear(); - for (unsigned j = 0; j < nV; ++j) { - unsigned int idx; - readInteger(prop.value, _in, idx); - vhandles.push_back(VertexHandle(idx)); - } - } - - fh = _bi.add_face(vhandles); - if (!fh.is_valid()) - ++complex_faces; - break; - case COLORRED: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[0] = static_cast (tmp * 255.0f); - } else - readInteger(prop.value, _in, c[0]); - break; - case COLORGREEN: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[1] = static_cast (tmp * 255.0f); - } else - readInteger(prop.value, _in, c[1]); - break; - case COLORBLUE: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[2] = static_cast (tmp * 255.0f); - } else - readInteger(prop.value, _in, c[2]); - break; - case COLORALPHA: - if (prop.value == ValueTypeFLOAT32 || - prop.value == ValueTypeFLOAT) { - readValue(prop.value, _in, tmp); - c[3] = static_cast (tmp * 255.0f); - } else - readInteger(prop.value, _in, c[3]); - break; - case CUSTOM_PROP: - if (_opt.check(Options::Custom) && fh.is_valid()) - readCustomProperty(_in, _bi, fh, prop.name, prop.value, prop.listIndexType); - else - consume_input(_in, scalar_size_[prop.value]); - break; - - default: - consume_input(_in, scalar_size_[prop.value]); - break; - } - } - if (_opt.face_has_color()) - _bi.set_color(fh, Vec4uc(c)); - } - } - else { - for (unsigned int i = 0; i < e_it->count_ && !_in.eof(); ++i) - { - for (size_t propertyIndex = 0; propertyIndex < e_it->properties_.size(); ++propertyIndex) - { - PropertyInfo prop = e_it->properties_[propertyIndex]; - // skip element values - consume_input(_in, scalar_size_[prop.value]); - } - } - } - - if (_in.eof()) { - if (err_enabled) - omerr().enable(); - - omerr() << "Unexpected end of file while reading." << std::endl; - return false; - } - - if (e_it->element_ == FACE) - // stop reading after the faces since additional elements are not preserved anyway - break; - } - if (err_enabled) - omerr().enable(); - - if (complex_faces) - omerr() << complex_faces << "The reader encountered invalid faces, that could not be added.\n"; - - - return true; -} - - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, float& _value) const { - - switch (_type) { - case ValueTypeFLOAT32: - case ValueTypeFLOAT: - float32_t tmp; - restore(_in, tmp, options_.check(Options::MSB)); - _value = tmp; - break; - case ValueTypeDOUBLE: - case ValueTypeFLOAT64: - double dtmp; - readValue(_type, _in, dtmp); - _value = static_cast(dtmp); - break; - default: - _value = 0.0; - std::cerr << "unsupported conversion type to float: " << _type << std::endl; - break; - } -} - - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, double& _value) const { - - switch (_type) { - - case ValueTypeFLOAT64: - - case ValueTypeDOUBLE: - - float64_t tmp; - restore(_in, tmp, options_.check(Options::MSB)); - _value = tmp; - - break; - - default: - - _value = 0.0; - std::cerr << "unsupported conversion type to double: " << _type << std::endl; - - break; - } -} - - -//----------------------------------------------------------------------------- - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned char& _value) const{ - unsigned int tmp; - readValue(_type,_in,tmp); - _value = tmp; -} - -//----------------------------------------------------------------------------- - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned short& _value) const{ - unsigned int tmp; - readValue(_type,_in,tmp); - _value = tmp; -} - -//----------------------------------------------------------------------------- - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, signed char& _value) const{ - int tmp; - readValue(_type,_in,tmp); - _value = tmp; -} - -//----------------------------------------------------------------------------- - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, short& _value) const{ - int tmp; - readValue(_type,_in,tmp); - _value = tmp; -} - - -//----------------------------------------------------------------------------- -void _PLYReader_::readValue(ValueType _type, std::istream& _in, unsigned int& _value) const { - - uint32_t tmp_uint32_t; - uint16_t tmp_uint16_t; - uint8_t tmp_uchar; - - switch (_type) { - - case ValueTypeUINT: - - case ValueTypeUINT32: - - restore(_in, tmp_uint32_t, options_.check(Options::MSB)); - _value = tmp_uint32_t; - - break; - - case ValueTypeUSHORT: - - case ValueTypeUINT16: - - restore(_in, tmp_uint16_t, options_.check(Options::MSB)); - _value = tmp_uint16_t; - - break; - - case ValueTypeUCHAR: - - case ValueTypeUINT8: - - restore(_in, tmp_uchar, options_.check(Options::MSB)); - _value = tmp_uchar; - - break; - - default: - - _value = 0; - std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; - - break; - } -} - - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readValue(ValueType _type, std::istream& _in, int& _value) const { - - int32_t tmp_int32_t; - int16_t tmp_int16_t; - int8_t tmp_char; - - switch (_type) { - - case ValueTypeINT: - - case ValueTypeINT32: - - restore(_in, tmp_int32_t, options_.check(Options::MSB)); - _value = tmp_int32_t; - - break; - - case ValueTypeSHORT: - - case ValueTypeINT16: - - restore(_in, tmp_int16_t, options_.check(Options::MSB)); - _value = tmp_int16_t; - - break; - - case ValueTypeCHAR: - - case ValueTypeINT8: - - restore(_in, tmp_char, options_.check(Options::MSB)); - _value = tmp_char; - - break; - - default: - - _value = 0; - std::cerr << "unsupported conversion type to int: " << _type << std::endl; - - break; - } -} - - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readInteger(ValueType _type, std::istream& _in, int& _value) const { - - int32_t tmp_int32_t; - uint32_t tmp_uint32_t; - int8_t tmp_char; - uint8_t tmp_uchar; - - switch (_type) { - - case ValueTypeINT: - - case ValueTypeINT32: - - restore(_in, tmp_int32_t, options_.check(Options::MSB)); - _value = tmp_int32_t; - - break; - - case ValueTypeUINT: - - case ValueTypeUINT32: - - restore(_in, tmp_uint32_t, options_.check(Options::MSB)); - _value = tmp_uint32_t; - - break; - - case ValueTypeCHAR: - - case ValueTypeINT8: - - restore(_in, tmp_char, options_.check(Options::MSB)); - _value = tmp_char; - - break; - - case ValueTypeUCHAR: - - case ValueTypeUINT8: - - restore(_in, tmp_uchar, options_.check(Options::MSB)); - _value = tmp_uchar; - - break; - - default: - - _value = 0; - std::cerr << "unsupported conversion type to int: " << _type << std::endl; - - break; - } -} - - -//----------------------------------------------------------------------------- - - -void _PLYReader_::readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const { - - int32_t tmp_int32_t; - uint32_t tmp_uint32_t; - int8_t tmp_char; - uint8_t tmp_uchar; - - switch (_type) { - - case ValueTypeUINT: - - case ValueTypeUINT32: - - restore(_in, tmp_uint32_t, options_.check(Options::MSB)); - _value = tmp_uint32_t; - - break; - - case ValueTypeINT: - - case ValueTypeINT32: - - restore(_in, tmp_int32_t, options_.check(Options::MSB)); - _value = tmp_int32_t; - - break; - - case ValueTypeUCHAR: - - case ValueTypeUINT8: - - restore(_in, tmp_uchar, options_.check(Options::MSB)); - _value = tmp_uchar; - - break; - - case ValueTypeCHAR: - - case ValueTypeINT8: - - restore(_in, tmp_char, options_.check(Options::MSB)); - _value = tmp_char; - - break; - - default: - - _value = 0; - std::cerr << "unsupported conversion type to unsigned int: " << _type << std::endl; - - break; - } -} - - -//------------------------------------------------------------------------------ - - -bool _PLYReader_::can_u_read(const std::string& _filename) const { - - // !!! Assuming BaseReader::can_u_parse( std::string& ) - // does not call BaseReader::read_magic()!!! - - if (BaseReader::can_u_read(_filename)) { - std::ifstream ifs(_filename.c_str()); - if (ifs.is_open() && can_u_read(ifs)) { - ifs.close(); - return true; - } - } - return false; -} - - - -//----------------------------------------------------------------------------- - -std::string get_property_name(std::string _string1, std::string _string2) { - - if (_string1 == "float32" || _string1 == "float64" || _string1 == "float" || _string1 == "double" || - _string1 == "int8" || _string1 == "uint8" || _string1 == "char" || _string1 == "uchar" || - _string1 == "int32" || _string1 == "uint32" || _string1 == "int" || _string1 == "uint" || - _string1 == "int16" || _string1 == "uint16" || _string1 == "short" || _string1 == "ushort") - return _string2; - - if (_string2 == "float32" || _string2 == "float64" || _string2 == "float" || _string2 == "double" || - _string2 == "int8" || _string2 == "uint8" || _string2 == "char" || _string2 == "uchar" || - _string2 == "int32" || _string2 == "uint32" || _string2 == "int" || _string2 == "uint" || - _string2 == "int16" || _string2 == "uint16" || _string2 == "short" || _string2 == "ushort") - return _string1; - - - std::cerr << "Unsupported entry type" << std::endl; - return "Unsupported"; -} - -//----------------------------------------------------------------------------- - -_PLYReader_::ValueType get_property_type(std::string& _string1, std::string& _string2) { - - if (_string1 == "float32" || _string2 == "float32") - - return _PLYReader_::ValueTypeFLOAT32; - - else if (_string1 == "float64" || _string2 == "float64") - - return _PLYReader_::ValueTypeFLOAT64; - - else if (_string1 == "float" || _string2 == "float") - - return _PLYReader_::ValueTypeFLOAT; - - else if (_string1 == "double" || _string2 == "double") - - return _PLYReader_::ValueTypeDOUBLE; - - else if (_string1 == "int8" || _string2 == "int8") - - return _PLYReader_::ValueTypeINT8; - - else if (_string1 == "uint8" || _string2 == "uint8") - - return _PLYReader_::ValueTypeUINT8; - - else if (_string1 == "char" || _string2 == "char") - - return _PLYReader_::ValueTypeCHAR; - - else if (_string1 == "uchar" || _string2 == "uchar") - - return _PLYReader_::ValueTypeUCHAR; - - else if (_string1 == "int32" || _string2 == "int32") - - return _PLYReader_::ValueTypeINT32; - - else if (_string1 == "uint32" || _string2 == "uint32") - - return _PLYReader_::ValueTypeUINT32; - - else if (_string1 == "int" || _string2 == "int") - - return _PLYReader_::ValueTypeINT; - - else if (_string1 == "uint" || _string2 == "uint") - - return _PLYReader_::ValueTypeUINT; - - else if (_string1 == "int16" || _string2 == "int16") - - return _PLYReader_::ValueTypeINT16; - - else if (_string1 == "uint16" || _string2 == "uint16") - - return _PLYReader_::ValueTypeUINT16; - - else if (_string1 == "short" || _string2 == "short") - - return _PLYReader_::ValueTypeSHORT; - - else if (_string1 == "ushort" || _string2 == "ushort") - - return _PLYReader_::ValueTypeUSHORT; - - return _PLYReader_::Unsupported; -} - - -//----------------------------------------------------------------------------- - -bool _PLYReader_::can_u_read(std::istream& _is) const { - - // Clear per file options - options_.cleanup(); - - // clear element list - elements_.clear(); - - // read 1st line - std::string line; - std::getline(_is, line); - trim(line); - - // Handle '\r\n' newlines - const size_t s = line.size(); - if( s > 0 && line[s - 1] == '\r') line.resize(s - 1); - - //Check if this file is really a ply format - if (line != "PLY" && line != "ply") - return false; - - vertexCount_ = 0; - faceCount_ = 0; - vertexDimension_ = 0; - - unsigned int elementCount = 0; - - std::string keyword; - std::string fileType; - std::string elementName = ""; - std::string propertyName; - std::string listIndexType; - std::string listEntryType; - float version; - - _is >> keyword; - _is >> fileType; - _is >> version; - - if (_is.bad()) { - omerr() << "Defect PLY header detected" << std::endl; - return false; - } - - if (fileType == "ascii") { - options_ -= Options::Binary; - } else if (fileType == "binary_little_endian") { - options_ += Options::Binary; - options_ += Options::LSB; - //if (Endian::local() == Endian::MSB) - - // options_ += Options::Swap; - } else if (fileType == "binary_big_endian") { - options_ += Options::Binary; - options_ += Options::MSB; - //if (Endian::local() == Endian::LSB) - - // options_ += Options::Swap; - } else { - omerr() << "Unsupported PLY format: " << fileType << std::endl; - return false; - } - - std::streamoff streamPos = _is.tellg(); - _is >> keyword; - while (keyword != "end_header") { - - if (keyword == "comment") { - std::getline(_is, line); - } else if (keyword == "element") { - _is >> elementName; - _is >> elementCount; - - ElementInfo element; - element.name_ = elementName; - element.count_ = elementCount; - - if (elementName == "vertex") { - vertexCount_ = elementCount; - element.element_ = VERTEX; - } else if (elementName == "face") { - faceCount_ = elementCount; - element.element_ = FACE; - } else { - omerr() << "PLY header unsupported element type: " << elementName << std::endl; - element.element_ = UNKNOWN; - } - - elements_.push_back(element); - } else if (keyword == "property") { - std::string tmp1; - std::string tmp2; - - // Read first keyword, as it might be a list - _is >> tmp1; - - if (tmp1 == "list") { - _is >> listIndexType; - _is >> listEntryType; - _is >> propertyName; - - ValueType indexType = Unsupported; - ValueType entryType = Unsupported; - - if (listIndexType == "uint8") { - indexType = ValueTypeUINT8; - } else if (listIndexType == "uint16") { - indexType = ValueTypeUINT16; - } else if (listIndexType == "uchar") { - indexType = ValueTypeUCHAR; - } else if (listIndexType == "int") { - indexType = ValueTypeINT; - } else { - omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl; - return false; - } - - entryType = get_property_type(listEntryType, listEntryType); - - if (entryType == Unsupported) { - omerr() << "Unsupported Entry type for property list: " << listEntryType << std::endl; - } - - PropertyInfo property(CUSTOM_PROP, entryType, propertyName); - property.listIndexType = indexType; - - if (elementName == "face") - { - // special case for vertex indices - if (propertyName == "vertex_index" || propertyName == "vertex_indices") - { - property.property = VERTEX_INDICES; - - if (!elements_.back().properties_.empty()) - { - omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl; - elements_.back().properties_.clear(); - } - } else { - options_ += Options::Custom; - } - - } - else - omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl; - - elements_.back().properties_.push_back(property); - - } else { - // as this is not a list property, read second value of property - _is >> tmp2; - - - // Extract name and type of property - // As the order seems to be different in some files, autodetect it. - ValueType valueType = get_property_type(tmp1, tmp2); - propertyName = get_property_name(tmp1, tmp2); - - PropertyInfo entry; - - //special treatment for some vertex properties. - if (elementName == "vertex") { - if (propertyName == "x") { - entry = PropertyInfo(XCOORD, valueType); - vertexDimension_++; - } else if (propertyName == "y") { - entry = PropertyInfo(YCOORD, valueType); - vertexDimension_++; - } else if (propertyName == "z") { - entry = PropertyInfo(ZCOORD, valueType); - vertexDimension_++; - } else if (propertyName == "nx") { - entry = PropertyInfo(XNORM, valueType); - options_ += Options::VertexNormal; - } else if (propertyName == "ny") { - entry = PropertyInfo(YNORM, valueType); - options_ += Options::VertexNormal; - } else if (propertyName == "nz") { - entry = PropertyInfo(ZNORM, valueType); - options_ += Options::VertexNormal; - } else if (propertyName == "u" || propertyName == "s") { - entry = PropertyInfo(TEXX, valueType); - options_ += Options::VertexTexCoord; - } else if (propertyName == "v" || propertyName == "t") { - entry = PropertyInfo(TEXY, valueType); - options_ += Options::VertexTexCoord; - } else if (propertyName == "red") { - entry = PropertyInfo(COLORRED, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "green") { - entry = PropertyInfo(COLORGREEN, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "blue") { - entry = PropertyInfo(COLORBLUE, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_red") { - entry = PropertyInfo(COLORRED, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_green") { - entry = PropertyInfo(COLORGREEN, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_blue") { - entry = PropertyInfo(COLORBLUE, valueType); - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "alpha") { - entry = PropertyInfo(COLORALPHA, valueType); - options_ += Options::VertexColor; - options_ += Options::ColorAlpha; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } - } - else if (elementName == "face") { - if (propertyName == "red") { - entry = PropertyInfo(COLORRED, valueType); - options_ += Options::FaceColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "green") { - entry = PropertyInfo(COLORGREEN, valueType); - options_ += Options::FaceColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "blue") { - entry = PropertyInfo(COLORBLUE, valueType); - options_ += Options::FaceColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "alpha") { - entry = PropertyInfo(COLORALPHA, valueType); - options_ += Options::FaceColor; - options_ += Options::ColorAlpha; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } - } - - //not a special property, load as custom - if (entry.value == Unsupported){ - Property prop = CUSTOM_PROP; - options_ += Options::Custom; - entry = PropertyInfo(prop, valueType, propertyName); - } - - if (entry.property != UNSUPPORTED) - { - elements_.back().properties_.push_back(entry); - } - } - - } else { - omlog() << "Unsupported keyword : " << keyword << std::endl; - } - - streamPos = _is.tellg(); - _is >> keyword; - if (_is.bad()) { - omerr() << "Error while reading PLY file header" << std::endl; - return false; - } - } - - // As the binary data is directy after the end_header keyword - // and the stream removes too many bytes, seek back to the right position - if (options_.is_binary()) { - _is.seekg(streamPos); - - char c1 = 0; - char c2 = 0; - _is.get(c1); - _is.get(c2); - - if (c1 == 0x0D && c2 == 0x0A) { - _is.seekg(streamPos + 14); - } - else { - _is.seekg(streamPos + 12); - } - } - - return true; -} - -//============================================================================= -} // namespace IO -} // namespace OpenMesh -//============================================================================= From 8c9214009d662340702cbbf7ef936080f89b9656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:27:17 +0200 Subject: [PATCH 8/9] Added ply test --- src/Unittests/unittests_read_write_PLY.cc | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/src/Unittests/unittests_read_write_PLY.cc b/src/Unittests/unittests_read_write_PLY.cc index bd1a4533..e587625d 100644 --- a/src/Unittests/unittests_read_write_PLY.cc +++ b/src/Unittests/unittests_read_write_PLY.cc @@ -543,6 +543,91 @@ TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithCustomProps) { } +/* + * Just load a ply with custom properties, binary mode + */ +TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithCustomPropsBinary) { + + PolyMesh mesh; + + OpenMesh::IO::Options options; + options += OpenMesh::IO::Options::Custom; + options += OpenMesh::IO::Options::Binary; + + bool ok = OpenMesh::IO::read_mesh(mesh, "cube-minimal-custom_props-binary.ply", options); + + EXPECT_TRUE(ok) << "Unable to load cube-minimal-custom_props.ply"; + + EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!"; + EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!"; + EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!"; + + OpenMesh::VPropHandleT qualityProp; + OpenMesh::VPropHandleT indexProp; + ASSERT_TRUE(mesh.get_property_handle(qualityProp,"quality")) << "Could not access quality property"; + ASSERT_TRUE(mesh.get_property_handle(indexProp,"index")) << "Could not access index property"; + + //check index property + for (unsigned i = 0; i < mesh.n_vertices(); ++i) + EXPECT_EQ(i ,mesh.property(indexProp,OpenMesh::VertexHandle(i))) << "Vertex index at vertex " << i << " is wrong"; + + //check quality property + EXPECT_EQ(1.f,mesh.property(qualityProp,OpenMesh::VertexHandle(0))) << "Wrong quality value at Vertex 0"; + EXPECT_EQ(0.5f,mesh.property(qualityProp,OpenMesh::VertexHandle(1))) << "Wrong quality value at Vertex 1"; + EXPECT_EQ(0.7f,mesh.property(qualityProp,OpenMesh::VertexHandle(2))) << "Wrong quality value at Vertex 2"; + EXPECT_EQ(1.f,mesh.property(qualityProp,OpenMesh::VertexHandle(3))) << "Wrong quality value at Vertex 3"; + EXPECT_EQ(0.1f,mesh.property(qualityProp,OpenMesh::VertexHandle(4))) << "Wrong quality value at Vertex 4"; + EXPECT_EQ(0.f,mesh.property(qualityProp,OpenMesh::VertexHandle(5))) << "Wrong quality value at Vertex 5"; + EXPECT_EQ(2.f,mesh.property(qualityProp,OpenMesh::VertexHandle(6))) << "Wrong quality value at Vertex 6"; + EXPECT_EQ(5.f,mesh.property(qualityProp,OpenMesh::VertexHandle(7))) << "Wrong quality value at Vertex 7"; + + //check for custom list properties + + OpenMesh::VPropHandleT< std::vector > testValues; + ASSERT_TRUE(mesh.get_property_handle(testValues,"test_values")) << "Could not access texcoords per face"; + + EXPECT_EQ(2u,mesh.property(testValues,OpenMesh::VertexHandle(0)).size()) << "Wrong verctor size"; + + EXPECT_EQ(1,mesh.property(testValues,OpenMesh::VertexHandle(0))[0]) << "Wrong list value at Vertex 0"; + EXPECT_EQ(4,mesh.property(testValues,OpenMesh::VertexHandle(1))[1]) << "Wrong list value at Vertex 1"; + EXPECT_EQ(5,mesh.property(testValues,OpenMesh::VertexHandle(2))[0]) << "Wrong list value at Vertex 2"; + EXPECT_EQ(8,mesh.property(testValues,OpenMesh::VertexHandle(3))[1]) << "Wrong list value at Vertex 3"; + EXPECT_EQ(9,mesh.property(testValues,OpenMesh::VertexHandle(4))[0]) << "Wrong list value at Vertex 4"; + EXPECT_EQ(12,mesh.property(testValues,OpenMesh::VertexHandle(5))[1]) << "Wrong list value at Vertex 5"; + EXPECT_EQ(13,mesh.property(testValues,OpenMesh::VertexHandle(6))[0]) << "Wrong list value at Vertex 6"; + EXPECT_EQ(16,mesh.property(testValues,OpenMesh::VertexHandle(7))[1]) << "Wrong list value at Vertex 7"; + + OpenMesh::FPropHandleT< std::vector > texCoordsPerFace; + ASSERT_TRUE(mesh.get_property_handle(texCoordsPerFace,"texcoords")) << "Could not access texcoords per face"; + + for (Mesh::FaceIter f_iter = mesh.faces_begin(); f_iter != mesh.faces_end(); ++f_iter) + { + EXPECT_EQ(8u, mesh.property(texCoordsPerFace, *f_iter).size()) << "Texcoords per face container has wrong size on face: " << f_iter->idx(); + if (!mesh.property(texCoordsPerFace, *f_iter).empty()) + { + EXPECT_EQ(1.0, mesh.property(texCoordsPerFace, *f_iter)[0]) << "Texcoords wrong on index 0 with face: " << f_iter->idx(); + EXPECT_EQ(1.0, mesh.property(texCoordsPerFace, *f_iter)[1]) << "Texcoords wrong on index 1 with face: " << f_iter->idx(); + EXPECT_EQ(-1.0f, mesh.property(texCoordsPerFace, *f_iter)[2]) << "Texcoords wrong on index 2 with face: " << f_iter->idx(); + EXPECT_EQ(-1.0f, mesh.property(texCoordsPerFace, *f_iter)[3]) << "Texcoords wrong on index 3 with face: " << f_iter->idx(); + EXPECT_EQ(0.0f, mesh.property(texCoordsPerFace, *f_iter)[4]) << "Texcoords wrong on index 4 with face: " << f_iter->idx(); + EXPECT_EQ(0.0f, mesh.property(texCoordsPerFace, *f_iter)[5]) << "Texcoords wrong on index 5 with face: " << f_iter->idx(); + EXPECT_EQ(-0.5f, mesh.property(texCoordsPerFace, *f_iter)[6]) << "Texcoords wrong on index 6 with face: " << f_iter->idx(); + EXPECT_EQ(-0.5f, mesh.property(texCoordsPerFace, *f_iter)[7]) << "Texcoords wrong on index 7 with face: " << f_iter->idx(); + } + + } + + OpenMesh::FPropHandleT< unsigned > faceIndex; + ASSERT_TRUE(mesh.get_property_handle(faceIndex,"faceIndex")) << "Could not access faceIndex per face"; + + EXPECT_EQ(0u,mesh.property(faceIndex,OpenMesh::FaceHandle(0))) << "Wrong index value at FaceHandle 0"; + EXPECT_EQ(1u,mesh.property(faceIndex,OpenMesh::FaceHandle(1))) << "Wrong index value at FaceHandle 1"; + EXPECT_EQ(2u,mesh.property(faceIndex,OpenMesh::FaceHandle(2))) << "Wrong index value at FaceHandle 2"; + EXPECT_EQ(3u,mesh.property(faceIndex,OpenMesh::FaceHandle(3))) << "Wrong index value at FaceHandle 3"; + EXPECT_EQ(4u,mesh.property(faceIndex,OpenMesh::FaceHandle(4))) << "Wrong index value at FaceHandle 4"; + EXPECT_EQ(5u,mesh.property(faceIndex,OpenMesh::FaceHandle(5))) << "Wrong index value at FaceHandle 5"; + +} TEST_F(OpenMeshReadWritePLY, WriteReadSimplePLYWithCustomProps) { From 79bf4a7742a98fd9812b65546a167f76b5af496d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Tue, 3 Sep 2019 08:27:39 +0200 Subject: [PATCH 9/9] Added ply test --- .../cube-minimal-custom_props-binary.ply | Bin 0 -> 1035 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Unittests/TestFiles/cube-minimal-custom_props-binary.ply diff --git a/src/Unittests/TestFiles/cube-minimal-custom_props-binary.ply b/src/Unittests/TestFiles/cube-minimal-custom_props-binary.ply new file mode 100644 index 0000000000000000000000000000000000000000..53be426bd05c4be80be4dfefa0a336980f7e18d7 GIT binary patch literal 1035 zcma)3TW-QI5Om%2l|GN)6I5*@Rs2-px2K2dUM)@G%}NczS&`3ZU#f}C zwU6G^st=WY=%)|414?&5>JDhX7n;0w$cv0jW-c|Iq&Ay-g^K~*z^XTMpDeXqn0edS zM30Sn-?{6Fs?HP2osCJ?_TM2kPeCs<&hsMeu-F%Be6lxs+2qUU)D)o*>&PP+g&Uo_<1If|kfiR1-^OW;*$ltNZ6$1v@YOkPpAW~B89 za!p*vf7|T`D#{xQ)CrBIEUz815U46|Dcpfq5o^L8c?fIrp27oot+#!W5Whp%laCah zXmaPxTfsdUZzY>54WZSbv%nMqTtSLlD120f5&>JJ4Gzd~RE2jB;0krBPdY)xKMDo^ U2CXMKM0)NE?l1rxb%-{?fAlxjx&QzG literal 0 HcmV?d00001