2 #include <gtest/gtest.h> 3 #include <OpenMesh/Core/Utils/PropertyManager.hh> 4 #include <Unittests/unittests_common.hh> 7 #include "generate_cube.hh" 8 #include "fill_props.hh" 24 : ival(0), dval(0.0), bval(
false)
28 : ival(_cpy.ival), dval(_cpy.dval), bval(_cpy.bval),
29 vec4fval(_cpy.vec4fval)
39 vec4fval = _rhs.vec4fval;
43 MyData& operator = (
int _rhs) { ival = _rhs;
return *
this; }
44 MyData& operator = (
double _rhs) { dval = _rhs;
return *
this; }
45 MyData& operator = (
bool _rhs) { bval = _rhs;
return *
this; }
47 { vec4fval = _rhs;
return *
this; }
51 bool operator == (
const MyData& _rhs)
const 53 return ival == _rhs.ival
56 && vec4fval == _rhs.vec4fval;
58 bool operator != (
const MyData& _rhs)
const {
return !(*
this == _rhs); }
61 typedef std::map< std::string, unsigned int > MyMap;
77 static size_t size_of(
const value_type&)
82 static size_t store(std::ostream& _os,
const value_type& _v,
bool _swap=
false)
85 bytes = IO::store( _os, _v.ival, _swap );
86 bytes += IO::store( _os, _v.dval, _swap );
87 bytes += IO::store( _os, _v.bval, _swap );
88 bytes += IO::store( _os, _v.vec4fval, _swap );
89 return _os.good() ? bytes : 0;
92 static size_t restore( std::istream& _is, value_type& _v,
bool _swap=
false)
95 bytes = IO::restore( _is, _v.ival, _swap );
96 bytes += IO::restore( _is, _v.dval, _swap );
97 bytes += IO::restore( _is, _v.bval, _swap );
98 bytes += IO::restore( _is, _v.vec4fval, _swap );
99 return _is.good() ? bytes : 0;
105 typedef MyMap value_type;
109 static size_t size_of(
void) {
return UnknownSize; }
112 static size_t size_of(
const value_type& _v)
115 return sizeof(
unsigned int);
117 value_type::const_iterator it = _v.begin();
118 unsigned int N = _v.size();
119 size_t bytes = IO::size_of(N);
120 for(;it!=_v.end(); ++it)
122 bytes += IO::size_of( it->first );
123 bytes += IO::size_of( it->second );
129 size_t store(std::ostream& _os,
const value_type& _v,
bool _swap=
false)
132 unsigned int N = _v.size();
133 value_type::const_iterator it = _v.begin();
134 bytes += IO::store( _os, N, _swap );
135 for (; it != _v.end() && _os.good(); ++it)
137 bytes += IO::store( _os, it->first, _swap );
138 bytes += IO::store( _os, it->second, _swap );
140 return _os.good() ? bytes : 0;
144 size_t restore( std::istream& _is, value_type& _v,
bool _swap=
false)
149 bytes += IO::restore( _is, N, _swap );
150 value_type::key_type key;
151 value_type::mapped_type val;
152 for (
size_t i=0; i<N && _is.good(); ++i)
154 bytes += IO::restore( _is, key, _swap );
155 bytes += IO::restore( _is, val, _swap );
158 return _is.good() ? bytes : 0;
172 virtual void SetUp() {
178 virtual void TearDown() {
193 template <
class Mesh>
class SmootherT
201 explicit SmootherT(
Mesh& _mesh)
204 mesh_.add_property( cog_ );
208 mesh_.remove_property( cog_ );
211 void smooth(
unsigned int _iterations)
213 for (
unsigned int i=0; i < _iterations; ++i)
215 std::for_each(mesh_.vertices_begin(),
216 mesh_.vertices_end(),
217 ComputeCOG(mesh_, cog_));
218 std::for_each(mesh_.vertices_begin(),
219 mesh_.vertices_end(),
220 SetCOG(mesh_, cog_));
229 ComputeCOG(
Mesh& _mesh, Property_cog& _cog)
230 : mesh_(_mesh), cog_(_cog)
237 mesh_.property(cog_, _vh) =
typename Mesh::Point(0.0, 0.0, 0.0);
238 for (vv_it=mesh_.vv_iter(_vh); vv_it.is_valid(); ++vv_it)
240 mesh_.property(cog_, _vh) += mesh_.point( *vv_it );
243 mesh_.property(cog_, _vh ) /= valence;
253 SetCOG(
Mesh& _mesh, Property_cog& _cog)
254 : mesh_(_mesh), cog_(_cog)
258 if (!mesh_.is_boundary(_vh))
259 mesh_.set_point( _vh, mesh_.property(cog_, _vh) );
308 VertexT() : cog_( Point(0.0f, 0.0f, 0.0f ) ) { }
309 const Point& cog()
const {
return cog_; }
310 void set_cog(
const Point& _p) { cog_ = _p; }
341 TEST_F(OpenMeshTutorials, building_a_cube) {
357 std::vector<MyMesh::VertexHandle> face_vhandles;
358 face_vhandles.clear();
359 face_vhandles.push_back(vhandle[0]);
360 face_vhandles.push_back(vhandle[1]);
361 face_vhandles.push_back(vhandle[2]);
362 face_vhandles.push_back(vhandle[3]);
363 mesh.add_face(face_vhandles);
365 face_vhandles.clear();
366 face_vhandles.push_back(vhandle[7]);
367 face_vhandles.push_back(vhandle[6]);
368 face_vhandles.push_back(vhandle[5]);
369 face_vhandles.push_back(vhandle[4]);
370 mesh.add_face(face_vhandles);
371 face_vhandles.clear();
372 face_vhandles.push_back(vhandle[1]);
373 face_vhandles.push_back(vhandle[0]);
374 face_vhandles.push_back(vhandle[4]);
375 face_vhandles.push_back(vhandle[5]);
376 mesh.add_face(face_vhandles);
377 face_vhandles.clear();
378 face_vhandles.push_back(vhandle[2]);
379 face_vhandles.push_back(vhandle[1]);
380 face_vhandles.push_back(vhandle[5]);
381 face_vhandles.push_back(vhandle[6]);
382 mesh.add_face(face_vhandles);
383 face_vhandles.clear();
384 face_vhandles.push_back(vhandle[3]);
385 face_vhandles.push_back(vhandle[2]);
386 face_vhandles.push_back(vhandle[6]);
387 face_vhandles.push_back(vhandle[7]);
388 mesh.add_face(face_vhandles);
389 face_vhandles.clear();
390 face_vhandles.push_back(vhandle[0]);
391 face_vhandles.push_back(vhandle[3]);
392 face_vhandles.push_back(vhandle[7]);
393 face_vhandles.push_back(vhandle[4]);
394 mesh.add_face(face_vhandles);
398 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'output.off'";
401 TEST_F(OpenMeshTutorials, using_iterators_and_circulators) {
406 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
409 std::vector<MyMesh::Point> cogs;
410 std::vector<MyMesh::Point>::iterator cog_it;
411 cogs.reserve(mesh.n_vertices());
414 MyMesh::VertexIter v_it, v_end(mesh.vertices_end());
418 unsigned int i, N(100);
419 for (i=0; i < N; ++i)
422 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
424 cog[0] = cog[1] = cog[2] = valence = 0.0;
426 for (vv_it = mesh.vv_iter( *v_it ); vv_it.is_valid(); ++vv_it)
428 cog += mesh.point( *vv_it );
431 cogs.push_back(cog / valence);
434 for (v_it = mesh.vertices_begin(), cog_it = cogs.begin();
435 v_it != v_end; ++v_it, ++cog_it)
436 if ( !mesh.is_boundary( *v_it ) )
437 mesh.set_point( *v_it, *cog_it );
443 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_output.off'";
446 TEST_F(OpenMeshTutorials, using_custom_properties) {
450 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
452 const int iterations = 100;
459 for (
int i = 0; i < iterations; ++i) {
461 for (
const auto& vh : mesh.vertices()) {
465 for (
const auto& vvh : mesh.vv_range(vh)) {
466 cog[vh] += mesh.point(vvh);
472 for (
const auto& vh : mesh.vertices()) {
473 mesh.point(vh) = cog[vh];
481 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_custom_properties_output.off'";
484 TEST_F(OpenMeshTutorials, using_STL_algorithms) {
485 MyMeshWithTraits mesh;
488 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
490 SmootherT<MyMeshWithTraits> smoother(mesh);
491 smoother.smooth(100);
496 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_STL_output.off'";
499 TEST_F(OpenMeshTutorials, using_standard_properties) {
502 mesh.request_vertex_normals();
503 EXPECT_TRUE(mesh.has_vertex_normals()) <<
"Standard vertex property 'Normals' not available";
507 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
513 mesh.request_face_normals();
515 mesh.update_normals();
517 mesh.release_face_normals();
521 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
522 v_it != mesh.vertices_end(); ++v_it)
524 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
528 mesh.release_vertex_normals();
530 EXPECT_FALSE(mesh.has_vertex_normals()) <<
"Shouldn't have any vertex normals anymore";
533 TEST_F(OpenMeshTutorials, using_mesh_attributes_and_traits) {
538 typeid(
double)) <<
"Data type is wrong";
542 typeid(
double)) <<
"Data type is wrong";
545 mesh.request_vertex_normals();
547 mesh.request_face_normals();
552 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
556 mesh.has_face_normals() && mesh.has_vertex_normals() )
559 mesh.update_normals();
563 for (MyMesh::VertexIter v_it = mesh.vertices_begin();
564 v_it != mesh.vertices_end(); ++v_it)
566 mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
570 TEST_F(OpenMeshTutorials, extending_the_mesh_using_traits) {
571 MyTriMeshWithCOG mesh;
574 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'output.off'";
577 MyTriMeshWithCOG::VertexIter v_it, v_end(mesh.vertices_end());
578 MyTriMeshWithCOG::VertexVertexIter vv_it;
579 MyTriMeshWithCOG::Point cog;
580 MyTriMeshWithCOG::Scalar valence;
581 unsigned int i, N(100);
583 for (i=0; i < N; ++i)
585 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
587 cog[0] = cog[1] = cog[2] = valence = 0.0;
589 for (vv_it = mesh.vv_iter(*v_it); vv_it.is_valid(); ++vv_it)
591 cog += mesh.point( *vv_it );
594 mesh.data(*v_it).set_cog(cog / valence);
597 for (v_it = mesh.vertices_begin(); v_it != v_end; ++v_it)
598 if (!mesh.is_boundary(*v_it))
599 mesh.set_point( *v_it, mesh.data(*v_it).cog());
605 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_extended_output.off'";
609 TEST_F(OpenMeshTutorials, deleting_geometry_elements) {
613 mesh.request_face_status();
614 mesh.request_edge_status();
615 mesh.request_vertex_status();
619 Mesh::FaceHandle fhandle[6];
631 std::vector<Mesh::VertexHandle> tmp_face_vhandles;
632 tmp_face_vhandles.clear();
633 tmp_face_vhandles.push_back(vhandle[0]);
634 tmp_face_vhandles.push_back(vhandle[1]);
635 tmp_face_vhandles.push_back(vhandle[2]);
636 tmp_face_vhandles.push_back(vhandle[3]);
637 fhandle[0] = mesh.add_face(tmp_face_vhandles);
639 tmp_face_vhandles.clear();
640 tmp_face_vhandles.push_back(vhandle[7]);
641 tmp_face_vhandles.push_back(vhandle[6]);
642 tmp_face_vhandles.push_back(vhandle[5]);
643 tmp_face_vhandles.push_back(vhandle[4]);
644 fhandle[1] = mesh.add_face(tmp_face_vhandles);
646 tmp_face_vhandles.clear();
647 tmp_face_vhandles.push_back(vhandle[1]);
648 tmp_face_vhandles.push_back(vhandle[0]);
649 tmp_face_vhandles.push_back(vhandle[4]);
650 tmp_face_vhandles.push_back(vhandle[5]);
651 fhandle[2] = mesh.add_face(tmp_face_vhandles);
653 tmp_face_vhandles.clear();
654 tmp_face_vhandles.push_back(vhandle[2]);
655 tmp_face_vhandles.push_back(vhandle[1]);
656 tmp_face_vhandles.push_back(vhandle[5]);
657 tmp_face_vhandles.push_back(vhandle[6]);
658 fhandle[3] = mesh.add_face(tmp_face_vhandles);
659 tmp_face_vhandles.clear();
660 tmp_face_vhandles.push_back(vhandle[3]);
661 tmp_face_vhandles.push_back(vhandle[2]);
662 tmp_face_vhandles.push_back(vhandle[6]);
663 tmp_face_vhandles.push_back(vhandle[7]);
664 fhandle[4] = mesh.add_face(tmp_face_vhandles);
666 tmp_face_vhandles.clear();
667 tmp_face_vhandles.push_back(vhandle[0]);
668 tmp_face_vhandles.push_back(vhandle[3]);
669 tmp_face_vhandles.push_back(vhandle[7]);
670 tmp_face_vhandles.push_back(vhandle[4]);
671 fhandle[5] = mesh.add_face(tmp_face_vhandles);
677 EXPECT_FALSE(mesh.status(fhandle[0]).deleted()) <<
"face shouldn't be deleted";
678 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) <<
"face shouldn't be deleted";
679 EXPECT_FALSE(mesh.status(fhandle[2]).deleted()) <<
"face shouldn't be deleted";
680 EXPECT_FALSE(mesh.status(fhandle[3]).deleted()) <<
"face shouldn't be deleted";
681 EXPECT_FALSE(mesh.status(fhandle[4]).deleted()) <<
"face shouldn't be deleted";
682 EXPECT_FALSE(mesh.status(fhandle[5]).deleted()) <<
"face shouldn't be deleted";
685 mesh.delete_face(fhandle[0],
false);
687 mesh.delete_face(fhandle[2],
false);
689 mesh.delete_face(fhandle[3],
false);
691 mesh.delete_face(fhandle[4],
false);
693 mesh.delete_face(fhandle[5],
false);
695 EXPECT_TRUE(mesh.status(fhandle[0]).deleted()) <<
"face should be deleted";
696 EXPECT_FALSE(mesh.status(fhandle[1]).deleted()) <<
"face shouldn't be deleted";
697 EXPECT_TRUE(mesh.status(fhandle[2]).deleted()) <<
"face should be deleted";
698 EXPECT_TRUE(mesh.status(fhandle[3]).deleted()) <<
"face should be deleted";
699 EXPECT_TRUE(mesh.status(fhandle[4]).deleted()) <<
"face should be deleted";
700 EXPECT_TRUE(mesh.status(fhandle[5]).deleted()) <<
"face should be deleted";
708 EXPECT_FALSE(mesh.status(vhandle[0]).deleted()) <<
"vertex shouldn't be deleted";
709 EXPECT_FALSE(mesh.status(vhandle[1]).deleted()) <<
"vertex shouldn't be deleted";
710 EXPECT_FALSE(mesh.status(vhandle[2]).deleted()) <<
"vertex shouldn't be deleted";
711 EXPECT_FALSE(mesh.status(vhandle[3]).deleted()) <<
"vertex shouldn't be deleted";
714 mesh.delete_vertex(vhandle[0],
false);
715 mesh.delete_vertex(vhandle[1],
false);
716 mesh.delete_vertex(vhandle[2],
false);
717 mesh.delete_vertex(vhandle[3],
false);
720 EXPECT_TRUE(mesh.status(vhandle[0]).deleted()) <<
"vertex should be deleted";
721 EXPECT_TRUE(mesh.status(vhandle[1]).deleted()) <<
"vertex should be deleted";
722 EXPECT_TRUE(mesh.status(vhandle[2]).deleted()) <<
"vertex should be deleted";
723 EXPECT_TRUE(mesh.status(vhandle[3]).deleted()) <<
"vertex should be deleted";
727 mesh.garbage_collection();
732 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'deleted_output.off'";
736 TEST_F(OpenMeshTutorials, storing_custom_properties) {
740 generate_cube<MyMesh>(mesh);
750 mesh.add_property(vprop_float,
"vprop_float");
751 mesh.add_property(eprop_bool,
"eprop_bool");
752 mesh.add_property(fprop_string,
"fprop_string");
753 mesh.add_property(hprop_mydata,
"hprop_mydata");
754 mesh.add_property(mprop_map,
"mprop_map");
757 fill_props(mesh, vprop_float);
758 fill_props(mesh, eprop_bool);
759 fill_props(mesh, fprop_string);
760 fill_props(mesh, hprop_mydata);
761 fill_props(mesh, mprop_map);
763 EXPECT_TRUE(fill_props(mesh, vprop_float,
true)) <<
"property not filled correctly";
764 EXPECT_TRUE(fill_props(mesh, eprop_bool,
true)) <<
"property not filled correctly";
765 EXPECT_TRUE(fill_props(mesh, fprop_string,
true)) <<
"property not filled correctly";
766 EXPECT_TRUE(fill_props(mesh, hprop_mydata,
true)) <<
"property not filled correctly";
767 EXPECT_TRUE(fill_props(mesh, mprop_map,
true)) <<
"property not filled correctly";
770 mesh.property(vprop_float).set_persistent(
true);
771 EXPECT_TRUE(mesh.property(vprop_float).persistent()) <<
"property should be persistent";
772 mesh.property(eprop_bool).set_persistent(
true);
773 EXPECT_TRUE(mesh.property(eprop_bool).persistent()) <<
"property should be persistent";
774 mesh.property(fprop_string).set_persistent(
true);
775 EXPECT_TRUE(mesh.property(fprop_string).persistent()) <<
"property should be persistent";
776 mesh.property(hprop_mydata).set_persistent(
true);
777 EXPECT_TRUE(mesh.property(hprop_mydata).persistent()) <<
"property should be persistent";
778 mesh.mproperty(mprop_map).set_persistent(
true);
779 EXPECT_TRUE(mesh.mproperty(mprop_map).persistent()) <<
"property should be persistent";
783 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'persistent-check.om'";
790 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'persistent-check.om'";
793 EXPECT_TRUE(fill_props(mesh, vprop_float,
true)) <<
"property not filled correctly";
794 EXPECT_TRUE(fill_props(mesh, eprop_bool,
true)) <<
"property not filled correctly";
795 EXPECT_TRUE(fill_props(mesh, fprop_string,
true)) <<
"property not filled correctly";
796 EXPECT_TRUE(fill_props(mesh, hprop_mydata,
true)) <<
"property not filled correctly";
797 EXPECT_TRUE(fill_props(mesh, mprop_map,
true)) <<
"property not filled correctly";
802 TEST_F(OpenMeshTutorials, flipping_edges) {
811 std::vector<Mesh::VertexHandle> face_vhandles;
812 face_vhandles.push_back(vhandle[2]);
813 face_vhandles.push_back(vhandle[1]);
814 face_vhandles.push_back(vhandle[0]);
815 mesh.add_face(face_vhandles);
816 face_vhandles.clear();
817 face_vhandles.push_back(vhandle[2]);
818 face_vhandles.push_back(vhandle[0]);
819 face_vhandles.push_back(vhandle[3]);
820 mesh.add_face(face_vhandles);
824 for(Mesh::EdgeIter it = mesh.edges_begin(); it != mesh.edges_end(); ++it) {
825 if(!mesh.is_boundary(*it)) {
827 EXPECT_EQ(vhandle[2].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) <<
"expected vertex handle 2!" ;
828 EXPECT_EQ(vhandle[0].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) <<
"expected vertex handle 0!" ;
830 EXPECT_EQ(vhandle[1].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,0)).idx()) <<
"expected vertex handle 1 (did the flip work?)!" ;
831 EXPECT_EQ(vhandle[3].idx(), mesh.to_vertex_handle(mesh.halfedge_handle(*it,1)).idx()) <<
"expected vertex handle 3 (did the flip work?)!" ;
839 TEST_F(OpenMeshTutorials, collapsing_edges) {
841 mesh.request_vertex_status();
842 mesh.request_edge_status();
853 std::vector<PolyMesh::VertexHandle> face_vhandles;
854 face_vhandles.push_back(vhandle[1]);
855 face_vhandles.push_back(vhandle[0]);
856 face_vhandles.push_back(vhandle[2]);
857 face_vhandles.push_back(vhandle[3]);
858 mesh.add_face(face_vhandles);
859 face_vhandles.clear();
860 face_vhandles.push_back(vhandle[1]);
861 face_vhandles.push_back(vhandle[3]);
862 face_vhandles.push_back(vhandle[5]);
863 face_vhandles.push_back(vhandle[4]);
864 mesh.add_face(face_vhandles);
865 face_vhandles.clear();
866 face_vhandles.push_back(vhandle[3]);
867 face_vhandles.push_back(vhandle[2]);
868 face_vhandles.push_back(vhandle[6]);
869 face_vhandles.push_back(vhandle[5]);
870 mesh.add_face(face_vhandles);
873 for(PolyMesh::HalfedgeIter it = mesh.halfedges_begin(); it != mesh.halfedges_end(); ++it) {
874 if( mesh.to_vertex_handle(*it) == vhandle[3] &&
875 mesh.from_vertex_handle(*it) == vhandle[2])
885 TEST_F(OpenMeshTutorials, using_smart_handles_and_smart_ranges) {
889 EXPECT_TRUE(ok) <<
"Cannot read mesh from file 'cube_noisy.off'";
891 const int iterations = 100;
901 auto points = OpenMesh::getPointsProperty(mesh);
904 for (
int i = 0; i < iterations; ++i) {
906 for (
const auto& vh : mesh.vertices())
907 laplace(vh) = vh.vertices().avg(points) - points(vh);
910 for (
const auto& vh : mesh.vertices())
911 bi_laplace(vh) = (vh.vertices().avg(laplace) - laplace(vh));
914 for (
const auto& vh : mesh.vertices())
915 points(vh) += -0.5 * bi_laplace(vh);
922 EXPECT_TRUE(ok) <<
"Cannot write mesh to file 'smoothed_smart_output.off'";
Kernel::VertexVertexIter VertexVertexIter
Circulator.
size_t size_of(const T &_v)
Add storage for previous halfedge (halfedges). The bit is set by default in the DefaultTraits.
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.
Kernel::Point Point
Coordinate type.
Add status to mesh item (all items)
#define VertexTraits
Macro for defining the vertex traits. See Specifying your MyMesh.
#define VertexAttributes(_i)
Macro for defining the vertex attributes. See Specifying your MyMesh.
bool read_mesh(Mesh &_mesh, const std::string &_filename)
Read a mesh from file _filename.
#define EdgeAttributes(_i)
Macro for defining the edge attributes. See Specifying your MyMesh.
SmartVertexHandle add_vertex(const Point &_p)
Set options for reader/writer modules.
Kernel::Scalar Scalar
Scalar type.
Has (r) / store (w) vertex normals.
#define HalfedgeAttributes(_i)
Macro for defining the halfedge attributes. See Specifying your MyMesh.
#define FaceAttributes(_i)
Macro for defining the face attributes. See Specifying your MyMesh.
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
T::value_type value_type
Type of the scalar value.