Merge branch 'master' into PLY_istream_fix

This commit is contained in:
Jan Möbius
2018-11-27 14:33:05 +01:00
17 changed files with 1224 additions and 51 deletions

View File

@@ -18,6 +18,9 @@
<ul> <ul>
<li>PLY Reader: Allowing the PLY reader to read custom face ( Thanks to morgan Leborgne for the patch)</li> <li>PLY Reader: Allowing the PLY reader to read custom face ( Thanks to morgan Leborgne for the patch)</li>
<li>PLY Reader: Fixed endless loop on unknown property list type</li> <li>PLY Reader: Fixed endless loop on unknown property list type</li>
<li>OM Writer/Reader: Update file format version to 2.0. Older files can still be read, but older OpenMesh versions cannot read new format.</li>
<li>OM Writer/Reader: Fixed inconsistent writing/reading of edge properties</li>
<li>OM Writer/Reader: Add option to store status</li>
</ul> </ul>
<b>Tools</b> <b>Tools</b>

View File

@@ -113,6 +113,19 @@ namespace OMFormat {
return hdr; 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) const char *as_string(Chunk::Entity e)

View File

@@ -469,6 +469,8 @@ namespace OMFormat {
// ---------------------------------------- convenience functions // ---------------------------------------- convenience functions
std::string as_string(uint8 version);
const char *as_string(Chunk::Type t); const char *as_string(Chunk::Type t);
const char *as_string(Chunk::Entity e); const char *as_string(Chunk::Entity e);
const char *as_string(Chunk::Dim d); const char *as_string(Chunk::Dim d);

View File

@@ -115,7 +115,8 @@ public:
FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates FaceTexCoord = 0x0400, ///< Has (r) / store (w) face texture coordinates
ColorAlpha = 0x0800, ///< Has (r) / store (w) alpha values for colors 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) 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: public:
@@ -206,10 +207,14 @@ public:
bool vertex_has_normal() const { return check(VertexNormal); } bool vertex_has_normal() const { return check(VertexNormal); }
bool vertex_has_color() const { return check(VertexColor); } bool vertex_has_color() const { return check(VertexColor); }
bool vertex_has_texcoord() const { return check(VertexTexCoord); } 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_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_normal() const { return check(FaceNormal); }
bool face_has_color() const { return check(FaceColor); } bool face_has_color() const { return check(FaceColor); }
bool face_has_texcoord() const { return check(FaceTexCoord); } 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_has_alpha() const { return check(ColorAlpha); }
bool color_is_float() const { return check(ColorFloat); } bool color_is_float() const { return check(ColorFloat); }

View File

@@ -104,12 +104,14 @@ public:
virtual Vec4f colorAf(VertexHandle _vh) const = 0; virtual Vec4f colorAf(VertexHandle _vh) const = 0;
virtual Vec2f texcoord(VertexHandle _vh) const = 0; virtual Vec2f texcoord(VertexHandle _vh) const = 0;
virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0; virtual Vec2f texcoord(HalfedgeHandle _heh) const = 0;
virtual OpenMesh::Attributes::StatusInfo status(VertexHandle _vh) const = 0;
// get face data // get face data
virtual unsigned int virtual unsigned int
get_vhandles(FaceHandle _fh, get_vhandles(FaceHandle _fh,
std::vector<VertexHandle>& _vhandles) const=0; std::vector<VertexHandle>& _vhandles) const=0;
/// ///
/// \brief getHeh returns the HalfEdgeHandle that belongs to the face /// \brief getHeh returns the HalfEdgeHandle that belongs to the face
/// specified by _fh and has a toVertexHandle that corresponds to _vh. /// specified by _fh and has a toVertexHandle that corresponds to _vh.
@@ -127,6 +129,7 @@ public:
virtual Vec4ui colorAi(FaceHandle _fh) const = 0; virtual Vec4ui colorAi(FaceHandle _fh) const = 0;
virtual Vec3f colorf(FaceHandle _fh) const = 0; virtual Vec3f colorf(FaceHandle _fh) const = 0;
virtual Vec4f colorAf(FaceHandle _fh) const = 0; virtual Vec4f colorAf(FaceHandle _fh) const = 0;
virtual OpenMesh::Attributes::StatusInfo status(FaceHandle _fh) const = 0;
// get edge data // get edge data
virtual Vec3uc color(EdgeHandle _eh) const = 0; virtual Vec3uc color(EdgeHandle _eh) const = 0;
@@ -135,6 +138,15 @@ public:
virtual Vec4ui colorAi(EdgeHandle _eh) const = 0; virtual Vec4ui colorAi(EdgeHandle _eh) const = 0;
virtual Vec3f colorf(EdgeHandle _eh) const = 0; virtual Vec3f colorf(EdgeHandle _eh) const = 0;
virtual Vec4f colorAf(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 // get reference to base kernel
virtual const BaseKernel* kernel() { return 0; } virtual const BaseKernel* kernel() { return 0; }
@@ -150,10 +162,14 @@ public:
virtual bool is_triangle_mesh() const { return false; } virtual bool is_triangle_mesh() const { return false; }
virtual bool has_vertex_normals() const { return false; } virtual bool has_vertex_normals() const { return false; }
virtual bool has_vertex_colors() 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_vertex_texcoords() const { return false; }
virtual bool has_edge_colors() 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_normals() const { return false; }
virtual bool has_face_colors() const { return false; } virtual bool has_face_colors() const { return false; }
virtual bool has_face_status() const { return false; }
}; };

View File

@@ -171,6 +171,13 @@ public:
: Vec2f(0.0f, 0.0f)); : 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 // get edge data
Vec3uc color(EdgeHandle _eh) const Vec3uc color(EdgeHandle _eh) const
@@ -215,6 +222,47 @@ public:
: Vec4f(0, 0, 0, 0)); : Vec4f(0, 0, 0, 0));
} }
OpenMesh::Attributes::StatusInfo status(EdgeHandle _eh) const
{
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();
}
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();
}
OpenMesh::Attributes::StatusInfo status(HalfedgeHandle _heh) const
{
if (mesh_.has_halfedge_status())
return mesh_.status(_heh);
return OpenMesh::Attributes::StatusInfo();
}
// get face data // get face data
unsigned int get_vhandles(FaceHandle _fh, unsigned int get_vhandles(FaceHandle _fh,
@@ -304,6 +352,13 @@ public:
: Vec4f(0, 0, 0, 0)); : 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_; } virtual const BaseKernel* kernel() { return &mesh_; }
@@ -320,9 +375,13 @@ public:
bool has_vertex_normals() const { return mesh_.has_vertex_normals(); } bool has_vertex_normals() const { return mesh_.has_vertex_normals(); }
bool has_vertex_colors() const { return mesh_.has_vertex_colors(); } bool has_vertex_colors() const { return mesh_.has_vertex_colors(); }
bool has_vertex_texcoords() const { return mesh_.has_vertex_texcoords2D(); } 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_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_normals() const { return mesh_.has_face_normals(); }
bool has_face_colors() const { return mesh_.has_face_colors(); } bool has_face_colors() const { return mesh_.has_face_colors(); }
bool has_face_status() const { return mesh_.has_face_status(); }
private: private:

View File

@@ -99,10 +99,16 @@ public:
// add a vertex without coordinate. Use set_point to set the position deferred // add a vertex without coordinate. Use set_point to set the position deferred
virtual VertexHandle add_vertex() = 0; 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 // add a face with indices _indices refering to vertices
typedef std::vector<VertexHandle> VHandles; typedef std::vector<VertexHandle> VHandles;
virtual FaceHandle add_face(const VHandles& _indices) = 0; 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 // add texture coordinates per face, _vh references the first texcoord
virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector<Vec2f>& _face_texcoords) = 0; virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector<Vec2f>& _face_texcoords) = 0;
@@ -115,6 +121,9 @@ public:
// Set coordinate of the given vertex. Use this function, if you created a vertex without coordinate // 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; 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 // set vertex normal
virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0; virtual void set_normal(VertexHandle _vh, const Vec3f& _normal) = 0;
@@ -133,6 +142,15 @@ public:
// set vertex texture coordinate // set vertex texture coordinate
virtual void set_texcoord(VertexHandle _vh, const Vec2f& _texcoord) = 0; 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;
// set incident face handle for given halfedge
virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) = 0;
// set vertex texture coordinate // set vertex texture coordinate
virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0; virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) = 0;
@@ -142,6 +160,9 @@ public:
// set 3d vertex texture coordinate // set 3d vertex texture coordinate
virtual void set_texcoord(HalfedgeHandle _heh, const Vec3f& _texcoord) = 0; 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 // set edge color
virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0; virtual void set_color(EdgeHandle _eh, const Vec3uc& _color) = 0;
@@ -154,6 +175,9 @@ public:
// set edge color // set edge color
virtual void set_color(EdgeHandle _eh, const Vec4f& _color) = 0; 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 // set face normal
virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0; virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) = 0;
@@ -169,6 +193,9 @@ public:
// set face color // set face color
virtual void set_color(FaceHandle _fh, const Vec4f& _color) = 0; 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 // 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 // Use set_face_texindex to set the index for each face
virtual void add_texture_information( int _id , std::string _name ) = 0; virtual void add_texture_information( int _id , std::string _name ) = 0;

View File

@@ -107,6 +107,11 @@ public:
return mesh_.new_vertex(); 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) virtual FaceHandle add_face(const VHandles& _indices)
{ {
FaceHandle fh; FaceHandle fh;
@@ -192,6 +197,13 @@ public:
return fh; return fh;
} }
virtual FaceHandle add_face(HalfedgeHandle _heh) override
{
auto fh = mesh_.new_face();
mesh_.set_halfedge_handle(fh, _heh);
return fh;
}
// vertex attributes // vertex attributes
virtual void set_point(VertexHandle _vh, const Vec3f& _point) virtual void set_point(VertexHandle _vh, const Vec3f& _point)
@@ -199,6 +211,11 @@ public:
mesh_.set_point(_vh,vector_cast<Point>(_point)); mesh_.set_point(_vh,vector_cast<Point>(_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) virtual void set_normal(VertexHandle _vh, const Vec3f& _normal)
{ {
if (mesh_.has_vertex_normals()) if (mesh_.has_vertex_normals())
@@ -240,6 +257,24 @@ public:
mesh_.set_texcoord2D(_vh, vector_cast<TexCoord2D>(_texcoord)); mesh_.set_texcoord2D(_vh, vector_cast<TexCoord2D>(_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);
}
virtual void set_face(HalfedgeHandle _heh, FaceHandle _fh) override
{
mesh_.set_face_handle(_heh, _fh);
}
virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord) virtual void set_texcoord(HalfedgeHandle _heh, const Vec2f& _texcoord)
{ {
if (mesh_.has_halfedge_texcoords2D()) if (mesh_.has_halfedge_texcoords2D())
@@ -258,6 +293,12 @@ public:
mesh_.set_texcoord3D(_heh, vector_cast<TexCoord3D>(_texcoord)); mesh_.set_texcoord3D(_heh, vector_cast<TexCoord3D>(_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 // edge attributes
@@ -285,6 +326,13 @@ public:
mesh_.set_color(_eh, color_cast<Color>(_color)); mesh_.set_color(_eh, color_cast<Color>(_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 // face attributes
virtual void set_normal(FaceHandle _fh, const Vec3f& _normal) virtual void set_normal(FaceHandle _fh, const Vec3f& _normal)
@@ -317,6 +365,13 @@ public:
mesh_.set_color(_fh, color_cast<Color>(_color)); mesh_.set_color(_fh, color_cast<Color>(_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<Vec2f>& _face_texcoords) virtual void add_face_texcoords( FaceHandle _fh, VertexHandle _vh, const std::vector<Vec2f>& _face_texcoords)
{ {
// get first halfedge handle // get first halfedge handle

View File

@@ -61,6 +61,7 @@
#include <OpenMesh/Core/Utils/Endian.hh> #include <OpenMesh/Core/Utils/Endian.hh>
#include <OpenMesh/Core/IO/OMFormat.hh> #include <OpenMesh/Core/IO/OMFormat.hh>
#include <OpenMesh/Core/IO/reader/OMReader.hh> #include <OpenMesh/Core/IO/reader/OMReader.hh>
#include <OpenMesh/Core/IO/writer/OMWriter.hh>
//=== NAMESPACES ============================================================== //=== NAMESPACES ==============================================================
@@ -176,6 +177,15 @@ bool _OMReader_::read_binary(std::istream& _is, BaseImporter& _bi, Options& _opt
bytes_ += restore(_is, header_, swap); 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()) { while (!_is.eof()) {
bytes_ += restore(_is, chunk_header_, swap); bytes_ += restore(_is, chunk_header_, swap);
@@ -294,6 +304,7 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi,
OpenMesh::Vec3f v3f; OpenMesh::Vec3f v3f;
OpenMesh::Vec2f v2f; OpenMesh::Vec2f v2f;
OpenMesh::Vec3uc v3uc; // rgb OpenMesh::Vec3uc v3uc; // rgb
OpenMesh::Attributes::StatusInfo status;
OMFormat::Chunk::PropertyName custom_prop; OMFormat::Chunk::PropertyName custom_prop;
@@ -343,6 +354,20 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi,
} }
break; 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: case Chunk::Type_Custom:
bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap); bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_vprop(property_name_), header_.n_vertices_, _swap);
@@ -351,6 +376,19 @@ bool _OMReader_::read_binary_vertex_chunk(std::istream &_is, BaseImporter &_bi,
break; 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<int>(vidx)), HalfedgeHandle(halfedge_id));
}
}
break;
default: // skip unknown chunks default: // skip unknown chunks
{ {
omerr() << "Unknown chunk type ignored!\n"; omerr() << "Unknown chunk type ignored!\n";
@@ -376,34 +414,51 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op
size_t fidx = 0; size_t fidx = 0;
OpenMesh::Vec3f v3f; // normal OpenMesh::Vec3f v3f; // normal
OpenMesh::Vec3uc v3uc; // rgb OpenMesh::Vec3uc v3uc; // rgb
OpenMesh::Attributes::StatusInfo status;
switch (chunk_header_.type_) { switch (chunk_header_.type_) {
case Chunk::Type_Topology: { case Chunk::Type_Topology:
BaseImporter::VHandles vhandles; {
size_t nV = 0; if (header_.version_ < OMFormat::mk_version(2,0))
size_t vidx = 0; {
// add faces based on vertex indices
BaseImporter::VHandles vhandles;
size_t nV = 0;
size_t vidx = 0;
switch (header_.mesh_) { switch (header_.mesh_) {
case 'T': case 'T':
nV = 3; nV = 3;
break; break;
case 'Q': case 'Q':
nV = 4; nV = 4;
break; 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)));
} }
_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 simply setting an incident halfedge
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; break;
@@ -430,6 +485,19 @@ bool _OMReader_::read_binary_face_chunk(std::istream &_is, BaseImporter &_bi, Op
_bi.set_color(FaceHandle(int(fidx)), v3uc); _bi.set_color(FaceHandle(int(fidx)), v3uc);
} }
break; 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: case Chunk::Type_Custom:
@@ -453,7 +521,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; using OMFormat::Chunk;
@@ -461,6 +529,8 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op
size_t b = bytes_; size_t b = bytes_;
OpenMesh::Attributes::StatusInfo status;
switch (chunk_header_.type_) { switch (chunk_header_.type_) {
case Chunk::Type_Custom: case Chunk::Type_Custom:
@@ -468,6 +538,20 @@ bool _OMReader_::read_binary_edge_chunk(std::istream &_is, BaseImporter &_bi, Op
break; break;
case Chunk::Type_Status:
{
assert( OMFormat::dimensions(chunk_header_) == 1);
fileOptions_ += Options::Status;
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);
}
break;
}
default: default:
// skip unknown type // skip unknown type
size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_); size_t size_of = OMFormat::chunk_data_size(header_, chunk_header_);
@@ -481,13 +565,14 @@ 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; using OMFormat::Chunk;
assert( chunk_header_.entity_ == Chunk::Entity_Halfedge); assert( chunk_header_.entity_ == Chunk::Entity_Halfedge);
size_t b = bytes_; size_t b = bytes_;
OpenMesh::Attributes::StatusInfo status;
switch (chunk_header_.type_) { switch (chunk_header_.type_) {
case Chunk::Type_Custom: case Chunk::Type_Custom:
@@ -495,6 +580,55 @@ 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); bytes_ += restore_binary_custom_data(_is, _bi.kernel()->_get_hprop(property_name_), 2 * header_.n_edges_, _swap);
break; break;
case Chunk::Type_Topology:
{
std::vector<HalfedgeHandle> 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<int>(i)), next_halfedges[i]);
}
break;
case Chunk::Type_Status:
{
assert( OMFormat::dimensions(chunk_header_) == 1);
fileOptions_ += Options::Status;
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);
}
break;
}
default: default:
// skip unknown chunk // skip unknown chunk
omerr() << "Unknown chunk type ignored!\n"; omerr() << "Unknown chunk type ignored!\n";

View File

@@ -86,7 +86,7 @@ _OMWriter_& OMWriter() { return __OMWriterInstance; }
const OMFormat::uchar _OMWriter_::magic_[3] = "OM"; 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_:: _OMWriter_::
@@ -187,8 +187,6 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
unsigned int i, nV, nF; unsigned int i, nV, nF;
Vec3f v; Vec3f v;
Vec2f t; Vec2f t;
std::vector<VertexHandle> vhandles;
// -------------------- write header // -------------------- write header
OMFormat::Header header; OMFormat::Header header;
@@ -286,6 +284,50 @@ 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(_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;
for (i=0; i<nE; ++i)
{
auto next_id = _be.get_next_halfedge_id(HalfedgeHandle(static_cast<int>(i)));
auto to_vertex_id = _be.get_to_vertex_id(HalfedgeHandle(static_cast<int>(i)));
auto face_id = _be.get_face_id(HalfedgeHandle(static_cast<int>(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()*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<nV; ++i)
bytes += store( _os, _be.get_halfedge_id(VertexHandle(i)), OMFormat::Chunk::Integer_Size(chunk_header.bits_), swap );
}
// -------------------- write face data // -------------------- write face data
// ---------- write topology // ---------- write topology
@@ -293,27 +335,17 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
chunk_header.name_ = false; chunk_header.name_ = false;
chunk_header.entity_ = OMFormat::Chunk::Entity_Face; chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
chunk_header.type_ = OMFormat::Chunk::Type_Topology; chunk_header.type_ = OMFormat::Chunk::Type_Topology;
chunk_header.signed_ = 0; chunk_header.signed_ = true;
chunk_header.float_ = 0; 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; // ignored chunk_header.dim_ = OMFormat::Chunk::Dim_1D;
chunk_header.bits_ = OMFormat::needed_bits(_be.n_vertices()); 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 ); bytes += store( _os, chunk_header, swap );
for (i=0, nF=header.n_faces_; i<nF; ++i) for (i=0, nF=header.n_faces_; i<nF; ++i)
{ {
//nV = _be.get_vhandles(FaceHandle(i), vhandles); auto size = OMFormat::Chunk::Integer_Size(chunk_header.bits_);
_be.get_vhandles(FaceHandle(i), vhandles); bytes += store( _os, _be.get_halfedge_id(FaceHandle(i)), size, swap);
if ( header.mesh_ == 'P' )
bytes += store( _os, vhandles.size(), OMFormat::Chunk::Integer_16, swap );
for (size_t j=0; j < vhandles.size(); ++j)
{
using namespace OMFormat;
using namespace GenProg;
bytes += store( _os, vhandles[j].idx(), Chunk::Integer_Size(chunk_header.bits_), swap );
}
} }
} }
@@ -385,6 +417,82 @@ bool _OMWriter_::write_binary(std::ostream& _os, BaseExporter& _be,
#endif #endif
} }
// ---------- write vertex status
if (_be.n_vertices() && _be.has_vertex_status() && _opt.check(Options::Status))
{
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))
{
auto s = _be.status(EdgeHandle(0));
chunk_header.name_ = false;
chunk_header.entity_ = OMFormat::Chunk::Entity_Edge;
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))
{
auto s = _be.status(HalfedgeHandle(0));
chunk_header.name_ = false;
chunk_header.entity_ = OMFormat::Chunk::Entity_Halfedge;
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))
{
auto s = _be.status(FaceHandle(0));
chunk_header.name_ = false;
chunk_header.entity_ = OMFormat::Chunk::Entity_Face;
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 // -------------------- write custom properties

View File

@@ -111,10 +111,10 @@ public:
bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const; bool write(std::ostream&, BaseExporter&, Options, std::streamsize _precision = 6) const;
size_t binary_size(BaseExporter& _be, Options _opt) const; size_t binary_size(BaseExporter& _be, Options _opt) const;
static OMFormat::uint8 get_version() { return version_; }
protected: protected:

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -72,7 +72,7 @@ TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithTexCoords) {
bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-texCoords.om",options); 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(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(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
@@ -464,11 +464,11 @@ TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) {
Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1); Mesh::EdgeHandle e2 = Mesh::EdgeHandle(1);
Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2); Mesh::EdgeHandle e3 = Mesh::EdgeHandle(2);
int va1ue1 = 10, int value1 = 10,
value2 = 21, value2 = 21,
value3 = 32; value3 = 32;
mesh.property(prop,e1) = va1ue1; mesh.property(prop,e1) = value1;
mesh.property(prop,e2) = value2; mesh.property(prop,e2) = value2;
mesh.property(prop,e3) = value3; 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,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(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(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1";
EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2"; EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2";
@@ -503,6 +503,292 @@ 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<int> 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 "<<filename;
// load
Mesh cmpMesh;
cmpMesh.add_property(prop,propName);
cmpMesh.property(prop).set_persistent(true);
ok = OpenMesh::IO::read_mesh(cmpMesh,filename);
EXPECT_TRUE(ok) << "Unable to read "<<filename;
// compare
EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
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(c , cmpMesh.point(v4)) << "Wrong coordinates at vertex 3";
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";
EXPECT_EQ(value4 , cmpMesh.property(prop,e4)) << "Wrong property at edge 3";
EXPECT_EQ(value5 , cmpMesh.property(prop,e5)) << "Wrong property at edge 4";
EXPECT_EQ(value6 , cmpMesh.property(prop,e6)) << "Wrong property at edge 5";
// The above only shows that the edge properties are stored in the same order which is not what we want if the edges are different
// Check edge properties based on edges defined by from and to vertex
for (auto eh : mesh.edges())
{
auto heh = mesh.halfedge_handle(eh, 0);
auto from_vh = mesh.from_vertex_handle(heh);
auto to_vh = mesh.to_vertex_handle(heh);
// find corresponding halfedge in loaded mesh
auto cmpHeh = cmpMesh.find_halfedge(from_vh, to_vh);
auto cmpEh = cmpMesh.edge_handle(cmpHeh);
EXPECT_EQ(mesh.property(prop, eh), cmpMesh.property(prop, cmpEh)) << "Wrong property at input edge " << eh.idx()
<< " corresponding to edge " << cmpEh.idx() << " in the loaded Mesh";
}
// cleanup
remove(filename.c_str());
}
/*
* 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<bool> vertex_deleted;
std::vector<bool> vertex_selected;
std::vector<bool> vertex_feature;
std::vector<bool> vertex_tagged;
std::vector<bool> 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<bool> edge_deleted;
std::vector<bool> edge_selected;
std::vector<bool> edge_feature;
std::vector<bool> edge_tagged;
std::vector<bool> 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<bool> halfedge_deleted;
std::vector<bool> halfedge_selected;
std::vector<bool> halfedge_feature;
std::vector<bool> halfedge_tagged;
std::vector<bool> 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<bool> face_deleted;
std::vector<bool> face_selected;
std::vector<bool> face_feature;
std::vector<bool> face_tagged;
std::vector<bool> 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 = OpenMesh::IO::Options::Status;
bool ok = OpenMesh::IO::write_mesh(mesh,filename, options);
EXPECT_TRUE(ok) << "Unable to write "<<filename;
// load
Mesh cmpMesh;
cmpMesh.request_vertex_status();
cmpMesh.request_edge_status();
cmpMesh.request_halfedge_status();
cmpMesh.request_face_status();
ok = OpenMesh::IO::read_mesh(cmpMesh,filename, options);
EXPECT_TRUE(ok) << "Unable to read "<<filename;
// compare
EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v0)) << "Wrong coordinates at vertex 0";
EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 1";
EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 2";
EXPECT_EQ(c , cmpMesh.point(v3)) << "Wrong coordinates at vertex 3";
for (auto vh : cmpMesh.all_vertices())
{
EXPECT_EQ(cmpMesh.status(vh).deleted(), vertex_deleted [vh.idx()]) << "Wrong deleted status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).selected(), vertex_selected[vh.idx()]) << "Wrong selected status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).feature(), vertex_feature [vh.idx()]) << "Wrong feature status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).tagged(), vertex_tagged [vh.idx()]) << "Wrong tagged status at vertex " << vh.idx();
EXPECT_EQ(cmpMesh.status(vh).tagged2(), vertex_tagged2 [vh.idx()]) << "Wrong tagged2 status at vertex " << vh.idx();
}
for (auto eh : cmpMesh.all_edges())
{
EXPECT_EQ(cmpMesh.status(eh).deleted(), edge_deleted [eh.idx()]) << "Wrong deleted status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).selected(), edge_selected[eh.idx()]) << "Wrong selected status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).feature(), edge_feature [eh.idx()]) << "Wrong feature status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).tagged(), edge_tagged [eh.idx()]) << "Wrong tagged status at edge " << eh.idx();
EXPECT_EQ(cmpMesh.status(eh).tagged2(), edge_tagged2 [eh.idx()]) << "Wrong tagged2 status at edge " << eh.idx();
}
for (auto heh : cmpMesh.all_halfedges())
{
EXPECT_EQ(cmpMesh.status(heh).deleted(), halfedge_deleted [heh.idx()]) << "Wrong deleted status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).selected(), halfedge_selected[heh.idx()]) << "Wrong selected status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).feature(), halfedge_feature [heh.idx()]) << "Wrong feature status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).tagged(), halfedge_tagged [heh.idx()]) << "Wrong tagged status at halfedge " << heh.idx();
EXPECT_EQ(cmpMesh.status(heh).tagged2(), halfedge_tagged2 [heh.idx()]) << "Wrong tagged2 status at halfedge " << heh.idx();
}
for (auto fh : cmpMesh.all_faces())
{
EXPECT_EQ(cmpMesh.status(fh).deleted(), face_deleted [fh.idx()]) << "Wrong deleted status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).selected(), face_selected[fh.idx()]) << "Wrong selected status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).feature(), face_feature [fh.idx()]) << "Wrong feature status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).tagged(), face_tagged [fh.idx()]) << "Wrong tagged status at face " << fh.idx();
EXPECT_EQ(cmpMesh.status(fh).tagged2(), face_tagged2 [fh.idx()]) << "Wrong tagged2 status at face " << fh.idx();
}
// cleanup
remove(filename.c_str());
}
/* /*
* Save and load simple mesh with custom property * Save and load simple mesh with custom property
*/ */
@@ -670,4 +956,469 @@ TEST_F(OpenMeshReadWriteOM, ReadBigMeshWithCustomProperty) {
EXPECT_FALSE(wrong) << "min one vertex has worng vertex property"; 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_halfedge_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";
}
}
/*
* 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!";
}
/*
* Try to load mesh from om file with a version that is not yet supported
*/
TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_7_5) {
PolyMesh mesh;
std::string file_name = "cube_tri_version_7_5.om";
bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
EXPECT_FALSE(ok) << file_name;
}
} }