Merge branch 'SmartRangeFilterFix' into 'master'
Smart range filter fix See merge request OpenMesh/OpenMesh!261
This commit is contained in:
@@ -408,6 +408,20 @@ struct SmartRangeT
|
|||||||
return FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::type>(f, b, e);
|
return FilteredSmartRangeT<SmartRange, Handle, typename std::decay<Functor>::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 <typename Functor>
|
||||||
|
auto filtered(Functor& f) -> FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>
|
||||||
|
{
|
||||||
|
auto range = static_cast<const RangeT*>(this);
|
||||||
|
auto b = (*range).begin();
|
||||||
|
auto e = (*range).end();
|
||||||
|
return FilteredSmartRangeT<SmartRange, Handle, const typename std::decay<Functor>::type&>(f, b, e);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -423,7 +437,7 @@ struct FilteredSmartRangeT : public SmartRangeT<FilteredSmartRangeT<RangeT, Hand
|
|||||||
|
|
||||||
FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end)
|
FilteredIterator(Functor f, BaseIterator it, BaseIterator end): BaseIterator(it), f_(f), end_(end)
|
||||||
{
|
{
|
||||||
if (!f_(*(*this))) // if start is not valid go to first valid one
|
if (!BaseIterator::operator==(end_) && !f_(*(*this))) // if start is not valid go to first valid one
|
||||||
operator++();
|
operator++();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,6 +301,7 @@ TEST_F(OpenMeshSmartRanges, ForEach)
|
|||||||
TEST_F(OpenMeshSmartRanges, Filtered)
|
TEST_F(OpenMeshSmartRanges, Filtered)
|
||||||
{
|
{
|
||||||
using VH = OpenMesh::VertexHandle;
|
using VH = OpenMesh::VertexHandle;
|
||||||
|
using FH = OpenMesh::FaceHandle;
|
||||||
|
|
||||||
auto is_even = [](VH vh) { return vh.idx() % 2 == 0; };
|
auto is_even = [](VH vh) { return vh.idx() % 2 == 0; };
|
||||||
auto is_odd = [](VH vh) { return vh.idx() % 2 == 1; };
|
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_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";
|
EXPECT_TRUE(mesh_.vertices().all_of([&](VH vh) { return !to_be_processed(vh); })) << "did not visit all vertices";
|
||||||
|
|
||||||
|
{
|
||||||
|
OpenMesh::FProp<bool> 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<bool> 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";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user