Templated 3D Vector Class

vector3d.h

#ifndef VECTOR3D_H
#define VECTOR3D_H
 
#include <cstddef>
 
template<typename T>
class vector3d
{
private:
    T X;
    T Y;
    T Z;
 
public:
    //! Sets all members to zero
    vector3d();
 
    //! Explicitly converts from one type to another
    template<typename R>
    explicit vector3d(const vector3d<R>& other);
 
    vector3d(const T& x, const T& y, const T& z);
 
    vector3d(const T coords[3]);
 
    // Get-Set methods
 
    const T& getX() const;
    void setX(const T& newX);
 
    const T& getY() const;
    void setY(const T& newY);
 
    const T& getZ() const;
    void setZ(const T& newZ);
 
    void getv(T buffer[3]) const;
    void setv(const T coords[3]);
 
    void get(T& x, T& y, T& z) const;
    void set(const T& x, const T& y, const T& z);
 
    // Interface for indexing
 
    const T& operator[] (size_t index) const;
    T& operator[] (size_t index);
 
    //! Considering vectors as matrices with one row
    const T& operator() (size_t column) const;
    T& operator() (size_t column);
 
    // Standard operations
 
    //! This does absolutely nothing, but it should be included for consistency
    const vector3d operator+ () const;
 
    const vector3d operator+ (const vector3d& other) const;
    vector3d& operator+= (const vector3d& other);
 
    //! The same as multiplying *this by -1
    const vector3d operator- () const;
 
    const vector3d operator- (const vector3d& other) const;
    vector3d& operator-= (const vector3d& other);
 
    //! Multiplying *this by a scalar
    const vector3d operator* (const T& scalar) const;
    vector3d& operator*= (const T& scalar);
 
    //! Same as multiplication by 1/scalar, maybe more accurate but also slower
    const vector3d operator/ (const T& scalar) const;
    vector3d& operator/= (const T& scalar);
 
    //! Calculate the dot/inner/scalar product
    const T operator* (const vector3d& other) const;
 
    //! Calculate the cross/outer/vector product
    const vector3d operator% (const vector3d& other) const;
    vector3d& operator%= (const vector3d& other);
 
    // Auxiliary methods
 
    //! Returns the squared length of *this
    const T getSqrLen() const;
    //! Returns the length of *this
    const T getLen() const;
 
    //! Returns a vector with the same orientation, but with a length of 1
    const vector3d getUnit() const;
 
    //! Interpolates *this between another vector, by a ratio
    const vector3d getInterpolation(const vector3d& other, const T& ratio) const;
 
    //! Reflects *this according to a surface's normal
    const vector3d getReflection(const vector3d& surfaceNormal) const;
 
    //! Rotates *this about an origin, using Euler angles( X=pitch, Y=yaw, Z=roll)
    const vector3d getRotationEuler(const vector3d& angles,
                                    const vector3d& origin = vector3d(), bool degs = true) const;
 
    //! Rotates *this about an origin, using an arbitrary axis( axis should be a unit vector )
    const vector3d getRotationArbAxis(const vector3d& axis, const T& amount,
                                      const vector3d& origin = vector3d(), bool degs = true) const;
};
 
#include "vector3d.inl"
 
#endif // VECTOR3D_H

vector3d.inl

#include <cmath>
 
template<typename T>
inline vector3d<T>::vector3d()
: X(0), Y(0), Z(0)
{}
 
template<typename T>
template<typename R>
inline vector3d<T>::vector3d(const vector3d<R>& other)
: X(other.X), Y(other.Y), Z(other.Z)
{}
 
template<typename T>
inline vector3d<T>::vector3d(const T& x, const T& y, const T& z)
: X(x), Y(y), Z(z)
{}
 
template<typename T>
inline vector3d<T>::vector3d(const T coords[3])
: X(coords[0]), Y(coords[1]), Z(coords[2])
{}
 
template<typename T>
inline const T& vector3d<T>::getX() const
{
    return X;
}
 
template<typename T>
inline void vector3d<T>::setX(const T& newX)
{
    X = newX;
}
 
template<typename T>
inline const T& vector3d<T>::getY() const
{
    return Y;
}
 
template<typename T>
inline void vector3d<T>::setY(const T& newY)
{
    Y = newY;
}
 
template<typename T>
inline const T& vector3d<T>::getZ() const
{
    return Z;
}
 
template<typename T>
inline void vector3d<T>::setZ(const T& newZ)
{
    Z = newZ;
}
 
template<typename T>
inline void vector3d<T>::getv(T buffer[3]) const
{
    buffer[0] = X;
    buffer[1] = Y;
    buffer[2] = Z;
}
 
template<typename T>
inline void vector3d<T>::setv(const T coords[3])
{
    X = coords[0];
    Y = coords[1];
    Z = coords[2];
}
 
template<typename T>
inline void vector3d<T>::get(T& x, T& y, T& z) const
{
    x = X;
    y = Y;
    z = Z;
}
 
template<typename T>
inline void vector3d<T>::set(const T& x, const T& y, const T& z)
{
    X = x;
    Y = y;
    Z = z;
}
 
template<typename T>
inline const T& vector3d<T>::operator[] (size_t index) const
{
    switch (index)
    {
    case 0:
        return X;
    case 1:
        return Y;
    case 2:
        return Z;
    }
 
    return T();
}
 
template<typename T>
inline T& vector3d<T>::operator[] (size_t index)
{
    switch (index)
    {
    case 0:
        return X;
    case 1:
        return Y;
    case 2:
        return Z;
    }
 
    return T();
}
 
template<typename T>
inline const T& vector3d<T>::operator() (size_t column) const
{
    switch (column)
    {
    case 1:
        return X;
    case 2:
        return Y;
    case 3:
        return Z;
    }
 
    return T();
}
 
template<typename T>
inline T& vector3d<T>::operator() (size_t column)
{
    switch (column)
    {
    case 1:
        return X;
    case 2:
        return Y;
    case 3:
        return Z;
    }
 
    return T();
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator+ () const
{
    return *this;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator+ (const vector3d& other) const
{
    return vector3d(X + other.X, Y + other.Y, Z + other.Z);
}
 
template<typename T>
inline vector3d<T>& vector3d<T>::operator+= (const vector3d& other)
{
    return *this = *this + other;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator- () const
{
    return vector3d(-X, -Y, -Z);
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator- (const vector3d& other) const
{
    return vector3d(X - other.X, Y - other.Y, Z - other.Z);
}
 
template<typename T>
inline vector3d<T>& vector3d<T>::operator-= (const vector3d& other)
{
    return *this = *this - other;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator* (const T& scalar) const
{
    return vector3d(X*scalar, Y*scalar, Z*scalar);
}
 
template<typename T>
inline vector3d<T>& vector3d<T>::operator*= (const T& scalar)
{
    return *this = *this * scalar;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator/ (const T& scalar) const
{
    return vector3d(X/scalar, Y/scalar, Z/scalar);
}
 
template<typename T>
inline vector3d<T>& vector3d<T>::operator/= (const T& scalar)
{
    return *this = *this / scalar;
}
 
template<typename T>
inline const T vector3d<T>::operator* (const vector3d& other) const
{
    return X*other.X + Y*other.Y + Z*other.Z;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::operator% (const vector3d& other) const
{
    return vector3d(Y*other.Z - Z*other.Y,
                    Z*other.X - X*other.Z,
                    X*other.Y - Y*other.X);
}
 
template<typename T>
inline vector3d<T>& vector3d<T>::operator%= (const vector3d& other)
{
    return *this = *this % other;
}
 
template<typename T>
inline const T vector3d<T>::getSqrLen() const
{
    return X*X + Y*Y + Z*Z;
}
 
template<typename T>
inline const T vector3d<T>::getLen() const
{
    return std::sqrt(getSqrLen());
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::getUnit() const
{
    if (getSqrLen() != 0)
        return *this / getLen();
 
    return *this;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::getInterpolation(const vector3d& other, const T& ratio) const
{
    return *this + (other - *this)*ratio;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::getReflection(const vector3d& surfaceNormal) const
{
    return *this - surfaceNormal*((*this * surfaceNormal)*2);
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::
getRotationEuler(const vector3d& angles, const vector3d& origin, bool degs, bool ccw) const
{
    T sin_phi, sin_theta, sin_psi;
    T cos_phi, cos_theta, cos_psi;
 
    if (degs)
    {
        const T degToRad = T(M_PI)/360;
 
        sin_phi = std::sin(angles.getX()*degToRad);
        sin_theta = std::sin(angles.getY()*degToRad);
        sin_psi = std::sin(angles.getZ()*degToRad);
 
        cos_phi = std::cos(angles.getX()*degToRad);
        cos_theta = std::cos(angles.getY()*degToRad);
        cos_psi = std::cos(angles.getZ()*degToRad);
    }
    else
    {
        sin_phi = std::sin(angles.getX());
        sin_theta = std::sin(angles.getY());
        sin_psi = std::sin(angles.getZ());
 
        cos_phi = std::cos(angles.getX());
        cos_theta = std::cos(angles.getY());
        cos_psi = std::cos(angles.getZ());
    }
 
    if (!ccw)
    {
        sin_phi = -sin_phi;
        sin_theta = -sin_theta;
        sin_psi = -sin_psi;
    }
 
    vector3d temp = *this - origin;
    vector3d result = temp;
 
    result.setY( temp.getY()*cos_phi + temp.getZ()*sin_phi);
    result.setZ(-temp.getY()*sin_phi + temp.getZ()*cos_phi);
 
    temp = result;
 
    result.setX(temp.getX()*cos_theta - temp.getZ()*sin_theta);
    result.setZ(temp.getX()*sin_theta + temp.getZ()*cos_theta);
 
    temp = result;
 
    result.setX( temp.getX()*cos_psi + temp.getY()*sin_psi);
    result.setY(-temp.getX()*sin_psi + temp.getY()*cos_psi);
 
    return result + origin;
}
 
template<typename T>
inline const vector3d<T> vector3d<T>::
getRotationArbAxis(const vector3d& axis, const T& amount, const vector3d& origin, bool degs, bool ccw) const
{
    T cos_theta, sin_theta;
 
    if (degs)
    {
        const T degToRad = T(M_PI)/360;
 
        cos_theta = std::cos(amount*degToRad);
        sin_theta = std::sin(amount*degToRad);
    }
    else
    {
        cos_theta = std::cos(amount);
        sin_theta = std::sin(amount);
    }
 
    if (!ccw)
        sin_theta = -sin_theta;
 
    return *this*cos_theta + (axis % *this)*sin_theta + axis*((axis * *this)*(1 - cos_theta));
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution 3.0 License