Welcome to lark3ri.fi

Matrix and vector classes with c++

28.10.2020

I wrote these classes a couple of years ago. They became a byproduct of when I developed my own 3d game engine. I never got to finish it, still, not yet. It loaded 3d objects from files and drew those in 3d and it was fun to make. It was made using only SDL2 2d library. There was also a cube in the game. The camera was able to rotate around the cube by moving the mouse. Also the cube could be moved with the WASD keys.

I remember that I have tested the functionality of these classes. I remember some bug was in the matrix class, somewhere on top of it. The bug didn't affect its use in any way so I left it there.

matrix.h
/*
    Copyright (C) 2017 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    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.
*/

#ifndef MATRIX_H
#define MATRIX_H

#include <cstring>

#include "vector.h"

/*     A   B   C   D
 * a { 00, 01, 02, 03 }
 * b { 10, 11, 12, 13 }
 * c { 20, 21, 22, 23 }
 * d { 30, 31, 32, 33 }
 *
 * aA, bA, cA = x, y, z = Forward Vector,
 * aB, bB, cB = x, y, z = Up Vector,
 * aC, bC, cC = x, y, z = Right Vector,
 * aD, bD, cD = x, y, z = Translation Vector.
 *
 * Matrix = Matrix +/- Vector
 * Matrix +=/-= Vector
 * Adding or subtracting translation.
 *
 * T *get_row(unsigned int p) const;
 * T *get_column(unsigned int p) const;
 * Return a dynamically allocated array. Remember to delete[] it.
*/

template<class T>
class Matrix
{
public:
    Matrix() {identity();}
    Matrix(T x0,T y0,T z0,
           T x1,T y1,T z1,
           T x2,T y2,T z2,
           T xT,T yT,T zT,
           T w0,T w1,T w2,T w3);
    Matrix(const Vector<T> &forward,
           const Vector<T> &up,
           const Vector<T> &right);
    Matrix(const T (&forward)[3],
           const T (&up)[3],
           const T (&right)[3]);
    Matrix(const T (&array)[4][4]);
    Matrix(const Matrix &_m);

    Matrix<T>& operator =(const T (&rhs)[4][4]);
    Matrix<T>& operator =(const T rhs);
    Matrix<T>& operator =(const Matrix &rhs);

    Matrix<T>& operator *=(const T rhs);
    Matrix<T>& operator *=(const Matrix &rhs);
    Matrix<T> operator *(const T rhs);
    Matrix<T> operator *(const Matrix &rhs);
    Vector<T> operator *(const Vector<T> &rhs);
    Vector<T> transform_vector(const Vector<T> &rhs);

    Matrix<T>& operator +=(const T rhs);
    Matrix<T>& operator +=(const Matrix<T> &rhs);
    Matrix<T>& operator +=(const Vector<T> &rhs);
    Matrix<T> operator +(const T rhs);
    Matrix<T> operator +(const Matrix<T> &rhs);
    Matrix<T> operator +(const Vector<T> &rhs);

    Matrix<T>& operator -=(const T rhs);
    Matrix<T>& operator -=(const Matrix<T> &rhs);
    Matrix<T>& operator -=(const Vector<T> &rhs);
    Matrix<T> operator -(const T rhs);
    Matrix<T> operator -(const Matrix<T> &rhs);
    Matrix<T> operator -(const Vector<T> &rhs);

    bool operator ==(const T (&rhs)[4][4]) const;
    bool operator ==(const T rhs) const;
    bool operator ==(const Matrix &rhs) const;
    bool operator ==(const Vector<T> &rhs) const;
    bool operator !=(const T (&rhs)[4][4]) const;
    bool operator !=(const T rhs) const;
    bool operator !=(const Matrix &rhs) const;
    bool operator !=(const Vector<T> &rhs) const;

    void identity();
    bool is_identity() const;

    Vector<T> get_forward_vector() const;
    Vector<T> get_up_vector() const;
    Vector<T> get_right_vector() const;
    Vector<T> get_translation_vector() const;

    void set_scale(T x,T y,T z);
    void set_scale(const Vector<T> &v);
    void set_rotation(double a, T x, T y, T z);
    void set_rotation(double a, const Vector<T> &v);
    void set_translation(T x,T y,T z);
    void set_translation(const Vector<T> &v);
    void set_forward(T x,T y,T z);
    void set_forward(const Vector<T> &v);
    void set_up(T x,T y,T z);
    void set_up(const Vector<T> &v);
    void set_right(T x,T y,T z);
    void set_right(const Vector<T> &v);

    T *get_row(unsigned int p) const;
    void set_row(unsigned int p,T r0,T r1,T r2,T r3);
    T *get_column(unsigned int p) const;
    void set_column(unsigned int p,T c0,T c1,T c2,T c3);
    void set_column(unsigned int p, const Vector<T> &v,T c3);

    T m[4][4];

    const unsigned int ROW_SIZE = sizeof(m)/sizeof(m[0]);
    const unsigned int COLUMN_SIZE = sizeof(m[0])/sizeof(T);

private:
    template<class U>
    friend std::ostream &operator <<(std::ostream &, const Matrix<U> &);
};

template<class T>
std::ostream& operator <<(std::ostream &os, const Matrix<T> &m)
{
    os << "Matrix\n";
    for (unsigned int r = 0; r < m.ROW_SIZE; r++)
    {
        os << "[";
        for (unsigned int c = 0; c < m.COLUMN_SIZE; c++)
            os << m.m[r][c] << ((c<3)?",":"]\n");
    }
    return os << "\n";
}

template<class T>
Matrix<T>::Matrix(T x0,T y0,T z0,
                  T x1,T y1,T z1,
                  T x2,T y2,T z2,
                  T xT,T yT,T zT,
                  T w0,T w1,T w2,T w3)
{
    m[0][0] = x0; m[0][1] = x1; m[0][2] = x2; m[0][3] = xT;
    m[1][0] = y0; m[1][1] = y1; m[1][2] = y2; m[1][3] = yT;
    m[2][0] = z0; m[2][1] = z1; m[2][2] = z2; m[2][3] = zT;
    m[3][0] = w0; m[3][1] = w1; m[3][2] = w2; m[3][3] = w3;
}

template<class T>
Matrix<T>::Matrix(const Matrix &_m)
{
    memcpy(m, _m.m, sizeof m);
}

template<class T>
Matrix<T>::Matrix(const Vector<T> &f,
               const Vector<T> &u,
               const Vector<T> &r)
{
    *this = {{f.x,u.x,r.x,0},
             {f.y,u.y,r.y,0},
             {f.z,u.z,r.z,0},
             {0,0,0,1}};
}

template<class T>
Matrix<T>::Matrix(const T (&f)[3],
                  const T (&u)[3],
                  const T (&r)[3])
{
    *this = {{f[0],u[0],r[0],0},
             {f[1],u[1],r[1],0},
             {f[2],u[2],r[2],0},
             {0,0,0,1}};
}

template<class T>
Matrix<T>::Matrix(const T (&array)[4][4])
{
    *this = array;
}

// Basic assignment
template<class T>
Matrix<T>& Matrix<T>::operator =(const T (&rhs)[4][4])
{
    if (*this != rhs) memcpy(m, rhs, sizeof m);
    return *this;
}
template<class T>
Matrix<T>& Matrix<T>::operator =(const T rhs)
{
    return *this = {{rhs,rhs,rhs,rhs},
                    {rhs,rhs,rhs,rhs},
                    {rhs,rhs,rhs,rhs},
                    {rhs,rhs,rhs,rhs}};
}
template<class T>
Matrix<T>& Matrix<T>::operator =(const Matrix<T> &rhs)
{
    return *this = rhs.m;
}

// Multiplication
template<class T>
Matrix<T>& Matrix<T>::operator *=(const T rhs)
{
    m[0][0] *= rhs; m[0][1] *= rhs; m[0][2] *= rhs; m[0][3] *= rhs;
    m[1][0] *= rhs; m[1][1] *= rhs; m[1][2] *= rhs; m[1][3] *= rhs;
    m[2][0] *= rhs; m[2][1] *= rhs; m[2][2] *= rhs; m[2][3] *= rhs;
    m[3][0] *= rhs; m[3][1] *= rhs; m[3][2] *= rhs; m[3][3] *= rhs;
    return *this;
}
template<class T>
Matrix<T>& Matrix<T>::operator *=(const Matrix &rhs)
{
    T r[ROW_SIZE][COLUMN_SIZE];
    r[0][0] = m[0][0]*rhs.m[0][0] + m[0][1]*rhs.m[1][0] + m[0][2]*rhs.m[2][0] + m[0][3]*rhs.m[3][0];
    r[0][1] = m[0][0]*rhs.m[0][1] + m[0][1]*rhs.m[1][1] + m[0][2]*rhs.m[2][1] + m[0][3]*rhs.m[3][1];
    r[0][2] = m[0][0]*rhs.m[0][2] + m[0][1]*rhs.m[1][2] + m[0][2]*rhs.m[2][2] + m[0][3]*rhs.m[3][2];
    r[0][3] = m[0][0]*rhs.m[0][3] + m[0][1]*rhs.m[1][3] + m[0][2]*rhs.m[2][3] + m[0][3]*rhs.m[3][3];

    r[1][0] = m[1][0]*rhs.m[0][0] + m[1][1]*rhs.m[1][0] + m[1][2]*rhs.m[2][0] + m[1][3]*rhs.m[3][0];
    r[1][1] = m[1][0]*rhs.m[0][1] + m[1][1]*rhs.m[1][1] + m[1][2]*rhs.m[2][1] + m[1][3]*rhs.m[3][1];
    r[1][2] = m[1][0]*rhs.m[0][2] + m[1][1]*rhs.m[1][2] + m[1][2]*rhs.m[2][2] + m[1][3]*rhs.m[3][2];
    r[1][3] = m[1][0]*rhs.m[0][3] + m[1][1]*rhs.m[1][3] + m[1][2]*rhs.m[2][3] + m[1][3]*rhs.m[3][3];

    r[2][0] = m[2][0]*rhs.m[0][0] + m[2][1]*rhs.m[1][0] + m[2][2]*rhs.m[2][0] + m[2][3]*rhs.m[3][0];
    r[2][1] = m[2][0]*rhs.m[0][1] + m[2][1]*rhs.m[1][1] + m[2][2]*rhs.m[2][1] + m[2][3]*rhs.m[3][1];
    r[2][2] = m[2][0]*rhs.m[0][2] + m[2][1]*rhs.m[1][2] + m[2][2]*rhs.m[2][2] + m[2][3]*rhs.m[3][2];
    r[2][3] = m[2][0]*rhs.m[0][3] + m[2][1]*rhs.m[1][3] + m[2][2]*rhs.m[2][3] + m[2][3]*rhs.m[3][3];

    r[3][0] = m[3][0]*rhs.m[0][0] + m[3][1]*rhs.m[1][0] + m[3][2]*rhs.m[2][0] + m[3][3]*rhs.m[3][0];
    r[3][1] = m[3][0]*rhs.m[0][1] + m[3][1]*rhs.m[1][1] + m[3][2]*rhs.m[2][1] + m[3][3]*rhs.m[3][1];
    r[3][2] = m[3][0]*rhs.m[0][2] + m[3][1]*rhs.m[1][2] + m[3][2]*rhs.m[2][2] + m[3][3]*rhs.m[3][2];
    r[3][3] = m[3][0]*rhs.m[0][3] + m[3][1]*rhs.m[1][3] + m[3][2]*rhs.m[2][3] + m[3][3]*rhs.m[3][3];

    memcpy(m, r, sizeof m);
    return *this;
}
template<class T>
Matrix<T> Matrix<T>::operator *(const T rhs)
{
    return Matrix(*this) *= rhs;
}
template<class T>
Matrix<T> Matrix<T>::operator *(const Matrix &rhs)
{
    return Matrix(*this) *= rhs;
}
template<class T>
Vector<T> Matrix<T>::operator *(const Vector<T> &rhs)
{
    return Vector<T>(m[0][0]*rhs.x + m[0][1]*rhs.y + m[0][2]*rhs.z + m[0][3]*m[0][3],
                     m[1][0]*rhs.x + m[1][1]*rhs.y + m[1][2]*rhs.z + m[1][3]*m[1][3],
                     m[2][0]*rhs.x + m[2][1]*rhs.y + m[2][2]*rhs.z + m[2][3]*m[2][3]);
}
template<class T>
Vector<T> Matrix<T>::transform_vector(const Vector<T> &rhs)
{
    return Vector<T>(m[0][0]*rhs.x + m[0][1]*rhs.y + m[0][2]*rhs.z + m[0][3],
                     m[1][0]*rhs.x + m[1][1]*rhs.y + m[1][2]*rhs.z + m[1][3],
                     m[2][0]*rhs.x + m[2][1]*rhs.y + m[2][2]*rhs.z + m[2][3]);
}

// Addition
template<class T>
Matrix<T>& Matrix<T>::operator +=(const T rhs)
{
    m[0][0] += rhs; m[0][1] += rhs; m[0][2] += rhs; m[0][3] += rhs;
    m[1][0] += rhs; m[1][1] += rhs; m[1][2] += rhs; m[1][3] += rhs;
    m[2][0] += rhs; m[2][1] += rhs; m[2][2] += rhs; m[2][3] += rhs;
    m[3][0] += rhs; m[3][1] += rhs; m[3][2] += rhs; m[3][3] += rhs;
    return *this;
}
template<class T>
Matrix<T>& Matrix<T>::operator +=(const Matrix<T> &rhs)
{
    m[0][0] += rhs.m[0][0]; m[0][1] += rhs.m[0][1]; m[0][2] += rhs.m[0][2]; m[0][3] += rhs.m[0][3];
    m[1][0] += rhs.m[1][0]; m[1][1] += rhs.m[1][1]; m[1][2] += rhs.m[1][2]; m[1][3] += rhs.m[1][3];
    m[2][0] += rhs.m[2][0]; m[2][1] += rhs.m[2][1]; m[2][2] += rhs.m[2][2]; m[2][3] += rhs.m[2][3];
    m[3][0] += rhs.m[3][0]; m[3][1] += rhs.m[3][1]; m[3][2] += rhs.m[3][2]; m[3][3] += rhs.m[3][3];
    return *this;
}
template<class T>
Matrix<T>& Matrix<T>::operator +=(const Vector<T> &rhs)
{
    m[0][3] += rhs.x;
    m[1][3] += rhs.y;
    m[2][3] += rhs.z;
    return *this;
}
template<class T>
Matrix<T> Matrix<T>::operator +(const T rhs)
{
    return Matrix(*this) += rhs;
}
template<class T>
Matrix<T> Matrix<T>::operator +(const Matrix<T> &rhs)
{
    return Matrix(*this) += rhs;
}
template<class T>
Matrix<T> Matrix<T>::operator +(const Vector<T> &rhs)
{
    return Matrix(*this) += rhs;
}

// Subtraction
template<class T>
Matrix<T>& Matrix<T>::operator -=(const T rhs)
{
    return *this += -rhs;
}
template<class T>
Matrix<T>& Matrix<T>::operator -=(const Matrix<T> &rhs)
{
    m[0][0] -= rhs.m[0][0]; m[0][1] -= rhs.m[0][1]; m[0][2] -= rhs.m[0][2]; m[0][3] -= rhs.m[0][3];
    m[1][0] -= rhs.m[1][0]; m[1][1] -= rhs.m[1][1]; m[1][2] -= rhs.m[1][2]; m[1][3] -= rhs.m[1][3];
    m[2][0] -= rhs.m[2][0]; m[2][1] -= rhs.m[2][1]; m[2][2] -= rhs.m[2][2]; m[2][3] -= rhs.m[2][3];
    m[3][0] -= rhs.m[3][0]; m[3][1] -= rhs.m[3][1]; m[3][2] -= rhs.m[3][2]; m[3][3] -= rhs.m[3][3];
    return *this;
}
template<class T>
Matrix<T>& Matrix<T>::operator -=(const Vector<T> &rhs)
{
    m[0][3] -= rhs.x;
    m[1][3] -= rhs.y;
    m[2][3] -= rhs.z;
    return *this;
}
template<class T>
Matrix<T> Matrix<T>::operator -(const T rhs)
{
    return Matrix(*this) -= rhs;
}
template<class T>
Matrix<T> Matrix<T>::operator -(const Matrix<T> &rhs)
{
    return Matrix(*this) -= rhs;
}
template<class T>
Matrix<T> Matrix<T>::operator -(const Vector<T> &rhs)
{
    return Matrix(*this) -= rhs;
}

// Comparison operators
template<class T>
bool Matrix<T>::operator ==(const T (&rhs)[4][4]) const
{
    return m[0][0] == rhs[0][0] && m[0][1] == rhs[0][1] && m[0][2] == rhs[0][2] && m[0][3] == rhs[0][3] &&
           m[1][0] == rhs[1][0] && m[1][1] == rhs[1][1] && m[1][2] == rhs[1][2] && m[1][3] == rhs[1][3] &&
           m[2][0] == rhs[2][0] && m[2][1] == rhs[2][1] && m[2][2] == rhs[2][2] && m[2][3] == rhs[2][3] &&
           m[3][0] == rhs[3][0] && m[3][1] == rhs[3][1] && m[3][2] == rhs[3][2] && m[3][3] == rhs[3][3];
}
template<class T>
bool Matrix<T>::operator ==(const T rhs) const
{
    return this->operator ==({{rhs,rhs,rhs,rhs},
                              {rhs,rhs,rhs,rhs},
                              {rhs,rhs,rhs,rhs},
                              {rhs,rhs,rhs,rhs}});
}
template<class T>
bool Matrix<T>::operator ==(const Matrix &rhs) const
{
    return *this == rhs.m;
}
template<class T>
bool Matrix<T>::operator ==(const Vector<T> &rhs) const
{
    return m[0][3] == rhs.x && m[1][3] == rhs.y && m[2][3] == rhs.z;
}
template<class T>
bool Matrix<T>::operator !=(const T (&rhs)[4][4]) const
{
    return !(*this == rhs);
}
template<class T>
bool Matrix<T>::operator !=(const T rhs) const
{
    return !(*this == rhs);
}
template<class T>
bool Matrix<T>::operator !=(const Matrix &rhs) const
{
    return !(*this == rhs);
}
template<class T>
bool Matrix<T>::operator !=(const Vector<T> &rhs) const
{
    return !(*this == rhs);
}

template<class T>
void Matrix<T>::identity()
{
    memset(m, 0, sizeof m);
    m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1;
}

template<class T>
bool Matrix<T>::is_identity() const
{
    return m[0][0] == 1 && m[0][1] == 0 && m[0][2] == 0 && m[0][3] == 0 &&
           m[1][0] == 0 && m[1][1] == 1 && m[1][2] == 0 && m[1][3] == 0 &&
           m[2][0] == 0 && m[2][1] == 0 && m[2][2] == 1 && m[2][3] == 0 &&
           m[3][0] == 0 && m[3][1] == 0 && m[3][2] == 0 && m[3][3] == 1;
}

// Get vector
template<class T>
Vector<T> Matrix<T>::get_forward_vector() const
{
    return Vector<T>(m[0][0],m[1][0],m[2][0]);
}
template<class T>
Vector<T> Matrix<T>::get_up_vector() const
{
    return Vector<T>(m[0][1],m[1][1],m[2][1]);
}
template<class T>
Vector<T> Matrix<T>::get_right_vector() const
{
    return Vector<T>(m[0][2],m[1][2],m[2][2]);
}
template<class T>
Vector<T> Matrix<T>::get_translation_vector() const
{
    return Vector<T>(m[0][3],m[1][3],m[2][3]);
}

// Set scale
template<class T>
void Matrix<T>::set_scale(T x,T y,T z)
{
    m[0][0] = x;
    m[1][1] = y;
    m[2][2] = z;
}
template<class T>
void Matrix<T>::set_scale(const Vector<T> &v)
{
    set_scale(v.x, v.y, v.z);
}

// Set rotation
template<class T>
void Matrix<T>::set_rotation(double a,T x,T y,T z)
{
    double c = cos(a);
    double s = sin(a);
    double t = 1-c;

    m[0][0] = x*x*t + c;
    m[1][0] = y*x*t + z*s;
    m[2][0] = z*x*t - y*s;

    m[0][1] = x*y*t - z*s;
    m[1][1] = y*y*t + c;
    m[2][1] = z*y*t + x*s;

    m[0][2] = x*z*t + y*s;
    m[1][2] = y*z*t - x*s;
    m[2][2] = z*z*t + c;
}
template<class T>
void Matrix<T>::set_rotation(double a, const Vector<T> &v)
{
    set_rotation(a, v.x, v.y, v.z);
}

// Set translation
template<class T>
void Matrix<T>::set_translation(T x,T y,T z)
{
    m[0][3] = x;
    m[1][3] = y;
    m[2][3] = z;
}
template<class T>
void Matrix<T>::set_translation(const Vector<T> &v)
{
    set_translation(v.x, v.y, v.z);
}

// Set FUR vectors
template<class T>
void Matrix<T>::set_forward(T x,T y,T z)
{
    m[0][0] = x;
    m[1][0] = y;
    m[2][0] = z;
}
template<class T>
void Matrix<T>::set_forward(const Vector<T> &v)
{
    set_forward_vector(v.x, v.y, v.z);
}
template<class T>
void Matrix<T>::set_up(T x,T y,T z)
{
    m[0][1] = x;
    m[1][1] = y;
    m[2][1] = z;
}
template<class T>
void Matrix<T>::set_up(const Vector<T> &v)
{
    set_up_vector(v.x, v.y, v.z);
}
template<class T>
void Matrix<T>::set_right(T x,T y,T z)
{
    m[0][2] = x;
    m[1][2] = y;
    m[2][2] = z;
}
template<class T>
void Matrix<T>::set_right(const Vector<T> &v)
{
    set_right_vector(v.x, v.y, v.z);
}

// Get/Set row
template<class T>
T *Matrix<T>::get_row(unsigned int p) const
{
    if (p > ROW_SIZE) return NULL;
    T *r = new T[ROW_SIZE];
    r[0] = m[p][0];
    r[1] = m[p][1];
    r[2] = m[p][2];
    r[3] = m[p][3];
    return r;
}
template<class T>
void Matrix<T>::set_row(unsigned int p,T r0,T r1,T r2,T r3)
{
    if (p > ROW_SIZE) return;
    m[p][0] = r0;
    m[p][1] = r1;
    m[p][2] = r2;
    m[p][3] = r3;
}
// Get/Set column
template<class T>
T *Matrix<T>::get_column(unsigned int p) const
{
    if (p > COLUMN_SIZE) return NULL;
    T *r = new T[COLUMN_SIZE];
    r[0] = m[0][p];
    r[1] = m[1][p];
    r[2] = m[2][p];
    r[3] = m[3][p];
    return r;
}
template<class T>
void Matrix<T>::set_column(unsigned int p,T c0,T c1,T c2,T c3)
{
    if (p > COLUMN_SIZE) return;
    m[0][p] = c0;
    m[1][p] = c1;
    m[2][p] = c2;
    m[3][p] = c3;
}
template<class T>
void Matrix<T>::set_column(unsigned int p, const Vector<T> &v,T c3)
{
    set_column(p, v.x, v.y, v.z, c3);
}

#endif // MATRIX_H

vector.h
/*
    Copyright (C) 2017 Lari Varjonen <[email protected]>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    version 2 as published by the Free Software Foundation.

    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.
*/

#ifndef VECTOR_H
#define VECTOR_H

#include <math.h>


template<class T>
class Vector
{
public:
    Vector();
    Vector(T rhs);
    Vector(T x, T y, T z);
    Vector(const T (&array)[3]);

    Vector<T>& operator =(const T rhs);
    Vector<T>& operator =(const T (&rhs)[3]);
    Vector<T>& operator =(const Vector &rhs);

    Vector<T>& operator *=(const T rhs);
    Vector<T>& operator *=(const Vector &rhs);
    Vector<T> operator *(const T rhs);
    Vector<T> operator *(const Vector &rhs);

    Vector<T>& operator /=(const T rhs);
    Vector<T>& operator /=(const Vector &rhs);
    Vector<T> operator /(const T rhs);
    Vector<T> operator /(const Vector &rhs);

    Vector<T>& operator +=(const T rhs);
    Vector<T>& operator +=(const Vector &rhs);
    Vector<T> operator +(const T rhs);
    Vector<T> operator +(const Vector &rhs);

    Vector<T>& operator -=(const T rhs);
    Vector<T>& operator -=(const Vector &rhs);
    Vector<T> operator -(const T rhs);
    Vector<T> operator -(const Vector &rhs);

    bool operator ==(const T (&rhs)[3]) const;
    bool operator ==(const T rhs) const;
    bool operator ==(const Vector &rhs) const;
    bool operator !=(const T (&rhs)[3]) const;
    bool operator !=(const T rhs) const;
    bool operator !=(const Vector &rhs) const;

    T dot(const Vector &rhs) const;
    Vector<T> cross(const Vector &rhs) const;

    T length() const;
    T length_sqr() const;
    Vector<T> normalized() const;
    void normalize();

    T x, y, z;

private:
    template<class U>
    friend std::ostream &operator <<(std::ostream &, const Vector<U> &);
};

template<class T>
std::ostream& operator <<(std::ostream &os, const Vector<T> &vec)
{
    return os << "Vector " << vec.x << ", " << vec.y << ", " << vec.z << "\n";
}

template<class T>
Vector<T>::Vector()
{
    x = y = z = 0;
}

template<class T>
Vector<T>::Vector(T rhs)
{
    x = rhs;
    y = rhs;
    z = rhs;
}

template<class T>
Vector<T>::Vector(T x, T y, T z)
{
    this->x = x;
    this->y = y;
    this->z = z;
}

template<class T>
Vector<T>::Vector(const T (&array)[3])
{
    x = array[0];
    y = array[1];
    z = array[2];
}

// Basic assignment
template<class T>
Vector<T>& Vector<T>::operator =(const T (&rhs)[3])
{
    if (*this != rhs)
    {
        x = rhs[0];
        y = rhs[1];
        z = rhs[2];
    }
    return *this;
}
template<class T>
Vector<T>& Vector<T>::operator =(const T rhs)
{
    return *this = { rhs, rhs, rhs };
}
template<class T>
Vector<T>& Vector<T>::operator =(const Vector<T> &rhs)
{
    return *this = { rhs.x, rhs.y, rhs.z };
}

// Multiplication
template<class T>
Vector<T>& Vector<T>::operator *=(const T rhs)
{
    x *= rhs;
    y *= rhs;
    z *= rhs;
    return *this;
}
template<class T>
Vector<T>& Vector<T>::operator *=(const Vector &rhs)
{
    x *= rhs.x;
    y *= rhs.y;
    z *= rhs.z;
    return *this;
}
template<class T>
Vector<T> Vector<T>::operator *(const T rhs)
{
    return Vector(*this) *= rhs;
}
template<class T>
Vector<T> Vector<T>::operator *(const Vector &rhs)
{
    return Vector(*this) *= rhs;
}

// Division
template<class T>
Vector<T>& Vector<T>::operator /=(const T rhs)
{
    x /= rhs;
    y /= rhs;
    z /= rhs;
    return *this;
}
template<class T>
Vector<T>& Vector<T>::operator /=(const Vector &rhs)
{
    x /= rhs.x;
    y /= rhs.y;
    z /= rhs.z;
    return *this;
}
template<class T>
Vector<T> Vector<T>::operator /(const T rhs)
{
    return Vector(*this) /= rhs;
}
template<class T>
Vector<T> Vector<T>::operator /(const Vector &rhs)
{
    return Vector(*this) /= rhs;
}

// Addition
template<class T>
Vector<T>& Vector<T>::operator +=(const T rhs)
{
    x += rhs;
    y += rhs;
    z += rhs;
    return *this;
}
template<class T>
Vector<T>& Vector<T>::operator +=(const Vector &rhs)
{
    x += rhs.x;
    y += rhs.y;
    z += rhs.z;
    return *this;
}
template<class T>
Vector<T> Vector<T>::operator +(const T rhs)
{
    return Vector(*this) += rhs;
}
template<class T>
Vector<T> Vector<T>::operator +(const Vector &rhs)
{
    return Vector(*this) += rhs;
}

// Subtraction
template<class T>
Vector<T>& Vector<T>::operator -=(const T rhs)
{
    return *this += -rhs;
}
template<class T>
Vector<T>& Vector<T>::operator -=(const Vector &rhs)
{
    x -= rhs.x;
    y -= rhs.y;
    z -= rhs.z;
    return *this;
}
template<class T>
Vector<T> Vector<T>::operator -(const T rhs)
{
    return Vector(*this) -= rhs;
}
template<class T>
Vector<T> Vector<T>::operator -(const Vector &rhs)
{
    return Vector(*this) -= rhs;
}

// Comparison operators
template<class T>
bool Vector<T>::operator ==(const T (&rhs)[3]) const
{
    return x == rhs[0] && y == rhs[1] && z == rhs[2];
}
template<class T>
bool Vector<T>::operator ==(const T rhs) const
{
    return x == rhs && y == rhs && z == rhs;
}
template<class T>
bool Vector<T>::operator ==(const Vector &rhs) const
{
    return x == rhs.x && y == rhs.y && z == rhs.z;
}
template<class T>
bool Vector<T>::operator !=(const T (&rhs)[3]) const
{
    return !(*this == rhs);
}
template<class T>
bool Vector<T>::operator !=(const T rhs) const
{
    return !(*this == rhs);
}
template<class T>
bool Vector<T>::operator !=(const Vector &rhs) const
{
    return !(*this == rhs);
}

// Products
template<class T>
T Vector<T>::dot(const Vector &rhs) const
{
    return x * rhs.x + y * rhs.y + z * rhs.z;
}
template<class T>
Vector<T> Vector<T>::cross(const Vector &rhs) const
{
    T _x = y * rhs.z - z * rhs.y;
    T _y = z * rhs.x - x * rhs.z;
    T _z = x * rhs.y - y * rhs.x;
    return Vector(_x, _y, _z);
}

template<class T>
T Vector<T>::length() const
{
    return sqrt(x*x + y*y + z*z);
}
template<class T>
T Vector<T>::length_sqr() const
{
    return (x*x + y*y + z*z);
}
template<class T>
Vector<T> Vector<T>::normalized() const
{
    T l = length();
    Vector<T> r = 0;
    if (l == 0) return r;
    r = (*this);
    return r /= l;
}
template<class T>
void Vector<T>::normalize()
{
    T l = length();
    if (l == 0) x = y = z = 0;
    else (*this) /= l;
}

#endif // VECTOR_H
« Back | ↑ Top