Commit d8d26b7c authored by Matthias Möller's avatar Matthias Möller

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
parent eed151aa
......@@ -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;
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<T> PropT;
};
template<typename T>
struct Handle2Prop<T,FaceHandle>
{
typedef OpenMesh::FPropHandleT<T> PropT;
};
void _PLYReader_::readCustomProperty(std::istream& _in, BaseImporter& _bi, VertexHandle _vh, const std::string& _propName, const ValueType _valueType) const
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,_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;
}
}
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,12 +396,17 @@ 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) {
// 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<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,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[0] = VertexHandle(j);
vhandles[1] = VertexHandle(k);
vhandles[2] = VertexHandle(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);
} 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;
if (listIndexType == "uint8") {
faceIndexType_ = ValueTypeUINT8;
} else if (listIndexType == "uchar") {
faceIndexType_ = ValueTypeUCHAR;
} else {
omerr() << "Unsupported Index type for face list: " << listIndexType << std::endl;
return false;
}
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;
}
_is >> listIndexType;
_is >> listEntryType;
_is >> propertyName;
ValueType indexType = Unsupported;
ValueType entryType = Unsupported;
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 {
// 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;
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;
}
vertexPropertyCount_++;
}
else
omerr() << "property " << propertyName << " belongs to unsupported element " << elementName << std::endl;
} else if (elementName == "face") {
omerr() << "Properties not supported for faces " << std::endl;
} 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;