Commit eb877fe9 authored by Matthias Möller's avatar Matthias Möller

adding cw and ccw circulators

closes #2406

git-svn-id: http://www.openmesh.org/svnrepo/OpenMesh/trunk@1227 fdac6126-5c0c-442c-9429-916003d36597
parent 0f9b4c23
......@@ -845,6 +845,10 @@ All circulators provide the operations listed in
CirculatorT<Mesh>, which are basically the same as the
iterator funtions.
\note Circulators are similar to bidirectional iterators and therefore they have the bidirectional_iterator_tag.
However, the bidirectional requires that the attribute OpenMesh::Attributes::PrevHalfedge is available.
Otherwise it is just a forward iterator.
\deprecated
While it is possible to use \c operator \c bool(), which returns true, as long
as the circulator hasn't reached the end of the sequence, this function is
......@@ -855,6 +859,35 @@ to get circulators around a specified center item:
\include circulator_functions.cc
Additionally to the normal circulators there exists some for each
direction (clock-wise, counterclock-wise). Those circulators might be slower
than the normal one, but the direction of circulation is guaranteed.
You can get these types of circulators by adding the infix "ccw" or "cw" to
the function used to request the circulator of an item after the underscore.
Example:
\code
VertexVertexIter vvit = mesh.vv_iter(some_vertex_handle); // fastest (clock or counterclockwise)
VertexVertexCWIter vvcwit = mesh.vv_cwiter(some_vertex_handle); // clockwise
VertexVertexCCWIter vvccwit = mesh.vv_ccwiter(some_vertex_handle); // counter-clockwise
\endcode
It is also possible to convert a cw circulator to a ccw circulator and vice versa.
For this purpose, each circulator provides a constructor taking the other circulator as input.
If a cw circulator is converted, the ccw circulator points on the same element as
the cw circulator pointed on, but the direction for the increment and decrement changed.\n
The conversion is only valid for valid circulators. The resulting circulator from a invalid circulator is still invalid,
but might behave in a fashion not expected by normal iterators. Example:
\code
VertexVertexCWIter vvcwit = mesh.vv_cwend(some_vertex_handle);
VertexVertexCCWIter vvccwit = VertexVertexCCWIter(vvcwit); //conversion of an invalid circulator
--vvcwit; //is valid now (if the range >= 1)
++vvccwit; //can still be invalid
\endcode
CW and CCW circulators requires that OpenMesh::Attributes::PrevHalfedge is available.
\note For every circulator there also exists a constant version.
To make use of these constant circulators just add the prefix<br />
"Const" to the type specifier and add the prefix "c" to the function used to request
......
......@@ -61,7 +61,7 @@
namespace OpenMesh {
namespace Iterators {
template<class Mesh, class CenterEntityHandle>
template<class Mesh, class CenterEntityHandle, bool CW>
class GenericCirculator_CenterEntityFnsT {
public:
static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter);
......@@ -69,31 +69,61 @@ class GenericCirculator_CenterEntityFnsT {
};
template<class Mesh>
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::VertexHandle> {
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::VertexHandle, true> {
public:
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
heh = mesh->cw_rotated_halfedge_handle(heh);
if (heh == start) lap_counter++;
if (heh == start) ++lap_counter;
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
if (heh == start) lap_counter--;
if (heh == start) --lap_counter;
heh = mesh->ccw_rotated_halfedge_handle(heh);
}
};
template<class Mesh>
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::FaceHandle> {
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::FaceHandle, true> {
public:
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
heh = mesh->next_halfedge_handle(heh);
if (heh == start) lap_counter++;
if (heh == start) ++lap_counter;
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
if (heh == start) lap_counter--;
if (heh == start) --lap_counter;
heh = mesh->prev_halfedge_handle(heh);
}
};
/////////////////////////////////////////////////////////////
// CCW
template<class Mesh>
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::VertexHandle, false> {
public:
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
heh = mesh->ccw_rotated_halfedge_handle(heh);
if (heh == start) ++lap_counter;
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
if (heh == start) --lap_counter;
heh = mesh->cw_rotated_halfedge_handle(heh);
}
};
template<class Mesh>
class GenericCirculator_CenterEntityFnsT<Mesh, typename Mesh::FaceHandle, false> {
public:
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
heh = mesh->prev_halfedge_handle(heh);
if (heh == start) ++lap_counter;
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
if (heh == start) --lap_counter;
heh = mesh->next_halfedge_handle(heh);
}
};
/////////////////////////////////////////////////////////////
template<class Mesh, class CenterEntityHandle, class ValueHandle>
class GenericCirculator_DereferenciabilityCheckT {
public:
......@@ -116,7 +146,7 @@ class GenericCirculator_DereferenciabilityCheckT<Mesh, typename Mesh::VertexHand
}
};
template<class Mesh, class CenterEntityHandle, class ValueHandle>
template<class Mesh, class CenterEntityHandle, class ValueHandle, bool CW = true>
class GenericCirculator_ValueHandleFnsT {
public:
inline static bool is_valid(const typename Mesh::HalfedgeHandle &heh, const int lap_counter) {
......@@ -124,15 +154,15 @@ class GenericCirculator_ValueHandleFnsT {
}
inline static void init(const Mesh*, typename Mesh::HalfedgeHandle&, typename Mesh::HalfedgeHandle&, int&) {};
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle>::increment(mesh, heh, start, lap_counter);
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle, CW>::increment(mesh, heh, start, lap_counter);
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle>::decrement(mesh, heh, start, lap_counter);
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle, CW>::decrement(mesh, heh, start, lap_counter);
}
};
template<class Mesh, class CenterEntityHandle>
class GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, typename Mesh::FaceHandle> {
template<class Mesh, class CenterEntityHandle, bool CW>
class GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, typename Mesh::FaceHandle, CW> {
public:
typedef GenericCirculator_DereferenciabilityCheckT<Mesh, CenterEntityHandle, typename Mesh::FaceHandle> GenericCirculator_DereferenciabilityCheck;
......@@ -145,12 +175,12 @@ class GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, typename Mesh:
};
inline static void increment(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
do {
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle>::increment(mesh, heh, start, lap_counter);
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle, CW>::increment(mesh, heh, start, lap_counter);
} while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
}
inline static void decrement(const Mesh *mesh, typename Mesh::HalfedgeHandle &heh, typename Mesh::HalfedgeHandle &start, int &lap_counter) {
do {
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle>::decrement(mesh, heh, start, lap_counter);
GenericCirculator_CenterEntityFnsT<Mesh, CenterEntityHandle, CW>::decrement(mesh, heh, start, lap_counter);
} while (is_valid(heh, lap_counter) && !GenericCirculator_DereferenciabilityCheck::isDereferenciable(mesh, heh));
}
};
......@@ -217,7 +247,7 @@ class GenericCirculatorBaseT {
};
template<class Mesh, class CenterEntityHandle, class ValueHandle,
ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const>
ValueHandle (GenericCirculatorBaseT<Mesh>::*Handle2Value)() const, bool CW = true >
class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
public:
typedef std::ptrdiff_t difference_type;
......@@ -228,7 +258,7 @@ class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
typedef typename GenericCirculatorBaseT<Mesh>::mesh_ptr mesh_ptr;
typedef typename GenericCirculatorBaseT<Mesh>::mesh_ref mesh_ref;
typedef GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, ValueHandle> GenericCirculator_ValueHandleFns;
typedef GenericCirculator_ValueHandleFnsT<Mesh, CenterEntityHandle, ValueHandle, CW> GenericCirculator_ValueHandleFns;
public:
GenericCirculatorT() {}
......@@ -244,6 +274,10 @@ class GenericCirculatorT : protected GenericCirculatorBaseT<Mesh> {
}
GenericCirculatorT(const GenericCirculatorT &rhs) : GenericCirculatorBaseT<Mesh>(rhs) {}
friend class GenericCirculatorT<Mesh,CenterEntityHandle,ValueHandle,Handle2Value,!CW>;
explicit GenericCirculatorT( const GenericCirculatorT<Mesh,CenterEntityHandle,ValueHandle,Handle2Value,!CW>& rhs )
:GenericCirculatorBaseT<Mesh>(rhs){}
GenericCirculatorT& operator++() {
assert(this->mesh_);
GenericCirculator_ValueHandleFns::increment(this->mesh_, this->heh_, this->start_, this->lap_counter_);
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <algorithm>
namespace {
......@@ -129,6 +130,145 @@ TEST_F(OpenMeshTrimeshCirculatorFaceEdge, FaceEdgeIterWithoutHolesIncrement) {
}
}
/*
* test CW and CCW iterators
*/
TEST_F(OpenMeshTrimeshCirculatorFaceEdge, CWAndCCWTest) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[6];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(4, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
// Add three faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
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[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
/* Test setup:
*
* 0 ------ 2 ------ 4
* \ / \ /
* \ 0 / \ 2 /
* \ / 1 \ /
* 1 ------- 3
* \ /
* \ 3 /
* \ /
* \ /
* 5
*/
int indices[4] = {4, 1, 3, 4};
int rev_indices[4];
std::reverse_copy(indices,indices+4,rev_indices);
//CCW
Mesh::FaceEdgeCCWIter fe_ccwit = mesh_.fe_ccwbegin(mesh_.face_handle(1));
Mesh::FaceEdgeCCWIter fe_ccwend = mesh_.fe_ccwend(mesh_.face_handle(1));
size_t i = 0;
for (;fe_ccwit != fe_ccwend; ++fe_ccwit, ++i)
{
EXPECT_EQ(indices[i], fe_ccwit->idx()) << "Index wrong in FaceEdgeCCWIter";
}
EXPECT_FALSE(fe_ccwit.is_valid()) << "Iterator invalid in FaceEdgeCCWIter at end";
EXPECT_TRUE( fe_ccwit == fe_ccwend ) << "End iterator for FaceEdgeCCWIter not matching";
//constant CCW
Mesh::ConstFaceEdgeCCWIter cfe_ccwit = mesh_.cfe_ccwbegin(mesh_.face_handle(1));
Mesh::ConstFaceEdgeCCWIter cfe_ccwend = mesh_.cfe_ccwend(mesh_.face_handle(1));
i = 0;
for (;cfe_ccwit != cfe_ccwend; ++cfe_ccwit, ++i)
{
EXPECT_EQ(indices[i], cfe_ccwit->idx()) << "Index wrong in ConstFaceEdgeCCWIter";
}
EXPECT_FALSE(cfe_ccwit.is_valid()) << "Iterator invalid in ConstFaceEdgeCCWIter at end";
EXPECT_TRUE( cfe_ccwit == cfe_ccwend ) << "End iterator for ConstFaceEdgeCCWIter not matching";
//CW
Mesh::FaceEdgeCWIter fe_cwit = mesh_.fe_cwbegin(mesh_.face_handle(1));
Mesh::FaceEdgeCWIter fe_cwend = mesh_.fe_cwend(mesh_.face_handle(1));
i = 0;
for (;fe_cwit != fe_cwend; ++fe_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], fe_cwit->idx()) << "Index wrong in FaceEdgeCWIter";
}
EXPECT_FALSE(fe_cwit.is_valid()) << "Iterator invalid in FaceEdgeCWIter at end";
EXPECT_TRUE( fe_cwit == fe_cwend ) << "End iterator for FaceEdgeCWIter not matching";
//constant CW
Mesh::ConstFaceEdgeCWIter cfe_cwit = mesh_.cfe_cwbegin(mesh_.face_handle(1));
Mesh::ConstFaceEdgeCWIter cfe_cwend = mesh_.cfe_cwend(mesh_.face_handle(1));
i = 0;
for (;cfe_cwit != cfe_cwend; ++cfe_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], cfe_cwit->idx()) << "Index wrong in ConstFaceEdgeCWIter";
}
EXPECT_FALSE(cfe_cwit.is_valid()) << "Iterator invalid in ConstFaceEdgeCWIter at end";
EXPECT_TRUE( cfe_cwit == cfe_cwend ) << "End iterator for ConstFaceEdgeCWIter not matching";
/*
* conversion properties:
* a) cw_begin == CWIter(ccw_begin())
* b) cw_iter->idx() == CCWIter(cw_iter)->idx() for valid iterators
* c) --cw_iter == CWIter(++ccwIter) for valid iterators
* d) cw_end == CWIter(ccw_end()) => --cw_end != CWIter(++ccw_end()) *
*/
Mesh::FaceEdgeCWIter fe_cwIter = mesh_.fe_cwbegin(mesh_.face_handle(1));
// a)
EXPECT_TRUE( fe_cwIter == Mesh::FaceEdgeCWIter(mesh_.fe_ccwbegin(mesh_.face_handle(1))) ) << "ccw to cw conversion failed";
EXPECT_TRUE( Mesh::FaceEdgeCCWIter(fe_cwIter) == mesh_.fe_ccwbegin(mesh_.face_handle(1)) ) << "cw to ccw conversion failed";
// b)
EXPECT_EQ( fe_cwIter->idx(), Mesh::FaceEdgeCCWIter(fe_cwIter)->idx()) << "iterators doesnt point on the same element";
// c)
++fe_cwIter;
fe_ccwend = mesh_.fe_ccwend(mesh_.face_handle(1));
--fe_ccwend;
EXPECT_EQ(fe_cwIter->idx(),fe_ccwend->idx()) << "iteratoes are not equal after inc/dec";
// additional conversion check
fe_ccwend = Mesh::FaceEdgeCCWIter(fe_cwIter);
EXPECT_EQ(fe_cwIter->idx(),fe_ccwend->idx())<< "iterators doesnt point on the same element";
// d)
fe_cwIter = Mesh::FaceEdgeCWIter(mesh_.fe_ccwend(mesh_.face_handle(1)));
EXPECT_FALSE(fe_cwIter.is_valid()) << "end iterator is not invalid";
EXPECT_TRUE(Mesh::FaceEdgeCCWIter(mesh_.fe_cwend(mesh_.face_handle(1))) == mesh_.fe_ccwend(mesh_.face_handle(1))) << "end iterators are not equal";
}
/*
* Test if the end iterator stays invalid after one lap
......
......@@ -2,6 +2,7 @@
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <algorithm>
namespace {
......@@ -205,6 +206,146 @@ TEST_F(OpenMeshTrimeshCirculatorFaceFace, FaceFaceIterWithoutHoles) {
}
/*
* Test CW and CCW iterators
*/
TEST_F(OpenMeshTrimeshCirculatorFaceFace, CWAndCCWCheck) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[6];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(4, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
// Add three faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
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[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
/* Test setup:
*
* 0 ------ 2 ------ 4
* \ / \ /
* \ 0 / \ 2 /
* \ / 1 \ /
* 1 ------- 3
* \ /
* \ 3 /
* \ /
* \ /
* 5
*/
int indices[4] = {2, 0, 3, 2};
int rev_indices[4];
std::reverse_copy(indices,indices+4,rev_indices);
//CCW
Mesh::FaceFaceCCWIter ff_ccwit = mesh_.ff_ccwbegin(mesh_.face_handle(1));
Mesh::FaceFaceCCWIter ff_ccwend = mesh_.ff_ccwend(mesh_.face_handle(1));
size_t i = 0;
for (;ff_ccwit != ff_ccwend; ++ff_ccwit, ++i)
{
EXPECT_EQ(indices[i], ff_ccwit->idx()) << "Index wrong in FaceFaceCCWIter";
}
EXPECT_FALSE(ff_ccwit.is_valid()) << "Iterator invalid in FaceFaceCCWIter at end";
EXPECT_TRUE( ff_ccwit == ff_ccwend ) << "End iterator for FaceFaceCCWIter not matching";
//constant CCW
Mesh::ConstFaceFaceCCWIter cff_ccwit = mesh_.cff_ccwbegin(mesh_.face_handle(1));
Mesh::ConstFaceFaceCCWIter cff_ccwend = mesh_.cff_ccwend(mesh_.face_handle(1));
i = 0;
for (;cff_ccwit != cff_ccwend; ++cff_ccwit, ++i)
{
EXPECT_EQ(indices[i], cff_ccwit->idx()) << "Index wrong in ConstFaceFaceCCWIter";
}
EXPECT_FALSE(cff_ccwit.is_valid()) << "Iterator invalid in ConstFaceFaceCCWIter at end";
EXPECT_TRUE( cff_ccwit == cff_ccwend ) << "End iterator for ConstFaceFaceCCWIter not matching";
//CW
Mesh::FaceFaceCWIter ff_cwit = mesh_.ff_cwbegin(mesh_.face_handle(1));
Mesh::FaceFaceCWIter ff_cwend = mesh_.ff_cwend(mesh_.face_handle(1));
i = 0;
for (;ff_cwit != ff_cwend; ++ff_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], ff_cwit->idx()) << "Index wrong in FaceFaceCWIter";
}
EXPECT_FALSE(ff_cwit.is_valid()) << "Iterator invalid in FaceFaceCWIter at end";
EXPECT_TRUE( ff_cwit == ff_cwend ) << "End iterator for FaceFaceCWIter not matching";
//constant CW
Mesh::ConstFaceFaceCWIter cff_cwit = mesh_.cff_cwbegin(mesh_.face_handle(1));
Mesh::ConstFaceFaceCWIter cff_cwend = mesh_.cff_cwend(mesh_.face_handle(1));
i = 0;
for (;cff_cwit != cff_cwend; ++cff_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], cff_cwit->idx()) << "Index wrong in ConstFaceFaceCWIter";
}
EXPECT_FALSE(cff_cwit.is_valid()) << "Iterator invalid in ConstFaceFaceCWIter at end";
EXPECT_TRUE( cff_cwit == cff_cwend ) << "End iterator for ConstFaceFaceCWIter not matching";
/*
* conversion properties:
* a) cw_begin == CWIter(ccw_begin())
* b) cw_iter->idx() == CCWIter(cw_iter)->idx() for valid iterators
* c) --cw_iter == CWIter(++ccwIter) for valid iterators
* d) cw_end == CWIter(ccw_end()) => --cw_end != CWIter(++ccw_end()) *
*/
Mesh::FaceFaceCWIter ff_cwIter = mesh_.ff_cwbegin(mesh_.face_handle(1));
// a)
EXPECT_TRUE( ff_cwIter == Mesh::FaceFaceCWIter(mesh_.ff_ccwbegin(mesh_.face_handle(1))) ) << "ccw to cw conversion failed";
EXPECT_TRUE( Mesh::FaceFaceCCWIter(ff_cwIter) == mesh_.ff_ccwbegin(mesh_.face_handle(1)) ) << "cw to ccw conversion failed";
// b)
EXPECT_EQ( ff_cwIter->idx(), Mesh::FaceFaceCCWIter(ff_cwIter)->idx()) << "iterators doesnt point on the same element";
// c)
++ff_cwIter;
ff_ccwend = mesh_.ff_ccwend(mesh_.face_handle(1));
--ff_ccwend;
EXPECT_EQ(ff_cwIter->idx(),ff_ccwend->idx()) << "iteratoes are not equal after inc/dec";
// additional conversion check
ff_ccwend = Mesh::FaceFaceCCWIter(ff_cwIter);
EXPECT_EQ(ff_cwIter->idx(),ff_ccwend->idx())<< "iterators doesnt point on the same element";
// d)
ff_cwIter = Mesh::FaceFaceCWIter(mesh_.ff_ccwend(mesh_.face_handle(1)));
EXPECT_FALSE(ff_cwIter.is_valid()) << "end iterator is not invalid";
EXPECT_TRUE(Mesh::FaceFaceCCWIter(mesh_.ff_cwend(mesh_.face_handle(1))) == mesh_.ff_ccwend(mesh_.face_handle(1))) << "end iterators are not equal";
}
/*
......
......@@ -2,6 +2,7 @@
#include <Unittests/unittests_common.hh>
#include <iostream>
#include <algorithm>
namespace {
......@@ -127,6 +128,146 @@ TEST_F(OpenMeshTrimeshCirculatorFaceHalfEdge, FaceHalfedgeIterWithoutHolesIncrem
}
/*
* test CW and CCW iterators
*/
TEST_F(OpenMeshTrimeshCirculatorFaceHalfEdge, CWAndCCWTest) {
mesh_.clear();
// Add some vertices
Mesh::VertexHandle vhandle[6];
vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
vhandle[1] = mesh_.add_vertex(Mesh::Point(1, 0, 0));
vhandle[2] = mesh_.add_vertex(Mesh::Point(2, 1, 0));
vhandle[3] = mesh_.add_vertex(Mesh::Point(3, 0, 0));
vhandle[4] = mesh_.add_vertex(Mesh::Point(4, 1, 0));
vhandle[5] = mesh_.add_vertex(Mesh::Point(2,-1, 0));
// Add three faces
std::vector<Mesh::VertexHandle> face_vhandles;
face_vhandles.push_back(vhandle[0]);
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[2]);
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[2]);
face_vhandles.push_back(vhandle[3]);
face_vhandles.push_back(vhandle[4]);
mesh_.add_face(face_vhandles);
face_vhandles.clear();
face_vhandles.push_back(vhandle[1]);
face_vhandles.push_back(vhandle[5]);
face_vhandles.push_back(vhandle[3]);
mesh_.add_face(face_vhandles);
/* Test setup:
*
* 0 ------ 2 ------ 4
* \ / \ /
* \ 0 / \ 2 /
* \ / 1 \ /
* 1 ------- 3
* \ /
* \ 3 /
* \ /
* \ /
* 5
*/
int indices[4] = {8, 3, 6, 8};
int rev_indices[4];
std::reverse_copy(indices,indices+4,rev_indices);
//CCW
Mesh::FaceHalfedgeIter fh_ccwit = mesh_.fh_ccwbegin(mesh_.face_handle(1));
Mesh::FaceHalfedgeIter fh_ccwend = mesh_.fh_ccwend(mesh_.face_handle(1));
size_t i = 0;
for (;fh_ccwit != fh_ccwend; ++fh_ccwit, ++i)
{
EXPECT_EQ(indices[i], fh_ccwit->idx()) << "Index wrong in FaceHalfedgeIter";
}
EXPECT_FALSE(fh_ccwit.is_valid()) << "Iterator invalid in FaceHalfedgeIter at end";
EXPECT_TRUE( fh_ccwit == fh_ccwend ) << "End iterator for FaceHalfedgeIter not matching";
//constant CCW
Mesh::ConstFaceHalfedgeIter cfh_ccwit = mesh_.cfh_ccwbegin(mesh_.face_handle(1));
Mesh::ConstFaceHalfedgeIter cfh_ccwend = mesh_.cfh_ccwend(mesh_.face_handle(1));
i = 0;
for (;cfh_ccwit != cfh_ccwend; ++cfh_ccwit, ++i)
{
EXPECT_EQ(indices[i], cfh_ccwit->idx()) << "Index wrong in ConstFaceHalfedgeIter";
}
EXPECT_FALSE(cfh_ccwit.is_valid()) << "Iterator invalid in ConstFaceHalfedgeIter at end";
EXPECT_TRUE( cfh_ccwit == cfh_ccwend ) << "End iterator for ConstFaceHalfedgeIter not matching";
//CW
Mesh::FaceHalfedgeCWIter fh_cwit = mesh_.fh_cwbegin(mesh_.face_handle(1));
Mesh::FaceHalfedgeCWIter fh_cwend = mesh_.fh_cwend(mesh_.face_handle(1));
i = 0;
for (;fh_cwit != fh_cwend; ++fh_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], fh_cwit->idx()) << "Index wrong in FaceHalfedgeCWIter";
}
EXPECT_FALSE(fh_cwit.is_valid()) << "Iterator invalid in FaceHalfedgeCWIter at end";
EXPECT_TRUE( fh_cwit == fh_cwend ) << "End iterator for FaceHalfedgeCWIter not matching";
//constant CW
Mesh::ConstFaceHalfedgeCWIter cfh_cwit = mesh_.cfh_cwbegin(mesh_.face_handle(1));
Mesh::ConstFaceHalfedgeCWIter cfh_cwend = mesh_.cfh_cwend(mesh_.face_handle(1));
i = 0;
for (;cfh_cwit != cfh_cwend; ++cfh_cwit, ++i)
{
EXPECT_EQ(rev_indices[i], cfh_cwit->idx()) << "Index wrong in ConstFaceHalfedgeCWIter";
}
EXPECT_FALSE(cfh_cwit.is_valid()) << "Iterator invalid in ConstFaceHalfedgeCWIter at end";
EXPECT_TRUE( cfh_cwit == cfh_cwend ) << "End iterator for ConstFaceHalfedgeCWIter not matching";
/*
* conversion properties:
* a) cw_begin == CWIter(ccw_begin())
* b) cw_iter->idx() == CCWIter(cw_iter)->idx() for valid iterators
* c) --cw_iter == CWIter(++ccwIter) for valid iterators
* d) cw_end == CWIter(ccw_end()) => --cw_end != CWIter(++ccw_end()) *
*/
Mesh::FaceHalfedgeCWIter fh_cwIter = mesh_.fh_cwbegin(mesh_.face_handle(1));
// a)
EXPECT_TRUE( fh_cwIter == Mesh::FaceHalfedgeCWIter(mesh_.fh_ccwbegin(mesh_.face_handle(1))) ) << "ccw to cw conversion failed";
EXPECT_TRUE( Mesh::FaceHalfedgeCCWIter(fh_cwIter) == mesh_.fh_ccwbegin(mesh_.face_handle(1)) ) << "cw to ccw conversion failed";
// b)