Get rid of Matrix<N,M>, just use Matrix4

This commit is contained in:
Eryn Wells 2014-08-10 10:51:12 -07:00
parent 30d0570010
commit 49d097a803
6 changed files with 399 additions and 333 deletions

View file

@ -18,10 +18,4 @@
#include "basics/util.hh"
#include "basics/vector.hh"
inline bool
TooFar(const Double& value)
{
return value > MAX_DISTANCE;
}
#endif /* __BASICS_BASICS_HH__ */

View file

@ -3,27 +3,243 @@
* Eryn Wells <eryn@erynwells.me>
*/
#include "matrix.hh"
#include <cstring>
#include <stdexcept>
#include <sstream>
#include "basics/matrix.hh"
#include "basics/util.hh"
namespace charles {
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 --
*/
Matrix4
TranslationMatrix(const Double& x,
const Double& y,
const Double& z)
/* static */ Matrix4
Translation(Double x,
Double y,
Double z)
{
Matrix4 m = Matrix4::Identity();
m(0, 3) = x;
m(1, 3) = y;
m(2, 3) = z;
m(0,3) = x;
m(1,3) = y;
m(2,3) = z;
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
{
return operator()(i, 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::operator* --
*/
Matrix4
operator*(Double lhs,
const Matrix4& rhs)
{
/* Scalar multiplication is commutative. */
return rhs * lhs;
}
} /* namespace mespace */
} /* namespace charles */

View file

@ -16,274 +16,71 @@
namespace charles {
namespace basics {
/**
* 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.
*/
template<UInt N, UInt M = N>
struct Matrix
struct Vector4;
/** A 4x4 matrix, used for 3D transforms. */
struct Matrix4
{
/** Construct an N x M matrix of zeros. */
static Matrix<N,M> Zero();
/** Create a 4x4 matrix of zeros. */
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.
* It is a (compile time) error to call Identity on a Matrix class where
* N != M.
* Get the ij'th item. In debug builds, this will assert if i or j are
* outside the bounds of the array.
*/
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) 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
* @{
*/
Matrix<N,M> operator*(const Double& rhs) const;
Matrix<N,M>& operator*=(const Double& rhs);
Matrix<N,M> operator/(const Double& rhs) const;
Matrix<N,M>& operator/=(const Double& rhs);
Matrix4 operator*(Double rhs) const;
Matrix4 operator/(Double rhs) const;
Matrix4& operator*=(Double rhs);
Matrix4& operator/=(Double rhs);
/** @} */
/** Matrix multiplication */
template<UInt P>
Matrix<N,P> operator*(Matrix<M,P> rhs) const;
/** Get the underlying C array */
const Double* CArray() const;
/**
* @defgroup Matrix multiplication
* @{
*/
Matrix4 operator*(const Matrix4 &rhs) const;
Vector4 operator*(const Vector4 &rhs) const;
/** @} */
protected:
/** The matrix data, stored in row-major format. */
Double mData[N * M];
/** The matrix data */
Double mData[16];
};
/** Scalar multiplication, scalar factor on the left. */
template<UInt N, UInt M>
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;
}
Matrix4 operator*(const Double &lhs, const Matrix4 &rhs);
} /* namespace basics */
} /* namespace charles */

View file

@ -4,6 +4,7 @@
*/
#include <cmath>
#include <cstring>
#include "basics/vector.hh"
@ -14,9 +15,18 @@ namespace basics {
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4(const Double& x,
const Double& y,
const Double& z)
Vector4::Vector4()
{
bzero(mData, sizeof(Double) * 4);
}
/*
* charles::basics::Vector4::Vector4 --
*/
Vector4::Vector4(Double x,
Double y,
Double z)
{
mData[0] = x;
mData[1] = y;
@ -24,12 +34,7 @@ Vector4::Vector4(const Double& x,
mData[3] = 1.0;
}
Vector4::Vector4(const Matrix<4,1>& rhs)
{
memcpy(mData, rhs.CArray(), sizeof(Double) * 4);
}
#pragma mark Component Access
/*
* charles::basics::Vector4::X --
@ -40,7 +45,11 @@ Vector4::X()
return mData[0];
}
const Double&
/*
* charles::basics::Vector4::X --
*/
Double
Vector4::X()
const
{
@ -58,7 +67,10 @@ Vector4::Y()
}
const Double&
/*
* charles::basics::Vector4::Y --
*/
Double
Vector4::Y()
const
{
@ -79,43 +91,87 @@ Vector4::Z()
/*
* charles::basics::Vector4::Z --
*/
const Double&
Double
Vector4::Z()
const
{
return mData[2];
}
#pragma mark Maths
#if 0
/*
* charles::basics::Vector4::operator* --
*/
Vector4
Vector4::operator*(const Double& rhs)
Vector4::operator*(Double rhs)
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+ --
*/
Vector4
Vector4::operator+(const Vector4& rhs)
Vector4::operator+(const Vector4 &rhs)
const
{
return Vector4(*this) += rhs;
}
/*
* charles::basics::Vector4::operator- --
*/
Vector4
Vector4::operator-(const Vector4 &rhs)
const
{
return Vector4(*this) -= rhs;
}
/*
* charles::basics::Vector4::operator+= --
*/
Vector4&
Vector4::operator+=(const Vector4& rhs)
Vector4::operator+=(const Vector4 &rhs)
{
mData[0] += rhs.mData[0];
mData[1] += rhs.mData[1];
@ -124,22 +180,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-= --
*/
Vector4&
Vector4::operator-=(const Vector4& rhs)
Vector4::operator-=(const Vector4 &rhs)
{
return *this += -rhs;
}
@ -163,7 +208,7 @@ Double
Vector4::Length2()
const
{
return mData[0] * mData[0] + mData[1] * mData[1] + mData[2] * mData[2];
return X()*X() + Y()*Y() + Z()*Z();
}
@ -185,7 +230,7 @@ Double
Vector4::Dot(const Vector4& rhs)
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 +253,7 @@ Vector4::Cross(const Vector4& rhs)
Vector4&
Vector4::Normalize()
{
/* XXX: Is there some way to do this with the Matrix<>::operator/? */
const Double len = Length();
X() = X() / len;
Y() = Y() / len;
Z() = Z() / len;
return *this;
return *this /= Length();
}
@ -221,7 +261,7 @@ Vector4::Normalize()
* charles::basics::operator* --
*/
Vector4
operator*(const Double& lhs,
operator*(Double lhs,
const Vector4& rhs)
{
return rhs * lhs;
@ -232,9 +272,9 @@ operator*(const Double& lhs,
* charles::basics::Normalized --
*/
Vector4
Normalized(const Vector4& v)
Normalized(Vector4 v)
{
return Vector4(v).Normalize();
return v.Normalize();
}

View file

@ -15,34 +15,50 @@
namespace charles {
namespace basics {
template<UInt N>
struct Vector
: public Matrix<N,1>
{ };
/** A 4x1 matrix, used for specifying points and directions in 3D space. */
struct Vector4
: public Vector<4>
{
Vector4(const Double& x = 0.0, const Double& y = 0.0, const Double& z = 0.0);
Vector4(const Matrix<4,1>& m);
Vector4();
Vector4(Double x, Double y, Double z);
Vector4 &operator=(const Vector4 &rhs);
/**
* @defgroup Component access
* @{
*/
Double& X();
const Double& X() const;
Double X() const;
Double& Y();
const Double& Y() const;
Double Y() const;
Double& Z();
const Double& Z() const;
Double Z() const;
/** @} */
#if 0
Vector4 operator*(const Double& rhs) const;
#endif
bool operator==(const Vector4 &rhs) const;
bool operator!=(const Vector4 &rhs) const;
Vector4 operator+(const Vector4& rhs) const;
Vector4& operator+=(const Vector4& rhs);
Vector4 operator-(const Vector4& rhs) const;
Vector4& operator-=(const Vector4& rhs);
/**
* @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;
/** Get the length-squared of this vector. */
@ -52,30 +68,33 @@ struct Vector4
Double Length() const;
/** 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`. */
Vector4 Cross(const Vector4& rhs) const;
/** Normalize this vector. */
Vector4& Normalize();
private:
Double mData[4];
};
/** 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. */
Vector4 Normalized(const Vector4& v);
/** Normalize a copy of the given vector. */
Vector4 Normalized(Vector4 v);
Vector4 LinearCombination(const Double k1, const Vector4& v1,
const Double k2, const Vector4& v2,
const Double k3, const Vector4& v3);
Vector4 LinearCombination(Double k1, const Vector4 &v1,
Double k2, const Vector4 &v2,
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 charles */

View file

@ -25,7 +25,7 @@ namespace charles {
* charles::Object::Object --
*/
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()
{ }