Developer Documentation

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
unittests_tutorials.cc
1
2 #include <gtest/gtest.h>
3 #include <Unittests/unittests_common.hh>
4 #include <string>
5 #include <map>
6 #include "generate_cube.hh"
7 #include "fill_props.hh"
8
9 /*
10 * ====================================================================
11 * Definition of custom properties related classes
12 * ====================================================================
13 */
14
15 struct MyData
16 {
17 int ival;
18 double dval;
19 bool bval;
20 OpenMesh::Vec4f vec4fval;
21
22 MyData()
23 : ival(0), dval(0.0), bval(false)
24 { }
25
26 MyData( const MyData& _cpy )
27 : ival(_cpy.ival), dval(_cpy.dval), bval(_cpy.bval),
28 vec4fval(_cpy.vec4fval)
29 { }
30
31 // ---------- assignment
32
33 MyData& operator = (const MyData& _rhs)
34 {
35 ival = _rhs.ival;
36 dval = _rhs.dval;
37 bval = _rhs.bval;
38 vec4fval = _rhs.vec4fval;
39 return *this;
40 }
41
42 MyData& operator = (int _rhs) { ival = _rhs; return *this; }
43 MyData& operator = (double _rhs) { dval = _rhs; return *this; }
44 MyData& operator = (bool _rhs) { bval = _rhs; return *this; }
45 MyData& operator = (const OpenMesh::Vec4f& _rhs)
46 { vec4fval = _rhs; return *this; }
47
48 // ---------- comparison
49
50 bool operator == (const MyData& _rhs) const
51 {
52 return ival == _rhs.ival
53 && dval == _rhs.dval
54 && bval == _rhs.bval
55 && vec4fval == _rhs.vec4fval;
56 }
57 bool operator != (const MyData& _rhs) const { return !(*this == _rhs); }
58 };
59
60 typedef std::map< std::string, unsigned int > MyMap;
61
62 namespace OpenMesh {
63 namespace IO {
64 // support persistence for struct MyData
65 template <> struct binary<MyData>
66 {
67 typedef MyData value_type;
68 static const bool is_streamable = true;
69
70 // return binary size of the value
71 static size_t size_of(void)
72 {
73 return sizeof(int)+sizeof(double)+sizeof(bool)+sizeof(OpenMesh::Vec4f);
74 }
75
76 static size_t size_of(const value_type&)
77 {
78 return size_of();
79 }
80
81 static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
82 {
83 size_t bytes;
84 bytes = IO::store( _os, _v.ival, _swap );
85 bytes += IO::store( _os, _v.dval, _swap );
86 bytes += IO::store( _os, _v.bval, _swap );
87 bytes += IO::store( _os, _v.vec4fval, _swap );
88 return _os.good() ? bytes : 0;
89 }
90
91 static size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
92 {
93 size_t bytes;
94 bytes = IO::restore( _is, _v.ival, _swap );
95 bytes += IO::restore( _is, _v.dval, _swap );
96 bytes += IO::restore( _is, _v.bval, _swap );
97 bytes += IO::restore( _is, _v.vec4fval, _swap );
98 return _is.good() ? bytes : 0;
99 }
100 };
101
102 template <> struct binary< MyMap >
103 {
104 typedef MyMap value_type;
105 static const bool is_streamable = true;
106
107 // return generic binary size of self, if known
108 static size_t size_of(void) { return UnknownSize; }
109
110 // return binary size of the value
111 static size_t size_of(const value_type& _v)
112 {
113 if (_v.empty())
114 return sizeof(unsigned int);
115
116 value_type::const_iterator it = _v.begin();
117 unsigned int N = _v.size();
118 size_t bytes = IO::size_of(N);
119 for(;it!=_v.end(); ++it)
120 {
121 bytes += IO::size_of( it->first );
122 bytes += IO::size_of( it->second );
123 }
124 return bytes;
125 }
126
127 static
128 size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
129 {
130 size_t bytes = 0;
131 unsigned int N = _v.size();
132 value_type::const_iterator it = _v.begin();
133 bytes += IO::store( _os, N, _swap );
134 for (; it != _v.end() && _os.good(); ++it)
135 {
136 bytes += IO::store( _os, it->first, _swap );
137 bytes += IO::store( _os, it->second, _swap );
138 }
139 return _os.good() ? bytes : 0;
140 }
141
142 static
143 size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
144 {
145 size_t bytes = 0;
146 unsigned int N = 0;
147 _v.clear();
148 bytes += IO::restore( _is, N, _swap );
149 value_type::key_type key;
150 value_type::mapped_type val;
151 for (size_t i=0; i<N && _is.good(); ++i)
152 {
153 bytes += IO::restore( _is, key, _swap );
154 bytes += IO::restore( _is, val, _swap );
155 _v[key] = val;
156 }
157 return _is.good() ? bytes : 0;
158 }
159 };
160
161 }
162 }
163
164 namespace {
165
166 class OpenMeshTutorials: public OpenMeshBase {
167
168 protected:
169
170 // This function is called before each test is run
171 virtual void SetUp() {
172
173 // Do some initial stuff with the member data here...
174 }
175
176 // This function is called after all tests are through
177 virtual void TearDown() {
178
179 // Do some final stuff with the member data here...
180 }
181
182 // Member already defined in OpenMeshBase
183 //Mesh mesh_;
184 };
185
186 /*
187 * ====================================================================
188 * Classes for unittests
189 * ====================================================================
190 */
191
192 template <class Mesh> class SmootherT
193 {
194 public:
195 typedef typename Mesh::Point cog_t;
196 typedef OpenMesh::VPropHandleT< cog_t > Property_cog;
197
198 public:
199 // construct with a given mesh
200 SmootherT(Mesh& _mesh)
201 : mesh_(_mesh)
202 {
203 mesh_.add_property( cog_ );
204 }
205 ~SmootherT()
206 {
207 mesh_.remove_property( cog_ );
208 }
209 // smooth mesh _iterations times
210 void smooth(unsigned int _iterations)
211 {
212 for (unsigned int i=0; i < _iterations; ++i)
213 {
214 std::for_each(mesh_.vertices_begin(),
215 mesh_.vertices_end(),
216 ComputeCOG(mesh_, cog_));
217 std::for_each(mesh_.vertices_begin(),
218 mesh_.vertices_end(),
219 SetCOG(mesh_, cog_));
220 }
221 }
222
223 private:
224 //--- private classes ---
225 class ComputeCOG
226 {
227 public:
228 ComputeCOG(Mesh& _mesh, Property_cog& _cog)
229 : mesh_(_mesh), cog_(_cog)
230 {}
231 void operator()(const typename Mesh::VertexHandle& _vh)
232 {
233 typename Mesh::VertexVertexIter vv_it;
234 typename Mesh::Scalar valence(0.0);
235
236 mesh_.property(cog_, _vh) = typename Mesh::Point(0.0, 0.0, 0.0);
237 for (vv_it=mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it)
238 {
239 mesh_.property(cog_, _vh) += mesh_.point( *vv_it );
240 ++valence;
241 }
242 mesh_.property(cog_, _vh ) /= valence;
243 }
244 private:
245 Mesh& mesh_;
246 Property_cog& cog_;
247 };
248
249 class SetCOG
250 {
251 public:
252 SetCOG(Mesh& _mesh, Property_cog& _cog)
253 : mesh_(_mesh), cog_(_cog)
254 {}
255 void operator()(const typename Mesh::VertexHandle& _vh)
256 {
257 if (!mesh_.is_boundary(_vh))
258 mesh_.set_point( _vh, mesh_.property(cog_, _vh) );
259 }
260 private:
261 Mesh& mesh_;
262 Property_cog& cog_;
263 };
264
265 //--- private elements ---
266 Mesh& mesh_;
267 Property_cog cog_;
268 };
269
270
271 /*
272 * ====================================================================
273 * Specify our traits
274 * ====================================================================
275 */
276
277 struct MyTraits : public OpenMesh::DefaultTraits
278 {
279 HalfedgeAttributes(OpenMesh::Attributes::PrevHalfedge);
280 };
281
282 // Define my personal fancy traits
283 struct MyFancyTraits : OpenMesh::DefaultTraits
284 {
285 // Let Point and Normal be a vector of doubles
286 typedef OpenMesh::Vec3d Point;
287 typedef OpenMesh::Vec3d Normal;
288 // Already defined in OpenMesh::DefaultTraits
289 // HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );
290
291 // Uncomment next line to disable attribute PrevHalfedge
292 // HalfedgeAttributes( OpenMesh::Attributes::None );
293 //
294 // or
295 //
296 // HalfedgeAttributes( 0 );
297 };
298
299 struct MyTraitsWithCOG : public OpenMesh::DefaultTraits
300 {
301 // store barycenter of neighbors in this member
302 VertexTraits
303 {
304 private:
305 Point cog_;
306 public:
307 VertexT() : cog_( Point(0.0f, 0.0f, 0.0f ) ) { }
308 const Point& cog() const { return cog_; }
309 void set_cog(const Point& _p) { cog_ = _p; }
310 };
311 };
312
313 struct MyTraitsWithStatus : public OpenMesh::DefaultTraits
314 {
315 VertexAttributes(OpenMesh::Attributes::Status);
316 FaceAttributes(OpenMesh::Attributes::Status);
317 EdgeAttributes(OpenMesh::Attributes::Status);
318 };
319
320 /*
321 * ====================================================================
322 * Specify our meshes
323 * ====================================================================
324 */
325 typedef OpenMesh::PolyMesh_ArrayKernelT<> MyMesh;
326 typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> MyMeshWithTraits;
327 typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> MyTriMesh;
328 typedef OpenMesh::TriMesh_ArrayKernelT<MyFancyTraits> MyFancyTriMesh;
329 typedef OpenMesh::TriMesh_ArrayKernelT<MyTraitsWithCOG> MyTriMeshWithCOG;
330 typedef OpenMesh::PolyMesh_ArrayKernelT<MyTraitsWithStatus> MyMeshWithStatus;
331
332 /*
333 * ====================================================================
334 * Define tests below
335 * ====================================================================
336 */
337
338 /*
339 */
340 TEST_F(OpenMeshTutorials, building_a_cube) {
341
342 MyMesh mesh;
343
344 // generate vertices
345 MyMesh::VertexHandle vhandle[8];
346 vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1));
347 vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1));
348 vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1));
349 vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1));
350 vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1));
351 vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1));
352 vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1));
353 vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1));
354
355 // generate (quadrilateral) faces
356 std::vector<MyMesh::VertexHandle> face_vhandles;
357 face_vhandles.clear();
358 face_vhandles.push_back(vhandle[0]);
359 face_vhandles.push_back(vhandle[1]);
360 face_vhandles.push_back(vhandle[2]);
361 face_vhandles.push_back(vhandle[3]);
362 mesh.add_face(face_vhandles);
363
364 face_vhandles.clear();
365 face_vhandles.push_back(vhandle[7]);
366 face_vhandles.push_back(vhandle[6]);
367 face_vhandles.push_back(vhandle[5]);
368 face_vhandles.push_back(vhandle[4]);
369 mesh.add_face(face_vhandles);
370 face_vhandles.clear();
371 face_vhandles.push_back(vhandle[1]);
372 face_vhandles.push_back(vhandle[0]);
373 face_vhandles.push_back(vhandle[4]);
374 face_vhandles.push_back(vhandle[5]);
375 mesh.add_face(face_vhandles);
376 face_vhandles.clear();
377 face_vhandles.push_back(vhandle[2]);
378 face_vhandles.push_back(vhandle[1]);
379 face_vhandles.push_back(vhandle[5]);
380 face_vhandles.push_back(vhandle[6]);
381 mesh.add_face(face_vhandles);
382 face_vhandles.clear();
383 face_vhandles.push_back(vhandle[3]);
384 face_vhandles.push_back(vhandle[2]);
385 face_vhandles.push_back(vhandle[6]);
386 face_vhandles.push_back(vhandle[7]);
387 mesh.add_face(face_vhandles);
388 face_vhandles.clear();
389 face_vhandles.push_back(vhandle[0]);
390 face_vhandles.push_back(vhandle[3]);
391 face_vhandles.push_back(vhandle[7]);
392 face_vhandles.push_back(vhandle[4]);
393 mesh.add_face(face_vhandles);
394
395 bool ok = OpenMesh::IO::write_mesh(mesh, "output.off");
396
397 EXPECT_TRUE(ok) << "Cannot write mesh to file 'output.off'";
398 }
399
400 TEST_F(OpenMeshTutorials, using_iterators_and_circulators) {
401 MyMesh mesh;
402
403 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
404
405 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
406
407 // this vector stores the computed centers of gravity
408 std::vector<MyMesh::Point> cogs;
409 std::vector<MyMesh::Point>::iterator cog_it;
410 cogs.reserve(mesh.n_vertices());
411
412 // smoothing mesh N times
413 MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
414 MyMesh::VertexVertexIter vv_it;
415 MyMesh::Point cog;
416 MyMesh::Scalar valence;
417 unsigned int i, N(100);
418 for (i=0; i < N; ++i)
419 {
420 cogs.clear();
421 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
422 {
423 cog[0] = cog[1] = cog[2] = valence = 0.0;
424
425 for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
426 {
427 cog += mesh.point( *vv_it );
428 ++valence;
429 }
430 cogs.push_back(cog / valence);
431 }
432
433 for (v_it = mesh.vertices_begin(), cog_it = cogs.begin();
434 v_it != v_end; ++v_it, ++cog_it)
435 if ( !mesh.is_boundary( *v_it ) )
436 mesh.set_point( *v_it, *cog_it );
437 }
438
439 // write mesh
440 ok = OpenMesh::IO::write_mesh(mesh, "smoothed_output.off");
441
442 EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_output.off'";
443 }
444
445 TEST_F(OpenMeshTutorials, using_custom_properties) {
446 MyMesh mesh;
447
448 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
449 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
450
451 // this vertex property stores the computed centers of gravity
452 OpenMesh::VPropHandleT<MyMesh::Point> cogs;
453 mesh.add_property(cogs);
454
455 // smoothing mesh N times
456 MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
457 MyMesh::VertexVertexIter vv_it;
458 MyMesh::Point cog;
459 MyMesh::Scalar valence;
460 unsigned int i, N(100);
461
462 for (i=0; i < N; ++i)
463 {
464 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
465 {
466 mesh.property(cogs,*v_it).vectorize(0.0f);
467 valence = 0.0;
468
469 for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
470 {
471 mesh.property(cogs,*v_it) += mesh.point( *vv_it );
472 ++valence;
473 }
474 mesh.property(cogs,*v_it) /= valence;
475 }
476
477 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
478 if ( !mesh.is_boundary( *v_it ) )
479 mesh.set_point( *v_it, mesh.property(cogs,*v_it) );
480 }
481
482 // write mesh
483 ok = OpenMesh::IO::write_mesh(mesh, "smoothed_custom_properties_output.off");
484
485 EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_custom_properties_output.off'";
486 }
487
488 TEST_F(OpenMeshTutorials, using_STL_algorithms) {
489 MyMeshWithTraits mesh;
490
491 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
492 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
493
494 SmootherT<MyMeshWithTraits> smoother(mesh);
495 smoother.smooth(100);
496
497 // write mesh
498 ok = OpenMesh::IO::write_mesh(mesh, "smoothed_STL_output.off");
499
500 EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_STL_output.off'";
501 }
502
503 TEST_F(OpenMeshTutorials, using_standard_properties) {
504 MyTriMesh mesh;
505
506 mesh.request_vertex_normals();
507 EXPECT_TRUE(mesh.has_vertex_normals()) << "Standard vertex property 'Normals' not available";
508
509 OpenMesh::IO::Options opt;
510 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off", opt);
511 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
512
513 // If the file did not provide vertex normals, then calculate them
514 if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) )
515 {
516 // we need face normals to update the vertex normals
517 mesh.request_face_normals();
518 // let the mesh update the normals
519 mesh.update_normals();
520 // dispose the face normals, as we don't need them anymore
521 mesh.release_face_normals();
522 }
523
524 // move all vertices one unit length along it's normal direction
525 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
526 v_it != mesh.vertices_end(); ++v_it)
527 {
528 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
529 }
530
531 // don't need the normals anymore? Remove them!
532 mesh.release_vertex_normals();
533 // just check if it really works
534 EXPECT_FALSE(mesh.has_vertex_normals()) << "Shouldn't have any vertex normals anymore";
535 }
536
537 TEST_F(OpenMeshTutorials, using_mesh_attributes_and_traits) {
538 MyFancyTriMesh mesh;
539
540 // Just make sure that point element type is double
541 EXPECT_TRUE(typeid( OpenMesh::vector_traits<MyFancyTriMesh::Point>::value_type ) ==
542 typeid(double)) << "Data type is wrong";
543
544 // Make sure that normal element type is double
545 EXPECT_TRUE(typeid( OpenMesh::vector_traits<MyFancyTriMesh::Normal>::value_type ) ==
546 typeid(double)) << "Data type is wrong";
547
548 // Add vertex normals as default property (ref. previous tutorial)
549 mesh.request_vertex_normals();
550 // Add face normals as default property
551 mesh.request_face_normals();
552
553 // load a mesh
554 OpenMesh::IO::Options opt;
555 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off", opt);
556 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
557
558 // If the file did not provide vertex normals, then calculate them
559 if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) &&
560 mesh.has_face_normals() && mesh.has_vertex_normals() )
561 {
562 // let the mesh update the normals
563 mesh.update_normals();
564 }
565
566 // move all vertices one unit length along it's normal direction
567 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
568 v_it != mesh.vertices_end(); ++v_it)
569 {
570 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
571 }
572 }
573
574 TEST_F(OpenMeshTutorials, extending_the_mesh_using_traits) {
575 MyTriMeshWithCOG mesh;
576
577 bool ok = OpenMesh::IO::read_mesh(mesh, "output.off");
578 EXPECT_TRUE(ok) << "Cannot read mesh from file 'output.off'";
579
580 // smoothing mesh N times
581 MyTriMeshWithCOG::VertexIter v_it, v_end(mesh.vertices_end());
582 MyTriMeshWithCOG::VertexVertexIter vv_it;
583 MyTriMeshWithCOG::Point cog;
584 MyTriMeshWithCOG::Scalar valence;
585 unsigned int i, N(100);
586
587 for (i=0; i < N; ++i)
588 {
589 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
590 {
591 cog[0] = cog[1] = cog[2] = valence = 0.0;
592
593 for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
594 {
595 cog += mesh.point( *vv_it );
596 ++valence;
597 }
598 mesh.data(*v_it).set_cog(cog / valence);
599 }
600
601 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
602 if (!mesh.is_boundary(*v_it))
603 mesh.set_point( *v_it, mesh.data(*v_it).cog());
604 }
605
606 // write mesh
607 ok = OpenMesh::IO::write_mesh(mesh, "smoothed_extended_output.off");
608
609 EXPECT_TRUE(ok) << "Cannot write mesh to file 'smoothed_extended_output.off'";
610 }
611
612
613 TEST_F(OpenMeshTutorials, deleting_geometry_elements) {
614 Mesh mesh;
615
616 // the request has to be called before a vertex/face/edge can be deleted. it grants access to the status attribute
617 mesh.request_face_status();
618 mesh.request_edge_status();
619 mesh.request_vertex_status();
620
621 // generate vertices
622 MyMeshWithStatus::VertexHandle vhandle[8];
623 MyMeshWithStatus::FaceHandle fhandle[6];
624
625 vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, -1, 1));
626 vhandle[1] = mesh.add_vertex(MyMesh::Point( 1, -1, 1));
627 vhandle[2] = mesh.add_vertex(MyMesh::Point( 1, 1, 1));
628 vhandle[3] = mesh.add_vertex(MyMesh::Point(-1, 1, 1));
629 vhandle[4] = mesh.add_vertex(MyMesh::Point(-1, -1, -1));
630 vhandle[5] = mesh.add_vertex(MyMesh::Point( 1, -1, -1));
631 vhandle[6] = mesh.add_vertex(MyMesh::Point( 1, 1, -1));
632 vhandle[7] = mesh.add_vertex(MyMesh::Point(-1, 1, -1));
633
634 // generate (quadrilateral) faces
635 std::vector<MyMesh::VertexHandle> tmp_face_vhandles;
636 tmp_face_vhandles.clear();
637 tmp_face_vhandles.push_back(vhandle[0]);
638 tmp_face_vhandles.push_back(vhandle[1]);
639 tmp_face_vhandles.push_back(vhandle[2]);
640 tmp_face_vhandles.push_back(vhandle[3]);
641 fhandle[0] = mesh.add_face(tmp_face_vhandles);
642
643 tmp_face_vhandles.clear();
644 tmp_face_vhandles.push_back(vhandle[7]);
645 tmp_face_vhandles.push_back(vhandle[6]);
646 tmp_face_vhandles.push_back(vhandle[5]);
647 tmp_face_vhandles.push_back(vhandle[4]);
648 fhandle[1] = mesh.add_face(tmp_face_vhandles);
649
650 tmp_face_vhandles.clear();
651 tmp_face_vhandles.push_back(vhandle[1]);
652 tmp_face_vhandles.push_back(vhandle[0]);
653 tmp_face_vhandles.push_back(vhandle[4]);
654 tmp_face_vhandles.push_back(vhandle[5]);
655 fhandle[2] = mesh.add_face(tmp_face_vhandles);
656
657 tmp_face_vhandles.clear();
658 tmp_face_vhandles.push_back(vhandle[2]);
659 tmp_face_vhandles.push_back(vhandle[1]);
660 tmp_face_vhandles.push_back(vhandle[5]);
661 tmp_face_vhandles.push_back(vhandle[6]);
662 fhandle[3] = mesh.add_face(tmp_face_vhandles);
663 tmp_face_vhandles.clear();
664 tmp_face_vhandles.push_back(vhandle[3]);
665 tmp_face_vhandles.push_back(vhandle[2]);
666 tmp_face_vhandles.push_back(vhandle[6]);
667 tmp_face_vhandles.push_back(vhandle[7]);
668 fhandle[4] = mesh.add_face(tmp_face_vhandles);
669
670 tmp_face_vhandles.clear();
671 tmp_face_vhandles.push_back(vhandle[0]);
672 tmp_face_vhandles.push_back(vhandle[3]);
673 tmp_face_vhandles.push_back(vhandle[7]);
674 tmp_face_vhandles.push_back(vhandle[4]);
675 fhandle[5] = mesh.add_face(tmp_face_vhandles);
676
677 // And now delete all faces and vertices
678 // except face (vh[7], vh[6], vh[5], vh[4])
679 // whose handle resides in fhandle[1]
680
681 EXPECT_FALSE(mesh.status(fhandle[0]).deleted()) << "face shouldn't be deleted";
682 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) << "face shouldn't be deleted";
683 EXPECT_FALSE(mesh.status(fhandle[2]).deleted()) << "face shouldn't be deleted";
684 EXPECT_FALSE(mesh.status(fhandle[3]).deleted()) << "face shouldn't be deleted";
685 EXPECT_FALSE(mesh.status(fhandle[4]).deleted()) << "face shouldn't be deleted";
686 EXPECT_FALSE(mesh.status(fhandle[5]).deleted()) << "face shouldn't be deleted";
687
688 // Delete face 0
689 mesh.delete_face(fhandle[0], false);
690 // ... face 2
691 mesh.delete_face(fhandle[2], false);
692 // ... face 3
693 mesh.delete_face(fhandle[3], false);
694 // ... face 4
695 mesh.delete_face(fhandle[4], false);
696 // ... face 5
697 mesh.delete_face(fhandle[5], false);
698
699 EXPECT_TRUE(mesh.status(fhandle[0]).deleted()) << "face should be deleted";
700 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) << "face shouldn't be deleted";
701 EXPECT_TRUE(mesh.status(fhandle[2]).deleted()) << "face should be deleted";
702 EXPECT_TRUE(mesh.status(fhandle[3]).deleted()) << "face should be deleted";
703 EXPECT_TRUE(mesh.status(fhandle[4]).deleted()) << "face should be deleted";
704 EXPECT_TRUE(mesh.status(fhandle[5]).deleted()) << "face should be deleted";
705
706 // If isolated vertices result in a face deletion
707 // they have to be deleted manually. If you want this
708 // to happen automatically, change the second parameter
709 // to true.
710 // Now delete the isolated vertices 0, 1, 2 and 3
711
712 EXPECT_FALSE(mesh.status(vhandle[0]).deleted()) << "vertex shouldn't be deleted";
713 EXPECT_FALSE(mesh.status(vhandle[1]).deleted()) << "vertex shouldn't be deleted";
714 EXPECT_FALSE(mesh.status(vhandle[2]).deleted()) << "vertex shouldn't be deleted";
715 EXPECT_FALSE(mesh.status(vhandle[3]).deleted()) << "vertex shouldn't be deleted";
716
717
718 mesh.delete_vertex(vhandle[0], false);
719 mesh.delete_vertex(vhandle[1], false);
720 mesh.delete_vertex(vhandle[2], false);
721 mesh.delete_vertex(vhandle[3], false);
722
723
724 EXPECT_TRUE(mesh.status(vhandle[0]).deleted()) << "vertex should be deleted";
725 EXPECT_TRUE(mesh.status(vhandle[1]).deleted()) << "vertex should be deleted";
726 EXPECT_TRUE(mesh.status(vhandle[2]).deleted()) << "vertex should be deleted";
727 EXPECT_TRUE(mesh.status(vhandle[3]).deleted()) << "vertex should be deleted";
728
729 // Delete all elements that are marked as deleted
730 // from memory.
731 mesh.garbage_collection();
732
733 // write mesh
734 bool ok = OpenMesh::IO::write_mesh(mesh, "deleted_output.off");
735
736 EXPECT_TRUE(ok) << "Cannot write mesh to file 'deleted_output.off'";
737 }
738
739
740 TEST_F(OpenMeshTutorials, storing_custom_properties) {
741 MyMesh mesh;
742
743 // generate a geometry
744 generate_cube<MyMesh>(mesh);
745
746 // define some custom properties
747 OpenMesh::VPropHandleT<float> vprop_float;
748 OpenMesh::EPropHandleT<bool> eprop_bool;
749 OpenMesh::FPropHandleT<std::string> fprop_string;
750 OpenMesh::HPropHandleT<MyData> hprop_mydata;
751 OpenMesh::MPropHandleT<MyMap> mprop_map;
752
753 // registrate them at the mesh object
754 mesh.add_property(vprop_float, "vprop_float");
755 mesh.add_property(eprop_bool, "eprop_bool");
756 mesh.add_property(fprop_string, "fprop_string");
757 mesh.add_property(hprop_mydata, "hprop_mydata");
758 mesh.add_property(mprop_map, "mprop_map");
759
760 //fill the props
761 fill_props(mesh, vprop_float);
762 fill_props(mesh, eprop_bool);
763 fill_props(mesh, fprop_string);
764 fill_props(mesh, hprop_mydata);
765 fill_props(mesh, mprop_map);
766
767 EXPECT_TRUE(fill_props(mesh, vprop_float, true)) << "property not filled correctly";
768 EXPECT_TRUE(fill_props(mesh, eprop_bool, true)) << "property not filled correctly";
769 EXPECT_TRUE(fill_props(mesh, fprop_string, true)) << "property not filled correctly";
770 EXPECT_TRUE(fill_props(mesh, hprop_mydata, true)) << "property not filled correctly";
771 EXPECT_TRUE(fill_props(mesh, mprop_map, true)) << "property not filled correctly";
772
773 //Set persistent flag
774 mesh.property(vprop_float).set_persistent(true);
775 EXPECT_TRUE(mesh.property(vprop_float).persistent()) << "property should be persistent";
776 mesh.property(eprop_bool).set_persistent(true);
777 EXPECT_TRUE(mesh.property(eprop_bool).persistent()) << "property should be persistent";
778 mesh.property(fprop_string).set_persistent(true);
779 EXPECT_TRUE(mesh.property(fprop_string).persistent()) << "property should be persistent";
780 mesh.property(hprop_mydata).set_persistent(true);
781 EXPECT_TRUE(mesh.property(hprop_mydata).persistent()) << "property should be persistent";
782 mesh.mproperty(mprop_map).set_persistent(true);
783 EXPECT_TRUE(mesh.mproperty(mprop_map).persistent()) << "property should be persistent";
784
785 // write mesh
786 bool ok = OpenMesh::IO::write_mesh( mesh, "persistence-check.om" );
787 EXPECT_TRUE(ok) << "Cannot write mesh to file 'persistent-check.om'";
788
789 // clear mesh
790 mesh.clear();
791
792 //Read back mesh
793 ok = OpenMesh::IO::read_mesh( mesh, "persistence-check.om" );
794 EXPECT_TRUE(ok) << "Cannot read mesh from file 'persistent-check.om'";
795
796 // check props
797 EXPECT_TRUE(fill_props(mesh, vprop_float, true)) << "property not filled correctly";
798 EXPECT_TRUE(fill_props(mesh, eprop_bool, true)) << "property not filled correctly";
799 EXPECT_TRUE(fill_props(mesh, fprop_string, true)) << "property not filled correctly";
800 EXPECT_TRUE(fill_props(mesh, hprop_mydata, true)) << "property not filled correctly";
801 EXPECT_TRUE(fill_props(mesh, mprop_map, true)) << "property not filled correctly";
802 }
803
804 /*Testcase for code snippet from flipping edges in triangle meshes
805 * */
806 TEST_F(OpenMeshTutorials, flipping_edges) {
807 Mesh mesh;
808 // Add some vertices
809 Mesh::VertexHandle vhandle[4];
810 vhandle[0] = mesh.add_vertex(MyMesh::Point(0, 0, 0));
811 vhandle[1] = mesh.add_vertex(MyMesh::Point(0, 1, 0));
812 vhandle[2] = mesh.add_vertex(MyMesh::Point(1, 1, 0));
813 vhandle[3] = mesh.add_vertex(MyMesh::Point(1, 0, 0));
814 // Add two faces
815 std::vector<Mesh::VertexHandle> face_vhandles;
816 face_vhandles.push_back(vhandle[2]);
817 face_vhandles.push_back(vhandle[1]);
818 face_vhandles.push_back(vhandle[0]);
819 mesh.add_face(face_vhandles);
820 face_vhandles.clear();
821 face_vhandles.push_back(vhandle[2]);
822 face_vhandles.push_back(vhandle[0]);
823 face_vhandles.push_back(vhandle[3]);
824 mesh.add_face(face_vhandles);
825 // Now the edge adjacent to the two faces connects
826 // vertex vhandle[0] and vhandle[2].
827 // Find this edge and then flip it
828 for(Mesh::EdgeIter it = mesh.edges_begin(); it != mesh.edges_end(); ++it) {
829 if(!mesh.is_boundary(*it)) {
830 // Flip edge
831 EXPECT_EQ(vhandle[2].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) << "expected vertex handle 2!" ;
832 EXPECT_EQ(vhandle[0].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) << "expected vertex handle 0!" ;
833 mesh.flip(*it);
834 EXPECT_EQ(vhandle[1].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) << "expected vertex handle 1 (did the flip work?)!" ;
835 EXPECT_EQ(vhandle[3].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) << "expected vertex handle 3 (did the flip work?)!" ;
836 }
837 }
838 // The edge now connects vertex vhandle[1] and vhandle[3].
839 }
840
841 /*Testcase for code snippet from collapsing edges in triangle meshes
842 * */
843 TEST_F(OpenMeshTutorials, collapsing_edges) {
844 PolyMesh mesh;
845 mesh.request_vertex_status();
846 mesh.request_edge_status();
847 // Add some vertices as in the illustration above
848 PolyMesh::VertexHandle vhandle[7];
849 vhandle[0] = mesh.add_vertex(MyMesh::Point(-1, 1, 0));
850 vhandle[1] = mesh.add_vertex(MyMesh::Point(-1, 3, 0));
851 vhandle[2] = mesh.add_vertex(MyMesh::Point(0, 0, 0));
852 vhandle[3] = mesh.add_vertex(MyMesh::Point(0, 2, 0));
853 vhandle[4] = mesh.add_vertex(MyMesh::Point(0, 4, 0));
854 vhandle[5] = mesh.add_vertex(MyMesh::Point(1, 1, 0));
855 vhandle[6] = mesh.add_vertex(MyMesh::Point(1, 3, 0));
856 // Add three quad faces
857 std::vector<PolyMesh::VertexHandle> face_vhandles;
858 face_vhandles.push_back(vhandle[1]);
859 face_vhandles.push_back(vhandle[0]);
860 face_vhandles.push_back(vhandle[2]);
861 face_vhandles.push_back(vhandle[3]);
862 mesh.add_face(face_vhandles);
863 face_vhandles.clear();
864 face_vhandles.push_back(vhandle[1]);
865 face_vhandles.push_back(vhandle[3]);
866 face_vhandles.push_back(vhandle[5]);
867 face_vhandles.push_back(vhandle[4]);
868 mesh.add_face(face_vhandles);
869 face_vhandles.clear();
870 face_vhandles.push_back(vhandle[3]);
871 face_vhandles.push_back(vhandle[2]);
872 face_vhandles.push_back(vhandle[6]);
873 face_vhandles.push_back(vhandle[5]);
874 mesh.add_face(face_vhandles);
875 // Now find the edge between vertex vhandle[2]
876 // and vhandle[3]
877 for(PolyMesh::HalfedgeIter it = mesh.halfedges_begin(); it != mesh.halfedges_end(); ++it) {
878 if( mesh.to_vertex_handle(*it) == vhandle[3] &&
879 mesh.from_vertex_handle(*it) == vhandle[2])
880 {
881 // Collapse edge
882 mesh.collapse(*it);
883 break;
884 }
885 }
886 // Our mesh now looks like in the illustration above after the collapsing.
887 }
888
889 }
OpenMesh::IO::read_mesh
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition: MeshIO.hh:104
OpenMesh::HPropHandleT
Definition: Property.hh:501
OpenMesh::PolyMesh_ArrayKernelT
Definition: PolyMesh_ArrayKernelT.hh:98
OpenMesh::IO::Options::VertexNormal
Has (r) / store (w) vertex normals.
Definition: Options.hh:109
OpenMesh
Definition: MeshItems.hh:64
OpenMesh::PolyMeshT::VertexVertexIter
Kernel::VertexVertexIter VertexVertexIter
Circulator.
Definition: PolyMeshT.hh:165
OpenMesh::vector_traits::value_type
T::value_type value_type
Type of the scalar value.
Definition: vector_traits.hh:99
OpenMesh::IO::binary
Definition: SR_binary.hh:105
OpenMeshBase
Definition: unittests_common.hh:21
OpenMesh::PolyMeshT::Point
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:115
OpenMesh::PolyMeshT::add_vertex
VertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
Definition: PolyMeshT.hh:236
OpenMesh::EPropHandleT
Definition: Property.hh:515
OpenMesh::TriMesh_ArrayKernelT
Definition: TriMesh_ArrayKernelT.hh:98
OpenMesh::IO::Options
Set options for reader/writer modules.
Definition: Options.hh:95
VertexTraits
#define VertexTraits
Macro for defining the vertex traits. See Specifying your MyMesh.
Definition: Traits.hh:96
OpenMesh::IO::size_of
size_t size_of(const T &_v)
Definition: StoreRestore.hh:94
OpenMesh::VPropHandleT
Definition: Property.hh:487
OpenMesh::VectorT< float, 4 >
FaceAttributes
#define FaceAttributes(_i)
Macro for defining the face attributes. See Specifying your MyMesh.
Definition: Traits.hh:93
EdgeAttributes
#define EdgeAttributes(_i)
Macro for defining the edge attributes. See Specifying your MyMesh.
Definition: Traits.hh:90
OpenMesh::Attributes::PrevHalfedge
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
Definition: Attributes.hh:89
OpenMesh::PolyMeshT::Scalar
Kernel::Scalar Scalar
Scalar type.
Definition: PolyMeshT.hh:113
OpenMesh::PolyMeshT::VertexHandle
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:139
OpenMesh::FPropHandleT
Definition: Property.hh:529
MyTraits
Definition: mymesh.cc:5
OpenMesh::DefaultTraits::Point
Vec3f Point
The default coordinate type is OpenMesh::Vec3f.
Definition: Traits.hh:129
OpenMesh::IO::write_mesh
bool write_mesh(const Mesh &_mesh, const std::string &_filename, Options _opt=Options::Default, std::streamsize _precision=6)
Write a mesh to the file _filename.
Definition: MeshIO.hh:199
OpenMesh::Attributes::Status
Add status to mesh item (all items)
Definition: Attributes.hh:90
OpenMesh::MPropHandleT
Definition: Property.hh:543
OpenMesh::DefaultTraits
Definition: Traits.hh:126
VertexAttributes
#define VertexAttributes(_i)
Macro for defining the vertex attributes. See Specifying your MyMesh.
Definition: Traits.hh:84
OpenMesh::DefaultTraits::Normal
Vec3f Normal
The default normal type is OpenMesh::Vec3f.
Definition: Traits.hh:132
MyData
Definition: unittests_tutorials.cc:15