Developer Documentation
Loading...
Searching...
No Matches
unittests_read_write_OM.cc
1#include <gtest/gtest.h>
2#include <Unittests/unittests_common.hh>
3
4#include <OpenMesh/Core/Utils/PropertyManager.hh>
5#include <OpenMesh/Core/Utils/PropertyCreator.hh>
6
8 int ival;
9 double dval;
10 bool bval;
11 OpenMesh::Vec4f vec4fval;
12 RegisteredDataType() : ival(0), dval(0.0) , bval(false), vec4fval(OpenMesh::Vec4f(0,0,0,0)) {}
13 RegisteredDataType(int i) : ival(i), dval(i*1.234567), bval(i%2) , vec4fval(OpenMesh::Vec4f(dval,2*dval,3*dval,4*dval)) {}
14
15 bool operator==(const RegisteredDataType& _other) const
16 {
17 return ival == _other.ival &&
18 dval == _other.dval &&
19 bval == _other.bval &&
20 vec4fval == _other.vec4fval;
21 }
22};
23
24namespace OpenMesh
25{
26namespace IO
27{
28 template <> struct binary<RegisteredDataType>
29 {
31 static const bool is_streamable = true;
32 // return binary size of the value
33 static size_t size_of(void)
34 {
35 return sizeof(int)+sizeof(double)+sizeof(bool)+sizeof(OpenMesh::Vec4f);
36 }
37 static size_t size_of(const value_type&)
38 {
39 return size_of();
40 }
41 static std::string type_identifier(void)
42 {
43 return "RegisteredDataType";
44 }
45 static size_t store(std::ostream& _os, const value_type& _v, bool _swap=false)
46 {
47 size_t bytes;
48 bytes = IO::store( _os, _v.ival, _swap );
49 bytes += IO::store( _os, _v.dval, _swap );
50 bytes += IO::store( _os, _v.bval, _swap );
51 bytes += IO::store( _os, _v.vec4fval, _swap );
52 return _os.good() ? bytes : 0;
53 }
54 static size_t restore( std::istream& _is, value_type& _v, bool _swap=false)
55 {
56 size_t bytes;
57 bytes = IO::restore( _is, _v.ival, _swap );
58 bytes += IO::restore( _is, _v.dval, _swap );
59 bytes += IO::restore( _is, _v.bval, _swap );
60 bytes += IO::restore( _is, _v.vec4fval, _swap );
61 return _is.good() ? bytes : 0;
62 }
63 };
64}
65}
66
67namespace {
68
69class OpenMeshReadWriteOM : public OpenMeshBase {
70
71 protected:
72
73 // This function is called before each test is run
74 virtual void SetUp() {
75
76 // Do some initial stuff with the member data here...
77 }
78
79 // This function is called after all tests are through
80 virtual void TearDown() {
81
82 // Do some final stuff with the member data here...
83 }
84
85 // Member already defined in OpenMeshBase
86 //Mesh mesh_;
87};
88
89/*
90 * ====================================================================
91 * Define tests below
92 * ====================================================================
93 */
94
95/*
96 * Just load an om file and set vertex color option before loading
97 */
98TEST_F(OpenMeshReadWriteOM, LoadSimpleOMForceVertexColorsAlthoughNotAvailable) {
99
100 mesh_.clear();
101
102 mesh_.request_vertex_colors();
103
104 std::string file_name = "cube-minimal.om";
105
106 OpenMesh::IO::Options options;
108
109 bool ok = OpenMesh::IO::read_mesh(mesh_, file_name,options);
110
111 EXPECT_TRUE(ok) << file_name;
112
113 EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
114 EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
115 EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
116 EXPECT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
117
118 EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
119 EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
120 EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned!";
121}
122
123/*
124 * Just load an om file of a cube with vertex texCoords
125 */
126TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithTexCoords) {
127
128 mesh_.clear();
129
130 mesh_.request_vertex_texcoords2D();
131
132 OpenMesh::IO::Options options;
134
135 bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-texCoords.om",options);
136
137 ASSERT_TRUE(ok) << "Unable to load cube-minimal-texCoords.om";
138
139 EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
140 EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
141 EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
142
143 EXPECT_EQ(10, mesh_.texcoord2D(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
144 EXPECT_EQ(10, mesh_.texcoord2D(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
145
146 EXPECT_EQ(6, mesh_.texcoord2D(mesh_.vertex_handle(2))[0] ) << "Wrong vertex color at vertex 2 component 0";
147 EXPECT_EQ(6, mesh_.texcoord2D(mesh_.vertex_handle(2))[1] ) << "Wrong vertex color at vertex 2 component 1";
148
149 EXPECT_EQ(9, mesh_.texcoord2D(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
150 EXPECT_EQ(9, mesh_.texcoord2D(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
151
152 EXPECT_EQ(12, mesh_.texcoord2D(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
153 EXPECT_EQ(12, mesh_.texcoord2D(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
154
155
156 EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
157 EXPECT_TRUE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
158 EXPECT_FALSE(options.vertex_has_color()) << "Wrong user options are returned!";
159
160 mesh_.release_vertex_texcoords2D();
161}
162
163/*
164 * Just load an om file of a cube with vertex colors
165 */
166TEST_F(OpenMeshReadWriteOM, LoadSimpleOMWithVertexColors) {
167
168 mesh_.clear();
169
170 mesh_.request_vertex_colors();
171
172 OpenMesh::IO::Options options;
174
175 bool ok = OpenMesh::IO::read_mesh(mesh_, "cube-minimal-vertexColors.om",options);
176
177 EXPECT_TRUE(ok) << "Unable to load cube-minimal-vertexColors.om";
178
179 EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
180 EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
181 EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
182
183#ifdef TEST_DOUBLE_TRAITS
184 EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
185 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
186 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
187
188 EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
189 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
190 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
191
192 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
193 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
194 EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
195
196 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
197 EXPECT_FLOAT_EQ(0.0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
198 EXPECT_FLOAT_EQ(1.0, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
199#else
200 EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(0))[0] ) << "Wrong vertex color at vertex 0 component 0";
201 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[1] ) << "Wrong vertex color at vertex 0 component 1";
202 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(0))[2] ) << "Wrong vertex color at vertex 0 component 2";
203
204 EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(3))[0] ) << "Wrong vertex color at vertex 3 component 0";
205 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[1] ) << "Wrong vertex color at vertex 3 component 1";
206 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(3))[2] ) << "Wrong vertex color at vertex 3 component 2";
207
208 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[0] ) << "Wrong vertex color at vertex 4 component 0";
209 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(4))[1] ) << "Wrong vertex color at vertex 4 component 1";
210 EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(4))[2] ) << "Wrong vertex color at vertex 4 component 2";
211
212 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[0] ) << "Wrong vertex color at vertex 7 component 0";
213 EXPECT_EQ(0, mesh_.color(mesh_.vertex_handle(7))[1] ) << "Wrong vertex color at vertex 7 component 1";
214 EXPECT_EQ(255, mesh_.color(mesh_.vertex_handle(7))[2] ) << "Wrong vertex color at vertex 7 component 2";
215#endif
216
217 EXPECT_FALSE(options.vertex_has_normal()) << "Wrong user options are returned!";
218 EXPECT_FALSE(options.vertex_has_texcoord()) << "Wrong user options are returned!";
219 EXPECT_TRUE(options.vertex_has_color()) << "Wrong user options are returned!";
220
221 mesh_.release_vertex_colors();
222}
223
224/*
225 * Save and load simple mesh
226 */
227TEST_F(OpenMeshReadWriteOM, WriteTriangle) {
228
229 Mesh mesh;
230 mesh.clear();
231
232 const std::string filename = "triangle-minimal.om";
233
234 // generate data
235 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
236 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
237 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
238 mesh.add_face(v1,v2,v3);
239
240 // save
241 bool ok = OpenMesh::IO::write_mesh(mesh,filename);
242 EXPECT_TRUE(ok) << "Unable to write " << filename;
243
244 // reset
245 mesh.clear();
246
247 // load
248 ok = OpenMesh::IO::read_mesh(mesh,filename);
249 EXPECT_TRUE(ok) << "Unable to read " << filename;
250
251 // compare
252 EXPECT_EQ(3u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
253 EXPECT_EQ(3u , mesh.n_edges()) << "The number of loaded edges is not correct!";
254 EXPECT_EQ(1u , mesh.n_faces()) << "The number of loaded faces is not correct!";
255
256 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , mesh.point(v1)) << "Wrong coordinates at vertex 0";
257 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , mesh.point(v2)) << "Wrong coordinates at vertex 1";
258 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , mesh.point(v3)) << "Wrong coordinates at vertex 2";
259
260 // cleanup
261 remove(filename.c_str());
262
263}
264
265/*
266 * Save and load simple mesh with integer colors per vertex
267 */
268TEST_F(OpenMeshReadWriteOM, WriteTriangleVertexIntegerColor) {
269
270 Mesh mesh;
271
272 mesh.request_vertex_colors();
273
274 OpenMesh::IO::Options options;
277
278 const std::string filename = "triangle-minimal-ColorsPerVertex.om";
279
280 // generate data
281 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
282 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
283 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
284 mesh.add_face(v1,v2,v3);
285
286#ifdef TEST_DOUBLE_TRAITS
287 Mesh::Color c1 = Mesh::Color(0,0,123/255.0,1.0),
288 c2 = Mesh::Color(21/255.0,0,0,1.0),
289 c3 = Mesh::Color(0,222/255.0,0,1.0);
290#else
291 Mesh::Color c1 = Mesh::Color(0,0,123),
292 c2 = Mesh::Color(21,0,0),
293 c3 = Mesh::Color(0,222,0);
294#endif
295
296 mesh.set_color(v1,c1);
297 mesh.set_color(v2,c2);
298 mesh.set_color(v3,c3);
299
300 // save
301 bool ok = OpenMesh::IO::write_mesh(mesh,filename,options);
302 EXPECT_TRUE(ok) << "Unable to write "<<filename;
303
304 mesh.release_vertex_colors();
305
306 // load
307 Mesh cmpMesh;
308 cmpMesh.request_vertex_colors();
309 ok = OpenMesh::IO::read_mesh(cmpMesh,filename,options);
310 EXPECT_TRUE(ok) << "Unable to read "<<filename;
311
312 EXPECT_TRUE(cmpMesh.has_vertex_colors()) << "Loaded mesh has no vertex colors.";
313
314 // compare
315 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
316 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
317 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
318
319 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
320 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
321 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
322
323#ifdef TEST_DOUBLE_TRAITS
324 // OM file format does not support writing colors as float. They are stored as unsigned character.
325 // Thus, the values will not be exactly equal.
326 for (size_t i = 0; i < c1.size(); ++i)
327 {
328 EXPECT_FLOAT_EQ(c1[i] , cmpMesh.color(v1)[i]) << "Wrong colors at coordinate " << i << " of vertex 0";
329 EXPECT_FLOAT_EQ(c2[i] , cmpMesh.color(v2)[i]) << "Wrong colors at coordinate " << i << " of vertex 1";
330 EXPECT_FLOAT_EQ(c3[i] , cmpMesh.color(v3)[i]) << "Wrong colors at coordinate " << i << " of vertex 2";
331 }
332#else
333 EXPECT_EQ(c1 , cmpMesh.color(v1)) << "Wrong colors at vertex 0";
334 EXPECT_EQ(c2 , cmpMesh.color(v2)) << "Wrong colors at vertex 1";
335 EXPECT_EQ(c3 , cmpMesh.color(v3)) << "Wrong colors at vertex 2";
336#endif
337
338 //clean up
339 cmpMesh.release_vertex_colors();
340 remove(filename.c_str());
341
342}
343
344/*
345 * Save and load simple mesh with custom property
346 */
347TEST_F(OpenMeshReadWriteOM, WriteTriangleVertexBoolProperty) {
348
349 Mesh mesh;
350
351 const std::string filename = "triangle-minimal-VBProp.om";
352
353 // generate data
354 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
355 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
356 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
357 mesh.add_face(v1,v2,v3);
358
360 mesh.add_property(prop,"VBProp");
361 mesh.property(prop).set_persistent(true);
362
363 mesh.property(prop,v1) = true;
364 mesh.property(prop,v2) = false;
365 mesh.property(prop,v3) = true;
366
367 // save
369
370 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
371 EXPECT_TRUE(ok) << "Unable to write "<<filename;
372
373 // load
374 Mesh cmpMesh;
375
376
377 cmpMesh.add_property(prop,"VBProp");
378 cmpMesh.property(prop).set_persistent(true);
379
380 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
381 EXPECT_TRUE(ok) << "Unable to read "<<filename;
382
383 // compare
384 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
385 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
386 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
387
388 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
389 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
390 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
391
392 EXPECT_TRUE(cmpMesh.property(prop,v1)) << "Wrong Property value at vertex 0";
393 EXPECT_FALSE(cmpMesh.property(prop,v2)) << "Wrong Property value at vertex 1";
394 EXPECT_TRUE(cmpMesh.property(prop,v3)) << "Wrong Property value at vertex 2";
395
396 // cleanup
397 remove(filename.c_str());
398
399}
400
401/*
402 * Save and load simple mesh with custom property
403 */
404TEST_F(OpenMeshReadWriteOM, WriteTriangleVertexBoolPropertySpaceEquivalent) {
405
406 Mesh mesh;
407
408 const std::string filename = "triangle-minimal-VBProp-pattern-test.om";
409
410 // generate data
411 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
412 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
413 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
414 mesh.add_face(v1,v2,v3);
415
416 Mesh::VertexHandle v4 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
417 Mesh::VertexHandle v5 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
418 Mesh::VertexHandle v6 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
419 mesh.add_face(v4,v5,v6);
420
421 Mesh::VertexHandle v7 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
422 Mesh::VertexHandle v8 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
423 Mesh::VertexHandle v9 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
424
426 mesh.add_property(prop,"VBProp");
427 mesh.property(prop).set_persistent(true);
428
429 // Create a 0x20 hex pattern in the bitset
430 mesh.property(prop,v1) = false;
431 mesh.property(prop,v2) = false;
432 mesh.property(prop,v3) = false;
433 mesh.property(prop,v4) = false;
434 mesh.property(prop,v5) = false;
435 mesh.property(prop,v6) = true;
436 mesh.property(prop,v7) = false;
437 mesh.property(prop,v8) = false;
438 mesh.property(prop,v9) = true;
439
440 // save
442
443 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
444 EXPECT_TRUE(ok) << "Unable to write "<<filename;
445
446 // load
447 Mesh cmpMesh;
448
449 cmpMesh.add_property(prop,"VBProp");
450 cmpMesh.property(prop).set_persistent(true);
451
452 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
453 EXPECT_TRUE(ok) << "Unable to read "<<filename;
454
455 // compare
456 EXPECT_EQ(9u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
457 EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
458 EXPECT_EQ(2u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
459
460 EXPECT_FALSE(cmpMesh.property(prop,v1)) << "Wrong Property value at vertex 0";
461 EXPECT_FALSE(cmpMesh.property(prop,v2)) << "Wrong Property value at vertex 1";
462 EXPECT_FALSE(cmpMesh.property(prop,v3)) << "Wrong Property value at vertex 2";
463 EXPECT_FALSE(cmpMesh.property(prop,v4)) << "Wrong Property value at vertex 3";
464 EXPECT_FALSE(cmpMesh.property(prop,v5)) << "Wrong Property value at vertex 4";
465 EXPECT_TRUE(cmpMesh.property(prop,v6)) << "Wrong Property value at vertex 5";
466 EXPECT_FALSE(cmpMesh.property(prop,v7)) << "Wrong Property value at vertex 6";
467 EXPECT_FALSE(cmpMesh.property(prop,v8)) << "Wrong Property value at vertex 7";
468 EXPECT_TRUE(cmpMesh.property(prop,v9)) << "Wrong Property value at vertex 8";
469
470 // cleanup
471 remove(filename.c_str());
472
473}
474
475/*
476 * Save and load simple mesh with multiple custom property
477 */
478TEST_F(OpenMeshReadWriteOM, WriteTriangleTwoVertexBoolProperty) {
479
480 Mesh mesh;
481
482 const std::string filename = "triangle-minimal-VBProp.om";
483
484 // generate data
485 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
486 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
487 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
488 mesh.add_face(v1,v2,v3);
489
491 mesh.add_property(prop,"VBProp");
492 mesh.property(prop).set_persistent(true);
493
494 mesh.property(prop,v1) = true;
495 mesh.property(prop,v2) = false;
496 mesh.property(prop,v3) = true;
497
499 mesh.add_property(prop2,"VBProp2");
500 mesh.property(prop2).set_persistent(true);
501
502 mesh.property(prop2,v1) = false;
503 mesh.property(prop2,v2) = false;
504 mesh.property(prop2,v3) = false;
505
506 // save
508
509 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
510 EXPECT_TRUE(ok) << "Unable to write "<<filename;
511
512
513 // load
514 Mesh cmpMesh;
515 cmpMesh.add_property(prop,"VBProp");
516 cmpMesh.property(prop).set_persistent(true);
517
518 cmpMesh.add_property(prop2,"VBProp2");
519 cmpMesh.property(prop2).set_persistent(true);
520
521 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
522 EXPECT_TRUE(ok) << "Unable to read "<<filename;
523
524 // compare
525 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
526 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
527 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
528
529 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
530 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
531 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
532
533 EXPECT_TRUE(cmpMesh.property(prop,v1)) << "Wrong Property value at vertex 0";
534 EXPECT_FALSE(cmpMesh.property(prop,v2)) << "Wrong Property value at vertex 1";
535 EXPECT_TRUE(cmpMesh.property(prop,v3)) << "Wrong Property value at vertex 2";
536
537 EXPECT_FALSE(cmpMesh.property(prop2,v1)) << "Wrong second Property value at vertex 0";
538 EXPECT_FALSE(cmpMesh.property(prop2,v2)) << "Wrong second Property value at vertex 1";
539 EXPECT_FALSE(cmpMesh.property(prop2,v3)) << "Wrong second Property value at vertex 2";
540
541 // cleanup
542 remove(filename.c_str());
543
544}
545
546/*
547 * Save and load simple mesh with custom property
548 */
549TEST_F(OpenMeshReadWriteOM, WriteTriangleEdgeIntProperty) {
550
551 Mesh mesh;
552
553 const std::string propName = "EIProp";
554 const std::string filename = std::string("triangle-minimal-")+propName+".om";
555
556 // generate data
557 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
558 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
559 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
560 mesh.add_face(v1,v2,v3);
561
563 mesh.add_property(prop,propName);
564 mesh.property(prop).set_persistent(true);
565
569
570 int value1 = 10,
571 value2 = 21,
572 value3 = 32;
573
574 mesh.property(prop,e1) = value1;
575 mesh.property(prop,e2) = value2;
576 mesh.property(prop,e3) = value3;
577
578 // save
580
581 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
582 EXPECT_TRUE(ok) << "Unable to write "<<filename;
583
584 // load
585 Mesh cmpMesh;
586
587 cmpMesh.add_property(prop,propName);
588 cmpMesh.property(prop).set_persistent(true);
589
590 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
591 EXPECT_TRUE(ok) << "Unable to read "<<filename;
592
593 // compare
594 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
595 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
596 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
597
598 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
599 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
600 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
601
602 EXPECT_EQ(value1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0";
603 EXPECT_EQ(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1";
604 EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2";
605
606 // cleanup
607 remove(filename.c_str());
608
609}
610
611/*
612 * Save and load simple mesh with custom property
613 */
614TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleEdgeIntProperty) {
615
616 Mesh mesh;
617
618 const std::string propName = "EIProp";
619 const std::string filename = std::string("triangle-minimal-")+propName+".om";
620
621 // generate data
622 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
623 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
624 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
625 auto fh0 = mesh.add_face(v1,v2,v3);
626 auto c = mesh.calc_face_centroid(fh0);
627 Mesh::VertexHandle v4 = mesh.add_vertex(c);
628 mesh.split(fh0, v4);
629
630
632 mesh.add_property(prop,propName);
633 mesh.property(prop).set_persistent(true);
634
641
642 int value1 = 10,
643 value2 = 21,
644 value3 = 32,
645 value4 = 43,
646 value5 = 54,
647 value6 = 65;
648
649 mesh.property(prop,e1) = value1;
650 mesh.property(prop,e2) = value2;
651 mesh.property(prop,e3) = value3;
652 mesh.property(prop,e4) = value4;
653 mesh.property(prop,e5) = value5;
654 mesh.property(prop,e6) = value6;
655
656 // save
658
659 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
660 EXPECT_TRUE(ok) << "Unable to write "<<filename;
661
662 // load
663 Mesh cmpMesh;
664
665 cmpMesh.add_property(prop,propName);
666 cmpMesh.property(prop).set_persistent(true);
667
668 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
669 EXPECT_TRUE(ok) << "Unable to read "<<filename;
670
671 // compare
672 EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
673 EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
674 EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
675
676 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
677 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
678 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
679
680#ifdef TEST_DOUBLE_TRAITS
681 // TODO: should it be possible to read and write double precision exactly?
682 EXPECT_FLOAT_EQ(c[0] , cmpMesh.point(v4)[0]) << "Wrong coordinate 0 at vertex 4";
683 EXPECT_FLOAT_EQ(c[1] , cmpMesh.point(v4)[1]) << "Wrong coordinate 1 at vertex 4";
684 EXPECT_FLOAT_EQ(c[2] , cmpMesh.point(v4)[2]) << "Wrong coordinate 2 at vertex 4";
685#else
686 EXPECT_EQ(c , cmpMesh.point(v4)) << "Wrong coordinates at vertex 4";
687#endif
688
689 EXPECT_EQ(value1 , cmpMesh.property(prop,e1)) << "Wrong property at edge 0";
690 EXPECT_EQ(value2 , cmpMesh.property(prop,e2)) << "Wrong property at edge 1";
691 EXPECT_EQ(value3 , cmpMesh.property(prop,e3)) << "Wrong property at edge 2";
692 EXPECT_EQ(value4 , cmpMesh.property(prop,e4)) << "Wrong property at edge 3";
693 EXPECT_EQ(value5 , cmpMesh.property(prop,e5)) << "Wrong property at edge 4";
694 EXPECT_EQ(value6 , cmpMesh.property(prop,e6)) << "Wrong property at edge 5";
695 // The above only shows that the edge properties are stored in the same order which is not what we want if the edges are different
696
697 // Check edge properties based on edges defined by from and to vertex
698 for (auto eh : mesh.edges())
699 {
700 auto heh = mesh.halfedge_handle(eh, 0);
701 auto from_vh = mesh.from_vertex_handle(heh);
702 auto to_vh = mesh.to_vertex_handle(heh);
703
704 // find corresponding halfedge in loaded mesh
705 auto cmpHeh = cmpMesh.find_halfedge(from_vh, to_vh);
706 auto cmpEh = cmpMesh.edge_handle(cmpHeh);
707
708 EXPECT_EQ(mesh.property(prop, eh), cmpMesh.property(prop, cmpEh)) << "Wrong property at input edge " << eh.idx()
709 << " corresponding to edge " << cmpEh.idx() << " in the loaded Mesh";
710 }
711
712
713
714 // cleanup
715 remove(filename.c_str());
716
717}
718
719/*
720 * Save and load simple mesh with status property
721 */
722TEST_F(OpenMeshReadWriteOM, WriteSplitTriangleStatusProperties) {
723
724 Mesh mesh;
725
726 mesh.request_vertex_status();
727 mesh.request_edge_status();
728 mesh.request_halfedge_status();
729 mesh.request_face_status();
730
731 const std::string filename = std::string("triangle-minimal-status.om");
732
733 // generate data
734 Mesh::VertexHandle v0 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
735 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
736 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
737 auto fh0 = mesh.add_face(v0,v1,v2);
738 auto c = mesh.calc_face_centroid(fh0);
739 Mesh::VertexHandle v3 = mesh.add_vertex(c);
740 mesh.split(fh0, v3);
741
742 mesh.delete_vertex(v0);
743 mesh.status(v1).set_selected(true);
744 mesh.status(v2).set_feature(true);
745 mesh.status(v3).set_tagged(true);
746 mesh.status(v2).set_tagged2(true);
747
748 std::vector<bool> vertex_deleted;
749 std::vector<bool> vertex_selected;
750 std::vector<bool> vertex_feature;
751 std::vector<bool> vertex_tagged;
752 std::vector<bool> vertex_tagged2;
753
754 for (auto vh : mesh.all_vertices())
755 {
756 vertex_deleted.push_back(mesh.status(vh).deleted());
757 vertex_selected.push_back(mesh.status(vh).selected());
758 vertex_feature.push_back(mesh.status(vh).feature());
759 vertex_tagged.push_back(mesh.status(vh).tagged());
760 vertex_tagged2.push_back(mesh.status(vh).tagged2());
761 }
762
767
768 mesh.status(e1).set_selected(true);
769 mesh.status(e2).set_feature(true);
770 mesh.status(e3).set_tagged(true);
771 mesh.status(e4).set_tagged2(true);
772
773 std::vector<bool> edge_deleted;
774 std::vector<bool> edge_selected;
775 std::vector<bool> edge_feature;
776 std::vector<bool> edge_tagged;
777 std::vector<bool> edge_tagged2;
778
779 for (auto eh : mesh.all_edges())
780 {
781 edge_deleted.push_back(mesh.status(eh).deleted());
782 edge_selected.push_back(mesh.status(eh).selected());
783 edge_feature.push_back(mesh.status(eh).feature());
784 edge_tagged.push_back(mesh.status(eh).tagged());
785 edge_tagged2.push_back(mesh.status(eh).tagged2());
786 }
787
788
793
794 mesh.status(he1).set_selected(true);
795 mesh.status(he2).set_feature(true);
796 mesh.status(he3).set_tagged(true);
797 mesh.status(he4).set_tagged2(true);
798
799 std::vector<bool> halfedge_deleted;
800 std::vector<bool> halfedge_selected;
801 std::vector<bool> halfedge_feature;
802 std::vector<bool> halfedge_tagged;
803 std::vector<bool> halfedge_tagged2;
804
805 for (auto heh : mesh.all_halfedges())
806 {
807 halfedge_deleted.push_back(mesh.status(heh).deleted());
808 halfedge_selected.push_back(mesh.status(heh).selected());
809 halfedge_feature.push_back(mesh.status(heh).feature());
810 halfedge_tagged.push_back(mesh.status(heh).tagged());
811 halfedge_tagged2.push_back(mesh.status(heh).tagged2());
812 }
813
818
819 mesh.status(f1).set_selected(true);
820 mesh.status(f2).set_feature(true);
821 mesh.status(f3).set_tagged(true);
822 mesh.status(f4).set_tagged2(true);
823
824 std::vector<bool> face_deleted;
825 std::vector<bool> face_selected;
826 std::vector<bool> face_feature;
827 std::vector<bool> face_tagged;
828 std::vector<bool> face_tagged2;
829
830 for (auto fh : mesh.all_faces())
831 {
832 face_deleted.push_back(mesh.status(fh).deleted());
833 face_selected.push_back(mesh.status(fh).selected());
834 face_feature.push_back(mesh.status(fh).feature());
835 face_tagged.push_back(mesh.status(fh).tagged());
836 face_tagged2.push_back(mesh.status(fh).tagged2());
837 }
838
839 // save
841 bool ok = OpenMesh::IO::write_mesh(mesh,filename, options);
842 EXPECT_TRUE(ok) << "Unable to write "<<filename;
843
844 // load
845 Mesh cmpMesh;
846
847 cmpMesh.request_vertex_status();
848 cmpMesh.request_edge_status();
849 cmpMesh.request_halfedge_status();
850 cmpMesh.request_face_status();
851
852 ok = OpenMesh::IO::read_mesh(cmpMesh,filename, options);
853 EXPECT_TRUE(ok) << "Unable to read "<<filename;
854
855 // compare
856 EXPECT_EQ(4u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
857 EXPECT_EQ(6u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
858 EXPECT_EQ(3u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
859
860 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v0)) << "Wrong coordinates at vertex 0";
861 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 1";
862 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 2";
863
864#ifdef TEST_DOUBLE_TRAITS
865 // TODO: should it be possible to read and write double precision exactly?
866 EXPECT_FLOAT_EQ(c[0] , cmpMesh.point(v3)[0]) << "Wrong coordinate 0 at vertex 3";
867 EXPECT_FLOAT_EQ(c[1] , cmpMesh.point(v3)[1]) << "Wrong coordinate 1 at vertex 3";
868 EXPECT_FLOAT_EQ(c[2] , cmpMesh.point(v3)[2]) << "Wrong coordinate 2 at vertex 3";
869#else
870 EXPECT_EQ(c , cmpMesh.point(v3)) << "Wrong coordinates at vertex 3";
871#endif
872
873 for (auto vh : cmpMesh.all_vertices())
874 {
875 EXPECT_EQ(cmpMesh.status(vh).deleted(), vertex_deleted [vh.idx()]) << "Wrong deleted status at vertex " << vh.idx();
876 EXPECT_EQ(cmpMesh.status(vh).selected(), vertex_selected[vh.idx()]) << "Wrong selected status at vertex " << vh.idx();
877 EXPECT_EQ(cmpMesh.status(vh).feature(), vertex_feature [vh.idx()]) << "Wrong feature status at vertex " << vh.idx();
878 EXPECT_EQ(cmpMesh.status(vh).tagged(), vertex_tagged [vh.idx()]) << "Wrong tagged status at vertex " << vh.idx();
879 EXPECT_EQ(cmpMesh.status(vh).tagged2(), vertex_tagged2 [vh.idx()]) << "Wrong tagged2 status at vertex " << vh.idx();
880 }
881
882 for (auto eh : cmpMesh.all_edges())
883 {
884 EXPECT_EQ(cmpMesh.status(eh).deleted(), edge_deleted [eh.idx()]) << "Wrong deleted status at edge " << eh.idx();
885 EXPECT_EQ(cmpMesh.status(eh).selected(), edge_selected[eh.idx()]) << "Wrong selected status at edge " << eh.idx();
886 EXPECT_EQ(cmpMesh.status(eh).feature(), edge_feature [eh.idx()]) << "Wrong feature status at edge " << eh.idx();
887 EXPECT_EQ(cmpMesh.status(eh).tagged(), edge_tagged [eh.idx()]) << "Wrong tagged status at edge " << eh.idx();
888 EXPECT_EQ(cmpMesh.status(eh).tagged2(), edge_tagged2 [eh.idx()]) << "Wrong tagged2 status at edge " << eh.idx();
889 }
890
891 for (auto heh : cmpMesh.all_halfedges())
892 {
893 EXPECT_EQ(cmpMesh.status(heh).deleted(), halfedge_deleted [heh.idx()]) << "Wrong deleted status at halfedge " << heh.idx();
894 EXPECT_EQ(cmpMesh.status(heh).selected(), halfedge_selected[heh.idx()]) << "Wrong selected status at halfedge " << heh.idx();
895 EXPECT_EQ(cmpMesh.status(heh).feature(), halfedge_feature [heh.idx()]) << "Wrong feature status at halfedge " << heh.idx();
896 EXPECT_EQ(cmpMesh.status(heh).tagged(), halfedge_tagged [heh.idx()]) << "Wrong tagged status at halfedge " << heh.idx();
897 EXPECT_EQ(cmpMesh.status(heh).tagged2(), halfedge_tagged2 [heh.idx()]) << "Wrong tagged2 status at halfedge " << heh.idx();
898 }
899
900 for (auto fh : cmpMesh.all_faces())
901 {
902 EXPECT_EQ(cmpMesh.status(fh).deleted(), face_deleted [fh.idx()]) << "Wrong deleted status at face " << fh.idx();
903 EXPECT_EQ(cmpMesh.status(fh).selected(), face_selected[fh.idx()]) << "Wrong selected status at face " << fh.idx();
904 EXPECT_EQ(cmpMesh.status(fh).feature(), face_feature [fh.idx()]) << "Wrong feature status at face " << fh.idx();
905 EXPECT_EQ(cmpMesh.status(fh).tagged(), face_tagged [fh.idx()]) << "Wrong tagged status at face " << fh.idx();
906 EXPECT_EQ(cmpMesh.status(fh).tagged2(), face_tagged2 [fh.idx()]) << "Wrong tagged2 status at face " << fh.idx();
907 }
908
909
910 // cleanup
911 remove(filename.c_str());
912}
913
914/*
915 * Save and load simple mesh with custom property
916 */
917TEST_F(OpenMeshReadWriteOM, WriteTriangleFaceDoubleProperty) {
918
919 Mesh mesh;
920
921 const std::string propName = "FDProp";
922 const std::string filename = std::string("triangle-minimal-")+propName+".om";
923
924 // generate data
925 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
926 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
927 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
928 mesh.add_face(v1,v2,v3);
929
931 mesh.add_property(prop,propName);
932 mesh.property(prop).set_persistent(true);
933
935
936 double va1ue1 = 0.5;
937
938 mesh.property(prop,f1) = va1ue1;
939
940 // save
942
943 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
944 EXPECT_TRUE(ok) << "Unable to write "<<filename;
945
946 // load
947 Mesh cmpMesh;
948
949 cmpMesh.add_property(prop,propName);
950 cmpMesh.property(prop).set_persistent(true);
951
952 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
953 EXPECT_TRUE(ok) << "Unable to read "<<filename;
954
955 // compare
956 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
957 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
958 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
959
960 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
961 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
962 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
963
964 EXPECT_EQ(va1ue1 , cmpMesh.property(prop,f1)) << "Wrong property at edge 0";
965
966 // cleanup
967 remove(filename.c_str());
968
969}
970
971/*
972 * Save and load simple mesh with custom property
973 */
974TEST_F(OpenMeshReadWriteOM, WriteTriangleFaceFloatProperty) {
975
976 const std::string propName = "FFProp";
977 const std::string filename = std::string("triangle-minimal-")+propName+".om";
978
979 // generate data
980 Mesh mesh;
981 Mesh::VertexHandle v1 = mesh.add_vertex(Mesh::Point(1.0,0.0,0.0));
982 Mesh::VertexHandle v2 = mesh.add_vertex(Mesh::Point(0.0,1.0,0.0));
983 Mesh::VertexHandle v3 = mesh.add_vertex(Mesh::Point(0.0,0.0,1.0));
984 mesh.add_face(v1,v2,v3);
985
987 mesh.add_property(prop,propName);
988 mesh.property(prop).set_persistent(true);
989
991
992 float va1ue1 = 3.1f;
993
994 mesh.property(prop,f1) = va1ue1;
995
996 // save
998
999 bool ok = OpenMesh::IO::write_mesh(mesh, filename, opts);
1000 EXPECT_TRUE(ok) << "Unable to write "<<filename;
1001
1002
1003 // load
1004 Mesh cmpMesh;
1005 cmpMesh.add_property(prop,propName);
1006 cmpMesh.property(prop).set_persistent(true);
1007
1008 ok = OpenMesh::IO::read_mesh(cmpMesh, filename, opts);
1009 EXPECT_TRUE(ok) << "Unable to read "<<filename;
1010
1011 // compare
1012 EXPECT_EQ(3u , cmpMesh.n_vertices()) << "The number of loaded vertices is not correct!";
1013 EXPECT_EQ(3u , cmpMesh.n_edges()) << "The number of loaded edges is not correct!";
1014 EXPECT_EQ(1u , cmpMesh.n_faces()) << "The number of loaded faces is not correct!";
1015
1016 EXPECT_EQ(Mesh::Point(1.0,0.0,0.0) , cmpMesh.point(v1)) << "Wrong coordinates at vertex 0";
1017 EXPECT_EQ(Mesh::Point(0.0,1.0,0.0) , cmpMesh.point(v2)) << "Wrong coordinates at vertex 1";
1018 EXPECT_EQ(Mesh::Point(0.0,0.0,1.0) , cmpMesh.point(v3)) << "Wrong coordinates at vertex 2";
1019
1020 EXPECT_EQ(va1ue1 , cmpMesh.property(prop,f1)) << "Wrong property at edge 0";
1021
1022 // cleanup
1023 remove(filename.c_str());
1024
1025}
1026
1027/*
1028 * Save and load simple mesh with custom property
1029 */
1030TEST_F(OpenMeshReadWriteOM, ReadBigMeshWithCustomProperty) {
1031
1033 OpenMesh::VPropHandleT<int> vertexProp;
1034 bool ok;
1035
1036 //generate file
1037 /* mesh_.clear();
1038 ok = OpenMesh::IO::read_mesh(mesh_,"cube1.off");
1039
1040 mesh_.add_property(faceProp,"DFProp");
1041 mesh_.property(faceProp).set_persistent(true);
1042
1043 mesh_.add_property(vertexProp, "IVProp");
1044 mesh_.property(vertexProp).set_persistent(true);
1045
1046
1047 for (Mesh::FaceIter fIter = mesh_.faces_begin(); fIter != mesh_.faces_end(); ++fIter)
1048 mesh_.property(faceProp,*fIter) = 0.3;
1049
1050 for (Mesh::VertexIter vIter = mesh_.vertices_begin(); vIter != mesh_.vertices_end(); ++vIter)
1051 mesh_.property(vertexProp,*vIter) = vIter->idx();
1052
1053 OpenMesh::IO::write_mesh(mesh_,"cube1_customProps.om");
1054
1055
1056 mesh_.clear();
1057*/
1058 //read file
1059 Mesh mesh;
1060 mesh.add_property(faceProp,"DFProp");
1061 mesh.property(faceProp).set_persistent(true);
1062
1063 mesh.add_property(vertexProp, "IVProp");
1064 mesh.property(vertexProp).set_persistent(true);
1065
1067 ok = OpenMesh::IO::read_mesh(mesh,"cube1_customProps.om", opts);
1068 EXPECT_TRUE(ok) << "Unable to read cube1_customProps.om";
1069
1071 EXPECT_EQ(7526u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
1072 EXPECT_EQ(22572u, mesh.n_edges()) << "The number of loaded edges is not correct!";
1073 EXPECT_EQ(15048u, mesh.n_faces()) << "The number of loaded faces is not correct!";
1074
1075 bool wrong = false;
1076 for (Mesh::FaceIter fIter = mesh.faces_begin(); fIter != mesh.faces_end() && !wrong; ++fIter)
1077 wrong = (0.3 != mesh.property(faceProp,*fIter));
1078 EXPECT_FALSE(wrong) << "min one face has wrong face property";
1079
1080 wrong = false;
1081 for (Mesh::VertexIter vIter = mesh.vertices_begin(); vIter != mesh.vertices_end() && !wrong; ++vIter)
1082 wrong = (vIter->idx() != mesh.property(vertexProp,*vIter));
1083 EXPECT_FALSE(wrong) << "min one vertex has wrong vertex property";
1084}
1085
1086
1087/*
1088 * Save and load simple mesh with vertex status
1089 */
1090TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyVertexOnly) {
1091
1092 //read file
1093 Mesh mesh;
1094 auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
1095 auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
1096 auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
1097 mesh.add_face(vh0, vh1, vh2);
1098
1099 mesh.request_vertex_status();
1100
1101 mesh.status(vh0).set_selected(true);
1102 mesh.status(vh1).set_feature(true);
1103 mesh.status(vh2).set_tagged(true);
1104 mesh.status(vh0).set_locked(true);
1105 mesh.status(vh1).set_deleted(true);
1106 mesh.status(vh2).set_hidden(true);
1107 mesh.status(vh0).set_fixed_nonmanifold(true);
1108
1109
1110 std::string filename_without_status = "no_vertex_status_test.om";
1111 std::string filename_with_status = "vertex_status_test.om";
1112
1114 OpenMesh::IO::write_mesh(mesh, filename_without_status);
1115 OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
1116
1117 // Load no status from file with status
1118 {
1119 Mesh loaded_mesh;
1120 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1121
1122 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
1123 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1124 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1125 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1126 }
1127
1128 // Load status from file with status
1129 {
1130 Mesh loaded_mesh;
1131 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
1132
1133 EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh has no vertex status even though they should have been loaded";
1134 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1135 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1136 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1137
1138 if (loaded_mesh.has_vertex_status())
1139 {
1140 for (auto vh : mesh.vertices())
1141 {
1142 EXPECT_EQ(mesh.status(vh).bits(), loaded_mesh.status(vh).bits());
1143 }
1144 }
1145 }
1146
1147 // Load no status from file with status
1148 {
1149 Mesh loaded_mesh;
1150 loaded_mesh.request_vertex_status();
1151 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1152
1153 EXPECT_TRUE (loaded_mesh.has_vertex_status()) << "Mesh vertex status was removed by reading";
1154 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1155 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1156 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1157
1158 for (auto vh : loaded_mesh.vertices())
1159 {
1160 EXPECT_EQ(loaded_mesh.status(vh).bits(), 0u) << "Vertex status was modified even though it should not have been loaded";
1161 }
1162 }
1163
1164 // Try to load status from file without status
1165 {
1166 Mesh loaded_mesh;
1167 OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
1168
1169 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1170 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1171 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
1172 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
1173 }
1174}
1175
1176
1177/*
1178 * Save and load simple mesh with halfedge status
1179 */
1180TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyHalfedgeOnly) {
1181
1182 //read file
1183 Mesh mesh;
1184 auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
1185 auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
1186 auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
1187 mesh.add_face(vh0, vh1, vh2);
1188
1189 mesh.request_halfedge_status();
1190
1191 auto heh0 = OpenMesh::HalfedgeHandle(0);
1192 auto heh1 = OpenMesh::HalfedgeHandle(1);
1193 auto heh2 = OpenMesh::HalfedgeHandle(2);
1194 auto heh3 = OpenMesh::HalfedgeHandle(3);
1195 auto heh4 = OpenMesh::HalfedgeHandle(4);
1196 auto heh5 = OpenMesh::HalfedgeHandle(5);
1197
1198 mesh.status(heh0).set_selected(true);
1199 mesh.status(heh1).set_feature(true);
1200 mesh.status(heh2).set_tagged(true);
1201 mesh.status(heh3).set_locked(true);
1202 mesh.status(heh4).set_deleted(true);
1203 mesh.status(heh5).set_hidden(true);
1204 mesh.status(heh0).set_fixed_nonmanifold(true);
1205
1206 std::string filename_without_status = "no_halfedge_status_test.om";
1207 std::string filename_with_status = "edge_halfstatus_test.om";
1208
1210 OpenMesh::IO::write_mesh(mesh, filename_without_status);
1211 OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
1212
1213 // Load no status from file with status
1214 {
1215 Mesh loaded_mesh;
1216 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1217
1218 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
1219 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1220 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1221 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1222 }
1223
1224 // Load status from file with status
1225 {
1226 Mesh loaded_mesh;
1227 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
1228
1229 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
1230 EXPECT_TRUE(loaded_mesh.has_halfedge_status()) << "Mesh has no halfedge status even though file should not have a stored status";
1231 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1232 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1233
1234 if (loaded_mesh.has_halfedge_status())
1235 {
1236 for (auto heh : mesh.halfedges())
1237 {
1238 EXPECT_EQ(mesh.status(heh).bits(), loaded_mesh.status(heh).bits());
1239 }
1240 }
1241 }
1242
1243 // Load no status from file with status
1244 {
1245 Mesh loaded_mesh;
1246 loaded_mesh.request_halfedge_status();
1247 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1248
1249 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1250 EXPECT_TRUE (loaded_mesh.has_halfedge_status()) << "Mesh halfedge status was removed by reading";
1251 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1252 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1253
1254 for (auto heh : loaded_mesh.halfedges())
1255 {
1256 EXPECT_EQ(loaded_mesh.status(heh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
1257 }
1258 }
1259
1260 // Try to load status from file without status
1261 {
1262 Mesh loaded_mesh;
1263 OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
1264
1265 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1266 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1267 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
1268 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
1269 }
1270}
1271
1272
1273/*
1274 * Save and load simple mesh with edge status
1275 */
1276TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyEdgeOnly) {
1277
1278 //read file
1279 Mesh mesh;
1280 auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
1281 auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
1282 auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
1283 mesh.add_face(vh0, vh1, vh2);
1284
1285 mesh.request_edge_status();
1286
1287 auto eh0 = OpenMesh::EdgeHandle(0);
1288 auto eh1 = OpenMesh::EdgeHandle(1);
1289 auto eh2 = OpenMesh::EdgeHandle(2);
1290
1291 mesh.status(eh0).set_selected(true);
1292 mesh.status(eh1).set_feature(true);
1293 mesh.status(eh2).set_tagged(true);
1294 mesh.status(eh0).set_locked(true);
1295 mesh.status(eh1).set_deleted(true);
1296 mesh.status(eh2).set_hidden(true);
1297 mesh.status(eh0).set_fixed_nonmanifold(true);
1298
1299 std::string filename_without_status = "no_edge_status_test.om";
1300 std::string filename_with_status = "edge_status_test.om";
1301
1303 OpenMesh::IO::write_mesh(mesh, filename_without_status);
1304 OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
1305
1306 // Load no status from file with status
1307 {
1308 Mesh loaded_mesh;
1309 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1310
1311 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
1312 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1313 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1314 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1315 }
1316
1317 // Load status from file with status
1318 {
1319 Mesh loaded_mesh;
1320 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
1321
1322 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
1323 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1324 EXPECT_TRUE(loaded_mesh.has_edge_status()) << "Mesh has no edge status even though file should not have a stored status";
1325 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1326
1327 if (loaded_mesh.has_edge_status())
1328 {
1329 for (auto eh : mesh.edges())
1330 {
1331 EXPECT_EQ(mesh.status(eh).bits(), loaded_mesh.status(eh).bits());
1332 }
1333 }
1334 }
1335
1336 // Load no status from file with status
1337 {
1338 Mesh loaded_mesh;
1339 loaded_mesh.request_edge_status();
1340 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1341
1342 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1343 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1344 EXPECT_TRUE (loaded_mesh.has_edge_status()) << "Mesh edge status was removed by reading";
1345 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1346
1347 for (auto eh : loaded_mesh.edges())
1348 {
1349 EXPECT_EQ(loaded_mesh.status(eh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
1350 }
1351 }
1352
1353 // Try to load status from file without status
1354 {
1355 Mesh loaded_mesh;
1356 OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
1357
1358 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1359 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1360 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
1361 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
1362 }
1363}
1364
1365
1366/*
1367 * Save and load simple mesh with face status
1368 */
1369TEST_F(OpenMeshReadWriteOM, WriteReadStatusPropertyFaceOnly) {
1370
1371 //read file
1372 Mesh mesh;
1373 auto vh0 = mesh.add_vertex(Mesh::Point(0,0,0));
1374 auto vh1 = mesh.add_vertex(Mesh::Point(1,0,0));
1375 auto vh2 = mesh.add_vertex(Mesh::Point(0,1,0));
1376 auto vh3 = mesh.add_vertex(Mesh::Point(1,1,0));
1377 auto fh0 = mesh.add_face(vh0, vh1, vh2);
1378 auto fh1 = mesh.add_face(vh2, vh1, vh3);
1379
1380 mesh.request_face_status();
1381
1382 mesh.status(fh0).set_selected(true);
1383 mesh.status(fh1).set_feature(true);
1384 mesh.status(fh0).set_tagged(true);
1385 mesh.status(fh1).set_locked(true);
1386 mesh.status(fh0).set_deleted(true);
1387 mesh.status(fh1).set_hidden(true);
1388 mesh.status(fh0).set_fixed_nonmanifold(true);
1389
1390 std::string filename_without_status = "no_face_status_test.om";
1391 std::string filename_with_status = "face_status_test.om";
1392
1394 OpenMesh::IO::write_mesh(mesh, filename_without_status);
1395 OpenMesh::IO::write_mesh(mesh, filename_with_status, opt_with_status);
1396
1397 // Load no status from file with status
1398 {
1399 Mesh loaded_mesh;
1400 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1401
1402 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should not have been loaded";
1403 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1404 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1405 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though file should not have a stored status";
1406 }
1407
1408 // Load status from file with status
1409 {
1410 Mesh loaded_mesh;
1411 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status, opt_with_status);
1412
1413 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though they should have been loaded";
1414 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1415 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though file should not have a stored status";
1416 EXPECT_TRUE(loaded_mesh.has_face_status()) << "Mesh has no face status even though file should not have a stored status";
1417
1418 if (loaded_mesh.has_face_status())
1419 {
1420 for (auto fh : mesh.faces())
1421 {
1422 EXPECT_EQ(mesh.status(fh).bits(), loaded_mesh.status(fh).bits());
1423 }
1424 }
1425 }
1426
1427 // Load no status from file with status
1428 {
1429 Mesh loaded_mesh;
1430 loaded_mesh.request_face_status();
1431 OpenMesh::IO::read_mesh(loaded_mesh, filename_with_status);
1432
1433 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1434 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1435 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edgestatus even though file should not have a stored status";
1436 EXPECT_TRUE (loaded_mesh.has_face_status()) << "Mesh face status was removed by reading";
1437
1438 for (auto fh : loaded_mesh.faces())
1439 {
1440 EXPECT_EQ(loaded_mesh.status(fh).bits(), 0u) << "Edge status was modified even though it should not have been loaded";
1441 }
1442 }
1443
1444 // Try to load status from file without status
1445 {
1446 Mesh loaded_mesh;
1447 OpenMesh::IO::read_mesh(loaded_mesh, filename_without_status, opt_with_status);
1448
1449 EXPECT_FALSE(loaded_mesh.has_vertex_status()) << "Mesh has vertex status even though file should not have a stored status";
1450 EXPECT_FALSE(loaded_mesh.has_halfedge_status()) << "Mesh has halfedge status even though file should not have a stored status";
1451 EXPECT_FALSE(loaded_mesh.has_edge_status()) << "Mesh has edge status even though they file should not have a stored status";
1452 EXPECT_FALSE(loaded_mesh.has_face_status()) << "Mesh has face status even though they file should not have a stored status";
1453 }
1454}
1455
1456
1457/*
1458 * Just load a triangle mesh from an om file of version 1.2
1459 */
1460TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_1_2) {
1461
1462 mesh_.clear();
1463
1464 std::string file_name = "cube_tri_version_1_2.om";
1465
1466 bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
1467
1468 EXPECT_TRUE(ok) << file_name;
1469
1470 EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
1471 EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
1472 EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
1473 EXPECT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
1474}
1475
1476
1477/*
1478 * Just load a polyhedral mesh from an om file of version 1.2
1479 */
1480TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_1_2) {
1481
1482 PolyMesh mesh;
1483
1484 std::string file_name = "cube_poly_version_1_2.om";
1485
1486 bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
1487
1488 EXPECT_TRUE(ok) << file_name;
1489
1490 EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
1491 EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!";
1492 EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!";
1493 EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!";
1494}
1495
1496
1497/*
1498 * Just load a triangle mesh from an om file of version 2.0
1499 */
1500TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshVersion_2_0) {
1501
1502 mesh_.clear();
1503
1504 std::string file_name = "cube_tri_version_2_0.om";
1505
1506 bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
1507
1508 EXPECT_TRUE(ok) << file_name;
1509
1510 EXPECT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
1511 EXPECT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
1512 EXPECT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
1513 EXPECT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
1514}
1515
1516
1517/*
1518 * Just load a polyhedral mesh from an om file of version 2.0
1519 */
1520TEST_F(OpenMeshReadWriteOM, LoadPolyMeshVersion_2_0) {
1521
1522 PolyMesh mesh;
1523
1524 std::string file_name = "cube_poly_version_2_0.om";
1525
1526 bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
1527
1528 EXPECT_TRUE(ok) << file_name;
1529
1530 EXPECT_EQ(8u , mesh.n_vertices()) << "The number of loaded vertices is not correct!";
1531 EXPECT_EQ(12u , mesh.n_edges()) << "The number of loaded edges is not correct!";
1532 EXPECT_EQ(6u , mesh.n_faces()) << "The number of loaded faces is not correct!";
1533 EXPECT_EQ(24u , mesh.n_halfedges()) << "The number of loaded halfedges is not correct!";
1534}
1535
1536
1537
1538std::string get_type_string(OpenMesh::FaceHandle) { return "Face"; }
1539std::string get_type_string(OpenMesh::EdgeHandle) { return "Edge"; }
1540std::string get_type_string(OpenMesh::HalfedgeHandle) { return "Halfedge"; }
1541std::string get_type_string(OpenMesh::VertexHandle) { return "Vertex"; }
1542
1543std::string get_type_string(char) { return "char"; }
1544std::string get_type_string(signed char) { return "signed char"; }
1545std::string get_type_string(double) { return "double"; }
1546std::string get_type_string(float) { return "float"; }
1547std::string get_type_string(int) { return "int"; }
1548std::string get_type_string(short) { return "short"; }
1549std::string get_type_string(unsigned char) { return "unsigned char"; }
1550std::string get_type_string(unsigned int) { return "unsigned int"; }
1551std::string get_type_string(unsigned short) { return "unsigned short"; }
1552std::string get_type_string(bool) { return "bool"; }
1553std::string get_type_string(std::string) { return "string"; }
1554std::string get_type_string(RegisteredDataType) { return "RegisteredDataType"; }
1555
1556template <typename T>
1557std::string get_type_string(std::vector<T>) { return "std::vector of " + get_type_string(T()); }
1558
1559template <typename T, int Dim>
1560std::string get_type_string(OpenMesh::VectorT<T, Dim>) { return "OM vector of dimension " + std::to_string(Dim) + " of type " + get_type_string(T()); }
1561
1562template <typename T>
1563T get_value(int seed, T, int seed2 = 0)
1564{
1565 return (seed * 3 + seed2) % 20;
1566}
1567
1568std::string get_value(int seed, std::string, int seed2 = 0)
1569{
1570 return std::to_string((seed * 3 + seed2) % 20);
1571}
1572
1573template <typename T>
1574std::vector<T> get_value(int seed, const std::vector<T>&, int _offset = 0)
1575{
1576 int size = get_value(seed, 3);
1577 std::vector<T> res(size);
1578 for (int i = 0; i < size; ++i)
1579 res[i] = get_value(seed, T(), i + _offset);
1580 return res;
1581}
1582
1583template <typename T, int Dim>
1584OpenMesh::VectorT<T, Dim> get_value(int seed, const OpenMesh::VectorT<T, Dim>&)
1585{
1587 for (int i = 0; i < Dim; ++i)
1588 res[i] = get_value(seed, T(), i);
1589 return res;
1590}
1591
1592template <typename MeshT, typename HandleT, typename T>
1593OpenMesh::Prop<HandleT, T> add_property(MeshT& _mesh)
1594{
1595 std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
1596 OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
1597 _mesh.property(prop.getRawProperty()).set_persistent(true);
1598 for (auto e : _mesh.template elements<HandleT>())
1599 prop[e] = get_value(e.idx(), T());
1600
1601 return prop;
1602}
1603
1604template <typename MeshT, typename HandleT, typename T>
1605void check_property(MeshT& _mesh)
1606{
1607 std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
1608 bool has_prop = OpenMesh::hasProperty<HandleT, T>(_mesh, name.c_str());
1609 EXPECT_TRUE(has_prop) << "Property " << name << " is not available";
1610 if (!has_prop)
1611 return;
1612 OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
1613 for (auto e : _mesh.template elements<HandleT>())
1614 EXPECT_EQ(prop[e], get_value(e.idx(), T())) << "For property " << name;
1615}
1616
1617template <typename MeshT, typename HandleT, typename T>
1618void request_property(MeshT& _mesh)
1619{
1620 std::string name = get_type_string(HandleT()) + ": " + get_type_string(T());
1621 OpenMesh::Prop<HandleT, T> prop(_mesh, name.c_str());
1622}
1623
1624
1625enum class PropertyAction
1626{
1627 Add, Check, Request
1628};
1629
1630// For a given Handle and Type add, check or request a property
1631template <typename MeshT, typename HandleT, typename T>
1632void do_property(MeshT& _mesh, PropertyAction action)
1633{
1634 switch (action)
1635 {
1636 case PropertyAction::Add:
1637 add_property<MeshT, HandleT, T>(_mesh);
1638 break;
1639 case PropertyAction::Check:
1640 check_property<MeshT, HandleT, T>(_mesh);
1641 break;
1642 case PropertyAction::Request:
1643 request_property<MeshT, HandleT, T>(_mesh);
1644 break;
1645 }
1646}
1647
1648// for a given handle do action for OpenMesh Vector of dimension Dim with many differnt types
1649template <typename MeshT, typename HandleT, int Dim>
1650void do_all_property_types_vec(MeshT& _mesh, PropertyAction action)
1651{
1652 do_property<MeshT, HandleT, OpenMesh::VectorT<signed char , Dim>>(_mesh, action);
1653 do_property<MeshT, HandleT, OpenMesh::VectorT<double , Dim>>(_mesh, action);
1654 do_property<MeshT, HandleT, OpenMesh::VectorT<float , Dim>>(_mesh, action);
1655 do_property<MeshT, HandleT, OpenMesh::VectorT<int , Dim>>(_mesh, action);
1656 do_property<MeshT, HandleT, OpenMesh::VectorT<short , Dim>>(_mesh, action);
1657 do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned char , Dim>>(_mesh, action);
1658 do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned int , Dim>>(_mesh, action);
1659 do_property<MeshT, HandleT, OpenMesh::VectorT<unsigned short, Dim>>(_mesh, action);
1660}
1661
1662// for a given handle do action for OpenMesh Vectors of dimensions 1 to 4
1663template <typename MeshT, typename HandleT>
1664void do_all_property_types_vec_all_dim(MeshT& _mesh, PropertyAction action)
1665{
1666 do_all_property_types_vec<MeshT, HandleT, 1>(_mesh, action);
1667 do_all_property_types_vec<MeshT, HandleT, 2>(_mesh, action);
1668 do_all_property_types_vec<MeshT, HandleT, 3>(_mesh, action);
1669 do_all_property_types_vec<MeshT, HandleT, 4>(_mesh, action);
1670}
1671
1672// for a given handle type do action for many different types
1673template <typename MeshT, typename HandleT>
1674void do_all_property_types(MeshT& _mesh, PropertyAction action, int version)
1675{
1676 do_property<MeshT, HandleT, int> (_mesh, action);
1677 do_property<MeshT, HandleT, double> (_mesh, action);
1678 do_property<MeshT, HandleT, float> (_mesh, action);
1679 do_property<MeshT, HandleT, char> (_mesh, action);
1680 do_property<MeshT, HandleT, bool> (_mesh, action);
1681 do_property<MeshT, HandleT, std::string> (_mesh, action);
1682 do_property<MeshT, HandleT, RegisteredDataType> (_mesh, action);
1683
1684 if(version >= 22)
1685 {
1686 do_property<MeshT, HandleT, std::vector<int>> (_mesh, action);
1687 do_property<MeshT, HandleT, std::vector<double>> (_mesh, action);
1688 do_property<MeshT, HandleT, std::vector<float>> (_mesh, action);
1689 do_property<MeshT, HandleT, std::vector<char>> (_mesh, action);
1690 do_property<MeshT, HandleT, std::vector<bool>> (_mesh, action);
1691 do_property<MeshT, HandleT, std::vector<std::string>> (_mesh, action);
1692 do_property<MeshT, HandleT, std::vector<RegisteredDataType>> (_mesh, action);
1693
1694 do_property<MeshT, HandleT, std::vector<std::vector<int>>> (_mesh, action);
1695 do_property<MeshT, HandleT, std::vector<std::vector<double>>> (_mesh, action);
1696 do_property<MeshT, HandleT, std::vector<std::vector<float>>> (_mesh, action);
1697 do_property<MeshT, HandleT, std::vector<std::vector<char>>> (_mesh, action);
1698 do_property<MeshT, HandleT, std::vector<std::vector<bool>>> (_mesh, action);
1699 do_property<MeshT, HandleT, std::vector<std::vector<std::string>>> (_mesh, action);
1700 do_property<MeshT, HandleT, std::vector<std::vector<RegisteredDataType>>> (_mesh, action);
1701
1702 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<int>>>> (_mesh, action);
1703 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<double>>>> (_mesh, action);
1704 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<float>>>> (_mesh, action);
1705 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<char>>>> (_mesh, action);
1706 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<bool>>>> (_mesh, action);
1707 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<std::string>>>> (_mesh, action);
1708 do_property<MeshT, HandleT, std::vector<std::vector<std::vector<RegisteredDataType>>>> (_mesh, action);
1709 }
1710
1711 do_all_property_types_vec_all_dim<MeshT, HandleT>(_mesh, action);
1712}
1713
1714// Do action for all property types for faces, edges, halfedges and vertices
1715template <typename MeshT>
1716void do_all_properties(MeshT& _mesh, PropertyAction action, int version)
1717{
1718 do_all_property_types<MeshT,OpenMesh::FaceHandle> (_mesh, action, version);
1719 do_all_property_types<MeshT,OpenMesh::EdgeHandle> (_mesh, action, version);
1720 do_all_property_types<MeshT,OpenMesh::HalfedgeHandle>(_mesh, action, version);
1721 do_all_property_types<MeshT,OpenMesh::VertexHandle> (_mesh, action, version);
1722}
1723
1724template <typename MeshT> void add_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Add , version); }
1725template <typename MeshT> void check_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Check , version); }
1726template <typename MeshT> void request_all_properties(MeshT& _mesh, int version) { do_all_properties(_mesh, PropertyAction::Request, version); }
1727
1728/*
1729 * Load a triangle mesh from an om file of version 2.1 with properties
1730 */
1731TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshWithPropertiesVersion_2_1) {
1732
1733 int version = 21;
1734 mesh_.clear();
1735
1736 std::string file_name = "cube_tri_with_properties_2_1.om";
1737
1738 request_all_properties(mesh_, version);
1739 bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
1740
1741 ASSERT_TRUE(ok) << file_name;
1742
1743 ASSERT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
1744 ASSERT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
1745 ASSERT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
1746 ASSERT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
1747
1748 check_all_properties(mesh_, version);
1749}
1750
1751/*
1752 * store and load a triangle mesh from an om file of the current version with properties
1753 */
1754TEST_F(OpenMeshReadWriteOM, LoadTriangleMeshWithPropertiesCurrentVersion) {
1755
1756 // TODO: create a LoadTriangleMeshWithPropertiesVersion_2_2 unittest from the file resulting from this test
1757 // so we will keep testing version 2.2 in the future.
1758
1759 int version = 22;
1760 mesh_.clear();
1761
1762 std::string file_name = "cube_tri_version_2_0.om";
1763
1764 bool ok = OpenMesh::IO::read_mesh(mesh_, file_name);
1765
1766 ASSERT_TRUE(ok) << file_name;
1767 ASSERT_EQ(8u , mesh_.n_vertices()) << "The number of loaded vertices is not correct!";
1768 ASSERT_EQ(18u , mesh_.n_edges()) << "The number of loaded edges is not correct!";
1769 ASSERT_EQ(12u , mesh_.n_faces()) << "The number of loaded faces is not correct!";
1770 ASSERT_EQ(36u , mesh_.n_halfedges()) << "The number of loaded halfedges is not correct!";
1771
1772 add_all_properties(mesh_, version);
1773 mesh_.request_halfedge_texcoords2D();
1774
1775 std::string file_name_2_2 = "cube_tri_with_properties_2_2.om";
1778
1779 OpenMesh::IO::write_mesh(mesh_, file_name_2_2, ops);
1780
1781 Mesh new_mesh;
1782 OpenMesh::IO::read_mesh(new_mesh, file_name_2_2, ops);
1783
1784 check_all_properties(new_mesh, version);
1785 EXPECT_TRUE(new_mesh.has_halfedge_texcoords2D());
1786}
1787
1788/*
1789 * Try to load mesh from om file with a version that is not yet supported
1790 */
1791TEST_F(OpenMeshReadWriteOM, LoadTriMeshVersion_7_5) {
1792
1793 PolyMesh mesh;
1794
1795 std::string file_name = "cube_tri_version_7_5.om";
1796
1797 bool ok = OpenMesh::IO::read_mesh(mesh, file_name);
1798
1799 EXPECT_FALSE(ok) << file_name;
1800}
1801
1802
1803/*
1804 * Try to write and load positions and normals that can only be represented by doubles
1805 */
1806TEST_F(OpenMeshReadWriteOM, WriteAndLoadDoubles) {
1807
1809
1810 DoublePolyMesh mesh;
1811 mesh.request_vertex_normals();
1812 mesh.request_face_normals();
1813
1814 std::vector<OpenMesh::VertexHandle> vertices;
1815 for (int i = 0; i < 3; ++i)
1816 {
1817 vertices.push_back(mesh.add_vertex(DoublePolyMesh::Point(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max())));
1818 mesh.set_normal(vertices.back(), DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max()));
1819 }
1820 auto fh = mesh.add_face(vertices);
1821 mesh.set_normal(fh, DoublePolyMesh::Normal(1.0/3.0, std::numeric_limits<double>::min(), std::numeric_limits<double>::max()));
1822
1823 std::string file_name = "doubles.om";
1824
1826 ASSERT_TRUE(OpenMesh::IO::write_mesh(mesh, file_name, opt)) << "Could not write file " << file_name;
1827
1828 DoublePolyMesh mesh2;
1829 mesh2.request_vertex_normals();
1830 mesh2.request_face_normals();
1831
1832 ASSERT_TRUE(OpenMesh::IO::read_mesh(mesh2, file_name, opt)) << "Could not read file " << file_name;
1833
1834 EXPECT_EQ(mesh.point(OpenMesh::VertexHandle(0)), mesh2.point(OpenMesh::VertexHandle(0)));
1835 EXPECT_EQ(mesh.normal(OpenMesh::VertexHandle(0)), mesh2.normal(OpenMesh::VertexHandle(0)));
1836 EXPECT_EQ(mesh.normal(OpenMesh::FaceHandle(0)), mesh2.normal(OpenMesh::FaceHandle(0)));
1837}
1838
1839/*
1840 * Create Property from String
1841 */
1842TEST_F(OpenMeshReadWriteOM, PropertyFromString)
1843{
1844 {
1845 std::string int_prop_name = "my int prop";
1846 OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "int32_t", int_prop_name);
1847 bool has_int_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, int>(mesh_, int_prop_name.c_str());
1848 EXPECT_TRUE(has_int_prop);
1849 }
1850
1851 {
1852 std::string double_prop_name = "my double prop";
1853 OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "double", double_prop_name);
1854 bool has_double_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, double>(mesh_, double_prop_name.c_str());
1855 EXPECT_TRUE(has_double_prop);
1856 }
1857
1858 {
1859 std::string vec_float_prop_name = "my vector of floats prop";
1860 OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "std::vector<float>", vec_float_prop_name);
1861 bool has_vec_float_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, std::vector<float>>(mesh_, vec_float_prop_name.c_str());
1862 EXPECT_TRUE(has_vec_float_prop);
1863 }
1864
1865 {
1866 std::string MyData_prop_name = "my MyData prop";
1867 OpenMesh::create_property_from_string<OpenMesh::VertexHandle>(mesh_, "RegisteredDataType", MyData_prop_name);
1868 bool has_myData_prop = OpenMesh::hasProperty<OpenMesh::VertexHandle, RegisteredDataType>(mesh_, MyData_prop_name.c_str());
1869 EXPECT_TRUE(has_myData_prop);
1870 }
1871}
1872
1873
1874/*
1875 * Try to write and load bool property
1876 */
1877TEST_F(OpenMeshReadWriteOM, WriteAndLoadBoolCheckSpaces) {
1878
1880
1881 DoublePolyMesh mesh;
1882
1884 mesh.add_property(prop,"VBProp");
1885 mesh.property(prop).set_persistent(true);
1886
1887
1888 // Generate a bool property which will be packed into a space character
1889
1890 std::vector<OpenMesh::VertexHandle> vertices;
1891 for (unsigned int i = 0; i < 8; ++i)
1892 {
1893 vertices.push_back(mesh.add_vertex(DoublePolyMesh::Point(0.0, 0.0, 0.0)));
1894
1895 if ( i == 5)
1896 mesh.property(prop,vertices[i]) = true;
1897 else
1898 mesh.property(prop,vertices[i]) = false;
1899 }
1900
1901 std::string file_name = "bool-space-test.om";
1902
1904 ASSERT_TRUE(OpenMesh::IO::write_mesh(mesh, file_name, opt)) << "Could not write file " << file_name;
1905
1906
1907 // ====================================================
1908 // Now read it back
1909 // ====================================================
1910
1911 DoublePolyMesh mesh2;
1913 mesh2.add_property(prop2,"VBProp");
1914 mesh2.property(prop2).set_persistent(true);
1915
1916 ASSERT_TRUE(OpenMesh::IO::read_mesh(mesh2, file_name, opt)) << "Could not read file " << file_name;
1917
1918 // Check if the property is still ok
1919 for (unsigned int i = 0; i < 8; ++i)
1920 {
1921 if ( i == 5)
1922 EXPECT_TRUE( mesh.property(prop,mesh2.vertex_handle((i)) ) );
1923 else
1924 EXPECT_FALSE(mesh.property(prop,mesh2.vertex_handle((i))));
1925 }
1926}
1927
1928}
1929
1930OM_REGISTER_PROPERTY_TYPE(RegisteredDataType)
1931OM_REGISTER_PROPERTY_TYPE(std::vector<std::string>)
1932OM_REGISTER_PROPERTY_TYPE(std::vector<float>)
1933OM_REGISTER_PROPERTY_TYPE(std::vector<RegisteredDataType>)
1934OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<int>>)
1935OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<double>>)
1936OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<float>>)
1937OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<char>>)
1938OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<bool>>)
1939OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::string>>)
1940OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<RegisteredDataType>>)
1941OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<int>>>)
1942OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<double>>>)
1943OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<float>>>)
1944OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<char>>>)
1945OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<bool>>>)
1946OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<std::string>>>)
1947OM_REGISTER_PROPERTY_TYPE(std::vector<std::vector<std::vector<RegisteredDataType>>>)
Set options for reader/writer modules.
Definition Options.hh:92
@ ColorFloat
Has (r) / store (w) float values for colors (currently only implemented for PLY and OFF files)
Definition Options.hh:113
@ FaceNormal
Has (r) / store (w) face normals.
Definition Options.hh:109
@ FaceTexCoord
Has (r) / store (w) face texture coordinates.
Definition Options.hh:111
@ Default
By default write persistent custom properties.
Definition Options.hh:117
@ Status
Has (r) / store (w) status properties.
Definition Options.hh:115
@ VertexNormal
Has (r) / store (w) vertex normals.
Definition Options.hh:105
@ VertexTexCoord
Has (r) / store (w) texture coordinates.
Definition Options.hh:107
@ VertexColor
Has (r) / store (w) vertex colors.
Definition Options.hh:106
@ Custom
Has (r) / store (w) custom properties marked persistent (currently PLY only supports reading and only...
Definition Options.hh:114
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
Kernel::EdgeHandle EdgeHandle
Scalar type.
Definition PolyMeshT.hh:138
Kernel::FaceIter FaceIter
Scalar type.
Definition PolyMeshT.hh:146
SmartVertexHandle add_vertex(const Point _p)
Definition PolyMeshT.hh:255
Kernel::FaceHandle FaceHandle
Scalar type.
Definition PolyMeshT.hh:139
Kernel::HalfedgeHandle HalfedgeHandle
Scalar type.
Definition PolyMeshT.hh:137
Kernel::Point Point
Coordinate type.
Definition PolyMeshT.hh:112
Kernel::Color Color
Color type.
Definition PolyMeshT.hh:116
Kernel::VertexIter VertexIter
Scalar type.
Definition PolyMeshT.hh:143
SmartVertexHandle split(EdgeHandle _eh, const Point &_p)
Edge split (= 2-to-4 split)
Definition TriMeshT.hh:275
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:190
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
Definition MeshIO.hh:95
Handle for a edge entity.
Definition Handles.hh:135
Handle for a face entity.
Definition Handles.hh:142
Handle for a halfedge entity.
Definition Handles.hh:128
static size_t restore(std::istream &, value_type &, bool=false, bool=true)
Restore a value of T and return the number of bytes read.
Definition SR_binary.hh:125
static const bool is_streamable
Can we store T? Set this to true in your specialization.
Definition SR_binary.hh:101
static std::string type_identifier(void)
A string that identifies the type of T.
Definition SR_binary.hh:109
static size_t size_of(void)
What's the size of T? If it depends on the actual value (e.g. for vectors) return UnknownSize.
Definition SR_binary.hh:104
Handle for a vertex entity.
Definition Handles.hh:121