Developer Documentation

unittests_smart_handles.cc
1 #include <gtest/gtest.h>
2 #include <Unittests/unittests_common.hh>
3
4 #include <OpenMesh/Core/Mesh/SmartHandles.hh>
5
6 #include <iostream>
7 #include <chrono>
8
9 namespace {
10
11 class OpenMeshSmartHandles : public OpenMeshBase {
12
13 protected:
14
15 // This function is called before each test is run
16 virtual void SetUp() {
17
18 mesh_.clear();
19
20 // Add some vertices
21 Mesh::VertexHandle vhandle[8];
22 vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
23 vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
24 vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
25 vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
26 vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
27 vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
28 vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
29 vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
30
31 // Add six faces to form a cube
32 std::vector<Mesh::VertexHandle> face_vhandles;
33
34 face_vhandles.clear();
35 face_vhandles.push_back(vhandle[0]);
36 face_vhandles.push_back(vhandle[1]);
37 face_vhandles.push_back(vhandle[3]);
38 mesh_.add_face(face_vhandles);
39
40 face_vhandles.clear();
41 face_vhandles.push_back(vhandle[1]);
42 face_vhandles.push_back(vhandle[2]);
43 face_vhandles.push_back(vhandle[3]);
44 mesh_.add_face(face_vhandles);
45
46 //=======================
47
48 face_vhandles.clear();
49 face_vhandles.push_back(vhandle[7]);
50 face_vhandles.push_back(vhandle[6]);
51 face_vhandles.push_back(vhandle[5]);
52 mesh_.add_face(face_vhandles);
53
54 face_vhandles.clear();
55 face_vhandles.push_back(vhandle[7]);
56 face_vhandles.push_back(vhandle[5]);
57 face_vhandles.push_back(vhandle[4]);
58 mesh_.add_face(face_vhandles);
59
60 //=======================
61
62 face_vhandles.clear();
63 face_vhandles.push_back(vhandle[1]);
64 face_vhandles.push_back(vhandle[0]);
65 face_vhandles.push_back(vhandle[4]);
66 mesh_.add_face(face_vhandles);
67
68 face_vhandles.clear();
69 face_vhandles.push_back(vhandle[1]);
70 face_vhandles.push_back(vhandle[4]);
71 face_vhandles.push_back(vhandle[5]);
72 mesh_.add_face(face_vhandles);
73
74 //=======================
75
76 face_vhandles.clear();
77 face_vhandles.push_back(vhandle[2]);
78 face_vhandles.push_back(vhandle[1]);
79 face_vhandles.push_back(vhandle[5]);
80 mesh_.add_face(face_vhandles);
81
82 face_vhandles.clear();
83 face_vhandles.push_back(vhandle[2]);
84 face_vhandles.push_back(vhandle[5]);
85 face_vhandles.push_back(vhandle[6]);
86 mesh_.add_face(face_vhandles);
87
88
89 //=======================
90
91 face_vhandles.clear();
92 face_vhandles.push_back(vhandle[3]);
93 face_vhandles.push_back(vhandle[2]);
94 face_vhandles.push_back(vhandle[6]);
95 mesh_.add_face(face_vhandles);
96
97 face_vhandles.clear();
98 face_vhandles.push_back(vhandle[3]);
99 face_vhandles.push_back(vhandle[6]);
100 face_vhandles.push_back(vhandle[7]);
101 mesh_.add_face(face_vhandles);
102
103 //=======================
104
105 face_vhandles.clear();
106 face_vhandles.push_back(vhandle[0]);
107 face_vhandles.push_back(vhandle[3]);
108 face_vhandles.push_back(vhandle[7]);
109 mesh_.add_face(face_vhandles);
110
111 face_vhandles.clear();
112 face_vhandles.push_back(vhandle[0]);
113 face_vhandles.push_back(vhandle[7]);
114 face_vhandles.push_back(vhandle[4]);
115 mesh_.add_face(face_vhandles);
116
117
118 // Test setup:
119 //
120 //
121 // 3 ======== 2
122 // / /|
123 // / / | z
124 // 0 ======== 1 | |
125 // | | | | y
126 // | 7 | 6 | /
127 // | | / | /
128 // | |/ |/
129 // 4 ======== 5 -------> x
130 //
131
132 // Check setup
133 EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
134 EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
135 EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
136 EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
137 }
138
139 // This function is called after all tests are through
140 virtual void TearDown() {
141
142 // Do some final stuff with the member data here...
143
144 mesh_.clear();
145 }
146
147 // Member already defined in OpenMeshBase
148 //Mesh mesh_;
149 };
150
151 /*
152 * ====================================================================
153 * Define tests below
154 * ====================================================================
155 */
156
157
158
159 /* Test if navigation operations on smart handles yield the expected element
160 */
161 TEST_F(OpenMeshSmartHandles, SimpleNavigation)
162 {
163 for (auto vh : mesh_.vertices())
164 {
165 EXPECT_EQ(mesh_.halfedge_handle(vh), vh.halfedge()) << "outgoing halfedge of vertex does not match";
166 }
167
168 for (auto heh : mesh_.halfedges())
169 {
170 EXPECT_EQ(mesh_.next_halfedge_handle(heh), heh.next()) << "next halfedge of halfedge does not match";
171 EXPECT_EQ(mesh_.prev_halfedge_handle(heh), heh.prev()) << "prevt halfedge of halfedge does not match";
172 EXPECT_EQ(mesh_.opposite_halfedge_handle(heh), heh.opp()) << "opposite halfedge of halfedge does not match";
173 EXPECT_EQ(mesh_.to_vertex_handle(heh), heh.to()) << "to vertex handle of halfedge does not match";
174 EXPECT_EQ(mesh_.from_vertex_handle(heh), heh.from()) << "from vertex handle of halfedge does not match";
175 EXPECT_EQ(mesh_.face_handle(heh), heh.face()) << "face handle of halfedge does not match";
176 }
177
178 for (auto eh : mesh_.edges())
179 {
180 EXPECT_EQ(mesh_.halfedge_handle(eh, 0), eh.h0()) << "halfedge 0 of edge does not match";
181 EXPECT_EQ(mesh_.halfedge_handle(eh, 1), eh.h1()) << "halfedge 1 of edge does not match";
182 EXPECT_EQ(mesh_.from_vertex_handle(mesh_.halfedge_handle(eh, 0)), eh.v0()) << "first vertex of edge does not match";
183 EXPECT_EQ(mesh_.to_vertex_handle (mesh_.halfedge_handle(eh, 0)), eh.v1()) << "second vertex of edge does not match";
184 }
185
186 for (auto fh : mesh_.faces())
187 {
188 EXPECT_EQ(mesh_.halfedge_handle(fh), fh.halfedge()) << "halfedge of face does not match";
189 }
190 }
191
192
193 /* Test if ranges yield the same elements when using smart handles
194 */
195 TEST_F(OpenMeshSmartHandles, SimpleRanges)
196 {
197 for (auto vh : mesh_.vertices())
198 {
199 {
200 std::vector<OpenMesh::VertexHandle> handles0;
201 std::vector<OpenMesh::VertexHandle> handles1;
202 for (auto h : mesh_.vv_range(vh))
203 handles0.push_back(h);
204 for (auto h : vh.vertices())
205 handles1.push_back(h);
206 EXPECT_EQ(handles0, handles1) << "vertex range of vertex does not match";
207 }
208 {
209 std::vector<OpenMesh::HalfedgeHandle> handles0;
210 std::vector<OpenMesh::HalfedgeHandle> handles1;
211 for (auto h : mesh_.voh_range(vh))
212 handles0.push_back(h);
213 for (auto h : vh.outgoing_halfedges())
214 handles1.push_back(h);
215 EXPECT_EQ(handles0, handles1) << "outgoing halfedge range of vertex does not match";
216 }
217 {
218 std::vector<OpenMesh::HalfedgeHandle> handles0;
219 std::vector<OpenMesh::HalfedgeHandle> handles1;
220 for (auto h : mesh_.vih_range(vh))
221 handles0.push_back(h);
222 for (auto h : vh.incoming_halfedges())
223 handles1.push_back(h);
224 EXPECT_EQ(handles0, handles1) << "incoming halfedge range of vertex does not match";
225 }
226 {
227 std::vector<OpenMesh::EdgeHandle> handles0;
228 std::vector<OpenMesh::EdgeHandle> handles1;
229 for (auto h : mesh_.ve_range(vh))
230 handles0.push_back(h);
231 for (auto h : vh.edges())
232 handles1.push_back(h);
233 EXPECT_EQ(handles0, handles1) << "edge range of vertex does not match";
234 }
235 {
236 std::vector<OpenMesh::FaceHandle> handles0;
237 std::vector<OpenMesh::FaceHandle> handles1;
238 for (auto h : mesh_.vf_range(vh))
239 handles0.push_back(h);
240 for (auto h : vh.faces())
241 handles1.push_back(h);
242 EXPECT_EQ(handles0, handles1) << "face range of vertex does not match";
243 }
244 }
245
246 for (auto fh : mesh_.faces())
247 {
248 {
249 std::vector<OpenMesh::VertexHandle> handles0;
250 std::vector<OpenMesh::VertexHandle> handles1;
251 for (auto h : mesh_.fv_range(fh))
252 handles0.push_back(h);
253 for (auto h : fh.vertices())
254 handles1.push_back(h);
255 EXPECT_EQ(handles0, handles1) << "vertex range of face does not match";
256 }
257 {
258 std::vector<OpenMesh::HalfedgeHandle> handles0;
259 std::vector<OpenMesh::HalfedgeHandle> handles1;
260 for (auto h : mesh_.fh_range(fh))
261 handles0.push_back(h);
262 for (auto h : fh.halfedges())
263 handles1.push_back(h);
264 EXPECT_EQ(handles0, handles1) << "halfedge range of face does not match";
265 }
266 {
267 std::vector<OpenMesh::EdgeHandle> handles0;
268 std::vector<OpenMesh::EdgeHandle> handles1;
269 for (auto h : mesh_.fe_range(fh))
270 handles0.push_back(h);
271 for (auto h : fh.edges())
272 handles1.push_back(h);
273 EXPECT_EQ(handles0, handles1) << "edge range of face does not match";
274 }
275 {
276 std::vector<OpenMesh::FaceHandle> handles0;
277 std::vector<OpenMesh::FaceHandle> handles1;
278 for (auto h : mesh_.ff_range(fh))
279 handles0.push_back(h);
280 for (auto h : fh.faces())
281 handles1.push_back(h);
282 EXPECT_EQ(handles0, handles1) << "face range of face does not match";
283 }
284 }
285 }
286
287 /* Test if ranges yield the same elements when using smart handles
288 */
289 TEST_F(OpenMeshSmartHandles, RangesOfRanges)
290 {
291 for (auto vh : mesh_.vertices())
292 {
293 {
294 std::vector<OpenMesh::VertexHandle> handles0;
295 std::vector<OpenMesh::VertexHandle> handles1;
296 for (auto h : mesh_.vv_range(vh))
297 for (auto h2 : mesh_.vv_range(h))
298 handles0.push_back(h2);
299 for (auto h : vh.vertices())
300 for (auto h2 : h.vertices())
301 handles1.push_back(h2);
302 EXPECT_EQ(handles0, handles1) << "vertex range of vertex range does not match";
303 }
304 {
305 std::vector<OpenMesh::HalfedgeHandle> handles0;
306 std::vector<OpenMesh::HalfedgeHandle> handles1;
307 for (auto h : mesh_.vv_range(vh))
308 for (auto h2 : mesh_.voh_range(h))
309 handles0.push_back(h2);
310 for (auto h : vh.vertices())
311 for (auto h2 : h.outgoing_halfedges())
312 handles1.push_back(h2);
313 EXPECT_EQ(handles0, handles1) << "outgoing halfedge range of vertex range does not match";
314 }
315 {
316 std::vector<OpenMesh::HalfedgeHandle> handles0;
317 std::vector<OpenMesh::HalfedgeHandle> handles1;
318 for (auto h : mesh_.vv_range(vh))
319 for (auto h2 : mesh_.vih_range(h))
320 handles0.push_back(h2);
321 for (auto h : vh.vertices())
322 for (auto h2 : h.incoming_halfedges())
323 handles1.push_back(h2);
324 EXPECT_EQ(handles0, handles1) << "incoming halfedge range of vertex range does not match";
325 }
326 {
327 std::vector<OpenMesh::EdgeHandle> handles0;
328 std::vector<OpenMesh::EdgeHandle> handles1;
329 for (auto h : mesh_.vv_range(vh))
330 for (auto h2 : mesh_.ve_range(h))
331 handles0.push_back(h2);
332 for (auto h : vh.vertices())
333 for (auto h2 : h.edges())
334 handles1.push_back(h2);
335 EXPECT_EQ(handles0, handles1) << "edge range of vertex range does not match";
336 }
337 {
338 std::vector<OpenMesh::FaceHandle> handles0;
339 std::vector<OpenMesh::FaceHandle> handles1;
340 for (auto h : mesh_.vv_range(vh))
341 for (auto h2 : mesh_.vf_range(h))
342 handles0.push_back(h2);
343 for (auto h : vh.vertices())
344 for (auto h2 : h.faces())
345 handles1.push_back(h2);
346 EXPECT_EQ(handles0, handles1) << "face range of vertex range does not match";
347 }
348 {
349 std::vector<OpenMesh::VertexHandle> handles0;
350 std::vector<OpenMesh::VertexHandle> handles1;
351 for (auto h : mesh_.vf_range(vh))
352 for (auto h2 : mesh_.fv_range(h))
353 handles0.push_back(h2);
354 for (auto h : vh.faces())
355 for (auto h2 : h.vertices())
356 handles1.push_back(h2);
357 EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
358 }
359 {
360 std::vector<OpenMesh::HalfedgeHandle> handles0;
361 std::vector<OpenMesh::HalfedgeHandle> handles1;
362 for (auto h : mesh_.vf_range(vh))
363 for (auto h2 : mesh_.fh_range(h))
364 handles0.push_back(h2);
365 for (auto h : vh.faces())
366 for (auto h2 : h.halfedges())
367 handles1.push_back(h2);
368 EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
369 }
370 {
371 std::vector<OpenMesh::FaceHandle> handles0;
372 std::vector<OpenMesh::FaceHandle> handles1;
373 for (auto h : mesh_.vf_range(vh))
374 for (auto h2 : mesh_.ff_range(h))
375 handles0.push_back(h2);
376 for (auto h : vh.faces())
377 for (auto h2 : h.faces())
378 handles1.push_back(h2);
379 EXPECT_EQ(handles0, handles1) << "vertex range of face range does not match";
380 }
381 }
382 }
383
384
385 /* Test a chain of navigation on a cube
386 */
387 TEST_F(OpenMeshSmartHandles, ComplicatedNavigtaion)
388 {
389 for (auto vh : mesh_.vertices())
390 {
391 EXPECT_EQ(mesh_.next_halfedge_handle(
392 mesh_.opposite_halfedge_handle(
393 mesh_.halfedge_handle(vh))),
394 vh.out().opp().next());
395 EXPECT_EQ(mesh_.prev_halfedge_handle(
396 mesh_.prev_halfedge_handle(
397 mesh_.opposite_halfedge_handle(
398 mesh_.next_halfedge_handle(
399 mesh_.next_halfedge_handle(
400 mesh_.halfedge_handle(vh)))))),
401 vh.out().next().next().opp().prev().prev());
402 EXPECT_EQ(mesh_.face_handle(
403 mesh_.opposite_halfedge_handle(
404 mesh_.halfedge_handle(
405 mesh_.face_handle(
406 mesh_.opposite_halfedge_handle(
407 mesh_.next_halfedge_handle(
408 mesh_.halfedge_handle(vh))))))),
409 vh.out().next().opp().face().halfedge().opp().face());
410 }
411 }
412
413
414 /* Test performance of smart handles
415 */
416 TEST_F(OpenMeshSmartHandles, Performance)
417 {
418 #if DEBUG
419 int n_tests = 300000;
420 #else
421 int n_tests = 10000000;
422 #endif
423
424 auto t_before_old = std::chrono::high_resolution_clock::now();
425
426 std::vector<OpenMesh::HalfedgeHandle> halfedges0;
427 for (int i = 0; i < n_tests; ++i)
428 {
429 for (auto vh : mesh_.vertices())
430 {
431 auto heh = mesh_.prev_halfedge_handle(
432 mesh_.prev_halfedge_handle(
433 mesh_.opposite_halfedge_handle(
434 mesh_.next_halfedge_handle(
435 mesh_.next_halfedge_handle(
436 mesh_.halfedge_handle(vh))))));
437 if (i == 0)
438 halfedges0.push_back(heh);
439 }
440 }
441
442 auto t_after_old = std::chrono::high_resolution_clock::now();
443
444 std::vector<OpenMesh::HalfedgeHandle> halfedges1;
445 for (int i = 0; i < n_tests; ++i)
446 {
447 for (auto vh : mesh_.vertices())
448 {
449 auto heh = vh.out().next().next().opp().prev().prev();
450 if (i == 0)
451 halfedges1.push_back(heh);
452 }
453 }
454
455 auto t_after_new = std::chrono::high_resolution_clock::now();
456
457 std::cout << "Conventional navigation took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_after_old-t_before_old).count() << "ms" << std::endl;
458 std::cout << "SmartHandle navigation took " << std::chrono::duration_cast<std::chrono::milliseconds>(t_after_new-t_after_old ).count() << "ms" << std::endl;
459
460 EXPECT_EQ(halfedges0, halfedges1) << "halfedges do not match";
461
462 }
463
464
465 /* Mix old and new api
466 */
467 TEST_F(OpenMeshSmartHandles, MixOldAndNew)
468 {
469 for (OpenMesh::SmartHalfedgeHandle heh : mesh_.halfedges())
470 {
471 heh = mesh_.opposite_halfedge_handle(heh);
472 EXPECT_TRUE((std::is_same<OpenMesh::SmartEdgeHandle, decltype(OpenMesh::PolyConnectivity::s_edge_handle(heh))>::value));
473 EXPECT_TRUE((std::is_same<OpenMesh::SmartEdgeHandle, decltype(mesh_.edge_handle(heh))>::value));
474 EXPECT_TRUE((std::is_same<OpenMesh::SmartFaceHandle, decltype(mesh_.face_handle(heh))>::value));
475 }
476 }
477
478
479
480 /* comparability
481 */
482 TEST_F(OpenMeshSmartHandles, ComparisionBetweenSmartHandleAndNormalHandles)
483 {
484 OpenMesh::VertexHandle vh(0);
485 OpenMesh::SmartVertexHandle svh(0, &mesh_);
486 EXPECT_EQ(vh, svh) << "Vertex handle and smart vertex handle are different";
487
488 std::vector<OpenMesh::VertexHandle> vertices = mesh_.vertices().to_vector([](OpenMesh::SmartVertexHandle _svh) { return OpenMesh::VertexHandle(_svh); });
489
490 std::replace(vertices.begin(), vertices.end(), OpenMesh::VertexHandle(0), OpenMesh::VertexHandle(1));
491 EXPECT_EQ(vertices[0], OpenMesh::VertexHandle(1));
492
493 std::vector<OpenMesh::SmartVertexHandle> smart_vertices = mesh_.vertices().to_vector();
494
495 std::replace(smart_vertices.begin(), smart_vertices.end(), OpenMesh::SmartVertexHandle(0, &mesh_), OpenMesh::SmartVertexHandle(1, &mesh_));
496 EXPECT_EQ(smart_vertices[0], OpenMesh::VertexHandle(1));
497 EXPECT_EQ(smart_vertices[0], OpenMesh::SmartVertexHandle(1, &mesh_));
498
499 std::replace(vertices.begin(), vertices.end(), OpenMesh::SmartVertexHandle(1, &mesh_), OpenMesh::SmartVertexHandle(2, &mesh_));
500 EXPECT_EQ(vertices[0], OpenMesh::VertexHandle(2));
501
502 }
503
504 TEST(OpenMeshSmartHandlesNoFixture, AddingFacesPolyMesh)
505 {
506 using MyMesh = OpenMesh::PolyMesh_ArrayKernelT<>;
507
508 MyMesh mesh;
509
510 std::vector<OpenMesh::SmartVertexHandle> vertices;
511 for (int i = 0; i < 4; ++i)
512 vertices.push_back(mesh.add_vertex(MyMesh::Point()));
513
514 auto fh = mesh.add_face(vertices);
515
516 for (auto heh : fh.halfedges())
517 {
518 heh = heh.next();
519 }
520 }
521
522 TEST(OpenMeshSmartHandlesNoFixture, AddingFacesTriMesh)
523 {
524 using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
525
526 MyMesh mesh;
527
528 std::vector<OpenMesh::SmartVertexHandle> vertices;
529 for (int i = 0; i < 4; ++i)
530 vertices.push_back(mesh.add_vertex(MyMesh::Point()));
531
532 auto fh = mesh.add_face(vertices);
533
534 for (auto heh : fh.halfedges())
535 {
536 heh = heh.next();
537 }
538 }
539
540 TEST(OpenMeshSmartHandlesNoFixture, SplitTriMesh)
541 {
542 using MyMesh = OpenMesh::TriMesh_ArrayKernelT<>;
543
544 MyMesh mesh;
545
546 std::vector<OpenMesh::SmartVertexHandle> vertices;
547 for (int i = 0; i < 3; ++i)
548 vertices.push_back(mesh.add_vertex(MyMesh::Point()));
549
550 auto fh = mesh.add_face(vertices);
551
552 auto p = (MyMesh::Point());
553
554 OpenMesh::SmartVertexHandle vh = mesh.split(fh, p);
555 OpenMesh::SmartEdgeHandle eh = fh.halfedge().edge();
556 OpenMesh::SmartVertexHandle vh2 = mesh.split(eh, p);
557
558 EXPECT_NE(vh.idx(), vh2.idx()) << "This was only intended to fix an unused variable warning but cool that it caugth an actual error now";
559
560 }
561
562
563
564
565
566 }
OpenMesh::SmartHalfedgeHandle
Definition: SmartHandles.hh:114
OpenMesh::SmartEdgeHandle
Definition: SmartHandles.hh:137
OpenMesh::SmartHalfedgeHandle::edge
SmartEdgeHandle edge() const
Returns incident edge of halfedge.
Definition: SmartHandles.hh:278
OpenMesh::BaseHandle::idx
int idx() const
Get the underlying index of this handle.
Definition: Handles.hh:69
OpenMesh::PolyMeshT::Point
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
OpenMesh::TriMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:73
OpenMesh::SmartEdgeHandle::halfedge
SmartHalfedgeHandle halfedge(unsigned int _i) const
Returns one of the two halfedges of the edge.
Definition: SmartHandles.hh:296
OpenMesh::VertexHandle
Handle for a vertex entity.
Definition: Handles.hh:120
OpenMesh::PolyMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:94
OpenMesh::PolyMeshT::add_vertex
SmartVertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
Definition: PolyMeshT.hh:235
OpenMesh::TriMeshT::split
SmartVertexHandle split(EdgeHandle _eh, const Point &_p)
Edge split (= 2-to-4 split)
Definition: TriMeshT.hh:267
OpenMesh::SmartFaceHandle
Definition: SmartHandles.hh:162
OpenMeshBase
Definition: unittests_common.hh:29
OpenMesh::SmartVertexHandle
Smart version of VertexHandle contains a pointer to the corresponding mesh and allows easier access t...
Definition: SmartHandles.hh:84
OpenMesh::PolyMeshT::VertexHandle
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136