...
 
Commits (14)
......@@ -32,6 +32,7 @@
<li>enable c++11 features of many classes for Visual Studio 2013</li>
<li>Fixed broken version macros (Thanks to Frederik Salomonsson for the fix)</li>
<li>Fixed Build on gcc-7.2 (Thanks to Gero Müller and Martial Tola for the patches)</li>
<li>Small compilation fix for MINGW64 cross-compilation(Thanks to Manuel Massing for the patch)</li>
</ul>
<b>Tools</b>
......@@ -53,14 +54,17 @@
<li>ImporterT: Modified the add_face function of importerT to always return a valid FaceHandle</li>
<li>ImporterT: Return a valid FaceHandle when adding non-manifold faces.</li>
<li>BaseExporter: Added accessor functions for HalfEdgeHandles and faceTexCoords to base exporter and exporter template.</li>
<li>OBJ Writer: Fail if vertex color export was requested (Thanks to Manuel Massing)</li>
<li>OBJ Writer: Added functionality to store FaceTexCoords to objwriter</li>
<li>OBJ Writer: Applied fix for bad or missing vertex tex coords (Thanks to Gero Müller for the patch)</li>>
<li>OBJ Writer: Fix vertex texture coordinates export in OBJ writer</li>
<li>OBJ Loader: range check for vertex colors and normals in OBJ loader</li>
<li>OBJ Loader: fixed handling of negative indices in OBJ loader</li>
<li>OM Writer: Fixed OMWriter when no faces are available (Thanks to Jamie Kydd for the patch)</li>
<li>OM Writer: Added Mark to the format header to identify end of stream correctly (Thanks to Jamie Kydd for the patch)</li>
<li>PLY Reader: Skip reading extra elements after face</li>
<li>PLY Reader: Return error when reaching EOF</li>
<li>OMFormat: Fix implicit fallthrough warning on gcc(Thanks to Manuel Massing for the patch)</li>
</ul>
<b>Unittests</b>
......
......@@ -315,16 +315,16 @@ namespace OMFormat {
/// Return the size of chunk data in bytes
inline size_t chunk_data_size( Header& _hdr, Chunk::Header& _chunk_hdr )
{
size_t C = 0;
size_t C;
switch( _chunk_hdr.entity_ )
{
case Chunk::Entity_Vertex: C = _hdr.n_vertices_; break;
case Chunk::Entity_Face: C = _hdr.n_faces_; break;
case Chunk::Entity_Halfedge: C = _hdr.n_edges_; // no break!
case Chunk::Entity_Edge: C += _hdr.n_edges_; break;
case Chunk::Entity_Halfedge: C = _hdr.n_edges_*2; break;
case Chunk::Entity_Edge: C = _hdr.n_edges_; break;
case Chunk::Entity_Mesh: C = 1; break;
default:
C = 0;
std::cerr << "Invalid value in _chunk_hdr.entity_\n";
assert( false );
break;
......
......@@ -224,12 +224,22 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
if (!check( _be, _opt))
return false;
// No binary mode for OBJ
if ( _opt.check(Options::Binary) ) {
omout() << "[OBJWriter] : Warning, Binary mode requested for OBJ Writer (No support for Binary mode), falling back to standard." << std::endl;
}
// check writer features
if ( _opt.check(Options::Binary) || // not supported by format
_opt.check(Options::FaceNormal))
return false;
// check for unsupported writer features
if (_opt.check(Options::FaceNormal) ) {
omerr() << "[OBJWriter] : FaceNormal not supported by OBJ Writer" << std::endl;
return false;
}
// check for unsupported writer features
if (_opt.check(Options::VertexColor) ) {
omerr() << "[OBJWriter] : VertexColor not supported by OBJ Writer" << std::endl;
return false;
}
//create material file if needed
if ( _opt.check(Options::FaceColor) ){
......@@ -270,10 +280,10 @@ write(std::ostream& _out, BaseExporter& _be, Options _opt, std::streamsize _prec
}
}
//collect Texturevertices from vertices
//collect Texture coordinates from vertices
if(_opt.check(Options::VertexTexCoord))
{
for (size_t i=0, nF=_be.n_faces(); i<nF; ++i)
for (size_t i=0, nV=_be.n_vertices(); i<nV; ++i)
{
vh = VertexHandle(static_cast<int>(i));
t = _be.texcoord(vh);
......
......@@ -777,6 +777,11 @@ void PolyConnectivity::collapse_edge(HalfedgeHandle _hh)
// delete stuff
status(edge_handle(h)).set_deleted(true);
status(vo).set_deleted(true);
if (has_halfedge_status())
{
status(h).set_deleted(true);
status(o).set_deleted(true);
}
}
//-----------------------------------------------------------------------------
......@@ -827,6 +832,11 @@ void PolyConnectivity::collapse_loop(HalfedgeHandle _hh)
status(fh).set_deleted(true);
}
status(edge_handle(h0)).set_deleted(true);
if (has_halfedge_status())
{
status(h0).set_deleted(true);
status(o0).set_deleted(true);
}
}
//-----------------------------------------------------------------------------
......
......@@ -1138,45 +1138,89 @@ public:
PolyConnectivity::ConstVertexIter,
&PolyConnectivity::vertices_begin,
&PolyConnectivity::vertices_end> ConstVertexRange;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstVertexIter,
&PolyConnectivity::vertices_sbegin,
&PolyConnectivity::vertices_end> ConstVertexRangeSkipping;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstHalfedgeIter,
&PolyConnectivity::halfedges_begin,
&PolyConnectivity::halfedges_end> ConstHalfedgeRange;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstHalfedgeIter,
&PolyConnectivity::halfedges_sbegin,
&PolyConnectivity::halfedges_end> ConstHalfedgeRangeSkipping;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstEdgeIter,
&PolyConnectivity::edges_begin,
&PolyConnectivity::edges_end> ConstEdgeRange;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstEdgeIter,
&PolyConnectivity::edges_sbegin,
&PolyConnectivity::edges_end> ConstEdgeRangeSkipping;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstFaceIter,
&PolyConnectivity::faces_begin,
&PolyConnectivity::faces_end> ConstFaceRange;
typedef EntityRange<
const PolyConnectivity,
PolyConnectivity::ConstFaceIter,
&PolyConnectivity::faces_sbegin,
&PolyConnectivity::faces_end> ConstFaceRangeSkipping;
/**
* @return The vertices as a range object suitable
* for C++11 range based for loops.
* for C++11 range based for loops. Will skip deleted vertices.
*/
ConstVertexRange vertices() const { return ConstVertexRange(*this); }
ConstVertexRangeSkipping vertices() const { return ConstVertexRangeSkipping(*this); }
/**
* @return The vertices as a range object suitable
* for C++11 range based for loops. Will include deleted vertices.
*/
ConstVertexRange all_vertices() const { return ConstVertexRange(*this); }
/**
* @return The halfedges as a range object suitable
* for C++11 range based for loops.
* for C++11 range based for loops. Will skip deleted halfedges.
*/
ConstHalfedgeRange halfedges() const { return ConstHalfedgeRange(*this); }
ConstHalfedgeRangeSkipping halfedges() const { return ConstHalfedgeRangeSkipping(*this); }
/**
* @return The edges as a range object suitabl
* for C++11 range based for loops.
* @return The halfedges as a range object suitable
* for C++11 range based for loops. Will include deleted halfedges.
*/
ConstHalfedgeRange all_halfedges() const { return ConstHalfedgeRange(*this); }
/**
* @return The edges as a range object suitable
* for C++11 range based for loops. Will skip deleted edges.
*/
ConstEdgeRangeSkipping edges() const { return ConstEdgeRangeSkipping(*this); }
/**
* @return The edges as a range object suitable
* for C++11 range based for loops. Will include deleted edges.
*/
ConstEdgeRange all_edges() const { return ConstEdgeRange(*this); }
/**
* @return The faces as a range object suitable
* for C++11 range based for loops. Will skip deleted faces.
*/
ConstEdgeRange edges() const { return ConstEdgeRange(*this); }
ConstFaceRangeSkipping faces() const { return ConstFaceRangeSkipping(*this); }
/**
* @return The faces as a range object suitable
* for C++11 range based for loops.
* for C++11 range based for loops. Will include deleted faces.
*/
ConstFaceRange faces() const { return ConstFaceRange(*this); }
ConstFaceRange all_faces() const { return ConstFaceRange(*this); }
/// Generic class for iterator ranges.
template<
......
......@@ -64,7 +64,7 @@ int getche() { return ::_getche(); }
} // AS
// ----------------------------------------------------------------- Win32 ----
#elif defined(WIN32)
#elif defined(WIN32) || defined(__MINGW32__)
#include <conio.h>
......
......@@ -607,4 +607,139 @@ TEST_F(OpenMeshCollapse, LargeCollapseHalfEdge) {
}
/*
* Test collapsing an halfedge in a triangle mesh
*
*/
TEST_F(OpenMeshCollapse, DeletedStatus) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[6];
vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, 0, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point( 0, 2, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point( 0, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point( 0,-1, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point( 0,-2, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, 0, 0));
// Add two faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[4]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[2]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
/* Test setup:
* 1
* /|\
* / | \
* / _2_ \
* /_/ | \_\
* 0__ | __5
* \ \_3_/ /
* \ | /
* \ | /
* \|/
* 4
*/
EXPECT_EQ(mesh_.n_faces(), 6u) << "Could not add all faces";
// Request the status bits
mesh_.request_vertex_status();
mesh_.request_edge_status();
mesh_.request_halfedge_status();
mesh_.request_face_status();
// =============================================
// Collapse halfedge from 3 to 2
// =============================================
Mesh::HalfedgeHandle heh_collapse = mesh_.find_halfedge(Mesh::VertexHandle(2), Mesh::VertexHandle(3));
EXPECT_TRUE(heh_collapse.is_valid()) << "Could not find halfedge from vertex 2 to vetex 3";
EXPECT_TRUE(mesh_.is_collapse_ok(heh_collapse)) << "Collapse is not ok for halfedge from vertex 2 to vertex 3";
Mesh::HalfedgeHandle top_left = mesh_.find_halfedge(Mesh::VertexHandle(2), Mesh::VertexHandle(0));
Mesh::HalfedgeHandle top_right = mesh_.find_halfedge(Mesh::VertexHandle(5), Mesh::VertexHandle(2));
Mesh::HalfedgeHandle bottom_left = mesh_.find_halfedge(Mesh::VertexHandle(0), Mesh::VertexHandle(3));
Mesh::HalfedgeHandle bottom_right = mesh_.find_halfedge(Mesh::VertexHandle(3), Mesh::VertexHandle(5));
EXPECT_TRUE(top_left.is_valid()) << "Could not find halfedge from vertex 2 to vetex 0";
EXPECT_TRUE(top_right.is_valid()) << "Could not find halfedge from vertex 5 to vetex 2";
EXPECT_TRUE(bottom_left.is_valid()) << "Could not find halfedge from vertex 0 to vetex 3";
EXPECT_TRUE(bottom_right.is_valid()) << "Could not find halfedge from vertex 3 to vetex 5";
Mesh::FaceHandle left = mesh_.face_handle(top_left);
Mesh::FaceHandle right = mesh_.face_handle(top_right);
EXPECT_TRUE(left.is_valid()) << "Could not find left face";
EXPECT_TRUE(right.is_valid()) << "Could not find right";
mesh_.collapse(heh_collapse);
EXPECT_TRUE(mesh_.status(Mesh::VertexHandle(2)).deleted()) << "Collapsed vertex is not deleted.";
EXPECT_TRUE(mesh_.status(left).deleted()) << "Left face is not deleted.";
EXPECT_TRUE(mesh_.status(right).deleted()) << "Right face is not deleted.";
EXPECT_TRUE(mesh_.status(mesh_.edge_handle(heh_collapse)).deleted()) << "Collapsed edge is not deleted.";
EXPECT_TRUE(mesh_.status(mesh_.edge_handle(top_left)).deleted()) << "Top left edge is not deleted.";
EXPECT_TRUE(mesh_.status(mesh_.edge_handle(top_right)).deleted()) << "Top right edge is not deleted.";
EXPECT_FALSE(mesh_.status(mesh_.edge_handle(bottom_left)).deleted()) << "Bottom left edge is deleted.";
EXPECT_FALSE(mesh_.status(mesh_.edge_handle(bottom_right)).deleted()) << "Bottom right edge is deleted.";
EXPECT_TRUE(mesh_.status(heh_collapse).deleted()) << "Collapsed halfedge is not deleted.";
EXPECT_TRUE(mesh_.status(mesh_.opposite_halfedge_handle(heh_collapse)).deleted()) << "Opposite of collapsed halfedge is not deleted.";
EXPECT_TRUE(mesh_.status(top_left).deleted()) << "Halfedge from vertex 0 to vertex 2 is not deleted";
EXPECT_TRUE(mesh_.status(mesh_.opposite_halfedge_handle(top_left)).deleted()) << "Halfedge from vertex 2 to vertex 0 is not deleted";
EXPECT_TRUE(mesh_.status(top_right).deleted()) << "Halfedge from vertex 5 to vertex 2 is not deleted";
EXPECT_TRUE(mesh_.status(mesh_.opposite_halfedge_handle(top_right)).deleted()) << "Halfedge from vertex 2 to vertex 5 is not deleted";
EXPECT_FALSE(mesh_.status(bottom_left).deleted()) << "Halfedge from vertex 0 to vertex 3 is deleted";
EXPECT_FALSE(mesh_.status(mesh_.opposite_halfedge_handle(bottom_left)).deleted()) << "Halfedge from vertex 3 to vertex 0 is deleted";
EXPECT_FALSE(mesh_.status(bottom_right).deleted()) << "Halfedge from vertex 3 to vertex 5 is deleted";
EXPECT_FALSE(mesh_.status(mesh_.opposite_halfedge_handle(bottom_right)).deleted()) << "Halfedge from vertex 5 to vertex 3 is deleted";
}
}
......@@ -773,7 +773,7 @@ TEST_F(OpenMeshIterators, FaceIterEmptyMeshOneDeletedFace) {
vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
// Add two faces
// Add one faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[2]);
......@@ -841,4 +841,154 @@ TEST_F(OpenMeshIterators, FaceIterEmptyMeshOneDeletedFace) {
mesh_.release_face_status();
}
/*
* Test range iterators
*/
TEST_F(OpenMeshIterators, RangeIterators) {
mesh_.clear();
// request delete_face capability
mesh_.request_vertex_status();
mesh_.request_edge_status();
mesh_.request_halfedge_status();
mesh_.request_face_status();
// Add some vertices
Mesh::VertexHandle vhandle[4];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 0, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
// Add two faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[0]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[0]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[2]);
Mesh::FaceHandle fh = mesh_.add_face(face_vhandles);
// Delete one face
mesh_.delete_face(fh);
// Test setup (right face deleted)
// 1 --- 2
// | / |
// | / |
// | / |
// 0 --- 3
// ====== Faces ======
int count_faces_iter = 0;
for (auto f_it = mesh_.faces_begin(); f_it != mesh_.faces_end(); ++f_it)
++count_faces_iter;
EXPECT_EQ(2, count_faces_iter) << "Wrong number of visited faces.";
int count_faces_skipping_iter = 0;
for (auto f_it = mesh_.faces_sbegin(); f_it != mesh_.faces_end(); ++f_it)
++count_faces_skipping_iter;
EXPECT_EQ(1, count_faces_skipping_iter) << "Wrong number of visited faces.";
int count_faces_range = 0;
for (auto fh : mesh_.faces())
++count_faces_range;
EXPECT_EQ(1, count_faces_range) << "Wrong number of visited faces.";
int count_faces_range_all = 0;
for (auto fh : mesh_.all_faces())
++count_faces_range_all;
EXPECT_EQ(2, count_faces_range_all) << "Wrong number of visited faces.";
// ====== Edges ======
int count_edges_iter = 0;
for (auto e_it = mesh_.edges_begin(); e_it != mesh_.edges_end(); ++e_it)
++count_edges_iter;
EXPECT_EQ(5, count_edges_iter) << "Wrong number of visited edges.";
int count_edges_skipping_iter = 0;
for (auto e_it = mesh_.edges_sbegin(); e_it != mesh_.edges_end(); ++e_it)
++count_edges_skipping_iter;
EXPECT_EQ(3, count_edges_skipping_iter) << "Wrong number of visited edges.";
int count_edges_range = 0;
for (auto eh : mesh_.edges())
++count_edges_range;
EXPECT_EQ(3, count_edges_range) << "Wrong number of visited edges.";
int count_edges_range_all = 0;
for (auto eh : mesh_.all_edges())
++count_edges_range_all;
EXPECT_EQ(5, count_edges_range_all) << "Wrong number of visited edges.";
// ====== Halfedges ======
int count_halfedges_iter = 0;
for (auto h_it = mesh_.halfedges_begin(); h_it != mesh_.halfedges_end(); ++h_it)
++count_halfedges_iter;
EXPECT_EQ(10, count_halfedges_iter) << "Wrong number of visited halfedges.";
int count_halfedges_skipping_iter = 0;
for (auto h_it = mesh_.halfedges_sbegin(); h_it != mesh_.halfedges_end(); ++h_it)
++count_halfedges_skipping_iter;
EXPECT_EQ(6, count_halfedges_skipping_iter) << "Wrong number of visited halfedges.";
int count_halfedges_range = 0;
for (auto heh : mesh_.halfedges())
++count_halfedges_range;
EXPECT_EQ(6, count_halfedges_range) << "Wrong number of visited halfedges.";
int count_halfedges_range_all = 0;
for (auto heh : mesh_.all_halfedges())
++count_halfedges_range_all;
EXPECT_EQ(10, count_halfedges_range_all) << "Wrong number of visited halfedges.";
// ====== Vertices ======
int count_vertices_iter = 0;
for (auto v_it = mesh_.vertices_begin(); v_it != mesh_.vertices_end(); ++v_it)
++count_vertices_iter;
EXPECT_EQ(4, count_vertices_iter) << "Wrong number of visited vertices.";
int count_vertices_skipping_iter = 0;
for (auto v_it = mesh_.vertices_sbegin(); v_it != mesh_.vertices_end(); ++v_it)
++count_vertices_skipping_iter;
EXPECT_EQ(3, count_vertices_skipping_iter) << "Wrong number of visited vertices.";
int count_vertices_range = 0;
for (auto vh : mesh_.vertices())
++count_vertices_range;
EXPECT_EQ(3, count_vertices_range) << "Wrong number of visited vertices.";
int count_vertices_range_all = 0;
for (auto vh : mesh_.all_vertices())
++count_vertices_range_all;
EXPECT_EQ(4, count_vertices_range_all) << "Wrong number of visited vertices.";
mesh_.release_vertex_status();
mesh_.release_edge_status();
mesh_.release_halfedge_status();
mesh_.release_face_status();
}
}