1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QGENERICMATRIX_H
5#define QGENERICMATRIX_H
6
7#include <QtGui/qtguiglobal.h>
8#include <QtCore/qmetatype.h>
9#include <QtCore/qdebug.h>
10#include <QtCore/qdatastream.h>
11
12QT_BEGIN_NAMESPACE
13
14
15template <int N, int M, typename T>
16class QGenericMatrix
17{
18public:
19 QGenericMatrix();
20 explicit QGenericMatrix(Qt::Initialization) {}
21 explicit QGenericMatrix(const T *values);
22
23 const T& operator()(int row, int column) const;
24 T& operator()(int row, int column);
25
26 bool isIdentity() const;
27 void setToIdentity();
28
29 void fill(T value);
30
31 [[nodiscard]] QGenericMatrix<M, N, T> transposed() const;
32
33 QGenericMatrix<N, M, T>& operator+=(const QGenericMatrix<N, M, T>& other);
34 QGenericMatrix<N, M, T>& operator-=(const QGenericMatrix<N, M, T>& other);
35 QGenericMatrix<N, M, T>& operator*=(T factor);
36 QGenericMatrix<N, M, T>& operator/=(T divisor);
37 bool operator==(const QGenericMatrix<N, M, T>& other) const;
38 bool operator!=(const QGenericMatrix<N, M, T>& other) const;
39
40 void copyDataTo(T *values) const;
41
42 T *data() { return *m; }
43 const T *data() const { return *m; }
44 const T *constData() const { return *m; }
45
46 template<int NN, int MM, typename TT>
47 friend QGenericMatrix<NN, MM, TT> operator+(const QGenericMatrix<NN, MM, TT>& m1, const QGenericMatrix<NN, MM, TT>& m2);
48 template<int NN, int MM, typename TT>
49 friend QGenericMatrix<NN, MM, TT> operator-(const QGenericMatrix<NN, MM, TT>& m1, const QGenericMatrix<NN, MM, TT>& m2);
50 template<int NN, int M1, int M2, typename TT>
51 friend QGenericMatrix<M1, M2, TT> operator*(const QGenericMatrix<NN, M2, TT>& m1, const QGenericMatrix<M1, NN, TT>& m2);
52 template<int NN, int MM, typename TT>
53 friend QGenericMatrix<NN, MM, TT> operator-(const QGenericMatrix<NN, MM, TT>& matrix);
54 template<int NN, int MM, typename TT>
55 friend QGenericMatrix<NN, MM, TT> operator*(TT factor, const QGenericMatrix<NN, MM, TT>& matrix);
56 template<int NN, int MM, typename TT>
57 friend QGenericMatrix<NN, MM, TT> operator*(const QGenericMatrix<NN, MM, TT>& matrix, TT factor);
58 template<int NN, int MM, typename TT>
59 friend QGenericMatrix<NN, MM, TT> operator/(const QGenericMatrix<NN, MM, TT>& matrix, TT divisor);
60
61private:
62 T m[N][M]; // Column-major order to match OpenGL.
63
64 template <int NN, int MM, typename TT>
65 friend class QGenericMatrix;
66};
67template <int N, int M, typename T>
68class QTypeInfo<QGenericMatrix<N, M, T> >
69 : public QTypeInfoMerger<QGenericMatrix<N, M, T>, T>
70{
71};
72
73template <int N, int M, typename T>
74Q_INLINE_TEMPLATE QGenericMatrix<N, M, T>::QGenericMatrix()
75{
76 setToIdentity();
77}
78
79template <int N, int M, typename T>
80Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>::QGenericMatrix(const T *values)
81{
82 for (int col = 0; col < N; ++col)
83 for (int row = 0; row < M; ++row)
84 m[col][row] = values[row * N + col];
85}
86
87template <int N, int M, typename T>
88Q_INLINE_TEMPLATE const T& QGenericMatrix<N, M, T>::operator()(int row, int column) const
89{
90 Q_ASSERT(row >= 0 && row < M && column >= 0 && column < N);
91 return m[column][row];
92}
93
94template <int N, int M, typename T>
95Q_INLINE_TEMPLATE T& QGenericMatrix<N, M, T>::operator()(int row, int column)
96{
97 Q_ASSERT(row >= 0 && row < M && column >= 0 && column < N);
98 return m[column][row];
99}
100
101template <int N, int M, typename T>
102Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::isIdentity() const
103{
104 for (int col = 0; col < N; ++col) {
105 for (int row = 0; row < M; ++row) {
106 if (row == col) {
107 if (m[col][row] != 1.0f)
108 return false;
109 } else {
110 if (m[col][row] != 0.0f)
111 return false;
112 }
113 }
114 }
115 return true;
116}
117
118template <int N, int M, typename T>
119Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::setToIdentity()
120{
121 for (int col = 0; col < N; ++col) {
122 for (int row = 0; row < M; ++row) {
123 if (row == col)
124 m[col][row] = 1.0f;
125 else
126 m[col][row] = 0.0f;
127 }
128 }
129}
130
131template <int N, int M, typename T>
132Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::fill(T value)
133{
134 for (int col = 0; col < N; ++col)
135 for (int row = 0; row < M; ++row)
136 m[col][row] = value;
137}
138
139template <int N, int M, typename T>
140Q_OUTOFLINE_TEMPLATE QGenericMatrix<M, N, T> QGenericMatrix<N, M, T>::transposed() const
141{
142 QGenericMatrix<M, N, T> result(Qt::Uninitialized);
143 for (int row = 0; row < M; ++row)
144 for (int col = 0; col < N; ++col)
145 result.m[row][col] = m[col][row];
146 return result;
147}
148
149template <int N, int M, typename T>
150Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator+=(const QGenericMatrix<N, M, T>& other)
151{
152 for (int row = 0; row < M; ++row)
153 for (int col = 0; col < N; ++col)
154 m[col][row] += other.m[col][row];
155 return *this;
156}
157
158template <int N, int M, typename T>
159Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator-=(const QGenericMatrix<N, M, T>& other)
160{
161 for (int row = 0; row < M; ++row)
162 for (int col = 0; col < N; ++col)
163 m[col][row] -= other.m[col][row];
164 return *this;
165}
166
167template <int N, int M, typename T>
168Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator*=(T factor)
169{
170 for (int row = 0; row < M; ++row)
171 for (int col = 0; col < N; ++col)
172 m[col][row] *= factor;
173 return *this;
174}
175
176QT_WARNING_PUSH
177QT_WARNING_DISABLE_FLOAT_COMPARE
178
179template <int N, int M, typename T>
180Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::operator==(const QGenericMatrix<N, M, T>& other) const
181{
182 for (int row = 0; row < M; ++row)
183 for (int col = 0; col < N; ++col) {
184 if (m[col][row] != other.m[col][row])
185 return false;
186 }
187 return true;
188}
189
190template <int N, int M, typename T>
191Q_OUTOFLINE_TEMPLATE bool QGenericMatrix<N, M, T>::operator!=(const QGenericMatrix<N, M, T>& other) const
192{
193 return !(*this == other);
194}
195
196QT_WARNING_POP
197
198template <int N, int M, typename T>
199Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T>& QGenericMatrix<N, M, T>::operator/=(T divisor)
200{
201 for (int row = 0; row < M; ++row)
202 for (int col = 0; col < N; ++col)
203 m[col][row] /= divisor;
204 return *this;
205}
206
207template <int N, int M, typename T>
208Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator+(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
209{
210 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
211 for (int row = 0; row < M; ++row)
212 for (int col = 0; col < N; ++col)
213 result.m[col][row] = m1.m[col][row] + m2.m[col][row];
214 return result;
215}
216
217template <int N, int M, typename T>
218Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& m1, const QGenericMatrix<N, M, T>& m2)
219{
220 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
221 for (int row = 0; row < M; ++row)
222 for (int col = 0; col < N; ++col)
223 result.m[col][row] = m1.m[col][row] - m2.m[col][row];
224 return result;
225}
226
227template <int N, int M1, int M2, typename T>
228Q_OUTOFLINE_TEMPLATE QGenericMatrix<M1, M2, T> operator*(const QGenericMatrix<N, M2, T>& m1, const QGenericMatrix<M1, N, T>& m2)
229{
230 QGenericMatrix<M1, M2, T> result(Qt::Uninitialized);
231 for (int row = 0; row < M2; ++row) {
232 for (int col = 0; col < M1; ++col) {
233 T sum(0.0f);
234 for (int j = 0; j < N; ++j)
235 sum += m1.m[j][row] * m2.m[col][j];
236 result.m[col][row] = sum;
237 }
238 }
239 return result;
240}
241
242template <int N, int M, typename T>
243Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator-(const QGenericMatrix<N, M, T>& matrix)
244{
245 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
246 for (int row = 0; row < M; ++row)
247 for (int col = 0; col < N; ++col)
248 result.m[col][row] = -matrix.m[col][row];
249 return result;
250}
251
252template <int N, int M, typename T>
253Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator*(T factor, const QGenericMatrix<N, M, T>& matrix)
254{
255 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
256 for (int row = 0; row < M; ++row)
257 for (int col = 0; col < N; ++col)
258 result.m[col][row] = matrix.m[col][row] * factor;
259 return result;
260}
261
262template <int N, int M, typename T>
263Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator*(const QGenericMatrix<N, M, T>& matrix, T factor)
264{
265 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
266 for (int row = 0; row < M; ++row)
267 for (int col = 0; col < N; ++col)
268 result.m[col][row] = matrix.m[col][row] * factor;
269 return result;
270}
271
272template <int N, int M, typename T>
273Q_OUTOFLINE_TEMPLATE QGenericMatrix<N, M, T> operator/(const QGenericMatrix<N, M, T>& matrix, T divisor)
274{
275 QGenericMatrix<N, M, T> result(Qt::Uninitialized);
276 for (int row = 0; row < M; ++row)
277 for (int col = 0; col < N; ++col)
278 result.m[col][row] = matrix.m[col][row] / divisor;
279 return result;
280}
281
282template <int N, int M, typename T>
283Q_OUTOFLINE_TEMPLATE void QGenericMatrix<N, M, T>::copyDataTo(T *values) const
284{
285 for (int col = 0; col < N; ++col)
286 for (int row = 0; row < M; ++row)
287 values[row * N + col] = T(m[col][row]);
288}
289
290// Define aliases for the useful variants of QGenericMatrix.
291typedef QGenericMatrix<2, 2, float> QMatrix2x2;
292typedef QGenericMatrix<2, 3, float> QMatrix2x3;
293typedef QGenericMatrix<2, 4, float> QMatrix2x4;
294typedef QGenericMatrix<3, 2, float> QMatrix3x2;
295typedef QGenericMatrix<3, 3, float> QMatrix3x3;
296typedef QGenericMatrix<3, 4, float> QMatrix3x4;
297typedef QGenericMatrix<4, 2, float> QMatrix4x2;
298typedef QGenericMatrix<4, 3, float> QMatrix4x3;
299
300#ifndef QT_NO_DEBUG_STREAM
301
302template <int N, int M, typename T>
303QDebug operator<<(QDebug dbg, const QGenericMatrix<N, M, T> &m)
304{
305 QDebugStateSaver saver(dbg);
306 dbg.nospace() << "QGenericMatrix<" << N << ", " << M
307 << ", " << QMetaType::fromType<T>().name()
308 << ">(" << Qt::endl << qSetFieldWidth(width: 10);
309 for (int row = 0; row < M; ++row) {
310 for (int col = 0; col < N; ++col)
311 dbg << m(row, col);
312 dbg << Qt::endl;
313 }
314 dbg << qSetFieldWidth(width: 0) << ')';
315 return dbg;
316}
317
318#endif
319
320#ifndef QT_NO_DATASTREAM
321
322template <int N, int M, typename T>
323QDataStream &operator<<(QDataStream &stream, const QGenericMatrix<N, M, T> &matrix)
324{
325 for (int row = 0; row < M; ++row)
326 for (int col = 0; col < N; ++col)
327 stream << double(matrix(row, col));
328 return stream;
329}
330
331template <int N, int M, typename T>
332QDataStream &operator>>(QDataStream &stream, QGenericMatrix<N, M, T> &matrix)
333{
334 double x;
335 for (int row = 0; row < M; ++row) {
336 for (int col = 0; col < N; ++col) {
337 stream >> x;
338 matrix(row, col) = T(x);
339 }
340 }
341 return stream;
342}
343
344#endif
345
346QT_END_NAMESPACE
347
348QT_DECL_METATYPE_EXTERN(QMatrix2x2, Q_GUI_EXPORT)
349QT_DECL_METATYPE_EXTERN(QMatrix2x3, Q_GUI_EXPORT)
350QT_DECL_METATYPE_EXTERN(QMatrix2x4, Q_GUI_EXPORT)
351QT_DECL_METATYPE_EXTERN(QMatrix3x2, Q_GUI_EXPORT)
352QT_DECL_METATYPE_EXTERN(QMatrix3x3, Q_GUI_EXPORT)
353QT_DECL_METATYPE_EXTERN(QMatrix3x4, Q_GUI_EXPORT)
354QT_DECL_METATYPE_EXTERN(QMatrix4x2, Q_GUI_EXPORT)
355QT_DECL_METATYPE_EXTERN(QMatrix4x3, Q_GUI_EXPORT)
356
357#endif
358

source code of qtbase/src/gui/math3d/qgenericmatrix.h