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
50QT_BEGIN_NAMESPACE
51
52class QVariant;
53class QPainterPath;
54
55class Q_GUI_EXPORT QTransform
56{
57public:
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
163private:
164 struct Affine {
165 qreal (& m_matrix)[3][3];
166 };
167
168public:
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
173private:
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};
180Q_DECLARE_TYPEINFO(QTransform, Q_MOVABLE_TYPE);
181
182Q_GUI_EXPORT Q_DECL_CONST_FUNCTION size_t qHash(const QTransform &key, size_t seed = 0) noexcept;
183
184/******* inlines *****/
185inline QTransform::TransformationType QTransform::inline_type() const
186{
187 if (m_dirty == TxNone)
188 return static_cast<TransformationType>(m_type);
189 return type();
190}
191
192inline bool QTransform::isAffine() const
193{
194 return inline_type() < TxProject;
195}
196inline bool QTransform::isIdentity() const
197{
198 return inline_type() == TxNone;
199}
200
201inline bool QTransform::isInvertible() const
202{
203 return !qFuzzyIsNull(determinant());
204}
205
206inline bool QTransform::isScaling() const
207{
208 return type() >= TxScale;
209}
210inline bool QTransform::isRotating() const
211{
212 return inline_type() >= TxRotate;
213}
214
215inline bool QTransform::isTranslating() const
216{
217 return inline_type() >= TxTranslate;
218}
219
220inline 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}
226inline qreal QTransform::m11() const
227{
228 return m_matrix[0][0];
229}
230inline qreal QTransform::m12() const
231{
232 return m_matrix[0][1];
233}
234inline qreal QTransform::m13() const
235{
236 return m_matrix[0][2];
237}
238inline qreal QTransform::m21() const
239{
240 return m_matrix[1][0];
241}
242inline qreal QTransform::m22() const
243{
244 return m_matrix[1][1];
245}
246inline qreal QTransform::m23() const
247{
248 return m_matrix[1][2];
249}
250inline qreal QTransform::m31() const
251{
252 return m_matrix[2][0];
253}
254inline qreal QTransform::m32() const
255{
256 return m_matrix[2][1];
257}
258inline qreal QTransform::m33() const
259{
260 return m_matrix[2][2];
261}
262inline qreal QTransform::dx() const
263{
264 return m_matrix[2][0];
265}
266inline qreal QTransform::dy() const
267{
268 return m_matrix[2][1];
269}
270
271QT_WARNING_PUSH
272QT_WARNING_DISABLE_FLOAT_COMPARE
273
274inline 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}
291inline QTransform &QTransform::operator/=(qreal div)
292{
293 if (div == 0)
294 return *this;
295 div = 1/div;
296 return operator*=(div);
297}
298inline 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}
314inline 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
331QT_WARNING_POP
332
333inline 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
349Q_GUI_EXPORT QDataStream &operator<<(QDataStream &, const QTransform &);
350Q_GUI_EXPORT QDataStream &operator>>(QDataStream &, QTransform &);
351#endif
352
353#ifndef QT_NO_DEBUG_STREAM
354Q_GUI_EXPORT QDebug operator<<(QDebug, const QTransform &);
355#endif
356/****** end stream functions *******************/
357
358// mathematical semantics
359inline QPoint operator*(const QPoint &p, const QTransform &m)
360{ return m.map(p); }
361inline QPointF operator*(const QPointF &p, const QTransform &m)
362{ return m.map(p); }
363inline QLineF operator*(const QLineF &l, const QTransform &m)
364{ return m.map(l); }
365inline QLine operator*(const QLine &l, const QTransform &m)
366{ return m.map(l); }
367inline QPolygon operator *(const QPolygon &a, const QTransform &m)
368{ return m.map(a); }
369inline QPolygonF operator *(const QPolygonF &a, const QTransform &m)
370{ return m.map(a); }
371inline QRegion operator *(const QRegion &r, const QTransform &m)
372{ return m.map(r); }
373
374inline QTransform operator *(const QTransform &a, qreal n)
375{ QTransform t(a); t *= n; return t; }
376inline QTransform operator /(const QTransform &a, qreal n)
377{ QTransform t(a); t /= n; return t; }
378inline QTransform operator +(const QTransform &a, qreal n)
379{ QTransform t(a); t += n; return t; }
380inline QTransform operator -(const QTransform &a, qreal n)
381{ QTransform t(a); t -= n; return t; }
382
383QT_END_NAMESPACE
384
385#endif // QTRANSFORM_H
386