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

source code of qtbase/src/gui/painting/qtransform.cpp