Merge branch 'matrix4' into feature/transform-matrix
This commit is contained in:
commit
5b25b402c7
8 changed files with 580 additions and 390 deletions
|
@ -15,60 +15,7 @@
|
|||
#include "basics/matrix.hh"
|
||||
#include "basics/ray.hh"
|
||||
#include "basics/types.hh"
|
||||
#include "basics/util.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__ */
|
||||
|
|
|
@ -3,19 +3,54 @@
|
|||
* 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 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
|
||||
Matrix4::Translation(Double x,
|
||||
Double y,
|
||||
Double z)
|
||||
{
|
||||
Matrix4 m = Matrix4::Identity();
|
||||
m(0,3) = x;
|
||||
|
@ -24,6 +59,213 @@ TranslationMatrix(const Double& x,
|
|||
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 charles */
|
||||
|
||||
|
|
|
@ -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*(Double lhs, const Matrix4 &rhs);
|
||||
|
||||
} /* namespace basics */
|
||||
} /* namespace charles */
|
||||
|
|
68
src/basics/util.hh
Normal file
68
src/basics/util.hh
Normal 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__ */
|
||||
|
|
@ -4,19 +4,35 @@
|
|||
*/
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "basics/vector.hh"
|
||||
|
||||
#include "basics/util.hh"
|
||||
|
||||
|
||||
namespace charles {
|
||||
namespace basics {
|
||||
|
||||
#pragma mark Constructors and Assignment
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
@ -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 --
|
||||
|
@ -40,7 +62,11 @@ Vector4::X()
|
|||
return mData[0];
|
||||
}
|
||||
|
||||
const Double&
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::X --
|
||||
*/
|
||||
Double
|
||||
Vector4::X()
|
||||
const
|
||||
{
|
||||
|
@ -58,7 +84,10 @@ Vector4::Y()
|
|||
}
|
||||
|
||||
|
||||
const Double&
|
||||
/*
|
||||
* charles::basics::Vector4::Y --
|
||||
*/
|
||||
Double
|
||||
Vector4::Y()
|
||||
const
|
||||
{
|
||||
|
@ -79,7 +108,7 @@ Vector4::Z()
|
|||
/*
|
||||
* charles::basics::Vector4::Z --
|
||||
*/
|
||||
const Double&
|
||||
Double
|
||||
Vector4::Z()
|
||||
const
|
||||
{
|
||||
|
@ -87,17 +116,114 @@ 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* --
|
||||
*/
|
||||
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
|
||||
|
||||
|
||||
/*
|
||||
|
@ -111,6 +237,17 @@ Vector4::operator+(const Vector4& rhs)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-(const Vector4 &rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator+= --
|
||||
*/
|
||||
|
@ -124,17 +261,6 @@ Vector4::operator+=(const Vector4& rhs)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator- --
|
||||
*/
|
||||
Vector4
|
||||
Vector4::operator-(const Vector4& rhs)
|
||||
const
|
||||
{
|
||||
return Vector4(*this) -= rhs;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* charles::basics::Vector4::operator-= --
|
||||
*/
|
||||
|
@ -163,7 +289,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 +311,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 +334,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 +342,7 @@ Vector4::Normalize()
|
|||
* charles::basics::operator* --
|
||||
*/
|
||||
Vector4
|
||||
operator*(const Double& lhs,
|
||||
operator*(Double lhs,
|
||||
const Vector4& rhs)
|
||||
{
|
||||
return rhs * lhs;
|
||||
|
@ -232,9 +353,9 @@ operator*(const Double& lhs,
|
|||
* charles::basics::Normalized --
|
||||
*/
|
||||
Vector4
|
||||
Normalized(const Vector4& v)
|
||||
Normalized(Vector4 v)
|
||||
{
|
||||
return Vector4(v).Normalize();
|
||||
return v.Normalize();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -15,34 +15,56 @@
|
|||
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
|
||||
Double &operator()(UInt i);
|
||||
Double operator()(UInt i) const;
|
||||
|
||||
/** Get the underlying C array. */
|
||||
const Double *CArray() const;
|
||||
/** @} */
|
||||
|
||||
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);
|
||||
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. */
|
||||
|
@ -59,20 +81,23 @@ struct Vector4
|
|||
|
||||
/** 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);
|
||||
|
|
|
@ -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()
|
||||
{ }
|
||||
|
||||
|
|
|
@ -248,7 +248,7 @@ TEST_F(Matrix4Test, ScalarMultiplication)
|
|||
}
|
||||
|
||||
|
||||
TEST_F(Matrix4Test, SquareMatrixMultiplication)
|
||||
TEST_F(Matrix4Test, MatrixMatrixMultiplication)
|
||||
{
|
||||
const Double p1Expect[] = {1045, 1690, 2735, 4425,
|
||||
2137, 3454, 5591, 9045,
|
||||
|
@ -267,20 +267,10 @@ TEST_F(Matrix4Test, SquareMatrixMultiplication)
|
|||
for (int i = 0; i < 16; 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;
|
||||
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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue