YAGE
Yet Another Game Engine
matrix.hpp
Go to the documentation of this file.
1 /* ----------------------------------------------------------------------------
2  * matrix.hpp
3  *
4  * Copyright (c) 2017 Yann Herklotz Grave <ymherklotz@gmail.com> -- MIT License
5  * See file LICENSE for more details
6  * ----------------------------------------------------------------------------
7  */
8 
16 #ifndef YAGE_MATH_MATRIX_HPP
17 #define YAGE_MATH_MATRIX_HPP
18 
19 #include <algorithm>
20 #include <exception>
21 #include <iostream>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 namespace yage
27 {
28 
29 template<int Rows, int Cols, class Type> class Matrix;
30 
31 // includes implementation details that should not be accessible to the user
32 namespace detail
33 {
34 
35 // Row class
36 //
37 // Used to implement the double square bracket operator and be able
38 // to return the value by reference of the array.
39 template<int Rows, int Cols, class Type> class Row
40 {
41 private:
42  Matrix<Rows, Cols, Type> *parent_;
43  int index_;
44 
45 public:
47  parent_(parent), index_(index)
48  {}
49 
50  Type& operator[](int col)
51  {
52  // the index is the y-position of the element in the matrix
53  return parent_->data_[index_*Cols+col];
54  }
55 
56  const Type& operator[](int col) const
57  {
58  return parent_->data_[index_*Cols+col];
59  }
60 };
61 
62 } // detail
63 
64 // Matrix class
65 //
66 // Implements the base Matrix class that is inherited by other classes to make them more
67 // specific.
68 template<int Rows=4, int Cols=4, class Type=double> class Matrix
69 {
70  // friended with the row class so that it can access protected member data
71  friend class detail::Row<Rows, Cols, Type>;
72 protected:
73  std::vector<Type> data_;
74 
75 public:
76  Matrix<Rows, Cols, Type>() : data_(Rows*Cols) {}
77 
78  int rowSize() const
79  {
80  return Rows;
81  }
82 
83  int colSize() const
84  {
85  return Cols;
86  }
87 
88  // returns the row in a row matrix
89  Matrix<1, Cols, Type> getRow(int row) const
90  {
91  Matrix<1, Cols, Type> rowMatrix;
92  for(int i=0; i<Cols; ++i)
93  {
94  rowMatrix[0][i]=data_[row][i];
95  }
96  return rowMatrix;
97  }
98 
99  // returns the column in a column matrix
100  Matrix<Rows, 1, Type> getCol(int col) const
101  {
102  Matrix<Rows, 1, Type> colMatrix;
103  for(int i=0; i<Rows; ++i)
104  {
105  colMatrix[i][0]=data_[i][col];
106  }
107  return colMatrix;
108  }
109 
110  // iterator support for begin
111  typename std::vector<Type>::iterator begin()
112  {
113  return data_.begin();
114  }
115 
116  // iterator support for end
117  typename std::vector<Type>::iterator end()
118  {
119  return data_.end();
120  }
121 
122  // prints out the matrix, but can also be implemented by other classes to print data
123  // differently
124  virtual std::string toString() const
125  {
126  std::stringstream ss;
127  ss<<'[';
128  for(int i=0; i<Rows-1; ++i)
129  {
130  ss<<'[';
131  for(int j=0; j<Cols-1; ++j)
132  {
133  ss<<data_[i*Cols+j]<<' ';
134  }
135  ss<<data_[(Rows-1)*Cols+Cols-1]<<"],";
136  }
137  ss<<'[';
138  for(int j=0; j<Cols-1; ++j)
139  {
140  ss<<data_[(Rows-1)*Cols+j]<<' ';
141  }
142  ss<<data_[(Rows-1)*Cols+Cols-1]<<"]]";
143  return ss.str();
144  }
145 
146  detail::Row<Rows, Cols, Type> operator[](int row)
147  {
148  return detail::Row<Rows, Cols, Type>(this, row);
149  }
150 
151  detail::Row<Rows, Cols, Type> operator[](int row) const
152  {
153  // TODO got to fix this
155  }
156 
157  Matrix<Rows, Cols, Type>& operator=(const Matrix<Rows, Cols, Type> &other)
158  {
159  if(this!=&other)
160  {
161  data_=other.data_;
162  }
163  return *this;
164  }
165 
166  Matrix<Rows, Cols, Type>& operator+=(const Matrix<Rows, Cols, Type> &rhs)
167  {
168  std::vector<Type> out;
169  out.reserve(data_.size());
170  std::transform(data_.begin(), data_.end(), rhs.data_.begin(), std::back_inserter(out),
171  [] (Type a, Type b) {
172  return a+b;
173  });
174  data_=std::move(out);
175  return *this;
176  }
177 
178  Matrix<Rows, Cols, Type>& operator-=(const Matrix<Rows, Cols, Type> &rhs)
179  {
180  std::vector<Type> out;
181  out.reserve(data_.size());
182  std::transform(data_.begin(), data_.end(), rhs.begin(), std::back_inserter(out),
183  [] (Type a, Type b) {
184  return a-b;
185  });
186  data_=std::move(out);
187  return *this;
188  }
189 };
190 
191 template<int M, int N, class T>
192 Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const Matrix<M, N, T> &rhs)
193 {
194  lhs+=rhs;
195  return lhs;
196 }
197 
198 template<int M, int N, class T>
199 Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const Matrix<M, N, T> &rhs)
200 {
201  lhs-=rhs;
202  return lhs;
203 }
204 
205 template<int M, int N, class T>
206 Matrix<M, N, T> operator+(Matrix<M, N, T> lhs, const T &rhs)
207 {
208  for(auto &data : lhs)
209  {
210  data+=rhs;
211  }
212  return lhs;
213 }
214 
215 template<int M, int N, class T>
216 Matrix<M, N, T> operator+(const T &lhs, Matrix<M, N, T> rhs)
217 {
218  for(auto &data : rhs)
219  {
220  data+=lhs;
221  }
222  return rhs;
223 }
224 
225 template<int M, int N, class T>
226 Matrix<M, N, T> operator-(Matrix<M, N, T> lhs, const T &rhs)
227 {
228  for(auto &data : lhs)
229  {
230  data-=rhs;
231  }
232  return lhs;
233 }
234 
235 template<int M, int N, class T>
236 Matrix<M, N, T> operator-(const T &lhs, Matrix<M, N, T> rhs)
237 {
238  for(auto &data : rhs)
239  {
240  data=lhs-data;
241  }
242  return rhs;
243 }
244 
245 template<int M, int N, class T>
246 Matrix<M, N, T> operator*(Matrix<M, N, T> lhs, const T &rhs)
247 {
248  for(auto &data : lhs)
249  {
250  data*=rhs;
251  }
252  return lhs;
253 }
254 
255 template<int M, int N, class T>
256 Matrix<M, N, T> operator*(const T &lhs, Matrix<M, N, T> rhs)
257 {
258  for(auto &data : rhs)
259  {
260  data*=lhs;
261  }
262  return rhs;
263 }
264 
265 template<int M, int N, class T>
266 Matrix<M, N, T> operator/(Matrix<M, N, T> lhs, const T &rhs)
267 {
268  for(auto &data : lhs)
269  {
270  data/=rhs;
271  }
272  return lhs;
273 }
274 
275 template<int M, int N, class T>
276 bool operator==(const Matrix<M, N, T> &lhs, const Matrix<M, N, T> &rhs)
277 {
278  for(int i=0; i<M; ++i)
279  for(int j=0; j<N; ++j)
280  if(lhs[i][j]!=rhs[i][j])
281  return false;
282  return true;
283 }
284 
285 template<int M, int N, class T>
286 std::ostream& operator<<(std::ostream &os, const Matrix<M, N, T> &mat)
287 {
288  return os<<mat.toString();
289 }
290 
291 template<int Rows=2, class Type=double> class Vector : public Matrix<Rows, 1, Type>
292 {
293 public:
295  explicit Vector<Rows, Type>(const Matrix<Rows, 1, Type> &other) : Matrix<Rows, 1, Type>(other) {}
296 
297  Type& operator[](int col)
298  {
299  return this->data_[col];
300  }
301 
302  const Type& operator[](int col) const
303  {
304  return this->data_[col];
305  }
306 
307  virtual std::string toString() const
308  {
309  std::stringstream ss;
310  ss<<"[";
311  for(std::size_t i=0; i<this->data_.size()-1; ++i)
312  {
313  ss<<this->data_[i]<<" ";
314  }
315  ss<<this->data_[this->data_.size()-1]<<"]";
316  return ss.str();
317  }
318 };
319 
320 template<class Type=double> class Vector2 : public Vector<2, Type>
321 {
322 public:
324 
325  Vector2<Type>(Type x, Type y)
326  {
327  this->data_[0]=x;
328  this->data_[1]=y;
329  }
330 
331  Vector2<Type>(const Matrix<2, 1, Type> &other) : Vector<2, Type>(other) {}
332 
333  Type& x()
334  {
335  return this->data_[0];
336  }
337 
338  const Type& x() const
339  {
340  return this->data_[0];
341  }
342 
343  Type& y()
344  {
345  return this->data_[1];
346  }
347 
348  const Type& y() const
349  {
350  return this->data_[1];
351  }
352 };
353 
354 typedef Vector2<double> Vector2d;
355 
356 namespace matrix
357 {
358 
359 template<int M, int N, class T> Matrix<N, M, T> transpose(const Matrix<M, N, T> &m)
360 {
361  Matrix<N, M, T> trans;
362  for(int i=0; i<M; ++i)
363  {
364  for(int j=0; j<N; ++j)
365  {
366  trans[j][i]=m[i][j];
367  }
368  }
369  return trans;
370 }
371 
372 template<int R, class T> T dot(const Matrix<R, 1, T> &m1, const Matrix<R, 1, T> &m2)
373 {
374  T sum=0;
375  for(int i=0; i<R; ++i)
376  {
377  sum += m1[i][0]*m2[i][0];
378  }
379  return sum;
380 }
381 
382 template<int M, int N, int P, int Q, class T>
383 Matrix<M, Q, T> multiply(const Matrix<M, N, T> &m1, const Matrix<P, Q, T> &m2)
384 {
385  if(N!=P)
386  {
387  throw std::runtime_error("Matrices don't have the right dimensions for multiplication");
388  }
389 
390  Matrix<M, Q, T> res;
391 
392  for(int i=0; i<M; ++i)
393  {
394  for(int j=0; j<Q; ++j)
395  {
396  res[i][j] = dot(transpose(m1.getRow(i)), m2.getCol(j));
397  }
398  }
399 
400  return res;
401 }
402 
403 } // matrix
404 
405 } // yage
406 
407 #endif
Definition: matrix.hpp:320
Definition: matrix.hpp:39
Definition: matrix.hpp:291
Definition: matrix.hpp:29
Definition: camera2d.hpp:17