//============================================================================ // // 3-dim real vector class // $Id$ // Copyright (C) 2004 Georg Drenkhahn // // This file is free software; you can redistribute it and/or modify it under // the terms of the GNU General Public License version 2 as published by the // Free Software Foundation. // //============================================================================ #ifndef VEC3_H #define VEC3_H #include <valarray> /** @brief 3-dimensional real vector * * Implements regular 3 dimensional (space) vectors including the common inner * scalar product (2 norm) and the cross product. @a T may be any integer or * float data type which is an acceptable template argument of std::valarray. */ template<typename T> class vec3 : public std::valarray<T> { public: /** Default constructor */ vec3(); /** Constructor with initial element values */ vec3(const T&, const T&, const T&); /** Copy constructor */ vec3(const std::valarray<T>&); /** Copy constructor */ vec3(const std::slice_array<T>&); /** Normalize the vector to have a norm of 1. @return Normalized vector if * length is non-zero and otherwise the zero vector. */ vec3& normalize(); /** Rotate the vector (*this) in positive mathematical direction around the * direction given by @a r. The norm of @a r specifies the rotation angle in * radians. * @param r Rotation vector. * @return Rotated vector. */ vec3& rotate(const vec3& r); /*--- static funcions ---*/ /** @param a first vector * @param b second vector * @return Cosine of the angle between @a a and @a b. If norm(@a a)==0 or * norm(@a b)==0 the global variable errno is set to EDOM and NAN (or * std::numeric_limits<T>::quiet_NaN()) is returned. */ static T cos_angle(const vec3& a, const vec3& b); /** @brief Returns the angle between vectors @c a and @a b but with respect * to a preferred rotation direction @a c. * * @param a First vector for angle. Must be | @a a |>0 otherwises NAN is * returned. * @param b Second vector for angle. Must be | @a b |>0 otherwises NAN is * returned. * @param c Indicates the rotation direction. @a c can be any vector which is * not part of the plane spanned by @a a and @a b. If | @a c | = 0 the * smalest possible angle angle is returned. * @return Angle in radians between 0 and 2*Pi or NAN if | @a a |=0 or | @a b * |=0. * * For @a a not parallel to @a b and @a a not antiparallel to @a b the 2 * vectors @a a,@a b span a unique plane in the 3-dimensional space. Let @b * n<sub>1</sub> and @b n<sub>2</sub> be the two possible normal vectors for * this plane with |@b n<sub>i</sub> |=1, i={1,2} and @b n<sub>1</sub> = -@b * n<sub>2</sub> . * * Let further @a a and @a b enclose an angle alpha in [0,Pi], then there is * one i in {1,2} so that (alpha*@b n<sub>i</sub> x @a a) * @a b = 0. This * means @a a rotated by the rotation vector alpha*@b n<sub>i</sub> is * parallel to @a b. One could also rotate @a a by (2*Pi-alpha)*(-@b * n<sub>i</sub>) to acomplish the same transformation with * ((2*Pi-alpha)*(-@b n<sub>i</sub>) x @a a) * @a b = 0 * * The vector @a c defines the direction of the normal vector to take as * reference. If @a c * @b n<sub>i</sub> > 0 alpha is returned and otherwise * 2*Pi-alpha. If @a a parallel to @a b or @a a parallel to @a b the choice * of @a c does not matter. */ static T angle(const vec3& a, const vec3& b, const vec3& c); /*--- static inline funcions ---*/ /** Norm of argument vector. * @param a vector. * @return | @a a | */ static T norm(const vec3& a); /** Angle between @a a and @a b. * @param a fist vector. Must be | @a a | > 0 otherwises NAN is returned. * @param b second vector. Must be | @a b | > 0 otherwises NAN is returned. * @return Angle in radians between 0 and Pi or NAN if | @a a | = 0 or | @a b * | = 0. */ static T angle(const vec3& a, const vec3& b); /** Cross product of @a a and @a b. * @param a fist vector. * @param b second vector. * @return Cross product of argument vectors @a a x @a b. */ static vec3 crossprod(const vec3& a, const vec3& b); /** Normalized version of argument vector. * @param a vector. * @return @a a / | @a a | for | @a a | > 0 and otherwise the zero vector * (=@a a). In the latter case the global variable errno is set to EDOM. */ static vec3 normalized(vec3 a); }; /*--- inline member functions ---*/ template<typename T> inline vec3<T>::vec3() : std::valarray<T>(3) {} template<typename T> inline vec3<T>::vec3(const T& a, const T& b, const T& c) : std::valarray<T>(3) { (*this)[0] = a; (*this)[1] = b; (*this)[2] = c; } template<typename T> inline vec3<T>::vec3(const std::valarray<T>& a) : std::valarray<T>(a) { } template<typename T> inline vec3<T>::vec3(const std::slice_array<T>& a) : std::valarray<T>(a) { } /*--- inline non-member operators ---*/ /** @param a first vector summand * @param b second vector summand * @return Sum vector of vectors @a a and @a b. */ template<typename T> inline vec3<T> operator+(vec3<T> a, const vec3<T>& b) { std::valarray<T> &a_ = a; const std::valarray<T> &b_ = b; a_ += b_; /* valarray<T>::operator+=(const valarray<T>&) */ return a; } /** @param a first vector multiplicant * @param b second vector multiplicant * @return Scalar product of vectors @a a and @a b. */ template<typename T> inline T operator*(vec3<T> a, const vec3<T>& b) { std::valarray<T> &a_ = a; const std::valarray<T> &b_ = b; a_ *= b_; /* valarray<T>::operator*=(const valarray<T>&) */ return a.sum(); } /** @param a scalar multiplicant * @param b vector operand * @return Product vector of scalar @a a and vector @a b. */ template<typename T> inline vec3<T> operator*(const T& a, vec3<T> b) { b *= a; /* valarray<T>::operator*=(const T&) */ return b; } /** @param a vector operand * @param b scalar multiplicant * @return Product vector of scalar @a b and vector @a a. */ template<typename T> inline vec3<T> operator*(vec3<T> a, const T& b) { return b*a; /* vec3<T>::operator*(const T&, vec3<T>) */ } /*--- static inline funcions ---*/ template<typename T> inline T vec3<T>::norm(const vec3<T>& a) { return sqrt(a*a); } template<typename T> inline T vec3<T>::angle(const vec3<T>& a, const vec3<T>& b) { // returns NAN if cos_angle() returns NAN (TODO: test this case) return acos(cos_angle(a,b)); } template<typename T> inline vec3<T> vec3<T>::crossprod(const vec3<T>& a, const vec3<T>& b) { return vec3<T>( a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]); } template<typename T> inline vec3<T> vec3<T>::normalized(vec3<T> a) { return a.normalize(); } #endif