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

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

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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