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

add custom property (with pod data type) support for binary ply files

closes #2496

git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@1331 fdac6126-5c0c-442c-9429-916003d36597
parent e9290b46
......@@ -65,7 +65,7 @@ ASCII is not a real option and will be selected, if binary was not defined.
\li defined with vc (e.g. used by meshlab)
\li colors encoded in a vertex line (v followed by 6 values)
\**) only ascii version and only vertex and face properties with fundamental types. Take into account, that you don't have to request these custom properties before loading.
\**) only vertex and face properties with fundamental types. Take into account, that you don't have to request these custom properties before loading.
\***) no reader exists
......
This diff is collapsed.
......@@ -70,6 +70,7 @@
#include <OpenMesh/Core/System/config.h>
#include <OpenMesh/Core/Utils/SingletonT.hh>
#include <OpenMesh/Core/IO/reader/BaseReader.hh>
#include <OpenMesh/Core/Utils/GenProg.hh>
#ifndef WIN32
#include <string.h>
......@@ -138,13 +139,15 @@ private:
bool read_binary(std::istream& _in, BaseImporter& _bi, bool swap, const Options& _opt) const;
float readToFloatValue(ValueType _type , std::fstream& _in) 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;
void readValue(ValueType _type , std::istream& _in, double& _value) const;
void readValue(ValueType _type , std::istream& _in, unsigned int& _value) const;
void readValue(ValueType _type , std::istream& _in, unsigned short& _value) const;
void readValue(ValueType _type , std::istream& _in, unsigned char& _value) const;
void readValue(ValueType _type , std::istream& _in, int& _value) const;
void readValue(ValueType _type , std::istream& _in, short& _value) const;
void readValue(ValueType _type , std::istream& _in, signed char& _value) const;
void readInteger(ValueType _type, std::istream& _in, int& _value) const;
void readInteger(ValueType _type, std::istream& _in, unsigned int& _value) const;
......@@ -193,6 +196,24 @@ private:
mutable std::vector< PropertyInfo > vertexProperties_;
mutable std::vector< PropertyInfo > faceProperties_;
template<typename T>
inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::TrueType /*_binary*/) const
{
readValue(_type, _in, _value);
}
template<typename T>
inline void read(_PLYReader_::ValueType _type, std::istream& _in, T& _value, OpenMesh::GenProg::FalseType /*_binary*/) const
{
_in >> _value;
}
//read and assign custom properties with the given type. Also creates property, if not exist
template<bool binary, typename T, typename Handle>
void readCreateCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const ValueType _valueType, const ValueType _listType) const;
template<bool binary, typename Handle>
void readCustomProperty(std::istream& _in, BaseImporter& _bi, Handle _h, const std::string& _propName, const _PLYReader_::ValueType _valueType, const _PLYReader_::ValueType _listIndexType) const;
};
......
......@@ -242,25 +242,25 @@ std::vector<_PLYWriter_::CustomProperty> _PLYWriter_::writeCustomTypeHeader(std:
//-----------------------------------------------------------------------------
void _PLYWriter_::write_customProp_ascii(std::ostream& _out, const CustomProperty& _prop, size_t _index) const
template<bool binary>
void _PLYWriter_::write_customProp(std::ostream& _out, const CustomProperty& _prop, size_t _index) const
{
if (_prop.type == ValueTypeCHAR)
_out << " " << castProperty<signed char>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<signed char>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeUCHAR || _prop.type == ValueTypeUINT8)
_out << " " << castProperty<unsigned char>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<unsigned char>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeSHORT)
_out << " " << castProperty<signed short>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<signed short>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeUSHORT)
_out << " " << castProperty<unsigned short>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<unsigned short>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeUINT)
_out << " " << castProperty<unsigned int>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<unsigned int>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeINT || _prop.type == ValueTypeINT32)
_out << " " << castProperty<signed int>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<signed int>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeFLOAT || _prop.type == ValueTypeFLOAT32)
_out << " " << castProperty<float>(_prop.property)->data()[_index] ;
writeProxy(_prop.type,_out, castProperty<float>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
else if (_prop.type == ValueTypeDOUBLE)
_out << " " << castProperty<double>(_prop.property)->data()[_index];
writeProxy(_prop.type,_out, castProperty<double>(_prop.property)->data()[_index], OpenMesh::GenProg::Bool2Type<binary>());
}
......@@ -317,14 +317,12 @@ void _PLYWriter_::write_header(std::ostream& _out, BaseExporter& _be, Options& _
}
}
if (!_opt.is_binary()) // binary not supported yet
_ovProps = writeCustomTypeHeader(_out, _be.kernel()->vprops_begin(), _be.kernel()->vprops_end());
_ovProps = writeCustomTypeHeader(_out, _be.kernel()->vprops_begin(), _be.kernel()->vprops_end());
_out << "element face " << _be.n_faces() << '\n';
_out << "property list uchar int vertex_indices" << '\n';
if (!_opt.is_binary()) // binary not supported yet
_ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end());
_ofProps = writeCustomTypeHeader(_out, _be.kernel()->fprops_begin(), _be.kernel()->fprops_end());
_out << "end_header" << '\n';
}
......@@ -403,7 +401,7 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
// write custom properties for vertices
for (std::vector<CustomProperty>::iterator iter = vProps.begin(); iter < vProps.end(); ++iter)
write_customProp_ascii(_out,*iter,i);
write_customProp<false>(_out,*iter,i);
_out << "\n";
}
......@@ -419,7 +417,7 @@ write_ascii(std::ostream& _out, BaseExporter& _be, Options _opt) const
// write custom props
for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
write_customProp_ascii(_out,*iter,i);
write_customProp<false>(_out,*iter,i);
_out << "\n";
}
......@@ -490,6 +488,78 @@ void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, float value) c
}
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, double value) const {
double_t tmp;
switch (_type) {
case ValueTypeDOUBLE:
tmp = value;
store( _out , tmp, options_.check(Options::MSB) );
break;
default :
std::cerr << "unsupported conversion type to float: " << _type << std::endl;
break;
}
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, signed char value) const{
int8_t tmp;
switch (_type) {
case ValueTypeCHAR:
tmp = value;
store(_out, tmp, options_.check(Options::MSB) );
break;
default :
std::cerr << "unsupported conversion type to int: " << _type << std::endl;
break;
}
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned char value) const{
uint8_t tmp;
switch (_type) {
case ValueTypeUCHAR:
tmp = value;
store(_out, tmp, options_.check(Options::MSB) );
break;
default :
std::cerr << "unsupported conversion type to int: " << _type << std::endl;
break;
}
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, short value) const{
int16_t tmp;
switch (_type) {
case ValueTypeSHORT:
tmp = value;
store(_out, tmp, options_.check(Options::MSB) );
break;
default :
std::cerr << "unsupported conversion type to int: " << _type << std::endl;
break;
}
}
void _PLYWriter_::writeValue(ValueType _type, std::ostream& _out, unsigned short value) const{
uint16_t tmp;
switch (_type) {
case ValueTypeUSHORT:
tmp = value;
store(_out, tmp, options_.check(Options::MSB) );
break;
default :
std::cerr << "unsupported conversion type to int: " << _type << std::endl;
break;
}
}
bool
_PLYWriter_::
write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
......@@ -555,53 +625,22 @@ write_binary(std::ostream& _out, BaseExporter& _be, Options _opt) const
writeValue(ValueTypeUCHAR, _out, (int)c[3]);
}
}
}
// faces (indices starting at 0)
if (_be.is_triangle_mesh())
{
for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
{
//face
_be.get_vhandles(FaceHandle(i), vhandles);
writeValue(ValueTypeUINT8, _out, 3);
writeValue(ValueTypeINT32, _out, vhandles[0].idx());
writeValue(ValueTypeINT32, _out, vhandles[1].idx());
writeValue(ValueTypeINT32, _out, vhandles[2].idx());
// //face color
// if ( _opt.face_has_color() ){
// c = _be.colorA( FaceHandle(i) );
// writeValue(_out, c[0]);
// writeValue(_out, c[1]);
// writeValue(_out, c[2]);
//
// if ( _opt.color_has_alpha() )
// writeValue(_out, c[3]);
// }
}
for (std::vector<CustomProperty>::iterator iter = vProps.begin(); iter < vProps.end(); ++iter)
write_customProp<true>(_out,*iter,i);
}
else
for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
{
for (i=0, nF=int(_be.n_faces()); i<nF; ++i)
{
//face
nV = _be.get_vhandles(FaceHandle(i), vhandles);
writeValue(ValueTypeUINT8, _out, nV);
for (size_t j=0; j<vhandles.size(); ++j)
writeValue(ValueTypeINT32, _out, vhandles[j].idx() );
// //face color
// if ( _opt.face_has_color() ){
// c = _be.colorA( FaceHandle(i) );
// writeValue(_out, c[0]);
// writeValue(_out, c[1]);
// writeValue(_out, c[2]);
//
// if ( _opt.color_has_alpha() )
// writeValue(_out, c[3]);
// }
}
//face
nV = _be.get_vhandles(FaceHandle(i), vhandles);
writeValue(ValueTypeUINT8, _out, nV);
for (size_t j=0; j<vhandles.size(); ++j)
writeValue(ValueTypeINT32, _out, vhandles[j].idx() );
for (std::vector<CustomProperty>::iterator iter = fProps.begin(); iter < fProps.end(); ++iter)
write_customProp<true>(_out,*iter,i);
}
return true;
......
......@@ -70,6 +70,7 @@
#include <OpenMesh/Core/Utils/SingletonT.hh>
#include <OpenMesh/Core/IO/exporter/BaseExporter.hh>
#include <OpenMesh/Core/IO/writer/BaseWriter.hh>
#include <OpenMesh/Core/Utils/GenProg.hh>
//== NAMESPACES ===============================================================
......@@ -132,12 +133,28 @@ private:
/// write custom persistant properties into the header for the current element, returns all properties, which were written sorted
std::vector<CustomProperty> writeCustomTypeHeader(std::ostream& _out, BaseKernel::const_prop_iterator _begin, BaseKernel::const_prop_iterator _end) const;
void write_customProp_ascii(std::ostream& _our, const CustomProperty& _prop, size_t _index) const;
template<bool binary>
void write_customProp(std::ostream& _our, const CustomProperty& _prop, size_t _index) const;
template<typename T>
void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::TrueType /*_binary*/) const
{
writeValue(_type, _out, _value);
}
template<typename T>
void writeProxy(ValueType _type, std::ostream& _out, T _value, OpenMesh::GenProg::FalseType /*_binary*/) const
{
_out << " " << _value;
}
protected:
void writeValue(ValueType _type, std::ostream& _out, signed char value) const;
void writeValue(ValueType _type, std::ostream& _out, unsigned char value) const;
void writeValue(ValueType _type, std::ostream& _out, short value) const;
void writeValue(ValueType _type, std::ostream& _out, unsigned short value) const;
void writeValue(ValueType _type, std::ostream& _out, int value) const;
void writeValue(ValueType _type, std::ostream& _out, unsigned int value) const;
void writeValue(ValueType _type, std::ostream& _out, float value) const;
void writeValue(ValueType _type, std::ostream& _out, double value) const;
bool write_ascii(std::ostream& _out, BaseExporter&, Options) const;
bool write_binary(std::ostream& _out, BaseExporter&, Options) const;
......
......@@ -606,5 +606,90 @@ TEST_F(OpenMeshReadWritePLY, WriteReadSimplePLYWithCustomProps) {
remove(outFilename);
}
TEST_F(OpenMeshReadWritePLY, WriteReadBinaryPLYWithCustomProps) {
PolyMesh mesh;
OpenMesh::IO::Options options;
bool ok = OpenMesh::IO::read_mesh(mesh, "cube-minimal.ply", options);
OpenMesh::VPropHandleT<unsigned short> indexProp;
OpenMesh::VPropHandleT<unsigned int> nonPersistant;
OpenMesh::VPropHandleT<double> qualityProp;
OpenMesh::FPropHandleT<signed int> faceProp;
OpenMesh::VPropHandleT<int> removedProp;
const std::string indexPropName = "mySuperIndexProperty";
const std::string qualityPropName = "quality";
const std::string facePropName = "anotherPropForFaces";
const std::string nonPersistantName = "nonPersistant";
const std::string removedPropName = "willBeRemoved";
mesh.add_property(indexProp,indexPropName);
mesh.add_property(qualityProp,qualityPropName);
mesh.add_property(removedProp, removedPropName);
mesh.add_property(faceProp,facePropName);
mesh.add_property(nonPersistant,nonPersistantName);
mesh.property(indexProp).set_persistent(true);
mesh.property(qualityProp).set_persistent(true);
mesh.property(faceProp).set_persistent(true);
mesh.remove_property(removedProp);
signed char i=0;
for (Mesh::VertexIter v_iter = mesh.vertices_begin(); v_iter != mesh.vertices_end(); ++v_iter, ++i)
{
mesh.property(indexProp, *v_iter) = i;
mesh.property(qualityProp, *v_iter) = 3.5*i;
}
i = 0;
for (Mesh::FaceIter f_iter = mesh.faces_begin(); f_iter != mesh.faces_end(); ++f_iter, ++i)
{
mesh.property(faceProp, *f_iter) = -i;
}
const char* outFilename = "cube-minimal-customprops_openmeshOutputTestfileBinary.ply";
options += OpenMesh::IO::Options::Binary;
ok = OpenMesh::IO::write_mesh(mesh, outFilename, options);
ASSERT_TRUE(ok);
PolyMesh loadedMesh;
EXPECT_FALSE(loadedMesh.get_property_handle(indexProp,indexPropName)) << "Could access to property which was deleted";
options.clear();
options += OpenMesh::IO::Options::Custom;
options += OpenMesh::IO::Options::Binary;
ok = OpenMesh::IO::read_mesh(loadedMesh, outFilename, options);
ASSERT_TRUE(ok);
ASSERT_TRUE(loadedMesh.get_property_handle(indexProp,indexPropName)) << "Could not access index property";
ASSERT_TRUE(loadedMesh.get_property_handle(qualityProp,qualityPropName)) << "Could not access quality property";
ASSERT_TRUE(loadedMesh.get_property_handle(faceProp,facePropName)) << "Could not access face property";
EXPECT_FALSE(loadedMesh.get_property_handle(nonPersistant,nonPersistantName)) << "Could access non persistant property";
i=0;
for (Mesh::VertexIter v_iter = loadedMesh.vertices_begin(); v_iter != loadedMesh.vertices_end(); ++v_iter, ++i)
{
EXPECT_EQ(loadedMesh.property(indexProp, *v_iter), static_cast<unsigned>(i));
EXPECT_EQ(loadedMesh.property(qualityProp, *v_iter),3.5*i);
}
i = 0;
for (Mesh::FaceIter f_iter = loadedMesh.faces_begin(); f_iter != loadedMesh.faces_end(); ++f_iter, ++i)
{
EXPECT_EQ(loadedMesh.property(faceProp, *f_iter),-i);
}
//remove(outFilename);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment