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:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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_;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user