Developer Documentation
Loading...
Searching...
No Matches
unittests_propertymanager.cc
1#include <gtest/gtest.h>
2#include <Unittests/unittests_common.hh>
3#include <OpenMesh/Core/Utils/PropertyManager.hh>
4
5#include <iostream>
6
7//#define ENABLE_PROPERTY_TIMING_OUTPUT
8#ifdef ENABLE_PROPERTY_TIMING_OUTPUT
9#define N_VERTICES_TIMING 1000000
10#define TIMING_OUTPUT(X) X
11#else
12#define N_VERTICES_TIMING 10
13#define TIMING_OUTPUT(X)
14#endif
15
16namespace {
17
18class OpenMeshPropertyManager : public OpenMeshBase {
19
20 protected:
21
22 // This function is called before each test is run
23 virtual void SetUp() {
24 }
25
26 // This function is called after all tests are through
27 virtual void TearDown() {
28
29 // Do some final stuff with the member data here...
30 }
31
32 // Member already defined in OpenMeshBase
33 //Mesh mesh_;
34};
35
36/*
37 * ====================================================================
38 * General Tests
39 * ====================================================================
40 */
41
42/*
43 * Collapsing a tetrahedron
44 */
45TEST_F(OpenMeshPropertyManager, set_range_bool) {
46
47 mesh_.clear();
48
49 // Add some vertices
50 Mesh::VertexHandle vhandle[4];
51
52 vhandle[0] = mesh_.add_vertex(Mesh::Point(0, 0, 0));
53 vhandle[1] = mesh_.add_vertex(Mesh::Point(0, 1, 0));
54 vhandle[2] = mesh_.add_vertex(Mesh::Point(1, 1, 0));
55 vhandle[3] = mesh_.add_vertex(Mesh::Point(0, 0, 1));
56
57 // Add two faces
58 std::vector<Mesh::VertexHandle> face_vhandles;
59
60 face_vhandles.push_back(vhandle[0]);
61 face_vhandles.push_back(vhandle[1]);
62 face_vhandles.push_back(vhandle[2]);
63 mesh_.add_face(face_vhandles);
64
65 face_vhandles.clear();
66
67 face_vhandles.push_back(vhandle[0]);
68 face_vhandles.push_back(vhandle[2]);
69 face_vhandles.push_back(vhandle[3]);
70 mesh_.add_face(face_vhandles);
71
72 {
74 OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool");
75 pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), false);
76 for (int i = 0; i < 4; ++i)
77 ASSERT_FALSE(pm_v_bool[vhandle[i]]);
78 pm_v_bool.set_range(mesh_.vertices_begin(), mesh_.vertices_end(), true);
79 for (int i = 0; i < 4; ++i)
80 ASSERT_TRUE(pm_v_bool[vhandle[i]]);
81
83 OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool");
84 pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), false);
85 for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
86 e_it != f_end; ++e_it)
87 ASSERT_FALSE(pm_e_bool[*e_it]);
88 pm_e_bool.set_range(mesh_.edges_begin(), mesh_.edges_end(), true);
89 for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
90 e_it != f_end; ++e_it)
91 ASSERT_TRUE(pm_e_bool[*e_it]);
92
94 OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool");
95 pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), false);
96 for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
97 f_it != f_end; ++f_it)
98 ASSERT_FALSE(pm_f_bool[*f_it]);
99 pm_f_bool.set_range(mesh_.faces_begin(), mesh_.faces_end(), true);
100 for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
101 f_it != f_end; ++f_it)
102 ASSERT_TRUE(pm_f_bool[*f_it]);
103 }
104
105 /*
106 * Same thing again, this time with C++11 ranges.
107 */
108 {
110 OpenMesh::VPropHandleT<bool>> pm_v_bool(mesh_, "pm_v_bool2");
111 pm_v_bool.set_range(mesh_.vertices(), false);
112 for (int i = 0; i < 4; ++i)
113 ASSERT_FALSE(pm_v_bool[vhandle[i]]);
114 pm_v_bool.set_range(mesh_.vertices(), true);
115 for (int i = 0; i < 4; ++i)
116 ASSERT_TRUE(pm_v_bool[vhandle[i]]);
117
119 OpenMesh::EPropHandleT<bool>> pm_e_bool(mesh_, "pm_e_bool2");
120 pm_e_bool.set_range(mesh_.edges(), false);
121 for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
122 e_it != f_end; ++e_it)
123 ASSERT_FALSE(pm_e_bool[*e_it]);
124 pm_e_bool.set_range(mesh_.edges(), true);
125 for (Mesh::EdgeIter e_it = mesh_.edges_begin(), f_end = mesh_.edges_end();
126 e_it != f_end; ++e_it)
127 ASSERT_TRUE(pm_e_bool[*e_it]);
128
130 OpenMesh::FPropHandleT<bool>> pm_f_bool(mesh_, "pm_f_bool2");
131 pm_f_bool.set_range(mesh_.faces(), false);
132 for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
133 f_it != f_end; ++f_it)
134 ASSERT_FALSE(pm_f_bool[*f_it]);
135 pm_f_bool.set_range(mesh_.faces(), true);
136 for (Mesh::FaceIter f_it = mesh_.faces_begin(), f_end = mesh_.faces_end();
137 f_it != f_end; ++f_it)
138 ASSERT_TRUE(pm_f_bool[*f_it]);
139 }
140}
141
142/*
143 * In sequence:
144 * - add a persistent property to a mesh
145 * - retrieve an existing property of a mesh and modify it
146 * - obtain a non-owning property handle
147 * - attempt to obtain a non-owning handle to a non-existing property (throws)
148 */
149TEST_F(OpenMeshPropertyManager, cpp11_persistent_and_non_owning_properties) {
150 auto vh = mesh_.add_vertex({0,0,0}); // Dummy vertex to attach properties to
151
152 const auto prop_name = "pm_v_test_property";
153
154 ASSERT_FALSE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
155
156 {
157 auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
158 prop[vh] = 100;
159 // End of scope, property persists
160 }
161
162 ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
163
164 {
165 // Since a property of the same name and type already exists, this refers to the existing property.
166 auto prop = OpenMesh::getOrMakeProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
167 ASSERT_EQ(100, prop[vh]);
168 prop[vh] = 200;
169 // End of scope, property persists
170 }
171
172 ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
173
174 {
175 // Acquire non-owning handle to the property, knowing it exists
176 auto prop = OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name);
177 ASSERT_EQ(200, prop[vh]);
178 }
179
180 ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
181
182 {
183 // Attempt to acquire non-owning handle for a non-existing property
184 auto code_that_throws = [&](){
185 OpenMesh::getProperty<OpenMesh::VertexHandle, int>(mesh_, "wrong_prop_name");
186 };
187 ASSERT_THROW(code_that_throws(), std::runtime_error);
188 }
189
190 ASSERT_TRUE((OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, prop_name)));
191}
192
193
194TEST_F(OpenMeshPropertyManager, property_copy_construction) {
195 for (int i = 0; i < N_VERTICES_TIMING; ++i)
196 mesh_.add_vertex(Mesh::Point());
197
198 // unnamed
199 {
200 auto prop1 = OpenMesh::VProp<int>(mesh_);
201 for (auto vh : mesh_.vertices())
202 prop1[vh] = vh.idx()*2-13;
203
204 auto prop2 = prop1; // prop1 and prop2 should be two different properties with the same content
205
206 prop1.set_range(mesh_.vertices(), 0);
207
208 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
209 }
210
211 // named
212 {
213 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
214 for (auto vh : mesh_.vertices())
215 prop1[vh] = vh.idx()*2-13;
216
217 auto prop2 = prop1; // prop1 and prop2 should refere to the same property
218
219 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
220
221 prop1.set_range(mesh_.vertices(), 0);
222
223 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
224 }
225}
226
227TEST_F(OpenMeshPropertyManager, property_move_construction) {
228 for (int i = 0; i < N_VERTICES_TIMING; ++i)
229 mesh_.add_vertex(Mesh::Point());
230
231 // unnamed
232 {
233 auto prop1 = OpenMesh::VProp<int>(mesh_);
234 for (auto vh : mesh_.vertices())
235 prop1[vh] = vh.idx()*2-13;
236
237 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
238 auto prop2 = std::move(prop1);
239 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
240 TIMING_OUTPUT(std::cout << "move constructing property from temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
241
242 EXPECT_FALSE(prop1.isValid()) << "prop1 should have been invalidated";
243
244 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13);
245 }
246
247 // named
248 {
249 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids");
250 for (auto vh : mesh_.vertices())
251 prop1[vh] = vh.idx()*2-13;
252
253 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
254 auto prop2 = std::move(prop1); // prop1 and prop2 should refere to the same property
255 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
256 TIMING_OUTPUT(std::cout << "move constructing from named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
257
258 EXPECT_TRUE(prop1.isValid()) << "named properties cannot be invalidated";
259
260 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "property is not valid anymore";
261 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "did not copy property correctly";
262
263 prop1.set_range(mesh_.vertices(), 0);
264
265 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0);
266 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0);
267 }
268}
269
270
271TEST_F(OpenMeshPropertyManager, property_copying_same_mesh) {
272
273 for (int i = 0; i < N_VERTICES_TIMING; ++i)
274 mesh_.add_vertex(Mesh::Point());
275
276 // unnamed to unnamed
277 {
278 auto prop1 = OpenMesh::VProp<int>(3, mesh_);
279 auto prop2 = OpenMesh::VProp<int>(0, mesh_);
280 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
281 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
282
283 for (auto vh : mesh_.vertices())
284 prop1[vh] = vh.idx()*2-13;
285
286 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
287
288 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
289 prop2 = prop1;
290 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
291 TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
292
293 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
294
295 prop1.set_range(mesh_.vertices(), 0);
296
297 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
298 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
299 }
300
301 // unnamed to named
302 {
303 auto prop1 = OpenMesh::VProp<int>(mesh_);
304 auto prop2 = OpenMesh::VProp<int>(0, mesh_, "ids");
305 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
306
307 for (auto vh : mesh_.vertices())
308 prop1[vh] = vh.idx()*2-13;
309
310 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
311
312 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
313 prop2 = prop1;
314 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
315 TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
316
317 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
318
319 prop1.set_range(mesh_.vertices(), 0);
320
321 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
322
323 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
324 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
325 }
326
327 // named to unnamed
328 {
329 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
330 auto prop2 = OpenMesh::VProp<int>(mesh_);
331 prop2.set_range(mesh_.vertices(), 0);
332 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
333
334 for (auto vh : mesh_.vertices())
335 prop1[vh] = vh.idx()*2-13;
336
337 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
338 prop2 = prop1;
339 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
340 TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
341
342 prop1.set_range(mesh_.vertices(), 0);
343
344 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
345
346 }
347
348 // named to named (different names)
349 {
350 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
351 auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
352 prop2.set_range(mesh_.vertices(), 0);
353 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
354
355 for (auto vh : mesh_.vertices())
356 prop1[vh] = vh.idx()*2-13;
357
358 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
359
360 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
361 prop2 = prop1;
362 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
363 TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
364
365 prop1.set_range(mesh_.vertices(), 0);
366
367 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
368 }
369
370 // named to named (same names)
371 {
372 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
373 auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
374
375 for (auto vh : mesh_.vertices())
376 prop1[vh] = vh.idx()*2-13;
377
378 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
379 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
380
381 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
382 prop2 = prop1; // this should be a no op
383 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
384 TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
385
386 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
387 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
388
389 prop1.set_range(mesh_.vertices(), 42);
390
391 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
392 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
393
394 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
395 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
396 }
397
398 {
399 auto prop1 = OpenMesh::MProp<int>(mesh_);
400 *prop1 = 43;
401 auto prop2 = prop1;
402
403 prop2 = prop1;
404
405 prop2 = std::move(prop1);
406 }
407}
408
409
410TEST_F(OpenMeshPropertyManager, property_moving_same_mesh) {
411
412 for (int i = 0; i < N_VERTICES_TIMING; ++i)
413 mesh_.add_vertex(Mesh::Point());
414
415 // unnamed to unnamed
416 {
417 auto prop1 = OpenMesh::VProp<int>(mesh_);
418 auto prop2 = OpenMesh::VProp<int>(mesh_);
419 prop2.set_range(mesh_.vertices(), 0);
420
421 for (auto vh : mesh_.vertices())
422 prop1[vh] = vh.idx()*2-13;
423
424 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
425
426 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
427 prop2 = std::move(prop1); // this should be cheap
428 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
429 TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
430
431 EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
432
433 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
434 }
435
436 // unnamed to named
437 {
438 auto prop1 = OpenMesh::VProp<int>(mesh_);
439 auto prop2 = OpenMesh::VProp<int>(mesh_, "ids");
440 prop2.set_range(mesh_.vertices(), 0);
441 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
442
443 for (auto vh : mesh_.vertices())
444 prop1[vh] = vh.idx()*2-13;
445
446 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
447
448 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
449 prop2 = std::move(prop1);
450 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
451 TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
452
453 EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
454
455 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
456
457 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids");
458 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
459 }
460
461 // named to unnamed
462 {
463 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
464 auto prop2 = OpenMesh::VProp<int>(mesh_);
465 prop2.set_range(mesh_.vertices(), 0);
466 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
467
468 for (auto vh : mesh_.vertices())
469 prop1[vh] = vh.idx()*2-13;
470
471 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
472 prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
473 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
474 TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
475
476 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
477
478 prop1.set_range(mesh_.vertices(), 0);
479
480 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
481
482 }
483
484 // named to named (different names)
485 {
486 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
487 auto prop2 = OpenMesh::VProp<int>(mesh_, "ids4");
488 prop2.set_range(mesh_.vertices(), 0);
489 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
490
491 for (auto vh : mesh_.vertices())
492 prop1[vh] = vh.idx()*2-13;
493
494 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
495
496 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
497 prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
498 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
499 TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
500
501 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
502
503 prop1.set_range(mesh_.vertices(), 0);
504
505 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
506 }
507
508 // named to named (same names)
509 {
510 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
511 auto prop2 = OpenMesh::VProp<int>(mesh_, "ids5");
512
513 for (auto vh : mesh_.vertices())
514 prop1[vh] = vh.idx()*2-13;
515
516 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
517 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
518
519 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
520 prop2 = std::move(prop1); // this should be a no op
521 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
522 TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
523
524 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
525
526 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
527 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
528
529 prop1.set_range(mesh_.vertices(), 0);
530
531 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
532 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
533
534 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
535 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
536 }
537}
538
539
540
541TEST_F(OpenMeshPropertyManager, property_copying_different_mesh) {
542
543 for (int i = 0; i < N_VERTICES_TIMING; ++i)
544 mesh_.add_vertex(Mesh::Point());
545
546 auto copy = mesh_;
547 for (int i = 0; i < 10; ++i)
548 copy.add_vertex(Mesh::Point());
549
550 // unnamed to unnamed
551 {
552 auto prop1 = OpenMesh::VProp<int>(3, mesh_);
553 auto prop2 = OpenMesh::VProp<int>(0, copy);
554 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 3) << "Property not initialized correctly";
555 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
556
557 for (auto vh : mesh_.vertices())
558 prop1[vh] = vh.idx()*2-13;
559
560 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
561
562 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
563 prop2 = prop1;
564 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
565 TIMING_OUTPUT(std::cout << "copying property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
566
567 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
568
569 prop1.set_range(mesh_.vertices(), 0);
570
571 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 0) << "Property not copied correctly";
572 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
573 EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
574 }
575
576 // unnamed to named
577 {
578 auto prop1 = OpenMesh::VProp<int>(mesh_);
579 auto prop2 = OpenMesh::VProp<int>(0, copy, "ids");
580 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
581
582 for (auto vh : mesh_.vertices())
583 prop1[vh] = vh.idx()*2-13;
584
585 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
586
587 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
588 prop2 = prop1;
589 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
590 TIMING_OUTPUT(std::cout << "copying property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
591
592 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Temporary property got destroyed";
593
594 prop1.set_range(mesh_.vertices(), 0);
595
596 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
597
598 auto prop3 = OpenMesh::VProp<int>(copy, "ids");
599 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
600 }
601
602 // named to unnamed
603 {
604 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
605 auto prop2 = OpenMesh::VProp<int>(copy);
606 prop2.set_range(mesh_.vertices(), 0);
607 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
608
609 for (auto vh : mesh_.vertices())
610 prop1[vh] = vh.idx()*2-13;
611
612 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
613 prop2 = prop1;
614 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
615 TIMING_OUTPUT(std::cout << "copying property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
616
617 prop1.set_range(mesh_.vertices(), 0);
618
619 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
620
621 }
622
623 // named to named (different names)
624 {
625 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
626 auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
627 prop2.set_range(mesh_.vertices(), 0);
628 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
629
630 for (auto vh : mesh_.vertices())
631 prop1[vh] = vh.idx()*2-13;
632
633 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
634
635 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
636 prop2 = prop1;
637 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
638 TIMING_OUTPUT(std::cout << "copying property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
639
640 prop1.set_range(mesh_.vertices(), 0);
641
642 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
643 }
644
645 // named to named (same names)
646 {
647 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
648 auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
649
650 for (auto vh : mesh_.vertices())
651 prop1[vh] = vh.idx()*2-13;
652
653 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
654
655 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
656 prop2 = prop1; // this should be a no op
657 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
658 TIMING_OUTPUT(std::cout << "copying property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
659
660 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
661 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
662
663 prop1.set_range(mesh_.vertices(), 42);
664
665 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
666 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
667
668 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
669 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
670 auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
671 EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
672 }
673}
674
675
676TEST_F(OpenMeshPropertyManager, property_moving_different_mesh) {
677
678 for (int i = 0; i < N_VERTICES_TIMING; ++i)
679 mesh_.add_vertex(Mesh::Point());
680
681 auto copy = mesh_;
682 for (int i = 0; i < 10; ++i)
683 copy.add_vertex(Mesh::Point());
684
685 // unnamed to unnamed
686 {
687 auto prop1 = OpenMesh::VProp<int>(mesh_);
688 auto prop2 = OpenMesh::VProp<int>(copy);
689 prop2.set_range(mesh_.vertices(), 0);
690
691 for (auto vh : mesh_.vertices())
692 prop1[vh] = vh.idx()*2-13;
693
694 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
695
696 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
697 prop2 = std::move(prop1); // this should be cheap
698 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
699 TIMING_OUTPUT(std::cout << "moving property temporary to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
700
701 EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
702
703 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
704 EXPECT_NO_FATAL_FAILURE(prop2[OpenMesh::VertexHandle(static_cast<int>(copy.n_vertices())-1)]) << "Property not correctly resized";
705 }
706
707 // unnamed to named
708 {
709 auto prop1 = OpenMesh::VProp<int>(mesh_);
710 auto prop2 = OpenMesh::VProp<int>(copy, "ids");
711 prop2.set_range(mesh_.vertices(), 0);
712 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
713
714 for (auto vh : mesh_.vertices())
715 prop1[vh] = vh.idx()*2-13;
716
717 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
718
719 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
720 prop2 = std::move(prop1);
721 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
722 TIMING_OUTPUT(std::cout << "moving property temporary to named took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
723
724 EXPECT_FALSE(prop1.isValid()) << "prop1 not invalidated after moving";
725
726 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
727
728 auto prop3 = OpenMesh::VProp<int>(copy, "ids");
729 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], -13) << "property with name 'ids' was not correctly changed";
730 }
731
732 // named to unnamed
733 {
734 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids2");
735 auto prop2 = OpenMesh::VProp<int>(copy);
736 prop2.set_range(mesh_.vertices(), 0);
737 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
738
739 for (auto vh : mesh_.vertices())
740 prop1[vh] = vh.idx()*2-13;
741
742 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
743 prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
744 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
745 TIMING_OUTPUT(std::cout << "moving property named to temporary took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
746
747 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
748
749 prop1.set_range(mesh_.vertices(), 0);
750
751 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
752
753 }
754
755 // named to named (different names)
756 {
757 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids3");
758 auto prop2 = OpenMesh::VProp<int>(copy, "ids4");
759 prop2.set_range(mesh_.vertices(), 0);
760 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
761
762 for (auto vh : mesh_.vertices())
763 prop1[vh] = vh.idx()*2-13;
764
765 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], 0) << "Property not initialized correctly";
766
767 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
768 prop2 = std::move(prop1); // moving named properties will not invalidate the property and will copy the data
769 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
770 TIMING_OUTPUT(std::cout << "moving property named to named with different name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
771
772 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
773
774 prop1.set_range(mesh_.vertices(), 0);
775
776 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
777 }
778
779 // named to named (same names)
780 {
781 auto prop1 = OpenMesh::VProp<int>(mesh_, "ids5");
782 auto prop2 = OpenMesh::VProp<int>(copy, "ids5");
783
785 prop6 = prop1;
786
787 for (auto vh : mesh_.vertices())
788 prop1[vh] = vh.idx()*2-13;
789
790 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
791
792 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
793 prop2 = std::move(prop1); // should copy
794 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
795 TIMING_OUTPUT(std::cout << "moving property named to named with same name took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
796
797 EXPECT_TRUE(prop1.isValid()) << "named prop1 should not be invalidated by moving";
798
799 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
800 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
801
802 prop1.set_range(mesh_.vertices(), 42);
803
804 EXPECT_EQ(prop1[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
805 EXPECT_EQ(prop2[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
806
807 auto prop3 = OpenMesh::VProp<int>(mesh_, "ids5");
808 EXPECT_EQ(prop3[OpenMesh::VertexHandle(0)], 42) << "Property not copied correctly";
809 auto prop4 = OpenMesh::VProp<int>(copy, "ids5");
810 EXPECT_EQ(prop4[OpenMesh::VertexHandle(0)], -13) << "Property not copied correctly";
811 }
812}
813
814
815TEST_F(OpenMeshPropertyManager, temporary_property_on_const_mesh) {
816
817 const auto& const_ref = mesh_;
818
819 auto cog = OpenMesh::FProp<Mesh::Point>(const_ref);
820 auto points = OpenMesh::getPointsProperty(const_ref);
821
822 for (auto fh : const_ref.faces())
823 cog(fh) = fh.vertices().avg(points);
824
825 auto cog_copy = cog;
826
827 for (auto fh : const_ref.faces())
828 {
829 EXPECT_NE(&cog(fh), &cog_copy(fh)) << "Both properties point to the same memory";
830 EXPECT_EQ(cog(fh), cog_copy(fh)) << "Property not copied correctly";
831 }
832
833 auto description = OpenMesh::MProp<std::string>(const_ref);
834 description() = "Cool Const Mesh";
835
836 std::cout << description(OpenMesh::MeshHandle(33)) << std::endl;
837
838}
839
840
842{
843 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
844
845 auto id_prop = OpenMesh::VProp<int>(mesh);
846 for (auto vh : mesh.vertices())
847 id_prop(vh) = vh.idx();
848
849 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
850 TIMING_OUTPUT(std::cout << "Time spend in function: " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
851
852 return id_prop;
853}
854
855TEST_F(OpenMeshPropertyManager, return_property_from_function) {
856
857 for (int i = 0; i < N_VERTICES_TIMING; ++i)
858 mesh_.add_vertex(Mesh::Point());
859
860 TIMING_OUTPUT(auto t_start = std::chrono::high_resolution_clock::now();)
861 auto id_p = get_id_prop(mesh_);
862 TIMING_OUTPUT(auto t_end = std::chrono::high_resolution_clock::now();)
863 TIMING_OUTPUT(std::cout << "Time spend around function " << std::chrono::duration_cast<std::chrono::milliseconds>(t_end-t_start).count() << "ms" << std::endl;)
864
865 for (auto vh : mesh_.vertices())
866 {
867 EXPECT_EQ(id_p(vh), vh.idx()) << "Property not returned correctly" << std::endl;
868 }
869
870}
871
872
873TEST_F(OpenMeshPropertyManager, mesh_property_initialization) {
874
875 OpenMesh::MProp<int> mesh_id(13, mesh_);
876 ASSERT_EQ(mesh_id(), 13);
877}
878
879
880
881
882TEST_F(OpenMeshPropertyManager, property_without_default_constructor ) {
883
884 // just check if this compiles
885
886 struct NoDefaultConstructor
887 {
888 int val;
889 NoDefaultConstructor() = delete;
890 NoDefaultConstructor(int i) : val(i) {}
891 };
892
898}
899
900
901}
Connectivity Class for polygonal meshes.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition PolyMeshT.hh:136
Kernel::FaceIter FaceIter
Scalar type.
Definition PolyMeshT.hh:146
SmartVertexHandle add_vertex(const Point _p)
Definition PolyMeshT.hh:255
Kernel::EdgeIter EdgeIter
Scalar type.
Definition PolyMeshT.hh:145
Kernel::Point Point
Coordinate type.
Definition PolyMeshT.hh:112
Handle type for meshes to simplify some template programming.
Definition Handles.hh:149
Handle for a vertex entity.
Definition Handles.hh:121