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

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