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