From d8d26b7c1866a3f79f2e2dffb9f9fd4afb94b7c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20M=C3=B6ller?= Date: Mon, 18 May 2015 11:52:18 +0000 Subject: [PATCH] ply ascii reader: - add read support for custom list properties (vertices and faces) closes #2370 git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@1268 fdac6126-5c0c-442c-9429-916003d36597 --- src/OpenMesh/Core/IO/reader/PLYReader.cc | 482 +++++++++++------- src/OpenMesh/Core/IO/reader/PLYReader.hh | 29 +- .../TestFiles/cube-minimal-custom_props.ply | 30 +- src/Unittests/unittests_read_write_PLY.cc | 83 ++- 4 files changed, 382 insertions(+), 242 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.cc b/src/OpenMesh/Core/IO/reader/PLYReader.cc index 7a1bf5c9..7aef8197 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.cc +++ b/src/OpenMesh/Core/IO/reader/PLYReader.cc @@ -175,49 +175,92 @@ bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) { } +template +struct Handle2Prop; + template -void assignCustomProperty(std::istream& _in, BaseImporter& _bi, VertexHandle _vh, const std::string& _propName) +struct Handle2Prop { - OpenMesh::VPropHandleT prop; - if (!_bi.kernel()->get_property_handle(prop,_propName)) - _bi.kernel()->add_property(prop,_propName); - T in; - _in >> in; - _bi.kernel()->property(prop,_vh) = in; + typedef OpenMesh::VPropHandleT PropT; +}; + +template +struct Handle2Prop +{ + typedef OpenMesh::FPropHandleT PropT; +}; + +template +void assignCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, bool isList) +{ + if (!isList) + { + //get/add property + typename Handle2Prop::PropT prop; + if (!_bi.kernel()->get_property_handle(prop,_propName)) + _bi.kernel()->add_property(prop,_propName); + + //read and assign + T in; + _in >> in; + _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); + + //init vector + int numberOfValues; + _in >> numberOfValues; + std::vector vec; + vec.reserve(numberOfValues); + //read and assign + for (int i = 0; i < numberOfValues; ++i) + { + T in; + _in >> in; + vec.push_back(in); + } + _bi.kernel()->property(prop,_h) = vec; + } } - -void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, VertexHandle _vh, const std::string& _propName, const ValueType _valueType) const +template +void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listIndexType) const { + const bool isList = _listIndexType != Unsupported; switch (_valueType) { case ValueTypeINT8: case ValueTypeCHAR: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeINT16: case ValueTypeSHORT: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeUINT16: case ValueTypeUSHORT: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeINT32: case ValueTypeINT: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeUINT32: case ValueTypeUINT: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeFLOAT32: case ValueTypeFLOAT: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; case ValueTypeFLOAT64: case ValueTypeDOUBLE: - assignCustomProperty(_in,_bi,_vh,_propName); + assignCustomProperty(_in,_bi,_h,_propName,isList); break; default: std::cerr << "unsupported type" << std::endl; @@ -273,8 +316,8 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options c[2] = 0; c[3] = 255; - for (uint propertyIndex = 0; propertyIndex < vertexPropertyCount_; ++propertyIndex) { - switch (vertexPropertyMap_[propertyIndex].property) { + for (size_t propertyIndex = 0; propertyIndex < vertexProperties_.size(); ++propertyIndex) { + switch (vertexProperties_[propertyIndex].property) { case XCOORD: _in >> v[0]; break; @@ -300,32 +343,32 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options _in >> t[1]; break; case COLORRED: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { _in >> tmp; c[0] = static_cast (tmp * 255.0f); } else _in >> c[0]; break; case COLORGREEN: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { _in >> tmp; c[1] = static_cast (tmp * 255.0f); } else _in >> c[1]; break; case COLORBLUE: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { _in >> tmp; c[2] = static_cast (tmp * 255.0f); } else _in >> c[2]; break; case COLORALPHA: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { _in >> tmp; c[3] = static_cast (tmp * 255.0f); } else @@ -333,7 +376,7 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options break; case CUSTOM_PROP: if (_opt.check(Options::Custom)) - readCustomProperty(_in, _bi, vh, vertexPropertyMap_[propertyIndex].name, vertexPropertyMap_[propertyIndex].value); + readCustomProperty(_in, _bi, vh, vertexProperties_[propertyIndex].name, vertexProperties_[propertyIndex].value, vertexProperties_[propertyIndex].listIndexType); else _in >> trash; break; @@ -353,12 +396,17 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options } // faces - // #N .. [color spec] for (i = 0; i < faceCount_; ++i) { - // nV = number of Vertices for current face - _in >> nV; + FaceHandle fh; + for (size_t propertyIndex = 0; propertyIndex < faceProperties_.size(); ++propertyIndex) { + PropertyInfo prop = faceProperties_[propertyIndex]; + switch (prop.property) { - if (nV == 3) { + case VERTEX_INDICES: + // nV = number of Vertices for current face + _in >> nV; + + if (nV == 3) { vhandles.resize(3); _in >> j; _in >> k; @@ -367,15 +415,29 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options vhandles[0] = VertexHandle(j); vhandles[1] = VertexHandle(k); vhandles[2] = VertexHandle(l); - } else { + } else { vhandles.clear(); for (j = 0; j < nV; ++j) { - _in >> idx; - vhandles.push_back(VertexHandle(idx)); + _in >> idx; + vhandles.push_back(VertexHandle(idx)); } - } + } - _bi.add_face(vhandles); + fh = _bi.add_face(vhandles); + 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; + } + } } @@ -422,72 +484,72 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap c[2] = 0; c[3] = 255; - for (uint propertyIndex = 0; propertyIndex < vertexPropertyCount_; ++propertyIndex) { - switch (vertexPropertyMap_[propertyIndex].property) { + for (size_t propertyIndex = 0; propertyIndex < vertexProperties_.size(); ++propertyIndex) { + switch (vertexProperties_[propertyIndex].property) { case XCOORD: - readValue(vertexPropertyMap_[propertyIndex].value, _in, v[0]); + readValue(vertexProperties_[propertyIndex].value, _in, v[0]); break; case YCOORD: - readValue(vertexPropertyMap_[propertyIndex].value, _in, v[1]); + readValue(vertexProperties_[propertyIndex].value, _in, v[1]); break; case ZCOORD: - readValue(vertexPropertyMap_[propertyIndex].value, _in, v[2]); + readValue(vertexProperties_[propertyIndex].value, _in, v[2]); break; case XNORM: - readValue(vertexPropertyMap_[propertyIndex].value, _in, n[0]); + readValue(vertexProperties_[propertyIndex].value, _in, n[0]); break; case YNORM: - readValue(vertexPropertyMap_[propertyIndex].value, _in, n[1]); + readValue(vertexProperties_[propertyIndex].value, _in, n[1]); break; case ZNORM: - readValue(vertexPropertyMap_[propertyIndex].value, _in, n[2]); + readValue(vertexProperties_[propertyIndex].value, _in, n[2]); break; case TEXX: - readValue(vertexPropertyMap_[propertyIndex].value, _in, t[0]); + readValue(vertexProperties_[propertyIndex].value, _in, t[0]); break; case TEXY: - readValue(vertexPropertyMap_[propertyIndex].value, _in, t[1]); + readValue(vertexProperties_[propertyIndex].value, _in, t[1]); break; case COLORRED: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { - readValue(vertexPropertyMap_[propertyIndex].value, _in, tmp); + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { + readValue(vertexProperties_[propertyIndex].value, _in, tmp); c[0] = static_cast (tmp * 255.0f); } else - readInteger(vertexPropertyMap_[propertyIndex].value, _in, c[0]); + readInteger(vertexProperties_[propertyIndex].value, _in, c[0]); break; case COLORGREEN: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { - readValue(vertexPropertyMap_[propertyIndex].value, _in, tmp); + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { + readValue(vertexProperties_[propertyIndex].value, _in, tmp); c[1] = static_cast (tmp * 255.0f); } else - readInteger(vertexPropertyMap_[propertyIndex].value, _in, c[1]); + readInteger(vertexProperties_[propertyIndex].value, _in, c[1]); break; case COLORBLUE: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { - readValue(vertexPropertyMap_[propertyIndex].value, _in, tmp); + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { + readValue(vertexProperties_[propertyIndex].value, _in, tmp); c[2] = static_cast (tmp * 255.0f); } else - readInteger(vertexPropertyMap_[propertyIndex].value, _in, c[2]); + readInteger(vertexProperties_[propertyIndex].value, _in, c[2]); break; case COLORALPHA: - if (vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT32 || - vertexPropertyMap_[propertyIndex].value == ValueTypeFLOAT) { - readValue(vertexPropertyMap_[propertyIndex].value, _in, tmp); + if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 || + vertexProperties_[propertyIndex].value == ValueTypeFLOAT) { + readValue(vertexProperties_[propertyIndex].value, _in, tmp); c[3] = static_cast (tmp * 255.0f); } else - readInteger(vertexPropertyMap_[propertyIndex].value, _in, c[3]); + readInteger(vertexProperties_[propertyIndex].value, _in, c[3]); break; default: // Read unsupported property - consume_input(_in, scalar_size_[vertexPropertyMap_[propertyIndex].value]); + consume_input(_in, scalar_size_[vertexProperties_[propertyIndex].value]); break; } @@ -502,28 +564,31 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap _bi.set_color(vh, Vec4uc(c)); } - for (i = 0; i < faceCount_; ++i) { + if(!faceProperties_.empty()) + { + for (i = 0; i < faceCount_; ++i) { // Read number of vertices for the current face - readValue(faceIndexType_, _in, nV); + readValue(faceProperties_[0].listIndexType, _in, nV); if (nV == 3) { - vhandles.resize(3); - readInteger(faceEntryType_, _in, j); - readInteger(faceEntryType_, _in, k); - readInteger(faceEntryType_, _in, l); + vhandles.resize(3); + readInteger(faceProperties_[0].value, _in, j); + readInteger(faceProperties_[0].value, _in, k); + readInteger(faceProperties_[0].value, _in, l); - vhandles[0] = VertexHandle(j); - vhandles[1] = VertexHandle(k); - vhandles[2] = VertexHandle(l); + vhandles[0] = VertexHandle(j); + vhandles[1] = VertexHandle(k); + vhandles[2] = VertexHandle(l); } else { - vhandles.clear(); - for (j = 0; j < nV; ++j) { - readInteger(faceEntryType_, _in, idx); - vhandles.push_back(VertexHandle(idx)); - } + vhandles.clear(); + for (j = 0; j < nV; ++j) { + readInteger(faceProperties_[0].value, _in, idx); + vhandles.push_back(VertexHandle(idx)); + } } _bi.add_face(vhandles); + } } return true; @@ -909,9 +974,9 @@ bool _PLYReader_::can_u_read(std::istream& _is) const { // Clear per file options options_.cleanup(); - // clear vertex property map, will be recreated - vertexPropertyMap_.clear(); - vertexPropertyCount_ = 0; + // clear property maps, will be recreated + vertexProperties_.clear(); + faceProperties_.clear(); // read 1st line std::string line; @@ -985,134 +1050,157 @@ bool _PLYReader_::can_u_read(std::istream& _is) const { _is >> tmp1; if (tmp1 == "list") { - if (elementName == "vertex") { - omerr() << "List type not supported for vertices!" << std::endl; - } else if (elementName == "face") { - _is >> listIndexType; - _is >> listEntryType; - _is >> propertyName; + _is >> listIndexType; + _is >> listEntryType; + _is >> propertyName; - if (listIndexType == "uint8") { - faceIndexType_ = ValueTypeUINT8; - } else if (listIndexType == "uchar") { - faceIndexType_ = ValueTypeUCHAR; - } else { - omerr() << "Unsupported Index type for face list: " << listIndexType << std::endl; - return false; - } + ValueType indexType = Unsupported; + ValueType entryType = Unsupported; - if (listEntryType == "int32") { - faceEntryType_ = ValueTypeINT32; - } else if (listEntryType == "int") { - faceEntryType_ = ValueTypeINT; - } else if (listEntryType == "uint32") { - faceEntryType_ = ValueTypeUINT32; - } else if (listEntryType == "uint") { - faceEntryType_ = ValueTypeUINT; - } else { - omerr() << "Unsupported Entry type for face list: " << listEntryType << std::endl; - return false; + if (listIndexType == "uint8") { + indexType = ValueTypeUINT8; + } else if (listIndexType == "uchar") { + indexType = ValueTypeUCHAR; + } else { + omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl; + continue; + } + + 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; + + // just 2 elements supported by now + if (elementName == "vertex" && !options_.is_binary()) + { + vertexProperties_.push_back(property); + } + else if (elementName == "face") + { + // special case for vertex indices, also needed by the binary version + if (propertyName == "vertex_index" || propertyName == "vertex_indices") + { + property.property = VERTEX_INDICES; + if (!faceProperties_.empty()) + { + omerr() << "Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl; + faceProperties_.clear(); } + faceProperties_.push_back(property); + }else + { + if (!options_.is_binary()) + faceProperties_.push_back(property); + else + omerr() << "Custom list properties per face not supported with binary files" << std::endl; + } } + else + omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl; + } else { - // as this is not a list property, read second value of property - _is >> tmp2; + // as this is not a list property, read second value of property + _is >> tmp2; - if (elementName == "vertex") { - // 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); - if (propertyName == "x") { - VertexPropertyInfo entry(XCOORD, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - vertexDimension_++; - } else if (propertyName == "y") { - VertexPropertyInfo entry(YCOORD, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - vertexDimension_++; - } else if (propertyName == "z") { - VertexPropertyInfo entry(ZCOORD, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - vertexDimension_++; - } else if (propertyName == "nx") { - VertexPropertyInfo entry(XNORM, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexNormal; - } else if (propertyName == "ny") { - VertexPropertyInfo entry(YNORM, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexNormal; - } else if (propertyName == "nz") { - VertexPropertyInfo entry(ZNORM, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexNormal; - } else if (propertyName == "u" || propertyName == "s") { - VertexPropertyInfo entry(TEXX, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexTexCoord; - } else if (propertyName == "v" || propertyName == "t") { - VertexPropertyInfo entry(TEXY, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexTexCoord; - } else if (propertyName == "red") { - VertexPropertyInfo entry(COLORRED, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "green") { - VertexPropertyInfo entry(COLORGREEN, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "blue") { - VertexPropertyInfo entry(COLORBLUE, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_red") { - VertexPropertyInfo entry(COLORRED, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_green") { - VertexPropertyInfo entry(COLORGREEN, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "diffuse_blue") { - VertexPropertyInfo entry(COLORBLUE, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else if (propertyName == "alpha") { - VertexPropertyInfo entry(COLORALPHA, valueType); - vertexPropertyMap_[vertexPropertyCount_] = entry; - options_ += Options::VertexColor; - options_ += Options::ColorAlpha; - if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32) - options_ += Options::ColorFloat; - } else { - VertexProperty prop = (!options_.is_binary()) ? CUSTOM_PROP : UNSUPPORTED; // loading vertex properties is not yet supported by the binary loader - if (prop != UNSUPPORTED) - options_ += Options::Custom; - VertexPropertyInfo entry(prop, valueType, propertyName); - vertexPropertyMap_[vertexPropertyCount_] = entry; - } + // 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); - vertexPropertyCount_++; + PropertyInfo entry; - } else if (elementName == "face") { - omerr() << "Properties not supported for faces " << std::endl; + //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; } + } + + //not a special property, load as custom + if (entry.value == Unsupported){ + Property prop = (!options_.is_binary()) ? CUSTOM_PROP : UNSUPPORTED; // loading vertex properties is not yet supported by the binary loader + if (prop != UNSUPPORTED) + options_ += Options::Custom; + else + omerr() << "Custom Properties not supported in binary files. Skipping" << std::endl; + PropertyInfo entry(prop, valueType, propertyName); + vertexProperties_.push_back(entry); + } + + if (entry.property != UNSUPPORTED) + { + if (elementName == "vertex") + vertexProperties_.push_back(entry); + else if (elementName == "face") + faceProperties_.push_back(entry); + else + omerr() << "Properties not supported in element " << elementName << std::endl; + } } diff --git a/src/OpenMesh/Core/IO/reader/PLYReader.hh b/src/OpenMesh/Core/IO/reader/PLYReader.hh index 0658e135..7045b745 100644 --- a/src/OpenMesh/Core/IO/reader/PLYReader.hh +++ b/src/OpenMesh/Core/IO/reader/PLYReader.hh @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -92,7 +93,8 @@ class BaseImporter; /** Implementation of the PLY format reader. This class is singleton'ed by - SingletonT to OFFReader. + SingletonT to OFFReader. It can read custom properties, accessible via the name + of the custom properties. List properties has the type std::vector. */ @@ -136,7 +138,8 @@ private: bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const; float readToFloatValue(ValueType _type , std::fstream& _in) const; - void readCustomProperty(std::istream& _in, BaseImporter& _bi, VertexHandle _vh, const std::string& _propName, const ValueType _valueType) const; + template + void readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listIndexType) const; void readValue(ValueType _type , std::istream& _in, float& _value) const; void readValue(ValueType _type, std::istream& _in, double& _value) const; @@ -165,14 +168,11 @@ private: mutable ValueType vertexType_; mutable uint vertexDimension_; - mutable ValueType faceIndexType_; - mutable ValueType faceEntryType_; - - enum VertexProperty { + enum Property { XCOORD,YCOORD,ZCOORD, TEXX,TEXY, COLORRED,COLORGREEN,COLORBLUE,COLORALPHA, - XNORM,YNORM,ZNORM, CUSTOM_PROP, + XNORM,YNORM,ZNORM, CUSTOM_PROP, VERTEX_INDICES, UNSUPPORTED }; @@ -180,17 +180,18 @@ private: mutable std::map scalar_size_; // Number of vertex properties - mutable unsigned int vertexPropertyCount_; - struct VertexPropertyInfo + struct PropertyInfo { - VertexProperty property; + Property property; ValueType value; std::string name;//for custom properties - VertexPropertyInfo():property(UNSUPPORTED),value(Unsupported),name(""){} - VertexPropertyInfo(VertexProperty _p, ValueType _v):property(_p),value(_v),name(""){} - VertexPropertyInfo(VertexProperty _p, ValueType _v, const std::string& _n):property(_p),value(_v),name(_n){} + ValueType listIndexType;//if type is unsupported, the poerty is not a list. otherwise, it the index type + PropertyInfo():property(UNSUPPORTED),value(Unsupported),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v):property(_p),value(_v),name(""),listIndexType(Unsupported){} + PropertyInfo(Property _p, ValueType _v, const std::string& _n):property(_p),value(_v),name(_n),listIndexType(Unsupported){} }; - mutable std::map< int , VertexPropertyInfo > vertexPropertyMap_; + mutable std::vector< PropertyInfo > vertexProperties_; + mutable std::vector< PropertyInfo > faceProperties_; }; diff --git a/src/Unittests/TestFiles/cube-minimal-custom_props.ply b/src/Unittests/TestFiles/cube-minimal-custom_props.ply index 5a94a0b2..38e00701 100644 --- a/src/Unittests/TestFiles/cube-minimal-custom_props.ply +++ b/src/Unittests/TestFiles/cube-minimal-custom_props.ply @@ -9,20 +9,22 @@ property float32 ny property float32 nz property float32 quality property uint index +property list uint8 int32 test_values element face 6 property list uint8 int32 vertex_indices +property list uint8 float32 texcoords end_header --1 -1 -1 0.0 0.0 1.0 1.0 0 -1 -1 -1 0.0 1.0 0.0 0.5 1 -1 1 -1 0.0 1.0 1.0 0.7 2 --1 1 -1 1.0 0.0 0.0 1.0 3 --1 -1 1 1.0 0.0 1.0 0.1 4 -1 -1 1 1.0 1.0 0.0 0.0 5 -1 1 1 1.0 1.0 1.0 2.0 6 --1 1 1 1.0 1.0 2.0 5.0 7 -4 0 1 2 3 -4 5 4 7 6 -4 6 2 1 5 -4 3 7 4 0 -4 7 3 2 6 -4 5 1 0 4 +-1 -1 -1 0.0 0.0 1.0 1.0 0 2 1 2 +1 -1 -1 0.0 1.0 0.0 0.5 1 2 3 4 +1 1 -1 0.0 1.0 1.0 0.7 2 2 5 6 +-1 1 -1 1.0 0.0 0.0 1.0 3 2 7 8 +-1 -1 1 1.0 0.0 1.0 0.1 4 2 9 10 +1 -1 1 1.0 1.0 0.0 0.0 5 2 11 12 +1 1 1 1.0 1.0 1.0 2.0 6 2 13 14 +-1 1 1 1.0 1.0 2.0 5.0 7 2 15 16 +4 0 1 2 3 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 +4 5 4 7 6 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 +4 6 2 1 5 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 +4 3 7 4 0 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 +4 7 3 2 6 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 +4 5 1 0 4 8 1.0 1.0 -1.0 -1.0 0.0 0.0 -0.5 -0.5 diff --git a/src/Unittests/unittests_read_write_PLY.cc b/src/Unittests/unittests_read_write_PLY.cc index 1f176a0c..4a4a1799 100644 --- a/src/Unittests/unittests_read_write_PLY.cc +++ b/src/Unittests/unittests_read_write_PLY.cc @@ -445,37 +445,86 @@ TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithNormals) { */ TEST_F(OpenMeshReadWritePLY, LoadSimplePLYWithCustomProps) { - mesh_.clear(); + PolyMesh mesh; OpenMesh::IO::Options options; options += OpenMesh::IO::Options::Custom; - bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-custom_props.ply", options); + bool ok = OpenMesh::IO::read_mesh(mesh, "cube-minimal-custom_props.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(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!"; - EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!"; + 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; - EXPECT_TRUE(mesh_.get_property_handle(qualityProp,"quality")) << "Could not access quality property"; - EXPECT_TRUE(mesh_.get_property_handle(indexProp,"index")) << "Could not access index property"; + EXPECT_TRUE(mesh.get_property_handle(qualityProp,"quality")) << "Could not access quality property"; + EXPECT_TRUE(mesh.get_property_handle(indexProp,"index")) << "Could not access index property"; + + if (!mesh.get_property_handle(qualityProp,"quality")) + return; + + if (!mesh.get_property_handle(indexProp,"index")) + return; //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"; + 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"; + 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; + EXPECT_TRUE(mesh.get_property_handle(testValues,"test_values")) << "Could not access texcoords per face"; + if (!mesh.get_property_handle(testValues,"test_values")) + return; + + 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; + EXPECT_TRUE(mesh.get_property_handle(texCoordsPerFace,"texcoords")) << "Could not access texcoords per face"; + + if (!mesh.get_property_handle(texCoordsPerFace,"texcoords")) + return; + + 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(); + } + + } + + } }