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