// vector.h (Vector<> class definition) // // The WorldForge Project // Copyright (C) 2001 The WorldForge Project // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // For information about WorldForge and its authors, please contact // the Worldforge Web Site at http://www.worldforge.org. // Author: Ron Steinke // Created: 2001-12-7 // Extensive amounts of this material come from the Vector2D // and Vector3D classes from stage/math, written by Bryce W. // Harrington, Kosh, and Jari Sundell (Rakshasa). #ifndef WFMATH_VECTOR_H #define WFMATH_VECTOR_H #include #include #include namespace WFMath { template Vector& operator+=(Vector& v1, const Vector& v2); template Vector& operator-=(Vector& v1, const Vector& v2); template Vector& operator*=(Vector& v, CoordType d); template Vector& operator/=(Vector& v, CoordType d); template Vector operator+(const Vector& v1, const Vector& v2); template Vector operator-(const Vector& v1, const Vector& v2); template Vector operator-(const Vector& v); // Unary minus template Vector operator*(CoordType d, const Vector& v); template Vector operator*(const Vector& v, CoordType d); template Vector operator/(const Vector& v, CoordType d); template CoordType Dot(const Vector& v1, const Vector& v2); template CoordType Angle(const Vector& v, const Vector& u); // The following are defined in rotmatrix_funcs.h /// returns m * v template // m * v Vector Prod(const RotMatrix& m, const Vector& v); /// returns m^-1 * v template // m^-1 * v Vector InvProd(const RotMatrix& m, const Vector& v); /// returns v * m /** * This is the function to use to rotate a Vector v using a Matrix m **/ template // v * m Vector Prod(const Vector& v, const RotMatrix& m); /// return v * m^-1 template // v * m^-1 Vector ProdInv(const Vector& v, const RotMatrix& m); /// template Vector operator*(const RotMatrix& m, const Vector& v); /// template Vector operator*(const Vector& v, const RotMatrix& m); template Vector operator-(const Point& c1, const Point& c2); template Point operator+(const Point& c, const Vector& v); template Point operator-(const Point& c, const Vector& v); template Point operator+(const Vector& v, const Point& c); template Point& operator+=(Point& p, const Vector& v); template Point& operator-=(Point& p, const Vector& v); template std::ostream& operator<<(std::ostream& os, const Vector& v); template std::istream& operator>>(std::istream& is, Vector& v); template class ZeroPrimitive; /// A dim dimensional vector /** * This class implements the 'generic' subset of the interface in * the fake class Shape. **/ template class Vector { friend class ZeroPrimitive >; public: /// Construct an uninitialized vector Vector() : m_valid(false) {} /// Construct a copy of a vector Vector(const Vector& v); /// Construct a vector from an object passed by Atlas explicit Vector(const AtlasInType& a); /// Construct a vector from a point. explicit Vector(const Point& point); /** * @brief Provides a global instance preset to zero. */ static const Vector& ZERO(); friend std::ostream& operator<< (std::ostream& os, const Vector& v); friend std::istream& operator>> (std::istream& is, Vector& v); /// Create an Atlas object from the vector AtlasOutType toAtlas() const; /// Set the vector's value to that given by an Atlas object void fromAtlas(const AtlasInType& a); Vector& operator=(const Vector& v); bool isEqualTo(const Vector& v, CoordType epsilon = numeric_constants::epsilon()) const; bool operator==(const Vector& v) const {return isEqualTo(v);} bool operator!=(const Vector& v) const {return !isEqualTo(v);} bool isValid() const {return m_valid;} /// make isValid() return true if you've initialized the vector by hand void setValid(bool valid = true) {m_valid = valid;} /// Zero the components of a vector Vector& zero(); // Math operators /// Add the second vector to the first friend Vector& operator+=(Vector& v1, const Vector& v2); /// Subtract the second vector from the first friend Vector& operator-=(Vector& v1, const Vector& v2); /// Multiply the magnitude of v by d friend Vector& operator*=(Vector& v, CoordType d); /// Divide the magnitude of v by d friend Vector& operator/=(Vector& v, CoordType d); /// Take the sum of two vectors friend Vector operator+(const Vector& v1, const Vector& v2); /// Take the difference of two vectors friend Vector operator-(const Vector& v1, const Vector& v2); /// Reverse the direction of a vector friend Vector operator-(const Vector& v); // Unary minus /// Multiply a vector by a scalar friend Vector operator*(CoordType d, const Vector& v); /// Multiply a vector by a scalar friend Vector operator*(const Vector& v, CoordType d); /// Divide a vector by a scalar friend Vector operator/(const Vector& v, CoordType d); // documented outside the class definition friend Vector Prod(const RotMatrix& m, const Vector& v); friend Vector InvProd(const RotMatrix& m, const Vector& v); /// Get the i'th element of the vector CoordType operator[](const int i) const {return m_elem[i];} /// Get the i'th element of the vector CoordType& operator[](const int i) {return m_elem[i];} /// Find the vector which gives the offset between two points friend Vector operator-(const Point& c1, const Point& c2); /// Find the point at the offset v from the point c friend Point operator+(const Point& c, const Vector& v); /// Find the point at the offset -v from the point c friend Point operator-(const Point& c, const Vector& v); /// Find the point at the offset v from the point c friend Point operator+(const Vector& v, const Point& c); /// Shift a point by a vector friend Point& operator+=(Point& p, const Vector& rhs); /// Shift a point by a vector, in the opposite direction friend Point& operator-=(Point& p, const Vector& rhs); friend CoordType Cross(const Vector<2>& v1, const Vector<2>& v2); friend Vector<3> Cross(const Vector<3>& v1, const Vector<3>& v2); /// The dot product of two vectors friend CoordType Dot(const Vector& v1, const Vector& v2); /// The angle between two vectors friend CoordType Angle(const Vector& v, const Vector& u); /// The squared magnitude of a vector CoordType sqrMag() const; /// The magnitude of a vector CoordType mag() const {return std::sqrt(sqrMag());} /// Normalize a vector Vector& normalize(CoordType norm = 1.0) {CoordType themag = mag(); return (*this *= norm / themag);} /// An approximation to the magnitude of a vector /** * The sloppyMag() function gives a value between * the true magnitude and sloppyMagMax multiplied by the * true magnitude. sloppyNorm() uses sloppyMag() to normalize * the vector. This is currently only implemented for * dim = {1, 2, 3}. For all current implementations, * sloppyMagMax is greater than or equal to one. * The constant sloppyMagMaxSqrt is provided for those * who want to most closely approximate the true magnitude, * without caring whether it's too low or too high. **/ CoordType sloppyMag() const; /// Approximately normalize a vector /** * Normalize a vector using sloppyMag() instead of the true magnitude. * The new length of the vector will be between norm/sloppyMagMax() * and norm. **/ Vector& sloppyNorm(CoordType norm = 1.0); // Can't seem to implement these as constants, implementing // inline lookup functions instead. /// The maximum ratio of the return value of sloppyMag() to the true magnitude static CoordType sloppyMagMax(); /// The square root of sloppyMagMax() /** * This is provided for people who want to obtain maximum accuracy from * sloppyMag(), without caring whether the answer is high or low. * The result sloppyMag()/sloppyMagMaxSqrt() will be within sloppyMagMaxSqrt() * of the true magnitude. **/ static CoordType sloppyMagMaxSqrt(); /// Rotate the vector in the (axis1, axis2) plane by the angle theta Vector& rotate(int axis1, int axis2, CoordType theta); /// Rotate the vector in the (v1, v2) plane by the angle theta /** * This throws CollinearVectors if v1 and v2 are parallel. **/ Vector& rotate(const Vector& v1, const Vector& v2, CoordType theta); /// Rotate the vector using a matrix Vector& rotate(const RotMatrix&); // mirror image functions /// Reflect a vector in the direction of the i'th axis Vector& mirror(const int i) { m_elem[i] *= -1; return *this;} /// Reflect a vector in the direction specified by v Vector& mirror(const Vector& v) {return operator-=(*this, 2 * v * Dot(v, *this) / v.sqrMag());} /// Reflect a vector in all directions simultaneously. /** * This is a nice way to implement the parity operation if dim is odd. **/ Vector& mirror() {return operator*=(*this, -1);} // Specialized 2D/3D stuff starts here // The following functions are defined only for // two dimensional (rotate(CoordType), Vector<>(CoordType, CoordType)) // and three dimensional (the rest of them) vectors. // Attempting to call these on any other vector will // result in a linker error. /// 2D only: construct a vector from (x, y) coordinates Vector(CoordType x, CoordType y); /// 3D only: construct a vector from (x, y, z) coordinates Vector(CoordType x, CoordType y, CoordType z); /// 2D only: rotate a vector by an angle theta Vector& rotate(CoordType theta); /// 3D only: rotate a vector about the x axis by an angle theta Vector& rotateX(CoordType theta); /// 3D only: rotate a vector about the y axis by an angle theta Vector& rotateY(CoordType theta); /// 3D only: rotate a vector about the z axis by an angle theta Vector& rotateZ(CoordType theta); /// 3D only: rotate a vector about the i'th axis by an angle theta Vector& rotate(const Vector& axis, CoordType theta); /// 3D only: rotate a vector using a Quaternion Vector& rotate(const Quaternion& q); // Label the first three components of the vector as (x,y,z) for // 2D/3D convienience /// Access the first component of a vector CoordType x() const {return m_elem[0];} /// Access the first component of a vector CoordType& x() {return m_elem[0];} /// Access the second component of a vector CoordType y() const {return m_elem[1];} /// Access the second component of a vector CoordType& y() {return m_elem[1];} /// Access the third component of a vector CoordType z() const; /// Access the third component of a vector CoordType& z(); /// Flip the x component of a vector Vector& mirrorX() {return mirror(0);} /// Flip the y component of a vector Vector& mirrorY() {return mirror(1);} /// Flip the z component of a vector Vector& mirrorZ(); /// 2D only: construct a vector from polar coordinates Vector& polar(CoordType r, CoordType theta); /// 2D only: convert a vector to polar coordinates void asPolar(CoordType& r, CoordType& theta) const; /// 3D only: construct a vector from polar coordinates Vector& polar(CoordType r, CoordType theta, CoordType z); /// 3D only: convert a vector to polar coordinates void asPolar(CoordType& r, CoordType& theta, CoordType& z) const; /// 3D only: construct a vector from shperical coordinates Vector& spherical(CoordType r, CoordType theta, CoordType phi); /// 3D only: convert a vector to shperical coordinates void asSpherical(CoordType& r, CoordType& theta, CoordType& phi) const; const CoordType* elements() const {return m_elem;} private: double _scaleEpsilon(const Vector& v, CoordType epsilon = numeric_constants::epsilon()) const {return _ScaleEpsilon(m_elem, v.m_elem, dim, epsilon);} CoordType m_elem[dim]; bool m_valid; }; template<> inline CoordType Vector<3>::z() const { return m_elem[2]; } template<> inline CoordType& Vector<3>::z() { return m_elem[2]; } template<> inline Vector<3>& Vector<3>::mirrorZ() { return mirror(2); } /// 2D only: get the z component of the cross product of two vectors CoordType Cross(const Vector<2>& v1, const Vector<2>& v2); /// 3D only: get the cross product of two vectors Vector<3> Cross(const Vector<3>& v1, const Vector<3>& v2); /// Check if two vectors are parallel /** * Returns true if the vectors are parallel. For parallel * vectors, same_dir is set to true if they point the same * direction, and false if they point opposite directions **/ template bool Parallel(const Vector& v1, const Vector& v2, bool& same_dir); /// Check if two vectors are parallel /** * Convienience wrapper if you don't care about same_dir **/ template bool Parallel(const Vector& v1, const Vector& v2); /// Check if two vectors are perpendicular template bool Perpendicular(const Vector& v1, const Vector& v2); template inline Vector operator+(const Vector& v1, const Vector& v2) { Vector ans(v1); ans += v2; return ans; } template inline Vector operator-(const Vector& v1, const Vector& v2) { Vector ans(v1); ans -= v2; return ans; } template inline Vector operator*(const Vector& v, CoordType d) { Vector ans(v); ans *= d; return ans; } template inline Vector operator*(CoordType d, const Vector& v) { Vector ans(v); ans *= d; return ans; } template inline Vector operator/(const Vector& v, CoordType d) { Vector ans(v); ans /= d; return ans; } template inline bool Parallel(const Vector& v1, const Vector& v2, bool& same_dir) { CoordType dot = Dot(v1, v2); same_dir = (dot > 0); return Equal(dot * dot, v1.sqrMag() * v2.sqrMag()); } template inline bool Parallel(const Vector& v1, const Vector& v2) { bool same_dir; return Parallel(v1, v2, same_dir); } template<> inline CoordType Vector<1>::sloppyMagMax() { return 1.f; } template<> inline CoordType Vector<2>::sloppyMagMax() { return 1.082392200292393968799446410733f; } template<> inline CoordType Vector<3>::sloppyMagMax() { return 1.145934719303161490541433900265f; } template<> inline CoordType Vector<1>::sloppyMagMaxSqrt() { return 1.f; } template<> inline CoordType Vector<2>::sloppyMagMaxSqrt() { return 1.040380795811030899095785063701f; } template<> inline CoordType Vector<3>::sloppyMagMaxSqrt() { return 1.070483404496847625250328653179f; } } // namespace WFMath #endif // WFMATH_VECTOR_H