Merge branch 'matrix4' into feature/transform-matrix

This commit is contained in:
Eryn Wells 2014-08-10 11:39:56 -07:00
commit 5b25b402c7
8 changed files with 580 additions and 390 deletions

View file

@ -15,60 +15,7 @@
#include "basics/matrix.hh" #include "basics/matrix.hh"
#include "basics/ray.hh" #include "basics/ray.hh"
#include "basics/types.hh" #include "basics/types.hh"
#include "basics/util.hh"
#include "basics/vector.hh" #include "basics/vector.hh"
/**
* A very small constant. If a value is between EPSILON and 0.0, it is
* considered to be zero.
*/
const Double EPSILON = 1.0e-10;
/**
* The maximum distance a ray can travel. This is the maximum value t can be.
*/
const Double MAX_DISTANCE = 1.0e7;
/**
* Determine if the value is "close enough" to zero. Takes the absolute value
* and compares it to `EPSILON`.
*
* @see EPSILON
*
* @param [in] value The value to check
* @returns `true` if the value is close enough to zero
*/
template <typename T>
inline bool
NearZero(const T value)
{
return std::fabs(value) < EPSILON;
}
/**
* Determine if two values are "close enough" to be considered equal. Subtracts
* one from the other and checks if the result is near zero.
*
* @see NearZero
*
* @param [in] left The left parameter
* @param [in] right The right parameter
* @returns `true` if the values are close enough to be equal
*/
template <typename T>
inline bool
NearlyEqual(const T left,
const T right)
{
return NearZero(left - right);
}
inline bool
TooFar(const Double& value)
{
return value > MAX_DISTANCE;
}
#endif /* __BASICS_BASICS_HH__ */ #endif /* __BASICS_BASICS_HH__ */

View file

@ -3,27 +3,269 @@
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
#include "matrix.hh" #include <cstring>
#include <stdexcept>
#include <sstream>
#include "basics/matrix.hh"
#include "basics/util.hh"
#include "basics/vector.hh"
namespace charles { namespace charles {
namespace basics { namespace basics {
#pragma mark Static Methods
/*
* charles::basics::Matrix4::Zero --
*/
/* static */ Matrix4
Matrix4::Zero()
{
Matrix4 m;
bzero(m.mData, sizeof(Double) * 16);
return m;
}
/*
* charles::basics::Matrix4::Identity --
*/
/* static */ Matrix4
Matrix4::Identity()
{
auto m = Matrix4::Zero();
for (size_t i = 0; i < 4; i++) {
m(i,i) = 1.0;
}
return m;
}
/* /*
* charles::basics::TranslationMatrix -- * charles::basics::TranslationMatrix --
*/ */
Matrix4 /* static */ Matrix4
TranslationMatrix(const Double& x, Matrix4::Translation(Double x,
const Double& y, Double y,
const Double& z) Double z)
{ {
Matrix4 m = Matrix4::Identity(); Matrix4 m = Matrix4::Identity();
m(0, 3) = x; m(0,3) = x;
m(1, 3) = y; m(1,3) = y;
m(2, 3) = z; m(2,3) = z;
return m; return m;
} }
#pragma mark Constructors and Assignment
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4()
: mData()
{ }
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4(const Double data[16])
{
memcpy(mData, data, sizeof(Double) * 16);
}
/*
* charles::basics::Matrix4::Matrix4 --
*/
Matrix4::Matrix4(const Matrix4 &rhs)
: Matrix4(rhs.mData)
{ }
/*
* charles::basics::Matrix4::operator= --
*/
Matrix4&
Matrix4::operator=(const Matrix4 &rhs)
{
memcpy(mData, rhs.mData, sizeof(Double) * 16);
return *this;
}
#pragma mark Boolean Operators
/*
* charles::basics::Matrix4::operator== --
*/
bool
Matrix4::operator==(const Matrix4 &rhs)
const
{
for (int i = 0; i < 16; i++) {
if (!NearlyEqual(mData[i], rhs.mData[i])) {
return false;
}
}
return true;
}
/*
* charles::basics::Matrix4::operator!= --
*/
bool
Matrix4::operator!=(const Matrix4 &rhs)
const
{
return !(*this == rhs);
}
#pragma mark Element Access
/*
* charles::basics::Matrix4::operator() --
*/
Double&
Matrix4::operator()(UInt i,
UInt j)
{
if (i >= 4 || j >= 4) {
std::stringstream ss;
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
throw std::out_of_range(ss.str());
}
return mData[i*4 + j];
}
/*
* charles::basics::Matrix4::operator() --
*/
Double
Matrix4::operator()(UInt i,
UInt j)
const
{
if (i >= 4 || j >= 4) {
std::stringstream ss;
ss << "matrix index out of bounds: i = " << i << ", j = " << j;
throw std::out_of_range(ss.str());
}
return mData[i*4 + j];
}
/*
* charles::basics::Matrix4::CArray --
*/
const Double*
Matrix4::CArray()
const
{
return mData;
}
#pragma mark Maths
/*
* charles::basics::Matrix4::operator* --
*/
Matrix4
Matrix4::operator*(Double rhs)
const
{
return Matrix4(*this) *= rhs;
}
/*
* charles::basics::Matrix4::operator/ --
*/
Matrix4
Matrix4::operator/(Double rhs)
const
{
return Matrix4(*this) /= rhs;
}
/*
* charles::basics::Matrix4::operator*= --
*/
Matrix4&
Matrix4::operator*=(Double rhs)
{
for (UInt i = 0; i < 16; i++) {
mData[i] *= rhs;
}
return *this;
}
/*
* charles::basics::Matrix4::operator/= --
*/
Matrix4&
Matrix4::operator/=(Double rhs)
{
return *this *= (1.0 / rhs);
}
/*
* charles::basics::Matrix4::operator* --
*/
Matrix4
Matrix4::operator*(const Matrix4& rhs)
const
{
Matrix4 result;
for (UInt i = 0; i < 4; i++) {
for (UInt j = 0; j < 4; j++) {
/* Each cell is Sigma(k=0, M)(lhs[ik] * rhs[kj]) */
result(i,j) = 0.0;
for (UInt k = 0; k < 4; k++) {
result(i,j) += mData[i*4 + k] * rhs(k,j);
}
}
}
return result;
}
/*
* charles::basics::Matrix4::operator* --
*/
Vector4
Matrix4::operator*(const Vector4 &rhs)
const
{
Vector4 result;
for (UInt i = 0; i < 4; i++) {
result(i) = 0.0;
for (UInt k = 0; k < 4; k++) {
result(i) += mData[i*4 + k] * rhs(k);
}
}
return result;
}
/*
* charles::basics::operator* --
*/
Matrix4
operator*(Double lhs,
const Matrix4& rhs)
{
/* Scalar multiplication is commutative. */
return rhs * lhs;
}
} /* namespace mespace */ } /* namespace mespace */
} /* namespace charles */ } /* namespace charles */

View file

@ -16,274 +16,71 @@
namespace charles { namespace charles {
namespace basics { namespace basics {
/** struct Vector4;
* A generic, templated Matrix class taking two template parameters. `N` is the
* number of rows. `M` is the number of columns. If `M` is not specified, the
* matrix will be square. /** A 4x4 matrix, used for 3D transforms. */
*/ struct Matrix4
template<UInt N, UInt M = N>
struct Matrix
{ {
/** Construct an N x M matrix of zeros. */ /** Create a 4x4 matrix of zeros. */
static Matrix<N,M> Zero(); static Matrix4 Zero();
/** Create a 4x4 identity matrix. */
static Matrix4 Identity();
/** Create a 4x4 translation matrix. */
static Matrix4 Translation(Double x, Double y, Double z);
Matrix4();
Matrix4(const Double *data);
Matrix4(const Matrix4 &rhs);
Matrix4& operator=(const Matrix4 &rhs);
bool operator==(const Matrix4 &rhs) const;
bool operator!=(const Matrix4 &rhs) const;
/** /**
* Construct an N x M identity matrix. Identity matrices are always square. * Get the ij'th item. In debug builds, this will assert if i or j are
* It is a (compile time) error to call Identity on a Matrix class where * outside the bounds of the array.
* N != M.
*/ */
static Matrix<N,M> Identity();
Matrix();
Matrix(const Double data[N*M]);
Matrix(const Matrix<N,M>& rhs);
Matrix<N,M>& operator=(const Matrix<N,M>& rhs);
bool operator==(const Matrix<N,M>& rhs) const;
bool operator!=(const Matrix<N,M>& rhs) const;
/** Value accessor. Get the ij'th item. */
Double& operator()(UInt i, UInt j); Double& operator()(UInt i, UInt j);
Double operator()(UInt i, UInt j) const;
/** Get the underlying C array */
const Double *CArray() const;
/*
* TODO: For completeness, matrix addition and subtraction, though I have
* yet to find a need for them...
*/
/** /**
* @defgroup Scalar multiplication * @defgroup Scalar multiplication
* @{ * @{
*/ */
Matrix<N,M> operator*(const Double& rhs) const; Matrix4 operator*(Double rhs) const;
Matrix<N,M>& operator*=(const Double& rhs); Matrix4 operator/(Double rhs) const;
Matrix<N,M> operator/(const Double& rhs) const; Matrix4& operator*=(Double rhs);
Matrix<N,M>& operator/=(const Double& rhs); Matrix4& operator/=(Double rhs);
/** @} */ /** @} */
/** Matrix multiplication */ /**
template<UInt P> * @defgroup Matrix multiplication
Matrix<N,P> operator*(Matrix<M,P> rhs) const; * @{
*/
/** Get the underlying C array */ Matrix4 operator*(const Matrix4 &rhs) const;
const Double* CArray() const; Vector4 operator*(const Vector4 &rhs) const;
/** @} */
protected: protected:
/** The matrix data, stored in row-major format. */ /** The matrix data */
Double mData[N * M]; Double mData[16];
}; };
/** Scalar multiplication, scalar factor on the left. */ /** Scalar multiplication, scalar factor on the left. */
template<UInt N, UInt M> Matrix4 operator*(Double lhs, const Matrix4 &rhs);
Matrix<N,M> operator*(const Double& lhs, const Matrix<N,M>& rhs);
/** A standard 4x4 matrix. */
typedef Matrix<4> Matrix4;
/**
* Create a translation matrix that will translate a vector to the given
* coordinates.
*/
Matrix4 TranslationMatrix(const Double& x, const Double& y, const Double& z);
#pragma mark Static Methods
/*
* charles::basics::Matrix<>::Zero --
*/
template<UInt N, UInt M>
/* static */ Matrix<N,M>
Matrix<N,M>::Zero()
{
Matrix<N,M> m;
bzero(m.mData, sizeof(Double) * N * M);
return m;
}
/*
* charles::basics::Matrix<>::Identity --
*/
template<UInt N, UInt M>
/* static */ Matrix<N,M>
Matrix<N,M>::Identity()
{
static_assert(N == M, "Identity matrices must be square.");
auto m = Matrix<N,M>::Zero();
for (size_t i = 0; i < N; i++) {
m(i,i) = 1.0;
}
return m;
}
#pragma mark Instance Methods
/*
* charles::basics::Matrix<>::Matrix --
*/
template<UInt N, UInt M>
Matrix<N,M>::Matrix()
: mData()
{ }
/*
* charles::basics::Matrix<>::Matrix --
*/
template<UInt N, UInt M>
Matrix<N,M>::Matrix(const Double data[N*M])
{
memcpy(mData, data, sizeof(Double) * N * M);
}
/*
* charles::basics::Matrix<>::Matrix --
*/
template<UInt N, UInt M>
Matrix<N,M>::Matrix(const Matrix<N,M>& rhs)
: Matrix(rhs.mData)
{ }
/*
* charles::basics::Matrix<>::operator= --
*/
template<UInt N, UInt M>
Matrix<N,M>&
Matrix<N,M>::operator=(const Matrix<N,M>& rhs)
{
memcpy(mData, rhs.mData, sizeof(Double) * N * M);
return *this;
}
/*
* charles::basics::Matrix<>::operator== --
*/
template<UInt N, UInt M>
bool
Matrix<N,M>::operator==(const Matrix<N,M>& rhs)
const
{
for (UInt i = 0; i < N*M; i++) {
/* TODO: Use NearlyEqual. */
if (mData[i] != rhs.mData[i]) {
return false;
}
}
return true;
}
/*
* charles::basics::Matrix<>::operator!= --
*/
template<UInt N, UInt M>
bool
Matrix<N,M>::operator!=(const Matrix<N,M>& rhs)
const
{
return !(*this == rhs);
}
/*
* charles::basics::Matrix<>::operator() --
*/
template<UInt N, UInt M>
Double&
Matrix<N,M>::operator()(UInt i, UInt j)
{
assert(i < N && j < M);
return mData[i * N + j];
}
/*
* charles::basics::Matrix<>::operator* --
*/
template<UInt N, UInt M>
Matrix<N,M>
Matrix<N,M>::operator*(const Double& rhs)
const
{
return Matrix<N,M>(*this) *= rhs;
}
template<UInt N, UInt M>
Matrix<N,M>&
Matrix<N,M>::operator*=(const Double& rhs)
{
for (size_t i = 0; i < N*M; i++) {
mData[i] *= rhs;
}
return *this;
}
template<UInt N, UInt M>
Matrix<N,M>
Matrix<N,M>::operator/(const Double& rhs)
const
{
return Matrix<N,M>(*this) /= rhs;
}
template<UInt N, UInt M>
Matrix<N,M>&
Matrix<N,M>::operator/=(const Double& rhs)
{
return *this *= (1.0 / rhs);
}
/*
* charles::basics::Matrix<>::operator* --
*/
template<UInt N, UInt M>
template<UInt P>
Matrix<N,P>
Matrix<N,M>::operator*(Matrix<M,P> rhs)
const
{
Matrix<N,P> result;
for (UInt i = 0; i < N; i++) {
for (UInt j = 0; j < P; j++) {
/* Each cell is Sigma(k=0, M)(lhs[ik] * rhs[kj]) */
result(i, j) = 0.0;
for (UInt k = 0; k < M; k++) {
result(i, j) += mData[i*N + k] * rhs(k, j);
}
}
}
return result;
}
/*
* charles::basics::Matrix<>::CArray --
*/
template<UInt N, UInt M>
const Double*
Matrix<N,M>::CArray()
const
{
return mData;
}
/*
* charles::basics::operator* --
*/
template<UInt N, UInt M>
Matrix<N,M>
operator*(const Double& lhs,
const Matrix<N,M>& rhs)
{
return rhs * lhs;
}
} /* namespace basics */ } /* namespace basics */
} /* namespace charles */ } /* namespace charles */

68
src/basics/util.hh Normal file
View file

@ -0,0 +1,68 @@
/* util.hh
* vim: set tw=80:
* Eryn Wells <eryn@erynwells.me>
*/
#ifndef __BASICS_UTIL_HH__
#define __BASICS_UTIL_HH__
#include <cmath>
/**
* A very small constant. If a value is between EPSILON and 0.0, it is
* considered to be zero.
*/
const Double EPSILON = 1.0e-10;
/**
* The maximum distance a ray can travel. This is the maximum value t can be.
*/
const Double MAX_DISTANCE = 1.0e7;
/**
* Determine if the value is "close enough" to zero. Takes the absolute value
* and compares it to `EPSILON`.
*
* @see EPSILON
*
* @param [in] value The value to check
* @returns `true` if the value is close enough to zero
*/
template <typename T>
inline bool
NearZero(T value)
{
return std::fabs(value) < EPSILON;
}
/**
* Determine if two values are "close enough" to be considered equal. Subtracts
* one from the other and checks if the result is near zero.
*
* @see NearZero
*
* @param [in] left The left parameter
* @param [in] right The right parameter
* @returns `true` if the values are close enough to be equal
*/
template <typename T, typename U>
inline bool
NearlyEqual(T left,
U right)
{
return NearZero(left - right);
}
inline bool
TooFar(const Double& value)
{
return value > MAX_DISTANCE;
}
#endif /* __BASICS_UTIL_HH__ */

View file

@ -4,19 +4,35 @@
*/ */
#include <cmath> #include <cmath>
#include <cstring>
#include <sstream>
#include <stdexcept>
#include "basics/vector.hh" #include "basics/vector.hh"
#include "basics/util.hh"
namespace charles { namespace charles {
namespace basics { namespace basics {
#pragma mark Constructors and Assignment
/* /*
* charles::basics::Vector4::Vector4 -- * charles::basics::Vector4::Vector4 --
*/ */
Vector4::Vector4(const Double& x, Vector4::Vector4()
const Double& y, {
const Double& z) bzero(mData, sizeof(Double) * 4);
}
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4(Double x,
Double y,
Double z)
{ {
mData[0] = x; mData[0] = x;
mData[1] = y; mData[1] = y;
@ -25,11 +41,17 @@ Vector4::Vector4(const Double& x,
} }
Vector4::Vector4(const Matrix<4,1>& rhs) /*
* charles::basics::Vector4::operator= --
*/
Vector4&
Vector4::operator=(const Vector4 &rhs)
{ {
memcpy(mData, rhs.CArray(), sizeof(Double) * 4); memcpy(mData, rhs.mData, sizeof(Double) * 4);
return *this;
} }
#pragma mark Component Access
/* /*
* charles::basics::Vector4::X -- * charles::basics::Vector4::X --
@ -40,7 +62,11 @@ Vector4::X()
return mData[0]; return mData[0];
} }
const Double&
/*
* charles::basics::Vector4::X --
*/
Double
Vector4::X() Vector4::X()
const const
{ {
@ -58,7 +84,10 @@ Vector4::Y()
} }
const Double& /*
* charles::basics::Vector4::Y --
*/
Double
Vector4::Y() Vector4::Y()
const const
{ {
@ -79,7 +108,7 @@ Vector4::Z()
/* /*
* charles::basics::Vector4::Z -- * charles::basics::Vector4::Z --
*/ */
const Double& Double
Vector4::Z() Vector4::Z()
const const
{ {
@ -87,35 +116,143 @@ Vector4::Z()
} }
#if 0 Double&
Vector4::operator()(UInt i)
{
if (i >= 4) {
std::stringstream ss;
ss << "vector index out of bounds: i = " << i;
throw std::out_of_range(ss.str());
}
return mData[i];
}
Double
Vector4::operator()(UInt i)
const
{
if (i >= 4) {
std::stringstream ss;
ss << "vector index out of bounds: i = " << i;
throw std::out_of_range(ss.str());
}
return mData[i];
}
/*
* charles::basics::Vector4::CArray --
*/
const Double*
Vector4::CArray()
const
{
return mData;
}
#pragma mark Boolean Operators
/*
* charles::basics::Vector4::operator== --
*/
bool
Vector4::operator==(const Vector4 &rhs)
const
{
for (UInt i = 0; i < 4; i++) {
if (!NearlyEqual(mData[i], rhs.mData[i])) {
return false;
}
}
return true;
}
/*
* charles::basics::Vector4::operator!= --
*/
bool
Vector4::operator!=(const Vector4 &rhs)
const
{
return !(*this == rhs);
}
#pragma mark Maths
/* /*
* charles::basics::Vector4::operator* -- * charles::basics::Vector4::operator* --
*/ */
Vector4 Vector4
Vector4::operator*(const Double& rhs) Vector4::operator*(Double rhs)
const const
{ {
return static_cast<Matrix<4,1>>(*this) * rhs; return Vector4(*this) *= rhs;
}
/*
* charles::basics::Vector4::operator* --
*/
Vector4
Vector4::operator/(Double rhs)
const
{
return Vector4(*this) /= rhs;
}
/*
* charles::basics::Vector4::operator*= --
*/
Vector4&
Vector4::operator*=(Double rhs)
{
for (int i = 0; i < 4; i++) {
mData[i] *= rhs;
}
return *this;
}
/*
* charles::basics::Vector4::operator/= --
*/
Vector4&
Vector4::operator/=(Double rhs)
{
return *this *= (1.0 / rhs);
} }
#endif
/* /*
* charles::basics::Vector4::operator+ -- * charles::basics::Vector4::operator+ --
*/ */
Vector4 Vector4
Vector4::operator+(const Vector4& rhs) Vector4::operator+(const Vector4 &rhs)
const const
{ {
return Vector4(*this) += rhs; return Vector4(*this) += rhs;
} }
/*
* charles::basics::Vector4::operator- --
*/
Vector4
Vector4::operator-(const Vector4 &rhs)
const
{
return Vector4(*this) -= rhs;
}
/* /*
* charles::basics::Vector4::operator+= -- * charles::basics::Vector4::operator+= --
*/ */
Vector4& Vector4&
Vector4::operator+=(const Vector4& rhs) Vector4::operator+=(const Vector4 &rhs)
{ {
mData[0] += rhs.mData[0]; mData[0] += rhs.mData[0];
mData[1] += rhs.mData[1]; mData[1] += rhs.mData[1];
@ -124,22 +261,11 @@ Vector4::operator+=(const Vector4& rhs)
} }
/*
* charles::basics::Vector4::operator- --
*/
Vector4
Vector4::operator-(const Vector4& rhs)
const
{
return Vector4(*this) -= rhs;
}
/* /*
* charles::basics::Vector4::operator-= -- * charles::basics::Vector4::operator-= --
*/ */
Vector4& Vector4&
Vector4::operator-=(const Vector4& rhs) Vector4::operator-=(const Vector4 &rhs)
{ {
return *this += -rhs; return *this += -rhs;
} }
@ -163,7 +289,7 @@ Double
Vector4::Length2() Vector4::Length2()
const const
{ {
return mData[0] * mData[0] + mData[1] * mData[1] + mData[2] * mData[2]; return X()*X() + Y()*Y() + Z()*Z();
} }
@ -185,7 +311,7 @@ Double
Vector4::Dot(const Vector4& rhs) Vector4::Dot(const Vector4& rhs)
const const
{ {
return mData[0] * rhs.mData[0] + mData[1] * rhs.mData[1] + mData[2] * rhs.mData[2]; return X()*rhs.X() + Y()*rhs.Y() + Z()*rhs.Z();
} }
@ -208,12 +334,7 @@ Vector4::Cross(const Vector4& rhs)
Vector4& Vector4&
Vector4::Normalize() Vector4::Normalize()
{ {
/* XXX: Is there some way to do this with the Matrix<>::operator/? */ return *this /= Length();
const Double len = Length();
X() = X() / len;
Y() = Y() / len;
Z() = Z() / len;
return *this;
} }
@ -221,7 +342,7 @@ Vector4::Normalize()
* charles::basics::operator* -- * charles::basics::operator* --
*/ */
Vector4 Vector4
operator*(const Double& lhs, operator*(Double lhs,
const Vector4& rhs) const Vector4& rhs)
{ {
return rhs * lhs; return rhs * lhs;
@ -232,9 +353,9 @@ operator*(const Double& lhs,
* charles::basics::Normalized -- * charles::basics::Normalized --
*/ */
Vector4 Vector4
Normalized(const Vector4& v) Normalized(Vector4 v)
{ {
return Vector4(v).Normalize(); return v.Normalize();
} }

View file

@ -15,34 +15,56 @@
namespace charles { namespace charles {
namespace basics { namespace basics {
template<UInt N> /** A 4x1 matrix, used for specifying points and directions in 3D space. */
struct Vector
: public Matrix<N,1>
{ };
struct Vector4 struct Vector4
: public Vector<4>
{ {
Vector4(const Double& x = 0.0, const Double& y = 0.0, const Double& z = 0.0); Vector4();
Vector4(const Matrix<4,1>& m); Vector4(Double x, Double y, Double z);
Vector4 &operator=(const Vector4 &rhs);
/**
* @defgroup Component access
* @{
*/
Double& X(); Double& X();
const Double& X() const; Double X() const;
Double& Y(); Double& Y();
const Double& Y() const; Double Y() const;
Double& Z(); Double& Z();
const Double& Z() const; Double Z() const;
#if 0 Double &operator()(UInt i);
Vector4 operator*(const Double& rhs) const; Double operator()(UInt i) const;
#endif
Vector4 operator+(const Vector4& rhs) const; /** Get the underlying C array. */
Vector4& operator+=(const Vector4& rhs); const Double *CArray() const;
Vector4 operator-(const Vector4& rhs) const; /** @} */
Vector4& operator-=(const Vector4& rhs);
bool operator==(const Vector4 &rhs) const;
bool operator!=(const Vector4 &rhs) const;
/**
* @defgroup Scalar multiplication
* @{
*/
Vector4 operator*(Double rhs) const;
Vector4 operator/(Double rhs) const;
Vector4 &operator*=(Double rhs);
Vector4 &operator/=(Double rhs);
/** @} */
/**
* @defgroup Vector addition and subtraction
* @{
*/
Vector4 operator+(const Vector4 &rhs) const;
Vector4 operator-(const Vector4 &rhs) const;
Vector4 &operator+=(const Vector4 &rhs);
Vector4 &operator-=(const Vector4 &rhs);
/** @} */
/** Negate this vector. */
Vector4 operator-() const; Vector4 operator-() const;
/** Get the length-squared of this vector. */ /** Get the length-squared of this vector. */
@ -52,30 +74,33 @@ struct Vector4
Double Length() const; Double Length() const;
/** Get the dot product of `this` and `rhs`. */ /** Get the dot product of `this` and `rhs`. */
Double Dot(const Vector4& rhs) const; Double Dot(const Vector4 &rhs) const;
/** Get the cross product of `this` and `rhs`. */ /** Get the cross product of `this` and `rhs`. */
Vector4 Cross(const Vector4& rhs) const; Vector4 Cross(const Vector4& rhs) const;
/** Normalize this vector. */ /** Normalize this vector. */
Vector4& Normalize(); Vector4& Normalize();
private:
Double mData[4];
}; };
/** Scalar multiplication of vectors, with the scalar factor on the left. */ /** Scalar multiplication of vectors, with the scalar factor on the left. */
Vector4 operator*(const Double& lhs, const Vector4& rhs); Vector4 operator*(Double lhs, const Vector4 &rhs);
/** Normalize the given vector and return a copy of it. */ /** Normalize a copy of the given vector. */
Vector4 Normalized(const Vector4& v); Vector4 Normalized(Vector4 v);
Vector4 LinearCombination(const Double k1, const Vector4& v1, Vector4 LinearCombination(Double k1, const Vector4 &v1,
const Double k2, const Vector4& v2, Double k2, const Vector4 &v2,
const Double k3, const Vector4& v3); Double k3, const Vector4 &v3);
std::ostream& operator<<(std::ostream& ost, const Vector4& v); std::ostream& operator<<(std::ostream &ost, const Vector4 &v);
} /* namespace basics */ } /* namespace basics */
} /* namespace charles */ } /* namespace charles */

View file

@ -25,7 +25,7 @@ namespace charles {
* charles::Object::Object -- * charles::Object::Object --
*/ */
Object::Object(const Vector4& origin) Object::Object(const Vector4& origin)
: mTranslation(basics::TranslationMatrix(origin.X(), origin.Y(), origin.Z())), : mTranslation(basics::Matrix4::Translation(origin.X(), origin.Y(), origin.Z())),
mMaterial() mMaterial()
{ } { }

View file

@ -248,7 +248,7 @@ TEST_F(Matrix4Test, ScalarMultiplication)
} }
TEST_F(Matrix4Test, SquareMatrixMultiplication) TEST_F(Matrix4Test, MatrixMatrixMultiplication)
{ {
const Double p1Expect[] = {1045, 1690, 2735, 4425, const Double p1Expect[] = {1045, 1690, 2735, 4425,
2137, 3454, 5591, 9045, 2137, 3454, 5591, 9045,
@ -267,20 +267,10 @@ TEST_F(Matrix4Test, SquareMatrixMultiplication)
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
EXPECT_EQ(p2.CArray()[i], p2Expect[i]); EXPECT_EQ(p2.CArray()[i], p2Expect[i]);
} }
/* Multiplication with the identity matrix produces the same matrix. */
Matrix4 p3 = m1 * Matrix4::Identity();
for (int i = 0; i < 16; i++) {
EXPECT_EQ(p3.CArray()[i], m1.CArray()[i]);
}
Matrix4 p4 = Matrix4::Identity() * m1;
for (int i = 0; i < 16; i++) {
EXPECT_EQ(p4.CArray()[i], m1.CArray()[i]);
}
} }
TEST_F(Matrix4Test, IdentityMultiplication) TEST_F(Matrix4Test, MatrixIdentityMultiplication)
{ {
Matrix4 p1 = m1 * id; Matrix4 p1 = m1 * id;
for (UInt i = 0; i < 16; i++) { for (UInt i = 0; i < 16; i++) {
@ -294,7 +284,7 @@ TEST_F(Matrix4Test, IdentityMultiplication)
} }
TEST_F(Matrix4Test, VectorMultiplication) TEST_F(Matrix4Test, IdentityVectorMultiplication)
{ {
Vector4 v1(1, 2, 3); Vector4 v1(1, 2, 3);