Subversion Repositories gelsvn

Rev

Rev 632 | Rev 634 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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