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