diff --git a/src/basics/basics.hh b/src/basics/basics.hh index a3c8fe4..bedc145 100644 --- a/src/basics/basics.hh +++ b/src/basics/basics.hh @@ -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__ */ diff --git a/src/basics/matrix.cc b/src/basics/matrix.cc index 23b28ba..5a3798b 100644 --- a/src/basics/matrix.cc +++ b/src/basics/matrix.cc @@ -3,27 +3,243 @@ * Eryn Wells */ -#include "matrix.hh" +#include +#include +#include + +#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 */ diff --git a/src/basics/matrix.hh b/src/basics/matrix.hh index 249f110..c7224a9 100644 --- a/src/basics/matrix.hh +++ b/src/basics/matrix.hh @@ -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 -struct Matrix +struct Vector4; + + +/** A 4x4 matrix, used for 3D transforms. */ +struct Matrix4 { - /** Construct an N x M matrix of zeros. */ - static Matrix 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 Identity(); - - Matrix(); - Matrix(const Double data[N*M]); - Matrix(const Matrix& rhs); - - Matrix& operator=(const Matrix& rhs); - - bool operator==(const Matrix& rhs) const; - bool operator!=(const Matrix& 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 operator*(const Double& rhs) const; - Matrix& operator*=(const Double& rhs); - Matrix operator/(const Double& rhs) const; - Matrix& 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 - Matrix operator*(Matrix 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 -Matrix operator*(const Double& lhs, const Matrix& 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 -/* static */ Matrix -Matrix::Zero() -{ - Matrix m; - bzero(m.mData, sizeof(Double) * N * M); - return m; -} - - -/* - * charles::basics::Matrix<>::Identity -- - */ -template -/* static */ Matrix -Matrix::Identity() -{ - static_assert(N == M, "Identity matrices must be square."); - - auto m = Matrix::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 -Matrix::Matrix() - : mData() -{ } - - -/* - * charles::basics::Matrix<>::Matrix -- - */ -template -Matrix::Matrix(const Double data[N*M]) -{ - memcpy(mData, data, sizeof(Double) * N * M); -} - - -/* - * charles::basics::Matrix<>::Matrix -- - */ -template -Matrix::Matrix(const Matrix& rhs) - : Matrix(rhs.mData) -{ } - - -/* - * charles::basics::Matrix<>::operator= -- - */ -template -Matrix& -Matrix::operator=(const Matrix& rhs) -{ - memcpy(mData, rhs.mData, sizeof(Double) * N * M); - return *this; -} - - -/* - * charles::basics::Matrix<>::operator== -- - */ -template -bool -Matrix::operator==(const Matrix& 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 -bool -Matrix::operator!=(const Matrix& rhs) - const -{ - return !(*this == rhs); -} - - -/* - * charles::basics::Matrix<>::operator() -- - */ -template -Double& -Matrix::operator()(UInt i, UInt j) -{ - assert(i < N && j < M); - return mData[i * N + j]; -} - - -/* - * charles::basics::Matrix<>::operator* -- - */ -template -Matrix -Matrix::operator*(const Double& rhs) - const -{ - return Matrix(*this) *= rhs; -} - - -template -Matrix& -Matrix::operator*=(const Double& rhs) -{ - for (size_t i = 0; i < N*M; i++) { - mData[i] *= rhs; - } - return *this; -} - - -template -Matrix -Matrix::operator/(const Double& rhs) - const -{ - return Matrix(*this) /= rhs; -} - - -template -Matrix& -Matrix::operator/=(const Double& rhs) -{ - return *this *= (1.0 / rhs); -} - - -/* - * charles::basics::Matrix<>::operator* -- - */ -template -template -Matrix -Matrix::operator*(Matrix rhs) - const -{ - Matrix 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 -const Double* -Matrix::CArray() - const -{ - return mData; -} - - -/* - * charles::basics::operator* -- - */ -template -Matrix -operator*(const Double& lhs, - const Matrix& rhs) -{ - return rhs * lhs; -} +Matrix4 operator*(const Double &lhs, const Matrix4 &rhs); } /* namespace basics */ } /* namespace charles */ diff --git a/src/basics/vector.cc b/src/basics/vector.cc index 7d42a59..a3b6fac 100644 --- a/src/basics/vector.cc +++ b/src/basics/vector.cc @@ -4,6 +4,7 @@ */ #include +#include #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>(*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(); } diff --git a/src/basics/vector.hh b/src/basics/vector.hh index 787bb4f..a98a095 100644 --- a/src/basics/vector.hh +++ b/src/basics/vector.hh @@ -15,34 +15,50 @@ namespace charles { namespace basics { -template -struct Vector - : public Matrix -{ }; - - +/** 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 */ diff --git a/src/object.cc b/src/object.cc index c3f6bce..57db9c0 100644 --- a/src/object.cc +++ b/src/object.cc @@ -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() { }