From 921d370038c129835dfc2174b5f0a036d949fada Mon Sep 17 00:00:00 2001 From: Daniel Sieger Date: Sun, 2 Oct 2022 19:06:02 +0200 Subject: [PATCH] Bring back support for PMP format --- src/pmp/SurfaceMesh.h | 5 +++ src/pmp/io/io.cpp | 18 +++++++---- src/pmp/io/io.h | 10 +++--- src/pmp/io/read_pmp.cpp | 67 ++++++++++++++++++++++++++++++++++++++++ src/pmp/io/read_pmp.h | 14 +++++++++ src/pmp/io/write_pmp.cpp | 56 +++++++++++++++++++++++++++++++++ src/pmp/io/write_pmp.h | 16 ++++++++++ tests/IOTest.cpp | 14 +++++++++ 8 files changed, 190 insertions(+), 10 deletions(-) create mode 100644 src/pmp/io/read_pmp.cpp create mode 100644 src/pmp/io/read_pmp.h create mode 100644 src/pmp/io/write_pmp.cpp create mode 100644 src/pmp/io/write_pmp.h diff --git a/src/pmp/SurfaceMesh.h b/src/pmp/SurfaceMesh.h index afaace21..512b131c 100644 --- a/src/pmp/SurfaceMesh.h +++ b/src/pmp/SurfaceMesh.h @@ -2022,6 +2022,11 @@ class SurfaceMesh // are there any deleted entities? inline bool has_garbage() const { return has_garbage_; } + // io functions that need access to internal details + friend void read_pmp(SurfaceMesh&, const std::string&); + friend void write_pmp(const SurfaceMesh&, const std::string&, + const IOFlags&); + // property containers for each entity type and object PropertyContainer oprops_; PropertyContainer vprops_; diff --git a/src/pmp/io/io.cpp b/src/pmp/io/io.cpp index 2b3689d5..9f90255a 100644 --- a/src/pmp/io/io.cpp +++ b/src/pmp/io/io.cpp @@ -5,9 +5,11 @@ #include "pmp/io/read_obj.h" #include "pmp/io/read_off.h" +#include "pmp/io/read_pmp.h" #include "pmp/io/read_stl.h" #include "pmp/io/write_obj.h" #include "pmp/io/write_off.h" +#include "pmp/io/write_pmp.h" #include "pmp/io/write_stl.h" namespace pmp { @@ -25,10 +27,12 @@ void read(SurfaceMesh& mesh, const std::string& filename) std::transform(ext.begin(), ext.end(), ext.begin(), tolower); // extension determines reader - if (ext == "off") - read_off(mesh, filename); - else if (ext == "obj") + if (ext == "obj") read_obj(mesh, filename); + else if (ext == "off") + read_off(mesh, filename); + else if (ext == "pmp") + read_pmp(mesh, filename); else if (ext == "stl") read_stl(mesh, filename); else @@ -46,10 +50,12 @@ void write(const SurfaceMesh& mesh, const std::string& filename, std::transform(ext.begin(), ext.end(), ext.begin(), tolower); // extension determines reader - if (ext == "off") - write_off(mesh, filename, flags); - else if (ext == "obj") + if (ext == "obj") write_obj(mesh, filename, flags); + else if (ext == "off") + write_off(mesh, filename, flags); + else if (ext == "pmp") + write_pmp(mesh, filename, flags); else if (ext == "stl") write_stl(mesh, filename, flags); else diff --git a/src/pmp/io/io.h b/src/pmp/io/io.h index ac3baa7d..d9b0454a 100644 --- a/src/pmp/io/io.h +++ b/src/pmp/io/io.h @@ -16,11 +16,12 @@ namespace pmp { //! //! Format | ASCII | Binary | Normals | Colors | Texcoords //! -------|-------|--------|---------|--------|---------- -//! OFF | yes | yes | a / b | a | a / b //! OBJ | yes | no | a | no | no +//! OFF | yes | yes | a / b | a | a / b +//! PMP | no | yes | no | no | no //! STL | yes | yes | no | no | no //! -//! In addition, the OBJ supports reading per-halfedge +//! In addition, the OBJ and PMP formats support reading per-halfedge //! texture coordinates. //! \ingroup io void read(SurfaceMesh& mesh, const std::string& filename); @@ -31,11 +32,12 @@ void read(SurfaceMesh& mesh, const std::string& filename); //! //! Format | ASCII | Binary | Normals | Colors | Texcoords //! -------|-------|--------|---------|--------|---------- -//! OFF | yes | yes | a | a | a //! OBJ | yes | no | a | no | no +//! OFF | yes | yes | a | a | a +//! PMP | no | yes | no | no | no //! STL | yes | no | no | no | no //! -//! In addition, the OBJ format supports writing per-halfedge +//! In addition, the OBJ and PMP formats support writing per-halfedge //! texture coordinates. //! \ingroup io void write(const SurfaceMesh& mesh, const std::string& filename, diff --git a/src/pmp/io/read_pmp.cpp b/src/pmp/io/read_pmp.cpp new file mode 100644 index 00000000..d2e738e5 --- /dev/null +++ b/src/pmp/io/read_pmp.cpp @@ -0,0 +1,67 @@ +// Copyright 2011-2022 the Polygon Mesh Processing Library developers. +// Distributed under a MIT-style license, see LICENSE.txt for details. + +#include "pmp/io/read_pmp.h" + +#include "pmp/io/helpers.h" + +namespace pmp { + +void read_pmp(SurfaceMesh& mesh, const std::string& filename) +{ + // open file (in binary mode) + FILE* in = fopen(filename.c_str(), "rb"); + if (!in) + throw IOException("Failed to open file: " + filename); + + // how many elements? + unsigned int nv(0), ne(0), nh(0), nf(0); + tfread(in, nv); + tfread(in, ne); + tfread(in, nf); + nh = 2 * ne; + + // texture coordinates? + bool has_htex(false); + tfread(in, has_htex); + + // resize containers + mesh.vprops_.resize(nv); + mesh.hprops_.resize(nh); + mesh.eprops_.resize(ne); + mesh.fprops_.resize(nf); + + // get properties + auto vconn = + mesh.vertex_property("v:connectivity"); + auto hconn = mesh.halfedge_property( + "h:connectivity"); + auto fconn = + mesh.face_property("f:connectivity"); + auto point = mesh.vertex_property("v:point"); + + // read properties from file + size_t nvc = fread((char*)vconn.data(), + sizeof(SurfaceMesh::VertexConnectivity), nv, in); + size_t nhc = fread((char*)hconn.data(), + sizeof(SurfaceMesh::HalfedgeConnectivity), nh, in); + size_t nfc = fread((char*)fconn.data(), + sizeof(SurfaceMesh::FaceConnectivity), nf, in); + size_t np = fread((char*)point.data(), sizeof(Point), nv, in); + PMP_ASSERT(nvc == nv); + PMP_ASSERT(nhc == nh); + PMP_ASSERT(nfc == nf); + PMP_ASSERT(np == nv); + + // read texture coordiantes + if (has_htex) + { + auto htex = mesh.halfedge_property("h:tex"); + size_t nhtc = fread((char*)htex.data(), sizeof(TexCoord), nh, in); + PMP_ASSERT(nhtc == nh); + } + + fclose(in); +} + +} // namespace pmp diff --git a/src/pmp/io/read_pmp.h b/src/pmp/io/read_pmp.h new file mode 100644 index 00000000..7e309943 --- /dev/null +++ b/src/pmp/io/read_pmp.h @@ -0,0 +1,14 @@ +// Copyright 2011-2022 the Polygon Mesh Processing Library developers. +// Distributed under a MIT-style license, see LICENSE.txt for details. + +#pragma once + +#include + +#include "pmp/SurfaceMesh.h" + +namespace pmp { + +void read_pmp(SurfaceMesh& mesh, const std::string& filename); + +} // namespace pmp \ No newline at end of file diff --git a/src/pmp/io/write_pmp.cpp b/src/pmp/io/write_pmp.cpp new file mode 100644 index 00000000..06b09fe2 --- /dev/null +++ b/src/pmp/io/write_pmp.cpp @@ -0,0 +1,56 @@ +// Copyright 2011-2022 the Polygon Mesh Processing Library developers. +// Distributed under a MIT-style license, see LICENSE.txt for details. + +#include "pmp/io/write_pmp.h" +#include "pmp/Types.h" +#include "pmp/io/helpers.h" + +namespace pmp { + +void write_pmp(const SurfaceMesh& mesh, const std::string& filename, + const IOFlags&) +{ + // open file (in binary mode) + FILE* out = fopen(filename.c_str(), "wb"); + if (!out) + throw IOException("Failed to open file: " + filename); + + // get properties + auto vconn = mesh.get_vertex_property( + "v:connectivity"); + auto hconn = mesh.get_halfedge_property( + "h:connectivity"); + auto fconn = + mesh.get_face_property("f:connectivity"); + auto point = mesh.get_vertex_property("v:point"); + auto htex = mesh.get_halfedge_property("h:tex"); + + // how many elements? + unsigned int nv, ne, nh, nf; + nv = mesh.n_vertices(); + ne = mesh.n_edges(); + nh = mesh.n_halfedges(); + nf = mesh.n_faces(); + + // write header + tfwrite(out, nv); + tfwrite(out, ne); + tfwrite(out, nf); + tfwrite(out, (bool)htex); + + // write properties to file + fwrite((char*)vconn.data(), sizeof(SurfaceMesh::VertexConnectivity), nv, + out); + fwrite((char*)hconn.data(), sizeof(SurfaceMesh::HalfedgeConnectivity), nh, + out); + fwrite((char*)fconn.data(), sizeof(SurfaceMesh::FaceConnectivity), nf, out); + fwrite((char*)point.data(), sizeof(Point), nv, out); + + // texture coordinates + if (htex) + fwrite((char*)htex.data(), sizeof(TexCoord), nh, out); + + fclose(out); +} + +} // namespace pmp \ No newline at end of file diff --git a/src/pmp/io/write_pmp.h b/src/pmp/io/write_pmp.h new file mode 100644 index 00000000..6c3d769b --- /dev/null +++ b/src/pmp/io/write_pmp.h @@ -0,0 +1,16 @@ +// Copyright 2011-2022 the Polygon Mesh Processing Library developers. +// Distributed under a MIT-style license, see LICENSE.txt for details. + +#pragma once + +#include + +#include "pmp/SurfaceMesh.h" +#include "pmp/Types.h" + +namespace pmp { + +void write_pmp(SurfaceMesh& mesh, const std::string& filename, + const IOFlags& flags); + +} // namespace pmp \ No newline at end of file diff --git a/tests/IOTest.cpp b/tests/IOTest.cpp index 05973a72..47cba084 100644 --- a/tests/IOTest.cpp +++ b/tests/IOTest.cpp @@ -61,6 +61,20 @@ TEST_F(IOTest, off_io_binary) EXPECT_EQ(mesh.n_faces(), size_t(1)); } +TEST_F(IOTest, pmp_io) +{ + add_triangle(); + write(mesh, "test.pmp"); + mesh.clear(); + EXPECT_TRUE(mesh.is_empty()); + read(mesh, "test.pmp"); + EXPECT_EQ(mesh.n_vertices(), size_t(3)); + EXPECT_EQ(mesh.n_faces(), size_t(1)); + + // check malformed file names + EXPECT_THROW(write(mesh, "testpolyly"), IOException); +} + TEST_F(IOTest, stl_io) { read(mesh, "pmp-data/stl/icosahedron_ascii.stl");