From 9138ae51da36ac0edd5a6cec00ff15ed140c9723 Mon Sep 17 00:00:00 2001 From: David Williams Date: Sat, 9 Feb 2008 17:50:10 +0000 Subject: [PATCH] Added replacement vector class. --- include/Vector.hpp | 117 +++++++++++ include/Vector.inl | 487 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 604 insertions(+) create mode 100644 include/Vector.hpp create mode 100644 include/Vector.inl diff --git a/include/Vector.hpp b/include/Vector.hpp new file mode 100644 index 00000000..248919e6 --- /dev/null +++ b/include/Vector.hpp @@ -0,0 +1,117 @@ +#ifndef VECTOR_HEADER_INCLUDED +#define VECTOR_HEADER_INCLUDED + +#include + +//#include "..\Base\Typedef.hpp" +#include "boost/cstdint.hpp" + +namespace Ogre +{ + //template class Matrix; //Forward declaration + + ///Represents a vector in space. + template + class Vector + : boost::addable< Vector // Vector + Vector + , boost::subtractable< Vector // Vector - Vector + , boost::dividable2< Vector, Type // Vector / Type + , boost::multipliable2< Vector, Type // Vector * Type, Type * Vector + , boost::equality_comparable1< Vector // Vector != Vector + > > > > > + { + public: + ///Constructor. + Vector(Type x, Type y) throw(); + ///Constructor. + Vector(Type x, Type y, Type z) throw(); + ///Constructor. + Vector(Type x, Type y, Type z, Type w) throw(); + ///Constructor + Vector(void) throw(); + ///Copy Constructor. + Vector(const Vector& vector) throw(); + ///Copy Constructor which performs casting. + template explicit Vector(const Vector& vector) throw(); + ///Destructor. + ~Vector(void) throw(); + + ///Assignment Operator. + Vector& operator=(const Vector& rhs) throw(); + ///Equality Operator. + bool operator==(const Vector& rhs) const throw(); + ///Addition and Assignment Operator. + Vector& operator+=(const Vector &rhs) throw(); + ///Subtraction and Assignment Operator. + Vector& operator-=(const Vector &rhs) throw(); + ///Multiplication and Assignment Operator. + Vector& operator*=(const Type& rhs) throw(); + ///Division and Assignment Operator. + Vector& operator/=(const Type& rhs) throw(); + ///Element Access + Type operator()(boost::uint32_t index) const throw(); + + ///Get the x component of the vector. + Type x(void) const throw(); + ///Get the y component of the vector. + Type y(void) const throw(); + ///Get the z component of the vector. + Type z(void) const throw(); + ///Get the w component of the vector. + Type w(void) const throw(); + + ///Element Access + void set(boost::uint32_t index, Type tValue) throw(); + ///Set the x component of the vector. + void setX(Type tX) throw(); + ///Set the y component of the vector. + void setY(Type tY) throw(); + ///Set the z component of the vector. + void setZ(Type tZ) throw(); + ///Set the w component of the vector. + void setW(Type tW) throw(); + + ///Get the length of the vector. + double length(void) const throw(); + ///Get the squared length of the vector. + double lengthSquared(void) const throw(); + ///Find the angle between this vector and that which is passed as a parameter. + double angleTo(const Vector& vector) const throw(); + ///Find the cross product between this vector and the vector passed as a parameter. + Vector cross(const Vector& vector) const throw(); + ///Find the dot product between this vector and the vector passed as a parameter. + Type dot(const Vector& rhs) const throw(); + ///Normalise the vector. + void normalise(void) throw(); + + private: + //Values for the vector + Type m_tElements[Size]; + }; + + //Non-member overloaded operators. + //!Multiplication operator. + //template + //Vector operator*(const Vector& lhs, const Matrix& rhs) throw(); + //!Multiplication operator. + //template + //Vector operator*(const Matrix& lhs, const Vector& rhs) throw(); + ///Stream insertion operator. + template + std::ostream& operator<<(std::ostream& os, const Vector& vector) throw(); + + //Some handy typedefs + typedef Vector<2,float> Vector2DFloat; + typedef Vector<2,double> Vector2DDouble; + typedef Vector<2,boost::int32_t> Vector2DInt32; + typedef Vector<2,boost::uint32_t> Vector2DUint32; + typedef Vector<3,float> Vector3DFloat; + typedef Vector<3,double> Vector3DDouble; + typedef Vector<3,boost::int32_t> Vector3DInt32; + typedef Vector<3,boost::uint32_t> Vector3DUint32; +}//namespace Thermite + +#include "Vector.inl" + +#endif + diff --git a/include/Vector.inl b/include/Vector.inl new file mode 100644 index 00000000..e4044a62 --- /dev/null +++ b/include/Vector.inl @@ -0,0 +1,487 @@ +#include +#include +#include + +namespace Ogre +{ + /** + 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 x(), setX(), y(), setY(), z(), 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 boost::operators. + + Lastly, note that for convienience a set of typedefs are included for 2 and 3 dimentionsal + vectors with type float, double, boost::int32_t, and boost::uint32_t. They are used as follows: + + Vector2DInt4 test(1,2); //Declares a 2 dimensional Vector of type int4. + */ + + //-------------------------- 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] = static_cast(vector(ct)); + } + } + + /** + Destroys the Vector. + */ + template + Vector::~Vector(void) throw() + { + } + + //------------------------------- Overloaded 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + if(m_tElements[ct] != rhs(ct)) + { + equal = false; + break; + } + } + return equal; + } + + /** + 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] -= rhs.m_tElements[ct]; + } + return *this; + } + + /** + 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] += rhs.m_tElements[ct]; + } + return *this; + } + + /** + 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] *= rhs; + } + return *this; + } + + /** + 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] /= rhs; + } + return *this; + } + + /** + Multiplies a Vector and a Matrix. + + NOTE: Although the Vector class does not distinguish between row and column vectors, the Vector + must conceptually be in row form for this operation to make sense. + \param lhs The Vector to be multiplied + \param rhs The Matrix to multiply by. + \return The resulting Vector + */ + /*template + Vector operator*(const Vector& lhs, const Matrix& rhs) throw() + { + Type tZero = static_cast(0); + Vector result(tZero,tZero,tZero); + for(boost::uint32_t colCt = 0; colCt < Size; ++colCt) + { + for(boost::uint32_t rowCt = 0; rowCt < Size; ++rowCt) + { + //result(colCt) += lhs(rowCt) * rhs(rowCt, colCt); + result.set(colCt, result(colCt) + (lhs(rowCt) * rhs(rowCt, colCt))); + } + } + return result; + }*/ + + /** + Multiplies a Matrix and a Vector. + + NOTE: Although the Vector class does not distinguish between row and column vectors, the Vector + must conceptually be in column form for this operation to make sense. + \param lhs The Matrix to be multiplied + \param rhs The Vector to multiply by. + \return The resulting Vector + */ + /*template + Vector operator*(const Matrix& lhs, const Vector& rhs) throw() + { + Type tZero = static_cast(0); + Vector result(tZero,tZero,tZero); + for(boost::uint32_t rowCt = 0; rowCt < Size; ++rowCt) + { + for(boost::uint32_t colCt = 0; colCt < Size; ++colCt) + { + //result(rowCt) += lhs(rowCt,colCt) * rhs(colCt); + result.set(rowCt, result(rowCt) + (lhs(rowCt,colCt) * rhs(colCt))); + } + } + 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + os << vector(ct); + if(ct < (Size-1)) + { + os << ","; + } + } + os << ")"; + return os; + } + + /** + Returns the element at the given position. + \param index The index of the element to return. + \return The element. + */ + template + inline Type Vector::operator()(boost::uint32_t index) const throw() + { + return m_tElements[index]; + } + + //----------------------------------- Getters ---------------------------------- + + /** + \return A const reference to the X component of a 1, 2, 3, or 4 dimensional Vector. + */ + template + inline Type Vector::x(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::y(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::z(void) const throw() + { + return m_tElements[2]; + } + + /** + \return A const reference to the W component of a 4 dimensional Vector. + */ + template + inline Type Vector::w(void) const throw() + { + return m_tElements[3]; + } + + //----------------------------------- Setters ---------------------------------- + + /** + \param index The index of the element to set. + \param tValue The new value for the element. + */ + template + inline void Vector::set(boost::uint32_t 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; + } + + //-------------------------------- Other Functions ----------------------------- + + /** + 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(boost::uint32_t 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.z() * this->y() - vector.y() * this->z(); + Type j = vector.x() * this->z() - vector.z() * this->x(); + Type k = vector.y() * this->x() - vector.x() * this->y(); + 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(boost::uint32_t 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(boost::uint32_t ct = 0; ct < Size; ++ct) + { + m_tElements[ct] /= length; + } + } +}//namespace Thermite