Subversion Repositories gelsvn

Rev

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