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
This commit is contained in:
Matthias Möller
2015-05-18 11:52:18 +00:00
parent eed151aa90
commit d8d26b7c18
4 changed files with 382 additions and 242 deletions

View File

@@ -175,49 +175,92 @@ bool _PLYReader_::read(std::istream& _in, BaseImporter& _bi, Options& _opt) {
}
template<typename T, typename Handle>
struct Handle2Prop;
template<typename T>
void assignCustomProperty(std::istream& _in, BaseImporter& _bi, VertexHandle _vh, const std::string& _propName)
struct Handle2Prop<T,VertexHandle>
{
OpenMesh::VPropHandleT<T> prop;
typedef OpenMesh::VPropHandleT<T> PropT;
};
template<typename T>
struct Handle2Prop<T,FaceHandle>
{
typedef OpenMesh::FPropHandleT<T> PropT;
};
template<typename T, typename Handle>
void assignCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, bool isList)
{
if (!isList)
{
//get/add property
typename Handle2Prop<T,Handle>::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,_vh) = in;
_bi.kernel()->property(prop,_h) = in;
}
else
{
//get/add property
typename Handle2Prop<std::vector<T>,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<T> 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<typename Handle>
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<char>(_in,_bi,_vh,_propName);
assignCustomProperty<char>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeINT16:
case ValueTypeSHORT:
assignCustomProperty<short>(_in,_bi,_vh,_propName);
assignCustomProperty<short>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeUINT16:
case ValueTypeUSHORT:
assignCustomProperty<unsigned short>(_in,_bi,_vh,_propName);
assignCustomProperty<unsigned short>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeINT32:
case ValueTypeINT:
assignCustomProperty<int>(_in,_bi,_vh,_propName);
assignCustomProperty<int>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeUINT32:
case ValueTypeUINT:
assignCustomProperty<unsigned int>(_in,_bi,_vh,_propName);
assignCustomProperty<unsigned int>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeFLOAT32:
case ValueTypeFLOAT:
assignCustomProperty<float>(_in,_bi,_vh,_propName);
assignCustomProperty<float>(_in,_bi,_h,_propName,isList);
break;
case ValueTypeFLOAT64:
case ValueTypeDOUBLE:
assignCustomProperty<double>(_in,_bi,_vh,_propName);
assignCustomProperty<double>(_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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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,8 +396,13 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options
}
// faces
// #N <v1> <v2> .. <v(n-1)> [color spec]
for (i = 0; i < faceCount_; ++i) {
FaceHandle fh;
for (size_t propertyIndex = 0; propertyIndex < faceProperties_.size(); ++propertyIndex) {
PropertyInfo prop = faceProperties_[propertyIndex];
switch (prop.property) {
case VERTEX_INDICES:
// nV = number of Vertices for current face
_in >> nV;
@@ -375,7 +423,21 @@ bool _PLYReader_::read_ascii(std::istream& _in, BaseImporter& _bi, const Options
}
}
_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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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<OpenMesh::Vec4i::value_type> (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,15 +564,17 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
_bi.set_color(vh, Vec4uc(c));
}
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);
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);
@@ -518,13 +582,14 @@ bool _PLYReader_::read_binary(std::istream& _in, BaseImporter& _bi, bool /*_swap
} else {
vhandles.clear();
for (j = 0; j < nV; ++j) {
readInteger(faceEntryType_, _in, idx);
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,133 +1050,156 @@ 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;
ValueType indexType = Unsupported;
ValueType entryType = Unsupported;
if (listIndexType == "uint8") {
faceIndexType_ = ValueTypeUINT8;
indexType = ValueTypeUINT8;
} else if (listIndexType == "uchar") {
faceIndexType_ = ValueTypeUCHAR;
indexType = ValueTypeUCHAR;
} else {
omerr() << "Unsupported Index type for face list: " << listIndexType << std::endl;
return false;
omerr() << "Unsupported Index type for property list: " << listIndexType << std::endl;
continue;
}
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;
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;
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);
PropertyInfo entry;
//special treatment for some vertex properties.
if (elementName == "vertex") {
if (propertyName == "x") {
VertexPropertyInfo entry(XCOORD, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(XCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "y") {
VertexPropertyInfo entry(YCOORD, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(YCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "z") {
VertexPropertyInfo entry(ZCOORD, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(ZCOORD, valueType);
vertexDimension_++;
} else if (propertyName == "nx") {
VertexPropertyInfo entry(XNORM, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(XNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "ny") {
VertexPropertyInfo entry(YNORM, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(YNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "nz") {
VertexPropertyInfo entry(ZNORM, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(ZNORM, valueType);
options_ += Options::VertexNormal;
} else if (propertyName == "u" || propertyName == "s") {
VertexPropertyInfo entry(TEXX, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(TEXX, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "v" || propertyName == "t") {
VertexPropertyInfo entry(TEXY, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(TEXY, valueType);
options_ += Options::VertexTexCoord;
} else if (propertyName == "red") {
VertexPropertyInfo entry(COLORRED, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "green") {
VertexPropertyInfo entry(COLORGREEN, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "blue") {
VertexPropertyInfo entry(COLORBLUE, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_red") {
VertexPropertyInfo entry(COLORRED, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORRED, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_green") {
VertexPropertyInfo entry(COLORGREEN, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORGREEN, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "diffuse_blue") {
VertexPropertyInfo entry(COLORBLUE, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORBLUE, valueType);
options_ += Options::VertexColor;
if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
options_ += Options::ColorFloat;
} else if (propertyName == "alpha") {
VertexPropertyInfo entry(COLORALPHA, valueType);
vertexPropertyMap_[vertexPropertyCount_] = entry;
entry = PropertyInfo(COLORALPHA, valueType);
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;
}
}
vertexPropertyCount_++;
//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);
}
} else if (elementName == "face") {
omerr() << "Properties not supported for faces " << std::endl;
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;
}
}

View File

@@ -65,6 +65,7 @@
#include <string>
#include <stdio.h>
#include <fstream>
#include <vector>
#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/Utils/SingletonT.hh>
@@ -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<Type>.
*/
@@ -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<typename Handle>
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<ValueType, int> 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_;
};

View File

@@ -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

View File

@@ -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<float> qualityProp;
OpenMesh::VPropHandleT<unsigned int> 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<int> > 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<float> > 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();
}
}
}
}