src/Vector.hh
author nireco
Sat, 31 Jan 2009 12:33:08 +0200
changeset 443 5d1119729f58
parent 425 567144562978
permissions -rw-r--r--
worm02 two pics to comment
#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 << ")";
}

/*
 * Vector template method implementation
 */

/**
 * 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) {
    // XXX: use hand-crafted abs because GCC 4.3/4.2 static template functions seem to be broken somehow
    if (coord > (tangent < 0 ? -tangent : tangent))
        return 1;

    else if (coord < (tangent > 0 ? -tangent : 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