1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | #ifndef QTRANSFORM_H |
40 | #define QTRANSFORM_H |
41 | |
42 | #include <QtGui/qtguiglobal.h> |
43 | #include <QtGui/qpolygon.h> |
44 | #include <QtGui/qregion.h> |
45 | #include <QtGui/qwindowdefs.h> |
46 | #include <QtCore/qline.h> |
47 | #include <QtCore/qpoint.h> |
48 | #include <QtCore/qrect.h> |
49 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | class QVariant; |
53 | class QPainterPath; |
54 | |
55 | class Q_GUI_EXPORT QTransform |
56 | { |
57 | public: |
58 | enum TransformationType { |
59 | TxNone = 0x00, |
60 | TxTranslate = 0x01, |
61 | TxScale = 0x02, |
62 | TxRotate = 0x04, |
63 | TxShear = 0x08, |
64 | TxProject = 0x10 |
65 | }; |
66 | |
67 | inline explicit QTransform(Qt::Initialization) {} |
68 | inline QTransform() |
69 | : m_matrix{ {1, 0, 0}, {0, 1, 0}, {0, 0, 1} } |
70 | , m_type(TxNone) |
71 | , m_dirty(TxNone) {} |
72 | QTransform(qreal h11, qreal h12, qreal h13, |
73 | qreal h21, qreal h22, qreal h23, |
74 | qreal h31, qreal h32, qreal h33) |
75 | : m_matrix{ {h11, h12, h13}, {h21, h22, h23}, {h31, h32, h33} } |
76 | , m_type(TxNone) |
77 | , m_dirty(TxProject) {} |
78 | QTransform(qreal h11, qreal h12, qreal h21, |
79 | qreal h22, qreal dx, qreal dy) |
80 | : m_matrix{ {h11, h12, 0}, {h21, h22, 0}, {dx, dy, 1} } |
81 | , m_type(TxNone) |
82 | , m_dirty(TxShear) {} |
83 | |
84 | QTransform &operator=(QTransform &&other) noexcept = default; |
85 | QTransform &operator=(const QTransform &) noexcept = default; |
86 | QTransform(QTransform &&other) noexcept = default; |
87 | QTransform(const QTransform &other) noexcept = default; |
88 | |
89 | bool isAffine() const; |
90 | bool isIdentity() const; |
91 | bool isInvertible() const; |
92 | bool isScaling() const; |
93 | bool isRotating() const; |
94 | bool isTranslating() const; |
95 | |
96 | TransformationType type() const; |
97 | |
98 | inline qreal determinant() const; |
99 | |
100 | qreal m11() const; |
101 | qreal m12() const; |
102 | qreal m13() const; |
103 | qreal m21() const; |
104 | qreal m22() const; |
105 | qreal m23() const; |
106 | qreal m31() const; |
107 | qreal m32() const; |
108 | qreal m33() const; |
109 | qreal dx() const; |
110 | qreal dy() const; |
111 | |
112 | void setMatrix(qreal m11, qreal m12, qreal m13, |
113 | qreal m21, qreal m22, qreal m23, |
114 | qreal m31, qreal m32, qreal m33); |
115 | |
116 | [[nodiscard]] QTransform inverted(bool *invertible = nullptr) const; |
117 | [[nodiscard]] QTransform adjoint() const; |
118 | [[nodiscard]] QTransform transposed() const; |
119 | |
120 | QTransform &translate(qreal dx, qreal dy); |
121 | QTransform &scale(qreal sx, qreal sy); |
122 | QTransform &shear(qreal sh, qreal sv); |
123 | QTransform &rotate(qreal a, Qt::Axis axis = Qt::ZAxis); |
124 | QTransform &rotateRadians(qreal a, Qt::Axis axis = Qt::ZAxis); |
125 | |
126 | static bool squareToQuad(const QPolygonF &square, QTransform &result); |
127 | static bool quadToSquare(const QPolygonF &quad, QTransform &result); |
128 | static bool quadToQuad(const QPolygonF &one, |
129 | const QPolygonF &two, |
130 | QTransform &result); |
131 | |
132 | bool operator==(const QTransform &) const; |
133 | bool operator!=(const QTransform &) const; |
134 | |
135 | QTransform &operator*=(const QTransform &); |
136 | QTransform operator*(const QTransform &o) const; |
137 | |
138 | operator QVariant() const; |
139 | |
140 | void reset(); |
141 | QPoint map(const QPoint &p) const; |
142 | QPointF map(const QPointF &p) const; |
143 | QLine map(const QLine &l) const; |
144 | QLineF map(const QLineF &l) const; |
145 | QPolygonF map(const QPolygonF &a) const; |
146 | QPolygon map(const QPolygon &a) const; |
147 | QRegion map(const QRegion &r) const; |
148 | QPainterPath map(const QPainterPath &p) const; |
149 | QPolygon mapToPolygon(const QRect &r) const; |
150 | QRect mapRect(const QRect &) const; |
151 | QRectF mapRect(const QRectF &) const; |
152 | void map(int x, int y, int *tx, int *ty) const; |
153 | void map(qreal x, qreal y, qreal *tx, qreal *ty) const; |
154 | |
155 | QTransform &operator*=(qreal div); |
156 | QTransform &operator/=(qreal div); |
157 | QTransform &operator+=(qreal div); |
158 | QTransform &operator-=(qreal div); |
159 | |
160 | static QTransform fromTranslate(qreal dx, qreal dy); |
161 | static QTransform fromScale(qreal dx, qreal dy); |
162 | |
163 | private: |
164 | struct Affine { |
165 | qreal (& m_matrix)[3][3]; |
166 | }; |
167 | |
168 | public: |
169 | auto asAffineMatrix() { return Affine { m_matrix }; } |
170 | friend Q_GUI_EXPORT QDataStream &operator>>(QDataStream &s, Affine &m); |
171 | friend Q_GUI_EXPORT QDataStream &operator<<(QDataStream &s, const Affine &m); |
172 | |
173 | private: |
174 | inline TransformationType inline_type() const; |
175 | qreal m_matrix[3][3]; |
176 | |
177 | mutable uint m_type : 5; |
178 | mutable uint m_dirty : 5; |
179 | }; |
180 | Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE); |
181 | |
182 | Q_GUI_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(const QTransform &key, size_t seed = 0) noexcept; |
183 | |
184 | /******* inlines *****/ |
185 | inline QTransform::TransformationType QTransform::inline_type() const |
186 | { |
187 | if (m_dirty == TxNone) |
188 | return static_cast<TransformationType>(m_type); |
189 | return type(); |
190 | } |
191 | |
192 | inline bool QTransform::isAffine() const |
193 | { |
194 | return inline_type() < TxProject; |
195 | } |
196 | inline bool QTransform::isIdentity() const |
197 | { |
198 | return inline_type() == TxNone; |
199 | } |
200 | |
201 | inline bool QTransform::isInvertible() const |
202 | { |
203 | return !qFuzzyIsNull(determinant()); |
204 | } |
205 | |
206 | inline bool QTransform::isScaling() const |
207 | { |
208 | return type() >= TxScale; |
209 | } |
210 | inline bool QTransform::isRotating() const |
211 | { |
212 | return inline_type() >= TxRotate; |
213 | } |
214 | |
215 | inline bool QTransform::isTranslating() const |
216 | { |
217 | return inline_type() >= TxTranslate; |
218 | } |
219 | |
220 | inline qreal QTransform::determinant() const |
221 | { |
222 | return m_matrix[0][0] * (m_matrix[2][2] * m_matrix[1][1] - m_matrix[2][1] * m_matrix[1][2]) - |
223 | m_matrix[1][0] * (m_matrix[2][2] * m_matrix[0][1] - m_matrix[2][1] * m_matrix[0][2]) + |
224 | m_matrix[2][0] * (m_matrix[1][2] * m_matrix[0][1] - m_matrix[1][1] * m_matrix[0][2]); |
225 | } |
226 | inline qreal QTransform::m11() const |
227 | { |
228 | return m_matrix[0][0]; |
229 | } |
230 | inline qreal QTransform::m12() const |
231 | { |
232 | return m_matrix[0][1]; |
233 | } |
234 | inline qreal QTransform::m13() const |
235 | { |
236 | return m_matrix[0][2]; |
237 | } |
238 | inline qreal QTransform::m21() const |
239 | { |
240 | return m_matrix[1][0]; |
241 | } |
242 | inline qreal QTransform::m22() const |
243 | { |
244 | return m_matrix[1][1]; |
245 | } |
246 | inline qreal QTransform::m23() const |
247 | { |
248 | return m_matrix[1][2]; |
249 | } |
250 | inline qreal QTransform::m31() const |
251 | { |
252 | return m_matrix[2][0]; |
253 | } |
254 | inline qreal QTransform::m32() const |
255 | { |
256 | return m_matrix[2][1]; |
257 | } |
258 | inline qreal QTransform::m33() const |
259 | { |
260 | return m_matrix[2][2]; |
261 | } |
262 | inline qreal QTransform::dx() const |
263 | { |
264 | return m_matrix[2][0]; |
265 | } |
266 | inline qreal QTransform::dy() const |
267 | { |
268 | return m_matrix[2][1]; |
269 | } |
270 | |
271 | QT_WARNING_PUSH |
272 | QT_WARNING_DISABLE_FLOAT_COMPARE |
273 | |
274 | inline QTransform &QTransform::operator*=(qreal num) |
275 | { |
276 | if (num == 1.) |
277 | return *this; |
278 | m_matrix[0][0] *= num; |
279 | m_matrix[0][1] *= num; |
280 | m_matrix[0][2] *= num; |
281 | m_matrix[1][0] *= num; |
282 | m_matrix[1][1] *= num; |
283 | m_matrix[1][2] *= num; |
284 | m_matrix[2][0] *= num; |
285 | m_matrix[2][1] *= num; |
286 | m_matrix[2][2] *= num; |
287 | if (m_dirty < TxScale) |
288 | m_dirty = TxScale; |
289 | return *this; |
290 | } |
291 | inline QTransform &QTransform::operator/=(qreal div) |
292 | { |
293 | if (div == 0) |
294 | return *this; |
295 | div = 1/div; |
296 | return operator*=(div); |
297 | } |
298 | inline QTransform &QTransform::operator+=(qreal num) |
299 | { |
300 | if (num == 0) |
301 | return *this; |
302 | m_matrix[0][0] += num; |
303 | m_matrix[0][1] += num; |
304 | m_matrix[0][2] += num; |
305 | m_matrix[1][0] += num; |
306 | m_matrix[1][1] += num; |
307 | m_matrix[1][2] += num; |
308 | m_matrix[2][0] += num; |
309 | m_matrix[2][1] += num; |
310 | m_matrix[2][2] += num; |
311 | m_dirty = TxProject; |
312 | return *this; |
313 | } |
314 | inline QTransform &QTransform::operator-=(qreal num) |
315 | { |
316 | if (num == 0) |
317 | return *this; |
318 | m_matrix[0][0] -= num; |
319 | m_matrix[0][1] -= num; |
320 | m_matrix[0][2] -= num; |
321 | m_matrix[1][0] -= num; |
322 | m_matrix[1][1] -= num; |
323 | m_matrix[1][2] -= num; |
324 | m_matrix[2][0] -= num; |
325 | m_matrix[2][1] -= num; |
326 | m_matrix[2][2] -= num; |
327 | m_dirty = TxProject; |
328 | return *this; |
329 | } |
330 | |
331 | QT_WARNING_POP |
332 | |
333 | inline bool qFuzzyCompare(const QTransform& t1, const QTransform& t2) |
334 | { |
335 | return qFuzzyCompare(t1.m11(), t2.m11()) |
336 | && qFuzzyCompare(t1.m12(), t2.m12()) |
337 | && qFuzzyCompare(t1.m13(), t2.m13()) |
338 | && qFuzzyCompare(t1.m21(), t2.m21()) |
339 | && qFuzzyCompare(t1.m22(), t2.m22()) |
340 | && qFuzzyCompare(t1.m23(), t2.m23()) |
341 | && qFuzzyCompare(t1.m31(), t2.m31()) |
342 | && qFuzzyCompare(t1.m32(), t2.m32()) |
343 | && qFuzzyCompare(t1.m33(), t2.m33()); |
344 | } |
345 | |
346 | |
347 | /****** stream functions *******************/ |
348 | #ifndef QT_NO_DATASTREAM |
349 | Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QTransform &); |
350 | Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QTransform &); |
351 | #endif |
352 | |
353 | #ifndef QT_NO_DEBUG_STREAM |
354 | Q_GUI_EXPORT QDebug operator<<(QDebug, const QTransform &); |
355 | #endif |
356 | /****** end stream functions *******************/ |
357 | |
358 | // mathematical semantics |
359 | inline QPoint operator*(const QPoint &p, const QTransform &m) |
360 | { return m.map(p); } |
361 | inline QPointF operator*(const QPointF &p, const QTransform &m) |
362 | { return m.map(p); } |
363 | inline QLineF operator*(const QLineF &l, const QTransform &m) |
364 | { return m.map(l); } |
365 | inline QLine operator*(const QLine &l, const QTransform &m) |
366 | { return m.map(l); } |
367 | inline QPolygon operator *(const QPolygon &a, const QTransform &m) |
368 | { return m.map(a); } |
369 | inline QPolygonF operator *(const QPolygonF &a, const QTransform &m) |
370 | { return m.map(a); } |
371 | inline QRegion operator *(const QRegion &r, const QTransform &m) |
372 | { return m.map(r); } |
373 | |
374 | inline QTransform operator *(const QTransform &a, qreal n) |
375 | { QTransform t(a); t *= n; return t; } |
376 | inline QTransform operator /(const QTransform &a, qreal n) |
377 | { QTransform t(a); t /= n; return t; } |
378 | inline QTransform operator +(const QTransform &a, qreal n) |
379 | { QTransform t(a); t += n; return t; } |
380 | inline QTransform operator -(const QTransform &a, qreal n) |
381 | { QTransform t(a); t -= n; return t; } |
382 | |
383 | QT_END_NAMESPACE |
384 | |
385 | #endif // QTRANSFORM_H |
386 | |