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