1 #include <gtest/gtest.h>
2 #include <Unittests/unittests_common.hh>
3 #include <iostream>
4 #include <list>
5 
6 #include <stdint.h>
7 
8 namespace {
9 
10 class OpenMeshVectorTest : public testing::Test {
11 
12     protected:
13 
14         // This function is called before each test is run
SetUp()15         virtual void SetUp() {
16 
17             // Do some initial stuff with the member data here...
18         }
19 
20         // This function is called after all tests are through
TearDown()21         virtual void TearDown() {
22 
23             // Do some final stuff with the member data here...
24         }
25 
26 };
27 
28 
29 
30 /*
31  * ====================================================================
32  * Define tests below
33  * ====================================================================
34  */
35 
36 /* Compute surface area via cross product
37  */
TEST_F(OpenMeshVectorTest,ComputeTriangleSurfaceWithCrossProduct)38 TEST_F(OpenMeshVectorTest, ComputeTriangleSurfaceWithCrossProduct) {
39 
40 
41   //
42   // vec1
43   //  x
44   //  |
45   //  |
46   //  |
47   //  x------>x vec2
48   //
49 
50   OpenMesh::Vec3d vec1(0.0,1.0,0.0);
51   OpenMesh::Vec3d vec2(1.0,0.0,0.0);
52 
53   double area = 0.5 * cross(vec1,vec2).norm();
54   EXPECT_EQ(0.5f , area ) << "Wrong area in cross product function";
55 
56   area = 0.5 * ( vec1 % vec2 ).norm();
57   EXPECT_EQ(0.5f , area ) << "Wrong area in cross product operator";
58 
59 }
60 
61 /* Check OpenMesh Vector type abs function
62  */
TEST_F(OpenMeshVectorTest,AbsTest)63 TEST_F(OpenMeshVectorTest, AbsTest) {
64 
65   OpenMesh::Vec3d vec1(0.5,0.5,-0.5);
66 
67   EXPECT_EQ( vec1.l8_norm() , 0.5f ) << "Wrong l8norm computation";
68 
69 }
70 
71 /* Compute surface area via cross product
72  */
TEST_F(OpenMeshVectorTest,VectorCasting)73 TEST_F(OpenMeshVectorTest, VectorCasting) {
74 
75   OpenMesh::Vec3d vecd(1.0,2.0,3.0);
76   OpenMesh::Vec3f vecf = OpenMesh::vector_cast<OpenMesh::Vec3f>(vecd);
77   EXPECT_EQ(1.f, vecf[0]) << "vector type cast failed on component 0";
78   EXPECT_EQ(2.f, vecf[1]) << "vector type cast failed on component 1";
79   EXPECT_EQ(3.f, vecf[2]) << "vector type cast failed on component 2";
80 
81   OpenMesh::Vec4d vecd4(40.0,30.0,20.0,10.0);
82   vecd = OpenMesh::vector_cast<OpenMesh::Vec3d>(vecd4);
83   EXPECT_EQ(40.0, vecd[0]) << "vector dimension cast failed on component 0";
84   EXPECT_EQ(30.0, vecd[1]) << "vector dimension cast failed on component 1";
85   EXPECT_EQ(20.0, vecd[2]) << "vector dimension cast failed on component 2";
86 
87 }
88 
89 #if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
TEST_F(OpenMeshVectorTest,cpp11_constructors)90 TEST_F(OpenMeshVectorTest, cpp11_constructors) {
91     OpenMesh::Vec3d vec1 { 1.2, 2.0, 3.0 };
92 
93     EXPECT_EQ(1.2, vec1[0]);
94     EXPECT_EQ(2.0, vec1[1]);
95     EXPECT_EQ(3.0, vec1[2]);
96 
97     OpenMesh::Vec4f vec2 { 1.2f, 3.5f, 1.0f, 0.0f };
98 
99     EXPECT_EQ(1.2f, vec2[0]);
100     EXPECT_EQ(3.5f, vec2[1]);
101     EXPECT_EQ(1.0f, vec2[2]);
102     EXPECT_EQ(0.0f, vec2[3]);
103 
104     OpenMesh::Vec4f vec2b { vec2 };
105 
106     EXPECT_EQ(1.2f, vec2b[0]);
107     EXPECT_EQ(3.5f, vec2b[1]);
108     EXPECT_EQ(1.0f, vec2b[2]);
109     EXPECT_EQ(0.0f, vec2b[3]);
110 
111     OpenMesh::Vec4d vec4d { 1.23 };
112     EXPECT_EQ(1.23, vec4d[0]);
113     EXPECT_EQ(1.23, vec4d[1]);
114     EXPECT_EQ(1.23, vec4d[2]);
115     EXPECT_EQ(1.23, vec4d[3]);
116 }
117 
TEST_F(OpenMeshVectorTest,cpp11_htmlColorLiteral)118 TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
119     static constexpr OpenMesh::Vec4f rose = 0xFFC7F1FF_htmlColor;
120 
121     EXPECT_EQ(0xFFC7F1FF_htmlColor, rose);
122 
123     const OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
124     EXPECT_LE((OpenMesh::Vec4f(0.1215686274f, 0.8117647058f, 1.0f, 1.0f)
125         - light_blue).sqrnorm(), 1e-10);
126 
127     const auto light_blue_2 = 0x1FCFFFFF_htmlColor;
128     // Check whether auto type deduction works as expected.
129     static_assert(std::is_same<decltype(light_blue_2), decltype(light_blue)>
130         ::value, "Bad type deduced from _htmlColor literal.");
131     EXPECT_EQ(light_blue, light_blue_2);
132 }
133 
134 
135 namespace {
136 class C {
137     public:
C()138         C() {}
C(const C & rhs)139         C(const C &rhs) { ADD_FAILURE() << "Copy constructor used."; }
C(C && rhs)140         C(C &&rhs) { ++copy_con; }
operator =(const C & rhs)141         C &operator= (const C &rhs) {
142             ADD_FAILURE() << "Copy assignemnt used.";
143             return *this;
144         }
operator =(C && rhs)145         C &operator= (C &&rhs) { ++copy_ass; return *this; }
146 
147         static int copy_con;
148         static int copy_ass;
149 };
150 
151 int C::copy_con = 0;
152 int C::copy_ass = 0;
153 }
154 
155 /**
156  * Checks two things:
157  *   1) Whether VectorT works with a non-arithmetic type.
158  *   2) Whether move construction and assignment works.
159  */
TEST_F(OpenMeshVectorTest,move_constructor_assignment)160 TEST_F(OpenMeshVectorTest, move_constructor_assignment) {
161 
162     C::copy_con = 0;
163     C::copy_ass = 0;
164 
165     // Test move assigning.
166     OpenMesh::VectorT<C, 3> x, y;
167     x = std::move(y);
168     EXPECT_EQ(3, C::copy_ass);
169     EXPECT_EQ(0, C::copy_con);
170 
171     // Test move constructing.
172     OpenMesh::VectorT<C, 3> z(std::move(x));
173     EXPECT_EQ(3, C::copy_ass);
174     EXPECT_EQ(3, C::copy_con);
175 }
176 
TEST_F(OpenMeshVectorTest,iterator_init)177 TEST_F(OpenMeshVectorTest, iterator_init) {
178     std::list<float> a;
179     a.push_back(1.0);
180     a.push_back(2.0);
181     a.push_back(3.0);
182     OpenMesh::Vec3f v(a.begin());
183     EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
184 }
185 
186 #endif // C++11
187 
188 
TEST_F(OpenMeshVectorTest,BasicArithmeticInPlace)189 TEST_F(OpenMeshVectorTest, BasicArithmeticInPlace) {
190     OpenMesh::Vec3d v1(1, 2, 3);
191     double s1 = 2;
192     const double epsilon = 1e-6;
193 
194     OpenMesh::Vec3d v2add (3, 4, 6); v2add  += v1;
195     OpenMesh::Vec3d v2sub (3, 4, 6); v2sub  -= v1;
196     OpenMesh::Vec3d v2cmul(3, 4, 6); v2cmul *= v1;
197     OpenMesh::Vec3d v2cdiv(3, 4, 6); v2cdiv /= v1;
198     OpenMesh::Vec3d v2smul(3, 4, 6); v2smul *= s1;
199     OpenMesh::Vec3d v2sdiv(3, 4, 6); v2sdiv /= s1;
200 
201     EXPECT_NEAR(4, v2add[0], epsilon);
202     EXPECT_NEAR(6, v2add[1], epsilon);
203     EXPECT_NEAR(9, v2add[2], epsilon);
204 
205     EXPECT_NEAR(2, v2sub[0], epsilon);
206     EXPECT_NEAR(2, v2sub[1], epsilon);
207     EXPECT_NEAR(3, v2sub[2], epsilon);
208 
209     EXPECT_NEAR( 3, v2cmul[0], epsilon);
210     EXPECT_NEAR( 8, v2cmul[1], epsilon);
211     EXPECT_NEAR(18, v2cmul[2], epsilon);
212 
213     EXPECT_NEAR(3, v2cdiv[0], epsilon);
214     EXPECT_NEAR(2, v2cdiv[1], epsilon);
215     EXPECT_NEAR(2, v2cdiv[2], epsilon);
216 
217     EXPECT_NEAR( 6, v2smul[0], epsilon);
218     EXPECT_NEAR( 8, v2smul[1], epsilon);
219     EXPECT_NEAR(12, v2smul[2], epsilon);
220 
221     EXPECT_NEAR(1.5, v2sdiv[0], epsilon);
222     EXPECT_NEAR(2.0, v2sdiv[1], epsilon);
223     EXPECT_NEAR(3.0, v2sdiv[2], epsilon);
224 }
225 
TEST_F(OpenMeshVectorTest,BasicArithmeticImmutable)226 TEST_F(OpenMeshVectorTest, BasicArithmeticImmutable) {
227     OpenMesh::Vec3d v1(1, 2, 3);
228     const double epsilon = 1e-6;
229 
230     OpenMesh::Vec3d v2add  = v1 + OpenMesh::Vec3d(2, 4, 6);
231     OpenMesh::Vec3d v2sub  = v1 - OpenMesh::Vec3d(2, 4, 6);
232     OpenMesh::Vec3d v2cmul = v1 * OpenMesh::Vec3d(2, 4, 6);
233     OpenMesh::Vec3d v2cdiv = v1 / OpenMesh::Vec3d(2, 4, 6);
234     OpenMesh::Vec3d v2smul = v1 * 2.0;
235     OpenMesh::Vec3d v2sdiv = v1 / 2.0;
236     OpenMesh::Vec3d v2neg  = -v1;
237 
238     EXPECT_NEAR(3, v2add[0], epsilon);
239     EXPECT_NEAR(6, v2add[1], epsilon);
240     EXPECT_NEAR(9, v2add[2], epsilon);
241 
242     EXPECT_NEAR(-1, v2sub[0], epsilon);
243     EXPECT_NEAR(-2, v2sub[1], epsilon);
244     EXPECT_NEAR(-3, v2sub[2], epsilon);
245 
246     EXPECT_NEAR( 2, v2cmul[0], epsilon);
247     EXPECT_NEAR( 8, v2cmul[1], epsilon);
248     EXPECT_NEAR(18, v2cmul[2], epsilon);
249 
250     EXPECT_NEAR(0.5, v2cdiv[0], epsilon);
251     EXPECT_NEAR(0.5, v2cdiv[1], epsilon);
252     EXPECT_NEAR(0.5, v2cdiv[2], epsilon);
253 
254     EXPECT_NEAR(2, v2smul[0], epsilon);
255     EXPECT_NEAR(4, v2smul[1], epsilon);
256     EXPECT_NEAR(6, v2smul[2], epsilon);
257 
258     EXPECT_NEAR(0.5, v2sdiv[0], epsilon);
259     EXPECT_NEAR(1.0, v2sdiv[1], epsilon);
260     EXPECT_NEAR(1.5, v2sdiv[2], epsilon);
261 
262     EXPECT_NEAR(-1, v2neg[0], epsilon);
263     EXPECT_NEAR(-2, v2neg[1], epsilon);
264     EXPECT_NEAR(-3, v2neg[2], epsilon);
265 }
266 template <typename V1, typename V2, typename S>
test_dot(const V1 & v1,const V2 & v2,const S & s)267 void test_dot(const V1 &v1, const V2 &v2, const S&s) {
268     EXPECT_NEAR(s, v1 | v2, 1e-6);
269     EXPECT_NEAR(s, v1.dot(v2), 1e-6);
270     EXPECT_NEAR(-s, (-v1) | v2, 1e-6);
271     EXPECT_NEAR(-s, (-v1).dot(v2), 1e-6);
272     EXPECT_NEAR(s, v2 | v1, 1e-6);
273     EXPECT_NEAR(s, v2.dot(v1), 1e-6);
274 }
275 
276 template <typename V1, typename V2, typename V3>
test_cross(const V1 & v1,const V2 & v2,const V3 & res)277 void test_cross(const V1 &v1, const V2 &v2, const V3 &res) {
278     EXPECT_NEAR(0, (v1.cross(v2) - res).norm(), 1e-6);
279     EXPECT_NEAR(0, (v1 % v2 - res).norm(), 1e-6);
280     EXPECT_NEAR(0, (v2.cross(v1) + res).norm(), 1e-6);
281     EXPECT_NEAR(0, (v2 % v1 + res).norm(), 1e-6);
282 }
283 
TEST_F(OpenMeshVectorTest,BasicLinearAlgebra)284 TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
285     OpenMesh::Vec3d v(1, 2, 3);
286     EXPECT_EQ(v[0], 1.0);
287     EXPECT_EQ(v[1], 2.0);
288     EXPECT_EQ(v[2], 3.0);
289 
290     EXPECT_EQ(OpenMesh::Vec3d(-1, -2, -3), -v);
291     EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, 2).max());
292     EXPECT_EQ(3, OpenMesh::Vec3d(1, 2, 3).max());
293     EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, -4).max());
294     EXPECT_EQ(3, OpenMesh::Vec3d(-4, 2, 3).max());
295     EXPECT_EQ(4, OpenMesh::Vec3d(1, 3, -4).max_abs());
296     EXPECT_EQ(4, OpenMesh::Vec3d(-4, 2, 3).max_abs());
297 
298     EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, 2).min());
299     EXPECT_EQ(1, OpenMesh::Vec3d(1, 2, 3).min());
300     EXPECT_EQ(-4, OpenMesh::Vec3d(1, 3, -4).min());
301     EXPECT_EQ(-4, OpenMesh::Vec3d(-4, 2, 3).min());
302     EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, -4).min_abs());
303     EXPECT_EQ(2, OpenMesh::Vec3d(-4, 2, 3).min_abs());
304 
305 
306     test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3d(1, 2, 3), 14.);
307     test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3d(-1, -2, -3), -14.);
308     test_dot(OpenMesh::Vec3d(1, 2, 3), OpenMesh::Vec3i(1, 2, 3), 14);
309     test_dot(OpenMesh::Vec3i(1, 2, 3), OpenMesh::Vec3i(1, 2, 3), 14);
310 
311     test_cross(OpenMesh::Vec3i(2, 0, 0), OpenMesh::Vec3i(0, 3, 0), OpenMesh::Vec3i(0, 0, 6));
312     test_cross(OpenMesh::Vec3d(2, 0, 0), OpenMesh::Vec3d(0, 3, 0), OpenMesh::Vec3d(0, 0, 6));
313     test_cross(OpenMesh::Vec3d(2, 0, 0), OpenMesh::Vec3i(0, 3, 0), OpenMesh::Vec3d(0, 0, 6));
314 }
315 
TEST_F(OpenMeshVectorTest,array_init)316 TEST_F(OpenMeshVectorTest, array_init) {
317     float a[3]; a[0] = 1.0; a[1] = 2.0; a[2] = 3.0;
318     OpenMesh::Vec3f v(a);
319     EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
320 
321     // This should not invoke the array constructor.
322     OpenMesh::Vec3d v2(3.0f);
323 }
324 
TEST_F(OpenMeshVectorTest,normalized_cond)325 TEST_F(OpenMeshVectorTest, normalized_cond) {
326     OpenMesh::Vec3d v1(1, -2, 3), v2(0, 0, 0);
327     EXPECT_EQ(OpenMesh::Vec3d(0, 0, 0), v2.normalize_cond());
328     const OpenMesh::Vec3d r1 =
329             OpenMesh::Vec3d(
330                      0.2672612419124244,
331                     -0.5345224838248488,
332                      0.8017837257372732) - v1.normalize_cond();
333     EXPECT_NEAR(r1[0], 0.0, 1e-12);
334     EXPECT_NEAR(r1[1], 0.0, 1e-12);
335     EXPECT_NEAR(r1[2], 0.0, 1e-12);
336 }
337 
TEST_F(OpenMeshVectorTest,size_dim)338 TEST_F(OpenMeshVectorTest, size_dim) {
339     OpenMesh::Vec3d v3d(1, 2, 3);
340     OpenMesh::Vec3f v3f(1, 2, 3);
341     OpenMesh::Vec2i v2i(1, 2);
342 
343     EXPECT_EQ(3u, v3d.size());
344     EXPECT_EQ(3, v3d.dim());
345     EXPECT_EQ(3u, v3f.size());
346     EXPECT_EQ(3, v3f.dim());
347     EXPECT_EQ(2u, v2i.size());
348     EXPECT_EQ(2, v2i.dim());
349 }
350 
351 class OpenMeshVectorGCCBugTest;
352 void trigger_alignment_bug(OpenMeshVectorGCCBugTest &obj);
353 
354 /**
355  * This is a regression test for a GCC compiler bug.
356  * @see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66598
357  * @see https://www.graphics.rwth-aachen.de:9000/OpenMesh/OpenMesh/issues/32
358  */
359 class OpenMeshVectorGCCBugTest : public testing::Test {
360 
361     protected:
362 
SetUp()363         virtual void SetUp() {
364             /*
365              * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
366              * pointless as it may look, is carefully crafted to provoke
367              * the GCC optimizer bug mentioned above.
368              */
369             testfn = trigger_alignment_bug;
370             vec1 = OpenMesh::Vec4f(1.0f, 2.0f, 3.0f, 4.0f);
371             vec2 = OpenMesh::Vec4f(5.0f, 6.0f, 7.0f, 8.0f);
372             padding = 42;
373         }
374 
TearDown()375         virtual void TearDown() {
376             // Do some final stuff with the member data here...
377         }
378 
379     public:
380         /*
381          * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
382          * pointless as it may look, is carefully crafted to provoke
383          * the GCC optimizer bug mentioned above.
384          */
385         int32_t padding;
386         OpenMesh::Vec4f vec1, vec2;
387         void (*testfn)(OpenMeshVectorGCCBugTest &obj);
388 
get_vec1()389         OpenMesh::Vec4f &get_vec1() { return vec1; }
get_vec2()390         OpenMesh::Vec4f &get_vec2() { return vec2; }
391 };
392 
trigger_alignment_bug(OpenMeshVectorGCCBugTest & obj)393 void trigger_alignment_bug(OpenMeshVectorGCCBugTest &obj) {
394     /*
395      * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
396      * pointless as it may look, is carefully crafted to provoke
397      * the GCC optimizer bug mentioned above.
398      */
399     int x1 = 1;
400 
401     OpenMesh::Vec4f vec3 = obj.get_vec1();
402     OpenMesh::Vec4f vec4 = obj.get_vec2();
403     vec3 += vec4;
404 
405     EXPECT_EQ(1, x1);
406     EXPECT_EQ(42, obj.padding);
407     EXPECT_EQ(6.0f, vec3[0]);
408     EXPECT_EQ(8.0f, vec3[1]);
409     EXPECT_EQ(10.0f, vec3[2]);
410     EXPECT_EQ(12.0f, vec3[3]);
411 }
412 
TEST_F(OpenMeshVectorGCCBugTest,alignment_bug)413 TEST_F(OpenMeshVectorGCCBugTest, alignment_bug) {
414     /*
415      * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
416      * pointless as it may look, is carefully crafted to provoke
417      * the GCC optimizer bug mentioned above.
418      */
419     (*testfn)(*this);
420 }
421 
422 
TEST_F(OpenMeshVectorTest,Test_simple_0_constructor)423 TEST_F(OpenMeshVectorTest, Test_simple_0_constructor) {
424 
425   // Create a test vector with zeroes from one parameter
426   OpenMesh::Vec3d testVec = OpenMesh::Vec3d(0);
427 
428   EXPECT_EQ(0.0f, testVec[0]) << "Wrong Value after construction!";
429   EXPECT_EQ(0.0f, testVec[1]) << "Wrong Value after construction!";
430   EXPECT_EQ(0.0f, testVec[2]) << "Wrong Value after construction!";
431 
432 
433 
434 }
435 
436 
437 
438 }
439