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