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 | #ifndef QTRANSFORM_H |
4 | #define QTRANSFORM_H |
5 | |
6 | #include <QtGui/qtguiglobal.h> |
7 | #include <QtGui/qpolygon.h> |
8 | #include <QtGui/qregion.h> |
9 | #include <QtGui/qwindowdefs.h> |
10 | #include <QtCore/qline.h> |
11 | #include <QtCore/qpoint.h> |
12 | #include <QtCore/qrect.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | class QVariant; |
17 | class QPainterPath; |
18 | |
19 | class Q_GUI_EXPORT QTransform |
20 | { |
21 | public: |
22 | enum TransformationType { |
23 | TxNone = 0x00, |
24 | TxTranslate = 0x01, |
25 | TxScale = 0x02, |
26 | TxRotate = 0x04, |
27 | TxShear = 0x08, |
28 | TxProject = 0x10 |
29 | }; |
30 | |
31 | inline explicit QTransform(Qt::Initialization) {} |
32 | inline QTransform() |
33 | : m_matrix{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1} } |
34 | , m_type(TxNone) |
35 | , m_dirty(TxNone) {} |
36 | QTransform(qreal h11, qreal h12, qreal h13, |
37 | qreal h21, qreal h22, qreal h23, |
38 | qreal h31, qreal h32, qreal h33) |
39 | : m_matrix{ {h11, h12, h13}, {h21, h22, h23}, {h31, h32, h33} } |
40 | , m_type(TxNone) |
41 | , m_dirty(TxProject) {} |
42 | QTransform(qreal h11, qreal h12, qreal h21, |
43 | qreal h22, qreal dx, qreal dy) |
44 | : m_matrix{ {h11, h12, 0}, {h21, h22, 0}, {dx, dy, 1} } |
45 | , m_type(TxNone) |
46 | , m_dirty(TxShear) {} |
47 | |
48 | QTransform &operator=(QTransform &&other) noexcept = default; |
49 | QTransform &operator=(const QTransform &) noexcept = default; |
50 | QTransform(QTransform &&other) noexcept = default; |
51 | QTransform(const QTransform &other) noexcept = default; |
52 | |
53 | bool isAffine() const; |
54 | bool isIdentity() const; |
55 | bool isInvertible() const; |
56 | bool isScaling() const; |
57 | bool isRotating() const; |
58 | bool isTranslating() const; |
59 | |
60 | TransformationType type() const; |
61 | |
62 | inline qreal determinant() const; |
63 | |
64 | qreal m11() const; |
65 | qreal m12() const; |
66 | qreal m13() const; |
67 | qreal m21() const; |
68 | qreal m22() const; |
69 | qreal m23() const; |
70 | qreal m31() const; |
71 | qreal m32() const; |
72 | qreal m33() const; |
73 | qreal dx() const; |
74 | qreal dy() const; |
75 | |
76 | void setMatrix(qreal m11, qreal m12, qreal m13, |
77 | qreal m21, qreal m22, qreal m23, |
78 | qreal m31, qreal m32, qreal m33); |
79 | |
80 | [[nodiscard]] QTransform inverted(bool *invertible = nullptr) const; |
81 | [[nodiscard]] QTransform adjoint() const; |
82 | [[nodiscard]] QTransform transposed() const; |
83 | |
84 | QTransform &translate(qreal dx, qreal dy); |
85 | QTransform &scale(qreal sx, qreal sy); |
86 | QTransform &shear(qreal sh, qreal sv); |
87 | #if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) |
88 | QTransform &rotate(qreal a, Qt::Axis axis, qreal distanceToPlane); |
89 | // ### Qt7: Remove |
90 | QTransform &rotate(qreal a, Qt::Axis axis = Qt::ZAxis); |
91 | QTransform &rotateRadians(qreal a, Qt::Axis axis, qreal distanceToPlane); |
92 | // ### Qt7: Remove |
93 | QTransform &rotateRadians(qreal a, Qt::Axis axis = Qt::ZAxis); |
94 | #else |
95 | QTransform &rotate(qreal a, Qt::Axis axis = Qt::ZAxis, qreal distanceToPlane = 1024.0f); |
96 | QTransform &rotateRadians(qreal a, Qt::Axis axis = Qt::ZAxis, qreal distanceToPlane = 1024.0f); |
97 | #endif |
98 | |
99 | static bool squareToQuad(const QPolygonF &square, QTransform &result); |
100 | static bool quadToSquare(const QPolygonF &quad, QTransform &result); |
101 | static bool quadToQuad(const QPolygonF &one, |
102 | const QPolygonF &two, |
103 | QTransform &result); |
104 | |
105 | bool operator==(const QTransform &) const; |
106 | bool operator!=(const QTransform &) const; |
107 | |
108 | QTransform &operator*=(const QTransform &); |
109 | QTransform operator*(const QTransform &o) const; |
110 | |
111 | operator QVariant() const; |
112 | |
113 | void reset(); |
114 | QPoint map(const QPoint &p) const; |
115 | QPointF map(const QPointF &p) const; |
116 | QLine map(const QLine &l) const; |
117 | QLineF map(const QLineF &l) const; |
118 | QPolygonF map(const QPolygonF &a) const; |
119 | QPolygon map(const QPolygon &a) const; |
120 | QRegion map(const QRegion &r) const; |
121 | QPainterPath map(const QPainterPath &p) const; |
122 | QPolygon mapToPolygon(const QRect &r) const; |
123 | QRect mapRect(const QRect &) const; |
124 | QRectF mapRect(const QRectF &) const; |
125 | void map(int x, int y, int *tx, int *ty) const; |
126 | void map(qreal x, qreal y, qreal *tx, qreal *ty) const; |
127 | |
128 | QTransform &operator*=(qreal div); |
129 | QTransform &operator/=(qreal div); |
130 | QTransform &operator+=(qreal div); |
131 | QTransform &operator-=(qreal div); |
132 | |
133 | static QTransform fromTranslate(qreal dx, qreal dy); |
134 | static QTransform fromScale(qreal dx, qreal dy); |
135 | |
136 | private: |
137 | struct Affine { |
138 | qreal (& m_matrix)[3][3]; |
139 | }; |
140 | |
141 | public: |
142 | auto asAffineMatrix() { return Affine { .m_matrix: m_matrix }; } |
143 | friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &s, Affine &m); |
144 | friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &s, const Affine &m); |
145 | |
146 | private: |
147 | inline TransformationType inline_type() const; |
148 | qreal m_matrix[3][3]; |
149 | |
150 | mutable uint m_type : 5; |
151 | mutable uint m_dirty : 5; |
152 | }; |
153 | Q_DECLARE_TYPEINFO(QTransform, Q_RELOCATABLE_TYPE); |
154 | |
155 | Q_GUI_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(const QTransform &key, size_t seed = 0) noexcept; |
156 | |
157 | /******* inlines *****/ |
158 | inline QTransform::TransformationType QTransform::inline_type() const |
159 | { |
160 | if (m_dirty == TxNone) |
161 | return static_cast<TransformationType>(m_type); |
162 | return type(); |
163 | } |
164 | |
165 | inline bool QTransform::isAffine() const |
166 | { |
167 | return inline_type() < TxProject; |
168 | } |
169 | inline bool QTransform::isIdentity() const |
170 | { |
171 | return inline_type() == TxNone; |
172 | } |
173 | |
174 | inline bool QTransform::isInvertible() const |
175 | { |
176 | return !qFuzzyIsNull(d: determinant()); |
177 | } |
178 | |
179 | inline bool QTransform::isScaling() const |
180 | { |
181 | return type() >= TxScale; |
182 | } |
183 | inline bool QTransform::isRotating() const |
184 | { |
185 | return inline_type() >= TxRotate; |
186 | } |
187 | |
188 | inline bool QTransform::isTranslating() const |
189 | { |
190 | return inline_type() >= TxTranslate; |
191 | } |
192 | |
193 | inline qreal QTransform::determinant() const |
194 | { |
195 | return m_matrix[0][0] * (m_matrix[2][2] * m_matrix[1][1] - m_matrix[2][1] * m_matrix[1][2]) - |
196 | m_matrix[1][0] * (m_matrix[2][2] * m_matrix[0][1] - m_matrix[2][1] * m_matrix[0][2]) + |
197 | m_matrix[2][0] * (m_matrix[1][2] * m_matrix[0][1] - m_matrix[1][1] * m_matrix[0][2]); |
198 | } |
199 | inline qreal QTransform::m11() const |
200 | { |
201 | return m_matrix[0][0]; |
202 | } |
203 | inline qreal QTransform::m12() const |
204 | { |
205 | return m_matrix[0][1]; |
206 | } |
207 | inline qreal QTransform::m13() const |
208 | { |
209 | return m_matrix[0][2]; |
210 | } |
211 | inline qreal QTransform::m21() const |
212 | { |
213 | return m_matrix[1][0]; |
214 | } |
215 | inline qreal QTransform::m22() const |
216 | { |
217 | return m_matrix[1][1]; |
218 | } |
219 | inline qreal QTransform::m23() const |
220 | { |
221 | return m_matrix[1][2]; |
222 | } |
223 | inline qreal QTransform::m31() const |
224 | { |
225 | return m_matrix[2][0]; |
226 | } |
227 | inline qreal QTransform::m32() const |
228 | { |
229 | return m_matrix[2][1]; |
230 | } |
231 | inline qreal QTransform::m33() const |
232 | { |
233 | return m_matrix[2][2]; |
234 | } |
235 | inline qreal QTransform::dx() const |
236 | { |
237 | return m_matrix[2][0]; |
238 | } |
239 | inline qreal QTransform::dy() const |
240 | { |
241 | return m_matrix[2][1]; |
242 | } |
243 | |
244 | QT_WARNING_PUSH |
245 | QT_WARNING_DISABLE_FLOAT_COMPARE |
246 | |
247 | inline QTransform &QTransform::operator*=(qreal num) |
248 | { |
249 | if (num == 1.) |
250 | return *this; |
251 | m_matrix[0][0] *= num; |
252 | m_matrix[0][1] *= num; |
253 | m_matrix[0][2] *= num; |
254 | m_matrix[1][0] *= num; |
255 | m_matrix[1][1] *= num; |
256 | m_matrix[1][2] *= num; |
257 | m_matrix[2][0] *= num; |
258 | m_matrix[2][1] *= num; |
259 | m_matrix[2][2] *= num; |
260 | if (m_dirty < TxScale) |
261 | m_dirty = TxScale; |
262 | return *this; |
263 | } |
264 | inline QTransform &QTransform::operator/=(qreal div) |
265 | { |
266 | if (div == 0) |
267 | return *this; |
268 | div = 1/div; |
269 | return operator*=(num: div); |
270 | } |
271 | inline QTransform &QTransform::operator+=(qreal num) |
272 | { |
273 | if (num == 0) |
274 | return *this; |
275 | m_matrix[0][0] += num; |
276 | m_matrix[0][1] += num; |
277 | m_matrix[0][2] += num; |
278 | m_matrix[1][0] += num; |
279 | m_matrix[1][1] += num; |
280 | m_matrix[1][2] += num; |
281 | m_matrix[2][0] += num; |
282 | m_matrix[2][1] += num; |
283 | m_matrix[2][2] += num; |
284 | m_dirty = TxProject; |
285 | return *this; |
286 | } |
287 | inline QTransform &QTransform::operator-=(qreal num) |
288 | { |
289 | if (num == 0) |
290 | return *this; |
291 | m_matrix[0][0] -= num; |
292 | m_matrix[0][1] -= num; |
293 | m_matrix[0][2] -= num; |
294 | m_matrix[1][0] -= num; |
295 | m_matrix[1][1] -= num; |
296 | m_matrix[1][2] -= num; |
297 | m_matrix[2][0] -= num; |
298 | m_matrix[2][1] -= num; |
299 | m_matrix[2][2] -= num; |
300 | m_dirty = TxProject; |
301 | return *this; |
302 | } |
303 | |
304 | QT_WARNING_POP |
305 | |
306 | inline bool qFuzzyCompare(const QTransform& t1, const QTransform& t2) |
307 | { |
308 | return qFuzzyCompare(p1: t1.m11(), p2: t2.m11()) |
309 | && qFuzzyCompare(p1: t1.m12(), p2: t2.m12()) |
310 | && qFuzzyCompare(p1: t1.m13(), p2: t2.m13()) |
311 | && qFuzzyCompare(p1: t1.m21(), p2: t2.m21()) |
312 | && qFuzzyCompare(p1: t1.m22(), p2: t2.m22()) |
313 | && qFuzzyCompare(p1: t1.m23(), p2: t2.m23()) |
314 | && qFuzzyCompare(p1: t1.m31(), p2: t2.m31()) |
315 | && qFuzzyCompare(p1: t1.m32(), p2: t2.m32()) |
316 | && qFuzzyCompare(p1: t1.m33(), p2: t2.m33()); |
317 | } |
318 | |
319 | |
320 | /****** stream functions *******************/ |
321 | #ifndef QT_NO_DATASTREAM |
322 | Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QTransform &); |
323 | Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QTransform &); |
324 | #endif |
325 | |
326 | #ifndef QT_NO_DEBUG_STREAM |
327 | Q_GUI_EXPORT QDebug operator<<(QDebug, const QTransform &); |
328 | #endif |
329 | /****** end stream functions *******************/ |
330 | |
331 | // mathematical semantics |
332 | inline QPoint operator*(const QPoint &p, const QTransform &m) |
333 | { return m.map(p); } |
334 | inline QPointF operator*(const QPointF &p, const QTransform &m) |
335 | { return m.map(p); } |
336 | inline QLineF operator*(const QLineF &l, const QTransform &m) |
337 | { return m.map(l); } |
338 | inline QLine operator*(const QLine &l, const QTransform &m) |
339 | { return m.map(l); } |
340 | inline QPolygon operator *(const QPolygon &a, const QTransform &m) |
341 | { return m.map(a); } |
342 | inline QPolygonF operator *(const QPolygonF &a, const QTransform &m) |
343 | { return m.map(a); } |
344 | inline QRegion operator *(const QRegion &r, const QTransform &m) |
345 | { return m.map(r); } |
346 | |
347 | inline QTransform operator *(const QTransform &a, qreal n) |
348 | { QTransform t(a); t *= n; return t; } |
349 | inline QTransform operator /(const QTransform &a, qreal n) |
350 | { QTransform t(a); t /= n; return t; } |
351 | inline QTransform operator +(const QTransform &a, qreal n) |
352 | { QTransform t(a); t += n; return t; } |
353 | inline QTransform operator -(const QTransform &a, qreal n) |
354 | { QTransform t(a); t -= n; return t; } |
355 | |
356 | QT_END_NAMESPACE |
357 | |
358 | #endif // QTRANSFORM_H |
359 | |