#pragma region License /****************************************************************************** This file is part of the PolyVox library Copyright (C) 2006 David Williams 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ******************************************************************************/ #pragma endregion #include #include #include namespace PolyVox { /** This Vector class is templated on both size and data type. It is designed to be generic but so far had only been tested with vectors of size 2 and 3. Also note that some of the operations do not make sense with integer types, for example it does not make conceptual sense to try and normalise an integer Vector. The elements of the Vector are accessed via the overloaded () operator which takes an index indicating the element to fetch. They are set using the set() function which takes an index indicating the element to set and a new value for that element. For convienience, the functions getX(), setX(), getY(), setY(), getZ(), setZ, w() and setW() do the same thing for the first 4 elements of the Vector. A variety of overloaded operators are also provided for comparison and arithmetic operations. For most of these arithmetic operators only the unary versions are documented below - however often binary versions are also generated by std::operators. Lastly, note that for convienience a set of typedefs are included for 2 and 3 dimentionsal vectors with type float, double, int32, and uint32. They are used as follows: Vector2DInt4 test(1,2); //Declares a 2 dimensional Vector of type int4. */ #pragma region Constructors/Destructors //-------------------------- Constructors, etc --------------------------------- /** Creates a Vector object and initialises it with given values. \param x x component to set. \param y y component to set. */ template Vector::Vector(Type x, Type y) throw() { m_tElements[0] = x; m_tElements[1] = y; } /** Creates a Vector3D object and initialises it with given values. \param x x component to set. \param y y component to set. \param z z component to set. */ template Vector::Vector(Type x, Type y, Type z) throw() { m_tElements[0] = x; m_tElements[1] = y; m_tElements[2] = z; } /** Creates a Vector3D object and initialises it with given values. \param x x component to set. \param y y component to set. \param z z component to set. \param w w component to set. */ template Vector::Vector(Type x, Type y, Type z, Type w) throw() { m_tElements[0] = x; m_tElements[1] = y; m_tElements[2] = z; m_tElements[3] = w; } /** Creates a Vector object but does not initialise it. */ template Vector::Vector(void) throw() { } /** Copy constructor builds object based on object passed as parameter. \param vector A reference to the Vector to be copied. */ template Vector::Vector(const Vector& vector) throw() { std::memcpy(m_tElements, vector.m_tElements, sizeof(Type) * Size); } /** This copy constructor allows casting between vectors with different data types. It is now possible to use code such as: Vector3DDouble v3dDouble(1.0,2.0,3.0); Vector3DFloat v3dFloat = static_cast(v3dDouble); //Casting \param vector A reference to the Vector to be copied. */ template template Vector::Vector(const Vector& vector) throw() { for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] = static_cast(vector.getElement(ct)); } } /** Destroys the Vector. */ template Vector::~Vector(void) throw() { } #pragma endregion #pragma region Operators /** Assignment operator copies each element of first Vector to the second. \param rhs Vector to assign to. \return A reference to the result to allow chaining. */ template Vector& Vector::operator=(const Vector& rhs) throw() { if(this == &rhs) { return *this; } std::memcpy(m_tElements, rhs.m_tElements, sizeof(Type) * Size); return *this; } /** Checks whether two Vectors are equal. \param rhs The Vector to compare to. \return true if the Vectors match. \see operator!= */ template inline bool Vector::operator==(const Vector &rhs) const throw() { bool equal = true; for(uint32 ct = 0; ct < Size; ++ct) { if(m_tElements[ct] != rhs(ct)) { equal = false; break; } } return equal; } /** Checks whether this vector is less than the parameter. The metric is meaningless but it allows Vectors to me used as key in sdt::map, etc. \param rhs The Vector to compare to. \return true if this is less than the parameter \see operator!= */ template inline bool Vector::operator<(const Vector &rhs) const throw() { for(int ct = 0; ct < Size; ++ct) { if (m_tElements[ct] < rhs.m_tElements[ct]) return true; if (rhs.m_tElements[ct] < m_tElements[ct]) return false; } return false; } /** Addition operator adds corresponding elements of the two Vectors. \param rhs Vector to add \return The resulting Vector. */ template inline Vector& Vector::operator+=(const Vector& rhs) throw() { for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] += rhs.m_tElements[ct]; } return *this; } /** Addition operator adds corresponding elements of the two Vectors. \param lhs Vector to add to. \param rhs Vector to add. \return The resulting Vector. */ template Vector operator+(const Vector& lhs, const Vector& rhs) throw() { Vector result = lhs; result += rhs; return result; } /** Subtraction operator subtracts corresponding elements of one Vector from the other. \param rhs Vector to subtract \return The resulting Vector. */ template inline Vector& Vector::operator-=(const Vector& rhs) throw() { for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] -= rhs.m_tElements[ct]; } return *this; } /** Subtraction operator subtracts corresponding elements of one Vector from the other. \param lhs Vector to subtract from. \param rhs Vector to subtract. \return The resulting Vector. */ template Vector operator-(const Vector& lhs, const Vector& rhs) throw() { Vector result = lhs; result -= rhs; return result; } /** Multiplication operator multiplies each element of the Vector by a number. \param rhs the number the Vector is multiplied by. \return The resulting Vector. */ template inline Vector& Vector::operator*=(const Type& rhs) throw() { for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] *= rhs; } return *this; } /** Multiplication operator multiplies each element of the Vector by a number. \param lhs the Vector to multiply. \param rhs the number the Vector is multiplied by. \return The resulting Vector. */ template Vector operator*(const Vector& lhs, const Type& rhs) throw() { Vector result = lhs; result *= rhs; return result; } /** Division operator divides each element of the Vector by a number. \param rhs the number the Vector is divided by. \return The resulting Vector. */ template inline Vector& Vector::operator/=(const Type& rhs) throw() { for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] /= rhs; } return *this; } /** Division operator divides each element of the Vector by a number. \param lhs the Vector to divide. \param rhs the number the Vector is divided by. \return The resulting Vector. */ template Vector operator/(const Vector& lhs, const Type& rhs) throw() { Vector result = lhs; result /= rhs; return result; } /** Enables the Vector to be used intuitively with output streams such as cout. \param os The output stream to write to. \param vector The Vector to write to the stream. \return A reference to the output stream to allow chaining. */ template std::ostream& operator<<(std::ostream& os, const Vector& vector) throw() { os << "("; for(uint32 ct = 0; ct < Size; ++ct) { os << vector.getElement(ct); if(ct < (Size-1)) { os << ","; } } os << ")"; return os; } #pragma endregion #pragma region Getters /** Returns the element at the given position. \param index The index of the element to return. \return The element. */ template inline Type Vector::getElement(uint32 index) const throw() { return m_tElements[index]; } /** \return A const reference to the X component of a 1, 2, 3, or 4 dimensional Vector. */ template inline Type Vector::getX(void) const throw() { return m_tElements[0]; } /** \return A const reference to the Y component of a 2, 3, or 4 dimensional Vector. */ template inline Type Vector::getY(void) const throw() { return m_tElements[1]; } /** \return A const reference to the Z component of a 3 or 4 dimensional Vector. */ template inline Type Vector::getZ(void) const throw() { return m_tElements[2]; } /** \return A const reference to the W component of a 4 dimensional Vector. */ template inline Type Vector::getW(void) const throw() { return m_tElements[3]; } #pragma endregion #pragma region Setters /** \param index The index of the element to set. \param tValue The new value for the element. */ template inline void Vector::setElement(uint32 index, Type tValue) throw() { m_tElements[index] = tValue; } /** \param tX The new value for the X component of a 1, 2, 3, or 4 dimensional Vector. */ template inline void Vector::setX(Type tX) throw() { m_tElements[0] = tX; } /** \param tX The new value for the Y component of a 2, 3, or 4 dimensional Vector. */ template inline void Vector::setY(Type tY) throw() { m_tElements[1] = tY; } /** \param tX The new value for the Z component of a 3 or 4 dimensional Vector. */ template inline void Vector::setZ(Type tZ) throw() { m_tElements[2] = tZ; } /** \param tX The new value for the W component of a 4 dimensional Vector. */ template inline void Vector::setW(Type tW) throw() { m_tElements[3] = tW; } #pragma endregion #pragma region Others /** NOTE: This function does not make much sense on integer Vectors. \return Length of the Vector. */ template inline double Vector::length(void) const throw() { return sqrt(lengthSquared()); } /** \return Squared length of the Vector. */ template inline double Vector::lengthSquared(void) const throw() { double result = 0.0f; for(uint32 ct = 0; ct < Size; ++ct) { result += m_tElements[ct] * m_tElements[ct]; } return result; } /** This function is commutative, such that a.angleTo(b) == b.angleTo(a). The angle returned is in radians and varies between 0 and 3.14(pi). It is always positive. NOTE: This function does not make much sense on integer Vectors. \param Vector3D The Vector to find the angle to. \return The angle between them in radians. */ template inline double Vector::angleTo(const Vector& vector) const throw() { return acos(dot(vector) / (vector.length() * this->length())); } /** This function is used to calculate the cross product of two Vectors. The cross product is the Vector which is perpendicular to the two given Vectors. It is worth remembering that, unlike the dot product, it is not commutative. E.g a.b != b.a. The cross product obeys the right-hand rule such that if the two vectors are given by the index finger and middle finger respectively then the cross product is given by the thumb. \param a first Vector. \param b Second Vector. \return The value of the cross product. \see dot() */ template inline Vector Vector::cross(const Vector& vector) const throw() { Type i = vector.getZ() * this->getY() - vector.getY() * this->getZ(); Type j = vector.getX() * this->getZ() - vector.getZ() * this->getX(); Type k = vector.getY() * this->getX() - vector.getX() * this->getY(); return Vector(i,j,k); } /** Calculates the dot product of the Vector and the parameter. This function is commutative, such that a.dot(b) == b.dot(a). \param rhs The Vector to find the dot product with. \return The value of the dot product. \see cross() */ template inline Type Vector::dot(const Vector& rhs) const throw() { Type dotProduct = static_cast(0); for(uint32 ct = 0; ct < Size; ++ct) { dotProduct += m_tElements[ct] * rhs.m_tElements[ct]; } return dotProduct; } /** Divides the i, j, and k components by the length to give a Vector of length 1.0. NOTE: This function does not make much sense on integer Vectors. */ template inline void Vector::normalise(void) throw() { double length = this->length(); //FIXME - throw div by zero exception? if(length < 0.0001f) { return; } for(uint32 ct = 0; ct < Size; ++ct) { m_tElements[ct] /= static_cast(length); } } #pragma endregion }//namespace Thermite