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

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