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#include "qtransform.h"
40
41#include "qdatastream.h"
42#include "qdebug.h"
43#include "qhashfunctions.h"
44#include "qmatrix.h"
45#include "qregion.h"
46#include "qpainterpath.h"
47#include "qpainterpath_p.h"
48#include "qvariant.h"
49#include <qmath.h>
50#include <qnumeric.h>
51
52#include <private/qbezier_p.h>
53
54QT_BEGIN_NAMESPACE
55
56#ifndef QT_NO_DEBUG
57Q_NEVER_INLINE
58static void nanWarning(const char *func)
59{
60 qWarning("QTransform::%s with NaN called", func);
61}
62#endif // QT_NO_DEBUG
63
64#define Q_NEAR_CLIP (sizeof(qreal) == sizeof(double) ? 0.000001 : 0.0001)
65
66#ifdef MAP
67# undef MAP
68#endif
69#define MAP(x, y, nx, ny) \
70 do { \
71 qreal FX_ = x; \
72 qreal FY_ = y; \
73 switch(t) { \
74 case TxNone: \
75 nx = FX_; \
76 ny = FY_; \
77 break; \
78 case TxTranslate: \
79 nx = FX_ + affine._dx; \
80 ny = FY_ + affine._dy; \
81 break; \
82 case TxScale: \
83 nx = affine._m11 * FX_ + affine._dx; \
84 ny = affine._m22 * FY_ + affine._dy; \
85 break; \
86 case TxRotate: \
87 case TxShear: \
88 case TxProject: \
89 nx = affine._m11 * FX_ + affine._m21 * FY_ + affine._dx; \
90 ny = affine._m12 * FX_ + affine._m22 * FY_ + affine._dy; \
91 if (t == TxProject) { \
92 qreal w = (m_13 * FX_ + m_23 * FY_ + m_33); \
93 if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
94 w = 1./w; \
95 nx *= w; \
96 ny *= w; \
97 } \
98 } \
99 } while (0)
100
101/*!
102 \class QTransform
103 \brief The QTransform class specifies 2D transformations of a coordinate system.
104 \since 4.3
105 \ingroup painting
106 \inmodule QtGui
107
108 A transformation specifies how to translate, scale, shear, rotate
109 or project the coordinate system, and is typically used when
110 rendering graphics.
111
112 QTransform differs from QMatrix in that it is a true 3x3 matrix,
113 allowing perspective transformations. QTransform's toAffine()
114 method allows casting QTransform to QMatrix. If a perspective
115 transformation has been specified on the matrix, then the
116 conversion will cause loss of data.
117
118 QTransform is the recommended transformation class in Qt.
119
120 A QTransform object can be built using the setMatrix(), scale(),
121 rotate(), translate() and shear() functions. Alternatively, it
122 can be built by applying \l {QTransform#Basic Matrix
123 Operations}{basic matrix operations}. The matrix can also be
124 defined when constructed, and it can be reset to the identity
125 matrix (the default) using the reset() function.
126
127 The QTransform class supports mapping of graphic primitives: A given
128 point, line, polygon, region, or painter path can be mapped to the
129 coordinate system defined by \e this matrix using the map()
130 function. In case of a rectangle, its coordinates can be
131 transformed using the mapRect() function. A rectangle can also be
132 transformed into a \e polygon (mapped to the coordinate system
133 defined by \e this matrix), using the mapToPolygon() function.
134
135 QTransform provides the isIdentity() function which returns \c true if
136 the matrix is the identity matrix, and the isInvertible() function
137 which returns \c true if the matrix is non-singular (i.e. AB = BA =
138 I). The inverted() function returns an inverted copy of \e this
139 matrix if it is invertible (otherwise it returns the identity
140 matrix), and adjoint() returns the matrix's classical adjoint.
141 In addition, QTransform provides the determinant() function which
142 returns the matrix's determinant.
143
144 Finally, the QTransform class supports matrix multiplication, addition
145 and subtraction, and objects of the class can be streamed as well
146 as compared.
147
148 \tableofcontents
149
150 \section1 Rendering Graphics
151
152 When rendering graphics, the matrix defines the transformations
153 but the actual transformation is performed by the drawing routines
154 in QPainter.
155
156 By default, QPainter operates on the associated device's own
157 coordinate system. The standard coordinate system of a
158 QPaintDevice has its origin located at the top-left position. The
159 \e x values increase to the right; \e y values increase
160 downward. For a complete description, see the \l {Coordinate
161 System} {coordinate system} documentation.
162
163 QPainter has functions to translate, scale, shear and rotate the
164 coordinate system without using a QTransform. For example:
165
166 \table 100%
167 \row
168 \li \inlineimage qtransform-simpletransformation.png
169 \li
170 \snippet transform/main.cpp 0
171 \endtable
172
173 Although these functions are very convenient, it can be more
174 efficient to build a QTransform and call QPainter::setTransform() if you
175 want to perform more than a single transform operation. For
176 example:
177
178 \table 100%
179 \row
180 \li \inlineimage qtransform-combinedtransformation.png
181 \li
182 \snippet transform/main.cpp 1
183 \endtable
184
185 \section1 Basic Matrix Operations
186
187 \image qtransform-representation.png
188
189 A QTransform object contains a 3 x 3 matrix. The \c m31 (\c dx) and
190 \c m32 (\c dy) elements specify horizontal and vertical translation.
191 The \c m11 and \c m22 elements specify horizontal and vertical scaling.
192 The \c m21 and \c m12 elements specify horizontal and vertical \e shearing.
193 And finally, the \c m13 and \c m23 elements specify horizontal and vertical
194 projection, with \c m33 as an additional projection factor.
195
196 QTransform transforms a point in the plane to another point using the
197 following formulas:
198
199 \snippet code/src_gui_painting_qtransform.cpp 0
200
201 The point \e (x, y) is the original point, and \e (x', y') is the
202 transformed point. \e (x', y') can be transformed back to \e (x,
203 y) by performing the same operation on the inverted() matrix.
204
205 The various matrix elements can be set when constructing the
206 matrix, or by using the setMatrix() function later on. They can also
207 be manipulated using the translate(), rotate(), scale() and
208 shear() convenience functions. The currently set values can be
209 retrieved using the m11(), m12(), m13(), m21(), m22(), m23(),
210 m31(), m32(), m33(), dx() and dy() functions.
211
212 Translation is the simplest transformation. Setting \c dx and \c
213 dy will move the coordinate system \c dx units along the X axis
214 and \c dy units along the Y axis. Scaling can be done by setting
215 \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to
216 1.5 will double the height and increase the width by 50%. The
217 identity matrix has \c m11, \c m22, and \c m33 set to 1 (all others are set
218 to 0) mapping a point to itself. Shearing is controlled by \c m12
219 and \c m21. Setting these elements to values different from zero
220 will twist the coordinate system. Rotation is achieved by
221 setting both the shearing factors and the scaling factors. Perspective
222 transformation is achieved by setting both the projection factors and
223 the scaling factors.
224
225 Here's the combined transformations example using basic matrix
226 operations:
227
228 \table 100%
229 \row
230 \li \inlineimage qtransform-combinedtransformation2.png
231 \li
232 \snippet transform/main.cpp 2
233 \endtable
234
235 \sa QPainter, {Coordinate System}, {painting/affine}{Affine
236 Transformations Example}, {Transformations Example}
237*/
238
239/*!
240 \enum QTransform::TransformationType
241
242 \value TxNone
243 \value TxTranslate
244 \value TxScale
245 \value TxRotate
246 \value TxShear
247 \value TxProject
248*/
249
250/*!
251 \fn QTransform::QTransform(Qt::Initialization)
252 \internal
253*/
254
255/*!
256 Constructs an identity matrix.
257
258 All elements are set to zero except \c m11 and \c m22 (specifying
259 the scale) and \c m33 which are set to 1.
260
261 \sa reset()
262*/
263QTransform::QTransform()
264 : affine(true)
265 , m_13(0), m_23(0), m_33(1)
266 , m_type(TxNone)
267 , m_dirty(TxNone)
268#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
269 , d(nullptr)
270#endif
271{
272}
273
274/*!
275 \fn QTransform::QTransform(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33)
276
277 Constructs a matrix with the elements, \a m11, \a m12, \a m13,
278 \a m21, \a m22, \a m23, \a m31, \a m32, \a m33.
279
280 \sa setMatrix()
281*/
282QTransform::QTransform(qreal h11, qreal h12, qreal h13,
283 qreal h21, qreal h22, qreal h23,
284 qreal h31, qreal h32, qreal h33)
285 : affine(h11, h12, h21, h22, h31, h32, true)
286 , m_13(h13), m_23(h23), m_33(h33)
287 , m_type(TxNone)
288 , m_dirty(TxProject)
289#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
290 , d(nullptr)
291#endif
292{
293}
294
295/*!
296 \fn QTransform::QTransform(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
297
298 Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a m22, \a dx and \a dy.
299
300 \sa setMatrix()
301*/
302QTransform::QTransform(qreal h11, qreal h12, qreal h21,
303 qreal h22, qreal dx, qreal dy)
304 : affine(h11, h12, h21, h22, dx, dy, true)
305 , m_13(0), m_23(0), m_33(1)
306 , m_type(TxNone)
307 , m_dirty(TxShear)
308#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
309 , d(nullptr)
310#endif
311{
312}
313
314/*!
315 \fn QTransform::QTransform(const QMatrix &matrix)
316
317 Constructs a matrix that is a copy of the given \a matrix.
318 Note that the \c m13, \c m23, and \c m33 elements are set to 0, 0,
319 and 1 respectively.
320 */
321QTransform::QTransform(const QMatrix &mtx)
322 : affine(mtx._m11, mtx._m12, mtx._m21, mtx._m22, mtx._dx, mtx._dy, true),
323 m_13(0), m_23(0), m_33(1)
324 , m_type(TxNone)
325 , m_dirty(TxShear)
326#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
327 , d(nullptr)
328#endif
329{
330}
331
332/*!
333 Returns the adjoint of this matrix.
334*/
335QTransform QTransform::adjoint() const
336{
337 qreal h11, h12, h13,
338 h21, h22, h23,
339 h31, h32, h33;
340 h11 = affine._m22*m_33 - m_23*affine._dy;
341 h21 = m_23*affine._dx - affine._m21*m_33;
342 h31 = affine._m21*affine._dy - affine._m22*affine._dx;
343 h12 = m_13*affine._dy - affine._m12*m_33;
344 h22 = affine._m11*m_33 - m_13*affine._dx;
345 h32 = affine._m12*affine._dx - affine._m11*affine._dy;
346 h13 = affine._m12*m_23 - m_13*affine._m22;
347 h23 = m_13*affine._m21 - affine._m11*m_23;
348 h33 = affine._m11*affine._m22 - affine._m12*affine._m21;
349
350 return QTransform(h11, h12, h13,
351 h21, h22, h23,
352 h31, h32, h33, true);
353}
354
355/*!
356 Returns the transpose of this matrix.
357*/
358QTransform QTransform::transposed() const
359{
360 QTransform t(affine._m11, affine._m21, affine._dx,
361 affine._m12, affine._m22, affine._dy,
362 m_13, m_23, m_33, true);
363 return t;
364}
365
366/*!
367 Returns an inverted copy of this matrix.
368
369 If the matrix is singular (not invertible), the returned matrix is
370 the identity matrix. If \a invertible is valid (i.e. not 0), its
371 value is set to true if the matrix is invertible, otherwise it is
372 set to false.
373
374 \sa isInvertible()
375*/
376QTransform QTransform::inverted(bool *invertible) const
377{
378 QTransform invert(true);
379 bool inv = true;
380
381 switch(inline_type()) {
382 case TxNone:
383 break;
384 case TxTranslate:
385 invert.affine._dx = -affine._dx;
386 invert.affine._dy = -affine._dy;
387 break;
388 case TxScale:
389 inv = !qFuzzyIsNull(affine._m11);
390 inv &= !qFuzzyIsNull(affine._m22);
391 if (inv) {
392 invert.affine._m11 = 1. / affine._m11;
393 invert.affine._m22 = 1. / affine._m22;
394 invert.affine._dx = -affine._dx * invert.affine._m11;
395 invert.affine._dy = -affine._dy * invert.affine._m22;
396 }
397 break;
398 case TxRotate:
399 case TxShear:
400 invert.affine = affine.inverted(&inv);
401 break;
402 default:
403 // general case
404 qreal det = determinant();
405 inv = !qFuzzyIsNull(det);
406 if (inv)
407 invert = adjoint() / det;
408 break;
409 }
410
411 if (invertible)
412 *invertible = inv;
413
414 if (inv) {
415 // inverting doesn't change the type
416 invert.m_type = m_type;
417 invert.m_dirty = m_dirty;
418 }
419
420 return invert;
421}
422
423/*!
424 Moves the coordinate system \a dx along the x axis and \a dy along
425 the y axis, and returns a reference to the matrix.
426
427 \sa setMatrix()
428*/
429QTransform &QTransform::translate(qreal dx, qreal dy)
430{
431 if (dx == 0 && dy == 0)
432 return *this;
433#ifndef QT_NO_DEBUG
434 if (qIsNaN(dx) | qIsNaN(dy)) {
435 nanWarning("translate");
436 return *this;
437 }
438#endif
439
440 switch(inline_type()) {
441 case TxNone:
442 affine._dx = dx;
443 affine._dy = dy;
444 break;
445 case TxTranslate:
446 affine._dx += dx;
447 affine._dy += dy;
448 break;
449 case TxScale:
450 affine._dx += dx*affine._m11;
451 affine._dy += dy*affine._m22;
452 break;
453 case TxProject:
454 m_33 += dx*m_13 + dy*m_23;
455 Q_FALLTHROUGH();
456 case TxShear:
457 case TxRotate:
458 affine._dx += dx*affine._m11 + dy*affine._m21;
459 affine._dy += dy*affine._m22 + dx*affine._m12;
460 break;
461 }
462 if (m_dirty < TxTranslate)
463 m_dirty = TxTranslate;
464 return *this;
465}
466
467/*!
468 Creates a matrix which corresponds to a translation of \a dx along
469 the x axis and \a dy along the y axis. This is the same as
470 QTransform().translate(dx, dy) but slightly faster.
471
472 \since 4.5
473*/
474QTransform QTransform::fromTranslate(qreal dx, qreal dy)
475{
476#ifndef QT_NO_DEBUG
477 if (qIsNaN(dx) | qIsNaN(dy)) {
478 nanWarning("fromTranslate");
479 return QTransform();
480}
481#endif
482 QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1, true);
483 if (dx == 0 && dy == 0)
484 transform.m_type = TxNone;
485 else
486 transform.m_type = TxTranslate;
487 transform.m_dirty = TxNone;
488 return transform;
489}
490
491/*!
492 Scales the coordinate system by \a sx horizontally and \a sy
493 vertically, and returns a reference to the matrix.
494
495 \sa setMatrix()
496*/
497QTransform & QTransform::scale(qreal sx, qreal sy)
498{
499 if (sx == 1 && sy == 1)
500 return *this;
501#ifndef QT_NO_DEBUG
502 if (qIsNaN(sx) | qIsNaN(sy)) {
503 nanWarning("scale");
504 return *this;
505 }
506#endif
507
508 switch(inline_type()) {
509 case TxNone:
510 case TxTranslate:
511 affine._m11 = sx;
512 affine._m22 = sy;
513 break;
514 case TxProject:
515 m_13 *= sx;
516 m_23 *= sy;
517 Q_FALLTHROUGH();
518 case TxRotate:
519 case TxShear:
520 affine._m12 *= sx;
521 affine._m21 *= sy;
522 Q_FALLTHROUGH();
523 case TxScale:
524 affine._m11 *= sx;
525 affine._m22 *= sy;
526 break;
527 }
528 if (m_dirty < TxScale)
529 m_dirty = TxScale;
530 return *this;
531}
532
533/*!
534 Creates a matrix which corresponds to a scaling of
535 \a sx horizontally and \a sy vertically.
536 This is the same as QTransform().scale(sx, sy) but slightly faster.
537
538 \since 4.5
539*/
540QTransform QTransform::fromScale(qreal sx, qreal sy)
541{
542#ifndef QT_NO_DEBUG
543 if (qIsNaN(sx) | qIsNaN(sy)) {
544 nanWarning("fromScale");
545 return QTransform();
546}
547#endif
548 QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1, true);
549 if (sx == 1. && sy == 1.)
550 transform.m_type = TxNone;
551 else
552 transform.m_type = TxScale;
553 transform.m_dirty = TxNone;
554 return transform;
555}
556
557/*!
558 Shears the coordinate system by \a sh horizontally and \a sv
559 vertically, and returns a reference to the matrix.
560
561 \sa setMatrix()
562*/
563QTransform & QTransform::shear(qreal sh, qreal sv)
564{
565 if (sh == 0 && sv == 0)
566 return *this;
567#ifndef QT_NO_DEBUG
568 if (qIsNaN(sh) | qIsNaN(sv)) {
569 nanWarning("shear");
570 return *this;
571 }
572#endif
573
574 switch(inline_type()) {
575 case TxNone:
576 case TxTranslate:
577 affine._m12 = sv;
578 affine._m21 = sh;
579 break;
580 case TxScale:
581 affine._m12 = sv*affine._m22;
582 affine._m21 = sh*affine._m11;
583 break;
584 case TxProject: {
585 qreal tm13 = sv*m_23;
586 qreal tm23 = sh*m_13;
587 m_13 += tm13;
588 m_23 += tm23;
589 }
590 Q_FALLTHROUGH();
591 case TxRotate:
592 case TxShear: {
593 qreal tm11 = sv*affine._m21;
594 qreal tm22 = sh*affine._m12;
595 qreal tm12 = sv*affine._m22;
596 qreal tm21 = sh*affine._m11;
597 affine._m11 += tm11; affine._m12 += tm12;
598 affine._m21 += tm21; affine._m22 += tm22;
599 break;
600 }
601 }
602 if (m_dirty < TxShear)
603 m_dirty = TxShear;
604 return *this;
605}
606
607const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
608const qreal inv_dist_to_plane = 1. / 1024.;
609
610/*!
611 \fn QTransform &QTransform::rotate(qreal angle, Qt::Axis axis)
612
613 Rotates the coordinate system counterclockwise by the given \a angle
614 about the specified \a axis and returns a reference to the matrix.
615
616 Note that if you apply a QTransform to a point defined in widget
617 coordinates, the direction of the rotation will be clockwise
618 because the y-axis points downwards.
619
620 The angle is specified in degrees.
621
622 \sa setMatrix()
623*/
624QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
625{
626 if (a == 0)
627 return *this;
628#ifndef QT_NO_DEBUG
629 if (qIsNaN(a)) {
630 nanWarning("rotate");
631 return *this;
632 }
633#endif
634
635 qreal sina = 0;
636 qreal cosa = 0;
637 if (a == 90. || a == -270.)
638 sina = 1.;
639 else if (a == 270. || a == -90.)
640 sina = -1.;
641 else if (a == 180.)
642 cosa = -1.;
643 else{
644 qreal b = deg2rad*a; // convert to radians
645 sina = qSin(b); // fast and convenient
646 cosa = qCos(b);
647 }
648
649 if (axis == Qt::ZAxis) {
650 switch(inline_type()) {
651 case TxNone:
652 case TxTranslate:
653 affine._m11 = cosa;
654 affine._m12 = sina;
655 affine._m21 = -sina;
656 affine._m22 = cosa;
657 break;
658 case TxScale: {
659 qreal tm11 = cosa*affine._m11;
660 qreal tm12 = sina*affine._m22;
661 qreal tm21 = -sina*affine._m11;
662 qreal tm22 = cosa*affine._m22;
663 affine._m11 = tm11; affine._m12 = tm12;
664 affine._m21 = tm21; affine._m22 = tm22;
665 break;
666 }
667 case TxProject: {
668 qreal tm13 = cosa*m_13 + sina*m_23;
669 qreal tm23 = -sina*m_13 + cosa*m_23;
670 m_13 = tm13;
671 m_23 = tm23;
672 Q_FALLTHROUGH();
673 }
674 case TxRotate:
675 case TxShear: {
676 qreal tm11 = cosa*affine._m11 + sina*affine._m21;
677 qreal tm12 = cosa*affine._m12 + sina*affine._m22;
678 qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
679 qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
680 affine._m11 = tm11; affine._m12 = tm12;
681 affine._m21 = tm21; affine._m22 = tm22;
682 break;
683 }
684 }
685 if (m_dirty < TxRotate)
686 m_dirty = TxRotate;
687 } else {
688 QTransform result;
689 if (axis == Qt::YAxis) {
690 result.affine._m11 = cosa;
691 result.m_13 = -sina * inv_dist_to_plane;
692 } else {
693 result.affine._m22 = cosa;
694 result.m_23 = -sina * inv_dist_to_plane;
695 }
696 result.m_type = TxProject;
697 *this = result * *this;
698 }
699
700 return *this;
701}
702
703/*!
704 \fn QTransform & QTransform::rotateRadians(qreal angle, Qt::Axis axis)
705
706 Rotates the coordinate system counterclockwise by the given \a angle
707 about the specified \a axis and returns a reference to the matrix.
708
709 Note that if you apply a QTransform to a point defined in widget
710 coordinates, the direction of the rotation will be clockwise
711 because the y-axis points downwards.
712
713 The angle is specified in radians.
714
715 \sa setMatrix()
716*/
717QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
718{
719#ifndef QT_NO_DEBUG
720 if (qIsNaN(a)) {
721 nanWarning("rotateRadians");
722 return *this;
723 }
724#endif
725 qreal sina = qSin(a);
726 qreal cosa = qCos(a);
727
728 if (axis == Qt::ZAxis) {
729 switch(inline_type()) {
730 case TxNone:
731 case TxTranslate:
732 affine._m11 = cosa;
733 affine._m12 = sina;
734 affine._m21 = -sina;
735 affine._m22 = cosa;
736 break;
737 case TxScale: {
738 qreal tm11 = cosa*affine._m11;
739 qreal tm12 = sina*affine._m22;
740 qreal tm21 = -sina*affine._m11;
741 qreal tm22 = cosa*affine._m22;
742 affine._m11 = tm11; affine._m12 = tm12;
743 affine._m21 = tm21; affine._m22 = tm22;
744 break;
745 }
746 case TxProject: {
747 qreal tm13 = cosa*m_13 + sina*m_23;
748 qreal tm23 = -sina*m_13 + cosa*m_23;
749 m_13 = tm13;
750 m_23 = tm23;
751 Q_FALLTHROUGH();
752 }
753 case TxRotate:
754 case TxShear: {
755 qreal tm11 = cosa*affine._m11 + sina*affine._m21;
756 qreal tm12 = cosa*affine._m12 + sina*affine._m22;
757 qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
758 qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
759 affine._m11 = tm11; affine._m12 = tm12;
760 affine._m21 = tm21; affine._m22 = tm22;
761 break;
762 }
763 }
764 if (m_dirty < TxRotate)
765 m_dirty = TxRotate;
766 } else {
767 QTransform result;
768 if (axis == Qt::YAxis) {
769 result.affine._m11 = cosa;
770 result.m_13 = -sina * inv_dist_to_plane;
771 } else {
772 result.affine._m22 = cosa;
773 result.m_23 = -sina * inv_dist_to_plane;
774 }
775 result.m_type = TxProject;
776 *this = result * *this;
777 }
778 return *this;
779}
780
781/*!
782 \fn bool QTransform::operator==(const QTransform &matrix) const
783 Returns \c true if this matrix is equal to the given \a matrix,
784 otherwise returns \c false.
785*/
786bool QTransform::operator==(const QTransform &o) const
787{
788 return affine._m11 == o.affine._m11 &&
789 affine._m12 == o.affine._m12 &&
790 affine._m21 == o.affine._m21 &&
791 affine._m22 == o.affine._m22 &&
792 affine._dx == o.affine._dx &&
793 affine._dy == o.affine._dy &&
794 m_13 == o.m_13 &&
795 m_23 == o.m_23 &&
796 m_33 == o.m_33;
797}
798
799/*!
800 \since 5.6
801 \relates QTransform
802
803 Returns the hash value for \a key, using
804 \a seed to seed the calculation.
805*/
806uint qHash(const QTransform &key, uint seed) noexcept
807{
808 QtPrivate::QHashCombine hash;
809 seed = hash(seed, key.m11());
810 seed = hash(seed, key.m12());
811 seed = hash(seed, key.m21());
812 seed = hash(seed, key.m22());
813 seed = hash(seed, key.dx());
814 seed = hash(seed, key.dy());
815 seed = hash(seed, key.m13());
816 seed = hash(seed, key.m23());
817 seed = hash(seed, key.m33());
818 return seed;
819}
820
821
822/*!
823 \fn bool QTransform::operator!=(const QTransform &matrix) const
824 Returns \c true if this matrix is not equal to the given \a matrix,
825 otherwise returns \c false.
826*/
827bool QTransform::operator!=(const QTransform &o) const
828{
829 return !operator==(o);
830}
831
832/*!
833 \fn QTransform & QTransform::operator*=(const QTransform &matrix)
834 \overload
835
836 Returns the result of multiplying this matrix by the given \a
837 matrix.
838*/
839QTransform & QTransform::operator*=(const QTransform &o)
840{
841 const TransformationType otherType = o.inline_type();
842 if (otherType == TxNone)
843 return *this;
844
845 const TransformationType thisType = inline_type();
846 if (thisType == TxNone)
847 return operator=(o);
848
849 TransformationType t = qMax(thisType, otherType);
850 switch(t) {
851 case TxNone:
852 break;
853 case TxTranslate:
854 affine._dx += o.affine._dx;
855 affine._dy += o.affine._dy;
856 break;
857 case TxScale:
858 {
859 qreal m11 = affine._m11*o.affine._m11;
860 qreal m22 = affine._m22*o.affine._m22;
861
862 qreal m31 = affine._dx*o.affine._m11 + o.affine._dx;
863 qreal m32 = affine._dy*o.affine._m22 + o.affine._dy;
864
865 affine._m11 = m11;
866 affine._m22 = m22;
867 affine._dx = m31; affine._dy = m32;
868 break;
869 }
870 case TxRotate:
871 case TxShear:
872 {
873 qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21;
874 qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22;
875
876 qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21;
877 qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22;
878
879 qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + o.affine._dx;
880 qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + o.affine._dy;
881
882 affine._m11 = m11; affine._m12 = m12;
883 affine._m21 = m21; affine._m22 = m22;
884 affine._dx = m31; affine._dy = m32;
885 break;
886 }
887 case TxProject:
888 {
889 qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21 + m_13*o.affine._dx;
890 qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22 + m_13*o.affine._dy;
891 qreal m13 = affine._m11*o.m_13 + affine._m12*o.m_23 + m_13*o.m_33;
892
893 qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21 + m_23*o.affine._dx;
894 qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22 + m_23*o.affine._dy;
895 qreal m23 = affine._m21*o.m_13 + affine._m22*o.m_23 + m_23*o.m_33;
896
897 qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + m_33*o.affine._dx;
898 qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + m_33*o.affine._dy;
899 qreal m33 = affine._dx*o.m_13 + affine._dy*o.m_23 + m_33*o.m_33;
900
901 affine._m11 = m11; affine._m12 = m12; m_13 = m13;
902 affine._m21 = m21; affine._m22 = m22; m_23 = m23;
903 affine._dx = m31; affine._dy = m32; m_33 = m33;
904 }
905 }
906
907 m_dirty = t;
908 m_type = t;
909
910 return *this;
911}
912
913/*!
914 \fn QTransform QTransform::operator*(const QTransform &matrix) const
915 Returns the result of multiplying this matrix by the given \a
916 matrix.
917
918 Note that matrix multiplication is not commutative, i.e. a*b !=
919 b*a.
920*/
921QTransform QTransform::operator*(const QTransform &m) const
922{
923 const TransformationType otherType = m.inline_type();
924 if (otherType == TxNone)
925 return *this;
926
927 const TransformationType thisType = inline_type();
928 if (thisType == TxNone)
929 return m;
930
931 QTransform t(true);
932 TransformationType type = qMax(thisType, otherType);
933 switch(type) {
934 case TxNone:
935 break;
936 case TxTranslate:
937 t.affine._dx = affine._dx + m.affine._dx;
938 t.affine._dy += affine._dy + m.affine._dy;
939 break;
940 case TxScale:
941 {
942 qreal m11 = affine._m11*m.affine._m11;
943 qreal m22 = affine._m22*m.affine._m22;
944
945 qreal m31 = affine._dx*m.affine._m11 + m.affine._dx;
946 qreal m32 = affine._dy*m.affine._m22 + m.affine._dy;
947
948 t.affine._m11 = m11;
949 t.affine._m22 = m22;
950 t.affine._dx = m31; t.affine._dy = m32;
951 break;
952 }
953 case TxRotate:
954 case TxShear:
955 {
956 qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21;
957 qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22;
958
959 qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21;
960 qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22;
961
962 qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m.affine._dx;
963 qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m.affine._dy;
964
965 t.affine._m11 = m11; t.affine._m12 = m12;
966 t.affine._m21 = m21; t.affine._m22 = m22;
967 t.affine._dx = m31; t.affine._dy = m32;
968 break;
969 }
970 case TxProject:
971 {
972 qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21 + m_13*m.affine._dx;
973 qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22 + m_13*m.affine._dy;
974 qreal m13 = affine._m11*m.m_13 + affine._m12*m.m_23 + m_13*m.m_33;
975
976 qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21 + m_23*m.affine._dx;
977 qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22 + m_23*m.affine._dy;
978 qreal m23 = affine._m21*m.m_13 + affine._m22*m.m_23 + m_23*m.m_33;
979
980 qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m_33*m.affine._dx;
981 qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m_33*m.affine._dy;
982 qreal m33 = affine._dx*m.m_13 + affine._dy*m.m_23 + m_33*m.m_33;
983
984 t.affine._m11 = m11; t.affine._m12 = m12; t.m_13 = m13;
985 t.affine._m21 = m21; t.affine._m22 = m22; t.m_23 = m23;
986 t.affine._dx = m31; t.affine._dy = m32; t.m_33 = m33;
987 }
988 }
989
990 t.m_dirty = type;
991 t.m_type = type;
992
993 return t;
994}
995
996/*!
997 \fn QTransform & QTransform::operator*=(qreal scalar)
998 \overload
999
1000 Returns the result of performing an element-wise multiplication of this
1001 matrix with the given \a scalar.
1002*/
1003
1004/*!
1005 \fn QTransform & QTransform::operator/=(qreal scalar)
1006 \overload
1007
1008 Returns the result of performing an element-wise division of this
1009 matrix by the given \a scalar.
1010*/
1011
1012/*!
1013 \fn QTransform & QTransform::operator+=(qreal scalar)
1014 \overload
1015
1016 Returns the matrix obtained by adding the given \a scalar to each
1017 element of this matrix.
1018*/
1019
1020/*!
1021 \fn QTransform & QTransform::operator-=(qreal scalar)
1022 \overload
1023
1024 Returns the matrix obtained by subtracting the given \a scalar from each
1025 element of this matrix.
1026*/
1027
1028#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1029/*!
1030 Assigns the given \a matrix's values to this matrix.
1031*/
1032QTransform & QTransform::operator=(const QTransform &matrix) noexcept
1033{
1034 affine._m11 = matrix.affine._m11;
1035 affine._m12 = matrix.affine._m12;
1036 affine._m21 = matrix.affine._m21;
1037 affine._m22 = matrix.affine._m22;
1038 affine._dx = matrix.affine._dx;
1039 affine._dy = matrix.affine._dy;
1040 m_13 = matrix.m_13;
1041 m_23 = matrix.m_23;
1042 m_33 = matrix.m_33;
1043 m_type = matrix.m_type;
1044 m_dirty = matrix.m_dirty;
1045
1046 return *this;
1047}
1048#endif
1049
1050/*!
1051 Resets the matrix to an identity matrix, i.e. all elements are set
1052 to zero, except \c m11 and \c m22 (specifying the scale) and \c m33
1053 which are set to 1.
1054
1055 \sa QTransform(), isIdentity(), {QTransform#Basic Matrix
1056 Operations}{Basic Matrix Operations}
1057*/
1058void QTransform::reset()
1059{
1060 affine._m11 = affine._m22 = m_33 = 1.0;
1061 affine._m12 = m_13 = affine._m21 = m_23 = affine._dx = affine._dy = 0;
1062 m_type = TxNone;
1063 m_dirty = TxNone;
1064}
1065
1066#ifndef QT_NO_DATASTREAM
1067/*!
1068 \fn QDataStream &operator<<(QDataStream &stream, const QTransform &matrix)
1069 \since 4.3
1070 \relates QTransform
1071
1072 Writes the given \a matrix to the given \a stream and returns a
1073 reference to the stream.
1074
1075 \sa {Serializing Qt Data Types}
1076*/
1077QDataStream & operator<<(QDataStream &s, const QTransform &m)
1078{
1079 s << double(m.m11())
1080 << double(m.m12())
1081 << double(m.m13())
1082 << double(m.m21())
1083 << double(m.m22())
1084 << double(m.m23())
1085 << double(m.m31())
1086 << double(m.m32())
1087 << double(m.m33());
1088 return s;
1089}
1090
1091/*!
1092 \fn QDataStream &operator>>(QDataStream &stream, QTransform &matrix)
1093 \since 4.3
1094 \relates QTransform
1095
1096 Reads the given \a matrix from the given \a stream and returns a
1097 reference to the stream.
1098
1099 \sa {Serializing Qt Data Types}
1100*/
1101QDataStream & operator>>(QDataStream &s, QTransform &t)
1102{
1103 double m11, m12, m13,
1104 m21, m22, m23,
1105 m31, m32, m33;
1106
1107 s >> m11;
1108 s >> m12;
1109 s >> m13;
1110 s >> m21;
1111 s >> m22;
1112 s >> m23;
1113 s >> m31;
1114 s >> m32;
1115 s >> m33;
1116 t.setMatrix(m11, m12, m13,
1117 m21, m22, m23,
1118 m31, m32, m33);
1119 return s;
1120}
1121
1122#endif // QT_NO_DATASTREAM
1123
1124#ifndef QT_NO_DEBUG_STREAM
1125QDebug operator<<(QDebug dbg, const QTransform &m)
1126{
1127 static const char typeStr[][12] =
1128 {
1129 "TxNone",
1130 "TxTranslate",
1131 "TxScale",
1132 "",
1133 "TxRotate",
1134 "", "", "",
1135 "TxShear",
1136 "", "", "", "", "", "", "",
1137 "TxProject"
1138 };
1139
1140 QDebugStateSaver saver(dbg);
1141 dbg.nospace() << "QTransform(type=" << typeStr[m.type()] << ','
1142 << " 11=" << m.m11()
1143 << " 12=" << m.m12()
1144 << " 13=" << m.m13()
1145 << " 21=" << m.m21()
1146 << " 22=" << m.m22()
1147 << " 23=" << m.m23()
1148 << " 31=" << m.m31()
1149 << " 32=" << m.m32()
1150 << " 33=" << m.m33()
1151 << ')';
1152
1153 return dbg;
1154}
1155#endif
1156
1157/*!
1158 \fn QPoint operator*(const QPoint &point, const QTransform &matrix)
1159 \relates QTransform
1160
1161 This is the same as \a{matrix}.map(\a{point}).
1162
1163 \sa QTransform::map()
1164*/
1165QPoint QTransform::map(const QPoint &p) const
1166{
1167 qreal fx = p.x();
1168 qreal fy = p.y();
1169
1170 qreal x = 0, y = 0;
1171
1172 TransformationType t = inline_type();
1173 switch(t) {
1174 case TxNone:
1175 x = fx;
1176 y = fy;
1177 break;
1178 case TxTranslate:
1179 x = fx + affine._dx;
1180 y = fy + affine._dy;
1181 break;
1182 case TxScale:
1183 x = affine._m11 * fx + affine._dx;
1184 y = affine._m22 * fy + affine._dy;
1185 break;
1186 case TxRotate:
1187 case TxShear:
1188 case TxProject:
1189 x = affine._m11 * fx + affine._m21 * fy + affine._dx;
1190 y = affine._m12 * fx + affine._m22 * fy + affine._dy;
1191 if (t == TxProject) {
1192 qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
1193 x *= w;
1194 y *= w;
1195 }
1196 }
1197 return QPoint(qRound(x), qRound(y));
1198}
1199
1200
1201/*!
1202 \fn QPointF operator*(const QPointF &point, const QTransform &matrix)
1203 \relates QTransform
1204
1205 Same as \a{matrix}.map(\a{point}).
1206
1207 \sa QTransform::map()
1208*/
1209
1210/*!
1211 \overload
1212
1213 Creates and returns a QPointF object that is a copy of the given point,
1214 \a p, mapped into the coordinate system defined by this matrix.
1215*/
1216QPointF QTransform::map(const QPointF &p) const
1217{
1218 qreal fx = p.x();
1219 qreal fy = p.y();
1220
1221 qreal x = 0, y = 0;
1222
1223 TransformationType t = inline_type();
1224 switch(t) {
1225 case TxNone:
1226 x = fx;
1227 y = fy;
1228 break;
1229 case TxTranslate:
1230 x = fx + affine._dx;
1231 y = fy + affine._dy;
1232 break;
1233 case TxScale:
1234 x = affine._m11 * fx + affine._dx;
1235 y = affine._m22 * fy + affine._dy;
1236 break;
1237 case TxRotate:
1238 case TxShear:
1239 case TxProject:
1240 x = affine._m11 * fx + affine._m21 * fy + affine._dx;
1241 y = affine._m12 * fx + affine._m22 * fy + affine._dy;
1242 if (t == TxProject) {
1243 qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
1244 x *= w;
1245 y *= w;
1246 }
1247 }
1248 return QPointF(x, y);
1249}
1250
1251/*!
1252 \fn QPoint QTransform::map(const QPoint &point) const
1253 \overload
1254
1255 Creates and returns a QPoint object that is a copy of the given \a
1256 point, mapped into the coordinate system defined by this
1257 matrix. Note that the transformed coordinates are rounded to the
1258 nearest integer.
1259*/
1260
1261/*!
1262 \fn QLineF operator*(const QLineF &line, const QTransform &matrix)
1263 \relates QTransform
1264
1265 This is the same as \a{matrix}.map(\a{line}).
1266
1267 \sa QTransform::map()
1268*/
1269
1270/*!
1271 \fn QLine operator*(const QLine &line, const QTransform &matrix)
1272 \relates QTransform
1273
1274 This is the same as \a{matrix}.map(\a{line}).
1275
1276 \sa QTransform::map()
1277*/
1278
1279/*!
1280 \overload
1281
1282 Creates and returns a QLineF object that is a copy of the given line,
1283 \a l, mapped into the coordinate system defined by this matrix.
1284*/
1285QLine QTransform::map(const QLine &l) const
1286{
1287 qreal fx1 = l.x1();
1288 qreal fy1 = l.y1();
1289 qreal fx2 = l.x2();
1290 qreal fy2 = l.y2();
1291
1292 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1293
1294 TransformationType t = inline_type();
1295 switch(t) {
1296 case TxNone:
1297 x1 = fx1;
1298 y1 = fy1;
1299 x2 = fx2;
1300 y2 = fy2;
1301 break;
1302 case TxTranslate:
1303 x1 = fx1 + affine._dx;
1304 y1 = fy1 + affine._dy;
1305 x2 = fx2 + affine._dx;
1306 y2 = fy2 + affine._dy;
1307 break;
1308 case TxScale:
1309 x1 = affine._m11 * fx1 + affine._dx;
1310 y1 = affine._m22 * fy1 + affine._dy;
1311 x2 = affine._m11 * fx2 + affine._dx;
1312 y2 = affine._m22 * fy2 + affine._dy;
1313 break;
1314 case TxRotate:
1315 case TxShear:
1316 case TxProject:
1317 x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
1318 y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
1319 x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
1320 y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
1321 if (t == TxProject) {
1322 qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
1323 x1 *= w;
1324 y1 *= w;
1325 w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
1326 x2 *= w;
1327 y2 *= w;
1328 }
1329 }
1330 return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
1331}
1332
1333/*!
1334 \overload
1335
1336 \fn QLineF QTransform::map(const QLineF &line) const
1337
1338 Creates and returns a QLine object that is a copy of the given \a
1339 line, mapped into the coordinate system defined by this matrix.
1340 Note that the transformed coordinates are rounded to the nearest
1341 integer.
1342*/
1343
1344QLineF QTransform::map(const QLineF &l) const
1345{
1346 qreal fx1 = l.x1();
1347 qreal fy1 = l.y1();
1348 qreal fx2 = l.x2();
1349 qreal fy2 = l.y2();
1350
1351 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1352
1353 TransformationType t = inline_type();
1354 switch(t) {
1355 case TxNone:
1356 x1 = fx1;
1357 y1 = fy1;
1358 x2 = fx2;
1359 y2 = fy2;
1360 break;
1361 case TxTranslate:
1362 x1 = fx1 + affine._dx;
1363 y1 = fy1 + affine._dy;
1364 x2 = fx2 + affine._dx;
1365 y2 = fy2 + affine._dy;
1366 break;
1367 case TxScale:
1368 x1 = affine._m11 * fx1 + affine._dx;
1369 y1 = affine._m22 * fy1 + affine._dy;
1370 x2 = affine._m11 * fx2 + affine._dx;
1371 y2 = affine._m22 * fy2 + affine._dy;
1372 break;
1373 case TxRotate:
1374 case TxShear:
1375 case TxProject:
1376 x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
1377 y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
1378 x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
1379 y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
1380 if (t == TxProject) {
1381 qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
1382 x1 *= w;
1383 y1 *= w;
1384 w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
1385 x2 *= w;
1386 y2 *= w;
1387 }
1388 }
1389 return QLineF(x1, y1, x2, y2);
1390}
1391
1392static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &poly)
1393{
1394 if (poly.size() == 0)
1395 return poly;
1396
1397 if (poly.size() == 1)
1398 return QPolygonF() << transform.map(poly.at(0));
1399
1400 QPainterPath path;
1401 path.addPolygon(poly);
1402
1403 path = transform.map(path);
1404
1405 QPolygonF result;
1406 const int elementCount = path.elementCount();
1407 result.reserve(elementCount);
1408 for (int i = 0; i < elementCount; ++i)
1409 result << path.elementAt(i);
1410 return result;
1411}
1412
1413
1414/*!
1415 \fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix)
1416 \since 4.3
1417 \relates QTransform
1418
1419 This is the same as \a{matrix}.map(\a{polygon}).
1420
1421 \sa QTransform::map()
1422*/
1423
1424/*!
1425 \fn QPolygon operator*(const QPolygon &polygon, const QTransform &matrix)
1426 \relates QTransform
1427
1428 This is the same as \a{matrix}.map(\a{polygon}).
1429
1430 \sa QTransform::map()
1431*/
1432
1433/*!
1434 \fn QPolygonF QTransform::map(const QPolygonF &polygon) const
1435 \overload
1436
1437 Creates and returns a QPolygonF object that is a copy of the given
1438 \a polygon, mapped into the coordinate system defined by this
1439 matrix.
1440*/
1441QPolygonF QTransform::map(const QPolygonF &a) const
1442{
1443 TransformationType t = inline_type();
1444 if (t <= TxTranslate)
1445 return a.translated(affine._dx, affine._dy);
1446
1447 if (t >= QTransform::TxProject)
1448 return mapProjective(*this, a);
1449
1450 int size = a.size();
1451 int i;
1452 QPolygonF p(size);
1453 const QPointF *da = a.constData();
1454 QPointF *dp = p.data();
1455
1456 for(i = 0; i < size; ++i) {
1457 MAP(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
1458 }
1459 return p;
1460}
1461
1462/*!
1463 \fn QPolygon QTransform::map(const QPolygon &polygon) const
1464 \overload
1465
1466 Creates and returns a QPolygon object that is a copy of the given
1467 \a polygon, mapped into the coordinate system defined by this
1468 matrix. Note that the transformed coordinates are rounded to the
1469 nearest integer.
1470*/
1471QPolygon QTransform::map(const QPolygon &a) const
1472{
1473 TransformationType t = inline_type();
1474 if (t <= TxTranslate)
1475 return a.translated(qRound(affine._dx), qRound(affine._dy));
1476
1477 if (t >= QTransform::TxProject)
1478 return mapProjective(*this, QPolygonF(a)).toPolygon();
1479
1480 int size = a.size();
1481 int i;
1482 QPolygon p(size);
1483 const QPoint *da = a.constData();
1484 QPoint *dp = p.data();
1485
1486 for(i = 0; i < size; ++i) {
1487 qreal nx = 0, ny = 0;
1488 MAP(da[i].xp, da[i].yp, nx, ny);
1489 dp[i].xp = qRound(nx);
1490 dp[i].yp = qRound(ny);
1491 }
1492 return p;
1493}
1494
1495/*!
1496 \fn QRegion operator*(const QRegion &region, const QTransform &matrix)
1497 \relates QTransform
1498
1499 This is the same as \a{matrix}.map(\a{region}).
1500
1501 \sa QTransform::map()
1502*/
1503
1504extern QPainterPath qt_regionToPath(const QRegion &region);
1505
1506/*!
1507 \fn QRegion QTransform::map(const QRegion &region) const
1508 \overload
1509
1510 Creates and returns a QRegion object that is a copy of the given
1511 \a region, mapped into the coordinate system defined by this matrix.
1512
1513 Calling this method can be rather expensive if rotations or
1514 shearing are used.
1515*/
1516QRegion QTransform::map(const QRegion &r) const
1517{
1518 TransformationType t = inline_type();
1519 if (t == TxNone)
1520 return r;
1521
1522 if (t == TxTranslate) {
1523 QRegion copy(r);
1524 copy.translate(qRound(affine._dx), qRound(affine._dy));
1525 return copy;
1526 }
1527
1528 if (t == TxScale) {
1529 QRegion res;
1530 if (m11() < 0 || m22() < 0) {
1531 for (const QRect &rect : r)
1532 res += mapRect(rect);
1533 } else {
1534 QVarLengthArray<QRect, 32> rects;
1535 rects.reserve(r.rectCount());
1536 for (const QRect &rect : r) {
1537 QRect nr = mapRect(rect);
1538 if (!nr.isEmpty())
1539 rects.append(nr);
1540 }
1541 res.setRects(rects.constData(), rects.count());
1542 }
1543 return res;
1544 }
1545
1546 QPainterPath p = map(qt_regionToPath(r));
1547 return p.toFillPolygon(QTransform()).toPolygon();
1548}
1549
1550struct QHomogeneousCoordinate
1551{
1552 qreal x;
1553 qreal y;
1554 qreal w;
1555
1556 QHomogeneousCoordinate() {}
1557 QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_) : x(x_), y(y_), w(w_) {}
1558
1559 const QPointF toPoint() const {
1560 qreal iw = 1. / w;
1561 return QPointF(x * iw, y * iw);
1562 }
1563};
1564
1565static inline QHomogeneousCoordinate mapHomogeneous(const QTransform &transform, const QPointF &p)
1566{
1567 QHomogeneousCoordinate c;
1568 c.x = transform.m11() * p.x() + transform.m21() * p.y() + transform.m31();
1569 c.y = transform.m12() * p.x() + transform.m22() * p.y() + transform.m32();
1570 c.w = transform.m13() * p.x() + transform.m23() * p.y() + transform.m33();
1571 return c;
1572}
1573
1574static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b,
1575 bool needsMoveTo, bool needsLineTo = true)
1576{
1577 QHomogeneousCoordinate ha = mapHomogeneous(transform, a);
1578 QHomogeneousCoordinate hb = mapHomogeneous(transform, b);
1579
1580 if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP)
1581 return false;
1582
1583 if (hb.w < Q_NEAR_CLIP) {
1584 const qreal t = (Q_NEAR_CLIP - hb.w) / (ha.w - hb.w);
1585
1586 hb.x += (ha.x - hb.x) * t;
1587 hb.y += (ha.y - hb.y) * t;
1588 hb.w = qreal(Q_NEAR_CLIP);
1589 } else if (ha.w < Q_NEAR_CLIP) {
1590 const qreal t = (Q_NEAR_CLIP - ha.w) / (hb.w - ha.w);
1591
1592 ha.x += (hb.x - ha.x) * t;
1593 ha.y += (hb.y - ha.y) * t;
1594 ha.w = qreal(Q_NEAR_CLIP);
1595
1596 const QPointF p = ha.toPoint();
1597 if (needsMoveTo) {
1598 path.moveTo(p);
1599 needsMoveTo = false;
1600 } else {
1601 path.lineTo(p);
1602 }
1603 }
1604
1605 if (needsMoveTo)
1606 path.moveTo(ha.toPoint());
1607
1608 if (needsLineTo)
1609 path.lineTo(hb.toPoint());
1610
1611 return true;
1612}
1613Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
1614
1615static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
1616{
1617 // Convert projective xformed curves to line
1618 // segments so they can be transformed more accurately
1619
1620 qreal scale;
1621 qt_scaleForTransform(transform, &scale);
1622
1623 qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
1624
1625 QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(curveThreshold);
1626
1627 for (int i = 0; i < segment.size() - 1; ++i)
1628 if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo))
1629 needsMoveTo = false;
1630
1631 return !needsMoveTo;
1632}
1633
1634static QPainterPath mapProjective(const QTransform &transform, const QPainterPath &path)
1635{
1636 QPainterPath result;
1637
1638 QPointF last;
1639 QPointF lastMoveTo;
1640 bool needsMoveTo = true;
1641 for (int i = 0; i < path.elementCount(); ++i) {
1642 switch (path.elementAt(i).type) {
1643 case QPainterPath::MoveToElement:
1644 if (i > 0 && lastMoveTo != last)
1645 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo);
1646
1647 lastMoveTo = path.elementAt(i);
1648 last = path.elementAt(i);
1649 needsMoveTo = true;
1650 break;
1651 case QPainterPath::LineToElement:
1652 if (lineTo_clipped(result, transform, last, path.elementAt(i), needsMoveTo))
1653 needsMoveTo = false;
1654 last = path.elementAt(i);
1655 break;
1656 case QPainterPath::CurveToElement:
1657 if (cubicTo_clipped(result, transform, last, path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), needsMoveTo))
1658 needsMoveTo = false;
1659 i += 2;
1660 last = path.elementAt(i);
1661 break;
1662 default:
1663 Q_ASSERT(false);
1664 }
1665 }
1666
1667 if (path.elementCount() > 0 && lastMoveTo != last)
1668 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false);
1669
1670 result.setFillRule(path.fillRule());
1671 return result;
1672}
1673
1674/*!
1675 \fn QPainterPath operator *(const QPainterPath &path, const QTransform &matrix)
1676 \since 4.3
1677 \relates QTransform
1678
1679 This is the same as \a{matrix}.map(\a{path}).
1680
1681 \sa QTransform::map()
1682*/
1683
1684/*!
1685 \overload
1686
1687 Creates and returns a QPainterPath object that is a copy of the
1688 given \a path, mapped into the coordinate system defined by this
1689 matrix.
1690*/
1691QPainterPath QTransform::map(const QPainterPath &path) const
1692{
1693 TransformationType t = inline_type();
1694 if (t == TxNone || path.elementCount() == 0)
1695 return path;
1696
1697 if (t >= TxProject)
1698 return mapProjective(*this, path);
1699
1700 QPainterPath copy = path;
1701
1702 if (t == TxTranslate) {
1703 copy.translate(affine._dx, affine._dy);
1704 } else {
1705 copy.detach();
1706 // Full xform
1707 for (int i=0; i<path.elementCount(); ++i) {
1708 QPainterPath::Element &e = copy.d_ptr->elements[i];
1709 MAP(e.x, e.y, e.x, e.y);
1710 }
1711 }
1712
1713 return copy;
1714}
1715
1716/*!
1717 \fn QPolygon QTransform::mapToPolygon(const QRect &rectangle) const
1718
1719 Creates and returns a QPolygon representation of the given \a
1720 rectangle, mapped into the coordinate system defined by this
1721 matrix.
1722
1723 The rectangle's coordinates are transformed using the following
1724 formulas:
1725
1726 \snippet code/src_gui_painting_qtransform.cpp 1
1727
1728 Polygons and rectangles behave slightly differently when
1729 transformed (due to integer rounding), so
1730 \c{matrix.map(QPolygon(rectangle))} is not always the same as
1731 \c{matrix.mapToPolygon(rectangle)}.
1732
1733 \sa mapRect(), {QTransform#Basic Matrix Operations}{Basic Matrix
1734 Operations}
1735*/
1736QPolygon QTransform::mapToPolygon(const QRect &rect) const
1737{
1738 TransformationType t = inline_type();
1739
1740 QPolygon a(4);
1741 qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
1742 if (t <= TxScale) {
1743 x[0] = affine._m11*rect.x() + affine._dx;
1744 y[0] = affine._m22*rect.y() + affine._dy;
1745 qreal w = affine._m11*rect.width();
1746 qreal h = affine._m22*rect.height();
1747 if (w < 0) {
1748 w = -w;
1749 x[0] -= w;
1750 }
1751 if (h < 0) {
1752 h = -h;
1753 y[0] -= h;
1754 }
1755 x[1] = x[0]+w;
1756 x[2] = x[1];
1757 x[3] = x[0];
1758 y[1] = y[0];
1759 y[2] = y[0]+h;
1760 y[3] = y[2];
1761 } else {
1762 qreal right = rect.x() + rect.width();
1763 qreal bottom = rect.y() + rect.height();
1764 MAP(rect.x(), rect.y(), x[0], y[0]);
1765 MAP(right, rect.y(), x[1], y[1]);
1766 MAP(right, bottom, x[2], y[2]);
1767 MAP(rect.x(), bottom, x[3], y[3]);
1768 }
1769
1770 // all coordinates are correctly, tranform to a pointarray
1771 // (rounding to the next integer)
1772 a.setPoints(4, qRound(x[0]), qRound(y[0]),
1773 qRound(x[1]), qRound(y[1]),
1774 qRound(x[2]), qRound(y[2]),
1775 qRound(x[3]), qRound(y[3]));
1776 return a;
1777}
1778
1779/*!
1780 Creates a transformation matrix, \a trans, that maps a unit square
1781 to a four-sided polygon, \a quad. Returns \c true if the transformation
1782 is constructed or false if such a transformation does not exist.
1783
1784 \sa quadToSquare(), quadToQuad()
1785*/
1786bool QTransform::squareToQuad(const QPolygonF &quad, QTransform &trans)
1787{
1788 if (quad.count() != 4)
1789 return false;
1790
1791 qreal dx0 = quad[0].x();
1792 qreal dx1 = quad[1].x();
1793 qreal dx2 = quad[2].x();
1794 qreal dx3 = quad[3].x();
1795
1796 qreal dy0 = quad[0].y();
1797 qreal dy1 = quad[1].y();
1798 qreal dy2 = quad[2].y();
1799 qreal dy3 = quad[3].y();
1800
1801 double ax = dx0 - dx1 + dx2 - dx3;
1802 double ay = dy0 - dy1 + dy2 - dy3;
1803
1804 if (!ax && !ay) { //afine transform
1805 trans.setMatrix(dx1 - dx0, dy1 - dy0, 0,
1806 dx2 - dx1, dy2 - dy1, 0,
1807 dx0, dy0, 1);
1808 } else {
1809 double ax1 = dx1 - dx2;
1810 double ax2 = dx3 - dx2;
1811 double ay1 = dy1 - dy2;
1812 double ay2 = dy3 - dy2;
1813
1814 /*determinants */
1815 double gtop = ax * ay2 - ax2 * ay;
1816 double htop = ax1 * ay - ax * ay1;
1817 double bottom = ax1 * ay2 - ax2 * ay1;
1818
1819 double a, b, c, d, e, f, g, h; /*i is always 1*/
1820
1821 if (!bottom)
1822 return false;
1823
1824 g = gtop/bottom;
1825 h = htop/bottom;
1826
1827 a = dx1 - dx0 + g * dx1;
1828 b = dx3 - dx0 + h * dx3;
1829 c = dx0;
1830 d = dy1 - dy0 + g * dy1;
1831 e = dy3 - dy0 + h * dy3;
1832 f = dy0;
1833
1834 trans.setMatrix(a, d, g,
1835 b, e, h,
1836 c, f, 1.0);
1837 }
1838
1839 return true;
1840}
1841
1842/*!
1843 \fn bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1844
1845 Creates a transformation matrix, \a trans, that maps a four-sided polygon,
1846 \a quad, to a unit square. Returns \c true if the transformation is constructed
1847 or false if such a transformation does not exist.
1848
1849 \sa squareToQuad(), quadToQuad()
1850*/
1851bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1852{
1853 if (!squareToQuad(quad, trans))
1854 return false;
1855
1856 bool invertible = false;
1857 trans = trans.inverted(&invertible);
1858
1859 return invertible;
1860}
1861
1862/*!
1863 Creates a transformation matrix, \a trans, that maps a four-sided
1864 polygon, \a one, to another four-sided polygon, \a two.
1865 Returns \c true if the transformation is possible; otherwise returns
1866 false.
1867
1868 This is a convenience method combining quadToSquare() and
1869 squareToQuad() methods. It allows the input quad to be
1870 transformed into any other quad.
1871
1872 \sa squareToQuad(), quadToSquare()
1873*/
1874bool QTransform::quadToQuad(const QPolygonF &one,
1875 const QPolygonF &two,
1876 QTransform &trans)
1877{
1878 QTransform stq;
1879 if (!quadToSquare(one, trans))
1880 return false;
1881 if (!squareToQuad(two, stq))
1882 return false;
1883 trans *= stq;
1884 //qDebug()<<"Final = "<<trans;
1885 return true;
1886}
1887
1888/*!
1889 Sets the matrix elements to the specified values, \a m11,
1890 \a m12, \a m13 \a m21, \a m22, \a m23 \a m31, \a m32 and
1891 \a m33. Note that this function replaces the previous values.
1892 QTransform provides the translate(), rotate(), scale() and shear()
1893 convenience functions to manipulate the various matrix elements
1894 based on the currently defined coordinate system.
1895
1896 \sa QTransform()
1897*/
1898
1899void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
1900 qreal m21, qreal m22, qreal m23,
1901 qreal m31, qreal m32, qreal m33)
1902{
1903 affine._m11 = m11; affine._m12 = m12; m_13 = m13;
1904 affine._m21 = m21; affine._m22 = m22; m_23 = m23;
1905 affine._dx = m31; affine._dy = m32; m_33 = m33;
1906 m_type = TxNone;
1907 m_dirty = TxProject;
1908}
1909
1910static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
1911{
1912 const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
1913 const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
1914
1915 return wx + wy + transform.m33() < Q_NEAR_CLIP;
1916}
1917
1918QRect QTransform::mapRect(const QRect &rect) const
1919{
1920 TransformationType t = inline_type();
1921 if (t <= TxTranslate)
1922 return rect.translated(qRound(affine._dx), qRound(affine._dy));
1923
1924 if (t <= TxScale) {
1925 int x = qRound(affine._m11*rect.x() + affine._dx);
1926 int y = qRound(affine._m22*rect.y() + affine._dy);
1927 int w = qRound(affine._m11*rect.width());
1928 int h = qRound(affine._m22*rect.height());
1929 if (w < 0) {
1930 w = -w;
1931 x -= w;
1932 }
1933 if (h < 0) {
1934 h = -h;
1935 y -= h;
1936 }
1937 return QRect(x, y, w, h);
1938 } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
1939 // see mapToPolygon for explanations of the algorithm.
1940 qreal x = 0, y = 0;
1941 MAP(rect.left(), rect.top(), x, y);
1942 qreal xmin = x;
1943 qreal ymin = y;
1944 qreal xmax = x;
1945 qreal ymax = y;
1946 MAP(rect.right() + 1, rect.top(), x, y);
1947 xmin = qMin(xmin, x);
1948 ymin = qMin(ymin, y);
1949 xmax = qMax(xmax, x);
1950 ymax = qMax(ymax, y);
1951 MAP(rect.right() + 1, rect.bottom() + 1, x, y);
1952 xmin = qMin(xmin, x);
1953 ymin = qMin(ymin, y);
1954 xmax = qMax(xmax, x);
1955 ymax = qMax(ymax, y);
1956 MAP(rect.left(), rect.bottom() + 1, x, y);
1957 xmin = qMin(xmin, x);
1958 ymin = qMin(ymin, y);
1959 xmax = qMax(xmax, x);
1960 ymax = qMax(ymax, y);
1961 return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
1962 } else {
1963 QPainterPath path;
1964 path.addRect(rect);
1965 return map(path).boundingRect().toRect();
1966 }
1967}
1968
1969/*!
1970 \fn QRectF QTransform::mapRect(const QRectF &rectangle) const
1971
1972 Creates and returns a QRectF object that is a copy of the given \a
1973 rectangle, mapped into the coordinate system defined by this
1974 matrix.
1975
1976 The rectangle's coordinates are transformed using the following
1977 formulas:
1978
1979 \snippet code/src_gui_painting_qtransform.cpp 2
1980
1981 If rotation or shearing has been specified, this function returns
1982 the \e bounding rectangle. To retrieve the exact region the given
1983 \a rectangle maps to, use the mapToPolygon() function instead.
1984
1985 \sa mapToPolygon(), {QTransform#Basic Matrix Operations}{Basic Matrix
1986 Operations}
1987*/
1988QRectF QTransform::mapRect(const QRectF &rect) const
1989{
1990 TransformationType t = inline_type();
1991 if (t <= TxTranslate)
1992 return rect.translated(affine._dx, affine._dy);
1993
1994 if (t <= TxScale) {
1995 qreal x = affine._m11*rect.x() + affine._dx;
1996 qreal y = affine._m22*rect.y() + affine._dy;
1997 qreal w = affine._m11*rect.width();
1998 qreal h = affine._m22*rect.height();
1999 if (w < 0) {
2000 w = -w;
2001 x -= w;
2002 }
2003 if (h < 0) {
2004 h = -h;
2005 y -= h;
2006 }
2007 return QRectF(x, y, w, h);
2008 } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
2009 qreal x = 0, y = 0;
2010 MAP(rect.x(), rect.y(), x, y);
2011 qreal xmin = x;
2012 qreal ymin = y;
2013 qreal xmax = x;
2014 qreal ymax = y;
2015 MAP(rect.x() + rect.width(), rect.y(), x, y);
2016 xmin = qMin(xmin, x);
2017 ymin = qMin(ymin, y);
2018 xmax = qMax(xmax, x);
2019 ymax = qMax(ymax, y);
2020 MAP(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
2021 xmin = qMin(xmin, x);
2022 ymin = qMin(ymin, y);
2023 xmax = qMax(xmax, x);
2024 ymax = qMax(ymax, y);
2025 MAP(rect.x(), rect.y() + rect.height(), x, y);
2026 xmin = qMin(xmin, x);
2027 ymin = qMin(ymin, y);
2028 xmax = qMax(xmax, x);
2029 ymax = qMax(ymax, y);
2030 return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
2031 } else {
2032 QPainterPath path;
2033 path.addRect(rect);
2034 return map(path).boundingRect();
2035 }
2036}
2037
2038/*!
2039 \fn QRect QTransform::mapRect(const QRect &rectangle) const
2040 \overload
2041
2042 Creates and returns a QRect object that is a copy of the given \a
2043 rectangle, mapped into the coordinate system defined by this
2044 matrix. Note that the transformed coordinates are rounded to the
2045 nearest integer.
2046*/
2047
2048/*!
2049 Maps the given coordinates \a x and \a y into the coordinate
2050 system defined by this matrix. The resulting values are put in *\a
2051 tx and *\a ty, respectively.
2052
2053 The coordinates are transformed using the following formulas:
2054
2055 \snippet code/src_gui_painting_qtransform.cpp 3
2056
2057 The point (x, y) is the original point, and (x', y') is the
2058 transformed point.
2059
2060 \sa {QTransform#Basic Matrix Operations}{Basic Matrix Operations}
2061*/
2062void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
2063{
2064 TransformationType t = inline_type();
2065 MAP(x, y, *tx, *ty);
2066}
2067
2068/*!
2069 \overload
2070
2071 Maps the given coordinates \a x and \a y into the coordinate
2072 system defined by this matrix. The resulting values are put in *\a
2073 tx and *\a ty, respectively. Note that the transformed coordinates
2074 are rounded to the nearest integer.
2075*/
2076void QTransform::map(int x, int y, int *tx, int *ty) const
2077{
2078 TransformationType t = inline_type();
2079 qreal fx = 0, fy = 0;
2080 MAP(x, y, fx, fy);
2081 *tx = qRound(fx);
2082 *ty = qRound(fy);
2083}
2084
2085/*!
2086 Returns the QTransform as an affine matrix.
2087
2088 \warning If a perspective transformation has been specified,
2089 then the conversion will cause loss of data.
2090*/
2091const QMatrix &QTransform::toAffine() const
2092{
2093 return affine;
2094}
2095
2096/*!
2097 Returns the transformation type of this matrix.
2098
2099 The transformation type is the highest enumeration value
2100 capturing all of the matrix's transformations. For example,
2101 if the matrix both scales and shears, the type would be \c TxShear,
2102 because \c TxShear has a higher enumeration value than \c TxScale.
2103
2104 Knowing the transformation type of a matrix is useful for optimization:
2105 you can often handle specific types more optimally than handling
2106 the generic case.
2107 */
2108QTransform::TransformationType QTransform::type() const
2109{
2110 if(m_dirty == TxNone || m_dirty < m_type)
2111 return static_cast<TransformationType>(m_type);
2112
2113 switch (static_cast<TransformationType>(m_dirty)) {
2114 case TxProject:
2115 if (!qFuzzyIsNull(m_13) || !qFuzzyIsNull(m_23) || !qFuzzyIsNull(m_33 - 1)) {
2116 m_type = TxProject;
2117 break;
2118 }
2119 Q_FALLTHROUGH();
2120 case TxShear:
2121 case TxRotate:
2122 if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) {
2123 const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22;
2124 if (qFuzzyIsNull(dot))
2125 m_type = TxRotate;
2126 else
2127 m_type = TxShear;
2128 break;
2129 }
2130 Q_FALLTHROUGH();
2131 case TxScale:
2132 if (!qFuzzyIsNull(affine._m11 - 1) || !qFuzzyIsNull(affine._m22 - 1)) {
2133 m_type = TxScale;
2134 break;
2135 }
2136 Q_FALLTHROUGH();
2137 case TxTranslate:
2138 if (!qFuzzyIsNull(affine._dx) || !qFuzzyIsNull(affine._dy)) {
2139 m_type = TxTranslate;
2140 break;
2141 }
2142 Q_FALLTHROUGH();
2143 case TxNone:
2144 m_type = TxNone;
2145 break;
2146 }
2147
2148 m_dirty = TxNone;
2149 return static_cast<TransformationType>(m_type);
2150}
2151
2152/*!
2153
2154 Returns the transform as a QVariant.
2155*/
2156QTransform::operator QVariant() const
2157{
2158 return QVariant(QVariant::Transform, this);
2159}
2160
2161
2162/*!
2163 \fn bool QTransform::isInvertible() const
2164
2165 Returns \c true if the matrix is invertible, otherwise returns \c false.
2166
2167 \sa inverted()
2168*/
2169
2170#if QT_DEPRECATED_SINCE(5, 13)
2171/*!
2172 \fn qreal QTransform::det() const
2173 \obsolete
2174
2175 Returns the matrix's determinant. Use determinant() instead.
2176*/
2177#endif
2178
2179/*!
2180 \fn qreal QTransform::m11() const
2181
2182 Returns the horizontal scaling factor.
2183
2184 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
2185 Operations}
2186*/
2187
2188/*!
2189 \fn qreal QTransform::m12() const
2190
2191 Returns the vertical shearing factor.
2192
2193 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
2194 Operations}
2195*/
2196
2197/*!
2198 \fn qreal QTransform::m21() const
2199
2200 Returns the horizontal shearing factor.
2201
2202 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
2203 Operations}
2204*/
2205
2206/*!
2207 \fn qreal QTransform::m22() const
2208
2209 Returns the vertical scaling factor.
2210
2211 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
2212 Operations}
2213*/
2214
2215/*!
2216 \fn qreal QTransform::dx() const
2217
2218 Returns the horizontal translation factor.
2219
2220 \sa m31(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2221 Operations}
2222*/
2223
2224/*!
2225 \fn qreal QTransform::dy() const
2226
2227 Returns the vertical translation factor.
2228
2229 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2230 Operations}
2231*/
2232
2233
2234/*!
2235 \fn qreal QTransform::m13() const
2236
2237 Returns the horizontal projection factor.
2238
2239 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2240 Operations}
2241*/
2242
2243
2244/*!
2245 \fn qreal QTransform::m23() const
2246
2247 Returns the vertical projection factor.
2248
2249 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2250 Operations}
2251*/
2252
2253/*!
2254 \fn qreal QTransform::m31() const
2255
2256 Returns the horizontal translation factor.
2257
2258 \sa dx(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2259 Operations}
2260*/
2261
2262/*!
2263 \fn qreal QTransform::m32() const
2264
2265 Returns the vertical translation factor.
2266
2267 \sa dy(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2268 Operations}
2269*/
2270
2271/*!
2272 \fn qreal QTransform::m33() const
2273
2274 Returns the division factor.
2275
2276 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2277 Operations}
2278*/
2279
2280/*!
2281 \fn qreal QTransform::determinant() const
2282
2283 Returns the matrix's determinant.
2284*/
2285
2286/*!
2287 \fn bool QTransform::isIdentity() const
2288
2289 Returns \c true if the matrix is the identity matrix, otherwise
2290 returns \c false.
2291
2292 \sa reset()
2293*/
2294
2295/*!
2296 \fn bool QTransform::isAffine() const
2297
2298 Returns \c true if the matrix represent an affine transformation,
2299 otherwise returns \c false.
2300*/
2301
2302/*!
2303 \fn bool QTransform::isScaling() const
2304
2305 Returns \c true if the matrix represents a scaling
2306 transformation, otherwise returns \c false.
2307
2308 \sa reset()
2309*/
2310
2311/*!
2312 \fn bool QTransform::isRotating() const
2313
2314 Returns \c true if the matrix represents some kind of a
2315 rotating transformation, otherwise returns \c false.
2316
2317 \note A rotation transformation of 180 degrees and/or 360 degrees is treated as a scaling transformation.
2318
2319 \sa reset()
2320*/
2321
2322/*!
2323 \fn bool QTransform::isTranslating() const
2324
2325 Returns \c true if the matrix represents a translating
2326 transformation, otherwise returns \c false.
2327
2328 \sa reset()
2329*/
2330
2331/*!
2332 \fn bool qFuzzyCompare(const QTransform& t1, const QTransform& t2)
2333
2334 \relates QTransform
2335 \since 4.6
2336
2337 Returns \c true if \a t1 and \a t2 are equal, allowing for a small
2338 fuzziness factor for floating-point comparisons; false otherwise.
2339*/
2340
2341
2342// returns true if the transform is uniformly scaling
2343// (same scale in x and y direction)
2344// scale is set to the max of x and y scaling factors
2345Q_GUI_EXPORT
2346bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
2347{
2348 const QTransform::TransformationType type = transform.type();
2349 if (type <= QTransform::TxTranslate) {
2350 if (scale)
2351 *scale = 1;
2352 return true;
2353 } else if (type == QTransform::TxScale) {
2354 const qreal xScale = qAbs(transform.m11());
2355 const qreal yScale = qAbs(transform.m22());
2356 if (scale)
2357 *scale = qMax(xScale, yScale);
2358 return qFuzzyCompare(xScale, yScale);
2359 }
2360
2361 // rotate then scale: compare columns
2362 const qreal xScale1 = transform.m11() * transform.m11()
2363 + transform.m21() * transform.m21();
2364 const qreal yScale1 = transform.m12() * transform.m12()
2365 + transform.m22() * transform.m22();
2366
2367 // scale then rotate: compare rows
2368 const qreal xScale2 = transform.m11() * transform.m11()
2369 + transform.m12() * transform.m12();
2370 const qreal yScale2 = transform.m21() * transform.m21()
2371 + transform.m22() * transform.m22();
2372
2373 // decide the order of rotate and scale operations
2374 if (qAbs(xScale1 - yScale1) > qAbs(xScale2 - yScale2)) {
2375 if (scale)
2376 *scale = qSqrt(qMax(xScale1, yScale1));
2377
2378 return type == QTransform::TxRotate && qFuzzyCompare(xScale1, yScale1);
2379 } else {
2380 if (scale)
2381 *scale = qSqrt(qMax(xScale2, yScale2));
2382
2383 return type == QTransform::TxRotate && qFuzzyCompare(xScale2, yScale2);
2384 }
2385}
2386
2387QT_END_NAMESPACE
2388