From 563149a8c5424bf66975addae664d3e92b32848a Mon Sep 17 00:00:00 2001 From: Max Lyon Date: Thu, 15 Oct 2020 14:34:17 +0200 Subject: [PATCH] add test for range predicates --- src/Unittests/unittests_smart_ranges.cc | 438 +++++++++++++++++++++++- 1 file changed, 437 insertions(+), 1 deletion(-) diff --git a/src/Unittests/unittests_smart_ranges.cc b/src/Unittests/unittests_smart_ranges.cc index 93eaa15d..a1062e96 100644 --- a/src/Unittests/unittests_smart_ranges.cc +++ b/src/Unittests/unittests_smart_ranges.cc @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -258,7 +259,7 @@ TEST_F(OpenMeshSmartRanges, BoundingBox) // Thus we convert here. OpenMesh::VProp myPos(mesh_); for (auto vh : mesh_.vertices()) - for (size_t i = 0; i < 3; ++i) + for (int i = 0; i < 3; ++i) myPos(vh)[i] = mesh_.point(vh)[i]; auto bb_min = mesh_.vertices().min(myPos); @@ -421,4 +422,439 @@ TEST_F(OpenMeshSmartRanges, WeightedAvg) } +template +void test_range_predicates(Mesh& _mesh) +{ + using namespace OpenMesh::Predicates; + + auto get_random_set = [&](int n) + { + auto max = _mesh.n_elements(); + std::vector set; + set.push_back(HandleT(0)); + for (int i = 0; i < n; ++i) + set.push_back(HandleT(rand() % max)); + std::sort(set.begin(), set.end()); + set.erase(std::unique(set.begin(), set.end()), set.end()); + return set; + }; + + // Feature + { + for (auto el : _mesh.elements()) + _mesh.status(el).set_feature(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_feature(true); + + auto set2 = _mesh.elements().filtered(Feature()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_feature(false); + } + + // Selected + { + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_selected(true); + + auto set2 = _mesh.elements().filtered(Selected()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + } + + // Tagged + { + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_tagged(true); + + auto set2 = _mesh.elements().filtered(Tagged()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + + // Tagged2 + { + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged2(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_tagged2(true); + + auto set2 = _mesh.elements().filtered(Tagged2()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged2(false); + } + + // Locked + { + for (auto el : _mesh.elements()) + _mesh.status(el).set_locked(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_locked(true); + + auto set2 = _mesh.elements().filtered(Locked()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_locked(false); + } + + // Hidden + { + for (auto el : _mesh.all_elements()) + _mesh.status(el).set_hidden(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_hidden(true); + + auto set2 = _mesh.all_elements().filtered(Hidden()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.all_elements()) + _mesh.status(el).set_hidden(false); + } + + // Deleted + { + for (auto el : _mesh.all_elements()) + _mesh.status(el).set_deleted(false); + auto set = get_random_set(4); + for (auto el : set) + _mesh.status(el).set_deleted(true); + + auto set2 = _mesh.all_elements().filtered(Deleted()).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.all_elements()) + _mesh.status(el).set_deleted(false); + } + + // Custom property + { + OpenMesh::PropertyManager::template type> prop(false, _mesh); + auto set = get_random_set(4); + for (auto el : set) + prop[el] = true; + + auto set2 = _mesh.elements().filtered(prop).to_vector(); + + EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ"; + for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i) + EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i; + } + + // boundary + { + for (auto el : _mesh.elements().filtered(Boundary())) + EXPECT_TRUE(el.is_boundary()); + int n_boundary1 = 0.0; + for (auto el : _mesh.elements()) + if (el.is_boundary()) + n_boundary1 += 1; + int n_boundary2 = _mesh.elements().count_if(Boundary()); + EXPECT_EQ(n_boundary1, n_boundary2); + } +} + +template +void test_range_predicate_combinations(Mesh& _mesh) +{ + using namespace OpenMesh::Predicates; + + auto n_elements = _mesh.n_elements(); + auto get_random_set = [&](int n) + { + std::vector set; + for (int i = 0; i < n; ++i) + set.push_back(HandleT(rand() % n_elements)); + std::sort(set.begin(), set.end()); + set.erase(std::unique(set.begin(), set.end()), set.end()); + return set; + }; + + // negation + { + auto set = get_random_set(4); + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : set) + _mesh.status(el).set_selected(true); + + auto true_set = _mesh.elements().filtered(Selected()).to_vector(); + auto false_set = _mesh.elements().filtered(!Selected()).to_vector(); + + std::vector intersection; + std::set_intersection(true_set.begin(), true_set.end(), false_set.begin(), false_set.end(), std::back_inserter(intersection)); + + EXPECT_TRUE(intersection.empty()); + EXPECT_EQ(true_set.size() + false_set.size(), n_elements); + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + } + + // conjunction + { + auto set1 = get_random_set(4); + auto set2 = get_random_set(4); + // make sure there is some overlap + { + auto set3 = get_random_set(3); + set1.insert(set1.end(), set3.begin(), set3.end()); + set2.insert(set2.end(), set3.begin(), set3.end()); + std::sort(set1.begin(), set1.end()); + std::sort(set2.begin(), set2.end()); + set1.erase(std::unique(set1.begin(), set1.end()), set1.end()); + set2.erase(std::unique(set2.begin(), set2.end()), set2.end()); + } + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + for (auto el : set1) + _mesh.status(el).set_selected(true); + for (auto el : set2) + _mesh.status(el).set_tagged(true); + + auto set = _mesh.elements().filtered(Selected() && Tagged()).to_vector(); + + std::vector intersection; + std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(intersection)); + + EXPECT_EQ(intersection.size(), set.size()); + for (size_t i = 0; i < std::min(intersection.size(), set.size()); ++i) + EXPECT_EQ(intersection[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + + // Disjunction + { + auto set1 = get_random_set(4); + auto set2 = get_random_set(4); + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + for (auto el : set1) + _mesh.status(el).set_selected(true); + for (auto el : set2) + _mesh.status(el).set_tagged(true); + + auto set = _mesh.elements().filtered(Selected() || Tagged()).to_vector(); + + std::vector union_set; + std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set)); + + EXPECT_EQ(union_set.size(), set.size()); + for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i) + EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + +} + +template +bool test_func(HandleT _h) +{ + return _h.idx() % 3 == 0; +} + +template +void test_make_predicate(Mesh& _mesh) +{ + using namespace OpenMesh::Predicates; + + auto n_elements = _mesh.n_elements(); + auto get_random_set = [&](int n) + { + std::vector set; + for (int i = 0; i < n; ++i) + set.push_back(HandleT(rand() % n_elements)); + std::sort(set.begin(), set.end()); + set.erase(std::unique(set.begin(), set.end()), set.end()); + return set; + }; + + // custom property + { + OpenMesh::PropertyManager::template type> prop(false, _mesh); + auto set1 = get_random_set(4); + auto set2 = get_random_set(4); + for (auto el : set1) + prop[el] = true; + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : set2) + _mesh.status(el).set_selected(true); + + auto set = _mesh.elements().filtered(Selected() || make_predicate(prop)).to_vector(); + + std::vector union_set; + std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set)); + + EXPECT_EQ(union_set.size(), set.size()); + for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i) + EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + + // lambda + { + OpenMesh::PropertyManager::template type> prop(false, _mesh); + auto set1 = get_random_set(4); + auto set2 = get_random_set(4); + for (auto el : set1) + prop[el] = true; + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : set2) + _mesh.status(el).set_selected(true); + + auto test = [&](HandleT h) { return prop(h); }; + + auto set = _mesh.elements().filtered(Selected() || make_predicate(test)).to_vector(); + + std::vector union_set; + std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set)); + + EXPECT_EQ(union_set.size(), set.size()); + for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i) + EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + + // r value lambda + { + OpenMesh::PropertyManager::template type> prop(false, _mesh); + auto set1 = get_random_set(4); + auto set2 = get_random_set(4); + for (auto el : set1) + prop[el] = true; + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : set2) + _mesh.status(el).set_selected(true); + + auto set = _mesh.elements().filtered(Selected() || make_predicate([&](HandleT h) { return prop(h); })).to_vector(); + + std::vector union_set; + std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set)); + + EXPECT_EQ(union_set.size(), set.size()); + for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i) + EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } + + // function pointer + { + auto set1 = _mesh.elements().filtered([&](const HandleT& h) { return test_func(h); }).to_vector(); + auto set2 = get_random_set(4); + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : set2) + _mesh.status(el).set_selected(true); + + auto set = _mesh.elements().filtered(Selected() || make_predicate(&test_func)).to_vector(); + + std::vector union_set; + std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set)); + + EXPECT_EQ(union_set.size(), set.size()); + for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i) + EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i; + + for (auto el : _mesh.elements()) + _mesh.status(el).set_selected(false); + for (auto el : _mesh.elements()) + _mesh.status(el).set_tagged(false); + } +} + +TEST_F(OpenMeshSmartRanges, Predicate) +{ + using namespace OpenMesh; + + mesh_.request_vertex_status(); + mesh_.request_halfedge_status(); + mesh_.request_edge_status(); + mesh_.request_face_status(); + + mesh_.delete_face(FaceHandle(0)); // ensure there is a boundary + mesh_.garbage_collection(); + + test_range_predicates(mesh_); + test_range_predicates(mesh_); + test_range_predicates(mesh_); + test_range_predicates(mesh_); + + test_range_predicate_combinations(mesh_); + test_range_predicate_combinations(mesh_); + test_range_predicate_combinations(mesh_); + test_range_predicate_combinations(mesh_); + + test_make_predicate(mesh_); + test_make_predicate(mesh_); + test_make_predicate(mesh_); + test_make_predicate(mesh_); +} + + }