source: trunk/src/gui/painting/qtransform.cpp@ 617

Last change on this file since 617 was 561, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.1 sources.

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