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