unittests_vector_type.cc 11.4 KB
Newer Older
1
2
3
#include <gtest/gtest.h>
#include <Unittests/unittests_common.hh>
#include <iostream>
4
#include <list>
Jan Möbius's avatar
Jan Möbius committed
5
#include <cstdint>
6

7
8
namespace {

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class OpenMeshVectorTest : public testing::Test {

    protected:

        // This function is called before each test is run
        virtual void SetUp() {
            
            // Do some initial stuff with the member data here...
        }

        // This function is called after all tests are through
        virtual void TearDown() {

            // Do some final stuff with the member data here...
        }

};



/*
 * ====================================================================
 * Define tests below
 * ====================================================================
 */

/* Compute surface area via cross product
 */
TEST_F(OpenMeshVectorTest, ComputeTriangleSurfaceWithCrossProduct) {


  //
  // vec1
  //  x
  //  |
  //  |
  //  |
  //  x------>x vec2
  //

  OpenMesh::Vec3d vec1(0.0,1.0,0.0);
  OpenMesh::Vec3d vec2(1.0,0.0,0.0);

  double area = 0.5 * cross(vec1,vec2).norm();
  EXPECT_EQ(0.5f , area ) << "Wrong area in cross product function";

  area = 0.5 * ( vec1 % vec2 ).norm();
  EXPECT_EQ(0.5f , area ) << "Wrong area in cross product operator";

}

Jan Möbius's avatar
Jan Möbius committed
60
61
62
63
64
65
66
67
68
69
/* Check OpenMesh Vector type abs function
 */
TEST_F(OpenMeshVectorTest, AbsTest) {

  OpenMesh::Vec3d vec1(0.5,0.5,-0.5);

  EXPECT_EQ( vec1.l8_norm() , 0.5f ) << "Wrong l8norm computation";

}

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/* Compute surface area via cross product
 */
TEST_F(OpenMeshVectorTest, VectorCasting) {

  OpenMesh::Vec3d vecd(1.0,2.0,3.0);
  OpenMesh::Vec3f vecf = OpenMesh::vector_cast<OpenMesh::Vec3f>(vecd);
  EXPECT_EQ(1.f, vecf[0]) << "vector type cast failed on component 0";
  EXPECT_EQ(2.f, vecf[1]) << "vector type cast failed on component 1";
  EXPECT_EQ(3.f, vecf[2]) << "vector type cast failed on component 2";

  OpenMesh::Vec4d vecd4(40.0,30.0,20.0,10.0);
  vecd = OpenMesh::vector_cast<OpenMesh::Vec3d>(vecd4);
  EXPECT_EQ(40.0, vecd[0]) << "vector dimension cast failed on component 0";
  EXPECT_EQ(30.0, vecd[1]) << "vector dimension cast failed on component 1";
  EXPECT_EQ(20.0, vecd[2]) << "vector dimension cast failed on component 2";

}

xan's avatar
xan committed
88
#if (defined(_MSC_VER) && (_MSC_VER >= 1900)) || __cplusplus > 199711L || defined(__GXX_EXPERIMENTAL_CXX0X__)
89
90
TEST_F(OpenMeshVectorTest, cpp11_constructors) {
    OpenMesh::Vec3d vec1 { 1.2, 2.0, 3.0 };
91

92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
    EXPECT_EQ(1.2, vec1[0]);
    EXPECT_EQ(2.0, vec1[1]);
    EXPECT_EQ(3.0, vec1[2]);

    OpenMesh::Vec4f vec2 { 1.2f, 3.5f, 1.0f, 0.0f };

    EXPECT_EQ(1.2f, vec2[0]);
    EXPECT_EQ(3.5f, vec2[1]);
    EXPECT_EQ(1.0f, vec2[2]);
    EXPECT_EQ(0.0f, vec2[3]);

    OpenMesh::Vec4f vec2b { vec2 };

    EXPECT_EQ(1.2f, vec2b[0]);
    EXPECT_EQ(3.5f, vec2b[1]);
    EXPECT_EQ(1.0f, vec2b[2]);
    EXPECT_EQ(0.0f, vec2b[3]);

    OpenMesh::Vec4d vec4d { 1.23 };
    EXPECT_EQ(1.23, vec4d[0]);
    EXPECT_EQ(1.23, vec4d[1]);
    EXPECT_EQ(1.23, vec4d[2]);
    EXPECT_EQ(1.23, vec4d[3]);
}
116
117

TEST_F(OpenMeshVectorTest, cpp11_htmlColorLiteral) {
118
119
    static constexpr OpenMesh::Vec4f rose = 0xFFC7F1FF_htmlColor;

120
121
    EXPECT_EQ(0xFFC7F1FF_htmlColor, rose);

122
123
124
125
126
127
128
129
130
131
    const OpenMesh::Vec4f light_blue = 0x1FCFFFFF_htmlColor;
    EXPECT_LE((OpenMesh::Vec4f(0.1215686274f, 0.8117647058f, 1.0f, 1.0f)
        - light_blue).sqrnorm(), 1e-10);

    const auto light_blue_2 = 0x1FCFFFFF_htmlColor;
    // Check whether auto type deduction works as expected.
    static_assert(std::is_same<decltype(light_blue_2), decltype(light_blue)>
        ::value, "Bad type deduced from _htmlColor literal.");
    EXPECT_EQ(light_blue, light_blue_2);
}
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175


namespace {
class C {
    public:
        C() {}
        C(const C &rhs) { ADD_FAILURE() << "Copy constructor used."; }
        C(C &&rhs) { ++copy_con; }
        C &operator= (const C &rhs) {
            ADD_FAILURE() << "Copy assignemnt used.";
            return *this;
        }
        C &operator= (C &&rhs) { ++copy_ass; return *this; }

        static int copy_con;
        static int copy_ass;
};

int C::copy_con = 0;
int C::copy_ass = 0;
}

/**
 * Checks two things:
 *   1) Whether VectorT works with a non-arithmetic type.
 *   2) Whether move construction and assignment works.
 */
TEST_F(OpenMeshVectorTest, move_constructor_assignment) {

    C::copy_con = 0;
    C::copy_ass = 0;

    // Test move assigning.
    OpenMesh::VectorT<C, 3> x, y;
    x = std::move(y);
    EXPECT_EQ(3, C::copy_ass);
    EXPECT_EQ(0, C::copy_con);

    // Test move constructing.
    OpenMesh::VectorT<C, 3> z(std::move(x));
    EXPECT_EQ(3, C::copy_ass);
    EXPECT_EQ(3, C::copy_con);
}

176
177
178
179
180
181
182
183
184
TEST_F(OpenMeshVectorTest, iterator_init) {
    std::list<float> a;
    a.push_back(1.0);
    a.push_back(2.0);
    a.push_back(3.0);
    OpenMesh::Vec3f v(a.begin());
    EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
}

185
#endif // C++11
186

187

188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
TEST_F(OpenMeshVectorTest, BasicArithmeticInPlace) {
    OpenMesh::Vec3d v1(1, 2, 3);
    double s1 = 2;
    const double epsilon = 1e-6;

    OpenMesh::Vec3d v2add (3, 4, 6); v2add  += v1;
    OpenMesh::Vec3d v2sub (3, 4, 6); v2sub  -= v1;
    OpenMesh::Vec3d v2cmul(3, 4, 6); v2cmul *= v1;
    OpenMesh::Vec3d v2cdiv(3, 4, 6); v2cdiv /= v1;
    OpenMesh::Vec3d v2smul(3, 4, 6); v2smul *= s1;
    OpenMesh::Vec3d v2sdiv(3, 4, 6); v2sdiv /= s1;

    EXPECT_NEAR(4, v2add[0], epsilon);
    EXPECT_NEAR(6, v2add[1], epsilon);
    EXPECT_NEAR(9, v2add[2], epsilon);

    EXPECT_NEAR(2, v2sub[0], epsilon);
    EXPECT_NEAR(2, v2sub[1], epsilon);
    EXPECT_NEAR(3, v2sub[2], epsilon);

    EXPECT_NEAR( 3, v2cmul[0], epsilon);
    EXPECT_NEAR( 8, v2cmul[1], epsilon);
    EXPECT_NEAR(18, v2cmul[2], epsilon);

    EXPECT_NEAR(3, v2cdiv[0], epsilon);
    EXPECT_NEAR(2, v2cdiv[1], epsilon);
    EXPECT_NEAR(2, v2cdiv[2], epsilon);

    EXPECT_NEAR( 6, v2smul[0], epsilon);
    EXPECT_NEAR( 8, v2smul[1], epsilon);
    EXPECT_NEAR(12, v2smul[2], epsilon);

    EXPECT_NEAR(1.5, v2sdiv[0], epsilon);
    EXPECT_NEAR(2.0, v2sdiv[1], epsilon);
    EXPECT_NEAR(3.0, v2sdiv[2], epsilon);
}

TEST_F(OpenMeshVectorTest, BasicArithmeticImmutable) {
    OpenMesh::Vec3d v1(1, 2, 3);
    const double epsilon = 1e-6;

    OpenMesh::Vec3d v2add  = v1 + OpenMesh::Vec3d(2, 4, 6);
    OpenMesh::Vec3d v2sub  = v1 - OpenMesh::Vec3d(2, 4, 6);
    OpenMesh::Vec3d v2cmul = v1 * OpenMesh::Vec3d(2, 4, 6);
    OpenMesh::Vec3d v2cdiv = v1 / OpenMesh::Vec3d(2, 4, 6);
    OpenMesh::Vec3d v2smul = v1 * 2.0;
    OpenMesh::Vec3d v2sdiv = v1 / 2.0;
    OpenMesh::Vec3d v2neg  = -v1;

    EXPECT_NEAR(3, v2add[0], epsilon);
    EXPECT_NEAR(6, v2add[1], epsilon);
    EXPECT_NEAR(9, v2add[2], epsilon);

    EXPECT_NEAR(-1, v2sub[0], epsilon);
    EXPECT_NEAR(-2, v2sub[1], epsilon);
    EXPECT_NEAR(-3, v2sub[2], epsilon);

    EXPECT_NEAR( 2, v2cmul[0], epsilon);
    EXPECT_NEAR( 8, v2cmul[1], epsilon);
    EXPECT_NEAR(18, v2cmul[2], epsilon);

    EXPECT_NEAR(0.5, v2cdiv[0], epsilon);
    EXPECT_NEAR(0.5, v2cdiv[1], epsilon);
    EXPECT_NEAR(0.5, v2cdiv[2], epsilon);

    EXPECT_NEAR(2, v2smul[0], epsilon);
    EXPECT_NEAR(4, v2smul[1], epsilon);
    EXPECT_NEAR(6, v2smul[2], epsilon);

    EXPECT_NEAR(0.5, v2sdiv[0], epsilon);
    EXPECT_NEAR(1.0, v2sdiv[1], epsilon);
    EXPECT_NEAR(1.5, v2sdiv[2], epsilon);

    EXPECT_NEAR(-1, v2neg[0], epsilon);
    EXPECT_NEAR(-2, v2neg[1], epsilon);
    EXPECT_NEAR(-3, v2neg[2], epsilon);
}

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
TEST_F(OpenMeshVectorTest, BasicLinearAlgebra) {
    OpenMesh::Vec3d v(1, 2, 3);
    EXPECT_EQ(v[0], 1.0);
    EXPECT_EQ(v[1], 2.0);
    EXPECT_EQ(v[2], 3.0);

    EXPECT_EQ(OpenMesh::Vec3d(-1, -2, -3), -v);
    EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, 2).max());
    EXPECT_EQ(3, OpenMesh::Vec3d(1, 2, 3).max());
    EXPECT_EQ(3, OpenMesh::Vec3d(1, 3, -4).max());
    EXPECT_EQ(3, OpenMesh::Vec3d(-4, 2, 3).max());
    EXPECT_EQ(4, OpenMesh::Vec3d(1, 3, -4).max_abs());
    EXPECT_EQ(4, OpenMesh::Vec3d(-4, 2, 3).max_abs());

    EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, 2).min());
    EXPECT_EQ(1, OpenMesh::Vec3d(1, 2, 3).min());
    EXPECT_EQ(-4, OpenMesh::Vec3d(1, 3, -4).min());
    EXPECT_EQ(-4, OpenMesh::Vec3d(-4, 2, 3).min());
    EXPECT_EQ(1, OpenMesh::Vec3d(1, 3, -4).min_abs());
    EXPECT_EQ(2, OpenMesh::Vec3d(-4, 2, 3).min_abs());

    EXPECT_NEAR(14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(1, 2, 3), 1e-6);
    EXPECT_NEAR(-14, OpenMesh::Vec3d(1, 2, 3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
    EXPECT_NEAR(14, OpenMesh::Vec3d(-1, -2, -3) | OpenMesh::Vec3d(-1, -2, -3), 1e-6);
}

292
293
294
295
TEST_F(OpenMeshVectorTest, array_init) {
    float a[3]; a[0] = 1.0; a[1] = 2.0; a[2] = 3.0;
    OpenMesh::Vec3f v(a);
    EXPECT_EQ(OpenMesh::Vec3f(1.0, 2.0, 3.0), v);
296
297
298

    // This should not invoke the array constructor.
    OpenMesh::Vec3d v2(3.0f);
299
300
}

301
302
303
TEST_F(OpenMeshVectorTest, normalized_cond) {
    OpenMesh::Vec3d v1(1, -2, 3), v2(0, 0, 0);
    EXPECT_EQ(OpenMesh::Vec3d(0, 0, 0), v2.normalize_cond());
304
305
306
307
308
    const OpenMesh::Vec3d r1 =
            OpenMesh::Vec3d(
                     0.2672612419124244,
                    -0.5345224838248488,
                     0.8017837257372732) - v1.normalize_cond();
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
    EXPECT_NEAR(r1[0], 0.0, 1e-12);
    EXPECT_NEAR(r1[1], 0.0, 1e-12);
    EXPECT_NEAR(r1[2], 0.0, 1e-12);
}

TEST_F(OpenMeshVectorTest, size_dim) {
    OpenMesh::Vec3d v3d(1, 2, 3);
    OpenMesh::Vec3f v3f(1, 2, 3);
    OpenMesh::Vec2i v2i(1, 2);

    EXPECT_EQ(3u, v3d.size());
    EXPECT_EQ(3, v3d.dim());
    EXPECT_EQ(3u, v3f.size());
    EXPECT_EQ(3, v3f.dim());
    EXPECT_EQ(2u, v2i.size());
    EXPECT_EQ(2, v2i.dim());
325
326
}

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
class OpenMeshVectorGCCBugTest;
void trigger_alignment_bug(OpenMeshVectorGCCBugTest &obj);

/**
 * This is a regression test for a GCC compiler bug.
 * @see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66598
 * @see https://www.graphics.rwth-aachen.de:9000/OpenMesh/OpenMesh/issues/32
 */
class OpenMeshVectorGCCBugTest : public testing::Test {

    protected:

        virtual void SetUp() {
            /*
             * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
             * pointless as it may look, is carefully crafted to provoke
             * the GCC optimizer bug mentioned above.
             */
            testfn = trigger_alignment_bug;
            vec1 = OpenMesh::Vec4f(1.0f, 2.0f, 3.0f, 4.0f);
            vec2 = OpenMesh::Vec4f(5.0f, 6.0f, 7.0f, 8.0f);
            padding = 42;
        }

        virtual void TearDown() {
            // Do some final stuff with the member data here...
        }

    public:
        /*
         * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
         * pointless as it may look, is carefully crafted to provoke
         * the GCC optimizer bug mentioned above.
         */
        int32_t padding;
        OpenMesh::Vec4f vec1, vec2;
        void (*testfn)(OpenMeshVectorGCCBugTest &obj);

        OpenMesh::Vec4f &get_vec1() { return vec1; }
        OpenMesh::Vec4f &get_vec2() { return vec2; }
};

void trigger_alignment_bug(OpenMeshVectorGCCBugTest &obj) {
    /*
     * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
     * pointless as it may look, is carefully crafted to provoke
     * the GCC optimizer bug mentioned above.
     */
    int x1 = 1;

    OpenMesh::Vec4f vec3 = obj.get_vec1();
    OpenMesh::Vec4f vec4 = obj.get_vec2();
    vec3 += vec4;

    EXPECT_EQ(1, x1);
    EXPECT_EQ(42, obj.padding);
    EXPECT_EQ(6.0f, vec3[0]);
    EXPECT_EQ(8.0f, vec3[1]);
    EXPECT_EQ(10.0f, vec3[2]);
    EXPECT_EQ(12.0f, vec3[3]);
}

TEST_F(OpenMeshVectorGCCBugTest, alignment_bug) {
    /*
     * WARNING: DO NOT CHANGE ANYTHGIN! Every single line, as
     * pointless as it may look, is carefully crafted to provoke
     * the GCC optimizer bug mentioned above.
     */
    (*testfn)(*this);
}


399
}