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