56 #include <OpenMesh/Core/IO/reader/PLYReader.hh>
57 #include <OpenMesh/Core/IO/IOManager.hh>
58 #include <OpenMesh/Core/Utils/color_cast.hh>
87 _PLYReader_::_PLYReader_() {
115 std::fstream in(_filename.c_str(), (std::ios_base::binary | std::ios_base::in) );
117 if (!in.is_open() || !in.good()) {
118 omerr() <<
"[PLYReader] : cannot not open file " << _filename << std::endl;
122 bool result =
read(in, _bi, _opt);
134 omerr() <<
"[PLYReader] : cannot not use stream" << std::endl;
172 return (
options_.is_binary() ? read_binary(_in, _bi, swap, _opt) : read_ascii(_in, _bi, _opt));
176 template<
typename T,
typename Handle>
192 template<
bool binary,
typename T,
typename Handle>
193 void _PLYReader_::readCreateCustomProperty(std::istream& _in,
BaseImporter& _bi, Handle _h,
const std::string& _propName,
const _PLYReader_::ValueType _valueType,
const _PLYReader_::ValueType _listType)
const
195 if (_listType == Unsupported)
202 _bi.kernel()->
property(prop).set_persistent(
true);
207 read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type<binary>());
208 _bi.kernel()->
property(prop,_h) = in;
213 typename Handle2Prop<std::vector<T>,Handle>::PropT prop;
217 _bi.kernel()->
property(prop).set_persistent(
true);
222 read(_listType, _in, numberOfValues, OpenMesh::GenProg::Bool2Type<binary>());
224 vec.reserve(numberOfValues);
226 for (
int i = 0; i < numberOfValues; ++i)
229 read(_valueType, _in, in, OpenMesh::GenProg::Bool2Type<binary>());
232 _bi.kernel()->
property(prop,_h) = vec;
236 template<
bool binary,
typename Handle>
237 void _PLYReader_::readCustomProperty(std::istream& _in,
BaseImporter& _bi, Handle _h,
const std::string& _propName,
const _PLYReader_::ValueType _valueType,
const _PLYReader_::ValueType _listIndexType)
const
243 readCreateCustomProperty<binary,signed char>(_in,_bi,_h,_propName,_valueType,_listIndexType);
247 readCreateCustomProperty<binary,unsigned char>(_in,_bi,_h,_propName,_valueType,_listIndexType);
251 readCreateCustomProperty<binary,short>(_in,_bi,_h,_propName,_valueType,_listIndexType);
253 case ValueTypeUINT16:
254 case ValueTypeUSHORT:
255 readCreateCustomProperty<binary,unsigned short>(_in,_bi,_h,_propName,_valueType,_listIndexType);
259 readCreateCustomProperty<binary,int>(_in,_bi,_h,_propName,_valueType,_listIndexType);
261 case ValueTypeUINT32:
263 readCreateCustomProperty<binary,unsigned int>(_in,_bi,_h,_propName,_valueType,_listIndexType);
265 case ValueTypeFLOAT32:
267 readCreateCustomProperty<binary,float>(_in,_bi,_h,_propName,_valueType,_listIndexType);
269 case ValueTypeFLOAT64:
270 case ValueTypeDOUBLE:
271 readCreateCustomProperty<binary,double>(_in,_bi,_h,_propName,_valueType,_listIndexType);
274 std::cerr <<
"unsupported type" << std::endl;
282 bool _PLYReader_::read_ascii(std::istream& _in,
BaseImporter& _bi,
const Options& _opt)
const {
286 omerr() <<
"[PLYReader] : Unable to parse header\n";
290 unsigned int i, j, k, l, idx;
297 BaseImporter::VHandles vhandles;
300 _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_);
302 if (vertexDimension_ != 3) {
303 omerr() <<
"[PLYReader] : Only vertex dimension 3 is supported." << std::endl;
307 const bool err_enabled = omerr().is_enabled();
308 size_t complex_faces = 0;
313 for (i = 0; i < vertexCount_ && !_in.eof(); ++i) {
314 vh = _bi.add_vertex();
332 for (
size_t propertyIndex = 0; propertyIndex < vertexProperties_.size(); ++propertyIndex) {
333 switch (vertexProperties_[propertyIndex].property) {
359 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
360 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
362 c[0] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
367 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
368 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
370 c[1] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
375 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
376 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
378 c[2] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
383 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
384 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
386 c[3] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
392 readCustomProperty<false>(_in, _bi, vh, vertexProperties_[propertyIndex].name, vertexProperties_[propertyIndex].value, vertexProperties_[propertyIndex].listIndexType);
402 _bi.set_point(vh, v);
403 if (_opt.vertex_has_normal())
404 _bi.set_normal(vh, n);
405 if (_opt.vertex_has_texcoord())
406 _bi.set_texcoord(vh, t);
407 if (_opt.vertex_has_color())
408 _bi.set_color(vh,
Vec4uc(c));
412 for (i = 0; i < faceCount_; ++i) {
414 for (
size_t propertyIndex = 0; propertyIndex < faceProperties_.size(); ++propertyIndex) {
416 switch (prop.property) {
428 vhandles[0] = VertexHandle(j);
429 vhandles[1] = VertexHandle(k);
430 vhandles[2] = VertexHandle(l);
433 for (j = 0; j < nV; ++j) {
435 vhandles.push_back(VertexHandle(idx));
439 fh = _bi.add_face(vhandles);
446 readCustomProperty<false>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
463 omerr() << complex_faces <<
"The reader encountered invalid faces, that could not be added.\n";
471 bool _PLYReader_::read_binary(std::istream& _in,
BaseImporter& _bi,
bool ,
const Options& _opt)
const {
475 omerr() <<
"[PLYReader] : Unable to parse header\n";
481 BaseImporter::VHandles vhandles;
486 _bi.reserve(vertexCount_, 3* vertexCount_ , faceCount_);
488 const bool err_enabled = omerr().is_enabled();
489 size_t complex_faces = 0;
494 for (
unsigned int i = 0; i < vertexCount_ && !_in.eof(); ++i) {
495 vh = _bi.add_vertex();
513 for (
size_t propertyIndex = 0; propertyIndex < vertexProperties_.size(); ++propertyIndex) {
514 switch (vertexProperties_[propertyIndex].property) {
516 readValue(vertexProperties_[propertyIndex].value, _in, v[0]);
519 readValue(vertexProperties_[propertyIndex].value, _in, v[1]);
522 readValue(vertexProperties_[propertyIndex].value, _in, v[2]);
525 readValue(vertexProperties_[propertyIndex].value, _in, n[0]);
528 readValue(vertexProperties_[propertyIndex].value, _in, n[1]);
531 readValue(vertexProperties_[propertyIndex].value, _in, n[2]);
534 readValue(vertexProperties_[propertyIndex].value, _in, t[0]);
537 readValue(vertexProperties_[propertyIndex].value, _in, t[1]);
540 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
541 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
542 readValue(vertexProperties_[propertyIndex].value, _in, tmp);
544 c[0] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
546 readInteger(vertexProperties_[propertyIndex].value, _in, c[0]);
550 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
551 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
552 readValue(vertexProperties_[propertyIndex].value, _in, tmp);
553 c[1] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
555 readInteger(vertexProperties_[propertyIndex].value, _in, c[1]);
559 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
560 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
561 readValue(vertexProperties_[propertyIndex].value, _in, tmp);
562 c[2] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
564 readInteger(vertexProperties_[propertyIndex].value, _in, c[2]);
568 if (vertexProperties_[propertyIndex].value == ValueTypeFLOAT32 ||
569 vertexProperties_[propertyIndex].value == ValueTypeFLOAT) {
570 readValue(vertexProperties_[propertyIndex].value, _in, tmp);
571 c[3] =
static_cast<OpenMesh::Vec4i::value_type
> (tmp * 255.0f);
573 readInteger(vertexProperties_[propertyIndex].value, _in, c[3]);
578 readCustomProperty<true>(_in, _bi, vh, vertexProperties_[propertyIndex].name, vertexProperties_[propertyIndex].value, vertexProperties_[propertyIndex].listIndexType);
591 if (_opt.vertex_has_normal())
592 _bi.set_normal(vh, n);
593 if (_opt.vertex_has_texcoord())
594 _bi.set_texcoord(vh, t);
595 if (_opt.vertex_has_color())
596 _bi.set_color(vh,
Vec4uc(c));
599 for (
unsigned i = 0; i < faceCount_; ++i) {
601 for (
size_t propertyIndex = 0; propertyIndex < faceProperties_.size(); ++propertyIndex)
604 switch (prop.property) {
609 readInteger(prop.listIndexType, _in, nV);
614 readInteger(prop.value, _in, j);
615 readInteger(prop.value, _in, k);
616 readInteger(prop.value, _in, l);
618 vhandles[0] = VertexHandle(j);
619 vhandles[1] = VertexHandle(k);
620 vhandles[2] = VertexHandle(l);
623 for (
unsigned j = 0; j < nV; ++j) {
625 readInteger(prop.value, _in, idx);
626 vhandles.push_back(VertexHandle(idx));
630 fh = _bi.add_face(vhandles);
637 readCustomProperty<true>(_in, _bi, fh, prop.name, prop.value, prop.listIndexType);
653 omerr() << complex_faces <<
"The reader encountered invalid faces, that could not be added.\n";
663 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
float& _value)
const {
666 case ValueTypeFLOAT32:
674 std::cerr <<
"unsupported conversion type to float: " << _type << std::endl;
683 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
double& _value)
const {
687 case ValueTypeFLOAT64:
689 case ValueTypeDOUBLE:
700 std::cerr <<
"unsupported conversion type to double: " << _type << std::endl;
709 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
unsigned char& _value)
const{
711 readValue(_type,_in,tmp);
717 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
unsigned short& _value)
const{
719 readValue(_type,_in,tmp);
725 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
signed char& _value)
const{
727 readValue(_type,_in,tmp);
733 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
short& _value)
const{
735 readValue(_type,_in,tmp);
741 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
unsigned int& _value)
const {
751 case ValueTypeUINT32:
754 _value = tmp_uint32_t;
758 case ValueTypeUSHORT:
760 case ValueTypeUINT16:
763 _value = tmp_uint16_t;
779 std::cerr <<
"unsupported conversion type to unsigned int: " << _type << std::endl;
789 void _PLYReader_::readValue(ValueType _type, std::istream& _in,
int& _value)
const {
802 _value = tmp_int32_t;
811 _value = tmp_int16_t;
827 std::cerr <<
"unsupported conversion type to int: " << _type << std::endl;
837 void _PLYReader_::readInteger(ValueType _type, std::istream& _in,
int& _value)
const {
851 _value = tmp_int32_t;
857 case ValueTypeUINT32:
860 _value = tmp_uint32_t;
885 std::cerr <<
"unsupported conversion type to int: " << _type << std::endl;
895 void _PLYReader_::readInteger(ValueType _type, std::istream& _in,
unsigned int& _value)
const {
906 case ValueTypeUINT32:
909 _value = tmp_uint32_t;
918 _value = tmp_int32_t;
943 std::cerr <<
"unsupported conversion type to unsigned int: " << _type << std::endl;
959 std::ifstream ifs(_filename.c_str());
972 std::string get_property_name(std::string _string1, std::string _string2) {
974 if (_string1 ==
"float32" || _string1 ==
"float64" || _string1 ==
"float" || _string1 ==
"double" ||
975 _string1 ==
"int8" || _string1 ==
"uint8" || _string1 ==
"char" || _string1 ==
"uchar" ||
976 _string1 ==
"int32" || _string1 ==
"uint32" || _string1 ==
"int" || _string1 ==
"uint" ||
977 _string1 ==
"int16" || _string1 ==
"uint16" || _string1 ==
"short" || _string1 ==
"ushort")
980 if (_string2 ==
"float32" || _string2 ==
"float64" || _string2 ==
"float" || _string2 ==
"double" ||
981 _string2 ==
"int8" || _string2 ==
"uint8" || _string2 ==
"char" || _string2 ==
"uchar" ||
982 _string2 ==
"int32" || _string2 ==
"uint32" || _string2 ==
"int" || _string2 ==
"uint" ||
983 _string2 ==
"int16" || _string2 ==
"uint16" || _string2 ==
"short" || _string2 ==
"ushort")
987 std::cerr <<
"Unsupported entry type" << std::endl;
988 return "Unsupported";
993 _PLYReader_::ValueType get_property_type(std::string _string1, std::string _string2) {
995 if (_string1 ==
"float32" || _string2 ==
"float32")
997 return _PLYReader_::ValueTypeFLOAT32;
999 else if (_string1 ==
"float64" || _string2 ==
"float64")
1001 return _PLYReader_::ValueTypeFLOAT64;
1003 else if (_string1 ==
"float" || _string2 ==
"float")
1005 return _PLYReader_::ValueTypeFLOAT;
1007 else if (_string1 ==
"double" || _string2 ==
"double")
1009 return _PLYReader_::ValueTypeDOUBLE;
1011 else if (_string1 ==
"int8" || _string2 ==
"int8")
1013 return _PLYReader_::ValueTypeINT8;
1015 else if (_string1 ==
"uint8" || _string2 ==
"uint8")
1017 return _PLYReader_::ValueTypeUINT8;
1019 else if (_string1 ==
"char" || _string2 ==
"char")
1021 return _PLYReader_::ValueTypeCHAR;
1023 else if (_string1 ==
"uchar" || _string2 ==
"uchar")
1025 return _PLYReader_::ValueTypeUCHAR;
1027 else if (_string1 ==
"int32" || _string2 ==
"int32")
1029 return _PLYReader_::ValueTypeINT32;
1031 else if (_string1 ==
"uint32" || _string2 ==
"uint32")
1033 return _PLYReader_::ValueTypeUINT32;
1035 else if (_string1 ==
"int" || _string2 ==
"int")
1037 return _PLYReader_::ValueTypeINT;
1039 else if (_string1 ==
"uint" || _string2 ==
"uint")
1041 return _PLYReader_::ValueTypeUINT;
1043 else if (_string1 ==
"int16" || _string2 ==
"int16")
1045 return _PLYReader_::ValueTypeINT16;
1047 else if (_string1 ==
"uint16" || _string2 ==
"uint16")
1049 return _PLYReader_::ValueTypeUINT16;
1051 else if (_string1 ==
"short" || _string2 ==
"short")
1053 return _PLYReader_::ValueTypeSHORT;
1055 else if (_string1 ==
"ushort" || _string2 ==
"ushort")
1057 return _PLYReader_::ValueTypeUSHORT;
1059 return _PLYReader_::Unsupported;
1071 vertexProperties_.clear();
1072 faceProperties_.clear();
1076 std::getline(_is, line);
1080 const int s = line.size();
1081 if( s > 0 && line[s - 1] ==
'\r') line.resize(s - 1);
1084 if (line !=
"PLY" && line !=
"ply")
1089 vertexDimension_ = 0;
1091 std::string keyword;
1092 std::string fileType;
1093 std::string elementName =
"";
1094 std::string propertyName;
1095 std::string listIndexType;
1096 std::string listEntryType;
1104 omerr() <<
"Defect PLY header detected" << std::endl;
1108 if (fileType ==
"ascii") {
1110 }
else if (fileType ==
"binary_little_endian") {
1116 }
else if (fileType ==
"binary_big_endian") {
1123 omerr() <<
"Unsupported PLY format: " << fileType << std::endl;
1127 std::streamoff streamPos = _is.tellg();
1129 while (keyword !=
"end_header") {
1131 if (keyword ==
"comment") {
1132 std::getline(_is, line);
1133 }
else if (keyword ==
"element") {
1135 if (elementName ==
"vertex") {
1136 _is >> vertexCount_;
1137 }
else if (elementName ==
"face") {
1140 omerr() <<
"PLY header unsupported element type: " << elementName << std::endl;
1142 }
else if (keyword ==
"property") {
1149 if (tmp1 ==
"list") {
1150 _is >> listIndexType;
1151 _is >> listEntryType;
1152 _is >> propertyName;
1154 ValueType indexType = Unsupported;
1155 ValueType entryType = Unsupported;
1157 if (listIndexType ==
"uint8") {
1158 indexType = ValueTypeUINT8;
1159 }
else if (listIndexType ==
"uchar") {
1160 indexType = ValueTypeUCHAR;
1161 }
else if (listIndexType ==
"int") {
1162 indexType = ValueTypeINT;
1164 omerr() <<
"Unsupported Index type for property list: " << listIndexType << std::endl;
1168 entryType = get_property_type(listEntryType, listEntryType);
1170 if (entryType == Unsupported) {
1171 omerr() <<
"Unsupported Entry type for property list: " << listEntryType << std::endl;
1174 PropertyInfo property(CUSTOM_PROP, entryType, propertyName);
1175 property.listIndexType = indexType;
1178 if (elementName ==
"vertex")
1180 vertexProperties_.push_back(property);
1182 else if (elementName ==
"face")
1185 if (propertyName ==
"vertex_index" || propertyName ==
"vertex_indices")
1187 property.property = VERTEX_INDICES;
1188 if (!faceProperties_.empty())
1190 omerr() <<
"Custom face Properties defined, before 'vertex_indices' property was defined. They will be skipped" << std::endl;
1191 faceProperties_.clear();
1194 faceProperties_.push_back(property);
1198 omerr() <<
"property " << propertyName <<
" belongs to unsupported element " << elementName << std::endl;
1207 ValueType valueType = get_property_type(tmp1, tmp2);
1208 propertyName = get_property_name(tmp1, tmp2);
1213 if (elementName ==
"vertex") {
1214 if (propertyName ==
"x") {
1217 }
else if (propertyName ==
"y") {
1220 }
else if (propertyName ==
"z") {
1223 }
else if (propertyName ==
"nx") {
1226 }
else if (propertyName ==
"ny") {
1229 }
else if (propertyName ==
"nz") {
1232 }
else if (propertyName ==
"u" || propertyName ==
"s") {
1235 }
else if (propertyName ==
"v" || propertyName ==
"t") {
1238 }
else if (propertyName ==
"red") {
1241 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1243 }
else if (propertyName ==
"green") {
1246 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1248 }
else if (propertyName ==
"blue") {
1251 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1253 }
else if (propertyName ==
"diffuse_red") {
1256 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1258 }
else if (propertyName ==
"diffuse_green") {
1261 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1263 }
else if (propertyName ==
"diffuse_blue") {
1266 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1268 }
else if (propertyName ==
"alpha") {
1272 if (valueType == ValueTypeFLOAT || valueType == ValueTypeFLOAT32)
1278 if (entry.value == Unsupported){
1279 Property prop = CUSTOM_PROP;
1284 if (entry.property != UNSUPPORTED)
1286 if (elementName ==
"vertex")
1287 vertexProperties_.push_back(entry);
1288 else if (elementName ==
"face")
1289 faceProperties_.push_back(entry);
1291 omerr() <<
"Properties not supported in element " << elementName << std::endl;
1297 omlog() <<
"Unsupported keyword : " << keyword << std::endl;
1300 streamPos = _is.tellg();
1303 omerr() <<
"Error while reading PLY file header" << std::endl;
1311 _is.seekg(streamPos);
1318 if (c1 == 0x0D && c2 == 0x0A) {
1319 _is.seekg(streamPos + 14);
1322 _is.seekg(streamPos + 12);
void add_property(VPropHandleT< T > &_ph, const std::string &_name="<vprop>")
Options userOptions_
Options that the user wants to read.
Has (r) / store (w) vertex normals.
PropertyT< T > & property(VPropHandleT< T > _ph)
bool register_module(BaseReader *_bl)
Assume big endian byte ordering.
Has (r) / store (w) face colors.
Options options_
Available per file options for reading.
Has (r) / store (w) texture coordinates.
Set options for reader/writer modules.
_PLYReader_ __PLYReaderInstance
Declare the single entity of the PLY reader.
Handle for a vertex entity.
bool can_u_read(const std::string &_filename) const
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...
Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) ...
Handle for a face entity.
bool get_property_handle(VPropHandleT< T > &_ph, const std::string &_name) const
std::map< ValueType, int > scalar_size_
Stores sizes of property types.
bool read(const std::string &_filename, BaseImporter &_bi, Options &_opt)
void cleanup(void)
Restore state after default constructor.
Swap byte order in binary mode.
void clear(void)
Clear all bits.
Has (r) / store (w) vertex colors.
Assume little endian byte ordering.
Has (r) custom properties (currently only implemented in PLY Reader ASCII version) ...
Has (r) / store (w) alpha values for colors.
Cellection of information about a property.
void consume_input(std::istream &_in, int _count) const
Read unsupported properties in PLY file.
_IOManager_ & IOManager()
virtual bool can_u_read(const std::string &_filename) const
Returns true if writer can parse _filename (checks extension). _filename can also provide an extensio...