Subversion Repositories gelsvn

Rev

Rev 18 | 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
 
19 jrf 7
#include <numeric>
8
#include <functional>
9
#include <memory>
2 bj 10
 
12 jab 11
namespace CGLA 
12
{
2 bj 13
 
12 jab 14
  /** The ArithVec class template represents a generic arithmetic
15
      vector.  The three parameters to the template are
2 bj 16
 
12 jab 17
      T - the scalar type (i.e. float, int, double etc.)
2 bj 18
 
12 jab 19
      V - the name of the vector type. This template is always (and
20
      only) used as ancestor of concrete types, and the name of the
21
      class _inheriting_ _from_ this class is used as the V argument.
2 bj 22
 
12 jab 23
      N - The final argument is the dimension N. For instance, N=3 for a
24
      3D vector.
2 bj 25
 
12 jab 26
      This class template contains all functions that are assumed to be
27
      the same for any arithmetic vector - regardless of dimension or
28
      the type of scalars used for coordinates.
2 bj 29
 
12 jab 30
      The template contains no virtual functions which is important
31
      since they add overhead.
32
  */
2 bj 33
 
12 jab 34
  template <class T, class V, int N> 
35
    class ArithVec
36
    {
2 bj 37
#define for_all_i(expr) for(int i=0;i<N;i++) {expr;}
38
 
12 jab 39
    protected:
2 bj 40
 
12 jab 41
      /// The actual contents of the vector.
42
      T data[N];
2 bj 43
 
12 jab 44
    protected:
2 bj 45
 
12 jab 46
      //----------------------------------------------------------------------
47
      // Constructors
48
      //----------------------------------------------------------------------
2 bj 49
 
12 jab 50
      /// Construct uninitialized vector
51
      ArithVec() 
52
	{
53
	}
2 bj 54
 
12 jab 55
      /// Construct a vector where all coordinates are identical
56
      explicit ArithVec(T _a)
57
	{
19 jrf 58
	  std::fill_n(data, N, _a);
12 jab 59
	}
2 bj 60
 
12 jab 61
      /// Construct a 2D vector 
62
      ArithVec(T _a, T _b)
63
	{
64
	  assert(N==2);
65
	  data[0] = _a;
66
	  data[1] = _b;
67
	}
2 bj 68
 
12 jab 69
      /// Construct a 3D vector
70
      ArithVec(T _a, T _b, T _c)
71
	{
72
	  assert(N==3);
73
	  data[0] = _a;
74
	  data[1] = _b;
75
	  data[2] = _c;
76
	}
2 bj 77
 
12 jab 78
      /// Construct a 4D vector
79
      ArithVec(T _a, T _b, T _c, T _d)
80
	{
81
	  assert(N==4);
82
	  data[0] = _a;
83
	  data[1] = _b;
84
	  data[2] = _c;
85
	  data[3] = _d;
86
	}
2 bj 87
 
88
 
12 jab 89
    public:
2 bj 90
 
12 jab 91
      /// For convenience we define a more meaningful name for the scalar type
92
      typedef T ScalarType;
2 bj 93
 
12 jab 94
      /// A more meaningful name for vector type
95
      typedef V VectorType;
2 bj 96
 
12 jab 97
      /// Return dimension of vector
98
      static int get_dim() {return N;}
2 bj 99
 
12 jab 100
      /// Set all coordinates of a 2D vector.
101
      void set(T _a, T _b)
102
	{
103
	  assert(N==2);
104
	  data[0] = _a;
105
	  data[1] = _b;
106
	}
2 bj 107
 
12 jab 108
      /// Set all coordinates of a 3D vector.
109
      void set(T _a, T _b, T _c)
110
	{
111
	  assert(N==3);
112
	  data[0] = _a;
113
	  data[1] = _b;
114
	  data[2] = _c;
115
	}
2 bj 116
 
12 jab 117
      /// Set all coordinates of a 4D vector.
118
      void set(T _a, T _b, T _c, T _d)
119
	{
120
	  assert(N==4);
121
	  data[0] = _a;
122
	  data[1] = _b;
123
	  data[2] = _c;
124
	  data[3] = _d;
125
	}
2 bj 126
 
12 jab 127
      /// Const index operator
128
      const T& operator [] ( int i ) const
129
	{
130
	  assert(i<N);
131
	  return data[i];
132
	}
2 bj 133
 
12 jab 134
      /// Non-const index operator
135
      T& operator [] ( int i ) 
136
	{
137
	  assert(i<N);
138
	  return data[i];
139
	}
2 bj 140
 
12 jab 141
      /** Get a pointer to first element in data array.
142
	  This function may be useful when interfacing with some other API 
143
	  such as OpenGL (TM) */
144
      T* get() {return &data[0];}
2 bj 145
 
12 jab 146
      /** Get a const pointer to first element in data array.
147
	  This function may be useful when interfacing with some other API 
148
	  such as OpenGL (TM). */
149
      const T* get() const {return &data[0];}
2 bj 150
 
12 jab 151
      //----------------------------------------------------------------------
152
      // Comparison operators
153
      //----------------------------------------------------------------------
2 bj 154
 
12 jab 155
      /// Equality operator
156
      bool operator==(const V& v) const 
157
	{
19 jrf 158
	  return std::inner_product(data, &data[N], v.get(), true,
159
				    std::logical_and<bool>(), std::equal_to<T>());
12 jab 160
	}
2 bj 161
 
12 jab 162
      /// Equality wrt scalar. True if all coords are equal to scalar
163
      bool operator==(T k) const 
164
	{ 
165
	  for_all_i(if (data[i] != k) return false)
166
	    return true;
167
	}
2 bj 168
 
12 jab 169
      /// Inequality operator
170
      bool operator!=(const V& v) const 
171
	{
19 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
	{
19 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
	{
19 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
	{
19 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
	{
19 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
 
12 jab 224
      /// Assigment multiplication with scalar.
225
      const V& operator *=(T k) 
226
	{ 
19 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
	{ 
19 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
	{
19 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
	{ 
19 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
	{ 
19 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
	{
19 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
	{
19 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
	{ 
19 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;
19 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;
19 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;
19 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;
19 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;
19 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;
19 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;
19 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
	{
19 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
	{
19 jrf 362
	  return *std::max_element(data, &data[N]);
2 bj 363
	}
364
 
12 jab 365
#undef for_all_i  
366
    };
2 bj 367
 
12 jab 368
  template <class T, class V, int N> 
369
    inline std::ostream& operator<<(std::ostream&os, const ArithVec<T,V,N>& v)
370
    {
371
      os << "[ ";
372
      for(int i=0;i<N;i++) os << v[i] << " ";
373
      os << "]";
374
      return os;
375
    }
376
 
377
  /// Get from operator for ArithVec descendants. 
378
  template <class T,class V, int N>
379
    inline std::istream& operator>>(std::istream&is, ArithVec<T,V,N>& v)
380
    {
381
      for(int i=0;i<N;i++) is>>v[i];
382
      return is;
383
    }
384
 
385
 
386
  /** Dot product for two vectors. The `*' operator is 
387
      reserved for coordinatewise	multiplication of vectors. */
388
  template <class T,class V, int N>
389
    inline T dot(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
390
    {
19 jrf 391
      return std::inner_product(v0.get(), v0.get() + N, v1.get(), T(0));
12 jab 392
    }
393
 
394
  /** Compute the sqr length by taking dot product of vector with itself. */
395
  template <class T,class V, int N>
396
    inline T sqr_length(const ArithVec<T,V,N>& v)
397
    {
398
      return dot(v,v);
399
    }
400
 
401
  /** Multiply double onto vector. This operator handles the case 
402
      where the vector is on the righ side of the `*'.
403
 
404
      \note It seems to be optimal to put the binary operators inside the
405
      ArithVec class template, but the operator functions whose 
406
      left operand is _not_ a vector cannot be inside, hence they
407
      are here.
408
      We need three operators for scalar * vector although they are
409
      identical, because, if we use a separate template argument for
410
      the left operand, it will match any type. If we use just T as 
411
      type for the left operand hoping that other built-in types will
412
      be automatically converted, we will be disappointed. It seems that 
413
      a float * ArithVec<float,Vec3f,3> function is not found if the
414
      left operand is really a double.
415
  */
416
 
417
  template<class T, class V, int N>
418
    inline const V operator * (double k, const ArithVec<T,V,N>& v) 
419
    {
420
      return v * k;
421
    }
422
 
423
  /** Multiply float onto vector. See the note in the documentation
424
      regarding multiplication of a double onto a vector. */
425
  template<class T, class V, int N>
426
    inline const V operator * (float k, const ArithVec<T,V,N>& v) 
427
    {
428
      return v * k;
429
    }
430
 
431
  /** Multiply int onto vector. See the note in the documentation
432
      regarding multiplication of a double onto a vector. */
433
  template<class T, class V, int N>
434
    inline const V operator * (int k, const ArithVec<T,V,N>& v) 
435
    {
436
      return v * k;
437
    }
438
 
439
  /** Returns the vector containing for each coordinate the smallest
440
      value from two vectors. */
441
  template <class T,class V, int N>
442
    inline V v_min(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
443
    {
444
      V v;
445
      for(int i=0;i<N;i++)
446
	v[i] = s_min(v0[i],v1[i]);
19 jrf 447
      //std::transform(v0.get(), &v0[N], v1.get(), v.get(), std::ptr_fun(s_min));
12 jab 448
      return v;
449
    }
450
 
451
  /** Returns the vector containing for each coordinate the largest 
452
      value from two vectors. */
453
  template <class T,class V, int N>
454
    inline V v_max(const ArithVec<T,V,N>& v0, const ArithVec<T,V,N>& v1)
455
    {
456
      V v;
457
      for(int i=0;i<N;i++) 
458
	v[i] = s_max(v0[i],v1[i]);
19 jrf 459
      //std::transform(v0.get(), &v0[N], v1.get(), v.get(), std::ptr_fun(s_max));
12 jab 460
      return v;
461
    }
462
 
463
 
2 bj 464
}
465
 
466
#endif