source: trunk/src/gui/painting/qmatrix.cpp@ 347

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

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

File size: 31.4 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
42#include "qdatastream.h"
43#include "qdebug.h"
44#include "qmatrix.h"
45#include "qregion.h"
46#include "qpainterpath.h"
47#include "qvariant.h"
48#include <qmath.h>
49
50#include <limits.h>
51
52QT_BEGIN_NAMESPACE
53
54/*!
55 \class QMatrix
56 \brief The QMatrix class specifies 2D transformations of a
57 coordinate system.
58
59 \ingroup multimedia
60
61 A matrix specifies how to translate, scale, shear or rotate the
62 coordinate system, and is typically used when rendering graphics.
63
64 A QMatrix object can be built using the setMatrix(), scale(),
65 rotate(), translate() and shear() functions. Alternatively, it
66 can be built by applying \l {QMatrix#Basic Matrix
67 Operations}{basic matrix operations}. The matrix can also be
68 defined when constructed, and it can be reset to the identity
69 matrix (the default) using the reset() function.
70
71 The QMatrix class supports mapping of graphic primitives: A given
72 point, line, polygon, region, or painter path can be mapped to the
73 coordinate system defined by \e this matrix using the map()
74 function. In case of a rectangle, its coordinates can be
75 transformed using the mapRect() function. A rectangle can also be
76 transformed into a \e polygon (mapped to the coordinate system
77 defined by \e this matrix), using the mapToPolygon() function.
78
79 QMatrix provides the isIdentity() function which returns true if
80 the matrix is the identity matrix, and the isInvertible() function
81 which returns true if the matrix is non-singular (i.e. AB = BA =
82 I). The inverted() function returns an inverted copy of \e this
83 matrix if it is invertible (otherwise it returns the identity
84 matrix). In addition, QMatrix provides the det() function
85 returning the matrix's determinant.
86
87 Finally, the QMatrix class supports matrix multiplication, and
88 objects of the class can be streamed as well as compared.
89
90 \tableofcontents
91
92 \section1 Rendering Graphics
93
94 When rendering graphics, the matrix defines the transformations
95 but the actual transformation is performed by the drawing routines
96 in QPainter.
97
98 By default, QPainter operates on the associated device's own
99 coordinate system. The standard coordinate system of a
100 QPaintDevice has its origin located at the top-left position. The
101 \e x values increase to the right; \e y values increase
102 downward. For a complete description, see the \l {The Coordinate
103 System}{coordinate system} documentation.
104
105 QPainter has functions to translate, scale, shear and rotate the
106 coordinate system without using a QMatrix. For example:
107
108 \table 100%
109 \row
110 \o \inlineimage qmatrix-simpletransformation.png
111 \o
112 \snippet doc/src/snippets/matrix/matrix.cpp 0
113 \endtable
114
115 Although these functions are very convenient, it can be more
116 efficient to build a QMatrix and call QPainter::setMatrix() if you
117 want to perform more than a single transform operation. For
118 example:
119
120 \table 100%
121 \row
122 \o \inlineimage qmatrix-combinedtransformation.png
123 \o
124 \snippet doc/src/snippets/matrix/matrix.cpp 1
125 \endtable
126
127 \section1 Basic Matrix Operations
128
129 \image qmatrix-representation.png
130
131 A QMatrix object contains a 3 x 3 matrix. The \c dx and \c dy
132 elements specify horizontal and vertical translation. The \c m11
133 and \c m22 elements specify horizontal and vertical scaling. And
134 finally, the \c m21 and \c m12 elements specify horizontal and
135 vertical \e shearing.
136
137 QMatrix transforms a point in the plane to another point using the
138 following formulas:
139
140 \snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 0
141
142 The point \e (x, y) is the original point, and \e (x', y') is the
143 transformed point. \e (x', y') can be transformed back to \e (x,
144 y) by performing the same operation on the inverted() matrix.
145
146 The various matrix elements can be set when constructing the
147 matrix, or by using the setMatrix() function later on. They can also
148 be manipulated using the translate(), rotate(), scale() and
149 shear() convenience functions, The currently set values can be
150 retrieved using the m11(), m12(), m21(), m22(), dx() and dy()
151 functions.
152
153 Translation is the simplest transformation. Setting \c dx and \c
154 dy will move the coordinate system \c dx units along the X axis
155 and \c dy units along the Y axis. Scaling can be done by setting
156 \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to
157 1.5 will double the height and increase the width by 50%. The
158 identity matrix has \c m11 and \c m22 set to 1 (all others are set
159 to 0) mapping a point to itself. Shearing is controlled by \c m12
160 and \c m21. Setting these elements to values different from zero
161 will twist the coordinate system. Rotation is achieved by
162 carefully setting both the shearing factors and the scaling
163 factors.
164
165 Here's the combined transformations example using basic matrix
166 operations:
167
168 \table 100%
169 \row
170 \o \inlineimage qmatrix-combinedtransformation.png
171 \o
172 \snippet doc/src/snippets/matrix/matrix.cpp 2
173 \endtable
174
175 \sa QPainter, {The Coordinate System}, {demos/affine}{Affine
176 Transformations Demo}, {Transformations Example}
177*/
178
179
180// some defines to inline some code
181#define MAPDOUBLE(x, y, nx, ny) \
182{ \
183 qreal fx = x; \
184 qreal fy = y; \
185 nx = _m11*fx + _m21*fy + _dx; \
186 ny = _m12*fx + _m22*fy + _dy; \
187}
188
189#define MAPINT(x, y, nx, ny) \
190{ \
191 qreal fx = x; \
192 qreal fy = y; \
193 nx = qRound(_m11*fx + _m21*fy + _dx); \
194 ny = qRound(_m12*fx + _m22*fy + _dy); \
195}
196
197/*****************************************************************************
198 QMatrix member functions
199 *****************************************************************************/
200
201/*!
202 Constructs an identity matrix.
203
204 All elements are set to zero except \c m11 and \c m22 (specifying
205 the scale), which are set to 1.
206
207 \sa reset()
208*/
209
210QMatrix::QMatrix()
211{
212 _m11 = _m22 = 1.0;
213 _m12 = _m21 = _dx = _dy = 0.0;
214}
215
216/*!
217 Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a
218 m22, \a dx and \a dy.
219
220 \sa setMatrix()
221*/
222
223QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22,
224 qreal dx, qreal dy)
225{
226 _m11 = m11; _m12 = m12;
227 _m21 = m21; _m22 = m22;
228 _dx = dx; _dy = dy;
229}
230
231
232/*!
233 Constructs a matrix that is a copy of the given \a matrix.
234 */
235QMatrix::QMatrix(const QMatrix &matrix)
236{
237 *this = matrix;
238}
239
240/*!
241 Sets the matrix elements to the specified values, \a m11, \a m12,
242 \a m21, \a m22, \a dx and \a dy.
243
244 Note that this function replaces the previous values. QMatrix
245 provide the translate(), rotate(), scale() and shear() convenience
246 functions to manipulate the various matrix elements based on the
247 currently defined coordinate system.
248
249 \sa QMatrix()
250*/
251
252void QMatrix::setMatrix(qreal m11, qreal m12, qreal m21, qreal m22,
253 qreal dx, qreal dy)
254{
255 _m11 = m11; _m12 = m12;
256 _m21 = m21; _m22 = m22;
257 _dx = dx; _dy = dy;
258}
259
260
261/*!
262 \fn qreal QMatrix::m11() const
263
264 Returns the horizontal scaling factor.
265
266 \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix
267 Operations}
268*/
269
270/*!
271 \fn qreal QMatrix::m12() const
272
273 Returns the vertical shearing factor.
274
275 \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix
276 Operations}
277*/
278
279/*!
280 \fn qreal QMatrix::m21() const
281
282 Returns the horizontal shearing factor.
283
284 \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix
285 Operations}
286*/
287
288/*!
289 \fn qreal QMatrix::m22() const
290
291 Returns the vertical scaling factor.
292
293 \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix
294 Operations}
295*/
296
297/*!
298 \fn qreal QMatrix::dx() const
299
300 Returns the horizontal translation factor.
301
302 \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix
303 Operations}
304*/
305
306/*!
307 \fn qreal QMatrix::dy() const
308
309 Returns the vertical translation factor.
310
311 \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix
312 Operations}
313*/
314
315
316/*!
317 Maps the given coordinates \a x and \a y into the coordinate
318 system defined by this matrix. The resulting values are put in *\a
319 tx and *\a ty, respectively.
320
321 The coordinates are transformed using the following formulas:
322
323 \snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 1
324
325 The point (x, y) is the original point, and (x', y') is the
326 transformed point.
327
328 \sa {QMatrix#Basic Matrix Operations}{Basic Matrix Operations}
329*/
330
331void QMatrix::map(qreal x, qreal y, qreal *tx, qreal *ty) const
332{
333 MAPDOUBLE(x, y, *tx, *ty);
334}
335
336
337
338/*!
339 \overload
340
341 Maps the given coordinates \a x and \a y into the coordinate
342 system defined by this matrix. The resulting values are put in *\a
343 tx and *\a ty, respectively. Note that the transformed coordinates
344 are rounded to the nearest integer.
345*/
346
347void QMatrix::map(int x, int y, int *tx, int *ty) const
348{
349 MAPINT(x, y, *tx, *ty);
350}
351
352QRect QMatrix::mapRect(const QRect &rect) const
353{
354 QRect result;
355 if (_m12 == 0.0F && _m21 == 0.0F) {
356 int x = qRound(_m11*rect.x() + _dx);
357 int y = qRound(_m22*rect.y() + _dy);
358 int w = qRound(_m11*rect.width());
359 int h = qRound(_m22*rect.height());
360 if (w < 0) {
361 w = -w;
362 x -= w;
363 }
364 if (h < 0) {
365 h = -h;
366 y -= h;
367 }
368 result = QRect(x, y, w, h);
369 } else {
370 // see mapToPolygon for explanations of the algorithm.
371 qreal x0, y0;
372 qreal x, y;
373 MAPDOUBLE(rect.left(), rect.top(), x0, y0);
374 qreal xmin = x0;
375 qreal ymin = y0;
376 qreal xmax = x0;
377 qreal ymax = y0;
378 MAPDOUBLE(rect.right() + 1, rect.top(), x, y);
379 xmin = qMin(xmin, x);
380 ymin = qMin(ymin, y);
381 xmax = qMax(xmax, x);
382 ymax = qMax(ymax, y);
383 MAPDOUBLE(rect.right() + 1, rect.bottom() + 1, x, y);
384 xmin = qMin(xmin, x);
385 ymin = qMin(ymin, y);
386 xmax = qMax(xmax, x);
387 ymax = qMax(ymax, y);
388 MAPDOUBLE(rect.left(), rect.bottom() + 1, x, y);
389 xmin = qMin(xmin, x);
390 ymin = qMin(ymin, y);
391 xmax = qMax(xmax, x);
392 ymax = qMax(ymax, y);
393 result = QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
394 }
395 return result;
396}
397
398/*!
399 \fn QRectF QMatrix::mapRect(const QRectF &rectangle) const
400
401 Creates and returns a QRectF object that is a copy of the given \a
402 rectangle, mapped into the coordinate system defined by this
403 matrix.
404
405 The rectangle's coordinates are transformed using the following
406 formulas:
407
408 \snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 2
409
410 If rotation or shearing has been specified, this function returns
411 the \e bounding rectangle. To retrieve the exact region the given
412 \a rectangle maps to, use the mapToPolygon() function instead.
413
414 \sa mapToPolygon(), {QMatrix#Basic Matrix Operations}{Basic Matrix
415 Operations}
416*/
417QRectF QMatrix::mapRect(const QRectF &rect) const
418{
419 QRectF result;
420 if (_m12 == 0.0F && _m21 == 0.0F) {
421 qreal x = _m11*rect.x() + _dx;
422 qreal y = _m22*rect.y() + _dy;
423 qreal w = _m11*rect.width();
424 qreal h = _m22*rect.height();
425 if (w < 0) {
426 w = -w;
427 x -= w;
428 }
429 if (h < 0) {
430 h = -h;
431 y -= h;
432 }
433 result = QRectF(x, y, w, h);
434 } else {
435 qreal x0, y0;
436 qreal x, y;
437 MAPDOUBLE(rect.x(), rect.y(), x0, y0);
438 qreal xmin = x0;
439 qreal ymin = y0;
440 qreal xmax = x0;
441 qreal ymax = y0;
442 MAPDOUBLE(rect.x() + rect.width(), rect.y(), x, y);
443 xmin = qMin(xmin, x);
444 ymin = qMin(ymin, y);
445 xmax = qMax(xmax, x);
446 ymax = qMax(ymax, y);
447 MAPDOUBLE(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
448 xmin = qMin(xmin, x);
449 ymin = qMin(ymin, y);
450 xmax = qMax(xmax, x);
451 ymax = qMax(ymax, y);
452 MAPDOUBLE(rect.x(), rect.y() + rect.height(), x, y);
453 xmin = qMin(xmin, x);
454 ymin = qMin(ymin, y);
455 xmax = qMax(xmax, x);
456 ymax = qMax(ymax, y);
457 result = QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
458 }
459 return result;
460}
461
462/*!
463 \fn QRect QMatrix::mapRect(const QRect &rectangle) const
464 \overload
465
466 Creates and returns a QRect object that is a copy of the given \a
467 rectangle, mapped into the coordinate system defined by this
468 matrix. Note that the transformed coordinates are rounded to the
469 nearest integer.
470*/
471
472
473/*!
474 \fn QPoint operator*(const QPoint &point, const QMatrix &matrix)
475 \relates QMatrix
476
477 This is the same as \a{matrix}.map(\a{point}).
478
479 \sa QMatrix::map()
480*/
481
482QPoint QMatrix::map(const QPoint &p) const
483{
484 qreal fx = p.x();
485 qreal fy = p.y();
486 return QPoint(qRound(_m11*fx + _m21*fy + _dx),
487 qRound(_m12*fx + _m22*fy + _dy));
488}
489
490/*!
491 \fn QPointF operator*(const QPointF &point, const QMatrix &matrix)
492 \relates QMatrix
493
494 Same as \a{matrix}.map(\a{point}).
495
496 \sa QMatrix::map()
497*/
498
499/*!
500 \overload
501
502 Creates and returns a QPointF object that is a copy of the given
503 \a point, mapped into the coordinate system defined by this
504 matrix.
505*/
506QPointF QMatrix::map(const QPointF &point) const
507{
508 qreal fx = point.x();
509 qreal fy = point.y();
510 return QPointF(_m11*fx + _m21*fy + _dx, _m12*fx + _m22*fy + _dy);
511}
512
513/*!
514 \fn QPoint QMatrix::map(const QPoint &point) const
515 \overload
516
517 Creates and returns a QPoint object that is a copy of the given \a
518 point, mapped into the coordinate system defined by this
519 matrix. Note that the transformed coordinates are rounded to the
520 nearest integer.
521*/
522