//============================================================================ // // 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 /** @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 class vec3 : public std::valarray { public: /** Default constructor */ vec3(); /** Constructor with initial element values */ vec3(const T&, const T&, const T&); /** Copy constructor */ vec3(const std::valarray&); /** Copy constructor */ vec3(const std::slice_array&); /** 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::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 * n1 and @b n2 be the two possible normal vectors for * this plane with |@b ni |=1, i={1,2} and @b n1 = -@b * n2 . * * 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 ni x @a a) * @a b = 0. This * means @a a rotated by the rotation vector alpha*@b ni is * parallel to @a b. One could also rotate @a a by (2*Pi-alpha)*(-@b * ni) to acomplish the same transformation with * ((2*Pi-alpha)*(-@b ni) 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 ni > 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 inline vec3::vec3() : std::valarray(3) {} template inline vec3::vec3(const T& a, const T& b, const T& c) : std::valarray(3) { (*this)[0] = a; (*this)[1] = b; (*this)[2] = c; } template inline vec3::vec3(const std::valarray& a) : std::valarray(a) { } template inline vec3::vec3(const std::slice_array& a) : std::valarray(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 inline vec3 operator+(vec3 a, const vec3& b) { a += b; /* valarray::operator+=(const valarray&) */ return a; } /** @param a first vector multiplicant * @param b second vector multiplicant * @return Scalar product of vectors @a a and @a b. */ template inline T operator*(vec3 a, const vec3& b) { a *= b; /* valarray::operator*=(const T&) */ return a.sum(); } /** @param a scalar multiplicant * @param b vector operand * @return Product vector of scalar @a a and vector @a b. */ template inline vec3 operator*(const T& a, vec3 b) { b *= a; /* valarray::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 inline vec3 operator*(vec3 a, const T& b) { return b*a; /* vec3::operator*(const T&, vec3) */ } /*--- static inline funcions ---*/ template inline T vec3::norm(const vec3& a) { return sqrt(a*a); } template inline T vec3::angle(const vec3& a, const vec3& b) { // returns NAN if cos_angle() returns NAN (TODO: test this case) return acos(cos_angle(a,b)); } template inline vec3 vec3::crossprod(const vec3& a, const vec3& b) { return vec3( 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 inline vec3 vec3::normalized(vec3 a) { return a.normalize(); } #endif