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