diff --git a/Doc/changelog.docu b/Doc/changelog.docu index 5b291fd1..e9720768 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -45,6 +45,7 @@
  • PLY Reader: Fix reading doubles from PLY, missing cast (Thanks to Leo Walsh for the patch)
  • PLY Reader: Some cleanup (Thanks to Morgan Leborgne for the patch)
  • PLY Reader: Support for ushort (Thanks to Morgan Leborgne for the patch)
  • +
  • OM Reader: Positions with scalar type double will be stored as doubles.
  • diff --git a/src/OpenMesh/Core/IO/OMFormat.cc b/src/OpenMesh/Core/IO/OMFormat.cc index 97175088..abebc177 100644 --- a/src/OpenMesh/Core/IO/OMFormat.cc +++ b/src/OpenMesh/Core/IO/OMFormat.cc @@ -246,6 +246,9 @@ namespace OMFormat { } + //----------------------------------------------------------------------------- + + } // namespace OMFormat // -------------------------------------------------------------------------- diff --git a/src/OpenMesh/Core/IO/OMFormat.hh b/src/OpenMesh/Core/IO/OMFormat.hh index 66aaf26a..0bc8e3da 100644 --- a/src/OpenMesh/Core/IO/OMFormat.hh +++ b/src/OpenMesh/Core/IO/OMFormat.hh @@ -289,7 +289,7 @@ namespace OMFormat { inline size_t chunk_header_size( void ) { return sizeof(uint16); } - /// Return the size of a scale in bytes. + /// Return the size of a scaler in bytes. inline size_t scalar_size( const Chunk::Header& _hdr ) { return _hdr.float_ ? (0x01 << _hdr.bits_) : (0x04 << _hdr.bits_); @@ -350,6 +350,16 @@ namespace OMFormat { #endif } + template bool is_double(const T&) + { + return false; + } + + template <> inline bool is_double(const double&) + { + return true; + } + template bool is_integer(const T) { #if defined(OM_MISSING_HEADER_LIMITS) diff --git a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh index 86290720..c60181ff 100644 --- a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh +++ b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -90,11 +90,15 @@ public: // get vertex data virtual Vec3f point(VertexHandle _vh) const = 0; + virtual Vec3d pointd(VertexHandle _vh) const = 0; + virtual bool is_point_double() const = 0; virtual Vec3f normal(VertexHandle _vh) const = 0; + virtual Vec3d normald(VertexHandle _vh) const = 0; + virtual bool is_normal_double() const = 0; virtual Vec3uc color(VertexHandle _vh) const = 0; virtual Vec4uc colorA(VertexHandle _vh) const = 0; - virtual Vec3ui colori(VertexHandle _vh) const = 0; - virtual Vec4ui colorAi(VertexHandle _vh) const = 0; + virtual Vec3ui colori(VertexHandle _vh) const = 0; + virtual Vec4ui colorAi(VertexHandle _vh) const = 0; virtual Vec3f colorf(VertexHandle _vh) const = 0; virtual Vec4f colorAf(VertexHandle _vh) const = 0; virtual Vec2f texcoord(VertexHandle _vh) const = 0; @@ -118,6 +122,7 @@ public: virtual unsigned int get_face_texcoords(std::vector& _hehandles) const = 0; virtual Vec3f normal(FaceHandle _fh) const = 0; + virtual Vec3d normald(FaceHandle _fh) const = 0; virtual Vec3uc color (FaceHandle _fh) const = 0; virtual Vec4uc colorA(FaceHandle _fh) const = 0; virtual Vec3ui colori(FaceHandle _fh) const = 0; diff --git a/src/OpenMesh/Core/IO/exporter/ExporterT.hh b/src/OpenMesh/Core/IO/exporter/ExporterT.hh index 9de326ca..8f9dde90 100644 --- a/src/OpenMesh/Core/IO/exporter/ExporterT.hh +++ b/src/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -65,6 +65,7 @@ #include #include #include +#include //=== NAMESPACES ============================================================== @@ -94,11 +95,33 @@ public: return vector_cast(mesh_.point(_vh)); } + Vec3d pointd(VertexHandle _vh) const override + { + return vector_cast(mesh_.point(_vh)); + } + + bool is_point_double() const override + { + return OMFormat::is_double(typename Mesh::Point()[0]); + } + + bool is_normal_double() const override + { + return OMFormat::is_double(typename Mesh::Normal()[0]); + } + Vec3f normal(VertexHandle _vh) const override { return (mesh_.has_vertex_normals() - ? vector_cast(mesh_.normal(_vh)) - : Vec3f(0.0f, 0.0f, 0.0f)); + ? vector_cast(mesh_.normal(_vh)) + : Vec3f(0.0f, 0.0f, 0.0f)); + } + + Vec3d normald(VertexHandle _vh) const override + { + return (mesh_.has_vertex_normals() + ? vector_cast(mesh_.normal(_vh)) + : Vec3d(0.0f, 0.0f, 0.0f)); } Vec3uc color(VertexHandle _vh) const override @@ -305,6 +328,13 @@ public: : Vec3f(0.0f, 0.0f, 0.0f)); } + Vec3d normald(FaceHandle _fh) const override + { + return (mesh_.has_face_normals() + ? vector_cast(mesh_.normal(_fh)) + : Vec3d(0.0, 0.0, 0.0)); + } + Vec3uc color(FaceHandle _fh) const override { return (mesh_.has_face_colors() diff --git a/src/OpenMesh/Core/IO/importer/BaseImporter.hh b/src/OpenMesh/Core/IO/importer/BaseImporter.hh index ff86dadd..53da0ed0 100644 --- a/src/OpenMesh/Core/IO/importer/BaseImporter.hh +++ b/src/OpenMesh/Core/IO/importer/BaseImporter.hh @@ -91,6 +91,9 @@ public: // add a vertex with coordinate \c _point virtual VertexHandle add_vertex(const Vec3f& _point) = 0; + // add a vertex with coordinate \c _point + virtual VertexHandle add_vertex(const Vec3d& _point) { return add_vertex(Vec3f(_point)); } + // add a vertex without coordinate. Use set_point to set the position deferred virtual VertexHandle add_vertex() = 0; @@ -122,6 +125,9 @@ public: // set vertex normal virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; + // set vertex normal + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) = 0; + // set vertex color virtual void set_color(VertexHandle _vh, const Vec3uc& _color) = 0; @@ -176,6 +182,9 @@ public: // set face normal virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; + // set face normal + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) = 0; + // set face color virtual void set_color(FaceHandle _fh, const Vec3uc& _color) = 0; diff --git a/src/OpenMesh/Core/IO/importer/ImporterT.hh b/src/OpenMesh/Core/IO/importer/ImporterT.hh index 50ee3192..93de5e1b 100644 --- a/src/OpenMesh/Core/IO/importer/ImporterT.hh +++ b/src/OpenMesh/Core/IO/importer/ImporterT.hh @@ -97,6 +97,11 @@ public: return mesh_.add_vertex(vector_cast(_point)); } + virtual VertexHandle add_vertex(const Vec3d& _point) override + { + return mesh_.add_vertex(vector_cast(_point)); + } + virtual VertexHandle add_vertex() override { return mesh_.new_vertex(); @@ -222,6 +227,17 @@ public: halfedgeNormals_[_vh] = vector_cast(_normal); } + virtual void set_normal(VertexHandle _vh, const Vec3d& _normal) override + { + if (mesh_.has_vertex_normals()) + mesh_.set_normal(_vh, vector_cast(_normal)); + + //saves normals for half edges. + //they will be written, when the face is added + if (mesh_.has_halfedge_normals()) + halfedgeNormals_[_vh] = vector_cast(_normal); + } + virtual void set_color(VertexHandle _vh, const Vec4uc& _color) override { if (mesh_.has_vertex_colors()) @@ -336,6 +352,12 @@ public: mesh_.set_normal(_fh, vector_cast(_normal)); } + virtual void set_normal(FaceHandle _fh, const Vec3d& _normal) override + { + if (mesh_.has_face_normals()) + mesh_.set_normal(_fh, vector_cast(_normal)); + } + virtual void set_color(FaceHandle _fh, const Vec3uc& _color) override { if (mesh_.has_face_colors()) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 41a4b3a9..66d4e819 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -297,6 +297,7 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, assert( chunk_header_.entity_ == Chunk::Entity_Vertex); OpenMesh::Vec3f v3f; + OpenMesh::Vec3d v3d; OpenMesh::Vec2f v2f; OpenMesh::Vec3uc v3uc; // rgb OpenMesh::Attributes::StatusInfo status; @@ -306,22 +307,57 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, size_t vidx = 0; switch (chunk_header_.type_) { case Chunk::Type_Pos: - assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); - for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { - bytes_ += vector_restore(_is, v3f, _swap); - _bi.add_vertex(v3f); + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + _bi.add_vertex(v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim())); + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3d, _swap); + _bi.add_vertex(v3d); + } + } + else + { + omerr() << "unknown Vector size" << std::endl; } break; case Chunk::Type_Normal: - assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); - fileOptions_ += Options::VertexNormal; - for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { - bytes_ += vector_restore(_is, v3f, _swap); - if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) - _bi.set_normal(VertexHandle(int(vidx)), v3f); + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); + + fileOptions_ += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) + _bi.set_normal(VertexHandle(int(vidx)), v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3d::dim())); + + fileOptions_ += Options::VertexNormal; + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += vector_restore(_is, v3d, _swap); + if (fileOptions_.vertex_has_normal() && _opt.vertex_has_normal()) + _bi.set_normal(VertexHandle(int(vidx)), v3d); + } + } + else + { + omerr() << "Unknown vertex normal format" << std::endl; } break; @@ -410,6 +446,7 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op size_t fidx = 0; OpenMesh::Vec3f v3f; // normal + OpenMesh::Vec3d v3d; // normal as double OpenMesh::Vec3uc v3uc; // rgb OpenMesh::Attributes::StatusInfo status; @@ -464,10 +501,26 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op assert( OMFormat::dimensions(chunk_header_) == size_t(OpenMesh::Vec3f::dim())); fileOptions_ += Options::FaceNormal; - for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { - bytes_ += vector_restore(_is, v3f, _swap); - if( fileOptions_.face_has_normal() && _opt.face_has_normal()) - _bi.set_normal(FaceHandle(int(fidx)), v3f); + + if (chunk_header_.bits_ == OMFormat::bits(0.0f)) // read floats + { + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3f, _swap); + if( fileOptions_.face_has_normal() && _opt.face_has_normal()) + _bi.set_normal(FaceHandle(int(fidx)), v3f); + } + } + else if (chunk_header_.bits_ == OMFormat::bits(0.0)) // read doubles + { + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += vector_restore(_is, v3d, _swap); + if( fileOptions_.face_has_normal() && _opt.face_has_normal()) + _bi.set_normal(FaceHandle(int(fidx)), v3d); + } + } + else + { + omerr() << "Unknown face normal format" << std::endl; } break; diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index c7a601d6..78dfd6d3 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -81,7 +81,7 @@ _OMWriter_& OMWriter() { return __OMWriterInstance; } const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; -const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,0); +const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,1); _OMWriter_:: @@ -181,6 +181,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, unsigned int i, nV, nF; Vec3f v; + Vec3d vd; Vec2f t; // -------------------- write header @@ -211,14 +212,28 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, chunk_header.name_ = false; chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; chunk_header.type_ = OMFormat::Chunk::Type_Pos; - chunk_header.signed_ = OMFormat::is_signed(v[0]); - chunk_header.float_ = OMFormat::is_float(v[0]); - chunk_header.dim_ = OMFormat::dim(v); - chunk_header.bits_ = OMFormat::bits(v[0]); + if (_be.is_point_double()) + { + chunk_header.signed_ = OMFormat::is_signed(vd[0]); + chunk_header.float_ = OMFormat::is_float(vd[0]); + chunk_header.dim_ = OMFormat::dim(vd); + chunk_header.bits_ = OMFormat::bits(vd[0]); + } + else + { + chunk_header.signed_ = OMFormat::is_signed(v[0]); + chunk_header.float_ = OMFormat::is_float(v[0]); + chunk_header.dim_ = OMFormat::dim(v); + chunk_header.bits_ = OMFormat::bits(v[0]); + } bytes += store( _os, chunk_header, swap ); - for (i=0, nV=header.n_vertices_; istore(_os, swap ); } diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index e138f4cd..35e4522d 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -1472,4 +1472,41 @@ TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_7_5) { EXPECT_FALSE(ok) << file_name; } + +/* + * Try to write and load positions and normals that can only be represented by doubles + */ +TEST_F(OpenMeshReadWriteOM, WriteAndLoadDoubles) { + + typedef OpenMesh::PolyMesh_ArrayKernelT DoublePolyMesh; + + DoublePolyMesh mesh; + mesh.request_vertex_normals(); + mesh.request_face_normals(); + + std::vector vertices; + for (int i = 0; i < 3; ++i) + { + vertices.push_back(mesh.add_vertex(DoublePolyMesh::Point(1.0/3.0, std::numeric_limits::min(), std::numeric_limits::max()))); + mesh.set_normal(vertices.back(), DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits::min(), std::numeric_limits::max())); + } + auto fh = mesh.add_face(vertices); + mesh.set_normal(fh, DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits::min(), std::numeric_limits::max())); + + std::string file_name = "doubles.om"; + + OpenMesh::IO::Options opt = OpenMesh::IO::Options::VertexNormal | OpenMesh::IO::Options::FaceNormal; + ASSERT_TRUE(OpenMesh::IO::write_mesh(mesh, file_name, opt)) << "Could not write file " << file_name; + + DoublePolyMesh mesh2; + mesh2.request_vertex_normals(); + mesh2.request_face_normals(); + + ASSERT_TRUE(OpenMesh::IO::read_mesh(mesh2, file_name, opt)) << "Could not read file " << file_name; + + EXPECT_EQ(mesh.point(OpenMesh::VertexHandle(0)), mesh2.point(OpenMesh::VertexHandle(0))); + EXPECT_EQ(mesh.normal(OpenMesh::VertexHandle(0)), mesh2.normal(OpenMesh::VertexHandle(0))); + EXPECT_EQ(mesh.normal(OpenMesh::FaceHandle(0)), mesh2.normal(OpenMesh::FaceHandle(0))); +} + }