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

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