diff --git a/Doc/Examples/circulator_functions.cc b/Doc/Examples/circulator_functions.cc
index d43dc4c7..289cc6ef 100644
--- a/Doc/Examples/circulator_functions.cc
+++ b/Doc/Examples/circulator_functions.cc
@@ -32,3 +32,16 @@ FaceEdgeIter OpenMesh::PolyConnectivity::fe_iter (FaceHandle _fh);
// Get the face-face circulator of face _fh
FaceFaceIter OpenMesh::PolyConnectivity::ff_iter (FaceHandle _fh);
+
+/**************************************************
+ * Edge circulators
+ **************************************************/
+
+// Get the edge-vertex circulator of edge _eh
+EdgeVertexIter OpenMesh::PolyConnectivity::ev_iter (EdgeHandle _eh);
+
+// Get the edge-halfedge circulator of edge _eh
+EdgeHalfedgeIter OpenMesh::PolyConnectivity::eh_iter (EdgeHandle _eh);
+
+// Get the edge-face circulator of of edge _eh
+EdgeFaceIter OpenMesh::PolyConnectivity::ef_iter (EdgeHandle _eh);
diff --git a/Doc/changelog.docu b/Doc/changelog.docu
index cb70e049..bc73f013 100644
--- a/Doc/changelog.docu
+++ b/Doc/changelog.docu
@@ -19,6 +19,8 @@
legacy vector min max now take const args to avoid matching std implementations
Fixed several warnings
Make Previous Halfedge Attribute optional again
+Added edge-halfedge, edge-vertex, and edge-face circulators
+Added default argument: mesh.halfedge_handle(eh) is now equivalent to mesh.halfedge_handle(eh, 0)
Tools
diff --git a/Doc/mesh.docu b/Doc/mesh.docu
index 22984d89..2a75419e 100644
--- a/Doc/mesh.docu
+++ b/Doc/mesh.docu
@@ -899,6 +899,12 @@ The circulators around a face are:
\arg \c FaceEdgeIter: iterate over the face's edges.
\arg \c FaceFaceIter: iterate over all edge-neighboring faces.
+The circulators around an edge are:
+
+\arg \c EdgeVertexIter: iterate over the edge's incident vertices.
+\arg \c EdgeHalfedgeIter: iterate over the edge's halfedges.
+\arg \c EdgeFaceIter: iterate over the edge's incident faces.
+
Other circulators:
\arg \c HalfedgeLoopIter: iterate over a sequence of Halfedges. (all Halfedges over a face or a hole)
diff --git a/src/OpenMesh/Core/Mesh/ArrayKernel.hh b/src/OpenMesh/Core/Mesh/ArrayKernel.hh
index b9c97fa1..921907dc 100644
--- a/src/OpenMesh/Core/Mesh/ArrayKernel.hh
+++ b/src/OpenMesh/Core/Mesh/ArrayKernel.hh
@@ -471,7 +471,7 @@ public:
{ return next_halfedge_handle(opposite_halfedge_handle(_heh)); }
// --- edge connectivity ---
- static HalfedgeHandle s_halfedge_handle(EdgeHandle _eh, unsigned int _i)
+ static HalfedgeHandle s_halfedge_handle(EdgeHandle _eh, unsigned int _i = 0)
{
assert(_i<=1);
return HalfedgeHandle((_eh.idx() << 1) + _i);
@@ -480,7 +480,7 @@ public:
static EdgeHandle s_edge_handle(HalfedgeHandle _heh)
{ return EdgeHandle(_heh.idx() >> 1); }
- HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i) const
+ HalfedgeHandle halfedge_handle(EdgeHandle _eh, unsigned int _i = 0) const
{
return s_halfedge_handle(_eh, _i);
}
diff --git a/src/OpenMesh/Core/Mesh/CirculatorsT.hh b/src/OpenMesh/Core/Mesh/CirculatorsT.hh
index d937908b..a869ceb8 100644
--- a/src/OpenMesh/Core/Mesh/CirculatorsT.hh
+++ b/src/OpenMesh/Core/Mesh/CirculatorsT.hh
@@ -44,7 +44,7 @@
//=============================================================================
//
-// Vertex and Face circulators for PolyMesh/TriMesh
+// Vertex, Face, and Edge circulators for PolyMesh/TriMesh
//
//=============================================================================
@@ -98,6 +98,19 @@ class GenericCirculator_CenterEntityFnsT
}
};
+template
+class GenericCirculator_CenterEntityFnsT {
+ public:
+ inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) {
+ heh = mesh->opposite_halfedge_handle(heh);
+ if (heh == start) ++lap_counter;
+ }
+ inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, const typename Mesh::HalfedgeHandle &start, int &lap_counter) {
+ if (heh == start) --lap_counter;
+ heh = mesh->opposite_halfedge_handle(heh);
+ }
+};
+
/////////////////////////////////////////////////////////////
// CCW
@@ -150,6 +163,14 @@ class GenericCirculator_DereferenciabilityCheckT
+class GenericCirculator_DereferenciabilityCheckT {
+ public:
+ inline static bool isDereferenciable(const Mesh *mesh, const typename Mesh::HalfedgeHandle &heh) {
+ return mesh->face_handle(heh).is_valid();
+ }
+};
+
template
class GenericCirculator_ValueHandleFnsT {
public:
diff --git a/src/OpenMesh/Core/Mesh/PolyConnectivity.hh b/src/OpenMesh/Core/Mesh/PolyConnectivity.hh
index b34d2a19..005cd0f6 100644
--- a/src/OpenMesh/Core/Mesh/PolyConnectivity.hh
+++ b/src/OpenMesh/Core/Mesh/PolyConnectivity.hh
@@ -379,6 +379,53 @@ public:
typedef FaceFaceCWIter ConstFaceFaceCWIter;
typedef FaceFaceCCWIter ConstFaceFaceCCWIter;
+ /*
+ * Edge-centered circulators
+ */
+
+ struct EdgeVertexTraits
+ {
+ using Mesh = This;
+ using CenterEntityHandle = This::EdgeHandle;
+ using ValueHandle = This::VertexHandle;
+ static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->from_vertex_handle(_heh); }
+ };
+
+ /**
+ * Enumerate vertices incident to an edge.
+ */
+ typedef Iterators::GenericCirculatorT_DEPRECATED EdgeVertexIter;
+
+ struct EdgeHalfedgeTraits
+ {
+ using Mesh = This;
+ using CenterEntityHandle = This::EdgeHandle;
+ using ValueHandle = This::HalfedgeHandle;
+ static ValueHandle toHandle(const Mesh* const /* _mesh */, This::HalfedgeHandle _heh) { return _heh; }
+ };
+
+ /**
+ * Enumerate the halfedges of an edge.
+ */
+ typedef Iterators::GenericCirculatorT_DEPRECATED EdgeHalfedgeIter;
+
+ struct EdgeFaceTraits
+ {
+ using Mesh = This;
+ using CenterEntityHandle = This::EdgeHandle;
+ using ValueHandle = This::FaceHandle;
+ static ValueHandle toHandle(const Mesh* const _mesh, This::HalfedgeHandle _heh) { return static_cast(_mesh)->face_handle(_heh); }
+ };
+
+ /**
+ * Enumerate faces incident to an edge.
+ */
+ typedef Iterators::GenericCirculatorT_DEPRECATED EdgeFaceIter;
+
+ typedef EdgeVertexIter ConstEdgeVertexIter;
+ typedef EdgeHalfedgeIter ConstEdgeHalfedgeIter;
+ typedef EdgeFaceIter ConstEdgeFaceIter;
+
/*
* Halfedge circulator
*/
@@ -435,6 +482,9 @@ public:
typedef FaceEdgeCWIter FECWIter;
typedef FaceEdgeCCWIter FECWWIter;
typedef FaceFaceIter FFIter;
+ typedef EdgeVertexIter EVIter;
+ typedef EdgeHalfedgeIter EHIter;
+ typedef EdgeFaceIter EFIter;
typedef ConstVertexVertexIter CVVIter;
typedef ConstVertexVertexCWIter CVVCWIter;
@@ -463,6 +513,9 @@ public:
typedef ConstFaceFaceIter CFFIter;
typedef ConstFaceFaceCWIter CFFCWIter;
typedef ConstFaceFaceCCWIter CFFCCWIter;
+ typedef ConstEdgeVertexIter CEVIter;
+ typedef ConstEdgeHalfedgeIter CEHIter;
+ typedef ConstEdgeFaceIter CEFIter;
//@}
public:
@@ -600,14 +653,14 @@ public:
using ArrayKernel::s_halfedge_handle;
using ArrayKernel::s_edge_handle;
- static SmartHalfedgeHandle s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i);
+ static SmartHalfedgeHandle s_halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0);
static SmartEdgeHandle s_edge_handle(SmartHalfedgeHandle _heh);
using ArrayKernel::halfedge_handle;
using ArrayKernel::edge_handle;
using ArrayKernel::face_handle;
- inline SmartHalfedgeHandle halfedge_handle(SmartEdgeHandle _eh, unsigned int _i) const;
+ inline SmartHalfedgeHandle halfedge_handle(SmartEdgeHandle _eh, unsigned int _i = 0) const;
inline SmartHalfedgeHandle halfedge_handle(SmartFaceHandle _fh) const;
inline SmartHalfedgeHandle halfedge_handle(SmartVertexHandle _vh) const;
inline SmartEdgeHandle edge_handle(SmartHalfedgeHandle _heh) const;
@@ -688,7 +741,7 @@ public:
//--- circulators ---
- /** \name Vertex and Face circulators
+ /** \name Vertex, Face, and Edge circulators
*/
//@{
@@ -803,6 +856,20 @@ public:
ConstFaceFaceCWIter cff_cwiter(FaceHandle _fh) const;
/// const face - face circulator
ConstFaceFaceCCWIter cff_ccwiter(FaceHandle _fh) const;
+
+ /// edge - vertex circulator
+ EdgeVertexIter ev_iter(EdgeHandle _eh);
+ /// edge - halfedge circulator
+ EdgeHalfedgeIter eh_iter(EdgeHandle _eh);
+ /// edge - face circulator
+ EdgeFaceIter ef_iter(EdgeHandle _eh);
+
+ /// const edge - vertex circulator
+ ConstEdgeVertexIter cev_iter(EdgeHandle _eh) const;
+ /// const edge - halfedge circulator
+ ConstEdgeHalfedgeIter ceh_iter(EdgeHandle _eh) const;
+ /// const edge - face circulator
+ ConstEdgeFaceIter cef_iter(EdgeHandle _eh) const;
// 'begin' circulators
@@ -930,6 +997,20 @@ public:
ConstHalfedgeLoopCWIter chl_cwbegin(HalfedgeHandle _heh) const;
/// const halfedge circulator ccw
ConstHalfedgeLoopCCWIter chl_ccwbegin(HalfedgeHandle _heh) const;
+
+ /// edge - vertex circulator
+ EdgeVertexIter ev_begin(EdgeHandle _eh);
+ /// edge - halfedge circulator
+ EdgeHalfedgeIter eh_begin(EdgeHandle _eh);
+ /// edge - face circulator
+ EdgeFaceIter ef_begin(EdgeHandle _eh);
+
+ /// const edge - vertex circulator
+ ConstEdgeVertexIter cev_begin(EdgeHandle _eh) const;
+ /// const edge - halfedge circulator
+ ConstEdgeHalfedgeIter ceh_begin(EdgeHandle _eh) const;
+ /// const edge - face circulator
+ ConstEdgeFaceIter cef_begin(EdgeHandle _eh) const;
// 'end' circulators
@@ -1056,6 +1137,21 @@ public:
ConstHalfedgeLoopCWIter chl_cwend(HalfedgeHandle _heh) const;
/// const face - face circulator ccw
ConstHalfedgeLoopCCWIter chl_ccwend(HalfedgeHandle _heh) const;
+
+ /// edge - vertex circulator
+ EdgeVertexIter ev_end(EdgeHandle _eh);
+ /// edge - halfedge circulator
+ EdgeHalfedgeIter eh_end(EdgeHandle _eh);
+ /// edge - face circulator
+ EdgeFaceIter ef_end(EdgeHandle _eh);
+
+ /// const edge - vertex circulator
+ ConstEdgeVertexIter cev_end(EdgeHandle _eh) const;
+ /// const edge - halfedge circulator
+ ConstEdgeHalfedgeIter ceh_end(EdgeHandle _eh) const;
+ /// const edge - face circulator
+ ConstEdgeFaceIter cef_end(EdgeHandle _eh) const;
+
//@}
/** @name Range based iterators and circulators */
@@ -1178,6 +1274,9 @@ public:
typedef CirculatorRange> ConstFaceHalfedgeRange;
typedef CirculatorRange> ConstFaceEdgeRange;
typedef CirculatorRange> ConstFaceFaceRange;
+ typedef CirculatorRange> ConstEdgeVertexRange;
+ typedef CirculatorRange> ConstEdgeHalfedgeRange;
+ typedef CirculatorRange> ConstEdgeFaceRange;
typedef CirculatorRange> ConstHalfedgeLoopRange;
typedef CirculatorRange> ConstVertexVertexCWRange;
@@ -1270,6 +1369,31 @@ public:
*/
ConstFaceFaceRange ff_range(FaceHandle _fh) const;
+ /**
+ * @return The vertices incident to the specified edge
+ * as a range object suitable for C++11 range based for loops.
+ */
+ ConstEdgeVertexRange ev_range(EdgeHandle _eh) const;
+
+ /**
+ * @return The halfedges of the specified edge
+ * as a range object suitable for C++11 range based for loops.
+ */
+ ConstEdgeHalfedgeRange eh_range(EdgeHandle _eh) const;
+
+ /**
+ * @return The halfedges of the specified edge
+ * as a range object suitable for C++11 range based for loops.
+ * Like eh_range(_heh.edge()) but starts iteration at _heh
+ */
+ ConstEdgeHalfedgeRange eh_range(HalfedgeHandle _heh) const;
+
+ /**
+ * @return The faces incident to the specified edge
+ * as a range object suitable for C++11 range based for loops.
+ */
+ ConstEdgeFaceRange ef_range(EdgeHandle _eh) const;
+
/**
* @return The halfedges in the face
* as a range object suitable for C++11 range based for loops.
@@ -1313,7 +1437,7 @@ public:
* @return The edges incident to the specified vertex
* as a range object suitable for C++11 range based for loops.
*/
- ConstVertexEdgeCWRange ve_cw_range(VertexHandle _vh) const ;
+ ConstVertexEdgeCWRange ve_cw_range(VertexHandle _vh) const;
/**
* @return The faces incident to the specified vertex
@@ -1420,6 +1544,7 @@ public:
*/
ConstFaceFaceCCWRange ff_ccw_range(FaceHandle _fh) const;
+
/**
* @return The halfedges in the face
* as a range object suitable for C++11 range based for loops.
diff --git a/src/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh b/src/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh
index eab1e52d..a191dbbf 100644
--- a/src/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh
+++ b/src/OpenMesh/Core/Mesh/PolyConnectivity_inline_impl.hh
@@ -183,6 +183,22 @@ inline PolyConnectivity::ConstFaceFaceRange PolyConnectivity::ff_range(FaceHandl
return ConstFaceFaceRange(*this, _fh);
}
+inline PolyConnectivity::ConstEdgeVertexRange PolyConnectivity::ev_range(EdgeHandle _eh) const {
+ return ConstEdgeVertexRange(*this, _eh);
+}
+
+inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(EdgeHandle _eh) const {
+ return ConstEdgeHalfedgeRange(*this, _eh);
+}
+
+inline PolyConnectivity::ConstEdgeHalfedgeRange PolyConnectivity::eh_range(HalfedgeHandle _heh) const {
+ return ConstEdgeHalfedgeRange(*this, _heh, 1);
+}
+
+inline PolyConnectivity::ConstEdgeFaceRange PolyConnectivity::ef_range(EdgeHandle _eh) const {
+ return ConstEdgeFaceRange(*this, _eh);
+}
+
inline PolyConnectivity::ConstHalfedgeLoopRange PolyConnectivity::hl_range(HalfedgeHandle _heh) const {
return ConstHalfedgeLoopRange(*this, _heh);
}
@@ -282,6 +298,7 @@ inline PolyConnectivity::ConstFaceFaceCCWRange PolyConnectivity::ff_ccw_range(Fa
return ConstFaceFaceCCWRange(*this, _fh);
}
+
inline PolyConnectivity::ConstHalfedgeLoopCCWRange PolyConnectivity::hl_ccw_range(HalfedgeHandle _heh) const {
return ConstHalfedgeLoopCCWRange(*this, _heh);
}
@@ -523,6 +540,24 @@ inline PolyConnectivity::ConstFaceFaceCWIter PolyConnectivity::cff_cwiter(ArrayK
inline PolyConnectivity::ConstFaceFaceCCWIter PolyConnectivity::cff_ccwiter(ArrayKernel::FaceHandle _fh) const
{ return ConstFaceFaceCCWIter(*this, _fh); }
+inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_iter(ArrayKernel::EdgeHandle _eh)
+{ return EdgeVertexIter(*this, _eh); }
+
+inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_iter(ArrayKernel::EdgeHandle _eh)
+{ return EdgeHalfedgeIter(*this, _eh); }
+
+inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_iter(ArrayKernel::EdgeHandle _eh)
+{ return EdgeFaceIter(*this, _eh); }
+
+inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_iter(ArrayKernel::EdgeHandle _eh) const
+{ return ConstEdgeVertexIter(*this, _eh); }
+
+inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_iter(ArrayKernel::EdgeHandle _eh) const
+{ return ConstEdgeHalfedgeIter(*this, _eh); }
+
+inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_iter(ArrayKernel::EdgeHandle _eh) const
+{ return ConstEdgeFaceIter(*this, _eh); }
+
inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_begin(VertexHandle _vh)
{ return VertexVertexIter(*this, _vh); }
@@ -707,6 +742,27 @@ inline PolyConnectivity::ConstHalfedgeLoopCWIter PolyConnectivity::chl_cwbegin(H
inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwbegin(HalfedgeHandle _heh) const
{ return ConstHalfedgeLoopCCWIter(*this, _heh); }
+
+inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_begin(EdgeHandle _eh)
+{ return EdgeVertexIter(*this, _eh); }
+
+inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_begin(EdgeHandle _eh)
+{ return EdgeHalfedgeIter(*this, _eh); }
+
+inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_begin(EdgeHandle _eh)
+{ return EdgeFaceIter(*this, _eh); }
+
+
+inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_begin(EdgeHandle _eh) const
+{ return ConstEdgeVertexIter(*this, _eh); }
+
+inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_begin(EdgeHandle _eh) const
+{ return ConstEdgeHalfedgeIter(*this, _eh); }
+
+inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_begin(EdgeHandle _eh) const
+{ return ConstEdgeFaceIter(*this, _eh); }
+
+
// 'end' circulators
inline PolyConnectivity::VertexVertexIter PolyConnectivity::vv_end(VertexHandle _vh)
@@ -893,6 +949,26 @@ inline PolyConnectivity::ConstHalfedgeLoopCCWIter PolyConnectivity::chl_ccwend(H
{ return ConstHalfedgeLoopCCWIter(*this, _heh, true); }
+inline PolyConnectivity::EdgeVertexIter PolyConnectivity::ev_end(EdgeHandle _eh)
+{ return EdgeVertexIter(*this, _eh, true); }
+
+inline PolyConnectivity::EdgeHalfedgeIter PolyConnectivity::eh_end(EdgeHandle _eh)
+{ return EdgeHalfedgeIter(*this, _eh, true); }
+
+inline PolyConnectivity::EdgeFaceIter PolyConnectivity::ef_end(EdgeHandle _eh)
+{ return EdgeFaceIter(*this, _eh, true); }
+
+
+inline PolyConnectivity::ConstEdgeVertexIter PolyConnectivity::cev_end(EdgeHandle _eh) const
+{ return ConstEdgeVertexIter(*this, _eh, true); }
+
+inline PolyConnectivity::ConstEdgeHalfedgeIter PolyConnectivity::ceh_end(EdgeHandle _eh) const
+{ return ConstEdgeHalfedgeIter(*this, _eh, true); }
+
+inline PolyConnectivity::ConstEdgeFaceIter PolyConnectivity::cef_end(EdgeHandle _eh) const
+{ return ConstEdgeFaceIter(*this, _eh, true); }
+
+
inline PolyConnectivity::ConstVertexFaceRange SmartVertexHandle::faces() const { assert(mesh() != nullptr); return mesh()->vf_range (*this); }
inline PolyConnectivity::ConstVertexFaceCWRange SmartVertexHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->vf_cw_range (*this); }
inline PolyConnectivity::ConstVertexFaceCCWRange SmartVertexHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->vf_ccw_range(*this); }
@@ -943,4 +1019,13 @@ inline PolyConnectivity::ConstFaceFaceRange SmartFaceHandle::faces()
inline PolyConnectivity::ConstFaceFaceCWRange SmartFaceHandle::faces_cw() const { assert(mesh() != nullptr); return mesh()->ff_cw_range (*this); }
inline PolyConnectivity::ConstFaceFaceCCWRange SmartFaceHandle::faces_ccw() const { assert(mesh() != nullptr); return mesh()->ff_ccw_range(*this); }
+
+inline PolyConnectivity::ConstEdgeVertexRange SmartEdgeHandle::vertices() const { assert(mesh() != nullptr); return mesh()->ev_range (*this); }
+
+inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges() const { assert(mesh() != nullptr); return mesh()->eh_range (*this); }
+
+inline PolyConnectivity::ConstEdgeHalfedgeRange SmartEdgeHandle::halfedges(HalfedgeHandle _heh) const { assert(mesh() != nullptr); return mesh()->eh_range (_heh); }
+
+inline PolyConnectivity::ConstEdgeFaceRange SmartEdgeHandle::faces() const { assert(mesh() != nullptr); return mesh()->ef_range (*this); }
+
}//namespace OpenMesh
diff --git a/src/OpenMesh/Core/Mesh/SmartHandles.hh b/src/OpenMesh/Core/Mesh/SmartHandles.hh
index 812fbd79..67e21c88 100644
--- a/src/OpenMesh/Core/Mesh/SmartHandles.hh
+++ b/src/OpenMesh/Core/Mesh/SmartHandles.hh
@@ -213,6 +213,15 @@ struct OPENMESHDLLEXPORT SmartEdgeHandle : public SmartBaseHandle, EdgeHandle, S
SmartVertexHandle v0() const;
/// Shorthand for vertex(1)
SmartVertexHandle v1() const;
+
+ /// Returns a range of vertices incident to the edge (PolyConnectivity::ev_range())
+ PolyConnectivity::ConstEdgeVertexRange vertices() const;
+ /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range())
+ PolyConnectivity::ConstEdgeHalfedgeRange halfedges() const;
+ /// Returns a range of halfedges of the edge (PolyConnectivity::eh_range())
+ PolyConnectivity::ConstEdgeHalfedgeRange halfedges(HalfedgeHandle _heh) const;
+ /// Returns a range of faces incident to the edge (PolyConnectivity::ef_range())
+ PolyConnectivity::ConstEdgeFaceRange faces() const;
};
struct OPENMESHDLLEXPORT SmartFaceHandle : public SmartBaseHandle, FaceHandle, SmartHandleStatusPredicates, SmartHandleBoundaryPredicate
@@ -415,13 +424,13 @@ inline SmartFaceHandle SmartHalfedgeHandle::face() const
return make_smart(mesh()->face_handle(*this), mesh());
}
-inline SmartHalfedgeHandle SmartEdgeHandle::halfedge(unsigned int _i) const
+inline SmartHalfedgeHandle SmartEdgeHandle::halfedge(unsigned int _i = 0) const
{
assert(mesh() != nullptr);
return make_smart(mesh()->halfedge_handle(*this, _i), mesh());
}
-inline SmartHalfedgeHandle SmartEdgeHandle::h(unsigned int _i) const
+inline SmartHalfedgeHandle SmartEdgeHandle::h(unsigned int _i = 0) const
{
return halfedge(_i);
}
diff --git a/src/Unittests/CMakeLists.txt b/src/Unittests/CMakeLists.txt
index 8b82a407..fe8cfbeb 100644
--- a/src/Unittests/CMakeLists.txt
+++ b/src/Unittests/CMakeLists.txt
@@ -38,8 +38,11 @@ unittests_sr_binary.cc
unittests_stripifier.cc
unittests_subdivider_adaptive.cc
unittests_subdivider_uniform.cc
-unittests_trimesh_circulator_current_halfedge_handle_replacement.cc
unittests_traits.cc
+unittests_trimesh_circulator_current_halfedge_handle_replacement.cc
+unittests_trimesh_circulator_edge_face.cc
+unittests_trimesh_circulator_edge_halfedge.cc
+unittests_trimesh_circulator_edge_vertex.cc
unittests_trimesh_circulator_face_edge.cc
unittests_trimesh_circulator_face_face.cc
unittests_trimesh_circulator_face_halfedge.cc
@@ -53,6 +56,7 @@ unittests_trimesh_circulator_vertex_vertex.cc
unittests_trimesh_collapse.cc
unittests_trimesh_garbage_collection.cc
unittests_trimesh_iterators.cc
+unittests_trimesh_navigation.cc
unittests_trimesh_others.cc
unittests_trimesh_ranges.cc
unittests_trimesh_split.cc
diff --git a/src/Unittests/unittests_smart_handles.cc b/src/Unittests/unittests_smart_handles.cc
index eec50a1a..39afebf6 100644
--- a/src/Unittests/unittests_smart_handles.cc
+++ b/src/Unittests/unittests_smart_handles.cc
@@ -177,6 +177,10 @@ TEST_F(OpenMeshSmartHandles, SimpleNavigation)
for (auto eh : mesh_.edges())
{
+ EXPECT_EQ(mesh_.halfedge_handle(eh), eh.halfedge()) << "halfedge of edge does not match";
+ EXPECT_EQ(mesh_.halfedge_handle(eh, 0), eh.halfedge(0)) << "halfedge 0 of edge does not match";
+ EXPECT_EQ(mesh_.halfedge_handle(eh, 1), eh.halfedge(1)) << "halfedge 1 of edge does not match";
+ EXPECT_EQ(mesh_.halfedge_handle(eh), eh.h()) << "halfedge of edge does not match";
EXPECT_EQ(mesh_.halfedge_handle(eh, 0), eh.h0()) << "halfedge 0 of edge does not match";
EXPECT_EQ(mesh_.halfedge_handle(eh, 1), eh.h1()) << "halfedge 1 of edge does not match";
EXPECT_EQ(mesh_.from_vertex_handle(mesh_.halfedge_handle(eh, 0)), eh.v0()) << "first vertex of edge does not match";
diff --git a/src/Unittests/unittests_trimesh_circulator_edge.hh b/src/Unittests/unittests_trimesh_circulator_edge.hh
new file mode 100644
index 00000000..cbdd9ac2
--- /dev/null
+++ b/src/Unittests/unittests_trimesh_circulator_edge.hh
@@ -0,0 +1,62 @@
+#include
+
+#include
+
+namespace {
+
+class OpenMeshTrimeshCirculatorEdge : public OpenMeshBase {
+public:
+ using VH = OpenMesh::VertexHandle;
+ using FH = OpenMesh::FaceHandle;
+ using EH = OpenMesh::EdgeHandle;
+ using HEH = OpenMesh::HalfedgeHandle;
+
+ // This function is called before each test is run.
+ void SetUp() override {
+ std::vector vh;
+
+ // 3----2 5
+ // | /| |
+ // | / | |
+ // | / | |
+ // |/ | |
+ // 0----1 4
+
+ // A quad consisting of two triangles.
+ vh.push_back(mesh_.add_vertex({0.0, 0.0, 0.0})); // vh[0]
+ vh.push_back(mesh_.add_vertex({1.0, 0.0, 0.0})); // vh[1]
+ vh.push_back(mesh_.add_vertex({1.0, 1.0, 0.0})); // vh[2]
+ vh.push_back(mesh_.add_vertex({0.0, 1.0, 0.0})); // vh[3]
+ mesh_.add_face(vh[0], vh[1], vh[2]);
+ mesh_.add_face(vh[0], vh[2], vh[3]);
+
+ // An isolated edge.
+ vh.push_back(mesh_.add_vertex({2.0, 0.0, 0.0})); // vh[4]
+ vh.push_back(mesh_.add_vertex({2.0, 1.0, 0.0})); // vh[5]
+ auto heh = mesh_.new_edge(vh[4], vh[5]);
+ auto heh_opp = mesh_.opposite_halfedge_handle(heh);
+ mesh_.set_halfedge_handle(vh[4], heh);
+ mesh_.set_halfedge_handle(vh[5], heh_opp);
+
+ InteriorEdge = Edge(0, 2);
+ BoundaryEdge = Edge(0, 1);
+ IsolatedEdge = Edge(4, 5);
+ }
+
+ // Helper function to quickly retrieve edges from their endpoint vertex IDs.
+ EH Edge(int _vh0_idx, int _vh1_idx) {
+ VH vh0(_vh0_idx);
+ VH vh1(_vh1_idx);
+ HEH heh = mesh_.find_halfedge(vh0, vh1);
+ if (!heh.is_valid())
+ return EH();
+ return mesh_.edge_handle(heh);
+ }
+
+ // Handles of some interesting edges.
+ EH InteriorEdge;
+ EH BoundaryEdge;
+ EH IsolatedEdge;
+};
+
+}
diff --git a/src/Unittests/unittests_trimesh_circulator_edge_face.cc b/src/Unittests/unittests_trimesh_circulator_edge_face.cc
new file mode 100644
index 00000000..cc55bbfe
--- /dev/null
+++ b/src/Unittests/unittests_trimesh_circulator_edge_face.cc
@@ -0,0 +1,142 @@
+#include "unittests_trimesh_circulator_edge.hh"
+
+#include
+#include
+
+#include
+
+namespace {
+
+class OpenMeshTrimeshCirculatorEdgeFace : public OpenMeshTrimeshCirculatorEdge {
+public:
+ // Check that the _visited faces comply with the expected iteration order on _eh.
+ void CheckIteration(EH _eh, const std::vector& _visited) {
+ // Up to 2 elements, depending on whether incident faces exist.
+ ASSERT_TRUE(mesh_.is_valid_handle(_eh));
+ const auto eh = make_smart(_eh, mesh_);
+ std::vector expected;
+ for (int i = 0; i < 2; ++i) {
+ const auto fh = eh.halfedge(i).face();
+ if (fh.is_valid()) {
+ expected.push_back(fh);
+ }
+ }
+
+ // Elements must have been visited in the expected order.
+ ASSERT_EQ(_visited.size(), expected.size());
+ for (size_t i = 0; i < _visited.size(); ++i) {
+ EXPECT_EQ(_visited[i], expected[i]);
+ }
+ }
+};
+
+// Mutable mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, Iter) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.ef_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, BeginEnd) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.ef_begin(eh), end = mesh_.ef_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, Range) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto fh : mesh_.ef_range(eh)) {
+ visited.push_back(fh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, SmartHandleRange) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, mesh_);
+ for (auto fh : smart_eh.faces()) {
+ visited.push_back(fh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+// const mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, ConstIter) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.cef_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, ConstBeginEnd) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.cef_begin(eh), end = const_mesh.cef_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, ConstRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto fh : const_mesh.ef_range(eh)) {
+ visited.push_back(fh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, ConstSmartHandleRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, const_mesh);
+ for (auto fh : smart_eh.faces()) {
+ visited.push_back(fh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+// Expected number of faces for interior, boundary, isolated edges.
+TEST_F(OpenMeshTrimeshCirculatorEdgeFace, ExpectedNumber) {
+ std::vector> pairs = {
+ { InteriorEdge, 2 },
+ { BoundaryEdge, 1 },
+ { IsolatedEdge, 0 },
+ };
+ for (const auto& pair : pairs) {
+ const auto& eh = pair.first;
+ const auto& expected_faces = pair.second;
+ int visited_faces = 0;
+ for (auto fh : mesh_.ef_range(eh)) {
+ (void)fh; // Unused
+ ++visited_faces;
+ }
+ EXPECT_EQ(visited_faces, expected_faces);
+ }
+}
+
+}
diff --git a/src/Unittests/unittests_trimesh_circulator_edge_halfedge.cc b/src/Unittests/unittests_trimesh_circulator_edge_halfedge.cc
new file mode 100644
index 00000000..ec4869f5
--- /dev/null
+++ b/src/Unittests/unittests_trimesh_circulator_edge_halfedge.cc
@@ -0,0 +1,184 @@
+#include "unittests_trimesh_circulator_edge.hh"
+
+#include
+#include
+
+#include
+
+namespace {
+
+class OpenMeshTrimeshCirculatorEdgeHalfedge : public OpenMeshTrimeshCirculatorEdge {
+public:
+ // Check that the _visited halfedges comply with the expected iteration order on _eh.
+ void CheckIteration(EH _eh, const std::vector& _visited) {
+ ASSERT_TRUE(mesh_.is_valid_handle(_eh));
+ const auto eh = make_smart(_eh, mesh_);
+ std::vector expected;
+ for (int i = 0; i < 2; ++i) {
+ expected.push_back(eh.halfedge(i));
+ }
+
+ // Elements must have been visited in the expected order.
+ ASSERT_EQ(_visited.size(), expected.size());
+ for (size_t i = 0; i < _visited.size(); ++i) {
+ EXPECT_EQ(_visited[i], expected[i]);
+ }
+ }
+
+ // Check that the _visited halfedges comply with the expected iteration order on _heh.edge(), starting at _heh.
+ void CheckIteration(HEH _heh, const std::vector& _visited) {
+ // Always exactly 2 elements.
+ ASSERT_TRUE(mesh_.is_valid_handle(_heh));
+ std::vector expected;
+ expected.push_back(_heh);
+ expected.push_back(mesh_.opposite_halfedge_handle(_heh));
+
+ // Elements must have been visited in the expected order.
+ ASSERT_EQ(_visited.size(), expected.size());
+ for (size_t i = 0; i < _visited.size(); ++i) {
+ EXPECT_EQ(_visited[i], expected[i]);
+ }
+ }
+};
+
+// Mutable mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, Iter) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.eh_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, BeginEnd) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.eh_begin(eh), end = mesh_.eh_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, Range) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto vh : mesh_.eh_range(eh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, SmartHandleRange) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, mesh_);
+ for (auto vh : smart_eh.halfedges()) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+// const mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstIter) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.ceh_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstBeginEnd) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.ceh_begin(eh), end = const_mesh.ceh_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto vh : const_mesh.eh_range(eh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstSmartHandleRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, const_mesh);
+ for (auto vh : smart_eh.halfedges()) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+// Mutable mesh, with given start halfedge.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, InitializedRange) {
+ for (auto start_heh : mesh_.halfedges()) {
+ std::vector visited;
+ for (auto vh : mesh_.eh_range(start_heh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(start_heh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, InitializedSmartHandleRange) {
+ for (auto start_heh : mesh_.halfedges()) {
+ std::vector visited;
+ auto smart_start_heh = make_smart(start_heh, mesh_);
+ auto smart_start_eh = smart_start_heh.edge();
+ for (auto vh : smart_start_eh.halfedges(smart_start_heh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(start_heh, visited);
+ }
+}
+
+// const mesh, with given start halfedge.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstInitializedRange) {
+ const auto& const_mesh = mesh_;
+ for (auto start_heh : const_mesh.halfedges()) {
+ std::vector visited;
+ for (auto vh : mesh_.eh_range(start_heh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(start_heh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeHalfedge, ConstInitializedSmartHandleRange) {
+ const auto& const_mesh = mesh_;
+ for (auto start_heh : const_mesh.halfedges()) {
+ std::vector visited;
+ auto smart_start_heh = make_smart(start_heh, const_mesh);
+ auto smart_start_eh = smart_start_heh.edge();
+ for (auto vh : smart_start_eh.halfedges(smart_start_heh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(start_heh, visited);
+ }
+}
+
+}
diff --git a/src/Unittests/unittests_trimesh_circulator_edge_vertex.cc b/src/Unittests/unittests_trimesh_circulator_edge_vertex.cc
new file mode 100644
index 00000000..6157f99a
--- /dev/null
+++ b/src/Unittests/unittests_trimesh_circulator_edge_vertex.cc
@@ -0,0 +1,119 @@
+#include "unittests_trimesh_circulator_edge.hh"
+
+#include
+#include
+
+#include
+
+namespace {
+
+class OpenMeshTrimeshCirculatorEdgeVertex : public OpenMeshTrimeshCirculatorEdge {
+public:
+ // Check that the _visited vertices comply with the expected iteration order on _eh.
+ void CheckIteration(EH _eh, const std::vector& _visited) {
+ ASSERT_TRUE(mesh_.is_valid_handle(_eh));
+ const auto eh = make_smart(_eh, mesh_);
+ std::vector expected;
+ for (int i = 0; i < 2; ++i) {
+ expected.push_back(eh.vertex(i));
+ }
+
+ // Elements must have been visited in the expected order.
+ ASSERT_EQ(_visited.size(), expected.size());
+ for (size_t i = 0; i < _visited.size(); ++i) {
+ EXPECT_EQ(_visited[i], expected[i]);
+ }
+ }
+};
+
+// Mutable mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, Iter) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.ev_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, BeginEnd) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto it = mesh_.ev_begin(eh), end = mesh_.ev_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, Range) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ for (auto vh : mesh_.ev_range(eh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, SmartHandleRange) {
+ for (auto eh : mesh_.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, mesh_);
+ for (auto vh : smart_eh.vertices()) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+// const mesh.
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, ConstIter) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.cev_iter(eh); it.is_valid(); ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, ConstBeginEnd) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto it = const_mesh.cev_begin(eh), end = const_mesh.cev_end(eh); it != end; ++it) {
+ visited.push_back(*it);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, ConstRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ for (auto vh : const_mesh.ev_range(eh)) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+TEST_F(OpenMeshTrimeshCirculatorEdgeVertex, ConstSmartHandleRange) {
+ const auto& const_mesh = mesh_;
+ for (auto eh : const_mesh.edges()) {
+ std::vector visited;
+ auto smart_eh = make_smart(eh, const_mesh);
+ for (auto vh : smart_eh.vertices()) {
+ visited.push_back(vh);
+ }
+ CheckIteration(eh, visited);
+ }
+}
+
+}
diff --git a/src/Unittests/unittests_trimesh_navigation.cc b/src/Unittests/unittests_trimesh_navigation.cc
new file mode 100644
index 00000000..e03d928e
--- /dev/null
+++ b/src/Unittests/unittests_trimesh_navigation.cc
@@ -0,0 +1,42 @@
+#include
+
+#include
+
+#include
+
+namespace {
+
+class OpenMeshTrimeshNavigation : public OpenMeshBase {
+public:
+ using VH = OpenMesh::VertexHandle;
+ using FH = OpenMesh::FaceHandle;
+ using EH = OpenMesh::EdgeHandle;
+ using HEH = OpenMesh::HalfedgeHandle;
+
+ // This function is called before each test is run.
+ void SetUp() override {
+ std::vector vh;
+
+ // 3----2
+ // | /|
+ // | / |
+ // | / |
+ // |/ |
+ // 0----1
+
+ vh.push_back(mesh_.add_vertex({0.0, 0.0, 0.0})); // vh[0]
+ vh.push_back(mesh_.add_vertex({1.0, 0.0, 0.0})); // vh[1]
+ vh.push_back(mesh_.add_vertex({1.0, 1.0, 0.0})); // vh[2]
+ vh.push_back(mesh_.add_vertex({0.0, 1.0, 0.0})); // vh[3]
+ mesh_.add_face(vh[0], vh[1], vh[2]);
+ mesh_.add_face(vh[0], vh[2], vh[3]);
+ }
+};
+
+TEST_F(OpenMeshTrimeshNavigation, EdgeHalfedgeDefault) {
+ for (EH eh : mesh_.edges()) {
+ EXPECT_EQ(mesh_.halfedge_handle(eh), mesh_.halfedge_handle(eh, 0));
+ }
+}
+
+}