Subversion Repositories gelsvn

Rev

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

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