From 4e40352a5fdc16256f7bdd928db745a360297edb Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 6 May 2020 10:45:41 +0200 Subject: [PATCH 1/3] add filtered range that stores reference instead of copy if the filter is not an rvalue reference --- src/OpenMesh/Core/Mesh/SmartRange.hh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/OpenMesh/Core/Mesh/SmartRange.hh b/src/OpenMesh/Core/Mesh/SmartRange.hh index 04053153..09db60c6 100644 --- a/src/OpenMesh/Core/Mesh/SmartRange.hh +++ b/src/OpenMesh/Core/Mesh/SmartRange.hh @@ -408,6 +408,20 @@ struct SmartRangeT return FilteredSmartRangeT::type>(f, b, e); } + /** @brief Only iterate over a subset of elements + * + * Returns a smart range which skips all elements that do not satisfy functor \p f + * + * @param f Functor that needs to be evaluated to true if the element should not be skipped. + */ + template + auto filtered(Functor& f) -> FilteredSmartRangeT::type&> + { + auto range = static_cast(this); + auto b = (*range).begin(); + auto e = (*range).end(); + return FilteredSmartRangeT::type&>(f, b, e); + } }; From ac52f0d16909fd7926010154ee3aea0d8ee56582 Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Wed, 6 May 2020 10:46:30 +0200 Subject: [PATCH 2/3] fix filtered range for empty ranges --- src/OpenMesh/Core/Mesh/SmartRange.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OpenMesh/Core/Mesh/SmartRange.hh b/src/OpenMesh/Core/Mesh/SmartRange.hh index 09db60c6..8f026b19 100644 --- a/src/OpenMesh/Core/Mesh/SmartRange.hh +++ b/src/OpenMesh/Core/Mesh/SmartRange.hh @@ -437,7 +437,7 @@ struct FilteredSmartRangeT : public SmartRangeT Date: Wed, 6 May 2020 11:52:15 +0200 Subject: [PATCH 3/3] add more tests for filtered range --- src/Unittests/unittests_smart_ranges.cc | 42 +++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/src/Unittests/unittests_smart_ranges.cc b/src/Unittests/unittests_smart_ranges.cc index 7d1d228e..1e767db7 100644 --- a/src/Unittests/unittests_smart_ranges.cc +++ b/src/Unittests/unittests_smart_ranges.cc @@ -301,6 +301,7 @@ TEST_F(OpenMeshSmartRanges, ForEach) TEST_F(OpenMeshSmartRanges, Filtered) { using VH = OpenMesh::VertexHandle; + using FH = OpenMesh::FaceHandle; auto is_even = [](VH vh) { return vh.idx() % 2 == 0; }; auto is_odd = [](VH vh) { return vh.idx() % 2 == 1; }; @@ -342,6 +343,47 @@ TEST_F(OpenMeshSmartRanges, Filtered) EXPECT_EQ(vertices.size(), mesh_.n_vertices()) << " number of visited vertices not correct"; EXPECT_TRUE(mesh_.vertices().all_of([&](VH vh) { return !to_be_processed(vh); })) << "did not visit all vertices"; + { + OpenMesh::FProp to_be_visited(true, mesh_); + int visited_faces_in_main_loop = 0; + int visited_faces_in_sub_loop = 0; + for (auto fh : mesh_.faces().filtered(to_be_visited)) + { + to_be_visited(fh) = false; + ++visited_faces_in_main_loop; + for (auto neighbor : fh.faces().filtered(to_be_visited)) + { + to_be_visited(neighbor) = false; + ++visited_faces_in_sub_loop; + } + } + + EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected"; + EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces"; + EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once"; + } + + { + OpenMesh::FProp to_be_visited(true, mesh_); + const auto& to_be_visited_const_ref = to_be_visited; + int visited_faces_in_main_loop = 0; + int visited_faces_in_sub_loop = 0; + for (auto fh : mesh_.faces().filtered(to_be_visited_const_ref)) + { + to_be_visited(fh) = false; + ++visited_faces_in_main_loop; + for (auto neighbor : fh.faces().filtered(to_be_visited_const_ref)) + { + to_be_visited(neighbor) = false; + ++visited_faces_in_sub_loop; + } + } + + EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected"; + EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces"; + EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once"; + } + }