#ifndef VECTOR_HH
#define VECTOR_HH
#include <iostream>
#include <cmath>
/**
* A 2D Vector class. Implements standard vector operations.
*/
template <typename T> class VectorType {
public:
/** Horizontal component */
T x;
/** Vertical component */
T y;
/**
* Default constructor. Values are zero
*/
VectorType() :
x(0), y(0)
{
}
/**
* Scalar constuctor.
*
* @param x Initial x-coordinate
* @param y Initial y-coordinate
*/
VectorType (const T &x, const T &y) :
x(x), y(y)
{
}
/**
* Copy constructor.
*
* @param v Vector to be copied.
*/
VectorType (const VectorType &v) :
x(v.x),
y(v.y)
{
}
/**
* @name Standard operators
*
* @{
*/
VectorType& operator= (const VectorType &v) {
x = v.x;
y = v.y;
return *this;
}
VectorType operator+ (const VectorType &v) const {
return VectorType(x + v.x, y + v.y);
}
VectorType operator- (const VectorType &v) const {
return VectorType(x - v.x, y - v.y);
}
/** Unary minus (v + -v = 0) */
VectorType operator- (void) const {
return VectorType(-x, -y);
}
/** Scalar multiplication */
VectorType operator* (const T &scalar) const {
return VectorType(x * scalar, y * scalar);
}
/** Scalar division */
VectorType operator/ (const T &scalar) const {
return VectorType(x / scalar, y / scalar);
}
/** Dot product */
T operator* (const VectorType &v) const {
return (x * v.x + y * v.y);
}
void operator+= (const VectorType &v) {
x += v.x;
y += v.y;
}
void operator-= (const VectorType &v) {
x -= v.x;
y -= v.y;
}
void operator*= (const T &scalar) {
x *= scalar;
y *= scalar;
}
void operator/= (const T &scalar) {
x /= scalar;
y /= scalar;
}
/**
* XXX: This needs to do some rounding for float-vectors
*/
bool operator== (const VectorType &other) const {
return (x == other.x) && (y == other.y);
}
/**
* XXX: This needs to do some rounding for float-vectors
*/
bool operator!= (const VectorType &other) const {
return (x != other.x) || (y != other.y);
}
// @}
/**
* Vector scalar length
*/
T length (void) const {
return sqrt(sqrLength());
}
/**
* Vector scalar length, squared
*/
T sqrLength (void) const {
return (x * x) + (y * y);
}
/**
* XXX: should be replaced with a working operator== implementation
*
* This doesn't actually *round*, it *truncates*
*/
VectorType roundToInt (void) const {
return VectorType((int)(x), (int)(y));
}
/**
* Test for a zero-length vector.
*
* XXX: this is currently only used when testing for Vector(0, 0), probably breaks otherwise
*/
bool zero (void) const {
return x == 0 && y == 0;
}
/**
* Returns the corresponding unit vector, i.e. the vector divided by its own length
*
* @return Vector with length() == 1
*/
VectorType unitVector (void) const {
T len = length();
return VectorType(x / len, y / len);
}
/**
* Returns a normalized vector such that the x/y coordinates are both either -1, 0 or 1, to indicate which
* direction this vector points in.
*
* @return normalized Vector
*/
VectorType normalizeDirection (void) const;
/**
* Returns a vector's normal (one of the two)
*/
VectorType normal (void) const {
return VectorType(y, -x);
}
};
/**
* @name Postfix operators
* Operators with the vector as the second argument :)
*
* @{
*/
template<typename T> VectorType<T> operator* (const T &scalar, const VectorType<T> &v) {
return (v * scalar);
}
/**
* Make vectors printable
*/
template<typename T> std::ostream& operator<< (std::ostream &s, const VectorType<T> &v) {
return s << "(" << v.x << ", " << v.y << ")";
}
// Templates function implementations
#include <cmath>
#include <cstdlib>
/**
* Float/int absolute value
*/
template<typename T> static T absType (T value);
template<> static float absType<float> (float value) { return fabs(value); }
template<> static long absType<long> (long value) { return labs(value); }
/**
* Direction-normalize the given coordinate against the tangent coordinate.
*
* Returns 1 if the coordinate is positive and greater than the tangent, -1 if the coordinate is less than and
* negative, else zero.
*/
template<typename T> static T normalizeCoordinate (T coord, T tangent) {
if (coord > absType(tangent))
return 1;
else if (coord < -absType(tangent))
return -1;
else
return 0;
}
template<typename T> VectorType<T> VectorType<T>::normalizeDirection (void) const {
return VectorType<T>(
normalizeCoordinate(x, y),
normalizeCoordinate(y, x)
);
}
#endif