From 84eccff6a64a3749c0d01ff1f8a9b84d050c74cc Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 7 Aug 2018 14:03:51 +0200 Subject: [PATCH 01/24] add another test for custom edge property storing and loading --- src/Unittests/unittests_read_write_OM.cc | 105 ++++++++++++++++++++++- 1 file changed, 102 insertions(+), 3 deletions(-) diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index 4d33486e..b20e845d 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -464,11 +464,11 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) { Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1); Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2); - int va1ue1 = 10, + int value1 = 10, value2 = 21, value3 = 32; - mesh.property(prop,e1) = va1ue1; + mesh.property(prop,e1) = value1; mesh.property(prop,e2) = value2; mesh.property(prop,e3) = value3; @@ -494,7 +494,7 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) { EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1"; EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2"; - EXPECT_EQ(va1ue1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0"; + EXPECT_EQ(value1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0"; EXPECT_EQ(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1"; EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2"; @@ -503,6 +503,105 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) { } +/* + * Save and load simple mesh with custom property + */ +TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleEdgeIntProperty) { + + Mesh mesh; + + const std::string propName = "EIProp"; + const std::string filename = std::string("triangle-minimal-")+propName+".om"; + + // generate data + Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0)); + Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0)); + Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0)); + auto fh0 = mesh.add_face(v1,v2,v3); + auto c = mesh.calc_face_centroid(fh0); + Mesh::VertexHandle v4 = mesh.add_vertex(c); + mesh.split(fh0, v4); + + + OpenMesh::EPropHandleT prop; + mesh.add_property(prop,propName); + mesh.property(prop).set_persistent(true); + + Mesh::EdgeHandle e1 = Mesh::EdgeHandle(0); + Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1); + Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2); + Mesh::EdgeHandle e4 = Mesh::EdgeHandle(3); + Mesh::EdgeHandle e5 = Mesh::EdgeHandle(4); + Mesh::EdgeHandle e6 = Mesh::EdgeHandle(5); + + int value1 = 10, + value2 = 21, + value3 = 32, + value4 = 43, + value5 = 54, + value6 = 65; + + mesh.property(prop,e1) = value1; + mesh.property(prop,e2) = value2; + mesh.property(prop,e3) = value3; + mesh.property(prop,e4) = value4; + mesh.property(prop,e5) = value5; + mesh.property(prop,e6) = value6; + + // save + OpenMesh::IO::Options options; + bool ok = OpenMesh::IO::write_mesh(mesh,filename); + EXPECT_TRUE(ok) << "Unable to write "< Date: Wed, 8 Aug 2018 10:54:46 +0200 Subject: [PATCH 02/24] update om file format verision to 2.0 --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index 9c32282f..bb9910d0 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -86,7 +86,7 @@ _OMWriter_& OMWriter() { return __OMWriterInstance; } const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; -const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(1,2); +const OMFormat::uint8 _OMWriter_::version_ = OMFormat::mk_version(2,0); _OMWriter_:: From b511128131ad23c5ac4985dd789a52479534295e Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 8 Aug 2018 10:55:44 +0200 Subject: [PATCH 03/24] add methods to exporter for accessing halfedges for vertices and faces and for accessing next halfface, incident vertex and incident face for halfedges --- src/OpenMesh/Core/IO/exporter/BaseExporter.hh | 8 ++++++ src/OpenMesh/Core/IO/exporter/ExporterT.hh | 25 +++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh index 477d95a1..39de363f 100644 --- a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh +++ b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -110,6 +110,14 @@ public: virtual unsigned int get_vhandles(FaceHandle _fh, std::vector& _vhandles) const=0; + + // information needed for a halfedge based data structure such as OpenMesh + virtual int get_halfedge_id(VertexHandle _vh) = 0; + virtual int get_halfedge_id(FaceHandle _vh) = 0; + virtual int get_next_halfedge_id(HalfedgeHandle _heh) = 0; + virtual int get_to_vertex_id(HalfedgeHandle _heh) = 0; + virtual int get_face_id(HalfedgeHandle _heh) = 0; + /// /// \brief getHeh returns the HalfEdgeHandle that belongs to the face /// specified by _fh and has a toVertexHandle that corresponds to _vh. diff --git a/src/OpenMesh/Core/IO/exporter/ExporterT.hh b/src/OpenMesh/Core/IO/exporter/ExporterT.hh index 9a9d9b3f..15c6defe 100644 --- a/src/OpenMesh/Core/IO/exporter/ExporterT.hh +++ b/src/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -230,6 +230,31 @@ public: return count; } + int get_halfedge_id(VertexHandle _vh) override + { + return mesh_.halfedge_handle(_vh).idx(); + } + + int get_halfedge_id(FaceHandle _fh) override + { + return mesh_.halfedge_handle(_fh).idx(); + } + + int get_next_halfedge_id(HalfedgeHandle _heh) override + { + return mesh_.next_halfedge_handle(_heh).idx(); + } + + int get_to_vertex_id(HalfedgeHandle _heh) override + { + return mesh_.to_vertex_handle(_heh).idx(); + } + + int get_face_id(HalfedgeHandle _heh) override + { + return mesh_.face_handle(_heh).idx(); + } + unsigned int get_face_texcoords(std::vector& _hehandles) const { unsigned int count(0); From 95fceb4545624a20c11176a4eb4dec552c9c9836 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 8 Aug 2018 10:58:13 +0200 Subject: [PATCH 04/24] write halfedge based mesh information to file --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 66 +++++++++++++++++++------ 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index bb9910d0..2de4ef73 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -184,7 +184,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); - unsigned int i, nV, nF; + unsigned int i, nV, nE, nF; Vec3f v; Vec2f t; std::vector vhandles; @@ -286,6 +286,49 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, } + // ---------- wirte halfedge data + if (_be.n_edges()) + { + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge; + chunk_header.type_ = OMFormat::Chunk::Type_Topology; + chunk_header.signed_ = true; + chunk_header.float_ = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think? + chunk_header.dim_ = OMFormat::Chunk::Dim_3D; + chunk_header.bits_ = OMFormat::needed_bits(std::max(_be.n_edges()*2, std::max(_be.n_vertices(), _be.n_faces()))); + + bytes += store( _os, chunk_header, swap ); + for (i=0, nE=header.n_edges_*2; i(i))); + auto to_vertex_id = _be.get_to_vertex_id(HalfedgeHandle(static_cast(i))); + auto face_id = _be.get_face_id(HalfedgeHandle(static_cast(i))); + + bytes += store( _os, next_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap ); + bytes += store( _os, to_vertex_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap ); + bytes += store( _os, face_id, OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap ); + } + } + + // ---------- write vertex topology (outgoing halfedge) + if (_be.n_vertices()) + { + chunk_header.reserved_ = 0; + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Topology; + chunk_header.signed_ = true; + chunk_header.float_ = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think? + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::needed_bits(_be.n_edges()*2); + + bytes += store( _os, chunk_header, swap ); + for (i=0, nV=header.n_vertices_; i Date: Wed, 8 Aug 2018 10:58:51 +0200 Subject: [PATCH 05/24] add methods to importer to create a mesh based on halfedges --- src/OpenMesh/Core/IO/importer/BaseImporter.hh | 15 ++++++++++ src/OpenMesh/Core/IO/importer/ImporterT.hh | 28 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/OpenMesh/Core/IO/importer/BaseImporter.hh b/src/OpenMesh/Core/IO/importer/BaseImporter.hh index afcfd6ca..c1331e7d 100644 --- a/src/OpenMesh/Core/IO/importer/BaseImporter.hh +++ b/src/OpenMesh/Core/IO/importer/BaseImporter.hh @@ -99,10 +99,16 @@ public: // add a vertex without coordinate. Use set_point to set the position deferred virtual VertexHandle add_vertex() = 0; + // add an edge. Use set_next, set_vertex and set_face to set corresponding entities for halfedges + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) = 0; + // add a face with indices _indices refering to vertices typedef std::vector VHandles; virtual FaceHandle add_face(const VHandles& _indices) = 0; + // add a face with incident halfedge + virtual FaceHandle add_face(HalfedgeHandle _heh) = 0; + // add texture coordinates per face, _vh references the first texcoord virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) = 0; @@ -115,6 +121,9 @@ public: // Set coordinate of the given vertex. Use this function, if you created a vertex without coordinate virtual void set_point(VertexHandle _vh, const Vec3f& _point) = 0; + // Set outgoing halfedge for the given vertex. + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) = 0; + // set vertex normal virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; @@ -133,6 +142,12 @@ public: // set vertex texture coordinate virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + // set next halfedge handle + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) = 0; + + // set incident face handle for given halfedge + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) = 0; + // set vertex texture coordinate virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0; diff --git a/src/OpenMesh/Core/IO/importer/ImporterT.hh b/src/OpenMesh/Core/IO/importer/ImporterT.hh index fb6b6690..48744a36 100644 --- a/src/OpenMesh/Core/IO/importer/ImporterT.hh +++ b/src/OpenMesh/Core/IO/importer/ImporterT.hh @@ -107,6 +107,11 @@ public: return mesh_.new_vertex(); } + virtual HalfedgeHandle add_edge(VertexHandle _vh0, VertexHandle _vh1) override + { + return mesh_.new_edge(_vh0, _vh1); + } + virtual FaceHandle add_face(const VHandles& _indices) { FaceHandle fh; @@ -192,6 +197,13 @@ public: return fh; } + virtual FaceHandle add_face(HalfedgeHandle _heh) override + { + auto fh = mesh_.new_face(); + mesh_.set_halfedge_handle(fh, _heh); + return fh; + } + // vertex attributes virtual void set_point(VertexHandle _vh, const Vec3f& _point) @@ -199,6 +211,11 @@ public: mesh_.set_point(_vh,vector_cast(_point)); } + virtual void set_halfedge(VertexHandle _vh, HalfedgeHandle _heh) override + { + mesh_.set_halfedge_handle(_vh, _heh); + } + virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) { if (mesh_.has_vertex_normals()) @@ -240,6 +257,17 @@ public: mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); } + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) override + { + mesh_.set_next_halfedge_handle(_heh, _next); + } + + virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) override + { + mesh_.set_face_handle(_heh, _fh); + } + + virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) { if (mesh_.has_halfedge_texcoords2D()) From 76607e4ec6c3ef8b5a8a4280d47c2a78a6f18745 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 8 Aug 2018 10:59:51 +0200 Subject: [PATCH 06/24] read meshes based on halfedge information --- src/OpenMesh/Core/IO/reader/OMReader.cc | 110 +++++++++++++++++++----- 1 file changed, 87 insertions(+), 23 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index b66684eb..2db0dc93 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -351,6 +351,19 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, break; + case Chunk::Type_Topology: + { + for (; vidx < header_.n_vertices_; ++vidx) + { + int halfedge_id; + bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + _bi.set_halfedge(VertexHandle(static_cast(vidx)), HalfedgeHandle(halfedge_id)); + } + } + + break; + default: // skip unknown chunks { omerr() << "Unknown chunk type ignored!\n"; @@ -378,32 +391,48 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op OpenMesh::Vec3uc v3uc; // rgb switch (chunk_header_.type_) { - case Chunk::Type_Topology: { - BaseImporter::VHandles vhandles; - size_t nV = 0; - size_t vidx = 0; + case Chunk::Type_Topology: + { + if (header_.version_ < OMFormat::mk_version(2,0)) + { + // add faces based on vertex indices + BaseImporter::VHandles vhandles; + size_t nV = 0; + size_t vidx = 0; - switch (header_.mesh_) { - case 'T': - nV = 3; - break; - case 'Q': - nV = 4; - break; - } - - for (; fidx < header_.n_faces_; ++fidx) { - if (header_.mesh_ == 'P') - bytes_ += restore(_is, nV, Chunk::Integer_16, _swap); - - vhandles.clear(); - for (size_t j = 0; j < nV; ++j) { - bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap); - - vhandles.push_back(VertexHandle(int(vidx))); + switch (header_.mesh_) { + case 'T': + nV = 3; + break; + case 'Q': + nV = 4; + break; } - _bi.add_face(vhandles); + for (; fidx < header_.n_faces_; ++fidx) { + if (header_.mesh_ == 'P') + bytes_ += restore(_is, nV, Chunk::Integer_16, _swap); + + vhandles.clear(); + for (size_t j = 0; j < nV; ++j) { + bytes_ += restore(_is, vidx, Chunk::Integer_Size(chunk_header_.bits_), _swap); + + vhandles.push_back(VertexHandle(int(vidx))); + } + + _bi.add_face(vhandles); + } + } + else + { + // add faces by simple setting an incident face + for (; fidx < header_.n_faces_; ++fidx) + { + int halfedge_id; + bytes_ += restore( _is, halfedge_id, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + _bi.add_face(HalfedgeHandle(halfedge_id)); + } } } break; @@ -495,6 +524,41 @@ bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap); break; + case Chunk::Type_Topology: + { + std::vector next_halfedges; + for (size_t e_idx = 0; e_idx < header_.n_edges_; ++e_idx) + { + int next_id_0; + int to_vertex_id_0; + int face_id_0; + bytes_ += restore( _is, next_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, to_vertex_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, face_id_0, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + int next_id_1; + int to_vertex_id_1; + int face_id_1; + bytes_ += restore( _is, next_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, to_vertex_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + bytes_ += restore( _is, face_id_1, OMFormat::Chunk::Integer_Size(chunk_header_.bits_), _swap ); + + auto heh0 = _bi.add_edge(VertexHandle(to_vertex_id_1), VertexHandle(to_vertex_id_0)); + auto heh1 = HalfedgeHandle(heh0.idx() + 1); + + next_halfedges.push_back(HalfedgeHandle(next_id_0)); + next_halfedges.push_back(HalfedgeHandle(next_id_1)); + + _bi.set_face(heh0, FaceHandle(face_id_0)); + _bi.set_face(heh1, FaceHandle(face_id_1)); + } + + for (size_t i = 0; i < next_halfedges.size(); ++i) + _bi.set_next(HalfedgeHandle(static_cast(i)), next_halfedges[i]); + } + + break; + default: // skip unknown chunk omerr() << "Unknown chunk type ignored!\n"; From 4142d5f4def2e45791860f9fa6b9b7c75d95ec09 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 8 Aug 2018 11:09:24 +0200 Subject: [PATCH 07/24] fix warnings --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index 2de4ef73..9037c7f7 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -184,11 +184,9 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, bool swap = _opt.check(Options::Swap) || (Endian::local() == Endian::MSB); - unsigned int i, nV, nE, nF; + unsigned int i, nV, nF; Vec3f v; Vec2f t; - std::vector vhandles; - // -------------------- write header OMFormat::Header header; @@ -299,7 +297,8 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, chunk_header.bits_ = OMFormat::needed_bits(std::max(_be.n_edges()*2, std::max(_be.n_vertices(), _be.n_faces()))); bytes += store( _os, chunk_header, swap ); - for (i=0, nE=header.n_edges_*2; i(i))); auto to_vertex_id = _be.get_to_vertex_id(HalfedgeHandle(static_cast(i))); @@ -345,7 +344,6 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, for (i=0, nF=header.n_faces_; i Date: Wed, 8 Aug 2018 11:38:42 +0200 Subject: [PATCH 08/24] fix wrong number of written bits for meshes with between 2^15 and 2^16 halfedges --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index 9037c7f7..f91a59cc 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -294,7 +294,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, chunk_header.signed_ = true; chunk_header.float_ = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think? chunk_header.dim_ = OMFormat::Chunk::Dim_3D; - chunk_header.bits_ = OMFormat::needed_bits(std::max(_be.n_edges()*2, std::max(_be.n_vertices(), _be.n_faces()))); + chunk_header.bits_ = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness bytes += store( _os, chunk_header, swap ); auto nE=header.n_edges_*2; @@ -320,7 +320,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, chunk_header.signed_ = true; chunk_header.float_ = true; // TODO: is this correct? This causes a scalar size of 1 in OMFormat.hh scalar_size which we need I think? chunk_header.dim_ = OMFormat::Chunk::Dim_1D; - chunk_header.bits_ = OMFormat::needed_bits(_be.n_edges()*2); + chunk_header.bits_ = OMFormat::needed_bits(_be.n_edges()*4); // *2 due to halfedge ids being stored, *2 due to signedness bytes += store( _os, chunk_header, swap ); for (i=0, nV=header.n_vertices_; i Date: Wed, 8 Aug 2018 12:05:57 +0200 Subject: [PATCH 09/24] store status --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index f91a59cc..b48cd0d2 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -426,7 +426,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->vprops_end(); ++prop) { if ( !*prop ) continue; - if ( (*prop)->name()[1]==':') continue; + if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "v:status")) continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Vertex, swap ); } @@ -434,7 +434,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->fprops_end(); ++prop) { if ( !*prop ) continue; - if ( (*prop)->name()[1]==':') continue; + if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "f:status")) continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Face, swap ); } @@ -442,7 +442,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->eprops_end(); ++prop) { if ( !*prop ) continue; - if ( (*prop)->name()[1]==':') continue; + if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "e:status")) continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Edge, swap ); } @@ -450,7 +450,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->hprops_end(); ++prop) { if ( !*prop ) continue; - if ( (*prop)->name()[1]==':') continue; + if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "h:status")) continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Halfedge, swap ); } From bc2fe37aeb57122dac6d7c99dcd0ed23768fb594 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 8 Aug 2018 12:05:24 +0200 Subject: [PATCH 10/24] add test to check if status is correctly written to file and loaded from file --- src/Unittests/unittests_read_write_OM.cc | 187 +++++++++++++++++++++++ 1 file changed, 187 insertions(+) diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index b20e845d..336be479 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -602,6 +602,193 @@ TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleEdgeIntProperty) { } +/* + * Save and load simple mesh with status property + */ +TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleStatusProperties) { + + Mesh mesh; + + mesh.request_vertex_status(); + mesh.request_edge_status(); + mesh.request_halfedge_status(); + mesh.request_face_status(); + + const std::string filename = std::string("triangle-minimal-status.om"); + + // generate data + Mesh::VertexHandle v0 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0)); + Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0)); + Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0)); + auto fh0 = mesh.add_face(v0,v1,v2); + auto c = mesh.calc_face_centroid(fh0); + Mesh::VertexHandle v3 = mesh.add_vertex(c); + mesh.split(fh0, v3); + + mesh.delete_vertex(v0); + mesh.status(v1).set_selected(true); + mesh.status(v2).set_feature(true); + mesh.status(v3).set_tagged(true); + mesh.status(v2).set_tagged2(true); + + std::vector vertex_deleted; + std::vector vertex_selected; + std::vector vertex_feature; + std::vector vertex_tagged; + std::vector vertex_tagged2; + + for (auto vh : mesh.all_vertices()) + { + vertex_deleted.push_back(mesh.status(vh).deleted()); + vertex_selected.push_back(mesh.status(vh).selected()); + vertex_feature.push_back(mesh.status(vh).feature()); + vertex_tagged.push_back(mesh.status(vh).tagged()); + vertex_tagged2.push_back(mesh.status(vh).tagged2()); + } + + Mesh::EdgeHandle e1 = Mesh::EdgeHandle(0); + Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1); + Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2); + Mesh::EdgeHandle e4 = Mesh::EdgeHandle(3); + + mesh.status(e1).set_selected(true); + mesh.status(e2).set_feature(true); + mesh.status(e3).set_tagged(true); + mesh.status(e4).set_tagged2(true); + + std::vector edge_deleted; + std::vector edge_selected; + std::vector edge_feature; + std::vector edge_tagged; + std::vector edge_tagged2; + + for (auto eh : mesh.all_edges()) + { + edge_deleted.push_back(mesh.status(eh).deleted()); + edge_selected.push_back(mesh.status(eh).selected()); + edge_feature.push_back(mesh.status(eh).feature()); + edge_tagged.push_back(mesh.status(eh).tagged()); + edge_tagged2.push_back(mesh.status(eh).tagged2()); + } + + + Mesh::HalfedgeHandle he1 = Mesh::HalfedgeHandle(0); + Mesh::HalfedgeHandle he2 = Mesh::HalfedgeHandle(3); + Mesh::HalfedgeHandle he3 = Mesh::HalfedgeHandle(5); + Mesh::HalfedgeHandle he4 = Mesh::HalfedgeHandle(1); + + mesh.status(he1).set_selected(true); + mesh.status(he2).set_feature(true); + mesh.status(he3).set_tagged(true); + mesh.status(he4).set_tagged2(true); + + std::vector halfedge_deleted; + std::vector halfedge_selected; + std::vector halfedge_feature; + std::vector halfedge_tagged; + std::vector halfedge_tagged2; + + for (auto heh : mesh.all_halfedges()) + { + halfedge_deleted.push_back(mesh.status(heh).deleted()); + halfedge_selected.push_back(mesh.status(heh).selected()); + halfedge_feature.push_back(mesh.status(heh).feature()); + halfedge_tagged.push_back(mesh.status(heh).tagged()); + halfedge_tagged2.push_back(mesh.status(heh).tagged2()); + } + + Mesh::FaceHandle f1 = Mesh::FaceHandle(0); + Mesh::FaceHandle f2 = Mesh::FaceHandle(2); + Mesh::FaceHandle f3 = Mesh::FaceHandle(1); + Mesh::FaceHandle f4 = Mesh::FaceHandle(2); + + mesh.status(f1).set_selected(true); + mesh.status(f2).set_feature(true); + mesh.status(f3).set_tagged(true); + mesh.status(f4).set_tagged2(true); + + std::vector face_deleted; + std::vector face_selected; + std::vector face_feature; + std::vector face_tagged; + std::vector face_tagged2; + + for (auto fh : mesh.all_faces()) + { + face_deleted.push_back(mesh.status(fh).deleted()); + face_selected.push_back(mesh.status(fh).selected()); + face_feature.push_back(mesh.status(fh).feature()); + face_tagged.push_back(mesh.status(fh).tagged()); + face_tagged2.push_back(mesh.status(fh).tagged2()); + } + + // save + OpenMesh::IO::Options options; + bool ok = OpenMesh::IO::write_mesh(mesh,filename); + EXPECT_TRUE(ok) << "Unable to write "< Date: Wed, 8 Aug 2018 13:58:02 +0200 Subject: [PATCH 11/24] store status slightly better --- src/OpenMesh/Core/IO/Options.hh | 7 ++- src/OpenMesh/Core/IO/exporter/BaseExporter.hh | 4 ++ src/OpenMesh/Core/IO/exporter/ExporterT.hh | 4 ++ src/OpenMesh/Core/IO/writer/OMWriter.cc | 60 +++++++++++++++++-- src/Unittests/unittests_read_write_OM.cc | 4 +- 5 files changed, 72 insertions(+), 7 deletions(-) diff --git a/src/OpenMesh/Core/IO/Options.hh b/src/OpenMesh/Core/IO/Options.hh index f2667258..a703273c 100644 --- a/src/OpenMesh/Core/IO/Options.hh +++ b/src/OpenMesh/Core/IO/Options.hh @@ -115,7 +115,8 @@ public: FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates ColorAlpha = 0x0800, ///< Has (r) / store (w) alpha values for colors ColorFloat = 0x1000, ///< Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files) - Custom = 0x2000 ///< Has (r) custom properties (currently only implemented in PLY Reader ASCII version) + Custom = 0x2000, ///< Has (r) custom properties (currently only implemented in PLY Reader ASCII version) + Status = 0x4000 ///< Has (r) / store (w) status properties }; public: @@ -206,10 +207,14 @@ public: bool vertex_has_normal() const { return check(VertexNormal); } bool vertex_has_color() const { return check(VertexColor); } bool vertex_has_texcoord() const { return check(VertexTexCoord); } + bool vertex_has_status() const { return check(Status); } bool edge_has_color() const { return check(EdgeColor); } + bool edge_has_status() const { return check(Status); } + bool halfedge_has_status() const { return check(Status); } bool face_has_normal() const { return check(FaceNormal); } bool face_has_color() const { return check(FaceColor); } bool face_has_texcoord() const { return check(FaceTexCoord); } + bool face_has_status() const { return check(Status); } bool color_has_alpha() const { return check(ColorAlpha); } bool color_is_float() const { return check(ColorFloat); } diff --git a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh index 39de363f..2c93e19c 100644 --- a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh +++ b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -158,10 +158,14 @@ public: virtual bool is_triangle_mesh() const { return false; } virtual bool has_vertex_normals() const { return false; } virtual bool has_vertex_colors() const { return false; } + virtual bool has_vertex_status() const { return false; } virtual bool has_vertex_texcoords() const { return false; } virtual bool has_edge_colors() const { return false; } + virtual bool has_edge_status() const { return false; } + virtual bool has_halfedge_status() const { return false; } virtual bool has_face_normals() const { return false; } virtual bool has_face_colors() const { return false; } + virtual bool has_face_status() const { return false; } }; diff --git a/src/OpenMesh/Core/IO/exporter/ExporterT.hh b/src/OpenMesh/Core/IO/exporter/ExporterT.hh index 15c6defe..0ea30e6e 100644 --- a/src/OpenMesh/Core/IO/exporter/ExporterT.hh +++ b/src/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -345,9 +345,13 @@ public: bool has_vertex_normals() const { return mesh_.has_vertex_normals(); } bool has_vertex_colors() const { return mesh_.has_vertex_colors(); } bool has_vertex_texcoords() const { return mesh_.has_vertex_texcoords2D(); } + bool has_vertex_status() const { return mesh_.has_vertex_status(); } bool has_edge_colors() const { return mesh_.has_edge_colors(); } + bool has_edge_status() const { return mesh_.has_edge_status(); } + bool has_halfedge_status() const { return mesh_.has_halfedge_status(); } bool has_face_normals() const { return mesh_.has_face_normals(); } bool has_face_colors() const { return mesh_.has_face_colors(); } + bool has_face_status() const { return mesh_.has_face_status(); } private: diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index b48cd0d2..cc12d73d 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -417,6 +417,58 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, #endif } + // ---------- write vertex status + if (_be.n_vertices() && _be.has_vertex_status() && _opt.check(Options::Status)) + { + //store status as costum property because that already works + auto prop = _be.kernel()->_get_vprop("v:status"); + assert(prop != nullptr); + bool persistent = prop->persistent(); + const_cast(prop)->set_persistent(true); + bytes += store_binary_custom_chunk(_os, *prop, + OMFormat::Chunk::Entity_Vertex, swap ); + const_cast(prop)->set_persistent(persistent); + } + + // ---------- write edge status + if (_be.n_edges() && _be.has_edge_status() && _opt.check(Options::Status)) + { + //store status as costum property because that already works + auto prop = _be.kernel()->_get_eprop("e:status"); + assert(prop != nullptr); + bool persistent = prop->persistent(); + const_cast(prop)->set_persistent(true); + bytes += store_binary_custom_chunk(_os, *prop, + OMFormat::Chunk::Entity_Edge, swap ); + const_cast(prop)->set_persistent(persistent); + } + + // ---------- write halfedge status + if (_be.n_edges() && _be.has_halfedge_status() && _opt.check(Options::Status)) + { + //store status as costum property because that already works + auto prop = _be.kernel()->_get_hprop("h:status"); + assert(prop != nullptr); + bool persistent = prop->persistent(); + const_cast(prop)->set_persistent(true); + bytes += store_binary_custom_chunk(_os, *prop, + OMFormat::Chunk::Entity_Halfedge, swap ); + const_cast(prop)->set_persistent(persistent); + } + + // ---------- write face status + if (_be.n_faces() && _be.has_face_status() && _opt.check(Options::Status)) + { + //store status as costum property because that already works + auto prop = _be.kernel()->_get_fprop("f:status"); + assert(prop != nullptr); + bool persistent = prop->persistent(); + const_cast(prop)->set_persistent(true); + bytes += store_binary_custom_chunk(_os, *prop, + OMFormat::Chunk::Entity_Face, swap ); + const_cast(prop)->set_persistent(persistent); + } + // -------------------- write custom properties @@ -426,7 +478,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->vprops_end(); ++prop) { if ( !*prop ) continue; - if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "v:status")) continue; + if ( (*prop)->name()[1]==':') continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Vertex, swap ); } @@ -434,7 +486,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->fprops_end(); ++prop) { if ( !*prop ) continue; - if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "f:status")) continue; + if ( (*prop)->name()[1]==':') continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Face, swap ); } @@ -442,7 +494,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->eprops_end(); ++prop) { if ( !*prop ) continue; - if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "e:status")) continue; + if ( (*prop)->name()[1]==':') continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Edge, swap ); } @@ -450,7 +502,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, prop != _be.kernel()->hprops_end(); ++prop) { if ( !*prop ) continue; - if ( ((*prop)->name()[1]==':') && ((*prop)->name() != "h:status")) continue; + if ( (*prop)->name()[1]==':') continue; bytes += store_binary_custom_chunk(_os, **prop, OMFormat::Chunk::Entity_Halfedge, swap ); } diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index 336be479..899e86e5 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -723,8 +723,8 @@ TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleStatusProperties) { } // save - OpenMesh::IO::Options options; - bool ok = OpenMesh::IO::write_mesh(mesh,filename); + OpenMesh::IO::Options options = OpenMesh::IO::Options::Status; + bool ok = OpenMesh::IO::write_mesh(mesh,filename, options); EXPECT_TRUE(ok) << "Unable to write "< Date: Wed, 8 Aug 2018 14:38:07 +0200 Subject: [PATCH 12/24] fix typo --- src/OpenMesh/Core/IO/reader/OMReader.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 2db0dc93..00af3f73 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -425,7 +425,7 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op } else { - // add faces by simple setting an incident face + // add faces by simply setting an incident halfedge for (; fidx < header_.n_faces_; ++fidx) { int halfedge_id; From f6b106155f771758f1d363c95a9a044c6b73e1a6 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Fri, 12 Oct 2018 11:34:49 +0200 Subject: [PATCH 13/24] add unittests for writing and reading status information --- src/Unittests/unittests_read_write_OM.cc | 370 +++++++++++++++++++++++ 1 file changed, 370 insertions(+) diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index 899e86e5..92aaeed6 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -956,4 +956,374 @@ TEST_F(OpenMeshReadWriteOM, ReadBigMeshWithCustomProperty) { EXPECT_FALSE(wrong) << "min one vertex has worng vertex property"; } + +/* + * Save and load simple mesh with vertex status + */ +TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyVertexOnly) { + + //read file + Mesh mesh; + auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0)); + auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0)); + auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0)); + mesh.add_face(vh0, vh1, vh2); + + mesh.request_vertex_status(); + + mesh.status(vh0).set_selected(true); + mesh.status(vh1).set_feature(true); + mesh.status(vh2).set_tagged(true); + mesh.status(vh0).set_locked(true); + mesh.status(vh1).set_deleted(true); + mesh.status(vh2).set_hidden(true); + mesh.status(vh0).set_fixed_nonmanifold(true); + + + std::string filename_without_status = "no_vertex_status_test.om"; + std::string filename_with_status = "vertex_status_test.om"; + + OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status; + OpenMesh::IO::write_mesh(mesh, filename_without_status); + OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status); + + // Load no status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + } + + // Load status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status); + + EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh has no vertex status even though they should have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + if (loaded_mesh.has_vertex_status()) + { + for (auto vh : mesh.vertices()) + { + EXPECT_EQ(mesh.status(vh).bits(), loaded_mesh.status(vh).bits()); + } + } + } + + // Load no status from file with status + { + Mesh loaded_mesh; + loaded_mesh.request_vertex_status(); + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh vertex status was removed by reading"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + for (auto vh : loaded_mesh.vertices()) + { + EXPECT_EQ(loaded_mesh.status(vh).bits(), 0u) << "Vertex status was modified even though it should not have been loaded"; + } + } + + // Try to load status from file without status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status"; + } +} + + +/* + * Save and load simple mesh with halfedge status + */ +TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyHalfedgeOnly) { + + //read file + Mesh mesh; + auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0)); + auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0)); + auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0)); + mesh.add_face(vh0, vh1, vh2); + + mesh.request_edge_status(); + + auto heh0 = OpenMesh::HalfedgeHandle(0); + auto heh1 = OpenMesh::HalfedgeHandle(1); + auto heh2 = OpenMesh::HalfedgeHandle(2); + auto heh3 = OpenMesh::HalfedgeHandle(3); + auto heh4 = OpenMesh::HalfedgeHandle(4); + auto heh5 = OpenMesh::HalfedgeHandle(5); + + mesh.status(heh0).set_selected(true); + mesh.status(heh1).set_feature(true); + mesh.status(heh2).set_tagged(true); + mesh.status(heh3).set_locked(true); + mesh.status(heh4).set_deleted(true); + mesh.status(heh5).set_hidden(true); + mesh.status(heh0).set_fixed_nonmanifold(true); + + std::string filename_without_status = "no_halfedge_status_test.om"; + std::string filename_with_status = "edge_halfstatus_test.om"; + + OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status; + OpenMesh::IO::write_mesh(mesh, filename_without_status); + OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status); + + // Load no status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + } + + // Load status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded"; + EXPECT_TRUE(loaded_mesh.has_halfedge_status()) << "Mesh has no halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + if (loaded_mesh.has_halfedge_status()) + { + for (auto heh : mesh.halfedges()) + { + EXPECT_EQ(mesh.status(heh).bits(), loaded_mesh.status(heh).bits()); + } + } + } + + // Load no status from file with status + { + Mesh loaded_mesh; + loaded_mesh.request_halfedge_status(); + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_TRUE (loaded_mesh.has_halfedge_status()) << "Mesh halfedge status was removed by reading"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + for (auto heh : loaded_mesh.halfedges()) + { + EXPECT_EQ(loaded_mesh.status(heh).bits(), 0u) << "Edge status was modified even though it should not have been loaded"; + } + } + + // Try to load status from file without status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status"; + } +} + + +/* + * Save and load simple mesh with edge status + */ +TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyEdgeOnly) { + + //read file + Mesh mesh; + auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0)); + auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0)); + auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0)); + mesh.add_face(vh0, vh1, vh2); + + mesh.request_edge_status(); + + auto eh0 = OpenMesh::EdgeHandle(0); + auto eh1 = OpenMesh::EdgeHandle(1); + auto eh2 = OpenMesh::EdgeHandle(2); + + mesh.status(eh0).set_selected(true); + mesh.status(eh1).set_feature(true); + mesh.status(eh2).set_tagged(true); + mesh.status(eh0).set_locked(true); + mesh.status(eh1).set_deleted(true); + mesh.status(eh2).set_hidden(true); + mesh.status(eh0).set_fixed_nonmanifold(true); + + std::string filename_without_status = "no_edge_status_test.om"; + std::string filename_with_status = "edge_status_test.om"; + + OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status; + OpenMesh::IO::write_mesh(mesh, filename_without_status); + OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status); + + // Load no status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + } + + // Load status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_TRUE(loaded_mesh.has_edge_status()) << "Mesh has no edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + if (loaded_mesh.has_edge_status()) + { + for (auto eh : mesh.edges()) + { + EXPECT_EQ(mesh.status(eh).bits(), loaded_mesh.status(eh).bits()); + } + } + } + + // Load no status from file with status + { + Mesh loaded_mesh; + loaded_mesh.request_edge_status(); + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_TRUE (loaded_mesh.has_edge_status()) << "Mesh edge status was removed by reading"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + + for (auto eh : loaded_mesh.edges()) + { + EXPECT_EQ(loaded_mesh.status(eh).bits(), 0u) << "Edge status was modified even though it should not have been loaded"; + } + } + + // Try to load status from file without status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status"; + } +} + + +/* + * Save and load simple mesh with face status + */ +TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyFaceOnly) { + + //read file + Mesh mesh; + auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0)); + auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0)); + auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0)); + auto vh3 = mesh.add_vertex(Mesh::Point(1,1,0)); + auto fh0 = mesh.add_face(vh0, vh1, vh2); + auto fh1 = mesh.add_face(vh2, vh1, vh3); + + mesh.request_face_status(); + + mesh.status(fh0).set_selected(true); + mesh.status(fh1).set_feature(true); + mesh.status(fh0).set_tagged(true); + mesh.status(fh1).set_locked(true); + mesh.status(fh0).set_deleted(true); + mesh.status(fh1).set_hidden(true); + mesh.status(fh0).set_fixed_nonmanifold(true); + + std::string filename_without_status = "no_face_status_test.om"; + std::string filename_with_status = "face_status_test.om"; + + OpenMesh::IO::Options opt_with_status = OpenMesh::IO::Options::Status; + OpenMesh::IO::write_mesh(mesh, filename_without_status); + OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status); + + // Load no status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status"; + } + + // Load status from file with status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status"; + EXPECT_TRUE(loaded_mesh.has_face_status()) << "Mesh has no face status even though file should not have a stored status"; + + if (loaded_mesh.has_face_status()) + { + for (auto fh : mesh.faces()) + { + EXPECT_EQ(mesh.status(fh).bits(), loaded_mesh.status(fh).bits()); + } + } + } + + // Load no status from file with status + { + Mesh loaded_mesh; + loaded_mesh.request_face_status(); + OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edgestatus even though file should not have a stored status"; + EXPECT_TRUE (loaded_mesh.has_face_status()) << "Mesh face status was removed by reading"; + + for (auto fh : loaded_mesh.faces()) + { + EXPECT_EQ(loaded_mesh.status(fh).bits(), 0u) << "Edge status was modified even though it should not have been loaded"; + } + } + + // Try to load status from file without status + { + Mesh loaded_mesh; + OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status); + + EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status"; + EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status"; + } +} + } From f9b39f21c7c806ed64ddc188b786653e7b2d81e2 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Fri, 12 Oct 2018 11:35:18 +0200 Subject: [PATCH 14/24] implement status informationr reading and writing --- src/OpenMesh/Core/IO/exporter/BaseExporter.hh | 18 ++-- src/OpenMesh/Core/IO/exporter/ExporterT.hh | 54 +++++++++--- src/OpenMesh/Core/IO/importer/BaseImporter.hh | 12 +++ src/OpenMesh/Core/IO/importer/ImporterT.hh | 27 ++++++ src/OpenMesh/Core/IO/reader/OMReader.cc | 29 ++++++ src/OpenMesh/Core/IO/writer/OMWriter.cc | 88 ++++++++++++------- 6 files changed, 177 insertions(+), 51 deletions(-) diff --git a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh index 2c93e19c..bbd2b9e9 100644 --- a/src/OpenMesh/Core/IO/exporter/BaseExporter.hh +++ b/src/OpenMesh/Core/IO/exporter/BaseExporter.hh @@ -104,6 +104,7 @@ public: virtual Vec4f colorAf(VertexHandle _vh) const = 0; virtual Vec2f texcoord(VertexHandle _vh) const = 0; virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const = 0; // get face data @@ -111,13 +112,6 @@ public: get_vhandles(FaceHandle _fh, std::vector& _vhandles) const=0; - // information needed for a halfedge based data structure such as OpenMesh - virtual int get_halfedge_id(VertexHandle _vh) = 0; - virtual int get_halfedge_id(FaceHandle _vh) = 0; - virtual int get_next_halfedge_id(HalfedgeHandle _heh) = 0; - virtual int get_to_vertex_id(HalfedgeHandle _heh) = 0; - virtual int get_face_id(HalfedgeHandle _heh) = 0; - /// /// \brief getHeh returns the HalfEdgeHandle that belongs to the face /// specified by _fh and has a toVertexHandle that corresponds to _vh. @@ -135,6 +129,7 @@ public: virtual Vec4ui colorAi(FaceHandle _fh) const = 0; virtual Vec3f colorf(FaceHandle _fh) const = 0; virtual Vec4f colorAf(FaceHandle _fh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const = 0; // get edge data virtual Vec3uc color(EdgeHandle _eh) const = 0; @@ -143,6 +138,15 @@ public: virtual Vec4ui colorAi(EdgeHandle _eh) const = 0; virtual Vec3f colorf(EdgeHandle _eh) const = 0; virtual Vec4f colorAf(EdgeHandle _eh) const = 0; + virtual OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const = 0; + + // get halfedge data + virtual int get_halfedge_id(VertexHandle _vh) = 0; + virtual int get_halfedge_id(FaceHandle _vh) = 0; + virtual int get_next_halfedge_id(HalfedgeHandle _heh) = 0; + virtual int get_to_vertex_id(HalfedgeHandle _heh) = 0; + virtual int get_face_id(HalfedgeHandle _heh) = 0; + virtual OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const = 0; // get reference to base kernel virtual const BaseKernel* kernel() { return 0; } diff --git a/src/OpenMesh/Core/IO/exporter/ExporterT.hh b/src/OpenMesh/Core/IO/exporter/ExporterT.hh index 0ea30e6e..84313d2f 100644 --- a/src/OpenMesh/Core/IO/exporter/ExporterT.hh +++ b/src/OpenMesh/Core/IO/exporter/ExporterT.hh @@ -171,6 +171,13 @@ public: : Vec2f(0.0f, 0.0f)); } + OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const + { + if (mesh_.has_vertex_status()) + return mesh_.status(_vh); + return OpenMesh::Attributes::StatusInfo(); + } + // get edge data Vec3uc color(EdgeHandle _eh) const @@ -215,21 +222,15 @@ public: : Vec4f(0, 0, 0, 0)); } - // get face data - - unsigned int get_vhandles(FaceHandle _fh, - std::vector& _vhandles) const + OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const { - unsigned int count(0); - _vhandles.clear(); - for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it.is_valid(); ++fv_it) - { - _vhandles.push_back(*fv_it); - ++count; - } - return count; + if (mesh_.has_edge_status()) + return mesh_.status(_eh); + return OpenMesh::Attributes::StatusInfo(); } + // get halfedge data + int get_halfedge_id(VertexHandle _vh) override { return mesh_.halfedge_handle(_vh).idx(); @@ -255,6 +256,28 @@ public: return mesh_.face_handle(_heh).idx(); } + OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const + { + if (mesh_.has_halfedge_status()) + return mesh_.status(_heh); + return OpenMesh::Attributes::StatusInfo(); + } + + // get face data + + unsigned int get_vhandles(FaceHandle _fh, + std::vector& _vhandles) const + { + unsigned int count(0); + _vhandles.clear(); + for (typename Mesh::CFVIter fv_it=mesh_.cfv_iter(_fh); fv_it.is_valid(); ++fv_it) + { + _vhandles.push_back(*fv_it); + ++count; + } + return count; + } + unsigned int get_face_texcoords(std::vector& _hehandles) const { unsigned int count(0); @@ -329,6 +352,13 @@ public: : Vec4f(0, 0, 0, 0)); } + OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const + { + if (mesh_.has_face_status()) + return mesh_.status(_fh); + return OpenMesh::Attributes::StatusInfo(); + } + virtual const BaseKernel* kernel() { return &mesh_; } diff --git a/src/OpenMesh/Core/IO/importer/BaseImporter.hh b/src/OpenMesh/Core/IO/importer/BaseImporter.hh index c1331e7d..46630a5b 100644 --- a/src/OpenMesh/Core/IO/importer/BaseImporter.hh +++ b/src/OpenMesh/Core/IO/importer/BaseImporter.hh @@ -142,6 +142,9 @@ public: // set vertex texture coordinate virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; + // set vertex status + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + // set next halfedge handle virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) = 0; @@ -157,6 +160,9 @@ public: // set 3d vertex texture coordinate virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) = 0; + // set halfedge status + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + // set edge color virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0; @@ -169,6 +175,9 @@ public: // set edge color virtual void set_color(EdgeHandle _eh, const Vec4f& _color) = 0; + // set edge status + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + // set face normal virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; @@ -184,6 +193,9 @@ public: // set face color virtual void set_color(FaceHandle _fh, const Vec4f& _color) = 0; + // set face status + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) = 0; + // Store a property in the mesh mapping from an int to a texture file // Use set_face_texindex to set the index for each face virtual void add_texture_information( int _id , std::string _name ) = 0; diff --git a/src/OpenMesh/Core/IO/importer/ImporterT.hh b/src/OpenMesh/Core/IO/importer/ImporterT.hh index 48744a36..d95e1cbe 100644 --- a/src/OpenMesh/Core/IO/importer/ImporterT.hh +++ b/src/OpenMesh/Core/IO/importer/ImporterT.hh @@ -257,6 +257,13 @@ public: mesh_.set_texcoord2D(_vh, vector_cast(_texcoord)); } + virtual void set_status(VertexHandle _vh, const OpenMesh::Attributes::StatusInfo& _status) + { + if (!mesh_.has_vertex_status()) + mesh_.request_vertex_status(); + mesh_.status(_vh) = _status; + } + virtual void set_next(HalfedgeHandle _heh, HalfedgeHandle _next) override { mesh_.set_next_halfedge_handle(_heh, _next); @@ -286,6 +293,12 @@ public: mesh_.set_texcoord3D(_heh, vector_cast(_texcoord)); } + virtual void set_status(HalfedgeHandle _heh, const OpenMesh::Attributes::StatusInfo& _status) + { + if (!mesh_.has_halfedge_status()) + mesh_.request_halfedge_status(); + mesh_.status(_heh) = _status; + } // edge attributes @@ -313,6 +326,13 @@ public: mesh_.set_color(_eh, color_cast(_color)); } + virtual void set_status(EdgeHandle _eh, const OpenMesh::Attributes::StatusInfo& _status) + { + if (!mesh_.has_edge_status()) + mesh_.request_edge_status(); + mesh_.status(_eh) = _status; + } + // face attributes virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) @@ -345,6 +365,13 @@ public: mesh_.set_color(_fh, color_cast(_color)); } + virtual void set_status(FaceHandle _fh, const OpenMesh::Attributes::StatusInfo& _status) + { + if (!mesh_.has_face_status()) + mesh_.request_face_status(); + mesh_.status(_fh) = _status; + } + virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector& _face_texcoords) { // get first halfedge handle diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 00af3f73..8a22d607 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -294,6 +294,7 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, OpenMesh::Vec3f v3f; OpenMesh::Vec2f v2f; OpenMesh::Vec3uc v3uc; // rgb + OpenMesh::Attributes::StatusInfo status; OMFormat::Chunk::PropertyName custom_prop; @@ -343,6 +344,20 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi, } break; + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; vidx < header_.n_vertices_ && !_is.eof(); ++vidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.vertex_has_status() && _opt.vertex_has_status()) + _bi.set_status(VertexHandle(int(vidx)), status); + } + break; + } + case Chunk::Type_Custom: bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap); @@ -389,6 +404,7 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op size_t fidx = 0; OpenMesh::Vec3f v3f; // normal OpenMesh::Vec3uc v3uc; // rgb + OpenMesh::Attributes::StatusInfo status; switch (chunk_header_.type_) { case Chunk::Type_Topology: @@ -459,6 +475,19 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op _bi.set_color(FaceHandle(int(fidx)), v3uc); } break; + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; fidx < header_.n_faces_ && !_is.eof(); ++fidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.face_has_status() && _opt.face_has_status()) + _bi.set_status(FaceHandle(int(fidx)), status); + } + break; + } case Chunk::Type_Custom: diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index cc12d73d..721a25a1 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -420,53 +420,77 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, // ---------- write vertex status if (_be.n_vertices() && _be.has_vertex_status() && _opt.check(Options::Status)) { - //store status as costum property because that already works - auto prop = _be.kernel()->_get_vprop("v:status"); - assert(prop != nullptr); - bool persistent = prop->persistent(); - const_cast(prop)->set_persistent(true); - bytes += store_binary_custom_chunk(_os, *prop, - OMFormat::Chunk::Entity_Vertex, swap ); - const_cast(prop)->set_persistent(persistent); + auto s = _be.status(VertexHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap); + + for (i = 0, nV = header.n_vertices_; i < nV; ++i) + bytes += store(_os, _be.status(VertexHandle(i)), swap); } // ---------- write edge status if (_be.n_edges() && _be.has_edge_status() && _opt.check(Options::Status)) { - //store status as costum property because that already works - auto prop = _be.kernel()->_get_eprop("e:status"); - assert(prop != nullptr); - bool persistent = prop->persistent(); - const_cast(prop)->set_persistent(true); - bytes += store_binary_custom_chunk(_os, *prop, - OMFormat::Chunk::Entity_Edge, swap ); - const_cast(prop)->set_persistent(persistent); + auto s = _be.status(EdgeHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap); + + for (i = 0, nV = header.n_edges_; i < nV; ++i) + bytes += store(_os, _be.status(EdgeHandle(i)), swap); } // ---------- write halfedge status if (_be.n_edges() && _be.has_halfedge_status() && _opt.check(Options::Status)) { - //store status as costum property because that already works - auto prop = _be.kernel()->_get_hprop("h:status"); - assert(prop != nullptr); - bool persistent = prop->persistent(); - const_cast(prop)->set_persistent(true); - bytes += store_binary_custom_chunk(_os, *prop, - OMFormat::Chunk::Entity_Halfedge, swap ); - const_cast(prop)->set_persistent(persistent); + auto s = _be.status(HalfedgeHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap); + + for (i = 0, nV = header.n_edges_ * 2; i < nV; ++i) + bytes += store(_os, _be.status(HalfedgeHandle(i)), swap); } // ---------- write face status if (_be.n_faces() && _be.has_face_status() && _opt.check(Options::Status)) { - //store status as costum property because that already works - auto prop = _be.kernel()->_get_fprop("f:status"); - assert(prop != nullptr); - bool persistent = prop->persistent(); - const_cast(prop)->set_persistent(true); - bytes += store_binary_custom_chunk(_os, *prop, - OMFormat::Chunk::Entity_Face, swap ); - const_cast(prop)->set_persistent(persistent); + auto s = _be.status(FaceHandle(0)); + chunk_header.name_ = false; + chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.type_ = OMFormat::Chunk::Type_Status; + chunk_header.signed_ = false; + chunk_header.float_ = false; + chunk_header.dim_ = OMFormat::Chunk::Dim_1D; + chunk_header.bits_ = OMFormat::bits(s); + + // std::clog << chunk_header << std::endl; + bytes += store(_os, chunk_header, swap); + + for (i = 0, nV = header.n_faces_; i < nV; ++i) + bytes += store(_os, _be.status(FaceHandle(i)), swap); } // -------------------- write custom properties From 6a2d18739f45da7dbda38bc440fd71f123e6f7c5 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Fri, 12 Oct 2018 14:04:34 +0200 Subject: [PATCH 15/24] fix bugs in unittest --- src/Unittests/unittests_read_write_OM.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index 92aaeed6..c5f1726f 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -735,7 +735,7 @@ TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleStatusProperties) { cmpMesh.request_halfedge_status(); cmpMesh.request_face_status(); - ok = OpenMesh::IO::read_mesh(cmpMesh,filename); + ok = OpenMesh::IO::read_mesh(cmpMesh,filename, options); EXPECT_TRUE(ok) << "Unable to read "< Date: Fri, 12 Oct 2018 14:05:25 +0200 Subject: [PATCH 16/24] more implementation of status reading --- src/OpenMesh/Core/IO/reader/OMReader.cc | 37 +++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 8a22d607..4abc4b29 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -511,7 +511,7 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op //----------------------------------------------------------------------------- -bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Options &/*_opt */, bool _swap) const +bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Options &_opt, bool _swap) const { using OMFormat::Chunk; @@ -519,6 +519,9 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op size_t b = bytes_; + size_t eidx = 0; + OpenMesh::Attributes::StatusInfo status; + switch (chunk_header_.type_) { case Chunk::Type_Custom: @@ -526,6 +529,20 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op break; + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; eidx < header_.n_edges_ && !_is.eof(); ++eidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.edge_has_status() && _opt.edge_has_status()) + _bi.set_status(EdgeHandle(int(eidx)), status); + } + break; + } + default: // skip unknown type size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); @@ -539,13 +556,15 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op //----------------------------------------------------------------------------- -bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, Options &/* _opt */, bool _swap) const +bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi, Options & _opt, bool _swap) const { using OMFormat::Chunk; assert( chunk_header_.entity_ == Chunk::Entity_Halfedge); size_t b = bytes_; + size_t hidx = 0; + OpenMesh::Attributes::StatusInfo status; switch (chunk_header_.type_) { case Chunk::Type_Custom: @@ -588,6 +607,20 @@ bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi break; + case Chunk::Type_Status: + { + assert( OMFormat::dimensions(chunk_header_) == 1); + + fileOptions_ += Options::Status; + + for (; hidx < header_.n_edges_ * 2 && !_is.eof(); ++hidx) { + bytes_ += restore(_is, status, _swap); + if (fileOptions_.halfedge_has_status() && _opt.halfedge_has_status()) + _bi.set_status(HalfedgeHandle(int(hidx)), status); + } + break; + } + default: // skip unknown chunk omerr() << "Unknown chunk type ignored!\n"; From 1e9e4d59220bcb2b75797f34c553aafa88102b3a Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Fri, 12 Oct 2018 14:05:52 +0200 Subject: [PATCH 17/24] fix copy paste bugs for status writing --- src/OpenMesh/Core/IO/writer/OMWriter.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.cc b/src/OpenMesh/Core/IO/writer/OMWriter.cc index 721a25a1..ffcbbce4 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.cc +++ b/src/OpenMesh/Core/IO/writer/OMWriter.cc @@ -441,7 +441,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, { auto s = _be.status(EdgeHandle(0)); chunk_header.name_ = false; - chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.entity_ = OMFormat::Chunk::Entity_Edge; chunk_header.type_ = OMFormat::Chunk::Type_Status; chunk_header.signed_ = false; chunk_header.float_ = false; @@ -460,7 +460,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, { auto s = _be.status(HalfedgeHandle(0)); chunk_header.name_ = false; - chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge; chunk_header.type_ = OMFormat::Chunk::Type_Status; chunk_header.signed_ = false; chunk_header.float_ = false; @@ -479,7 +479,7 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be, { auto s = _be.status(FaceHandle(0)); chunk_header.name_ = false; - chunk_header.entity_ = OMFormat::Chunk::Entity_Vertex; + chunk_header.entity_ = OMFormat::Chunk::Entity_Face; chunk_header.type_ = OMFormat::Chunk::Type_Status; chunk_header.signed_ = false; chunk_header.float_ = false; From 8ce8d8a623876a4ec09e9755bb0bb957e6e0d74d Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Fri, 12 Oct 2018 15:16:33 +0200 Subject: [PATCH 18/24] reduce scope of variables --- src/OpenMesh/Core/IO/reader/OMReader.cc | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 4abc4b29..12bb6c8e 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -519,7 +519,6 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op size_t b = bytes_; - size_t eidx = 0; OpenMesh::Attributes::StatusInfo status; switch (chunk_header_.type_) { @@ -535,7 +534,7 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op fileOptions_ += Options::Status; - for (; eidx < header_.n_edges_ && !_is.eof(); ++eidx) { + for (size_t eidx = 0; eidx < header_.n_edges_ && !_is.eof(); ++eidx) { bytes_ += restore(_is, status, _swap); if (fileOptions_.edge_has_status() && _opt.edge_has_status()) _bi.set_status(EdgeHandle(int(eidx)), status); @@ -563,7 +562,6 @@ bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi assert( chunk_header_.entity_ == Chunk::Entity_Halfedge); size_t b = bytes_; - size_t hidx = 0; OpenMesh::Attributes::StatusInfo status; switch (chunk_header_.type_) { @@ -613,7 +611,7 @@ bool _OMReader_::read_binary_halfedge_chunk(std::istream &_is, BaseImporter &_bi fileOptions_ += Options::Status; - for (; hidx < header_.n_edges_ * 2 && !_is.eof(); ++hidx) { + for (size_t hidx = 0; hidx < header_.n_edges_ * 2 && !_is.eof(); ++hidx) { bytes_ += restore(_is, status, _swap); if (fileOptions_.halfedge_has_status() && _opt.halfedge_has_status()) _bi.set_status(HalfedgeHandle(int(hidx)), status); From 6ca8816c29fb53f17286ef2cea724ef1bc76d5b6 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 11:20:28 +0200 Subject: [PATCH 19/24] add function that turns writer version into string --- src/OpenMesh/Core/IO/OMFormat.cc | 13 +++++++++++++ src/OpenMesh/Core/IO/OMFormat.hh | 2 ++ 2 files changed, 15 insertions(+) diff --git a/src/OpenMesh/Core/IO/OMFormat.cc b/src/OpenMesh/Core/IO/OMFormat.cc index 231dfacd..0c1a63dd 100644 --- a/src/OpenMesh/Core/IO/OMFormat.cc +++ b/src/OpenMesh/Core/IO/OMFormat.cc @@ -113,6 +113,19 @@ namespace OMFormat { return hdr; } +//----------------------------------------------------------------------------- + + + std::string as_string(uint8 version) + { + std::stringstream ss; + ss << major_version(version); + ss << "."; + ss << minor_version(version); + return ss.str(); + } + + //----------------------------------------------------------------------------- const char *as_string(Chunk::Entity e) diff --git a/src/OpenMesh/Core/IO/OMFormat.hh b/src/OpenMesh/Core/IO/OMFormat.hh index 9bbcd860..2fef1389 100644 --- a/src/OpenMesh/Core/IO/OMFormat.hh +++ b/src/OpenMesh/Core/IO/OMFormat.hh @@ -469,6 +469,8 @@ namespace OMFormat { // ---------------------------------------- convenience functions + std::string as_string(uint8 version); + const char *as_string(Chunk::Type t); const char *as_string(Chunk::Entity e); const char *as_string(Chunk::Dim d); From f8b906c2d98aacdcef4d2514086bccba03d246d7 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 11:20:41 +0200 Subject: [PATCH 20/24] add function to access current writer version --- src/OpenMesh/Core/IO/writer/OMWriter.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/OpenMesh/Core/IO/writer/OMWriter.hh b/src/OpenMesh/Core/IO/writer/OMWriter.hh index efc48a8c..89c723b7 100644 --- a/src/OpenMesh/Core/IO/writer/OMWriter.hh +++ b/src/OpenMesh/Core/IO/writer/OMWriter.hh @@ -111,10 +111,10 @@ public: bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; - - size_t binary_size(BaseExporter& _be, Options _opt) const; + static OMFormat::uint8 get_version() { return version_; } + protected: From 87a2db3fe14328e07fcb17efcc898b93103756cd Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 11:21:01 +0200 Subject: [PATCH 21/24] check version before trying to read file --- src/OpenMesh/Core/IO/reader/OMReader.cc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/OpenMesh/Core/IO/reader/OMReader.cc b/src/OpenMesh/Core/IO/reader/OMReader.cc index 12bb6c8e..ca4655dd 100644 --- a/src/OpenMesh/Core/IO/reader/OMReader.cc +++ b/src/OpenMesh/Core/IO/reader/OMReader.cc @@ -61,6 +61,7 @@ #include #include #include +#include //=== NAMESPACES ============================================================== @@ -176,6 +177,15 @@ bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt bytes_ += restore(_is, header_, swap); + if (header_.version_ > _OMWriter_::get_version()) + { + omerr() << "File uses .om version " << OMFormat::as_string(header_.version_) << " but reader only " + << "supports up to version " << OMFormat::as_string(_OMWriter_::get_version()) << ".\n" + << "Please update your OpenMesh." << std::endl; + return false; + } + + while (!_is.eof()) { bytes_ += restore(_is, chunk_header_, swap); From c1ac62b901c003f727de84e75c22191d8a6cff50 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 11:21:32 +0200 Subject: [PATCH 22/24] add tests for reading different file versions --- .../TestFiles/cube_poly_version_1_2.om | Bin 0 -> 154 bytes .../TestFiles/cube_poly_version_2_0.om | Bin 0 -> 208 bytes .../TestFiles/cube_tri_version_10_5.om | Bin 0 -> 154 bytes .../TestFiles/cube_tri_version_1_2.om | Bin 0 -> 154 bytes .../TestFiles/cube_tri_version_2_0.om | Bin 0 -> 250 bytes src/Unittests/unittests_read_write_OM.cc | 95 ++++++++++++++++++ 6 files changed, 95 insertions(+) create mode 100644 src/Unittests/TestFiles/cube_poly_version_1_2.om create mode 100644 src/Unittests/TestFiles/cube_poly_version_2_0.om create mode 100644 src/Unittests/TestFiles/cube_tri_version_10_5.om create mode 100644 src/Unittests/TestFiles/cube_tri_version_1_2.om create mode 100644 src/Unittests/TestFiles/cube_tri_version_2_0.om diff --git a/src/Unittests/TestFiles/cube_poly_version_1_2.om b/src/Unittests/TestFiles/cube_poly_version_1_2.om new file mode 100644 index 0000000000000000000000000000000000000000..fa583a99ddd75ad5f0956f735578debf488e5313 GIT binary patch literal 154 zcmebG4N&4>U|?VaVjdu75My9yum|G(P#VOBVPr87n^-?|@20L=3mmjD0& literal 0 HcmV?d00001 diff --git a/src/Unittests/TestFiles/cube_poly_version_2_0.om b/src/Unittests/TestFiles/cube_poly_version_2_0.om new file mode 100644 index 0000000000000000000000000000000000000000..ec32c759da37ecf5e557fc765f9b7deac1ad2511 GIT binary patch literal 208 zcma)#%MF4+7=-74vjQR_%f()_0iz|^8LfD<1dlF85|19f%p;S`^>RB`0KCu?kb(QD zFn@LNE5F_1|IO?6qp!?_3Z#sd)CHNP{ElK9rGPa?TV)~|On1RaZSQ;tsf{OB6Y0Ww U7h!#Pv@)h)>YnaY_mYly1L4LVga7~l literal 0 HcmV?d00001 diff --git a/src/Unittests/TestFiles/cube_tri_version_10_5.om b/src/Unittests/TestFiles/cube_tri_version_10_5.om new file mode 100644 index 0000000000000000000000000000000000000000..b1ae2363b98b62faa9d9130c9bb3c2f465bf3e22 GIT binary patch literal 154 zcmebG4RPgQU|`?@Vj&=A5My9yum|G(P#VOBVPr87n^-lGT> literal 0 HcmV?d00001 diff --git a/src/Unittests/TestFiles/cube_tri_version_1_2.om b/src/Unittests/TestFiles/cube_tri_version_1_2.om new file mode 100644 index 0000000000000000000000000000000000000000..126a284642d46aad8620e7aae093df4d5ed0885b GIT binary patch literal 154 zcmebG4N>A?U|`?@Vj&=A5My9yum|G(P#VOBVPr87n^-ekgmFm({9iv#xI7 E1q7!db^rhX literal 0 HcmV?d00001 diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index c5f1726f..803ec4df 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -1326,4 +1326,99 @@ TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyFaceOnly) { } } + +/* + * Just load a triangle mesh from an om file of version 1.2 + */ +TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_1_2) { + + mesh_.clear(); + + std::string file_name = "cube_tri_version_1_2.om"; + + bool ok = OpenMesh::IO::read_mesh(mesh_, file_name); + + EXPECT_TRUE(ok) << file_name; + + 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(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!"; +} + + +/* + * Just load a polyhedral mesh from an om file of version 1.2 + */ +TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_1_2) { + + PolyMesh mesh; + + std::string file_name = "cube_poly_version_1_2.om"; + + bool ok = OpenMesh::IO::read_mesh(mesh, file_name); + + EXPECT_TRUE(ok) << file_name; + + 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!"; + EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!"; +} + + +/* + * Just load a triangle mesh from an om file of version 2.0 + */ +TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_2_0) { + + mesh_.clear(); + + std::string file_name = "cube_tri_version_2_0.om"; + + bool ok = OpenMesh::IO::read_mesh(mesh_, file_name); + + EXPECT_TRUE(ok) << file_name; + + 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(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!"; +} + + +/* + * Just load a polyhedral mesh from an om file of version 2.0 + */ +TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_2_0) { + + PolyMesh mesh; + + std::string file_name = "cube_poly_version_2_0.om"; + + bool ok = OpenMesh::IO::read_mesh(mesh, file_name); + + EXPECT_TRUE(ok) << file_name; + + 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!"; + EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!"; +} + + +/* + * Just load a triangles mesh from an om file of version 10.5 + */ +TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_10_5) { + + PolyMesh mesh; + + std::string file_name = "cube_tri_version_10_.om"; + + bool ok = OpenMesh::IO::read_mesh(mesh, file_name); + + EXPECT_FALSE(ok) << file_name; +} + } From 12f3e09d6b15577f4ba616ae72e1e07c90912e7d Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 11:49:21 +0200 Subject: [PATCH 23/24] update changelog --- Doc/changelog.docu | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Doc/changelog.docu b/Doc/changelog.docu index c38bd385..3129b82e 100644 --- a/Doc/changelog.docu +++ b/Doc/changelog.docu @@ -18,6 +18,9 @@
  • PLY Reader: Allowing the PLY reader to read custom face ( Thanks to morgan Leborgne for the patch)
  • PLY Reader: Fixed endless loop on unknown property list type
  • +
  • OM Writer/Reader: Update file format version to 2.0. Older files can still be read, but older OpenMesh versions cannot read new format.
  • +
  • OM Writer/Reader: Fixed inconsistent writing/reading of edge properties
  • +
  • OM Writer/Reader: Add option to store status
Tools From 62e822cffdd0a996263ff5f3a108b7e66a30911c Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Tue, 23 Oct 2018 12:07:19 +0200 Subject: [PATCH 24/24] change test file version from 10 to 7 because 7 is the biggest supported major version --- ..._version_10_5.om => cube_tri_version_7_5.om} | Bin 154 -> 154 bytes src/Unittests/unittests_read_write_OM.cc | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename src/Unittests/TestFiles/{cube_tri_version_10_5.om => cube_tri_version_7_5.om} (58%) diff --git a/src/Unittests/TestFiles/cube_tri_version_10_5.om b/src/Unittests/TestFiles/cube_tri_version_7_5.om similarity index 58% rename from src/Unittests/TestFiles/cube_tri_version_10_5.om rename to src/Unittests/TestFiles/cube_tri_version_7_5.om index b1ae2363b98b62faa9d9130c9bb3c2f465bf3e22..78cead572305dc631fece5bc7ce0cfaf5dbe80b1 100644 GIT binary patch delta 12 TcmbQmIE#_R-#6sxM3!j)82kh~ delta 12 TcmbQmIE#_R-#5f{BFi)Y7JLJn diff --git a/src/Unittests/unittests_read_write_OM.cc b/src/Unittests/unittests_read_write_OM.cc index 803ec4df..9b4b96d1 100644 --- a/src/Unittests/unittests_read_write_OM.cc +++ b/src/Unittests/unittests_read_write_OM.cc @@ -72,7 +72,7 @@ TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithTexCoords) { bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-texCoords.om",options); - EXPECT_TRUE(ok) << "Unable to load cube-minimal-texCoords.om"; + ASSERT_TRUE(ok) << "Unable to load cube-minimal-texCoords.om"; 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!"; @@ -1408,13 +1408,13 @@ TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_2_0) { /* - * Just load a triangles mesh from an om file of version 10.5 + * Try to load mesh from om file with a version that is not yet supported */ -TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_10_5) { +TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_7_5) { PolyMesh mesh; - std::string file_name = "cube_tri_version_10_.om"; + std::string file_name = "cube_tri_version_7_5.om"; bool ok = OpenMesh::IO::read_mesh(mesh, file_name);