C plus plus:Tutorials:Matrices
From GPWiki
The wiki is now hosted by GameDev.NET at wiki.gamedev.net. All gpwiki.org content has been moved to the new server. However, the GPWiki forums are still active! Come say hello. A general-purpose templated two-dimensional matrix in C++. Feel free to add to it. #ifndef MATRIX2_HPP #define MATRIX2_HPP #include <cmath> #include <iostream> #include <vector> #include <stdexcept> #include <algorithm> #include <functional> template <class T> class Matrix2 { public: explicit Matrix2(int r = 0, int c = 0, T init_with = T()) : rows_( r < 1 ? 4 : r), columns_( c < 1 ? 4 : c ), data_( rows_ * columns_, init_with ) {} template <typename U> explicit Matrix2(Matrix2<U> const &other) : rows_( other.rows() ), columns_( other.columns() ), data_( &*other, &*other+(rows_*columns_) ) {} T &operator()(int row, int column) { return data_[column+(columns_*row)]; } T const &operator()(int row, int column) const { return data_[column+(columns_*row)]; } int rows() const { return rows_; } int columns() const { return columns_; } operator T*() { return data_.empty() ? 0 : &data_[0]; } operator T const*() const { return data_.empty() ? 0 : &data_[0]; } Matrix2 &operator+=(const Matrix2& other) { if ( rows() != other.rows() || columns() != other.columns() ) { throw std::invalid_argument("To add matrices they must have the same size"); } std::transform( data_.begin(), data_.end(), other.data_.begin(), data_.begin(), std::plus<T>() ); return *this; } Matrix2 &operator-=(const Matrix2& other) { if ( rows() != other.rows() || columns() != other.columns() ) { throw std::invalid_argument("To subtract matrices they must have the same size"); } std::transform( data_.begin(), data_.end(), other.data_.begin(), data_.begin(), std::minus<T>() ); return *this; } template <class U> friend const Matrix2<U> operator*(const Matrix2<U>& one, const Matrix2<U>& two); Matrix2 &operator*=(const Matrix2& other) { return *this = *this * other; } Matrix2 &operator*=(T const &scale) { std::transform( data_.begin(), data_.end(), data_.begin(), std::bind2nd( std::multiplies<T>(), scale ) ); return *this; } Matrix2 &operator/=(T const &scale) { std::transform( data_.begin(), data_.end(), data_.begin(), std::bind2nd( std::divides<T>(), scale ) ); return *this; } void load_identity() { if ( rows() != columns() ) { throw std::invalid_argument("Identity matrices only exist for square matrices"); } for (int i=0; i<rows(); i++) { for (int j=0; j<columns(); j++) { operator()( i, j ) = (i==j); } } } template <typename U> Matrix2 &operator=(Matrix2<U> const &other) { // note that the assign needs to be done first for exception safety. data_.assign( other.data_.begin(), other.data_.end() ); rows_ = other.rows_; columns_ = other.columns_; return *this; } private: // note: changing the order here will break both constructors int rows_; int columns_; std::vector<T> data_; }; template <class T> const Matrix2<T> operator+(Matrix2<T> one, Matrix2<T> const &two) { return one += two; } template <class T> const Matrix2<T> operator-(Matrix2<T> one, Matrix2<T> const &two) { return one -= two; } template <class T> const Matrix2<T> operator*(const Matrix2<T>& one, const Matrix2<T>& two) { if ( one.columns() != two.rows() ) { throw std::invalid_argument("Matrices can only be multiplied if the first has" " exactly as many columns as the second has rows"); } Matrix2<T> result( one.rows(), two.columns() ); for (int i=0; i<result.rows(); i++) for (int j=0; j<result.columns(); j++) for (int a=0; a<one.columns(); a++) result(i,j) += one(i,a) * two(a,j); return result; } template <class T> const Matrix2<T> operator*(Matrix2<T> one, T const &factor) { return one *= factor; } template <class T> const Matrix2<T> operator*(T const &factor, Matrix2<T> one) { return one *= factor; } template <class T> const Matrix2<T> operator/(Matrix2<T> one, T const &factor) { return one /= factor; } template <typename T, typename U> bool operator==(Matrix2<T> const &one, Matrix2<U> const &two) { return (one.rows() == two.rows() && one.columns() == two.columns() && std::equal( &*one, &*one + one.rows()*one.columns(), &*two )); } template <typename T, typename U> bool operator!=(Matrix2<T> const &one, Matrix2<U> const &two) { return !( one == two ); } template<class T> std::ostream& operator<<(std::ostream& os, const Matrix2<T>& mat) { for (int i=0; i< mat.rows(); i++) { os << "\n["; for (int j=0; j<mat.columns(); j++) { os << mat(i,j); if ( j+1 < mat.columns() ) os << "\t"; } os << "]" << std::endl; } return os; } typedef Matrix2<float> Matrixf; typedef Matrix2<int> Matrixi; typedef Matrix2<size_t> Matrixu; #endif // MATRIX2_HPP |


