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

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

File size: 64.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
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 qt-info@nokia.com.
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
54QT_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*/
254QTransform::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*/
270QTransform::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*/
287QTransform::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 */
303QTransform::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*/
314QTransform 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*/
337QTransform 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*/
357QTransform 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*/
410QTransform &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*/
455QTransform 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*/
478QTransform & 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*/
521QTransform 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*/
544QTransform & 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
588const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
589const 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*/
605QTransform & 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*/
698QTransform & 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*/
767bool 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*/
785bool 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*/
797QTransform & 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*/
879QTransform 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*/
989QTransform & 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*/
1014void 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*/
1033QDataStream & 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*/
1057QDataStream & 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
1081QDebug operator<<(QDebug dbg, const QTransform &m)
1082{
1083 static const char *typeStr[] =
1084 {
1085 "TxNone",
1086 "TxTranslate",
1087 "TxScale",
1088 "TxRotate",
1089 "TxShear",
1090 "TxProject"
1091 };
1092
1093 dbg.nospace() << "QTransform(type=" << typeStr[m.type()] << ','
1094 << " 11=" << m.m11()
1095 << " 12=" << m.m12()
1096 << " 13=" << m.m13()
1097 << " 21=" << m.m21()
1098 << " 22=" << m.m22()
1099 << " 23=" << m.m23()
1100 << " 31=" << m.m31()
1101 << " 32=" << m.m32()
1102 << " 33=" << m.m33()
1103 << ')';
1104
1105 return dbg.space();
1106}
1107#endif
1108
1109/*!
1110 \fn QPoint operator*(const QPoint &point, const QTransform &matrix)
1111 \relates QTransform
1112
1113 This is the same as \a{matrix}.map(\a{point}).
1114
1115 \sa QTransform::map()
1116*/
1117QPoint QTransform::map(const QPoint &p) const
1118{
1119 qreal fx = p.x();
1120 qreal fy = p.y();
1121
1122 qreal x = 0, y = 0;
1123
1124 TransformationType t = inline_type();
1125 switch(t) {
1126 case TxNone:
1127 x = fx;
1128 y = fy;
1129 break;
1130 case TxTranslate:
1131 x = fx + affine._dx;
1132 y = fy + affine._dy;
1133 break;
1134 case TxScale:
1135 x = affine._m11 * fx + affine._dx;
1136 y = affine._m22 * fy + affine._dy;
1137 break;
1138 case TxRotate:
1139 case TxShear:
1140 case TxProject:
1141 x = affine._m11 * fx + affine._m21 * fy + affine._dx;
1142 y = affine._m12 * fx + affine._m22 * fy + affine._dy;
1143 if (t == TxProject) {
1144 qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
1145 x *= w;
1146 y *= w;
1147 }
1148 }
1149 return QPoint(qRound(x), qRound(y));
1150}
1151
1152
1153/*!
1154 \fn QPointF operator*(const QPointF &point, const QTransform &matrix)
1155 \relates QTransform
1156
1157 Same as \a{matrix}.map(\a{point}).
1158
1159 \sa QTransform::map()
1160*/
1161
1162/*!
1163 \overload
1164
1165 Creates and returns a QPointF object that is a copy of the given point,
1166 \a p, mapped into the coordinate system defined by this matrix.
1167*/
1168QPointF QTransform::map(const QPointF &p) const
1169{
1170 qreal fx = p.x();
1171 qreal fy = p.y();
1172
1173 qreal x = 0, y = 0;
1174
1175 TransformationType t = inline_type();
1176 switch(t) {
1177 case TxNone:
1178 x = fx;
1179 y = fy;
1180 break;
1181 case TxTranslate:
1182 x = fx + affine._dx;
1183 y = fy + affine._dy;
1184 break;
1185 case TxScale:
1186 x = affine._m11 * fx + affine._dx;
1187 y = affine._m22 * fy + affine._dy;
1188 break;
1189 case TxRotate:
1190 case TxShear:
1191 case TxProject:
1192 x = affine._m11 * fx + affine._m21 * fy + affine._dx;
1193 y = affine._m12 * fx + affine._m22 * fy + affine._dy;
1194 if (t == TxProject) {
1195 qreal w = 1./(m_13 * fx + m_23 * fy + m_33);
1196 x *= w;
1197 y *= w;
1198 }
1199 }
1200 return QPointF(x, y);
1201}
1202
1203/*!
1204 \fn QPoint QTransform::map(const QPoint &point) const
1205 \overload
1206
1207 Creates and returns a QPoint object that is a copy of the given \a
1208 point, mapped into the coordinate system defined by this
1209 matrix. Note that the transformed coordinates are rounded to the
1210 nearest integer.
1211*/
1212
1213/*!
1214 \fn QLineF operator*(const QLineF &line, const QTransform &matrix)
1215 \relates QTransform
1216
1217 This is the same as \a{matrix}.map(\a{line}).
1218
1219 \sa QTransform::map()
1220*/
1221
1222/*!
1223 \fn QLine operator*(const QLine &line, const QTransform &matrix)
1224 \relates QTransform
1225
1226 This is the same as \a{matrix}.map(\a{line}).
1227
1228 \sa QTransform::map()
1229*/
1230
1231/*!
1232 \overload
1233
1234 Creates and returns a QLineF object that is a copy of the given line,
1235 \a l, mapped into the coordinate system defined by this matrix.
1236*/
1237QLine QTransform::map(const QLine &l) const
1238{
1239 qreal fx1 = l.x1();
1240 qreal fy1 = l.y1();
1241 qreal fx2 = l.x2();
1242 qreal fy2 = l.y2();
1243
1244 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1245
1246 TransformationType t = inline_type();
1247 switch(t) {
1248 case TxNone:
1249 x1 = fx1;
1250 y1 = fy1;
1251 x2 = fx2;
1252 y2 = fy2;
1253 break;
1254 case TxTranslate:
1255 x1 = fx1 + affine._dx;
1256 y1 = fy1 + affine._dy;
1257 x2 = fx2 + affine._dx;
1258 y2 = fy2 + affine._dy;
1259 break;
1260 case TxScale:
1261 x1 = affine._m11 * fx1 + affine._dx;
1262 y1 = affine._m22 * fy1 + affine._dy;
1263 x2 = affine._m11 * fx2 + affine._dx;
1264 y2 = affine._m22 * fy2 + affine._dy;
1265 break;
1266 case TxRotate:
1267 case TxShear:
1268 case TxProject:
1269 x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
1270 y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
1271 x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
1272 y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
1273 if (t == TxProject) {
1274 qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
1275 x1 *= w;
1276 y1 *= w;
1277 w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
1278 x2 *= w;
1279 y2 *= w;
1280 }
1281 }
1282 return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
1283}
1284
1285/*!
1286 \overload
1287
1288 \fn QLineF QTransform::map(const QLineF &line) const
1289
1290 Creates and returns a QLine object that is a copy of the given \a
1291 line, mapped into the coordinate system defined by this matrix.
1292 Note that the transformed coordinates are rounded to the nearest
1293 integer.
1294*/
1295
1296QLineF QTransform::map(const QLineF &l) const
1297{
1298 qreal fx1 = l.x1();
1299 qreal fy1 = l.y1();
1300 qreal fx2 = l.x2();
1301 qreal fy2 = l.y2();
1302
1303 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1304
1305 TransformationType t = inline_type();
1306 switch(t) {
1307 case TxNone:
1308 x1 = fx1;
1309 y1 = fy1;
1310 x2 = fx2;
1311 y2 = fy2;
1312 break;
1313 case TxTranslate:
1314 x1 = fx1 + affine._dx;
1315 y1 = fy1 + affine._dy;
1316 x2 = fx2 + affine._dx;
1317 y2 = fy2 + affine._dy;
1318 break;
1319 case TxScale:
1320 x1 = affine._m11 * fx1 + affine._dx;
1321 y1 = affine._m22 * fy1 + affine._dy;
1322 x2 = affine._m11 * fx2 + affine._dx;
1323 y2 = affine._m22 * fy2 + affine._dy;
1324 break;
1325 case TxRotate:
1326 case TxShear:
1327 case TxProject:
1328 x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx;
1329 y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy;
1330 x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx;
1331 y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy;
1332 if (t == TxProject) {
1333 qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33);
1334 x1 *= w;
1335 y1 *= w;
1336 w = 1./(m_13 * fx2 + m_23 * fy2 + m_33);
1337 x2 *= w;
1338 y2 *= w;
1339 }
1340 }
1341 return QLineF(x1, y1, x2, y2);
1342}
1343
1344static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &poly)
1345{
1346 if (poly.size() == 0)
1347 return poly;
1348
1349 if (poly.size() == 1)
1350 return QPolygonF() << transform.map(poly.at(0));
1351
1352 QPainterPath path;
1353 path.addPolygon(poly);
1354
1355 path = transform.map(path);
1356
1357 QPolygonF result;
1358 for (int i = 0; i < path.elementCount(); ++i)
1359 result << path.elementAt(i);
1360 return result;
1361}
1362
1363
1364/*!
1365 \fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix)
1366 \since 4.3
1367 \relates QTransform
1368
1369 This is the same as \a{matrix}.map(\a{polygon}).
1370
1371 \sa QTransform::map()
1372*/
1373
1374/*!
1375 \fn QPolygon operator*(const QPolygon &polygon, const QTransform &matrix)
1376 \relates QTransform
1377
1378 This is the same as \a{matrix}.map(\a{polygon}).
1379
1380 \sa QTransform::map()
1381*/
1382
1383/*!
1384 \fn QPolygonF QTransform::map(const QPolygonF &polygon) const
1385 \overload
1386
1387 Creates and returns a QPolygonF object that is a copy of the given
1388 \a polygon, mapped into the coordinate system defined by this
1389 matrix.
1390*/
1391QPolygonF QTransform::map(const QPolygonF &a) const
1392{
1393 TransformationType t = inline_type();
1394 if (t <= TxTranslate)
1395 return a.translated(affine._dx, affine._dy);
1396
1397 if (t >= QTransform::TxProject)
1398 return mapProjective(*this, a);
1399
1400 int size = a.size();
1401 int i;
1402 QPolygonF p(size);
1403 const QPointF *da = a.constData();
1404 QPointF *dp = p.data();
1405
1406 for(i = 0; i < size; ++i) {
1407 MAP(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
1408 }
1409 return p;
1410}
1411
1412/*!
1413 \fn QPolygon QTransform::map(const QPolygon &polygon) const
1414 \overload
1415
1416 Creates and returns a QPolygon object that is a copy of the given
1417 \a polygon, mapped into the coordinate system defined by this
1418 matrix. Note that the transformed coordinates are rounded to the
1419 nearest integer.
1420*/
1421QPolygon QTransform::map(const QPolygon &a) const
1422{
1423 TransformationType t = inline_type();
1424 if (t <= TxTranslate)
1425 return a.translated(qRound(affine._dx), qRound(affine._dy));
1426
1427 if (t >= QTransform::TxProject)
1428 return mapProjective(*this, QPolygonF(a)).toPolygon();
1429
1430 int size = a.size();
1431 int i;
1432 QPolygon p(size);
1433 const QPoint *da = a.constData();
1434 QPoint *dp = p.data();
1435
1436 for(i = 0; i < size; ++i) {
1437 qreal nx = 0, ny = 0;
1438 MAP(da[i].xp, da[i].yp, nx, ny);
1439 dp[i].xp = qRound(nx);
1440 dp[i].yp = qRound(ny);
1441 }
1442 return p;
1443}
1444
1445/*!
1446 \fn QRegion operator*(const QRegion &region, const QTransform &matrix)
1447 \relates QTransform
1448
1449 This is the same as \a{matrix}.map(\a{region}).
1450
1451 \sa QTransform::map()
1452*/
1453
1454extern QPainterPath qt_regionToPath(const QRegion &region);
1455
1456/*!
1457 \fn QRegion QTransform::map(const QRegion &region) const
1458 \overload
1459
1460 Creates and returns a QRegion object that is a copy of the given
1461 \a region, mapped into the coordinate system defined by this matrix.
1462
1463 Calling this method can be rather expensive if rotations or
1464 shearing are used.
1465*/
1466QRegion QTransform::map(const QRegion &r) const
1467{
1468 TransformationType t = inline_type();
1469 if (t == TxNone)
1470 return r;
1471
1472 if (t == TxTranslate) {
1473 QRegion copy(r);
1474 copy.translate(qRound(affine._dx), qRound(affine._dy));
1475 return copy;
1476 }
1477
1478 if (t == TxScale && r.rectCount() == 1)
1479 return QRegion(mapRect(r.boundingRect()));
1480
1481 QPainterPath p = map(qt_regionToPath(r));
1482 return p.toFillPolygon(QTransform()).toPolygon();
1483}
1484
1485struct QHomogeneousCoordinate
1486{
1487 qreal x;
1488 qreal y;
1489 qreal w;
1490
1491 QHomogeneousCoordinate() {}
1492 QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_) : x(x_), y(y_), w(w_) {}
1493
1494 const QPointF toPoint() const {
1495 qreal iw = 1. / w;
1496 return QPointF(x * iw, y * iw);
1497 }
1498};
1499
1500static inline QHomogeneousCoordinate mapHomogeneous(const QTransform &transform, const QPointF &p)
1501{
1502 QHomogeneousCoordinate c;
1503 c.x = transform.m11() * p.x() + transform.m21() * p.y() + transform.m31();
1504 c.y = transform.m12() * p.x() + transform.m22() * p.y() + transform.m32();
1505 c.w = transform.m13() * p.x() + transform.m23() * p.y() + transform.m33();
1506 return c;
1507}
1508
1509static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b,
1510 bool needsMoveTo, bool needsLineTo = true)
1511{
1512 QHomogeneousCoordinate ha = mapHomogeneous(transform, a);
1513 QHomogeneousCoordinate hb = mapHomogeneous(transform, b);
1514
1515 if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP)
1516 return false;
1517
1518 if (hb.w < Q_NEAR_CLIP) {
1519 const qreal t = (Q_NEAR_CLIP - hb.w) / (ha.w - hb.w);
1520
1521 hb.x += (ha.x - hb.x) * t;
1522 hb.y += (ha.y - hb.y) * t;
1523 hb.w = qreal(Q_NEAR_CLIP);
1524 } else if (ha.w < Q_NEAR_CLIP) {
1525 const qreal t = (Q_NEAR_CLIP - ha.w) / (hb.w - ha.w);
1526
1527 ha.x += (hb.x - ha.x) * t;
1528 ha.y += (hb.y - ha.y) * t;
1529 ha.w = qreal(Q_NEAR_CLIP);
1530
1531 const QPointF p = ha.toPoint();
1532 if (needsMoveTo) {
1533 path.moveTo(p);
1534 needsMoveTo = false;
1535 } else {
1536 path.lineTo(p);
1537 }
1538 }
1539
1540 if (needsMoveTo)
1541 path.moveTo(ha.toPoint());
1542
1543 if (needsLineTo)
1544 path.lineTo(hb.toPoint());
1545
1546 return true;
1547}
1548Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
1549
1550static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
1551{
1552 // Convert projective xformed curves to line
1553 // segments so they can be transformed more accurately
1554
1555 qreal scale;
1556 qt_scaleForTransform(transform, &scale);
1557
1558 qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
1559
1560 QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(curveThreshold);
1561
1562 for (int i = 0; i < segment.size() - 1; ++i)
1563 if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo))
1564 needsMoveTo = false;
1565
1566 return !needsMoveTo;
1567}
1568
1569static QPainterPath mapProjective(const QTransform &transform, const QPainterPath &path)
1570{
1571 QPainterPath result;
1572
1573 QPointF last;
1574 QPointF lastMoveTo;
1575 bool needsMoveTo = true;
1576 for (int i = 0; i < path.elementCount(); ++i) {
1577 switch (path.elementAt(i).type) {
1578 case QPainterPath::MoveToElement:
1579 if (i > 0 && lastMoveTo != last)
1580 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo);
1581
1582 lastMoveTo = path.elementAt(i);
1583 last = path.elementAt(i);
1584 needsMoveTo = true;
1585 break;
1586 case QPainterPath::LineToElement:
1587 if (lineTo_clipped(result, transform, last, path.elementAt(i), needsMoveTo))
1588 needsMoveTo = false;
1589 last = path.elementAt(i);
1590 break;
1591 case QPainterPath::CurveToElement:
1592 if (cubicTo_clipped(result, transform, last, path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), needsMoveTo))
1593 needsMoveTo = false;
1594 i += 2;
1595 last = path.elementAt(i);
1596 break;
1597 default:
1598 Q_ASSERT(false);
1599 }
1600 }
1601
1602 if (path.elementCount() > 0 && lastMoveTo != last)
1603 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false);
1604
1605 result.setFillRule(path.fillRule());
1606 return result;
1607}
1608
1609/*!
1610 \fn QPainterPath operator *(const QPainterPath &path, const QTransform &matrix)
1611 \since 4.3
1612 \relates QTransform
1613
1614 This is the same as \a{matrix}.map(\a{path}).
1615
1616 \sa QTransform::map()
1617*/
1618
1619/*!
1620 \overload
1621
1622 Creates and returns a QPainterPath object that is a copy of the
1623 given \a path, mapped into the coordinate system defined by this
1624 matrix.
1625*/
1626QPainterPath QTransform::map(const QPainterPath &path) const
1627{
1628 TransformationType t = inline_type();
1629 if (t == TxNone || path.elementCount() == 0)
1630 return path;
1631
1632 if (t >= TxProject)
1633 return mapProjective(*this, path);
1634
1635 QPainterPath copy = path;
1636
1637 if (t == TxTranslate) {
1638 copy.translate(affine._dx, affine._dy);
1639 } else {
1640 copy.detach();
1641 // Full xform
1642 for (int i=0; i<path.elementCount(); ++i) {
1643 QPainterPath::Element &e = copy.d_ptr->elements[i];
1644 MAP(e.x, e.y, e.x, e.y);
1645 }
1646 }
1647
1648 return copy;
1649}
1650
1651/*!
1652 \fn QPolygon QTransform::mapToPolygon(const QRect &rectangle) const
1653
1654 Creates and returns a QPolygon representation of the given \a
1655 rectangle, mapped into the coordinate system defined by this
1656 matrix.
1657
1658 The rectangle's coordinates are transformed using the following
1659 formulas:
1660
1661 \snippet doc/src/snippets/code/src_gui_painting_qtransform.cpp 1
1662
1663 Polygons and rectangles behave slightly differently when
1664 transformed (due to integer rounding), so
1665 \c{matrix.map(QPolygon(rectangle))} is not always the same as
1666 \c{matrix.mapToPolygon(rectangle)}.
1667
1668 \sa mapRect(), {QTransform#Basic Matrix Operations}{Basic Matrix
1669 Operations}
1670*/
1671QPolygon QTransform::mapToPolygon(const QRect &rect) const
1672{
1673 TransformationType t = inline_type();
1674
1675 QPolygon a(4);
1676 qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
1677 if (t <= TxScale) {
1678 x[0] = affine._m11*rect.x() + affine._dx;
1679 y[0] = affine._m22*rect.y() + affine._dy;
1680 qreal w = affine._m11*rect.width();
1681 qreal h = affine._m22*rect.height();
1682 if (w < 0) {
1683 w = -w;
1684 x[0] -= w;
1685 }
1686 if (h < 0) {
1687 h = -h;
1688 y[0] -= h;
1689 }
1690 x[1] = x[0]+w;
1691 x[2] = x[1];
1692 x[3] = x[0];
1693 y[1] = y[0];
1694 y[2] = y[0]+h;
1695 y[3] = y[2];
1696 } else {
1697 qreal right = rect.x() + rect.width();
1698 qreal bottom = rect.y() + rect.height();
1699 MAP(rect.x(), rect.y(), x[0], y[0]);
1700 MAP(right, rect.y(), x[1], y[1]);
1701 MAP(right, bottom, x[2], y[2]);
1702 MAP(rect.x(), bottom, x[3], y[3]);
1703 }
1704
1705 // all coordinates are correctly, tranform to a pointarray
1706 // (rounding to the next integer)
1707 a.setPoints(4, qRound(x[0]), qRound(y[0]),
1708 qRound(x[1]), qRound(y[1]),
1709 qRound(x[2]), qRound(y[2]),
1710 qRound(x[3]), qRound(y[3]));
1711 return a;
1712}
1713
1714/*!
1715 Creates a transformation matrix, \a trans, that maps a unit square
1716 to a four-sided polygon, \a quad. Returns true if the transformation
1717 is constructed or false if such a transformation does not exist.
1718
1719 \sa quadToSquare(), quadToQuad()
1720*/
1721bool QTransform::squareToQuad(const QPolygonF &quad, QTransform &trans)
1722{
1723 if (quad.count() != 4)
1724 return false;
1725
1726 qreal dx0 = quad[0].x();
1727 qreal dx1 = quad[1].x();
1728 qreal dx2 = quad[2].x();
1729 qreal dx3 = quad[3].x();
1730
1731 qreal dy0 = quad[0].y();
1732 qreal dy1 = quad[1].y();
1733 qreal dy2 = quad[2].y();
1734 qreal dy3 = quad[3].y();
1735
1736 double ax = dx0 - dx1 + dx2 - dx3;
1737 double ay = dy0 - dy1 + dy2 - dy3;
1738
1739 if (!ax && !ay) { //afine transform
1740 trans.setMatrix(dx1 - dx0, dy1 - dy0, 0,
1741 dx2 - dx1, dy2 - dy1, 0,
1742 dx0, dy0, 1);
1743 } else {
1744 double ax1 = dx1 - dx2;
1745 double ax2 = dx3 - dx2;
1746 double ay1 = dy1 - dy2;
1747 double ay2 = dy3 - dy2;
1748
1749 /*determinants */
1750 double gtop = ax * ay2 - ax2 * ay;
1751 double htop = ax1 * ay - ax * ay1;
1752 double bottom = ax1 * ay2 - ax2 * ay1;
1753
1754 double a, b, c, d, e, f, g, h; /*i is always 1*/
1755
1756 if (!bottom)
1757 return false;
1758
1759 g = gtop/bottom;
1760 h = htop/bottom;
1761
1762 a = dx1 - dx0 + g * dx1;
1763 b = dx3 - dx0 + h * dx3;
1764 c = dx0;
1765 d = dy1 - dy0 + g * dy1;
1766 e = dy3 - dy0 + h * dy3;
1767 f = dy0;
1768
1769 trans.setMatrix(a, d, g,
1770 b, e, h,
1771 c, f, 1.0);
1772 }
1773
1774 return true;
1775}
1776
1777/*!
1778 \fn bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1779
1780 Creates a transformation matrix, \a trans, that maps a four-sided polygon,
1781 \a quad, to a unit square. Returns true if the transformation is constructed
1782 or false if such a transformation does not exist.
1783
1784 \sa squareToQuad(), quadToQuad()
1785*/
1786bool QTransform::quadToSquare(const QPolygonF &quad, QTransform &trans)
1787{
1788 if (!squareToQuad(quad, trans))
1789 return false;
1790
1791 bool invertible = false;
1792 trans = trans.inverted(&invertible);
1793
1794 return invertible;
1795}
1796
1797/*!
1798 Creates a transformation matrix, \a trans, that maps a four-sided
1799 polygon, \a one, to another four-sided polygon, \a two.
1800 Returns true if the transformation is possible; otherwise returns
1801 false.
1802
1803 This is a convenience method combining quadToSquare() and
1804 squareToQuad() methods. It allows the input quad to be
1805 transformed into any other quad.
1806
1807 \sa squareToQuad(), quadToSquare()
1808*/
1809bool QTransform::quadToQuad(const QPolygonF &one,
1810 const QPolygonF &two,
1811 QTransform &trans)
1812{
1813 QTransform stq;
1814 if (!quadToSquare(one, trans))
1815 return false;
1816 if (!squareToQuad(two, stq))
1817 return false;
1818 trans *= stq;
1819 //qDebug()<<"Final = "<<trans;
1820 return true;
1821}
1822
1823/*!
1824 Sets the matrix elements to the specified values, \a m11,
1825 \a m12, \a m13 \a m21, \a m22, \a m23 \a m31, \a m32 and
1826 \a m33. Note that this function replaces the previous values.
1827 QTransform provides the translate(), rotate(), scale() and shear()
1828 convenience functions to manipulate the various matrix elements
1829 based on the currently defined coordinate system.
1830
1831 \sa QTransform()
1832*/
1833
1834void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
1835 qreal m21, qreal m22, qreal m23,
1836 qreal m31, qreal m32, qreal m33)
1837{
1838 affine._m11 = m11; affine._m12 = m12; m_13 = m13;
1839 affine._m21 = m21; affine._m22 = m22; m_23 = m23;
1840 affine._dx = m31; affine._dy = m32; m_33 = m33;
1841 m_type = TxNone;
1842 m_dirty = TxProject;
1843}
1844
1845static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
1846{
1847 const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
1848 const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
1849
1850 return wx + wy + transform.m33() < Q_NEAR_CLIP;
1851}
1852
1853QRect QTransform::mapRect(const QRect &rect) const
1854{
1855 TransformationType t = inline_type();
1856 if (t <= TxTranslate)
1857 return rect.translated(qRound(affine._dx), qRound(affine._dy));
1858
1859 if (t <= TxScale) {
1860 int x = qRound(affine._m11*rect.x() + affine._dx);
1861 int y = qRound(affine._m22*rect.y() + affine._dy);
1862 int w = qRound(affine._m11*rect.width());
1863 int h = qRound(affine._m22*rect.height());
1864 if (w < 0) {
1865 w = -w;
1866 x -= w;
1867 }
1868 if (h < 0) {
1869 h = -h;
1870 y -= h;
1871 }
1872 return QRect(x, y, w, h);
1873 } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
1874 // see mapToPolygon for explanations of the algorithm.
1875 qreal x = 0, y = 0;
1876 MAP(rect.left(), rect.top(), x, y);
1877 qreal xmin = x;
1878 qreal ymin = y;
1879 qreal xmax = x;
1880 qreal ymax = y;
1881 MAP(rect.right() + 1, rect.top(), x, y);
1882 xmin = qMin(xmin, x);
1883 ymin = qMin(ymin, y);
1884 xmax = qMax(xmax, x);
1885 ymax = qMax(ymax, y);
1886 MAP(rect.right() + 1, rect.bottom() + 1, x, y);
1887 xmin = qMin(xmin, x);
1888 ymin = qMin(ymin, y);
1889 xmax = qMax(xmax, x);
1890 ymax = qMax(ymax, y);
1891 MAP(rect.left(), rect.bottom() + 1, x, y);
1892 xmin = qMin(xmin, x);
1893 ymin = qMin(ymin, y);
1894 xmax = qMax(xmax, x);
1895 ymax = qMax(ymax, y);
1896 return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
1897 } else {
1898 QPainterPath path;
1899 path.addRect(rect);
1900 return map(path).boundingRect().toRect();
1901 }
1902}
1903
1904/*!
1905 \fn QRectF QTransform::mapRect(const QRectF &rectangle) const
1906
1907 Creates and returns a QRectF object that is a copy of the given \a
1908 rectangle, mapped into the coordinate system defined by this
1909 matrix.
1910
1911 The rectangle's coordinates are transformed using the following
1912 formulas:
1913
1914 \snippet doc/src/snippets/code/src_gui_painting_qtransform.cpp 2
1915
1916 If rotation or shearing has been specified, this function returns
1917 the \e bounding rectangle. To retrieve the exact region the given
1918 \a rectangle maps to, use the mapToPolygon() function instead.
1919
1920 \sa mapToPolygon(), {QTransform#Basic Matrix Operations}{Basic Matrix
1921 Operations}
1922*/
1923QRectF QTransform::mapRect(const QRectF &rect) const
1924{
1925 TransformationType t = inline_type();
1926 if (t <= TxTranslate)
1927 return rect.translated(affine._dx, affine._dy);
1928
1929 if (t <= TxScale) {
1930 qreal x = affine._m11*rect.x() + affine._dx;
1931 qreal y = affine._m22*rect.y() + affine._dy;
1932 qreal w = affine._m11*rect.width();
1933 qreal h = affine._m22*rect.height();
1934 if (w < 0) {
1935 w = -w;
1936 x -= w;
1937 }
1938 if (h < 0) {
1939 h = -h;
1940 y -= h;
1941 }
1942 return QRectF(x, y, w, h);
1943 } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
1944 qreal x = 0, y = 0;
1945 MAP(rect.x(), rect.y(), x, y);
1946 qreal xmin = x;
1947 qreal ymin = y;
1948 qreal xmax = x;
1949 qreal ymax = y;
1950 MAP(rect.x() + rect.width(), rect.y(), x, y);
1951 xmin = qMin(xmin, x);
1952 ymin = qMin(ymin, y);
1953 xmax = qMax(xmax, x);
1954 ymax = qMax(ymax, y);
1955 MAP(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
1956 xmin = qMin(xmin, x);
1957 ymin = qMin(ymin, y);
1958 xmax = qMax(xmax, x);
1959 ymax = qMax(ymax, y);
1960 MAP(rect.x(), rect.y() + rect.height(), x, y);
1961 xmin = qMin(xmin, x);
1962 ymin = qMin(ymin, y);
1963 xmax = qMax(xmax, x);
1964 ymax = qMax(ymax, y);
1965 return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
1966 } else {
1967 QPainterPath path;
1968 path.addRect(rect);
1969 return map(path).boundingRect();
1970 }
1971}
1972
1973/*!
1974 \fn QRect QTransform::mapRect(const QRect &rectangle) const
1975 \overload
1976
1977 Creates and returns a QRect object that is a copy of the given \a
1978 rectangle, mapped into the coordinate system defined by this
1979 matrix. Note that the transformed coordinates are rounded to the
1980 nearest integer.
1981*/
1982
1983/*!
1984 Maps the given coordinates \a x and \a y into the coordinate
1985 system defined by this matrix. The resulting values are put in *\a
1986 tx and *\a ty, respectively.
1987
1988 The coordinates are transformed using the following formulas:
1989
1990 \snippet doc/src/snippets/code/src_gui_painting_qtransform.cpp 3
1991
1992 The point (x, y) is the original point, and (x', y') is the
1993 transformed point.
1994
1995 \sa {QTransform#Basic Matrix Operations}{Basic Matrix Operations}
1996*/
1997void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
1998{
1999 TransformationType t = inline_type();
2000 MAP(x, y, *tx, *ty);
2001}
2002
2003/*!
2004 \overload
2005
2006 Maps the given coordinates \a x and \a y into the coordinate
2007 system defined by this matrix. The resulting values are put in *\a
2008 tx and *\a ty, respectively. Note that the transformed coordinates
2009 are rounded to the nearest integer.
2010*/
2011void QTransform::map(int x, int y, int *tx, int *ty) const
2012{
2013 TransformationType t = inline_type();
2014 qreal fx = 0, fy = 0;
2015 MAP(x, y, fx, fy);
2016 *tx = qRound(fx);
2017 *ty = qRound(fy);
2018}
2019
2020/*!
2021 Returns the QTransform as an affine matrix.
2022
2023 \warning If a perspective transformation has been specified,
2024 then the conversion will cause loss of data.
2025*/
2026const QMatrix &QTransform::toAffine() const
2027{
2028 return affine;
2029}
2030
2031/*!
2032 Returns the transformation type of this matrix.
2033
2034 The transformation type is the highest enumeration value
2035 capturing all of the matrix's transformations. For example,
2036 if the matrix both scales and shears, the type would be \c TxShear,
2037 because \c TxShear has a higher enumeration value than \c TxScale.
2038
2039 Knowing the transformation type of a matrix is useful for optimization:
2040 you can often handle specific types more optimally than handling
2041 the generic case.
2042 */
2043QTransform::TransformationType QTransform::type() const
2044{
2045 if(m_dirty == TxNone || m_dirty < m_type)
2046 return static_cast<TransformationType>(m_type);
2047
2048 switch (static_cast<TransformationType>(m_dirty)) {
2049 case TxProject:
2050 if (!qFuzzyIsNull(m_13) || !qFuzzyIsNull(m_23) || !qFuzzyIsNull(m_33 - 1)) {
2051 m_type = TxProject;
2052 break;
2053 }
2054 case TxShear:
2055 case TxRotate:
2056 if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) {
2057 const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22;
2058 if (qFuzzyIsNull(dot))
2059 m_type = TxRotate;
2060 else
2061 m_type = TxShear;
2062 break;
2063 }
2064 case TxScale:
2065 if (!qFuzzyIsNull(affine._m11 - 1) || !qFuzzyIsNull(affine._m22 - 1)) {
2066 m_type = TxScale;
2067 break;
2068 }
2069 case TxTranslate:
2070 if (!qFuzzyIsNull(affine._dx) || !qFuzzyIsNull(affine._dy)) {
2071 m_type = TxTranslate;
2072 break;
2073 }
2074 case TxNone:
2075 m_type = TxNone;
2076 break;
2077 }
2078
2079 m_dirty = TxNone;
2080 return static_cast<TransformationType>(m_type);
2081}
2082
2083/*!
2084
2085 Returns the transform as a QVariant.
2086*/
2087QTransform::operator QVariant() const
2088{
2089 return QVariant(QVariant::Transform, this);
2090}
2091
2092
2093/*!
2094 \fn bool QTransform::isInvertible() const
2095
2096 Returns true if the matrix is invertible, otherwise returns false.
2097
2098 \sa inverted()
2099*/
2100
2101/*!
2102 \fn qreal QTransform::det() const
2103 \obsolete
2104
2105 Returns the matrix's determinant. Use determinant() instead.
2106*/
2107
2108
2109/*!
2110 \fn qreal QTransform::m11() const
2111
2112 Returns the horizontal scaling factor.
2113
2114 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
2115 Operations}
2116*/
2117
2118/*!
2119 \fn qreal QTransform::m12() const
2120
2121 Returns the vertical shearing factor.
2122
2123 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
2124 Operations}
2125*/
2126
2127/*!
2128 \fn qreal QTransform::m21() const
2129
2130 Returns the horizontal shearing factor.
2131
2132 \sa shear(), {QTransform#Basic Matrix Operations}{Basic Matrix
2133 Operations}
2134*/
2135
2136/*!
2137 \fn qreal QTransform::m22() const
2138
2139 Returns the vertical scaling factor.
2140
2141 \sa scale(), {QTransform#Basic Matrix Operations}{Basic Matrix
2142 Operations}
2143*/
2144
2145/*!
2146 \fn qreal QTransform::dx() const
2147
2148 Returns the horizontal translation factor.
2149
2150 \sa m31(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2151 Operations}
2152*/
2153
2154/*!
2155 \fn qreal QTransform::dy() const
2156
2157 Returns the vertical translation factor.
2158
2159 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2160 Operations}
2161*/
2162
2163
2164/*!
2165 \fn qreal QTransform::m13() const
2166
2167 Returns the horizontal projection factor.
2168
2169 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2170 Operations}
2171*/
2172
2173
2174/*!
2175 \fn qreal QTransform::m23() const
2176
2177 Returns the vertical projection factor.
2178
2179 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2180 Operations}
2181*/
2182
2183/*!
2184 \fn qreal QTransform::m31() const
2185
2186 Returns the horizontal translation factor.
2187
2188 \sa dx(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2189 Operations}
2190*/
2191
2192/*!
2193 \fn qreal QTransform::m32() const
2194
2195 Returns the vertical translation factor.
2196
2197 \sa dy(), translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2198 Operations}
2199*/
2200
2201/*!
2202 \fn qreal QTransform::m33() const
2203
2204 Returns the division factor.
2205
2206 \sa translate(), {QTransform#Basic Matrix Operations}{Basic Matrix
2207 Operations}
2208*/
2209
2210/*!
2211 \fn qreal QTransform::determinant() const
2212
2213 Returns the matrix's determinant.
2214*/
2215
2216/*!
2217 \fn bool QTransform::isIdentity() const
2218
2219 Returns true if the matrix is the identity matrix, otherwise
2220 returns false.
2221
2222 \sa reset()
2223*/
2224
2225/*!
2226 \fn bool QTransform::isAffine() const
2227
2228 Returns true if the matrix represent an affine transformation,
2229 otherwise returns false.
2230*/
2231
2232/*!
2233 \fn bool QTransform::isScaling() const
2234
2235 Returns true if the matrix represents a scaling
2236 transformation, otherwise returns false.
2237
2238 \sa reset()
2239*/
2240
2241/*!
2242 \fn bool QTransform::isRotating() const
2243
2244 Returns true if the matrix represents some kind of a
2245 rotating transformation, otherwise returns false.
2246
2247 \sa reset()
2248*/
2249
2250/*!
2251 \fn bool QTransform::isTranslating() const
2252
2253 Returns true if the matrix represents a translating
2254 transformation, otherwise returns false.
2255
2256 \sa reset()
2257*/
2258
2259/*!
2260 \fn bool qFuzzyCompare(const QTransform& t1, const QTransform& t2)
2261
2262 \relates QTransform
2263 \since 4.6
2264
2265 Returns true if \a t1 and \a t2 are equal, allowing for a small
2266 fuzziness factor for floating-point comparisons; false otherwise.
2267*/
2268
2269
2270// returns true if the transform is uniformly scaling
2271// (same scale in x and y direction)
2272// scale is set to the max of x and y scaling factors
2273Q_GUI_EXPORT
2274bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
2275{
2276 const QTransform::TransformationType type = transform.type();
2277 if (type <= QTransform::TxTranslate) {
2278 if (scale)
2279 *scale = 1;
2280 return true;
2281 } else if (type == QTransform::TxScale) {
2282 const qreal xScale = qAbs(transform.m11());
2283 const qreal yScale = qAbs(transform.m22());
2284 if (scale)
2285 *scale = qMax(xScale, yScale);
2286 return qFuzzyCompare(xScale, yScale);
2287 }
2288
2289 const qreal xScale = transform.m11() * transform.m11()
2290 + transform.m21() * transform.m21();
2291 const qreal yScale = transform.m12() * transform.m12()
2292 + transform.m22() * transform.m22();
2293 if (scale)
2294 *scale = qSqrt(qMax(xScale, yScale));
2295 return type == QTransform::TxRotate && qFuzzyCompare(xScale, yScale);
2296}
2297
2298QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.