Subversion Repositories gelsvn

Rev

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