1/*
2 * Copyright (c) 2010-2017 OTClient <https://github.com/edubart/otclient>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#ifndef MATRIX_H
24#define MATRIX_H
25
26#include <array>
27#include <cstring>
28#include <initializer_list>
29#include <sstream>
30
31template<int N, int M, typename T = float>
32class Matrix
33{
34public:
35 Matrix() { setIdentity(); }
36 Matrix(int) {} // construct without initializing identity matrix
37 Matrix(const Matrix<N,M,T>& other) = default;
38 template<typename U>
39 Matrix(const std::initializer_list<U>& values) { *this = values; }
40 template<typename U>
41 Matrix(const U *values) { *this = values; }
42
43 void setIdentity();
44 bool isIdentity() const;
45 void fill(T value);
46
47 Matrix<M,N,T> transposed() const;
48 typename std::enable_if<N==M>::type transpose() { *this = transposed(); }
49
50 T *data() { return m[0]; }
51 const T *data() const { return m[0]; }
52
53 T& operator()(int row, int column) { return m[row-1][column-1]; }
54 T operator()(int row, int column) const { return m[row-1][column-1]; }
55
56 Matrix<N,M,T>& operator=(const Matrix<N,M,T>& other) = default;
57 template<typename U>
58 Matrix<N,M,T>& operator=(const std::initializer_list<U>& values);
59 template<typename U>
60 Matrix<N,M,T>& operator=(const U *values);
61 Matrix<N,M,T>& operator+=(const Matrix<N,M,T>& other);
62 Matrix<N,M,T>& operator-=(const Matrix<N,M,T>& other);
63 Matrix<N,M,T>& operator*=(T factor);
64 Matrix<N,M,T>& operator/=(T divisor);
65 bool operator==(const Matrix<N,M,T>& other) const;
66 bool operator!=(const Matrix<N,M,T>& other) const;
67
68private:
69 T m[N][M];
70};
71
72template<int N, int M, typename T>
73void Matrix<N,M,T>::setIdentity() {
74 for(int i=0;i<N;++i) {
75 for(int j=0;j<M;++j) {
76 if(i==j)
77 m[i][j] = 1.0f;
78 else
79 m[i][j] = 0.0f;
80 }
81 }
82}
83
84template<int N, int M, typename T>
85bool Matrix<N,M,T>::isIdentity() const {
86 for(int i=0;i<N;++i)
87 for(int j=0;j<M;++j)
88 if((i==j && m[i][j] != 1.0f) || (i!=j && m[i][j] != 0.0f))
89 return false;
90 return true;
91}
92
93template<int N, int M, typename T>
94void Matrix<N,M,T>::fill(T value) {
95 for(int i=0;i<N;++i)
96 for(int j=0;j<M;++j)
97 m[i][j] = value;
98}
99
100template<int N, int M, typename T>
101Matrix<M,N,T> Matrix<N,M,T>::transposed() const {
102 Matrix<M,N,T> result(1);
103 for(int i=0;i<N;++i)
104 for(int j=0;j<M;++j)
105 result.m[j][i] = m[i][j];
106 return result;
107}
108
109template<int N, int M, typename T>
110template<typename U>
111Matrix<N,M,T>& Matrix<N,M,T>::operator=(const std::initializer_list<U>& values) {
112 auto it = values.begin();
113 for(int i=0;i<N;++i)
114 for(int j=0;j<M;++j)
115 m[i][j] = *(it++);
116 return *this;
117}
118
119template<int N, int M, typename T>
120template<typename U>
121Matrix<N,M,T>& Matrix<N,M,T>::operator=(const U *values) {
122 for(int i=0;i<N;++i)
123 for(int j=0;j<M;++j)
124 m[i][j] = values[i*N + j];
125 return *this;
126}
127
128template<int N, int M, typename T>
129Matrix<N,M,T>& Matrix<N,M,T>::operator+=(const Matrix<N,M,T>& other) {
130 for(int i=0;i<N;++i)
131 for(int j=0;j<M;++j)
132 m[i][j] += other.m[i][j];
133 return *this;
134}
135
136template<int N, int M, typename T>
137Matrix<N,M,T>& Matrix<N,M,T>::operator-=(const Matrix<N,M,T>& other) {
138 for(int i=0;i<N;++i)
139 for(int j=0;j<M;++j)
140 m[i][j] -= other.m[i][j];
141 return *this;
142}
143
144template<int N, int M, typename T>
145Matrix<N,M,T>& Matrix<N,M,T>::operator*=(T factor) {
146 for(int i=0;i<N;++i)
147 for(int j=0;j<M;++j)
148 m[i][j] *= factor;
149 return *this;
150}
151
152template<int N, int M, typename T>
153Matrix<N,M,T>& Matrix<N,M,T>::operator/=(T divisor) {
154 for(int i=0;i<N;++i)
155 for(int j=0;j<M;++j)
156 m[i][j] /= divisor;
157 return *this;
158}
159
160template<int N, int M, typename T>
161bool Matrix<N,M,T>::operator==(const Matrix<N,M,T>& other) const
162{
163 for(int i=0;i<N;++i)
164 for(int j=0;j<M;++j)
165 if(m[i][j] != other.m[i][j])
166 return false;
167 return true;
168}
169
170template<int N, int M, typename T>
171bool Matrix<N,M,T>::operator!=(const Matrix<N,M,T>& other) const
172{
173 return !(*this == other);
174}
175
176template<int N, int M, typename T>
177std::ostream& operator<<(std::ostream& out, const Matrix<N,M,T>& mat)
178{
179 for(int i=1;i<=N;++i) {
180 for(int j=1;j<=M;++j) {
181 out << mat(i,j);
182 if(j != M)
183 out << " ";
184 }
185 out << "\n";
186 }
187 return out;
188}
189
190template<int N, int M, typename T>
191std::istream& operator>>(std::istream& in, Matrix<N,M,T>& mat)
192{
193 for(int i=0;i<N;++i)
194 for(int j=0;j<M;++j)
195 in >> mat(i,j);
196 return in;
197}
198
199// faster comparing for 3x3 matrixes
200template<>
201inline bool Matrix<3,3,float>::operator==(const Matrix<3,3,float>& other) const
202{
203 return m[0][0] == other.m[0][0] && m[1][1] == other.m[1][1] &&
204 m[2][1] == other.m[2][1] && m[2][0] == other.m[2][0] &&
205 m[1][2] == other.m[1][2] && m[0][2] == other.m[0][2] &&
206 m[1][0] == other.m[1][0] && m[0][1] == other.m[0][1] &&
207 m[2][2] == other.m[2][2];
208}
209
210template<int M, int N, int P, int Q, typename T>
211Matrix<M, Q, T> operator*(const Matrix<M,N,T>& a, const Matrix<P,Q,T>& b)
212{
213 static_assert(N==P, "N==P");
214 Matrix<M,Q,T> c(1);
215 for(int i=1;i<=M;++i) {
216 for(int j=1;j<=Q;++j) {
217 T sum = 0;
218 for(int k=1;k<=N;++k)
219 sum += a(i,k) * b(k,j);
220 c(i,j) = sum;
221 }
222 }
223 return c;
224}
225
226template<int M, int N, typename T>
227Matrix<M, N, T> operator+(const Matrix<M,N,T>& a, const Matrix<M,N,T>& b) { Matrix<M,N,T> c(a); c += b; return c; }
228
229template<int M, int N, typename T>
230Matrix<M, N, T> operator-(const Matrix<M,N,T>& a, const Matrix<M,N,T>& b) { Matrix<M,N,T> c(a); c -= b; return c; }
231
232template<int M, int N, typename T>
233Matrix<M, N, T> operator*(const Matrix<M,N,T>& a, float b) { Matrix<M,N,T> c(a); c *= b; return c; }
234
235template<int M, int N, typename T>
236Matrix<M, N, T> operator/(const Matrix<M,N,T>& a, float b) { Matrix<M,N,T> c = a; c /= b; return c; }
237
238typedef Matrix<4,4> Matrix4x4;
239typedef Matrix<3,3> Matrix3x3;
240typedef Matrix<2,2> Matrix2x2;
241
242typedef Matrix4x4 Matrix4;
243typedef Matrix3x3 Matrix3;
244typedef Matrix2x2 Matrix2;
245
246#endif
247