source: projectionDesigner/trunk/projdesigner/include/gmtl/VecOps.h @ 287

Last change on this file since 287 was 4, checked in by Torben Dannhauer, 15 years ago
File size: 19.2 KB
Line 
1/************************************************************** ggt-head beg
2 *
3 * GGT: Generic Graphics Toolkit
4 *
5 * Original Authors:
6 *   Allen Bierbaum
7 *
8 * -----------------------------------------------------------------
9 * File:          VecOps.h,v
10 * Date modified: 2005/12/03 20:54:25
11 * Version:       1.34
12 * -----------------------------------------------------------------
13 *
14 *********************************************************** ggt-head end */
15/*************************************************************** ggt-cpr beg
16*
17* GGT: The Generic Graphics Toolkit
18* Copyright (C) 2001,2002 Allen Bierbaum
19*
20* This library is free software; you can redistribute it and/or
21* modify it under the terms of the GNU Lesser General Public
22* License as published by the Free Software Foundation; either
23* version 2.1 of the License, or (at your option) any later version.
24*
25* This library is distributed in the hope that it will be useful,
26* but WITHOUT ANY WARRANTY; without even the implied warranty of
27* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28* Lesser General Public License for more details.
29*
30* You should have received a copy of the GNU Lesser General Public
31* License along with this library; if not, write to the Free Software
32* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33*
34 ************************************************************ ggt-cpr end */
35#ifndef _GMTL_VEC_OPS_H_
36#define _GMTL_VEC_OPS_H_
37
38#include <gmtl/Defines.h>
39#include <gmtl/Math.h>
40#include <gmtl/Vec.h>
41#ifndef GMTL_NO_METAPROG
42#include <gmtl/VecOpsMeta.h>
43#include <gmtl/VecExprMeta.h>
44#endif
45
46namespace gmtl
47{
48
49/** @ingroup Ops
50 * @name Vector/Point Operations
51 * @{
52 */
53
54// --- Basic VEC types operations -- //
55
56/**
57 * Negates v1.  The result = -v1.
58 *
59 * @param v1   the vector.
60 *
61 * @return  the result of negating v1.
62 */
63#ifdef GMTL_NO_METAPROG
64template<typename DATA_TYPE, unsigned SIZE>
65Vec<DATA_TYPE, SIZE> operator- (const VecBase<DATA_TYPE, SIZE>& v1)
66{
67   Vec<DATA_TYPE, SIZE> ret_val;
68   for ( unsigned i=0; i < SIZE; ++i )
69   {
70      ret_val[i] = -v1[i];
71   }
72   return ret_val;
73}
74#else
75template<typename T, unsigned SIZE, typename R1>
76inline VecBase<T,SIZE, meta::VecUnaryExpr<VecBase<T,SIZE,R1>, meta::VecNegUnary> >
77operator-(const VecBase<T,SIZE,R1>& v1)
78{
79   return VecBase<T,SIZE,
80                  meta::VecUnaryExpr<VecBase<T,SIZE,R1>, meta::VecNegUnary> >
81                        ( meta::VecUnaryExpr<VecBase<T,SIZE,R1>, meta::VecNegUnary>(v1) );
82}
83#endif
84
85/**
86 * Adds v2 to v1 and stores the result in v1. This is equivalent to the
87 * expression v1 = v1 + v2.
88 *
89 * @param v1   the first vector
90 * @param v2   the second vector
91 *
92 * @return  v1 after v2 has been added to it
93 */
94#ifdef GMTL_NO_METAPROG
95template<class DATA_TYPE, unsigned SIZE>
96VecBase<DATA_TYPE, SIZE>& operator +=(VecBase<DATA_TYPE, SIZE>& v1,
97                                      const VecBase<DATA_TYPE, SIZE>& v2)
98#else
99template<class DATA_TYPE, unsigned SIZE, typename REP2>
100VecBase<DATA_TYPE, SIZE>& operator +=(VecBase<DATA_TYPE, SIZE>& v1,
101                                      const VecBase<DATA_TYPE, SIZE, REP2>& v2)
102#endif
103{
104   for(unsigned i=0;i<SIZE;++i)
105   {
106      v1[i] += v2[i];
107   }
108
109   return v1;
110}
111
112/**
113 * Adds v2 to v1 and returns the result. Thus result = v1 + v2.
114 *
115 * @param v1   the first vector
116 * @param v2   the second vector
117 *
118 * @return  the result of adding v2 to v1
119 */
120#ifdef GMTL_NO_METAPROG
121template<class DATA_TYPE, unsigned SIZE>
122VecBase<DATA_TYPE, SIZE> operator +(const VecBase<DATA_TYPE, SIZE>& v1,
123                                    const VecBase<DATA_TYPE, SIZE>& v2)
124{
125   VecBase<DATA_TYPE, SIZE> ret_val(v1);
126   ret_val += v2;
127   return ret_val;
128}
129#else
130template<typename T, unsigned SIZE, typename R1, typename R2>
131inline VecBase<T,SIZE, meta::VecBinaryExpr<VecBase<T,SIZE,R1>, VecBase<T,SIZE,R2>, meta::VecPlusBinary> >
132operator+(const VecBase<T,SIZE,R1>& v1, const VecBase<T,SIZE,R2>& v2)
133{
134   return VecBase<T,SIZE,
135               meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
136                                   VecBase<T,SIZE,R2>,
137                                   meta::VecPlusBinary> >( meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
138                                                                               VecBase<T,SIZE,R2>,
139                                                                               meta::VecPlusBinary>(v1,v2) );
140}
141#endif
142
143/**
144 * Subtracts v2 from v1 and stores the result in v1. This is equivalent to the
145 * expression v1 = v1 - v2.
146 *
147 * @param v1   the first vector
148 * @param v2   the second vector
149 *
150 * @return  v1 after v2 has been subtracted from it
151 */
152#ifdef GMTL_NO_METAPROG
153template<class DATA_TYPE, unsigned SIZE>
154VecBase<DATA_TYPE, SIZE>& operator -=(VecBase<DATA_TYPE, SIZE>& v1,
155                                      const VecBase<DATA_TYPE, SIZE>& v2)
156#else
157template<class DATA_TYPE, unsigned SIZE, typename REP2>
158VecBase<DATA_TYPE, SIZE>& operator -=(VecBase<DATA_TYPE, SIZE>& v1,
159                                      const VecBase<DATA_TYPE, SIZE, REP2>& v2)
160#endif
161{
162   for(unsigned i=0;i<SIZE;++i)
163   {
164      v1[i] -= v2[i];
165   }
166
167   return v1;
168}
169
170/**
171 * Subtracts v2 from v1 and returns the result. Thus result = v1 - v2.
172 *
173 * @param v1   the first vector
174 * @param v2   the second vector
175 *
176 * @return  the result of subtracting v2 from v1
177 */
178#ifdef GMTL_NO_METAPROG
179template < class DATA_TYPE, unsigned SIZE>
180Vec<DATA_TYPE, SIZE> operator -(const VecBase<DATA_TYPE, SIZE>& v1,
181                                const VecBase<DATA_TYPE, SIZE>& v2)
182{
183   Vec<DATA_TYPE, SIZE> ret_val(v1);
184   ret_val -= v2;
185   return ret_val;
186}
187#else
188template<typename T, unsigned SIZE, typename R1, typename R2>
189inline VecBase<T,SIZE, meta::VecBinaryExpr<VecBase<T,SIZE,R1>, VecBase<T,SIZE,R2>, meta::VecMinusBinary> >
190operator-(const VecBase<T,SIZE,R1>& v1, const VecBase<T,SIZE,R2>& v2)
191{
192   return VecBase<T,SIZE,
193               meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
194                                   VecBase<T,SIZE,R2>,
195                                   meta::VecMinusBinary> >( meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
196                                                                               VecBase<T,SIZE,R2>,
197                                                                               meta::VecMinusBinary>(v1,v2) );
198}
199#endif
200
201/**
202 * Multiplies v1 by a scalar value and stores the result in v1. This is
203 * equivalent to the expression v1 = v1 * scalar.
204 *
205 * @param v1      the vector to scale
206 * @param scalar  the amount by which to scale v1
207 *
208 * @return  v1 after it has been mutiplied by scalar
209 */
210template<class DATA_TYPE, unsigned SIZE, class SCALAR_TYPE>
211VecBase<DATA_TYPE, SIZE>& operator *=(VecBase<DATA_TYPE, SIZE>& v1,
212                                      const SCALAR_TYPE& scalar)
213{
214   for(unsigned i=0;i<SIZE;++i)
215   {
216      v1[i] *= (DATA_TYPE)scalar;
217   }
218
219   return v1;
220}
221
222/**
223 * Multiplies v1 by a scalar value and returns the result. Thus result = v1 *
224 * scalar.
225 *
226 * @param v1      the vector to scale
227 * @param scalar  the amount by which to scale v1
228 *
229 * @return  the result of multiplying v1 by scalar
230 */
231#ifdef GMTL_NO_METAPROG
232template<class DATA_TYPE, unsigned SIZE, class SCALAR_TYPE>
233VecBase<DATA_TYPE, SIZE> operator *(const VecBase<DATA_TYPE, SIZE>& v1,
234                                    const SCALAR_TYPE& scalar)
235{
236   VecBase<DATA_TYPE, SIZE> ret_val(v1);
237   ret_val *= scalar;
238   return ret_val;
239
240   //return VecBase<DATA_TYPE, SIZE>(v1) *= scalar;
241}
242#else
243template<typename T, unsigned SIZE, typename R1>
244inline VecBase<T,SIZE, meta::VecBinaryExpr<VecBase<T,SIZE,R1>, VecBase<T,SIZE, meta::ScalarArg<T> >, meta::VecMultBinary> >
245operator*(const VecBase<T,SIZE,R1>& v1, const T scalar)
246{
247   return VecBase<T,SIZE,
248             meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
249                                 VecBase<T,SIZE, meta::ScalarArg<T> >,
250                                 meta::VecMultBinary> >(
251                                       meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
252                                                           VecBase<T,SIZE, meta::ScalarArg<T> >,
253                                                           meta::VecMultBinary>(v1,
254                                                                                meta::ScalarArg<T>(scalar)) );
255}
256
257template<typename T, unsigned SIZE, typename R1>
258inline VecBase<T,SIZE, meta::VecBinaryExpr< VecBase<T,SIZE, meta::ScalarArg<T> >,
259                                            VecBase<T,SIZE,R1>,
260                                            meta::VecMultBinary> >
261operator*(const T scalar, const VecBase<T,SIZE,R1>& v1)
262{
263   return VecBase<T,SIZE,
264             meta::VecBinaryExpr<VecBase<T,SIZE, meta::ScalarArg<T> >,
265                                 VecBase<T,SIZE,R1>,
266                                 meta::VecMultBinary> >(
267                                       meta::VecBinaryExpr<VecBase<T,SIZE, meta::ScalarArg<T> >,
268                                                           VecBase<T,SIZE,R1>,
269                                                           meta::VecMultBinary>(meta::ScalarArg<T>(scalar), v1 ) );
270}
271#endif
272
273/**
274 * Multiplies v1 by a scalar value and returns the result. Thus result = scalar
275 * * v1. This is equivalent to result = v1 * scalar.
276 *
277 * @param scalar  the amount by which to scale v1
278 * @param v1      the vector to scale
279 *
280 * @return  the result of multiplying v1 by scalar
281 */
282#ifdef GMTL_NO_METAPROG
283template<class DATA_TYPE, unsigned SIZE, class SCALAR_TYPE>
284VecBase<DATA_TYPE, SIZE> operator *(const SCALAR_TYPE& scalar,
285                                    const VecBase<DATA_TYPE, SIZE>& v1)
286{
287   VecBase<DATA_TYPE, SIZE> ret_val(v1);
288   ret_val *= scalar;
289   return ret_val;
290
291   //return VecBase<DATA_TYPE, SIZE>(v1) *= scalar;
292}
293#endif
294
295/**
296 * Divides v1 by a scalar value and stores the result in v1. This is
297 * equivalent to the expression v1 = v1 / scalar.
298 *
299 * @param v1      the vector to scale
300 * @param scalar  the amount by which to scale v1
301 *
302 * @return  v1 after it has been divided by scalar
303 */
304template<class DATA_TYPE, unsigned SIZE, class SCALAR_TYPE>
305VecBase<DATA_TYPE, SIZE>& operator /=(VecBase<DATA_TYPE, SIZE>& v1,
306                                      const SCALAR_TYPE& scalar)
307{
308   for(unsigned i=0;i<SIZE;++i)
309   {
310      v1[i] /= scalar;
311   }
312
313   return v1;
314}
315
316/**
317 * Divides v1 by a scalar value and returns the result. Thus result = v1 /
318 * scalar.
319 *
320 * @param v1      the vector to scale
321 * @param scalar  the amount by which to scale v1
322 *
323 * @return  the result of dividing v1 by scalar
324 */
325#ifdef GMTL_NO_METAPROG
326template<class DATA_TYPE, unsigned SIZE, class SCALAR_TYPE>
327VecBase<DATA_TYPE, SIZE> operator /(const VecBase<DATA_TYPE, SIZE>& v1,
328                                    const SCALAR_TYPE& scalar)
329{
330   VecBase<DATA_TYPE, SIZE> ret_val(v1);
331   ret_val /= scalar;
332   return ret_val;
333   // return VecBase<DATA_TYPE, SIZE>(v1)( /= scalar;
334}
335#else
336template<typename T, unsigned SIZE, typename R1>
337inline VecBase<T,SIZE, meta::VecBinaryExpr<VecBase<T,SIZE,R1>, VecBase<T,SIZE, meta::ScalarArg<T> >, meta::VecDivBinary> >
338operator/(const VecBase<T,SIZE,R1>& v1, const T scalar)
339{
340   return VecBase<T,SIZE,
341             meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
342                                 VecBase<T,SIZE, meta::ScalarArg<T> >,
343                                 meta::VecDivBinary> >(
344                                       meta::VecBinaryExpr<VecBase<T,SIZE,R1>,
345                                                           VecBase<T,SIZE, meta::ScalarArg<T> >,
346                                                           meta::VecDivBinary>(v1,
347                                                                               meta::ScalarArg<T>(scalar)) );
348}
349#endif
350
351/** @} */
352
353
354/** @ingroup Ops
355 *  @name Vector Operations
356 * @{
357 */
358
359/**
360 * Computes dot product of v1 and v2 and returns the result.
361 *
362 * @param v1   the first vector
363 * @param v2   the second vector
364 *
365 * @return the dotproduct of v1 and v2
366 */
367#ifdef GMTL_NO_METAPROG
368template<class DATA_TYPE, unsigned SIZE>
369DATA_TYPE dot(const VecBase<DATA_TYPE, SIZE>& v1, const VecBase<DATA_TYPE, SIZE>& v2)
370{
371   DATA_TYPE ret_val(0);
372   for(unsigned i=0;i<SIZE;++i)
373   {
374      ret_val += (v1[i] * v2[i]);
375   }
376   return ret_val;
377}
378#else
379template<class DATA_TYPE, unsigned SIZE, typename REP1, typename REP2>
380DATA_TYPE dot(const VecBase<DATA_TYPE, SIZE, REP1>& v1, const VecBase<DATA_TYPE, SIZE, REP2>& v2)
381{
382   return gmtl::meta::DotVecUnrolled<SIZE-1,
383                                     VecBase<DATA_TYPE,SIZE,REP1>,
384                                     VecBase<DATA_TYPE,SIZE,REP2> >::func(v1,v2);
385}
386#endif
387
388/**
389 * Computes the length of the given vector.
390 *
391 * @param v1   the vector with which to compute the length
392 *
393 * @return  the length of v1
394 */
395template<class DATA_TYPE, unsigned SIZE>
396DATA_TYPE length(const Vec<DATA_TYPE, SIZE>& v1)
397{
398   DATA_TYPE ret_val = lengthSquared(v1);
399   if (ret_val == DATA_TYPE(0.0f))
400      return DATA_TYPE(0.0f);
401   else
402      return Math::sqrt(ret_val);
403}
404
405/**
406 * Computes the square of the length of the given vector. This can be used in
407 * many calculations instead of length to increase speed by saving you an
408 * expensive sqrt call.
409 *
410 * @param v1   the vector with which to compute the squared length
411 *
412 * @return  the square of the length of v1
413 */
414template<class DATA_TYPE, unsigned SIZE>
415DATA_TYPE lengthSquared(const Vec<DATA_TYPE, SIZE>& v1)
416{
417#ifdef GMTL_NO_METAPROG
418   DATA_TYPE ret_val(0);
419   for(unsigned i=0;i<SIZE;++i)
420   {
421      ret_val += (v1[i] * v1[i]);
422   }
423
424   return ret_val;
425#else
426   return gmtl::meta::LenSqrVecUnrolled<SIZE-1,Vec<DATA_TYPE,SIZE> >::func(v1);
427#endif
428}
429
430/**
431 * Normalizes the given vector in place causing it to be of unit length. If the
432 * vector is already of length 1.0, nothing is done. For convenience, the
433 * original length of the vector is returned.
434 *
435 * @post length(v1) == 1.0 unless length(v1) is originally 0.0, in which case it is unchanged
436 *
437 * @param v1   the vector to normalize
438 *
439 * @return  the length of v1 before it was normalized
440 */
441template<class DATA_TYPE, unsigned SIZE>
442DATA_TYPE normalize(Vec<DATA_TYPE, SIZE>& v1)
443{
444   DATA_TYPE len = length(v1);
445
446   if(len != 0.0f)
447   {
448      for(unsigned i=0;i<SIZE;++i)
449      {
450         v1[i] /= len;
451      }
452   }
453
454   return len;
455}
456
457/**
458 * Determines if the given vector is normalized within the given tolerance. The
459 * vector is normalized if its lengthSquared is 1.
460 *
461 * @param v1      the vector to test
462 * @param eps     the epsilon tolerance
463 *
464 * @return  true if the vector is normalized, false otherwise
465 */
466template< class DATA_TYPE, unsigned SIZE >
467bool isNormalized( const Vec<DATA_TYPE, SIZE>& v1,
468                   const DATA_TYPE eps = (DATA_TYPE) 0.0001f )
469{
470   return Math::isEqual( lengthSquared( v1 ), DATA_TYPE(1.0), eps );
471}
472
473/**
474 * Computes the cross product between v1 and v2 and stores the result in result.
475 * The result is also returned by reference. Use this when you want to reuse an
476 * existing Vec to store the result. Note that this only applies to
477 * 3-dimensional vectors.
478 *
479 * @pre v1 and v2 are 3-D vectors
480 * @post result = v1 x v2
481 *
482 * @param result  filled with the result of the cross product between v1 and v2
483 * @param v1   the first vector
484 * @param v2   the second vector
485 *
486 * @return  a reference to result for convenience
487 */
488template<class DATA_TYPE>
489Vec<DATA_TYPE,3>& cross( Vec<DATA_TYPE,3>& result, const Vec<DATA_TYPE, 3>& v1,
490                         const Vec<DATA_TYPE, 3>& v2 )
491{
492   result.set( (v1[Yelt]*v2[Zelt]) - (v1[Zelt]*v2[Yelt]),
493               (v1[Zelt]*v2[Xelt]) - (v1[Xelt]*v2[Zelt]),
494               (v1[Xelt]*v2[Yelt]) - (v1[Yelt]*v2[Xelt]) );
495   return result;
496}
497
498/**
499 * Reflect a vector about a normal.
500 *
501 * This method reflects the given vector around the normal vector given.  It is similar to if the normal vector was
502 * for a plane that you wanted to reflect about.  v going into the plane, n normal to the plane, and r coming back out
503 * of the plane. (see below)
504 *
505 * |   v
506 * | /
507 * |/
508 * |------> n
509 * |\
510 * | \
511 * |  r
512 *
513 * @param result     the vector to store the result i
514 * @param vec        the original vector that we want to reflect
515 * @param normal     the normal vector
516 *
517 * @post result contains the reflected vector
518*/
519template<class DATA_TYPE, unsigned SIZE>
520VecBase<DATA_TYPE, SIZE>& reflect( VecBase<DATA_TYPE, SIZE>& result, const
521                           VecBase<DATA_TYPE, SIZE>& vec,
522                           const Vec<DATA_TYPE, SIZE>& normal )
523{
524   result = vec - (DATA_TYPE( 2.0 ) * (dot( (Vec<DATA_TYPE, SIZE>)vec, normal ) * normal));
525   return result;
526}
527
528/** @} */
529
530/** @ingroup Interp
531 * @name Vector Interpolation
532 * @{
533 */
534
535/**
536 * Linearly interpolates between to vectors.
537 *
538 * @pre  lerpVal is a value between 0 and 1 that interpolates between from and to.
539 * @post undefined if lerpVal < 0 or lerpVal > 1
540 *
541 * @param result     the result of the linear interpolation
542 * @param lerpVal    the value to interpolate between from and to
543 * @param from       the vector at lerpVal 0
544 * @param to         the vector at lerpVal 1
545 *
546 * @return  a reference to result for convenience
547 */
548template <typename DATA_TYPE, unsigned SIZE>
549VecBase<DATA_TYPE, SIZE>& lerp( VecBase<DATA_TYPE, SIZE>& result,
550                                const DATA_TYPE& lerpVal,
551                                const VecBase<DATA_TYPE, SIZE>& from,
552                                const VecBase<DATA_TYPE, SIZE>& to )
553{
554   /// @todo metaprogramming...
555   for (unsigned int x = 0; x < SIZE; ++x)
556   {
557      Math::lerp( result[x], lerpVal, from[x], to[x] );
558   }
559   return result;
560}
561/** @} */
562
563/** @ingroup Compare
564 * @name Vector Comparitors
565 * @{
566 */
567
568
569// --- VEC comparisons -- //
570
571/**
572 * Compares v1 and v2 to see if they are exactly the same.
573 *
574 * @param v1   the first vector
575 * @param v2   the second vector
576 *
577 * @return  true if v1 equals v2; false if they differ
578 */
579template<class DATA_TYPE, unsigned SIZE>
580inline bool operator==(const VecBase<DATA_TYPE, SIZE>& v1,
581                       const VecBase<DATA_TYPE, SIZE>& v2)
582{
583#ifdef GMTL_NO_METAPROG
584   for(unsigned i=0;i<SIZE;++i)
585   {
586      if(v1[i] != v2[i])
587      {
588         return false;
589      }
590   }
591
592   return true;
593#else
594   return gmtl::meta::EqualVecUnrolled<SIZE-1,Vec<DATA_TYPE,SIZE> >::func(v1,v2);
595#endif
596   /*  Would like this
597   return(vec[0] == _v[0] &&
598          vec[1] == _v[1] &&
599          vec[2] == _v[2]);
600          */
601}
602
603/**
604 * Compares v1 and v2 to see if they are NOT exactly the same with zero
605 * tolerance.
606 *
607 * @param v1   the first vector
608 * @param v2   the second vector
609 *
610 * @return  true if v1 does not equal v2; false if they are equal
611 */
612template<class DATA_TYPE, unsigned SIZE>
613inline bool operator!=(const VecBase<DATA_TYPE, SIZE>& v1,
614                       const VecBase<DATA_TYPE, SIZE>& v2)
615{
616   return(! (v1 == v2));
617}
618
619/**
620 * Compares v1 and v2 to see if they are the same within the given epsilon
621 * tolerance.
622 *
623 * @pre eps must be >= 0
624 *
625 * @param v1   the first vector
626 * @param v2   the second vector
627 * @param eps  the epsilon tolerance value
628 *
629 * @return  true if v1 equals v2 within the tolerance; false if they differ
630 */
631template<class DATA_TYPE, unsigned SIZE>
632inline bool isEqual(const VecBase<DATA_TYPE, SIZE>& v1,
633                    const VecBase<DATA_TYPE, SIZE>& v2, const DATA_TYPE eps)
634{
635   gmtlASSERT(eps >= 0);
636
637   for(unsigned i=0;i<SIZE;++i)
638   {
639      if ( gmtl::Math::abs(v1[i] - v2[i]) > eps )
640      {
641         return false;
642      }
643   }
644   return true;
645}
646
647/** @} */
648
649}
650
651#endif
Note: See TracBrowser for help on using the repository browser.