Subversion Repositories gelsvn

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
667 khor 1
/* ----------------------------------------------------------------------- *
2
 * This file is part of GEL, http://www.imm.dtu.dk/GEL
3
 * Copyright (C) the authors and DTU Informatics
4
 * For license and list of authors, see ../../doc/intro.pdf
5
 * @brief Abstract vector class
6
 * ----------------------------------------------------------------------- */
7
 
8
/** @file ArithVec.h
9
 * @brief Abstract vector class
10
 */
11
 
12
#ifndef __CGLA_ARITHVEC_H__
13
#define __CGLA_ARITHVEC_H__
14
 
15
#include <array>
16
#include <algorithm>
17
#include <iostream>
18
#include "CGLA.h"
19
 
20
#include <numeric>
21
 
22
namespace CGLA
23
{
24
 
25
    /** \brief Template representing generic arithmetic vectors.
26
 
27
     The three parameters to the template are
28
 
29
     T - the scalar type (i.e. float, int, double etc.)
30
 
31
     V - the name of the vector type. This template is always (and
32
     only) used as ancestor of concrete types, and the name of the
33
     class _inheriting_ _from_ this class is used as the V argument.
34
 
35
     N - The final argument is the dimension N. For instance, N=3 for a
36
     3D vector.
37
 
38
     This class template contains all functions that are assumed to be
39
     the same for any arithmetic vector - regardless of dimension or
40
     the type of scalars used for coordinates.
41
 
42
     The template contains no virtual functions which is important
43
     since they add overhead.
44
     */
45
 
46
    template <class T, class V, unsigned int N>
47
    class ArithVec
48
    {
49
 
50
    protected:
51
 
52
        /// The actual contents of the vector.
53
        std::array<T,N> data;
54
 
55
    protected:
56
 
57
        //----------------------------------------------------------------------
58
        // Constructors
59
        //----------------------------------------------------------------------
60
 
61
        /// Construct uninitialized vector
62
        ArithVec() {}
63
 
64
        /// Construct a vector where all coordinates are identical
65
        explicit ArithVec(T _a)
66
        {
67
            std::fill_n(data, N, _a);
68
        }
69
 
70
        /// Construct a 2D vector
71
        ArithVec(T _a, T _b)
72
        {
73
            assert(N==2);
74
            data[0] = _a;
75
            data[1] = _b;
76
        }
77
 
78
        /// Construct a 3D vector
79
        ArithVec(T _a, T _b, T _c)
80
        {
81
            assert(N==3);
82
            data[0] = _a;
83
            data[1] = _b;
84
            data[2] = _c;
85
        }
86
 
87
        /// Construct a 4D vector
88
        ArithVec(T _a, T _b, T _c, T _d)
89
        {
90
            assert(N==4);
91
            data[0] = _a;
92
            data[1] = _b;
93
            data[2] = _c;
94
            data[3] = _d;
95
        }
96
    public:
97
 
98
        /// For convenience we define a more meaningful name for the scalar type
99
        typedef T ScalarType;
100
 
101
        /// A more meaningful name for vector type
102
        typedef V VectorType;
103
 
104
        /// Return dimension of vector
105
        static unsigned int get_dim() {return N;}
106
 
107
        /// Set all coordinates of a 2D vector.
108
        void set(T _a, T _b)
109
        {
110
            assert(N==2);
111
            data[0] = _a;
112
            data[1] = _b;
113
        }
114
 
115
        /// Set all coordinates of a 3D vector.
116
        void set(T _a, T _b, T _c)
117
        {
118
            assert(N==3);
119
            data[0] = _a;
120
            data[1] = _b;
121
            data[2] = _c;
122
        }
123
 
124
        /// Set all coordinates of a 4D vector.
125
        void set(T _a, T _b, T _c, T _d)
126
        {
127
            assert(N==4);
128
            data[0] = _a;
129
            data[1] = _b;
130
            data[2] = _c;
131
            data[3] = _d;
132
        }
133
 
134
        /// Const index operator
135
        const T& operator [] ( unsigned int i ) const
136
        {
137
            assert(i<N);
138
            return data[i];
139
        }
140
 
141
        /// Non-const index operator
142
        T& operator [] ( unsigned int i )
143
        {
144
            assert(i<N);
145
            return data[i];
146
        }
147
 
148
        /// Const index operator
149
        const T& operator () ( unsigned int i ) const
150
        {
151
            assert(i<N);
152
            return data[i];
153
        }
154
 
155
        /// Non-const index operator
156
        T& operator () ( unsigned int i )
157
        {
158
            assert(i<N);
159
            return data[i];
160
        }
161
 
162
        typedef typename std::array<T,N>::iterator iterator;
163
        typedef typename std::array<T,N>::const_iterator const_iterator;
164
 
165
 
166
        /** Get a pointer to first element in data array.
167
         This function may be useful when interfacing with some other API
168
         such as OpenGL (TM) */
169
        iterator begin() {return data.begin();}
170
        iterator end() {return data.end();}
171
        T* get() {return data.data();}
172
 
173
        /** Get a const pointer to first element in data array.
174
         This function may be useful when interfacing with some other API
175
         such as OpenGL (TM). */
176
        const_iterator begin() const {return data.begin();}
177
        const_iterator end() const {return data.end();}
178
        const T* get() const {return data.data();}
179
 
180
        //----------------------------------------------------------------------
181
        // Comparison operators
182
        //----------------------------------------------------------------------
183
 
184
        /// Equality operator
185
        bool operator==(const V& v) const
186
        {
187
            return std::equal(begin(),end(), v.begin());
188
        }
189
 
190
        /// Equality wrt scalar. True if all coords are equal to scalar
191
        bool operator==(T k) const
192
        {
193
            return std::count(begin(),end(), k)==N;
194
        }
195
 
196
        /// Inequality operator
197
        bool operator!=(const V& v) const
198
        {
199
            return !(*this==v);
200
        }
201
 
202
        /// Inequality wrt scalar. True if any coord not equal to scalar
203
        bool operator!=(T k) const
204
        {
205
            return !(*this==k);
206
        }
207
 
208
 
209
        //----------------------------------------------------------------------
210
        // Comparison functions ... of geometric significance
211
        //----------------------------------------------------------------------
212
 
213
        /** Compare all coordinates against other vector. ( < )
214
         Similar to testing whether we are on one side of three planes. */
215
        bool  all_l  (const V& v) const
216
        {
217
            return std::inner_product(begin(), end(), v.begin(), true,
218
                                      std::logical_and<bool>(), std::less<T>());
219
        }
220
 
221
        /** Compare all coordinates against other vector. ( <= )
222
         Similar to testing whether we are on one side of three planes. */
223
        bool  all_le (const V& v) const
224
        {
225
            return std::inner_product(begin(), end(), v.begin(), true,
226
                                      std::logical_and<bool>(), std::less_equal<T>());
227
        }
228
 
229
        /** Compare all coordinates against other vector. ( > )
230
         Similar to testing whether we are on one side of three planes. */
231
        bool  all_g  (const V& v) const
232
        {
233
            return std::inner_product(begin(), end(), v.begin(), true,
234
                                      std::logical_and<bool>(), std::greater<T>());
235
        }
236
 
237
        /** Compare all coordinates against other vector. ( >= )
238
         Similar to testing whether we are on one side of three planes. */
239
        bool  all_ge (const V& v) const
240
        {
241
            return std::inner_product(begin(), end(), v.begin(), true,
242
                                      std::logical_and<bool>(), std::greater_equal<T>());
243
        }
244
 
245
 
246
        //----------------------------------------------------------------------
247
        // Assignment operators
248
        //----------------------------------------------------------------------
249
 
250
        /// Assignment multiplication with scalar.
251
        const V& operator *=(T k)
252
        {
253
            for(auto& x : data) {x*=k;}
254
            return static_cast<const V&>(*this);
255
        }
256
 
257
        /// Assignment division with scalar.
258
        const V& operator /=(T k)
259
        {
260
            for(auto& x : data) {x/=k;}
261
            return static_cast<const V&>(*this);
262
        }
263
 
264
        /// Assignment addition with scalar. Adds scalar to each coordinate.
265
        const V& operator +=(T k)
266
        {
267
            for(auto& x : data) {x+=k;}
268
            return  static_cast<const V&>(*this);
269
        }
270
 
271
        /// Assignment subtraction with scalar. Subtracts scalar from each coord.
272
        const V& operator -=(T k)
273
        {
274
            for(auto& x : data) {x-=k;}
275
            return  static_cast<const V&>(*this);
276
        }
277
 
278
        /** Assignment multiplication with vector.
279
         Multiply each coord independently. */
280
        const V& operator *=(const V& v)
281
        {
282
            std::transform(begin(), end(), v.begin(), begin(), std::multiplies<T>());
283
            return  static_cast<const V&>(*this);
284
        }
285
 
286
        /// Assigment division with vector. Each coord divided independently.
287
        const V& operator /=(const V& v)
288
        {
289
            std::transform(begin(), end(),  v.begin(), begin(), std::divides<T>());
290
            return  static_cast<const V&>(*this);
291
        }
292
 
293
        /// Assignmment addition with vector.
294
        const V& operator +=(const V& v)
295
        {
296
            std::transform(begin(), end(), v.begin(), begin(), std::plus<T>());
297
            return  static_cast<const V&>(*this);
298
        }
299
 
300
        /// Assignment subtraction with vector.
301
        const V& operator -=(const V& v)
302
        {
303
            std::transform(begin(), end(), v.begin(), begin(), std::minus<T>());
304
            return  static_cast<const V&>(*this);
305
        }
306
 
307
 
308
        //----------------------------------------------------------------------
309
        // Unary operators on vectors
310
        //----------------------------------------------------------------------
311
 
312
        /// Negate vector.
313
        const V operator - () const
314
        {
315
            V v_new;
316
            std::transform(begin(), end(), v_new.begin(), std::negate<T>());
317
            return v_new;
318
        }
319
 
320
        //----------------------------------------------------------------------
321
        // Binary operators on vectors
322
        //----------------------------------------------------------------------
323
 
324
        /** Multiply vector with vector. Each coord multiplied independently
325
         Do not confuse this operation with dot product. */
326
        const V operator * (const V& v1) const
327
        {
328
            V v_new;
329
            std::transform(begin(), end(), v1.begin(), v_new.begin(), std::multiplies<T>());
330
            return v_new;
331
        }
332
 
333
        /// Add two vectors
334
        const V operator + (const V& v1) const
335
        {
336
            V v_new;
337
            std::transform(begin(), end(), v1.begin(), v_new.begin(), std::plus<T>());
338
            return v_new;
339
        }
340
 
341
        /// Subtract two vectors.
342
        const V operator - (const V& v1) const
343
        {
344
            V v_new;
345
            std::transform(begin(), end(), v1.begin(), v_new.begin(), std::minus<T>());
346
            return v_new;
347
        }
348
 
349
        /// Divide two vectors. Each coord separately
350
        const V operator / (const V& v1) const
351
        {
352
            V v_new;
353
            std::transform(begin(), end(), v1.begin(), v_new.begin(), std::divides<T>());
354
            return v_new;
355
        }
356
 
357
        //----------------------------------------------------------------------
358
        // Binary operators on vector and scalar
359
        //----------------------------------------------------------------------
360
 
361
        /// Multiply scalar onto vector.
362
        const V operator * (T k) const
363
        {
364
            V v_new;
365
            std::transform(begin(), end(), v_new.begin(), [k](T x){return x*k;});
366
            return v_new;
367
        }
368
 
369
 
370
        /// Divide vector by scalar.
371
        const V operator / (T k) const
372
        {
373
            V v_new;
374
            std::transform(begin(), end(), v_new.begin(), [k](T x){return x/k;});
375
            return v_new;
376
        }
377
 
378
 
379
        /// Return the smallest coordinate of the vector
380
        const T min_coord() const
381
        {
382
            return *std::min_element(begin(), end());
383
        }
384
 
385
        /// Return the largest coordinate of the vector
386
        const T max_coord() const
387
        {
388
            return *std::max_element(begin(), end());
389
        }
390
 
391
    };
392
 
393
    template <class T, class V, unsigned int N>
394
    inline std::ostream& operator<<(std::ostream&os, const ArithVec<T,V,N>& v)
395
    {
396
        os << "[ ";
397
        for(const T& x : v) os << x << " ";
398
        os << "]";
399
        return os;
400
        }
401
 
402
        /// Get from operator for ArithVec descendants.
403
        template <class T,class V, unsigned int N>
404
        inline std::istream& operator>>(std::istream&is, ArithVec<T,V,N>& v)
405
        {
406
            is >> std::ws;
407
            if (is.peek() == '[')
408
                is.ignore();
409
            is >> std::ws;
410
            for (int c=0; c<N; ++c)
411
            {
412
                is >> v(c) >> std::ws;
413
            }
414
            if (is.peek() == ']')
415
                is.ignore();
416
            return is;
417
        }
418
 
419
 
420
        /** Dot product for two vectors. The `*' operator is
421
         reserved for coordinatewise	multiplication of vectors. */
422
        template <class T,class V, unsigned int N>
423
        inline T dot(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
424
        {
425
            return std::inner_product(v0.begin(), v0.end(), v1.begin(), T(0));
426
        }
427
 
428
        /** Compute the sqr length by taking dot product of vector with itself. */
429
        template <class T,class V, unsigned int N>
430
        inline T sqr_length(const ArithVec<T,V,N>& v)
431
        {
432
            return dot(v,v);
433
        }
434
 
435
        /** Multiply double onto vector. This operator handles the case
436
         where the vector is on the righ side of the `*'.
437
 
438
         \note It seems to be optimal to put the binary operators inside the
439
         ArithVec class template, but the operator functions whose
440
         left operand is _not_ a vector cannot be inside, hence they
441
         are here.
442
         We need three operators for scalar * vector although they are
443
         identical, because, if we use a separate template argument for
444
         the left operand, it will match any type. If we use just T as
445
         type for the left operand hoping that other built-in types will
446
         be automatically converted, we will be disappointed. It seems that
447
         a float * ArithVec<float,Vec3f,3> function is not found if the
448
         left operand is really a double.
449
         */
450
 
451
        template<class T, class V, unsigned int N>
452
        inline const V operator * (double k, const ArithVec<T,V,N>& v)
453
        {
454
            return v * k;
455
        }
456
 
457
        /** Multiply float onto vector. See the note in the documentation
458
         regarding multiplication of a double onto a vector. */
459
        template<class T, class V, unsigned int N>
460
        inline const V operator * (float k, const ArithVec<T,V,N>& v)
461
        {
462
            return v * k;
463
        }
464
 
465
        /** Multiply unsigned int onto vector. See the note in the documentation
466
         regarding multiplication of a double onto a vector. */
467
        template<class T, class V, unsigned int N>
468
        inline const V operator * (int k, const ArithVec<T,V,N>& v)
469
        {
470
            return v * k;
471
        }
472
 
473
        /** Returns the vector containing for each coordinate the smallest
474
         value from two vectors. */
475
        template <class T,class V, unsigned int N>
476
        inline V v_min(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
477
        {
478
            V v;
479
            std::transform(v0.begin(), v0.end(), v1.begin(), v.begin(),
480
                           [](T a, T b){return (std::min)(a,b);});
481
            return v;
482
        }
483
 
484
        /** Returns the vector containing for each coordinate the largest
485
         value from two vectors. */
486
        template <class T,class V, unsigned int N>
487
        inline V v_max(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
488
        {
489
            V v;
490
            std::transform(v0.begin(), v0.end(), v1.begin(), v.begin(),
491
                           [](T a, T b){return (std::max)(a,b);});
492
            return v;
493
        }
494
 
495
 
496
}
497
 
498
#endif