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