Developer Documentation
unittests_smart_ranges.cc
1 #include <gtest/gtest.h>
2 #include <Unittests/unittests_common.hh>
3 
4 #include <OpenMesh/Core/Mesh/SmartHandles.hh>
5 #include <OpenMesh/Core/Utils/PropertyManager.hh>
6 
7 #include <iostream>
8 #include <chrono>
9 
10 namespace {
11 
12 class OpenMeshSmartRanges : public OpenMeshBase {
13 
14 protected:
15 
16  // This function is called before each test is run
17  virtual void SetUp() {
18 
19  mesh_.clear();
20 
21  // Add some vertices
22  Mesh::VertexHandle vhandle[8];
23  vhandle[0] = mesh_.add_vertex(Mesh::Point(-1, -1, 1));
24  vhandle[1] = mesh_.add_vertex(Mesh::Point( 1, -1, 1));
25  vhandle[2] = mesh_.add_vertex(Mesh::Point( 1, 1, 1));
26  vhandle[3] = mesh_.add_vertex(Mesh::Point(-1, 1, 1));
27  vhandle[4] = mesh_.add_vertex(Mesh::Point(-1, -1, -1));
28  vhandle[5] = mesh_.add_vertex(Mesh::Point( 1, -1, -1));
29  vhandle[6] = mesh_.add_vertex(Mesh::Point( 1, 1, -1));
30  vhandle[7] = mesh_.add_vertex(Mesh::Point(-1, 1, -1));
31 
32  // Add six faces to form a cube
33  std::vector<Mesh::VertexHandle> face_vhandles;
34 
35  face_vhandles.clear();
36  face_vhandles.push_back(vhandle[0]);
37  face_vhandles.push_back(vhandle[1]);
38  face_vhandles.push_back(vhandle[3]);
39  mesh_.add_face(face_vhandles);
40 
41  face_vhandles.clear();
42  face_vhandles.push_back(vhandle[1]);
43  face_vhandles.push_back(vhandle[2]);
44  face_vhandles.push_back(vhandle[3]);
45  mesh_.add_face(face_vhandles);
46 
47  //=======================
48 
49  face_vhandles.clear();
50  face_vhandles.push_back(vhandle[7]);
51  face_vhandles.push_back(vhandle[6]);
52  face_vhandles.push_back(vhandle[5]);
53  mesh_.add_face(face_vhandles);
54 
55  face_vhandles.clear();
56  face_vhandles.push_back(vhandle[7]);
57  face_vhandles.push_back(vhandle[5]);
58  face_vhandles.push_back(vhandle[4]);
59  mesh_.add_face(face_vhandles);
60 
61  //=======================
62 
63  face_vhandles.clear();
64  face_vhandles.push_back(vhandle[1]);
65  face_vhandles.push_back(vhandle[0]);
66  face_vhandles.push_back(vhandle[4]);
67  mesh_.add_face(face_vhandles);
68 
69  face_vhandles.clear();
70  face_vhandles.push_back(vhandle[1]);
71  face_vhandles.push_back(vhandle[4]);
72  face_vhandles.push_back(vhandle[5]);
73  mesh_.add_face(face_vhandles);
74 
75  //=======================
76 
77  face_vhandles.clear();
78  face_vhandles.push_back(vhandle[2]);
79  face_vhandles.push_back(vhandle[1]);
80  face_vhandles.push_back(vhandle[5]);
81  mesh_.add_face(face_vhandles);
82 
83  face_vhandles.clear();
84  face_vhandles.push_back(vhandle[2]);
85  face_vhandles.push_back(vhandle[5]);
86  face_vhandles.push_back(vhandle[6]);
87  mesh_.add_face(face_vhandles);
88 
89 
90  //=======================
91 
92  face_vhandles.clear();
93  face_vhandles.push_back(vhandle[3]);
94  face_vhandles.push_back(vhandle[2]);
95  face_vhandles.push_back(vhandle[6]);
96  mesh_.add_face(face_vhandles);
97 
98  face_vhandles.clear();
99  face_vhandles.push_back(vhandle[3]);
100  face_vhandles.push_back(vhandle[6]);
101  face_vhandles.push_back(vhandle[7]);
102  mesh_.add_face(face_vhandles);
103 
104  //=======================
105 
106  face_vhandles.clear();
107  face_vhandles.push_back(vhandle[0]);
108  face_vhandles.push_back(vhandle[3]);
109  face_vhandles.push_back(vhandle[7]);
110  mesh_.add_face(face_vhandles);
111 
112  face_vhandles.clear();
113  face_vhandles.push_back(vhandle[0]);
114  face_vhandles.push_back(vhandle[7]);
115  face_vhandles.push_back(vhandle[4]);
116  mesh_.add_face(face_vhandles);
117 
118 
119  // Test setup:
120  //
121  //
122  // 3 ======== 2
123  // / /|
124  // / / | z
125  // 0 ======== 1 | |
126  // | | | | y
127  // | 7 | 6 | /
128  // | | / | /
129  // | |/ |/
130  // 4 ======== 5 -------> x
131  //
132 
133  // Check setup
134  EXPECT_EQ(18u, mesh_.n_edges() ) << "Wrong number of Edges";
135  EXPECT_EQ(36u, mesh_.n_halfedges() ) << "Wrong number of HalfEdges";
136  EXPECT_EQ(8u, mesh_.n_vertices() ) << "Wrong number of vertices";
137  EXPECT_EQ(12u, mesh_.n_faces() ) << "Wrong number of faces";
138  }
139 
140  // This function is called after all tests are through
141  virtual void TearDown() {
142 
143  // Do some final stuff with the member data here...
144 
145  mesh_.clear();
146  }
147 
148  // Member already defined in OpenMeshBase
149  //Mesh mesh_;
150 };
151 
152 /*
153  * ====================================================================
154  * Define tests below
155  * ====================================================================
156  */
157 
158 
159 template <typename HandleT>
160 struct F
161 {
162  int operator()(HandleT ) { return 1; }
163 };
164 
165 /* Test if smart ranges work
166  */
167 TEST_F(OpenMeshSmartRanges, Sum)
168 {
169  auto one = [](OpenMesh::VertexHandle ) { return 1; };
170  EXPECT_EQ(mesh_.vertices().sum(one), mesh_.n_vertices());
171  EXPECT_EQ(mesh_.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.n_vertices());
172  EXPECT_EQ(mesh_.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.n_halfedges());
173  EXPECT_EQ(mesh_.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.n_edges());
174  EXPECT_EQ(mesh_.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.n_faces());
175 
176  for (auto vh : mesh_.vertices())
177  EXPECT_EQ(vh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(vh));
178  for (auto vh : mesh_.vertices())
179  EXPECT_EQ(vh.faces().sum(F<OpenMesh::FaceHandle>()), mesh_.valence(vh));
180  for (auto vh : mesh_.vertices())
181  EXPECT_EQ(vh.outgoing_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
182  for (auto vh : mesh_.vertices())
183  EXPECT_EQ(vh.incoming_halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(vh));
184 
185  for (auto fh : mesh_.faces())
186  EXPECT_EQ(fh.vertices().sum(F<OpenMesh::VertexHandle>()), mesh_.valence(fh));
187  for (auto fh : mesh_.faces())
188  EXPECT_EQ(fh.halfedges().sum(F<OpenMesh::HalfedgeHandle>()), mesh_.valence(fh));
189  for (auto fh : mesh_.faces())
190  EXPECT_EQ(fh.edges().sum(F<OpenMesh::EdgeHandle>()), mesh_.valence(fh));
191  for (auto fh : mesh_.faces())
192  EXPECT_EQ(fh.faces().sum(F<OpenMesh::FaceHandle>()), 3);
193 }
194 
195 
196 /* Test if Property Manager can be used in smart ranges
197  */
198 TEST_F(OpenMeshSmartRanges, PropertyManagerAsFunctor)
199 {
200  auto myPos = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, Mesh::Point>(mesh_);
201  for (auto vh : mesh_.vertices())
202  myPos(vh) = mesh_.point(vh);
203 
204  Mesh::Point cog(0,0,0);
205  for (auto vh : mesh_.vertices())
206  cog += mesh_.point(vh);
207  cog /= mesh_.n_vertices();
208 
209  auto cog2 = mesh_.vertices().avg(myPos);
210 
211  EXPECT_LT(norm(cog - cog2), 0.00001) << "Computed center of gravities are significantly different.";
212 }
213 
214 /* Test to vector
215  */
216 TEST_F(OpenMeshSmartRanges, ToVector)
217 {
218  auto uvs = OpenMesh::makeTemporaryProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh_);
219 
220  for (auto heh : mesh_.halfedges())
221  uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
222 
223  for (auto fh : mesh_.faces())
224  {
225  auto tri_uvs = fh.halfedges().to_vector(uvs);
226  auto heh_handles = fh.halfedges().to_vector();
227  for (auto heh : heh_handles)
228  heh.next();
229  }
230 
231  auto vertex_vec = mesh_.vertices().to_vector();
232  for (auto vh : vertex_vec)
233  vh.out();
234 }
235 
236 /* Test to array
237  */
238 TEST_F(OpenMeshSmartRanges, ToArray)
239 {
240  auto uvs = OpenMesh::makeTemporaryProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh_);
241 
242  for (auto heh : mesh_.halfedges())
243  uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
244 
245  for (auto fh : mesh_.faces())
246  {
247  fh.halfedges().to_array<3>(uvs);
248  fh.halfedges().to_array<3>();
249  }
250 }
251 
252 
253 /* Test bounding box
254  */
255 TEST_F(OpenMeshSmartRanges, BoundingBox)
256 {
257  // The custom vecs OpenMesh are tested with here do not implement a min or max function.
258  // Thus we convert here.
259  auto myPos = OpenMesh::makeTemporaryProperty<OpenMesh::VertexHandle, OpenMesh::Vec3f>(mesh_);
260  for (auto vh : mesh_.vertices())
261  for (size_t i = 0; i < 3; ++i)
262  myPos(vh)[i] = mesh_.point(vh)[i];
263 
264  auto bb_min = mesh_.vertices().min(myPos);
265  auto bb_max = mesh_.vertices().max(myPos);
266  mesh_.vertices().minmax(myPos);
267 
268  EXPECT_LT(norm(bb_min - OpenMesh::Vec3f(-1,-1,-1)), 0.000001) << "Bounding box minimum seems off";
269  EXPECT_LT(norm(bb_max - OpenMesh::Vec3f( 1, 1, 1)), 0.000001) << "Bounding box maximum seems off";
270 
271 
272  auto uvs = OpenMesh::makeTemporaryProperty<OpenMesh::HalfedgeHandle, OpenMesh::Vec2d>(mesh_);
273  for (auto heh : mesh_.halfedges())
274  uvs(heh) = OpenMesh::Vec2d(heh.idx(), (heh.idx() * 13)%7);
275 
276  for (auto fh : mesh_.faces())
277  {
278  fh.halfedges().min(uvs);
279  fh.halfedges().max(uvs);
280  }
281 }
282 
283 
284 
285 }
VectorT< double, 2 > Vec2d
Definition: Vector11T.hh:816
Kernel::Point Point
Coordinate type.
Definition: PolyMeshT.hh:112
Handle for a vertex entity.
Definition: Handles.hh:120
SmartVertexHandle add_vertex(const Point &_p)
Alias for new_vertex(const Point&).
Definition: PolyMeshT.hh:235
Kernel::VertexHandle VertexHandle
Handle for referencing the corresponding item.
Definition: PolyMeshT.hh:136