Developer Documentation
Loading...
Searching...
No Matches
unittests_smart_ranges.cc
1#include <gtest/gtest.h>
2#include <Unittests/unittests_common.hh>
3
4#include <OpenMesh/Core/Mesh/PolyConnectivity.hh>
5#include <OpenMesh/Core/Utils/PropertyManager.hh>
6#include <OpenMesh/Core/Utils/Predicates.hh>
7
8#include <iostream>
9#include <chrono>
10
11namespace {
12
13class OpenMeshSmartRanges : public OpenMeshBase {
14
15protected:
16
17 // This function is called before each test is run
18 virtual void SetUp() {
19
20 mesh_.clear();
21
22 // Add some vertices
23 Mesh::VertexHandle vhandle[8];
24 vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
25 vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
26 vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
27 vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
28 vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
29 vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
30 vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
31 vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
32
33 // Add six faces to form a cube
34 std::vector<Mesh::VertexHandle> face_vhandles;
35
36 face_vhandles.clear();
37 face_vhandles.push_back(vhandle[0]);
38 face_vhandles.push_back(vhandle[1]);
39 face_vhandles.push_back(vhandle[3]);
40 mesh_.add_face(face_vhandles);
41
42 face_vhandles.clear();
43 face_vhandles.push_back(vhandle[1]);
44 face_vhandles.push_back(vhandle[2]);
45 face_vhandles.push_back(vhandle[3]);
46 mesh_.add_face(face_vhandles);
47
48 //=======================
49
50 face_vhandles.clear();
51 face_vhandles.push_back(vhandle[7]);
52 face_vhandles.push_back(vhandle[6]);
53 face_vhandles.push_back(vhandle[5]);
54 mesh_.add_face(face_vhandles);
55
56 face_vhandles.clear();
57 face_vhandles.push_back(vhandle[7]);
58 face_vhandles.push_back(vhandle[5]);
59 face_vhandles.push_back(vhandle[4]);
60 mesh_.add_face(face_vhandles);
61
62 //=======================
63
64 face_vhandles.clear();
65 face_vhandles.push_back(vhandle[1]);
66 face_vhandles.push_back(vhandle[0]);
67 face_vhandles.push_back(vhandle[4]);
68 mesh_.add_face(face_vhandles);
69
70 face_vhandles.clear();
71 face_vhandles.push_back(vhandle[1]);
72 face_vhandles.push_back(vhandle[4]);
73 face_vhandles.push_back(vhandle[5]);
74 mesh_.add_face(face_vhandles);
75
76 //=======================
77
78 face_vhandles.clear();
79 face_vhandles.push_back(vhandle[2]);
80 face_vhandles.push_back(vhandle[1]);
81 face_vhandles.push_back(vhandle[5]);
82 mesh_.add_face(face_vhandles);
83
84 face_vhandles.clear();
85 face_vhandles.push_back(vhandle[2]);
86 face_vhandles.push_back(vhandle[5]);
87 face_vhandles.push_back(vhandle[6]);
88 mesh_.add_face(face_vhandles);
89
90
91 //=======================
92
93 face_vhandles.clear();
94 face_vhandles.push_back(vhandle[3]);
95 face_vhandles.push_back(vhandle[2]);
96 face_vhandles.push_back(vhandle[6]);
97 mesh_.add_face(face_vhandles);
98
99 face_vhandles.clear();
100 face_vhandles.push_back(vhandle[3]);
101 face_vhandles.push_back(vhandle[6]);
102 face_vhandles.push_back(vhandle[7]);
103 mesh_.add_face(face_vhandles);
104
105 //=======================
106
107 face_vhandles.clear();
108 face_vhandles.push_back(vhandle[0]);
109 face_vhandles.push_back(vhandle[3]);
110 face_vhandles.push_back(vhandle[7]);
111 mesh_.add_face(face_vhandles);
112
113 face_vhandles.clear();
114 face_vhandles.push_back(vhandle[0]);
115 face_vhandles.push_back(vhandle[7]);
116 face_vhandles.push_back(vhandle[4]);
117 mesh_.add_face(face_vhandles);
118
119
120 // Test setup:
121 //
122 //
123 // 3 ======== 2
124 // / /|
125 // / / | z
126 // 0 ======== 1 | |
127 // | | | | y
128 // | 7 | 6 | /
129 // | | / | /
130 // | |/ |/
131 // 4 ======== 5 -------> x
132 //
133
134 // Check setup
135 EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
136 EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
137 EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
138 EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
139 }
140
141 // This function is called after all tests are through
142 virtual void TearDown() {
143
144 // Do some final stuff with the member data here...
145
146 mesh_.clear();
147 }
148
149 // Member already defined in OpenMeshBase
150 //Mesh mesh_;
151};
152
153/*
154 * ====================================================================
155 * Define tests below
156 * ====================================================================
157 */
158
159
160template <typename HandleT>
161struct F
162{
163 unsigned int operator()(HandleT ) { return 1; }
164};
165
166/* Test if smart ranges work
167 */
168TEST_F(OpenMeshSmartRanges, Sum)
169{
170 auto one = [](OpenMesh::VertexHandle ) { return 1u; };
171 EXPECT_EQ(mesh_.vertices().sum(one), mesh_.n_vertices());
172 EXPECT_EQ(mesh_.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.n_vertices());
173 EXPECT_EQ(mesh_.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.n_halfedges());
174 EXPECT_EQ(mesh_.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.n_edges());
175 EXPECT_EQ(mesh_.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.n_faces());
176
177 for (auto vh : mesh_.vertices())
178 EXPECT_EQ(vh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(vh));
179 for (auto vh : mesh_.vertices())
180 EXPECT_EQ(vh.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.valence(vh));
181 for (auto vh : mesh_.vertices())
182 EXPECT_EQ(vh.outgoing_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
183 for (auto vh : mesh_.vertices())
184 EXPECT_EQ(vh.incoming_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
185
186 for (auto fh : mesh_.faces())
187 EXPECT_EQ(fh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(fh));
188 for (auto fh : mesh_.faces())
189 EXPECT_EQ(fh.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(fh));
190 for (auto fh : mesh_.faces())
191 EXPECT_EQ(fh.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.valence(fh));
192 for (auto fh : mesh_.faces())
193 EXPECT_EQ(fh.faces().sum(F<OpenMesh::FaceHandle>()), 3u);
194}
195
196
197/* Test if Property Manager can be used in smart ranges
198 */
199TEST_F(OpenMeshSmartRanges, PropertyManagerAsFunctor)
200{
201 OpenMesh::VProp<Mesh::Point> myPos(mesh_);
202 for (auto vh : mesh_.vertices())
203 myPos(vh) = mesh_.point(vh);
204
205 Mesh::Point cog(0,0,0);
206 for (auto vh : mesh_.vertices())
207 cog += mesh_.point(vh);
208 cog /= mesh_.n_vertices();
209
210 auto cog2 = mesh_.vertices().avg(myPos);
211
212 EXPECT_LT(norm(cog - cog2), 0.00001) << "Computed center of gravities are significantly different.";
213}
214
215/* Test to vector
216 */
217TEST_F(OpenMeshSmartRanges, ToVector)
218{
220
221 for (auto heh : mesh_.halfedges())
222 uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
223
224 for (auto fh : mesh_.faces())
225 {
226 auto tri_uvs = fh.halfedges().to_vector(uvs);
227 auto heh_handles = fh.halfedges().to_vector();
228 for (auto heh : heh_handles)
229 heh.next();
230 }
231
232 auto vertex_vec = mesh_.vertices().to_vector();
233 for (auto vh : vertex_vec)
234 vh.out();
235}
236
237/* Test to array
238 */
239TEST_F(OpenMeshSmartRanges, ToArray)
240{
242
243 for (auto heh : mesh_.halfedges())
244 uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
245
246 for (auto fh : mesh_.faces())
247 {
248 fh.halfedges().to_array<3>(uvs);
249 fh.halfedges().to_array<3>();
250 }
251}
252
253
254/* Test bounding box
255 */
256TEST_F(OpenMeshSmartRanges, BoundingBox)
257{
258 // The custom vecs OpenMesh are tested with here do not implement a min or max function.
259 // Thus we convert here.
261 for (auto vh : mesh_.vertices())
262 for (int i = 0; i < 3; ++i)
263 myPos(vh)[i] = mesh_.point(vh)[i];
264
265 auto bb_min = mesh_.vertices().min(myPos);
266 auto bb_max = mesh_.vertices().max(myPos);
267 mesh_.vertices().minmax(myPos);
268
269 EXPECT_LT(norm(bb_min - OpenMesh::Vec3f(-1,-1,-1)), 0.000001) << "Bounding box minimum seems off";
270 EXPECT_LT(norm(bb_max - OpenMesh::Vec3f( 1, 1, 1)), 0.000001) << "Bounding box maximum seems off";
271
272
273 auto uvs = OpenMesh::makeTemporaryProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh_);
274 for (auto heh : mesh_.halfedges())
275 uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
276
277 for (auto fh : mesh_.faces())
278 {
279 fh.halfedges().min(uvs);
280 fh.halfedges().max(uvs);
281 }
282}
283
284
285/* Test for each
286 */
287TEST_F(OpenMeshSmartRanges, ForEach)
288{
289 std::vector<int> vec;
290 auto f = [&vec](OpenMesh::VertexHandle vh) { vec.push_back(vh.idx()); };
291
292 mesh_.vertices().for_each(f);
293
294 ASSERT_EQ(vec.size(), mesh_.n_vertices()) << "vec has wrong size";
295 for (size_t i = 0; i < vec.size(); ++i)
296 EXPECT_EQ(vec[i], static_cast<int>(i)) << "wrong index in vector";
297}
298
299
300/* Test filter
301 */
302TEST_F(OpenMeshSmartRanges, Filtered)
303{
304 using VH = OpenMesh::VertexHandle;
305 using FH = OpenMesh::FaceHandle;
306
307 auto is_even = [](VH vh) { return vh.idx() % 2 == 0; };
308 auto is_odd = [](VH vh) { return vh.idx() % 2 == 1; };
309 auto is_divisible_by_3 = [](VH vh) { return vh.idx() % 3 == 0; };
310 auto to_id = [](VH vh) { return vh.idx(); };
311
312 auto even_vertices = mesh_.vertices().filtered(is_even).to_vector(to_id);
313 EXPECT_EQ(even_vertices.size(), 4u);
314 EXPECT_EQ(even_vertices[0], 0);
315 EXPECT_EQ(even_vertices[1], 2);
316 EXPECT_EQ(even_vertices[2], 4);
317 EXPECT_EQ(even_vertices[3], 6);
318
319 auto odd_vertices = mesh_.vertices().filtered(is_odd).to_vector(to_id);
320 EXPECT_EQ(odd_vertices.size(), 4u);
321 EXPECT_EQ(odd_vertices[0], 1);
322 EXPECT_EQ(odd_vertices[1], 3);
323 EXPECT_EQ(odd_vertices[2], 5);
324 EXPECT_EQ(odd_vertices[3], 7);
325
326 auto even_3_vertices = mesh_.vertices().filtered(is_even).filtered(is_divisible_by_3).to_vector(to_id);
327 EXPECT_EQ(even_3_vertices.size(), 2u);
328 EXPECT_EQ(even_3_vertices[0], 0);
329 EXPECT_EQ(even_3_vertices[1], 6);
330
331 auto odd_3_vertices = mesh_.vertices().filtered(is_odd).filtered(is_divisible_by_3).to_vector(to_id);
332 EXPECT_EQ(odd_3_vertices.size(), 1u);
333 EXPECT_EQ(odd_3_vertices[0], 3);
334
335
336 // create a vector of vertices in the order they are visited when iterating over face vertices, but every vertex only once
337 std::vector<VH> vertices;
338 OpenMesh::VProp<bool> to_be_processed(true, mesh_);
339 auto store_vertex = [&](VH vh) { to_be_processed(vh) = false; vertices.push_back(vh); };
340
341 for (auto fh : mesh_.faces())
342 fh.vertices().filtered(to_be_processed).for_each(store_vertex);
343
344 EXPECT_EQ(vertices.size(), mesh_.n_vertices()) << " number of visited vertices not correct";
345 EXPECT_TRUE(mesh_.vertices().all_of([&](VH vh) { return !to_be_processed(vh); })) << "did not visit all vertices";
346
347 {
348 OpenMesh::FProp<bool> to_be_visited(true, mesh_);
349 size_t visited_faces_in_main_loop = 0;
350 size_t visited_faces_in_sub_loop = 0;
351 for (auto fh : mesh_.faces().filtered(to_be_visited))
352 {
353 to_be_visited(fh) = false;
354 ++visited_faces_in_main_loop;
355 for (auto neighbor : fh.faces().filtered(to_be_visited))
356 {
357 to_be_visited(neighbor) = false;
358 ++visited_faces_in_sub_loop;
359 }
360 }
361
362 EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected";
363 EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces";
364 EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once";
365 }
366
367 {
368 OpenMesh::FProp<bool> to_be_visited(true, mesh_);
369 const auto& to_be_visited_const_ref = to_be_visited;
370 size_t visited_faces_in_main_loop = 0;
371 size_t visited_faces_in_sub_loop = 0;
372 for (auto fh : mesh_.faces().filtered(to_be_visited_const_ref))
373 {
374 to_be_visited(fh) = false;
375 ++visited_faces_in_main_loop;
376 for (auto neighbor : fh.faces().filtered(to_be_visited_const_ref))
377 {
378 to_be_visited(neighbor) = false;
379 ++visited_faces_in_sub_loop;
380 }
381 }
382
383 EXPECT_LT(visited_faces_in_main_loop, mesh_.n_faces()) << "Visted more faces than expected";
384 EXPECT_TRUE(mesh_.faces().all_of([&](FH fh) { return !to_be_visited(fh); })) << "did not visit all faces";
385 EXPECT_EQ(visited_faces_in_main_loop + visited_faces_in_sub_loop, mesh_.n_faces()) << "Did not visited all faces exactly once";
386 }
387
388}
389
390/* Test avg
391 */
392TEST_F(OpenMeshSmartRanges, Avg)
393{
394
395 Mesh::Point cog(0,0,0);
396 for (auto vh : mesh_.vertices())
397 cog += mesh_.point(vh);
398 cog /= mesh_.n_vertices();
399
400 auto points = OpenMesh::getPointsProperty(mesh_);
401 auto cog2 = mesh_.vertices().avg(points);
402
403 EXPECT_LT(norm(cog - cog2), 0.00001) << "Computed center of gravities are significantly different.";
404}
405
406/* Test weighted avg
407 */
408TEST_F(OpenMeshSmartRanges, WeightedAvg)
409{
410 Mesh::Point cog(0,0,0);
411 for (auto fh : mesh_.faces())
412 cog += mesh_.calc_face_centroid(fh);
413 cog /= mesh_.n_faces();
414
415 OpenMesh::FProp<float> area(mesh_);
416 for (auto fh : mesh_.faces())
417 area[fh] = mesh_.calc_face_area(fh);
418
419 auto cog2 = mesh_.faces().avg([&](OpenMesh::FaceHandle fh) { return mesh_.calc_face_centroid(fh); }, area);
420
421 EXPECT_LT(norm(cog - cog2), 0.00001) << "Computed area weighted center of gravities are significantly different.";
422}
423
424
425template <typename HandleT>
426void test_range_predicates(Mesh& _mesh)
427{
428 using namespace OpenMesh::Predicates;
429
430 auto get_random_set = [&](int n)
431 {
432 auto max = _mesh.n_elements<HandleT>();
433 std::vector<HandleT> set;
434 set.push_back(HandleT(0));
435 for (int i = 0; i < n; ++i)
436 set.push_back(HandleT(rand() % max));
437 std::sort(set.begin(), set.end());
438 set.erase(std::unique(set.begin(), set.end()), set.end());
439 return set;
440 };
441
442 // Feature
443 {
444 for (auto el : _mesh.elements<HandleT>())
445 _mesh.status(el).set_feature(false);
446 auto set = get_random_set(4);
447 for (auto el : set)
448 _mesh.status(el).set_feature(true);
449
450 auto set2 = _mesh.elements<HandleT>().filtered(Feature()).to_vector();
451
452 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
453 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
454 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
455
456 for (auto el : _mesh.elements<HandleT>())
457 _mesh.status(el).set_feature(false);
458 }
459
460 // Selected
461 {
462 for (auto el : _mesh.elements<HandleT>())
463 _mesh.status(el).set_selected(false);
464 auto set = get_random_set(4);
465 for (auto el : set)
466 _mesh.status(el).set_selected(true);
467
468 auto set2 = _mesh.elements<HandleT>().filtered(Selected()).to_vector();
469
470 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
471 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
472 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
473
474 for (auto el : _mesh.elements<HandleT>())
475 _mesh.status(el).set_selected(false);
476 }
477
478 // Tagged
479 {
480 for (auto el : _mesh.elements<HandleT>())
481 _mesh.status(el).set_tagged(false);
482 auto set = get_random_set(4);
483 for (auto el : set)
484 _mesh.status(el).set_tagged(true);
485
486 auto set2 = _mesh.elements<HandleT>().filtered(Tagged()).to_vector();
487
488 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
489 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
490 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
491
492 for (auto el : _mesh.elements<HandleT>())
493 _mesh.status(el).set_tagged(false);
494 }
495
496 // Tagged2
497 {
498 for (auto el : _mesh.elements<HandleT>())
499 _mesh.status(el).set_tagged2(false);
500 auto set = get_random_set(4);
501 for (auto el : set)
502 _mesh.status(el).set_tagged2(true);
503
504 auto set2 = _mesh.elements<HandleT>().filtered(Tagged2()).to_vector();
505
506 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
507 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
508 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
509
510 for (auto el : _mesh.elements<HandleT>())
511 _mesh.status(el).set_tagged2(false);
512 }
513
514 // Locked
515 {
516 for (auto el : _mesh.elements<HandleT>())
517 _mesh.status(el).set_locked(false);
518 auto set = get_random_set(4);
519 for (auto el : set)
520 _mesh.status(el).set_locked(true);
521
522 auto set2 = _mesh.elements<HandleT>().filtered(Locked()).to_vector();
523
524 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
525 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
526 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
527
528 for (auto el : _mesh.elements<HandleT>())
529 _mesh.status(el).set_locked(false);
530 }
531
532 // Hidden
533 {
534 for (auto el : _mesh.all_elements<HandleT>())
535 _mesh.status(el).set_hidden(false);
536 auto set = get_random_set(4);
537 for (auto el : set)
538 _mesh.status(el).set_hidden(true);
539
540 auto set2 = _mesh.all_elements<HandleT>().filtered(Hidden()).to_vector();
541
542 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
543 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
544 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
545
546 for (auto el : _mesh.all_elements<HandleT>())
547 _mesh.status(el).set_hidden(false);
548 }
549
550 // Deleted
551 {
552 for (auto el : _mesh.all_elements<HandleT>())
553 _mesh.status(el).set_deleted(false);
554 auto set = get_random_set(4);
555 for (auto el : set)
556 _mesh.status(el).set_deleted(true);
557
558 auto set2 = _mesh.all_elements<HandleT>().filtered(Deleted()).to_vector();
559
560 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
561 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
562 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
563
564 for (auto el : _mesh.all_elements<HandleT>())
565 _mesh.status(el).set_deleted(false);
566 }
567
568 // Custom property
569 {
571 auto set = get_random_set(4);
572 for (auto el : set)
573 prop[el] = true;
574
575 auto set2 = _mesh.elements<HandleT>().filtered(prop).to_vector();
576
577 EXPECT_EQ(set.size(), set2.size()) << "Set sizes differ";
578 for (size_t i = 0; i < std::min(set.size(), set2.size()); ++i)
579 EXPECT_EQ(set[i], set2[i]) << "Sets differ at position " << i;
580 }
581
582 // boundary
583 {
584 for (auto el : _mesh.elements<HandleT>().filtered(Boundary()))
585 EXPECT_TRUE(el.is_boundary());
586 int n_boundary1 = 0.0;
587 for (auto el : _mesh.elements<HandleT>())
588 if (el.is_boundary())
589 n_boundary1 += 1;
590 int n_boundary2 = _mesh.elements<HandleT>().count_if(Boundary());
591 EXPECT_EQ(n_boundary1, n_boundary2);
592 }
593}
594
595template <typename HandleT>
596void test_range_predicate_combinations(Mesh& _mesh)
597{
598 using namespace OpenMesh::Predicates;
599
600 auto n_elements = _mesh.n_elements<HandleT>();
601 auto get_random_set = [&](int n)
602 {
603 std::vector<HandleT> set;
604 for (int i = 0; i < n; ++i)
605 set.push_back(HandleT(rand() % n_elements));
606 std::sort(set.begin(), set.end());
607 set.erase(std::unique(set.begin(), set.end()), set.end());
608 return set;
609 };
610
611 // negation
612 {
613 auto set = get_random_set(4);
614 for (auto el : _mesh.elements<HandleT>())
615 _mesh.status(el).set_selected(false);
616 for (auto el : set)
617 _mesh.status(el).set_selected(true);
618
619 auto true_set = _mesh.elements<HandleT>().filtered(Selected()).to_vector();
620 auto false_set = _mesh.elements<HandleT>().filtered(!Selected()).to_vector();
621
622 std::vector<HandleT> intersection;
623 std::set_intersection(true_set.begin(), true_set.end(), false_set.begin(), false_set.end(), std::back_inserter(intersection));
624
625 EXPECT_TRUE(intersection.empty());
626 EXPECT_EQ(true_set.size() + false_set.size(), n_elements);
627
628 for (auto el : _mesh.elements<HandleT>())
629 _mesh.status(el).set_selected(false);
630 }
631
632 // conjunction
633 {
634 auto set1 = get_random_set(4);
635 auto set2 = get_random_set(4);
636 // make sure there is some overlap
637 {
638 auto set3 = get_random_set(3);
639 set1.insert(set1.end(), set3.begin(), set3.end());
640 set2.insert(set2.end(), set3.begin(), set3.end());
641 std::sort(set1.begin(), set1.end());
642 std::sort(set2.begin(), set2.end());
643 set1.erase(std::unique(set1.begin(), set1.end()), set1.end());
644 set2.erase(std::unique(set2.begin(), set2.end()), set2.end());
645 }
646
647 for (auto el : _mesh.elements<HandleT>())
648 _mesh.status(el).set_selected(false);
649 for (auto el : _mesh.elements<HandleT>())
650 _mesh.status(el).set_tagged(false);
651 for (auto el : set1)
652 _mesh.status(el).set_selected(true);
653 for (auto el : set2)
654 _mesh.status(el).set_tagged(true);
655
656 auto set = _mesh.elements<HandleT>().filtered(Selected() && Tagged()).to_vector();
657
658 std::vector<HandleT> intersection;
659 std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(intersection));
660
661 EXPECT_EQ(intersection.size(), set.size());
662 for (size_t i = 0; i < std::min(intersection.size(), set.size()); ++i)
663 EXPECT_EQ(intersection[i], set[i]) << "Sets differ at position " << i;
664
665 for (auto el : _mesh.elements<HandleT>())
666 _mesh.status(el).set_selected(false);
667 for (auto el : _mesh.elements<HandleT>())
668 _mesh.status(el).set_tagged(false);
669 }
670
671 // Disjunction
672 {
673 auto set1 = get_random_set(4);
674 auto set2 = get_random_set(4);
675 for (auto el : _mesh.elements<HandleT>())
676 _mesh.status(el).set_selected(false);
677 for (auto el : _mesh.elements<HandleT>())
678 _mesh.status(el).set_tagged(false);
679 for (auto el : set1)
680 _mesh.status(el).set_selected(true);
681 for (auto el : set2)
682 _mesh.status(el).set_tagged(true);
683
684 auto set = _mesh.elements<HandleT>().filtered(Selected() || Tagged()).to_vector();
685
686 std::vector<HandleT> union_set;
687 std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
688
689 EXPECT_EQ(union_set.size(), set.size());
690 for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
691 EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
692
693 for (auto el : _mesh.elements<HandleT>())
694 _mesh.status(el).set_selected(false);
695 for (auto el : _mesh.elements<HandleT>())
696 _mesh.status(el).set_tagged(false);
697 }
698
699}
700
701template <typename HandleT>
702bool test_func(HandleT _h)
703{
704 return _h.idx() % 3 == 0;
705}
706
707template <typename HandleT>
708void test_make_predicate(Mesh& _mesh)
709{
710 using namespace OpenMesh::Predicates;
711
712 auto n_elements = _mesh.n_elements<HandleT>();
713 auto get_random_set = [&](int n)
714 {
715 std::vector<HandleT> set;
716 for (int i = 0; i < n; ++i)
717 set.push_back(HandleT(rand() % n_elements));
718 std::sort(set.begin(), set.end());
719 set.erase(std::unique(set.begin(), set.end()), set.end());
720 return set;
721 };
722
723 // custom property
724 {
726 auto set1 = get_random_set(4);
727 auto set2 = get_random_set(4);
728 for (auto el : set1)
729 prop[el] = true;
730 for (auto el : _mesh.elements<HandleT>())
731 _mesh.status(el).set_selected(false);
732 for (auto el : set2)
733 _mesh.status(el).set_selected(true);
734
735 auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(prop)).to_vector();
736
737 std::vector<HandleT> union_set;
738 std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
739
740 EXPECT_EQ(union_set.size(), set.size());
741 for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
742 EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
743
744 for (auto el : _mesh.elements<HandleT>())
745 _mesh.status(el).set_selected(false);
746 for (auto el : _mesh.elements<HandleT>())
747 _mesh.status(el).set_tagged(false);
748 }
749
750 // lambda
751 {
753 auto set1 = get_random_set(4);
754 auto set2 = get_random_set(4);
755 for (auto el : set1)
756 prop[el] = true;
757 for (auto el : _mesh.elements<HandleT>())
758 _mesh.status(el).set_selected(false);
759 for (auto el : set2)
760 _mesh.status(el).set_selected(true);
761
762 auto test = [&](HandleT h) { return prop(h); };
763
764 auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(test)).to_vector();
765
766 std::vector<HandleT> union_set;
767 std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
768
769 EXPECT_EQ(union_set.size(), set.size());
770 for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
771 EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
772
773 for (auto el : _mesh.elements<HandleT>())
774 _mesh.status(el).set_selected(false);
775 for (auto el : _mesh.elements<HandleT>())
776 _mesh.status(el).set_tagged(false);
777 }
778
779 // r value lambda
780 {
782 auto set1 = get_random_set(4);
783 auto set2 = get_random_set(4);
784 for (auto el : set1)
785 prop[el] = true;
786 for (auto el : _mesh.elements<HandleT>())
787 _mesh.status(el).set_selected(false);
788 for (auto el : set2)
789 _mesh.status(el).set_selected(true);
790
791 auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate([&](HandleT h) { return prop(h); })).to_vector();
792
793 std::vector<HandleT> union_set;
794 std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
795
796 EXPECT_EQ(union_set.size(), set.size());
797 for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
798 EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
799
800 for (auto el : _mesh.elements<HandleT>())
801 _mesh.status(el).set_selected(false);
802 for (auto el : _mesh.elements<HandleT>())
803 _mesh.status(el).set_tagged(false);
804 }
805
806 // function pointer
807 {
808 auto set1 = _mesh.elements<HandleT>().filtered([&](const HandleT& h) { return test_func(h); }).to_vector();
809 auto set2 = get_random_set(4);
810 for (auto el : _mesh.elements<HandleT>())
811 _mesh.status(el).set_selected(false);
812 for (auto el : set2)
813 _mesh.status(el).set_selected(true);
814
815 auto set = _mesh.elements<HandleT>().filtered(Selected() || make_predicate(test_func<HandleT>)).to_vector();
816
817 std::vector<HandleT> union_set;
818 std::set_union(set1.begin(), set1.end(), set2.begin(), set2.end(), std::back_inserter(union_set));
819
820 EXPECT_EQ(union_set.size(), set.size());
821 for (size_t i = 0; i < std::min(union_set.size(), set.size()); ++i)
822 EXPECT_EQ(union_set[i], set[i]) << "Sets differ at position " << i;
823
824 for (auto el : _mesh.elements<HandleT>())
825 _mesh.status(el).set_selected(false);
826 for (auto el : _mesh.elements<HandleT>())
827 _mesh.status(el).set_tagged(false);
828 }
829}
830
831TEST_F(OpenMeshSmartRanges, Predicate)
832{
833 using namespace OpenMesh;
834
835 mesh_.request_vertex_status();
836 mesh_.request_halfedge_status();
837 mesh_.request_edge_status();
838 mesh_.request_face_status();
839
840 mesh_.delete_face(FaceHandle(0)); // ensure there is a boundary
841 mesh_.garbage_collection();
842
843 test_range_predicates<VertexHandle>(mesh_);
844 test_range_predicates<HalfedgeHandle>(mesh_);
845 test_range_predicates<EdgeHandle>(mesh_);
846 test_range_predicates<FaceHandle>(mesh_);
847
848 test_range_predicate_combinations<VertexHandle>(mesh_);
849 test_range_predicate_combinations<HalfedgeHandle>(mesh_);
850 test_range_predicate_combinations<EdgeHandle>(mesh_);
851 test_range_predicate_combinations<FaceHandle>(mesh_);
852
853 test_make_predicate<VertexHandle>(mesh_);
854 test_make_predicate<HalfedgeHandle>(mesh_);
855 test_make_predicate<EdgeHandle>(mesh_);
856 test_make_predicate<FaceHandle>(mesh_);
857}
858
859struct MemberFunctionWrapperTestStruct
860{
861 MemberFunctionWrapperTestStruct(int _i)
862 :
863 i_(_i)
864 {
865 }
866
867 int get_i(const OpenMesh::SmartEdgeHandle& /*_eh*/) const
868 {
869 return i_;
870 }
871
872 bool id_divisible_by_2(const OpenMesh::SmartEdgeHandle& _eh) const
873 {
874 return _eh.idx() % 2 == 0;
875 }
876
877 int valence_times_i(const OpenMesh::SmartVertexHandle& vh)
878 {
879 return vh.edges().sum(OM_MFW(get_i));
880 }
881
882 int i_;
883};
884
885TEST_F(OpenMeshSmartRanges, MemberFunctionFunctor)
886{
887 using namespace OpenMesh::Predicates;
888
889 EXPECT_TRUE(mesh_.n_vertices() > 0) << "Mesh has no vertices";
890 EXPECT_TRUE(mesh_.n_edges() > 0) << "Mesh has no edges";
891
892 int factor = 3;
893 MemberFunctionWrapperTestStruct test_object(factor);
894
895 // Test using a MemberFunctionWrapper as Functorstatic_cast<int>(
896 EXPECT_EQ(static_cast<int>(mesh_.n_edges() / 2), mesh_.edges().count_if(make_member_function_wrapper(test_object, &MemberFunctionWrapperTestStruct::id_divisible_by_2)));
897
898
899 // Test using a MemberFunctionWrapper as Functor that is created using the convenience macro from inside the struct
900 for (auto vh : mesh_.vertices())
901 EXPECT_EQ(test_object.valence_times_i(vh), static_cast<int>(vh.valence()) * factor);
902
903 factor = 4;
904 test_object.i_ = factor;
905 for (auto vh : mesh_.vertices())
906 {
907 EXPECT_EQ(test_object.valence_times_i(vh), static_cast<int>(vh.valence() * factor));
908 }
909
910
911
912}
913
914}
int idx() const
Get the underlying index of this handle.
Definition Handles.hh:69
void calc_face_centroid(FaceHandle _fh, Point &_pt) const
calculates the average of the vertices defining _fh
Definition PolyMeshT.hh:299
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition PolyMeshT.hh:136
SmartVertexHandle add_vertex(const Point _p)
Definition PolyMeshT.hh:255
Kernel::Point Point
Coordinate type.
Definition PolyMeshT.hh:112
Scalar min() const
return the minimal component
Definition Vector11T.hh:532
Handle for a face entity.
Definition Handles.hh:142
auto sum(Functor &&f) -> typename std::decay< decltype(f(std::declval< HandleT >()))>::type
Computes the sum of elements.
Definition SmartRange.hh:88
Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...
uint valence() const
Returns valence of the vertex.
PolyConnectivity::ConstVertexEdgeRange edges() const
Returns a range of edges incident to the vertex (PolyConnectivity::ve_range())
Handle for a vertex entity.
Definition Handles.hh:121