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 \qhashold{QTransform}
788*/
789size_t qHash(const QTransform &key, size_t seed) noexcept
790{
791 QtPrivate::QHashCombine hash;
792 seed = hash(seed, key.m11());
793 seed = hash(seed, key.m12());
794 seed = hash(seed, key.m21());
795 seed = hash(seed, key.m22());
796 seed = hash(seed, key.dx());
797 seed = hash(seed, key.dy());
798 seed = hash(seed, key.m13());
799 seed = hash(seed, key.m23());
800 seed = hash(seed, key.m33());
801 return seed;
802}
803
804
805/*!
806 \fn bool QTransform::operator!=(const QTransform &matrix) const
807 Returns \c true if this matrix is not equal to the given \a matrix,
808 otherwise returns \c false.
809*/
810bool QTransform::operator!=(const QTransform &o) const
811{
812 return !operator==(o);
813}
814
815/*!
816 \fn QTransform & QTransform::operator*=(const QTransform &matrix)
817 \overload
818
819 Returns the result of multiplying this matrix by the given \a
820 matrix.
821*/
822QTransform & QTransform::operator*=(const QTransform &o)
823{
824 const TransformationType otherType = o.inline_type();
825 if (otherType == TxNone)
826 return *this;
827
828 const TransformationType thisType = inline_type();
829 if (thisType == TxNone)
830 return operator=(o);
831
832 TransformationType t = qMax(a: thisType, b: otherType);
833 switch(t) {
834 case TxNone:
835 break;
836 case TxTranslate:
837 m_matrix[2][0] += o.m_matrix[2][0];
838 m_matrix[2][1] += o.m_matrix[2][1];
839 break;
840 case TxScale:
841 {
842 qreal m11 = m_matrix[0][0] * o.m_matrix[0][0];
843 qreal m22 = m_matrix[1][1] * o.m_matrix[1][1];
844
845 qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + o.m_matrix[2][0];
846 qreal m32 = m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1];
847
848 m_matrix[0][0] = m11;
849 m_matrix[1][1] = m22;
850 m_matrix[2][0] = m31; m_matrix[2][1] = m32;
851 break;
852 }
853 case TxRotate:
854 case TxShear:
855 {
856 qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0];
857 qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1];
858
859 qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0];
860 qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1];
861
862 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];
863 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];
864
865 m_matrix[0][0] = m11;
866 m_matrix[0][1] = m12;
867 m_matrix[1][0] = m21;
868 m_matrix[1][1] = m22;
869 m_matrix[2][0] = m31;
870 m_matrix[2][1] = m32;
871 break;
872 }
873 case TxProject:
874 {
875 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];
876 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];
877 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];
878
879 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];
880 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];
881 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];
882
883 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];
884 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];
885 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];
886
887 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
888 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
889 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
890 }
891 }
892
893 m_dirty = t;
894 m_type = t;
895
896 return *this;
897}
898
899/*!
900 \fn QTransform QTransform::operator*(const QTransform &matrix) const
901 Returns the result of multiplying this matrix by the given \a
902 matrix.
903
904 Note that matrix multiplication is not commutative, i.e. a*b !=
905 b*a.
906*/
907QTransform QTransform::operator*(const QTransform &m) const
908{
909 const TransformationType otherType = m.inline_type();
910 if (otherType == TxNone)
911 return *this;
912
913 const TransformationType thisType = inline_type();
914 if (thisType == TxNone)
915 return m;
916
917 QTransform t;
918 TransformationType type = qMax(a: thisType, b: otherType);
919 switch(type) {
920 case TxNone:
921 break;
922 case TxTranslate:
923 t.m_matrix[2][0] = m_matrix[2][0] + m.m_matrix[2][0];
924 t.m_matrix[2][1] = m_matrix[2][1] + m.m_matrix[2][1];
925 break;
926 case TxScale:
927 {
928 qreal m11 = m_matrix[0][0] * m.m_matrix[0][0];
929 qreal m22 = m_matrix[1][1] * m.m_matrix[1][1];
930
931 qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m.m_matrix[2][0];
932 qreal m32 = m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1];
933
934 t.m_matrix[0][0] = m11;
935 t.m_matrix[1][1] = m22;
936 t.m_matrix[2][0] = m31;
937 t.m_matrix[2][1] = m32;
938 break;
939 }
940 case TxRotate:
941 case TxShear:
942 {
943 qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0];
944 qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1];
945
946 qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0];
947 qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1];
948
949 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];
950 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];
951
952 t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12;
953 t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22;
954 t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32;
955 break;
956 }
957 case TxProject:
958 {
959 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];
960 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];
961 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];
962
963 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];
964 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];
965 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];
966
967 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];
968 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];
969 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];
970
971 t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12; t.m_matrix[0][2] = m13;
972 t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22; t.m_matrix[1][2] = m23;
973 t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32; t.m_matrix[2][2] = m33;
974 }
975 }
976
977 t.m_dirty = type;
978 t.m_type = type;
979
980 return t;
981}
982
983/*!
984 \fn QTransform & QTransform::operator*=(qreal scalar)
985 \overload
986
987 Returns the result of performing an element-wise multiplication of this
988 matrix with the given \a scalar.
989*/
990
991/*!
992 \fn QTransform & QTransform::operator/=(qreal scalar)
993 \overload
994
995 Returns the result of performing an element-wise division of this
996 matrix by the given \a scalar.
997*/
998
999/*!
1000 \fn QTransform & QTransform::operator+=(qreal scalar)
1001 \overload
1002
1003 Returns the matrix obtained by adding the given \a scalar to each
1004 element of this matrix.
1005*/
1006
1007/*!
1008 \fn QTransform & QTransform::operator-=(qreal scalar)
1009 \overload
1010
1011 Returns the matrix obtained by subtracting the given \a scalar from each
1012 element of this matrix.
1013*/
1014
1015/*!
1016 \fn QTransform &QTransform::operator=(const QTransform &matrix) noexcept
1017
1018 Assigns the given \a matrix's values to this matrix.
1019*/
1020
1021/*!
1022 Resets the matrix to an identity matrix, i.e. all elements are set
1023 to zero, except \c m11 and \c m22 (specifying the scale) and \c m33
1024 which are set to 1.
1025
1026 \sa QTransform(), isIdentity(), {QTransform#Basic Matrix
1027 Operations}{Basic Matrix Operations}
1028*/
1029void QTransform::reset()
1030{
1031 *this = QTransform();
1032}
1033
1034#ifndef QT_NO_DATASTREAM
1035/*!
1036 \fn QDataStream &operator<<(QDataStream &stream, const QTransform &matrix)
1037 \since 4.3
1038 \relates QTransform
1039
1040 Writes the given \a matrix to the given \a stream and returns a
1041 reference to the stream.
1042
1043 \sa {Serializing Qt Data Types}
1044*/
1045QDataStream & operator<<(QDataStream &s, const QTransform &m)
1046{
1047 s << double(m.m11())
1048 << double(m.m12())
1049 << double(m.m13())
1050 << double(m.m21())
1051 << double(m.m22())
1052 << double(m.m23())
1053 << double(m.m31())
1054 << double(m.m32())
1055 << double(m.m33());
1056 return s;
1057}
1058
1059/*!
1060 \fn QDataStream &operator>>(QDataStream &stream, QTransform &matrix)
1061 \since 4.3
1062 \relates QTransform
1063
1064 Reads the given \a matrix from the given \a stream and returns a
1065 reference to the stream.
1066
1067 \sa {Serializing Qt Data Types}
1068*/
1069QDataStream & operator>>(QDataStream &s, QTransform &t)
1070{
1071 double m11, m12, m13,
1072 m21, m22, m23,
1073 m31, m32, m33;
1074
1075 s >> m11;
1076 s >> m12;
1077 s >> m13;
1078 s >> m21;
1079 s >> m22;
1080 s >> m23;
1081 s >> m31;
1082 s >> m32;
1083 s >> m33;
1084 t.setMatrix(m11, m12, m13,
1085 m21, m22, m23,
1086 m31, m32, m33);
1087 return s;
1088}
1089
1090#endif // QT_NO_DATASTREAM
1091
1092#ifndef QT_NO_DEBUG_STREAM
1093QDebug operator<<(QDebug dbg, const QTransform &m)
1094{
1095 static const char typeStr[][12] =
1096 {
1097 "TxNone",
1098 "TxTranslate",
1099 "TxScale",
1100 "",
1101 "TxRotate",
1102 "", "", "",
1103 "TxShear",
1104 "", "", "", "", "", "", "",
1105 "TxProject"
1106 };
1107
1108 QDebugStateSaver saver(dbg);
1109 dbg.nospace() << "QTransform(type=" << typeStr[m.type()] << ','
1110 << " 11=" << m.m11()
1111 << " 12=" << m.m12()
1112 << " 13=" << m.m13()
1113 << " 21=" << m.m21()
1114 << " 22=" << m.m22()
1115 << " 23=" << m.m23()
1116 << " 31=" << m.m31()
1117 << " 32=" << m.m32()
1118 << " 33=" << m.m33()
1119 << ')';
1120
1121 return dbg;
1122}
1123#endif
1124
1125/*!
1126 \fn QPoint operator*(const QPoint &point, const QTransform &matrix)
1127 \relates QTransform
1128
1129 This is the same as \a{matrix}.map(\a{point}).
1130
1131 \sa QTransform::map()
1132*/
1133QPoint QTransform::map(const QPoint &p) const
1134{
1135 qreal fx = p.x();
1136 qreal fy = p.y();
1137
1138 qreal x = 0, y = 0;
1139
1140 do_map(x: fx, y: fy, nx&: x, ny&: y);
1141
1142 return QPoint(qRound(d: x), qRound(d: y));
1143}
1144
1145
1146/*!
1147 \fn QPointF operator*(const QPointF &point, const QTransform &matrix)
1148 \relates QTransform
1149
1150 Same as \a{matrix}.map(\a{point}).
1151
1152 \sa QTransform::map()
1153*/
1154
1155/*!
1156 \overload
1157
1158 Creates and returns a QPointF object that is a copy of the given point,
1159 \a p, mapped into the coordinate system defined by this matrix.
1160*/
1161QPointF QTransform::map(const QPointF &p) const
1162{
1163 qreal fx = p.x();
1164 qreal fy = p.y();
1165
1166 qreal x = 0, y = 0;
1167
1168 do_map(x: fx, y: fy, nx&: x, ny&: y);
1169
1170 return QPointF(x, y);
1171}
1172
1173/*!
1174 \fn QPoint QTransform::map(const QPoint &point) const
1175 \overload
1176
1177 Creates and returns a QPoint object that is a copy of the given \a
1178 point, mapped into the coordinate system defined by this
1179 matrix. Note that the transformed coordinates are rounded to the
1180 nearest integer.
1181*/
1182
1183/*!
1184 \fn QLineF operator*(const QLineF &line, const QTransform &matrix)
1185 \relates QTransform
1186
1187 This is the same as \a{matrix}.map(\a{line}).
1188
1189 \sa QTransform::map()
1190*/
1191
1192/*!
1193 \fn QLine operator*(const QLine &line, const QTransform &matrix)
1194 \relates QTransform
1195
1196 This is the same as \a{matrix}.map(\a{line}).
1197
1198 \sa QTransform::map()
1199*/
1200
1201/*!
1202 \overload
1203
1204 Creates and returns a QLineF object that is a copy of the given line,
1205 \a l, mapped into the coordinate system defined by this matrix.
1206*/
1207QLine QTransform::map(const QLine &l) const
1208{
1209 qreal fx1 = l.x1();
1210 qreal fy1 = l.y1();
1211 qreal fx2 = l.x2();
1212 qreal fy2 = l.y2();
1213
1214 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1215
1216 do_map(x: fx1, y: fy1, nx&: x1, ny&: y1);
1217 do_map(x: fx2, y: fy2, nx&: x2, ny&: y2);
1218
1219 return QLine(qRound(d: x1), qRound(d: y1), qRound(d: x2), qRound(d: y2));
1220}
1221
1222/*!
1223 \overload
1224
1225 \fn QLineF QTransform::map(const QLineF &line) const
1226
1227 Creates and returns a QLine object that is a copy of the given \a
1228 line, mapped into the coordinate system defined by this matrix.
1229 Note that the transformed coordinates are rounded to the nearest
1230 integer.
1231*/
1232
1233QLineF QTransform::map(const QLineF &l) const
1234{
1235 qreal fx1 = l.x1();
1236 qreal fy1 = l.y1();
1237 qreal fx2 = l.x2();
1238 qreal fy2 = l.y2();
1239
1240 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1241
1242 do_map(x: fx1, y: fy1, nx&: x1, ny&: y1);
1243 do_map(x: fx2, y: fy2, nx&: x2, ny&: y2);
1244
1245 return QLineF(x1, y1, x2, y2);
1246}
1247
1248/*!
1249 \fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix)
1250 \since 4.3
1251 \relates QTransform
1252
1253 This is the same as \a{matrix}.map(\a{polygon}).
1254
1255 \sa QTransform::map()
1256*/
1257
1258/*!
1259 \fn QPolygon operator*(const QPolygon &polygon, const QTransform &matrix)
1260 \relates QTransform
1261
1262 This is the same as \a{matrix}.map(\a{polygon}).
1263
1264 \sa QTransform::map()
1265*/
1266
1267/*!
1268 \fn QPolygonF QTransform::map(const QPolygonF &polygon) const
1269 \overload
1270
1271 Creates and returns a QPolygonF object that is a copy of the given
1272 \a polygon, mapped into the coordinate system defined by this
1273 matrix.
1274*/
1275QPolygonF QTransform::map(const QPolygonF &a) const
1276{
1277 TransformationType t = inline_type();
1278 if (t <= TxTranslate)
1279 return a.translated(dx: m_matrix[2][0], dy: m_matrix[2][1]);
1280
1281 int size = a.size();
1282 int i;
1283 QPolygonF p(size);
1284 const QPointF *da = a.constData();
1285 QPointF *dp = p.data();
1286
1287 for(i = 0; i < size; ++i) {
1288 do_map(x: da[i].xp, y: da[i].yp, nx&: dp[i].xp, ny&: dp[i].yp);
1289 }
1290 return p;
1291}
1292
1293/*!
1294 \fn QPolygon QTransform::map(const QPolygon &polygon) const
1295 \overload
1296
1297 Creates and returns a QPolygon object that is a copy of the given
1298 \a polygon, mapped into the coordinate system defined by this
1299 matrix. Note that the transformed coordinates are rounded to the
1300 nearest integer.
1301*/
1302QPolygon QTransform::map(const QPolygon &a) const
1303{
1304 TransformationType t = inline_type();
1305 if (t <= TxTranslate)
1306 return a.translated(dx: qRound(d: m_matrix[2][0]), dy: qRound(d: m_matrix[2][1]));
1307
1308 int size = a.size();
1309 int i;
1310 QPolygon p(size);
1311 const QPoint *da = a.constData();
1312 QPoint *dp = p.data();
1313
1314 for(i = 0; i < size; ++i) {
1315 qreal nx = 0, ny = 0;
1316 do_map(x: da[i].xp, y: da[i].yp, nx, ny);
1317 dp[i].xp = qRound(d: nx);
1318 dp[i].yp = qRound(d: ny);
1319 }
1320 return p;
1321}
1322
1323/*!
1324 \fn QRegion operator*(const QRegion &region, const QTransform &matrix)
1325 \relates QTransform
1326
1327 This is the same as \a{matrix}.map(\a{region}).
1328
1329 \sa QTransform::map()
1330*/
1331
1332extern QPainterPath qt_regionToPath(const QRegion &region);
1333
1334/*!
1335 \fn QRegion QTransform::map(const QRegion &region) const
1336 \overload
1337
1338 Creates and returns a QRegion object that is a copy of the given
1339 \a region, mapped into the coordinate system defined by this matrix.
1340
1341 Calling this method can be rather expensive if rotations or
1342 shearing are used.
1343*/
1344QRegion QTransform::map(const QRegion &r) const
1345{
1346 TransformationType t = inline_type();
1347 if (t == TxNone)
1348 return r;
1349
1350 if (t == TxTranslate) {
1351 QRegion copy(r);
1352 copy.translate(dx: qRound(d: m_matrix[2][0]), dy: qRound(d: m_matrix[2][1]));
1353 return copy;
1354 }
1355
1356 if (t == TxScale) {
1357 QRegion res;
1358 if (m11() < 0 || m22() < 0) {
1359 for (const QRect &rect : r)
1360 res += qt_mapFillRect(rect: QRectF(rect), xf: *this);
1361 } else {
1362 QVarLengthArray<QRect, 32> rects;
1363 rects.reserve(sz: r.rectCount());
1364 for (const QRect &rect : r) {
1365 QRect nr = qt_mapFillRect(rect: QRectF(rect), xf: *this);
1366 if (!nr.isEmpty())
1367 rects.append(t: nr);
1368 }
1369 res.setRects(rect: rects.constData(), num: rects.size());
1370 }
1371 return res;
1372 }
1373
1374 QPainterPath p = map(p: qt_regionToPath(region: r));
1375 return p.toFillPolygon().toPolygon();
1376}
1377
1378struct QHomogeneousCoordinate
1379{
1380 qreal x;
1381 qreal y;
1382 qreal w;
1383
1384 QHomogeneousCoordinate() {}
1385 QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_) : x(x_), y(y_), w(w_) {}
1386
1387 const QPointF toPoint() const {
1388 qreal iw = 1. / w;
1389 return QPointF(x * iw, y * iw);
1390 }
1391};
1392
1393static inline QHomogeneousCoordinate mapHomogeneous(const QTransform &transform, const QPointF &p)
1394{
1395 QHomogeneousCoordinate c;
1396 c.x = transform.m11() * p.x() + transform.m21() * p.y() + transform.m31();
1397 c.y = transform.m12() * p.x() + transform.m22() * p.y() + transform.m32();
1398 c.w = transform.m13() * p.x() + transform.m23() * p.y() + transform.m33();
1399 return c;
1400}
1401
1402static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b,
1403 bool needsMoveTo, bool needsLineTo = true)
1404{
1405 QHomogeneousCoordinate ha = mapHomogeneous(transform, p: a);
1406 QHomogeneousCoordinate hb = mapHomogeneous(transform, p: b);
1407
1408 if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP)
1409 return false;
1410
1411 if (hb.w < Q_NEAR_CLIP) {
1412 const qreal t = (Q_NEAR_CLIP - hb.w) / (ha.w - hb.w);
1413
1414 hb.x += (ha.x - hb.x) * t;
1415 hb.y += (ha.y - hb.y) * t;
1416 hb.w = qreal(Q_NEAR_CLIP);
1417 } else if (ha.w < Q_NEAR_CLIP) {
1418 const qreal t = (Q_NEAR_CLIP - ha.w) / (hb.w - ha.w);
1419
1420 ha.x += (hb.x - ha.x) * t;
1421 ha.y += (hb.y - ha.y) * t;
1422 ha.w = qreal(Q_NEAR_CLIP);
1423
1424 const QPointF p = ha.toPoint();
1425 if (needsMoveTo) {
1426 path.moveTo(p);
1427 needsMoveTo = false;
1428 } else {
1429 path.lineTo(p);
1430 }
1431 }
1432
1433 if (needsMoveTo)
1434 path.moveTo(p: ha.toPoint());
1435
1436 if (needsLineTo)
1437 path.lineTo(p: hb.toPoint());
1438
1439 return true;
1440}
1441Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
1442
1443static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
1444{
1445 // Convert projective xformed curves to line
1446 // segments so they can be transformed more accurately
1447
1448 qreal scale;
1449 qt_scaleForTransform(transform, scale: &scale);
1450
1451 qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
1452
1453 QPolygonF segment = QBezier::fromPoints(p1: a, p2: b, p3: c, p4: d).toPolygon(bezier_flattening_threshold: curveThreshold);
1454
1455 for (int i = 0; i < segment.size() - 1; ++i)
1456 if (lineTo_clipped(path, transform, a: segment.at(i), b: segment.at(i: i+1), needsMoveTo))
1457 needsMoveTo = false;
1458
1459 return !needsMoveTo;
1460}
1461
1462static QPainterPath mapProjective(const QTransform &transform, const QPainterPath &path)
1463{
1464 QPainterPath result;
1465
1466 QPointF last;
1467 QPointF lastMoveTo;
1468 bool needsMoveTo = true;
1469 for (int i = 0; i < path.elementCount(); ++i) {
1470 switch (path.elementAt(i).type) {
1471 case QPainterPath::MoveToElement:
1472 if (i > 0 && lastMoveTo != last)
1473 lineTo_clipped(path&: result, transform, a: last, b: lastMoveTo, needsMoveTo);
1474
1475 lastMoveTo = path.elementAt(i);
1476 last = path.elementAt(i);
1477 needsMoveTo = true;
1478 break;
1479 case QPainterPath::LineToElement:
1480 if (lineTo_clipped(path&: result, transform, a: last, b: path.elementAt(i), needsMoveTo))
1481 needsMoveTo = false;
1482 last = path.elementAt(i);
1483 break;
1484 case QPainterPath::CurveToElement:
1485 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))
1486 needsMoveTo = false;
1487 i += 2;
1488 last = path.elementAt(i);
1489 break;
1490 default:
1491 Q_ASSERT(false);
1492 }
1493 }
1494
1495 if (path.elementCount() > 0 && lastMoveTo != last)
1496 lineTo_clipped(path&: result, transform, a: last, b: lastMoveTo, needsMoveTo, needsLineTo: false);
1497
1498 result.setFillRule(path.fillRule());
1499 return result;
1500}
1501
1502/*!
1503 \fn QPainterPath operator *(const QPainterPath &path, const QTransform &matrix)
1504 \since 4.3
1505 \relates QTransform
1506
1507 This is the same as \a{matrix}.map(\a{path}).
1508
1509 \sa QTransform::map()
1510*/
1511
1512/*!
1513 \overload
1514
1515 Creates and returns a QPainterPath object that is a copy of the
1516 given \a path, mapped into the coordinate system defined by this
1517 matrix.
1518*/
1519QPainterPath QTransform::map(const QPainterPath &path) const
1520{
1521 TransformationType t = inline_type();
1522 if (t == TxNone || path.elementCount() == 0)
1523 return path;
1524
1525 if (t >= TxProject)
1526 return mapProjective(transform: *this, path);
1527
1528 QPainterPath copy = path;
1529
1530 if (t == TxTranslate) {
1531 copy.translate(dx: m_matrix[2][0], dy: m_matrix[2][1]);
1532 } else {
1533 copy.detach();
1534 // Full xform
1535 for (int i=0; i<path.elementCount(); ++i) {
1536 QPainterPath::Element &e = copy.d_ptr->elements[i];
1537 do_map(x: e.x, y: e.y, nx&: e.x, ny&: e.y);
1538 }
1539 }
1540
1541 return copy;
1542}
1543
1544/*!
1545 \fn QPolygon QTransform::mapToPolygon(const QRect &rectangle) const
1546
1547 Creates and returns a QPolygon representation of the given \a
1548 rectangle, mapped into the coordinate system defined by this
1549 matrix.
1550
1551 The rectangle's coordinates are transformed using the following
1552 formulas:
1553
1554 \snippet code/src_gui_painting_qtransform.cpp 1
1555
1556 Polygons and rectangles behave slightly differently when
1557 transformed (due to integer rounding), so
1558 \c{matrix.map(QPolygon(rectangle))} is not always the same as
1559 \c{matrix.mapToPolygon(rectangle)}.
1560
1561 \sa mapRect(), {QTransform#Basic Matrix Operations}{Basic Matrix
1562 Operations}
1563*/
1564QPolygon QTransform::mapToPolygon(const QRect &rect) const
1565{
1566 TransformationType t = inline_type();
1567
1568 QPolygon a(4);
1569 qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
1570 if (t <= TxScale) {
1571 x[0] = m_matrix[0][0]*rect.x() + m_matrix[2][0];
1572 y[0] = m_matrix[1][1]*rect.y() + m_matrix[2][1];
1573 qreal w = m_matrix[0][0]*rect.width();
1574 qreal h = m_matrix[1][1]*rect.height();
1575 if (w < 0) {
1576 w = -w;
1577 x[0] -= w;
1578 }
1579 if (h < 0) {
1580 h = -h;
1581 y[0] -= h;
1582 }
1583 x[1] = x[0]+w;
1584 x[2] = x[1];
1585 x[3] = x[0];
1586 y[1] = y[0];
1587 y[2] = y[0]+h;
1588 y[3] = y[2];
1589 } else {
1590 auto right = rect.x() + rect.width();
1591 auto bottom = rect.y() + rect.height();
1592 do_map(x: rect.x(), y: rect.y(), nx&: x[0], ny&: y[0]);
1593 do_map(x: right, y: rect.y(), nx&: x[1], ny&: y[1]);
1594 do_map(x: right, y: bottom, nx&: x[2], ny&: y[2]);
1595 do_map(x: rect.x(), y: bottom, nx&: x[3], ny&: y[3]);
1596 }
1597
1598 // all coordinates are correctly, transform to a pointarray
1599 // (rounding to the next integer)
1600 a.setPoints(nPoints: 4, firstx: qRound(d: x[0]), firsty: qRound(d: y[0]),
1601 qRound(d: x[1]), qRound(d: y[1]),
1602 qRound(d: x[2]), qRound(d: y[2]),
1603 qRound(d: x[3]), qRound(d: y[3]));
1604 return a;
1605}
1606
1607/*!
1608 Creates a transformation matrix, \a trans, that maps a unit square
1609 to a four-sided polygon, \a quad. Returns \c true if the transformation
1610 is constructed or false if such a transformation does not exist.
1611
1612 \sa quadToSquare(), quadToQuad()
1613*/
1614bool QTransform::squareToQuad(const QPolygonF &quad, QTransform &trans)
1615{
1616 if (quad.size() != (quad.isClosed() ? 5 : 4))
1617 return false;
1618
1619 qreal dx0 = quad[0].x();
1620 qreal dx1 = quad[1].x();
1621 qreal dx2 = quad[2].x();
1622 qreal dx3 = quad[3].x();
1623
1624 qreal dy0 = quad[0].y();
1625 qreal dy1 = quad[1].y();
1626 qreal dy2 = quad[2].y();
1627 qreal dy3 = quad[3].y();
1628
1629 double ax = dx0 - dx1 + dx2 - dx3;
1630 double ay = dy0 - dy1 + dy2 - dy3;
1631
1632 if (!ax && !ay) { //afine transform
1633 trans.setMatrix(m11: dx1 - dx0, m12: dy1 - dy0, m13: 0,
1634 m21: dx2 - dx1, m22: dy2 - dy1, m23: 0,
1635 m31: dx0, m32: dy0, m33: 1);
1636 } else {
1637 double ax1 = dx1 - dx2;
1638 double ax2 = dx3 - dx2;
1639 double ay1 = dy1 - dy2;
1640 double ay2 = dy3 - dy2;
1641
1642 /*determinants */
1643 double gtop = ax * ay2 - ax2 * ay;
1644 double htop = ax1 * ay - ax * ay1;
1645 double bottom = ax1 * ay2 - ax2 * ay1;
1646
1647 double a, b, c, d, e, f, g, h; /*i is always 1*/
1648
1649 if (!bottom)
1650 return false;
1651
1652 g = gtop/bottom;
1653 h = htop/bottom;
1654
1655 a = dx1 - dx0 + g * dx1;
1656 b = dx3 - dx0 + h * dx3;
1657 c = dx0;
1658 d = dy1 - dy0 + g * dy1;
1659 e = dy3 - dy0 + h * dy3;
1660 f = dy0;
1661
1662 trans.setMatrix(m11: a, m12: d, m13: g,
1663 m21: b, m22: e, m23: h,
1664 m31: c, m32: f, m33: 1.0);
1665 }
1666
1667 return true;
1668}
1669
1670/*!
1671 \fn bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1672
1673 Creates a transformation matrix, \a trans, that maps a four-sided polygon,
1674 \a quad, to a unit square. Returns \c true if the transformation is constructed
1675 or false if such a transformation does not exist.
1676
1677 \sa squareToQuad(), quadToQuad()
1678*/
1679bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1680{
1681 if (!squareToQuad(quad, trans))
1682 return false;
1683
1684 bool invertible = false;
1685 trans = trans.inverted(invertible: &invertible);
1686
1687 return invertible;
1688}
1689
1690/*!
1691 Creates a transformation matrix, \a trans, that maps a four-sided
1692 polygon, \a one, to another four-sided polygon, \a two.
1693 Returns \c true if the transformation is possible; otherwise returns
1694 false.
1695
1696 This is a convenience method combining quadToSquare() and
1697 squareToQuad() methods. It allows the input quad to be
1698 transformed into any other quad.
1699
1700 \sa squareToQuad(), quadToSquare()
1701*/
1702bool QTransform::quadToQuad(const QPolygonF &one,
1703 const QPolygonF &two,
1704 QTransform &trans)
1705{
1706 QTransform stq;
1707 if (!quadToSquare(quad: one, trans))
1708 return false;
1709 if (!squareToQuad(quad: two, trans&: stq))
1710 return false;
1711 trans *= stq;
1712 //qDebug()<<"Final = "<<trans;
1713 return true;
1714}
1715
1716/*!
1717 Sets the matrix elements to the specified values, \a m11,
1718 \a m12, \a m13 \a m21, \a m22, \a m23 \a m31, \a m32 and
1719 \a m33. Note that this function replaces the previous values.
1720 QTransform provides the translate(), rotate(), scale() and shear()
1721 convenience functions to manipulate the various matrix elements
1722 based on the currently defined coordinate system.
1723
1724 \sa QTransform()
1725*/
1726
1727void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
1728 qreal m21, qreal m22, qreal m23,
1729 qreal m31, qreal m32, qreal m33)
1730{
1731 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
1732 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
1733 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
1734 m_type = TxNone;
1735 m_dirty = TxProject;
1736}
1737
1738QRect QTransform::mapRect(const QRect &rect) const
1739{
1740 TransformationType t = inline_type();
1741 if (t <= TxTranslate)
1742 return rect.translated(dx: qRound(d: m_matrix[2][0]), dy: qRound(d: m_matrix[2][1]));
1743
1744 if (t <= TxScale) {
1745 int x = qRound(d: m_matrix[0][0] * rect.x() + m_matrix[2][0]);
1746 int y = qRound(d: m_matrix[1][1] * rect.y() + m_matrix[2][1]);
1747 int w = qRound(d: m_matrix[0][0] * rect.width());
1748 int h = qRound(d: m_matrix[1][1] * rect.height());
1749 if (w < 0) {
1750 w = -w;
1751 x -= w;
1752 }
1753 if (h < 0) {
1754 h = -h;
1755 y -= h;
1756 }
1757 return QRect(x, y, w, h);
1758 } else {
1759 qreal x = 0, y = 0;
1760 do_map(x: rect.left(), y: rect.top(), nx&: x, ny&: y);
1761 qreal xmin = x;
1762 qreal ymin = y;
1763 qreal xmax = x;
1764 qreal ymax = y;
1765 do_map(x: rect.right() + 1, y: rect.top(), nx&: x, ny&: y);
1766 xmin = qMin(a: xmin, b: x);
1767 ymin = qMin(a: ymin, b: y);
1768 xmax = qMax(a: xmax, b: x);
1769 ymax = qMax(a: ymax, b: y);
1770 do_map(x: rect.right() + 1, y: rect.bottom() + 1, nx&: x, ny&: y);
1771 xmin = qMin(a: xmin, b: x);
1772 ymin = qMin(a: ymin, b: y);
1773 xmax = qMax(a: xmax, b: x);
1774 ymax = qMax(a: ymax, b: y);
1775 do_map(x: rect.left(), y: rect.bottom() + 1, nx&: x, ny&: y);
1776 xmin = qMin(a: xmin, b: x);
1777 ymin = qMin(a: ymin, b: y);
1778 xmax = qMax(a: xmax, b: x);
1779 ymax = qMax(a: ymax, b: y);
1780 return QRectF(xmin, ymin, xmax-xmin, ymax-ymin).toRect();
1781 }
1782}
1783
1784/*!
1785 \fn QRectF QTransform::mapRect(const QRectF &rectangle) const
1786
1787 Creates and returns a QRectF object that is a copy of the given \a
1788 rectangle, mapped into the coordinate system defined by this
1789 matrix.
1790
1791 The rectangle's coordinates are transformed using the following
1792 formulas:
1793
1794 \snippet code/src_gui_painting_qtransform.cpp 2
1795
1796 If rotation or shearing has been specified, this function returns
1797 the \e bounding rectangle. To retrieve the exact region the given
1798 \a rectangle maps to, use the mapToPolygon() function instead.
1799
1800 \sa mapToPolygon(), {QTransform#Basic Matrix Operations}{Basic Matrix
1801 Operations}
1802*/
1803QRectF QTransform::mapRect(const QRectF &rect) const
1804{
1805 TransformationType t = inline_type();
1806 if (t <= TxTranslate)
1807 return rect.translated(dx: m_matrix[2][0], dy: m_matrix[2][1]);
1808
1809 if (t <= TxScale) {
1810 qreal x = m_matrix[0][0] * rect.x() + m_matrix[2][0];
1811 qreal y = m_matrix[1][1] * rect.y() + m_matrix[2][1];
1812 qreal w = m_matrix[0][0] * rect.width();
1813 qreal h = m_matrix[1][1] * rect.height();
1814 if (w < 0) {
1815 w = -w;
1816 x -= w;
1817 }
1818 if (h < 0) {
1819 h = -h;
1820 y -= h;
1821 }
1822 return QRectF(x, y, w, h);
1823 } else {
1824 qreal x = 0, y = 0;
1825 do_map(x: rect.x(), y: rect.y(), nx&: x, ny&: y);
1826 qreal xmin = x;
1827 qreal ymin = y;
1828 qreal xmax = x;
1829 qreal ymax = y;
1830 do_map(x: rect.x() + rect.width(), y: rect.y(), nx&: x, ny&: y);
1831 xmin = qMin(a: xmin, b: x);
1832 ymin = qMin(a: ymin, b: y);
1833 xmax = qMax(a: xmax, b: x);
1834 ymax = qMax(a: ymax, b: y);
1835 do_map(x: rect.x() + rect.width(), y: rect.y() + rect.height(), nx&: x, ny&: y);
1836 xmin = qMin(a: xmin, b: x);
1837 ymin = qMin(a: ymin, b: y);
1838 xmax = qMax(a: xmax, b: x);
1839 ymax = qMax(a: ymax, b: y);
1840 do_map(x: rect.x(), y: rect.y() + rect.height(), nx&: x, ny&: y);
1841 xmin = qMin(a: xmin, b: x);
1842 ymin = qMin(a: ymin, b: y);
1843 xmax = qMax(a: xmax, b: x);
1844 ymax = qMax(a: ymax, b: y);
1845 return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
1846 }
1847}
1848
1849/*!
1850 \fn QRect QTransform::mapRect(const QRect &rectangle) const
1851 \overload
1852
1853 Creates and returns a QRect object that is a copy of the given \a
1854 rectangle, mapped into the coordinate system defined by this
1855 matrix. Note that the transformed coordinates are rounded to the
1856 nearest integer.
1857*/
1858
1859/*!
1860 Maps the given coordinates \a x and \a y into the coordinate
1861 system defined by this matrix. The resulting values are put in *\a
1862 tx and *\a ty, respectively.
1863
1864 The coordinates are transformed using the following formulas:
1865
1866 \snippet code/src_gui_painting_qtransform.cpp 3
1867
1868 The point (x, y) is the original point, and (x', y') is the
1869 transformed point.
1870
1871 \sa {QTransform#Basic Matrix Operations}{Basic Matrix Operations}
1872*/
1873void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
1874{
1875 do_map(x, y, nx&: *tx, ny&: *ty);
1876}
1877
1878/*!
1879 \overload
1880
1881 Maps the given coordinates \a x and \a y into the coordinate
1882 system defined by this matrix. The resulting values are put in *\a
1883 tx and *\a ty, respectively. Note that the transformed coordinates
1884 are rounded to the nearest integer.
1885*/
1886void QTransform::map(int x, int y, int *tx, int *ty) const
1887{
1888 qreal fx = 0, fy = 0;
1889 do_map(x, y, nx&: fx, ny&: fy);
1890 *tx = qRound(d: fx);
1891 *ty = qRound(d: fy);
1892}
1893
1894/*!
1895 Returns the transformation type of this matrix.
1896
1897 The transformation type is the highest enumeration value
1898 capturing all of the matrix's transformations. For example,
1899 if the matrix both scales and shears, the type would be \c TxShear,
1900 because \c TxShear has a higher enumeration value than \c TxScale.
1901
1902 Knowing the transformation type of a matrix is useful for optimization:
1903 you can often handle specific types more optimally than handling
1904 the generic case.
1905 */
1906QTransform::TransformationType QTransform::type() const
1907{
1908 if (m_dirty == TxNone || m_dirty < m_type)
1909 return static_cast<TransformationType>(m_type);
1910
1911 switch (static_cast<TransformationType>(m_dirty)) {
1912 case TxProject:
1913 if (!qFuzzyIsNull(d: m_matrix[0][2]) || !qFuzzyIsNull(d: m_matrix[1][2]) || !qFuzzyIsNull(d: m_matrix[2][2] - 1)) {
1914 m_type = TxProject;
1915 break;
1916 }
1917 Q_FALLTHROUGH();
1918 case TxShear:
1919 case TxRotate:
1920 if (!qFuzzyIsNull(d: m_matrix[0][1]) || !qFuzzyIsNull(d: m_matrix[1][0])) {
1921 const qreal dot = m_matrix[0][0] * m_matrix[1][0] + m_matrix[0][1] * m_matrix[1][1];
1922 if (qFuzzyIsNull(d: dot))
1923 m_type = TxRotate;
1924 else
1925 m_type = TxShear;
1926 break;
1927 }
1928 Q_FALLTHROUGH();
1929 case TxScale:
1930 if (!qFuzzyIsNull(d: m_matrix[0][0] - 1) || !qFuzzyIsNull(d: m_matrix[1][1] - 1)) {
1931 m_type = TxScale;
1932 break;
1933 }
1934 Q_FALLTHROUGH();
1935 case TxTranslate:
1936 if (!qFuzzyIsNull(d: m_matrix[2][0]) || !qFuzzyIsNull(d: m_matrix[2][1])) {
1937 m_type = TxTranslate;
1938 break;
1939 }
1940 Q_FALLTHROUGH();
1941 case TxNone:
1942 m_type = TxNone;
1943 break;
1944 }
1945
1946 m_dirty = TxNone;
1947 return static_cast<TransformationType>(m_type);
1948}
1949
1950/*!
1951
1952 Returns the transform as a QVariant.
1953*/
1954QTransform::operator QVariant() const
1955{
1956 return QVariant::fromValue(value: *this);
1957}
1958
1959
1960/*!
1961 \fn bool QTransform::isInvertible() const
1962
1963 Returns \c true if the matrix is invertible, otherwise returns \c false.
1964
1965 \sa inverted()
1966*/
1967
1968/*!
1969 \fn qreal QTransform::m11() const
1970
1971 Returns the horizontal scaling factor.
1972
1973 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
1974 Operations}
1975*/
1976
1977/*!
1978 \fn qreal QTransform::m12() const
1979
1980 Returns the vertical shearing factor.
1981
1982 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
1983 Operations}
1984*/
1985
1986/*!
1987 \fn qreal QTransform::m21() const
1988
1989 Returns the horizontal shearing factor.
1990
1991 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
1992 Operations}
1993*/
1994
1995/*!
1996 \fn qreal QTransform::m22() const
1997
1998 Returns the vertical scaling factor.
1999
2000 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
2001 Operations}
2002*/
2003
2004/*!
2005 \fn qreal QTransform::dx() const
2006
2007 Returns the horizontal translation factor.
2008
2009 \sa m31(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2010 Operations}
2011*/
2012
2013/*!
2014 \fn qreal QTransform::dy() const
2015
2016 Returns the vertical translation factor.
2017
2018 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2019 Operations}
2020*/
2021
2022
2023/*!
2024 \fn qreal QTransform::m13() const
2025
2026 Returns the horizontal projection factor.
2027
2028 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2029 Operations}
2030*/
2031
2032
2033/*!
2034 \fn qreal QTransform::m23() const
2035
2036 Returns the vertical projection factor.
2037
2038 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2039 Operations}
2040*/
2041
2042/*!
2043 \fn qreal QTransform::m31() const
2044
2045 Returns the horizontal translation factor.
2046
2047 \sa dx(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2048 Operations}
2049*/
2050
2051/*!
2052 \fn qreal QTransform::m32() const
2053
2054 Returns the vertical translation factor.
2055
2056 \sa dy(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2057 Operations}
2058*/
2059
2060/*!
2061 \fn qreal QTransform::m33() const
2062
2063 Returns the division factor.
2064
2065 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2066 Operations}
2067*/
2068
2069/*!
2070 \fn qreal QTransform::determinant() const
2071
2072 Returns the matrix's determinant.
2073*/
2074
2075/*!
2076 \fn bool QTransform::isIdentity() const
2077
2078 Returns \c true if the matrix is the identity matrix, otherwise
2079 returns \c false.
2080
2081 \sa reset()
2082*/
2083
2084/*!
2085 \fn bool QTransform::isAffine() const
2086
2087 Returns \c true if the matrix represent an affine transformation,
2088 otherwise returns \c false.
2089*/
2090
2091/*!
2092 \fn bool QTransform::isScaling() const
2093
2094 Returns \c true if the matrix represents a scaling
2095 transformation, otherwise returns \c false.
2096
2097 \sa reset()
2098*/
2099
2100/*!
2101 \fn bool QTransform::isRotating() const
2102
2103 Returns \c true if the matrix represents some kind of a
2104 rotating transformation, otherwise returns \c false.
2105
2106 \note A rotation transformation of 180 degrees and/or 360 degrees is treated as a scaling transformation.
2107
2108 \sa reset()
2109*/
2110
2111/*!
2112 \fn bool QTransform::isTranslating() const
2113
2114 Returns \c true if the matrix represents a translating
2115 transformation, otherwise returns \c false.
2116
2117 \sa reset()
2118*/
2119
2120/*!
2121 \fn bool qFuzzyCompare(const QTransform& t1, const QTransform& t2)
2122
2123 \relates QTransform
2124 \since 4.6
2125
2126 Returns \c true if \a t1 and \a t2 are equal, allowing for a small
2127 fuzziness factor for floating-point comparisons; false otherwise.
2128*/
2129
2130
2131// returns true if the transform is uniformly scaling
2132// (same scale in x and y direction)
2133// scale is set to the max of x and y scaling factors
2134Q_GUI_EXPORT
2135bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
2136{
2137 const QTransform::TransformationType type = transform.type();
2138 if (type <= QTransform::TxTranslate) {
2139 if (scale)
2140 *scale = 1;
2141 return true;
2142 } else if (type == QTransform::TxScale) {
2143 const qreal xScale = qAbs(t: transform.m11());
2144 const qreal yScale = qAbs(t: transform.m22());
2145 if (scale)
2146 *scale = qMax(a: xScale, b: yScale);
2147 return qFuzzyCompare(p1: xScale, p2: yScale);
2148 }
2149
2150 // rotate then scale: compare columns
2151 const qreal xScale1 = transform.m11() * transform.m11()
2152 + transform.m21() * transform.m21();
2153 const qreal yScale1 = transform.m12() * transform.m12()
2154 + transform.m22() * transform.m22();
2155
2156 // scale then rotate: compare rows
2157 const qreal xScale2 = transform.m11() * transform.m11()
2158 + transform.m12() * transform.m12();
2159 const qreal yScale2 = transform.m21() * transform.m21()
2160 + transform.m22() * transform.m22();
2161
2162 // decide the order of rotate and scale operations
2163 if (qAbs(t: xScale1 - yScale1) > qAbs(t: xScale2 - yScale2)) {
2164 if (scale)
2165 *scale = qSqrt(v: qMax(a: xScale1, b: yScale1));
2166
2167 return type == QTransform::TxRotate && qFuzzyCompare(p1: xScale1, p2: yScale1);
2168 } else {
2169 if (scale)
2170 *scale = qSqrt(v: qMax(a: xScale2, b: yScale2));
2171
2172 return type == QTransform::TxRotate && qFuzzyCompare(p1: xScale2, p2: yScale2);
2173 }
2174}
2175
2176QDataStream & operator>>(QDataStream &s, QTransform::Affine &m)
2177{
2178 if (s.version() == 1) {
2179 float m11, m12, m21, m22, dx, dy;
2180 s >> m11; s >> m12; s >> m21; s >> m22; s >> dx; s >> dy;
2181
2182 m.m_matrix[0][0] = m11;
2183 m.m_matrix[0][1] = m12;
2184 m.m_matrix[1][0] = m21;
2185 m.m_matrix[1][1] = m22;
2186 m.m_matrix[2][0] = dx;
2187 m.m_matrix[2][1] = dy;
2188 } else {
2189 s >> m.m_matrix[0][0];
2190 s >> m.m_matrix[0][1];
2191 s >> m.m_matrix[1][0];
2192 s >> m.m_matrix[1][1];
2193 s >> m.m_matrix[2][0];
2194 s >> m.m_matrix[2][1];
2195 }
2196 m.m_matrix[0][2] = 0;
2197 m.m_matrix[1][2] = 0;
2198 m.m_matrix[2][2] = 1;
2199 return s;
2200}
2201
2202QDataStream &operator<<(QDataStream &s, const QTransform::Affine &m)
2203{
2204 if (s.version() == 1) {
2205 s << (float)m.m_matrix[0][0]
2206 << (float)m.m_matrix[0][1]
2207 << (float)m.m_matrix[1][0]
2208 << (float)m.m_matrix[1][1]
2209 << (float)m.m_matrix[2][0]
2210 << (float)m.m_matrix[2][1];
2211 } else {
2212 s << m.m_matrix[0][0]
2213 << m.m_matrix[0][1]
2214 << m.m_matrix[1][0]
2215 << m.m_matrix[1][1]
2216 << m.m_matrix[2][0]
2217 << m.m_matrix[2][1];
2218 }
2219 return s;
2220}
2221
2222QT_END_NAMESPACE
2223

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

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