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 |
|
---|
54 | QT_BEGIN_NAMESPACE
|
---|
55 |
|
---|
56 | #define Q_NEAR_CLIP (sizeof(qreal) == sizeof(double) ? 0.000001 : 0.0001)
|
---|
57 |
|
---|
58 | #ifdef MAP
|
---|
59 | # undef MAP
|
---|
60 | #endif
|
---|
61 | #define MAP(x, y, nx, ny) \
|
---|
62 | do { \
|
---|
63 | qreal FX_ = x; \
|
---|
64 | qreal FY_ = y; \
|
---|
65 | switch(t) { \
|
---|
66 | case TxNone: \
|
---|
67 | nx = FX_; \
|
---|
68 | ny = FY_; \
|
---|
69 | break; \
|
---|
70 | case TxTranslate: \
|
---|
71 | nx = FX_ + affine._dx; \
|
---|
72 | ny = FY_ + affine._dy; \
|
---|
73 | break; \
|
---|
74 | case TxScale: \
|
---|
75 | nx = affine._m11 * FX_ + affine._dx; \
|
---|
76 | ny = affine._m22 * FY_ + affine._dy; \
|
---|
77 | break; \
|
---|
78 | case TxRotate: \
|
---|
79 | case TxShear: \
|
---|
80 | case TxProject: \
|
---|
81 | nx = affine._m11 * FX_ + affine._m21 * FY_ + affine._dx; \
|
---|
82 | ny = affine._m12 * FX_ + affine._m22 * FY_ + affine._dy; \
|
---|
83 | if (t == TxProject) { \
|
---|
84 | qreal w = (m_13 * FX_ + m_23 * FY_ + m_33); \
|
---|
85 | if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
|
---|
86 | w = 1./w; \
|
---|
87 | nx *= w; \
|
---|
88 | ny *= w; \
|
---|
89 | } \
|
---|
90 | } \
|
---|
91 | } while (0)
|
---|
92 |
|
---|
93 | /*!
|
---|
94 | \class QTransform
|
---|
95 | \brief The QTransform class specifies 2D transformations of a coordinate system.
|
---|
96 | \since 4.3
|
---|
97 | \ingroup painting
|
---|
98 |
|
---|
99 | A transformation specifies how to translate, scale, shear, rotate
|
---|
100 | or project the coordinate system, and is typically used when
|
---|
101 | rendering graphics.
|
---|
102 |
|
---|
103 | QTransform differs from QMatrix in that it is a true 3x3 matrix,
|
---|
104 | allowing perspective transformations. QTransform's toAffine()
|
---|
105 | method allows casting QTransform to QMatrix. If a perspective
|
---|
106 | transformation has been specified on the matrix, then the
|
---|
107 | conversion will cause loss of data.
|
---|
108 |
|
---|
109 | QTransform is the recommended transformation class in Qt.
|
---|
110 |
|
---|
111 | A QTransform object can be built using the setMatrix(), scale(),
|
---|
112 | rotate(), translate() and shear() functions. Alternatively, it
|
---|
113 | can be built by applying \l {QTransform#Basic Matrix
|
---|
114 | Operations}{basic matrix operations}. The matrix can also be
|
---|
115 | defined when constructed, and it can be reset to the identity
|
---|
116 | matrix (the default) using the reset() function.
|
---|
117 |
|
---|
118 | The QTransform class supports mapping of graphic primitives: A given
|
---|
119 | point, line, polygon, region, or painter path can be mapped to the
|
---|
120 | coordinate system defined by \e this matrix using the map()
|
---|
121 | function. In case of a rectangle, its coordinates can be
|
---|
122 | transformed using the mapRect() function. A rectangle can also be
|
---|
123 | transformed into a \e polygon (mapped to the coordinate system
|
---|
124 | defined by \e this matrix), using the mapToPolygon() function.
|
---|
125 |
|
---|
126 | QTransform provides the isIdentity() function which returns true if
|
---|
127 | the matrix is the identity matrix, and the isInvertible() function
|
---|
128 | which returns true if the matrix is non-singular (i.e. AB = BA =
|
---|
129 | I). The inverted() function returns an inverted copy of \e this
|
---|
130 | matrix if it is invertible (otherwise it returns the identity
|
---|
131 | matrix), and adjoint() returns the matrix's classical adjoint.
|
---|
132 | In addition, QTransform provides the determinant() function which
|
---|
133 | returns the matrix's determinant.
|
---|
134 |
|
---|
135 | Finally, the QTransform class supports matrix multiplication, addition
|
---|
136 | and subtraction, and objects of the class can be streamed as well
|
---|
137 | as compared.
|
---|
138 |
|
---|
139 | \tableofcontents
|
---|
140 |
|
---|
141 | \section1 Rendering Graphics
|
---|
142 |
|
---|
143 | When rendering graphics, the matrix defines the transformations
|
---|
144 | but the actual transformation is performed by the drawing routines
|
---|
145 | in QPainter.
|
---|
146 |
|
---|
147 | By default, QPainter operates on the associated device's own
|
---|
148 | coordinate system. The standard coordinate system of a
|
---|
149 | QPaintDevice has its origin located at the top-left position. The
|
---|
150 | \e x values increase to the right; \e y values increase
|
---|
151 | downward. For a complete description, see the \l {Coordinate
|
---|
152 | System} {coordinate system} documentation.
|
---|
153 |
|
---|
154 | QPainter has functions to translate, scale, shear and rotate the
|
---|
155 | coordinate system without using a QTransform. For example:
|
---|
156 |
|
---|
157 | \table 100%
|
---|
158 | \row
|
---|
159 | \o \inlineimage qtransform-simpletransformation.png
|
---|
160 | \o
|
---|
161 | \snippet doc/src/snippets/transform/main.cpp 0
|
---|
162 | \endtable
|
---|
163 |
|
---|
164 | Although these functions are very convenient, it can be more
|
---|
165 | efficient to build a QTransform and call QPainter::setTransform() if you
|
---|
166 | want to perform more than a single transform operation. For
|
---|
167 | example:
|
---|
168 |
|
---|
169 | \table 100%
|
---|
170 | \row
|
---|
171 | \o \inlineimage qtransform-combinedtransformation.png
|
---|
172 | \o
|
---|
173 | \snippet doc/src/snippets/transform/main.cpp 1
|
---|
174 | \endtable
|
---|
175 |
|
---|
176 | \section1 Basic Matrix Operations
|
---|
177 |
|
---|
178 | \image qtransform-representation.png
|
---|
179 |
|
---|
180 | A QTransform object contains a 3 x 3 matrix. The \c m31 (\c dx) and
|
---|
181 | \c m32 (\c dy) elements specify horizontal and vertical translation.
|
---|
182 | The \c m11 and \c m22 elements specify horizontal and vertical scaling.
|
---|
183 | The \c m21 and \c m12 elements specify horizontal and vertical \e shearing.
|
---|
184 | And finally, the \c m13 and \c m23 elements specify horizontal and vertical
|
---|
185 | projection, with \c m33 as an additional projection factor.
|
---|
186 |
|
---|
187 | QTransform transforms a point in the plane to another point using the
|
---|
188 | following formulas:
|
---|
189 |
|
---|
190 | \snippet doc/src/snippets/code/src_gui_painting_qtransform.cpp 0
|
---|
191 |
|
---|
192 | The point \e (x, y) is the original point, and \e (x', y') is the
|
---|
193 | transformed point. \e (x', y') can be transformed back to \e (x,
|
---|
194 | y) by performing the same operation on the inverted() matrix.
|
---|
195 |
|
---|
196 | The various matrix elements can be set when constructing the
|
---|
197 | matrix, or by using the setMatrix() function later on. They can also
|
---|
198 | be manipulated using the translate(), rotate(), scale() and
|
---|
199 | shear() convenience functions. The currently set values can be
|
---|
200 | retrieved using the m11(), m12(), m13(), m21(), m22(), m23(),
|
---|
201 | m31(), m32(), m33(), dx() and dy() functions.
|
---|
202 |
|
---|
203 | Translation is the simplest transformation. Setting \c dx and \c
|
---|
204 | dy will move the coordinate system \c dx units along the X axis
|
---|
205 | and \c dy units along the Y axis. Scaling can be done by setting
|
---|
206 | \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to
|
---|
207 | 1.5 will double the height and increase the width by 50%. The
|
---|
208 | identity matrix has \c m11, \c m22, and \c m33 set to 1 (all others are set
|
---|
209 | to 0) mapping a point to itself. Shearing is controlled by \c m12
|
---|
210 | and \c m21. Setting these elements to values different from zero
|
---|
211 | will twist the coordinate system. Rotation is achieved by
|
---|
212 | setting both the shearing factors and the scaling factors. Perspective
|
---|
213 | transformation is achieved by setting both the projection factors and
|
---|
214 | the scaling factors.
|
---|
215 |
|
---|
216 | Here's the combined transformations example using basic matrix
|
---|
217 | operations:
|
---|
218 |
|
---|
219 | \table 100%
|
---|
220 | \row
|
---|
221 | \o \inlineimage qtransform-combinedtransformation2.png
|
---|
222 | \o
|
---|
223 | \snippet doc/src/snippets/transform/main.cpp 2
|
---|
224 | \endtable
|
---|
225 |
|
---|
226 | \sa QPainter, {Coordinate System}, {demos/affine}{Affine
|
---|
227 | Transformations Demo}, {Transformations Example}
|
---|
228 | */
|
---|
229 |
|
---|
230 | /*!
|
---|
231 | \enum QTransform::TransformationType
|
---|
232 |
|
---|
233 | \value TxNone
|
---|
234 | \value TxTranslate
|
---|
235 | \value TxScale
|
---|
236 | \value TxRotate
|
---|
237 | \value TxShear
|
---|
238 | \value TxProject
|
---|
239 | */
|
---|
240 |
|
---|
241 | /*!
|
---|
242 | \fn QTransform::QTransform(Qt::Initialization)
|
---|
243 | \internal
|
---|
244 | */
|
---|
245 |
|
---|
246 | /*!
|
---|
247 | Constructs an identity matrix.
|
---|
248 |
|
---|
249 | All elements are set to zero except \c m11 and \c m22 (specifying
|
---|
250 | the scale) and \c m13 which are set to 1.
|
---|
251 |
|
---|
252 | \sa reset()
|
---|
253 | */
|
---|
254 | QTransform::QTransform()
|
---|
255 | : affine(true)
|
---|
256 | , m_13(0), m_23(0), m_33(1)
|
---|
257 | , m_type(TxNone)
|
---|
258 | , m_dirty(TxNone)
|
---|
259 | {
|
---|
260 | }
|
---|
261 |
|
---|
262 | /*!
|
---|
263 | \fn QTransform::QTransform(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33)
|
---|
264 |
|
---|
265 | Constructs a matrix with the elements, \a m11, \a m12, \a m13,
|
---|
266 | \a m21, \a m22, \a m23, \a m31, \a m32, \a m33.
|
---|
267 |
|
---|
268 | \sa setMatrix()
|
---|
269 | */
|
---|
270 | QTransform::QTransform(qreal h11, qreal h12, qreal h13,
|
---|
271 | qreal h21, qreal h22, qreal h23,
|
---|
272 | qreal h31, qreal h32, qreal h33)
|
---|
273 | : affine(h11, h12, h21, h22, h31, h32, true)
|
---|
274 | , m_13(h13), m_23(h23), m_33(h33)
|
---|
275 | , m_type(TxNone)
|
---|
276 | , m_dirty(TxProject)
|
---|
277 | {
|
---|
278 | }
|
---|
279 |
|
---|
280 | /*!
|
---|
281 | \fn QTransform::QTransform(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
|
---|
282 |
|
---|
283 | Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a m22, \a dx and \a dy.
|
---|
284 |
|
---|
285 | \sa setMatrix()
|
---|
286 | */
|
---|
287 | QTransform::QTransform(qreal h11, qreal h12, qreal h21,
|
---|
288 | qreal h22, qreal dx, qreal dy)
|
---|
289 | : affine(h11, h12, h21, h22, dx, dy, true)
|
---|
290 | , m_13(0), m_23(0), m_33(1)
|
---|
291 | , m_type(TxNone)
|
---|
292 | , m_dirty(TxShear)
|
---|
293 | {
|
---|
294 | }
|
---|
295 |
|
---|
296 | /*!
|
---|
297 | \fn QTransform::QTransform(const QMatrix &matrix)
|
---|
298 |
|
---|
299 | Constructs a matrix that is a copy of the given \a matrix.
|
---|
300 | Note that the \c m13, \c m23, and \c m33 elements are set to 0, 0,
|
---|
301 | and 1 respectively.
|
---|
302 | */
|
---|
303 | QTransform::QTransform(const QMatrix &mtx)
|
---|
304 | : affine(mtx._m11, mtx._m12, mtx._m21, mtx._m22, mtx._dx, mtx._dy, true),
|
---|
305 | m_13(0), m_23(0), m_33(1)
|
---|
306 | , m_type(TxNone)
|
---|
307 | , m_dirty(TxShear)
|
---|
308 | {
|
---|
309 | }
|
---|
310 |
|
---|
311 | /*!
|
---|
312 | Returns the adjoint of this matrix.
|
---|
313 | */
|
---|
314 | QTransform QTransform::adjoint() const
|
---|
315 | {
|
---|
316 | qreal h11, h12, h13,
|
---|
317 | h21, h22, h23,
|
---|
318 | h31, h32, h33;
|
---|
319 | h11 = affine._m22*m_33 - m_23*affine._dy;
|
---|
320 | h21 = m_23*affine._dx - affine._m21*m_33;
|
---|
321 | h31 = affine._m21*affine._dy - affine._m22*affine._dx;
|
---|
322 | h12 = m_13*affine._dy - affine._m12*m_33;
|
---|
323 | h22 = affine._m11*m_33 - m_13*affine._dx;
|
---|
324 | h32 = affine._m12*affine._dx - affine._m11*affine._dy;
|
---|
325 | h13 = affine._m12*m_23 - m_13*affine._m22;
|
---|
326 | h23 = m_13*affine._m21 - affine._m11*m_23;
|
---|
327 | h33 = affine._m11*affine._m22 - affine._m12*affine._m21;
|
---|
328 |
|
---|
329 | return QTransform(h11, h12, h13,
|
---|
330 | h21, h22, h23,
|
---|
331 | h31, h32, h33, true);
|
---|
332 | }
|
---|
333 |
|
---|
334 | /*!
|
---|
335 | Returns the transpose of this matrix.
|
---|
336 | */
|
---|
337 | QTransform QTransform::transposed() const
|
---|
338 | {
|
---|
339 | QTransform t(affine._m11, affine._m21, affine._dx,
|
---|
340 | affine._m12, affine._m22, affine._dy,
|
---|
341 | m_13, m_23, m_33, true);
|
---|
342 | t.m_type = m_type;
|
---|
343 | t.m_dirty = m_dirty;
|
---|
344 | return t;
|
---|
345 | }
|
---|
346 |
|
---|
347 | /*!
|
---|
348 | Returns an inverted copy of this matrix.
|
---|
349 |
|
---|
350 | If the matrix is singular (not invertible), the returned matrix is
|
---|
351 | the identity matrix. If \a invertible is valid (i.e. not 0), its
|
---|
352 | value is set to true if the matrix is invertible, otherwise it is
|
---|
353 | set to false.
|
---|
354 |
|
---|
355 | \sa isInvertible()
|
---|
356 | */
|
---|
357 | QTransform QTransform::inverted(bool *invertible) const
|
---|
358 | {
|
---|
359 | QTransform invert(true);
|
---|
360 | bool inv = true;
|
---|
361 |
|
---|
362 | switch(inline_type()) {
|
---|
363 | case TxNone:
|
---|
364 | break;
|
---|
365 | case TxTranslate:
|
---|
366 | invert.affine._dx = -affine._dx;
|
---|
367 | invert.affine._dy = -affine._dy;
|
---|
368 | break;
|
---|
369 | case TxScale:
|
---|
370 | inv = !qFuzzyIsNull(affine._m11);
|
---|
371 | inv &= !qFuzzyIsNull(affine._m22);
|
---|
372 | if (inv) {
|
---|
373 | invert.affine._m11 = 1. / affine._m11;
|
---|
374 | invert.affine._m22 = 1. / affine._m22;
|
---|
375 | invert.affine._dx = -affine._dx * invert.affine._m11;
|
---|
376 | invert.affine._dy = -affine._dy * invert.affine._m22;
|
---|
377 | }
|
---|
378 | break;
|
---|
379 | case TxRotate:
|
---|
380 | case TxShear:
|
---|
381 | invert.affine = affine.inverted(&inv);
|
---|
382 | break;
|
---|
383 | default:
|
---|
384 | // general case
|
---|
385 | qreal det = determinant();
|
---|
386 | inv = !qFuzzyIsNull(det);
|
---|
387 | if (inv)
|
---|
388 | invert = adjoint() / det;
|
---|
389 | break;
|
---|
390 | }
|
---|
391 |
|
---|
392 | if (invertible)
|
---|
393 | *invertible = inv;
|
---|
394 |
|
---|
395 | if (inv) {
|
---|
396 | // inverting doesn't change the type
|
---|
397 | invert.m_type = m_type;
|
---|
398 | invert.m_dirty = m_dirty;
|
---|
399 | }
|
---|
400 |
|
---|
401 | return invert;
|
---|
402 | }
|
---|
403 |
|
---|
404 | /*!
|
---|
405 | Moves the coordinate system \a dx along the x axis and \a dy along
|
---|
406 | the y axis, and returns a reference to the matrix.
|
---|
407 |
|
---|
408 | \sa setMatrix()
|
---|
409 | */
|
---|
410 | QTransform &QTransform::translate(qreal dx, qreal dy)
|
---|
411 | {
|
---|
412 | if (dx == 0 && dy == 0)
|
---|
413 | return *this;
|
---|
414 | #ifndef QT_NO_DEBUG
|
---|
415 | if (qIsNaN(dx) | qIsNaN(dy)) {
|
---|
416 | qWarning() << "QTransform::translate with NaN called";
|
---|
417 | return *this;
|
---|
418 | }
|
---|
419 | #endif
|
---|
420 |
|
---|
421 | switch(inline_type()) {
|
---|
422 | case TxNone:
|
---|
423 | affine._dx = dx;
|
---|
424 | affine._dy = dy;
|
---|
425 | break;
|
---|
426 | case TxTranslate:
|
---|
427 | affine._dx += dx;
|
---|
428 | affine._dy += dy;
|
---|
429 | break;
|
---|
430 | case TxScale:
|
---|
431 | affine._dx += dx*affine._m11;
|
---|
432 | affine._dy += dy*affine._m22;
|
---|
433 | break;
|
---|
434 | case TxProject:
|
---|
435 | m_33 += dx*m_13 + dy*m_23;
|
---|
436 | // Fall through
|
---|
437 | case TxShear:
|
---|
438 | case TxRotate:
|
---|
439 | affine._dx += dx*affine._m11 + dy*affine._m21;
|
---|
440 | affine._dy += dy*affine._m22 + dx*affine._m12;
|
---|
441 | break;
|
---|
442 | }
|
---|
443 | if (m_dirty < TxTranslate)
|
---|
444 | m_dirty = TxTranslate;
|
---|
445 | return *this;
|
---|
446 | }
|
---|
447 |
|
---|
448 | /*!
|
---|
449 | Creates a matrix which corresponds to a translation of \a dx along
|
---|
450 | the x axis and \a dy along the y axis. This is the same as
|
---|
451 | QTransform().translate(dx, dy) but slightly faster.
|
---|
452 |
|
---|
453 | \since 4.5
|
---|
454 | */
|
---|
455 | QTransform QTransform::fromTranslate(qreal dx, qreal dy)
|
---|
456 | {
|
---|
457 | #ifndef QT_NO_DEBUG
|
---|
458 | if (qIsNaN(dx) | qIsNaN(dy)) {
|
---|
459 | qWarning() << "QTransform::fromTranslate with NaN called";
|
---|
460 | return QTransform();
|
---|
461 | }
|
---|
462 | #endif
|
---|
463 | QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1, true);
|
---|
464 | if (dx == 0 && dy == 0)
|
---|
465 | transform.m_type = TxNone;
|
---|
466 | else
|
---|
467 | transform.m_type = TxTranslate;
|
---|
468 | transform.m_dirty = TxNone;
|
---|
469 | return transform;
|
---|
470 | }
|
---|
471 |
|
---|
472 | /*!
|
---|
473 | Scales the coordinate system by \a sx horizontally and \a sy
|
---|
474 | vertically, and returns a reference to the matrix.
|
---|
475 |
|
---|
476 | \sa setMatrix()
|
---|
477 | */
|
---|
478 | QTransform & QTransform::scale(qreal sx, qreal sy)
|
---|
479 | {
|
---|
480 | if (sx == 1 && sy == 1)
|
---|
481 | return *this;
|
---|
482 | #ifndef QT_NO_DEBUG
|
---|
483 | if (qIsNaN(sx) | qIsNaN(sy)) {
|
---|
484 | qWarning() << "QTransform::scale with NaN called";
|
---|
485 | return *this;
|
---|
486 | }
|
---|
487 | #endif
|
---|
488 |
|
---|
489 | switch(inline_type()) {
|
---|
490 | case TxNone:
|
---|
491 | case TxTranslate:
|
---|
492 | affine._m11 = sx;
|
---|
493 | affine._m22 = sy;
|
---|
494 | break;
|
---|
495 | case TxProject:
|
---|
496 | m_13 *= sx;
|
---|
497 | m_23 *= sy;
|
---|
498 | // fall through
|
---|
499 | case TxRotate:
|
---|
500 | case TxShear:
|
---|
501 | affine._m12 *= sx;
|
---|
502 | affine._m21 *= sy;
|
---|
503 | // fall through
|
---|
504 | case TxScale:
|
---|
505 | affine._m11 *= sx;
|
---|
506 | affine._m22 *= sy;
|
---|
507 | break;
|
---|
508 | }
|
---|
509 | if (m_dirty < TxScale)
|
---|
510 | m_dirty = TxScale;
|
---|
511 | return *this;
|
---|
512 | }
|
---|
513 |
|
---|
514 | /*!
|
---|
515 | Creates a matrix which corresponds to a scaling of
|
---|
516 | \a sx horizontally and \a sy vertically.
|
---|
517 | This is the same as QTransform().scale(sx, sy) but slightly faster.
|
---|
518 |
|
---|
519 | \since 4.5
|
---|
520 | */
|
---|
521 | QTransform QTransform::fromScale(qreal sx, qreal sy)
|
---|
522 | {
|
---|
523 | #ifndef QT_NO_DEBUG
|
---|
524 | if (qIsNaN(sx) | qIsNaN(sy)) {
|
---|
525 | qWarning() << "QTransform::fromScale with NaN called";
|
---|
526 | return QTransform();
|
---|
527 | }
|
---|
528 | #endif
|
---|
529 | QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1, true);
|
---|
530 | if (sx == 1. && sy == 1.)
|
---|
531 | transform.m_type = TxNone;
|
---|
532 | else
|
---|
533 | transform.m_type = TxScale;
|
---|
534 | transform.m_dirty = TxNone;
|
---|
535 | return transform;
|
---|
536 | }
|
---|
537 |
|
---|
538 | /*!
|
---|
539 | Shears the coordinate system by \a sh horizontally and \a sv
|
---|
540 | vertically, and returns a reference to the matrix.
|
---|
541 |
|
---|
542 | \sa setMatrix()
|
---|
543 | */
|
---|
544 | QTransform & QTransform::shear(qreal sh, qreal sv)
|
---|
545 | {
|
---|
546 | if (sh == 0 && sv == 0)
|
---|
547 | return *this;
|
---|
548 | #ifndef QT_NO_DEBUG
|
---|
549 | if (qIsNaN(sh) | qIsNaN(sv)) {
|
---|
550 | qWarning() << "QTransform::shear with NaN called";
|
---|
551 | return *this;
|
---|
552 | }
|
---|
553 | #endif
|
---|
554 |
|
---|
555 | switch(inline_type()) {
|
---|
556 | case TxNone:
|
---|
557 | case TxTranslate:
|
---|
558 | affine._m12 = sv;
|
---|
559 | affine._m21 = sh;
|
---|
560 | break;
|
---|
561 | case TxScale:
|
---|
562 | affine._m12 = sv*affine._m22;
|
---|
563 | affine._m21 = sh*affine._m11;
|
---|
564 | break;
|
---|
565 | case TxProject: {
|
---|
566 | qreal tm13 = sv*m_23;
|
---|
567 | qreal tm23 = sh*m_13;
|
---|
568 | m_13 += tm13;
|
---|
569 | m_23 += tm23;
|
---|
570 | }
|
---|
571 | // fall through
|
---|
572 | case TxRotate:
|
---|
573 | case TxShear: {
|
---|
574 | qreal tm11 = sv*affine._m21;
|
---|
575 | qreal tm22 = sh*affine._m12;
|
---|
576 | qreal tm12 = sv*affine._m22;
|
---|
577 | qreal tm21 = sh*affine._m11;
|
---|
578 | affine._m11 += tm11; affine._m12 += tm12;
|
---|
579 | affine._m21 += tm21; affine._m22 += tm22;
|
---|
580 | break;
|
---|
581 | }
|
---|
582 | }
|
---|
583 | if (m_dirty < TxShear)
|
---|
584 | m_dirty = TxShear;
|
---|
585 | return *this;
|
---|
586 | }
|
---|
587 |
|
---|
588 | const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
|
---|
589 | const qreal inv_dist_to_plane = 1. / 1024.;
|
---|
590 |
|
---|
591 | /*!
|
---|
592 | \fn QTransform &QTransform::rotate(qreal angle, Qt::Axis axis)
|
---|
593 |
|
---|
594 | Rotates the coordinate system counterclockwise by the given \a angle
|
---|
595 | about the specified \a axis and returns a reference to the matrix.
|
---|
596 |
|
---|
597 | Note that if you apply a QTransform to a point defined in widget
|
---|
598 | coordinates, the direction of the rotation will be clockwise
|
---|
599 | because the y-axis points downwards.
|
---|
600 |
|
---|
601 | The angle is specified in degrees.
|
---|
602 |
|
---|
603 | \sa setMatrix()
|
---|
604 | */
|
---|
605 | QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
|
---|
606 | {
|
---|
607 | if (a == 0)
|
---|
608 | return *this;
|
---|
609 | #ifndef QT_NO_DEBUG
|
---|
610 | if (qIsNaN(a)) {
|
---|
611 | qWarning() << "QTransform::rotate with NaN called";
|
---|
612 | return *this;
|
---|
613 | }
|
---|
614 | #endif
|
---|
615 |
|
---|
616 | qreal sina = 0;
|
---|
617 | qreal cosa = 0;
|
---|
618 | if (a == 90. || a == -270.)
|
---|
619 | sina = 1.;
|
---|
620 | else if (a == 270. || a == -90.)
|
---|
621 | sina = -1.;
|
---|
622 | else if (a == 180.)
|
---|
623 | cosa = -1.;
|
---|
624 | else{
|
---|
625 | qreal b = deg2rad*a; // convert to radians
|
---|
626 | sina = qSin(b); // fast and convenient
|
---|
627 | cosa = qCos(b);
|
---|
628 | }
|
---|
629 |
|
---|
630 | if (axis == Qt::ZAxis) {
|
---|
631 | switch(inline_type()) {
|
---|
632 | case TxNone:
|
---|
633 | case TxTranslate:
|
---|
634 | affine._m11 = cosa;
|
---|
635 | affine._m12 = sina;
|
---|
636 | affine._m21 = -sina;
|
---|
637 | affine._m22 = cosa;
|
---|
638 | break;
|
---|
639 | case TxScale: {
|
---|
640 | qreal tm11 = cosa*affine._m11;
|
---|
641 | qreal tm12 = sina*affine._m22;
|
---|
642 | qreal tm21 = -sina*affine._m11;
|
---|
643 | qreal tm22 = cosa*affine._m22;
|
---|
644 | affine._m11 = tm11; affine._m12 = tm12;
|
---|
645 | affine._m21 = tm21; affine._m22 = tm22;
|
---|
646 | break;
|
---|
647 | }
|
---|
648 | case TxProject: {
|
---|
649 | qreal tm13 = cosa*m_13 + sina*m_23;
|
---|
650 | qreal tm23 = -sina*m_13 + cosa*m_23;
|
---|
651 | m_13 = tm13;
|
---|
652 | m_23 = tm23;
|
---|
653 | // fall through
|
---|
654 | }
|
---|
655 | case TxRotate:
|
---|
656 | case TxShear: {
|
---|
657 | qreal tm11 = cosa*affine._m11 + sina*affine._m21;
|
---|
658 | qreal tm12 = cosa*affine._m12 + sina*affine._m22;
|
---|
659 | qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
|
---|
660 | qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
|
---|
661 | affine._m11 = tm11; affine._m12 = tm12;
|
---|
662 | affine._m21 = tm21; affine._m22 = tm22;
|
---|
663 | break;
|
---|
664 | }
|
---|
665 | }
|
---|
666 | if (m_dirty < TxRotate)
|
---|
667 | m_dirty = TxRotate;
|
---|
668 | } else {
|
---|
669 | QTransform result;
|
---|
670 | if (axis == Qt::YAxis) {
|
---|
671 | result.affine._m11 = cosa;
|
---|
672 | result.m_13 = -sina * inv_dist_to_plane;
|
---|
673 | } else {
|
---|
674 | result.affine._m22 = cosa;
|
---|
675 | result.m_23 = -sina * inv_dist_to_plane;
|
---|
676 | }
|
---|
677 | result.m_type = TxProject;
|
---|
678 | *this = result * *this;
|
---|
679 | }
|
---|
680 |
|
---|
681 | return *this;
|
---|
682 | }
|
---|
683 |
|
---|
684 | /*!
|
---|
685 | \fn QTransform & QTransform::rotateRadians(qreal angle, Qt::Axis axis)
|
---|
686 |
|
---|
687 | Rotates the coordinate system counterclockwise by the given \a angle
|
---|
688 | about the specified \a axis and returns a reference to the matrix.
|
---|
689 |
|
---|
690 | Note that if you apply a QTransform to a point defined in widget
|
---|
691 | coordinates, the direction of the rotation will be clockwise
|
---|
692 | because the y-axis points downwards.
|
---|
693 |
|
---|
694 | The angle is specified in radians.
|
---|
695 |
|
---|
696 | \sa setMatrix()
|
---|
697 | */
|
---|
698 | QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
|
---|
699 | {
|
---|
700 | #ifndef QT_NO_DEBUG
|
---|
701 | if (qIsNaN(a)) {
|
---|
702 | qWarning() << "QTransform::rotateRadians with NaN called";
|
---|
703 | return *this;
|
---|
704 | }
|
---|
705 | #endif
|
---|
706 | qreal sina = qSin(a);
|
---|
707 | qreal cosa = qCos(a);
|
---|
708 |
|
---|
709 | if (axis == Qt::ZAxis) {
|
---|
710 | switch(inline_type()) {
|
---|
711 | case TxNone:
|
---|
712 | case TxTranslate:
|
---|
713 | affine._m11 = cosa;
|
---|
714 | affine._m12 = sina;
|
---|
715 | affine._m21 = -sina;
|
---|
716 | affine._m22 = cosa;
|
---|
717 | break;
|
---|
718 | case TxScale: {
|
---|
719 | qreal tm11 = cosa*affine._m11;
|
---|
720 | qreal tm12 = sina*affine._m22;
|
---|
721 | qreal tm21 = -sina*affine._m11;
|
---|
722 | qreal tm22 = cosa*affine._m22;
|
---|
723 | affine._m11 = tm11; affine._m12 = tm12;
|
---|
724 | affine._m21 = tm21; affine._m22 = tm22;
|
---|
725 | break;
|
---|
726 | }
|
---|
727 | case TxProject: {
|
---|
728 | qreal tm13 = cosa*m_13 + sina*m_23;
|
---|
729 | qreal tm23 = -sina*m_13 + cosa*m_23;
|
---|
730 | m_13 = tm13;
|
---|
731 | m_23 = tm23;
|
---|
732 | // fall through
|
---|
733 | }
|
---|
734 | case TxRotate:
|
---|
735 | case TxShear: {
|
---|
736 | qreal tm11 = cosa*affine._m11 + sina*affine._m21;
|
---|
737 | qreal tm12 = cosa*affine._m12 + sina*affine._m22;
|
---|
738 | qreal tm21 = -sina*affine._m11 + cosa*affine._m21;
|
---|
739 | qreal tm22 = -sina*affine._m12 + cosa*affine._m22;
|
---|
740 | affine._m11 = tm11; affine._m12 = tm12;
|
---|
741 | affine._m21 = tm21; affine._m22 = tm22;
|
---|
742 | break;
|
---|
743 | }
|
---|
744 | }
|
---|
745 | if (m_dirty < TxRotate)
|
---|
746 | m_dirty = TxRotate;
|
---|
747 | } else {
|
---|
748 | QTransform result;
|
---|
749 | if (axis == Qt::YAxis) {
|
---|
750 | result.affine._m11 = cosa;
|
---|
751 | result.m_13 = -sina * inv_dist_to_plane;
|
---|
752 | } else {
|
---|
753 | result.affine._m22 = cosa;
|
---|
754 | result.m_23 = -sina * inv_dist_to_plane;
|
---|
755 | }
|
---|
756 | result.m_type = TxProject;
|
---|
757 | *this = result * *this;
|
---|
758 | }
|
---|
759 | return *this;
|
---|
760 | }
|
---|
761 |
|
---|
762 | /*!
|
---|
763 | \fn bool QTransform::operator==(const QTransform &matrix) const
|
---|
764 | Returns true if this matrix is equal to the given \a matrix,
|
---|
765 | otherwise returns false.
|
---|
766 | */
|
---|
767 | bool QTransform::operator==(const QTransform &o) const
|
---|
768 | {
|
---|
769 | return affine._m11 == o.affine._m11 &&
|
---|
770 | affine._m12 == o.affine._m12 &&
|
---|
771 | affine._m21 == o.affine._m21 &&
|
---|
772 | affine._m22 == o.affine._m22 &&
|
---|
773 | affine._dx == o.affine._dx &&
|
---|
774 | affine._dy == o.affine._dy &&
|
---|
775 | m_13 == o.m_13 &&
|
---|
776 | m_23 == o.m_23 &&
|
---|
777 | m_33 == o.m_33;
|
---|
778 | }
|
---|
779 |
|
---|
780 | /*!
|
---|
781 | \fn bool QTransform::operator!=(const QTransform &matrix) const
|
---|
782 | Returns true if this matrix is not equal to the given \a matrix,
|
---|
783 | otherwise returns false.
|
---|
784 | */
|
---|
785 | bool QTransform::operator!=(const QTransform &o) const
|
---|
786 | {
|
---|
787 | return !operator==(o);
|
---|
788 | }
|
---|
789 |
|
---|
790 | /*!
|
---|
791 | \fn QTransform & QTransform::operator*=(const QTransform &matrix)
|
---|
792 | \overload
|
---|
793 |
|
---|
794 | Returns the result of multiplying this matrix by the given \a
|
---|
795 | matrix.
|
---|
796 | */
|
---|
797 | QTransform & QTransform::operator*=(const QTransform &o)
|
---|
798 | {
|
---|
799 | const TransformationType otherType = o.inline_type();
|
---|
800 | if (otherType == TxNone)
|
---|
801 | return *this;
|
---|
802 |
|
---|
803 | const TransformationType thisType = inline_type();
|
---|
804 | if (thisType == TxNone)
|
---|
805 | return operator=(o);
|
---|
806 |
|
---|
807 | TransformationType t = qMax(thisType, otherType);
|
---|
808 | switch(t) {
|
---|
809 | case TxNone:
|
---|
810 | break;
|
---|
811 | case TxTranslate:
|
---|
812 | affine._dx += o.affine._dx;
|
---|
813 | affine._dy += o.affine._dy;
|
---|
814 | break;
|
---|
815 | case TxScale:
|
---|
816 | {
|
---|
817 | qreal m11 = affine._m11*o.affine._m11;
|
---|
818 | qreal m22 = affine._m22*o.affine._m22;
|
---|
819 |
|
---|
820 | qreal m31 = affine._dx*o.affine._m11 + o.affine._dx;
|
---|
821 | qreal m32 = affine._dy*o.affine._m22 + o.affine._dy;
|
---|
822 |
|
---|
823 | affine._m11 = m11;
|
---|
824 | affine._m22 = m22;
|
---|
825 | affine._dx = m31; affine._dy = m32;
|
---|
826 | break;
|
---|
827 | }
|
---|
828 | case TxRotate:
|
---|
829 | case TxShear:
|
---|
830 | {
|
---|
831 | qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21;
|
---|
832 | qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22;
|
---|
833 |
|
---|
834 | qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21;
|
---|
835 | qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22;
|
---|
836 |
|
---|
837 | qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + o.affine._dx;
|
---|
838 | qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + o.affine._dy;
|
---|
839 |
|
---|
840 | affine._m11 = m11; affine._m12 = m12;
|
---|
841 | affine._m21 = m21; affine._m22 = m22;
|
---|
842 | affine._dx = m31; affine._dy = m32;
|
---|
843 | break;
|
---|
844 | }
|
---|
845 | case TxProject:
|
---|
846 | {
|
---|
847 | qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21 + m_13*o.affine._dx;
|
---|
848 | qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22 + m_13*o.affine._dy;
|
---|
849 | qreal m13 = affine._m11*o.m_13 + affine._m12*o.m_23 + m_13*o.m_33;
|
---|
850 |
|
---|
851 | qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21 + m_23*o.affine._dx;
|
---|
852 | qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22 + m_23*o.affine._dy;
|
---|
853 | qreal m23 = affine._m21*o.m_13 + affine._m22*o.m_23 + m_23*o.m_33;
|
---|
854 |
|
---|
855 | qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + m_33*o.affine._dx;
|
---|
856 | qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + m_33*o.affine._dy;
|
---|
857 | qreal m33 = affine._dx*o.m_13 + affine._dy*o.m_23 + m_33*o.m_33;
|
---|
858 |
|
---|
859 | affine._m11 = m11; affine._m12 = m12; m_13 = m13;
|
---|
860 | affine._m21 = m21; affine._m22 = m22; m_23 = m23;
|
---|
861 | affine._dx = m31; affine._dy = m32; m_33 = m33;
|
---|
862 | }
|
---|
863 | }
|
---|
864 |
|
---|
865 | m_dirty = t;
|
---|
866 | m_type = t;
|
---|
867 |
|
---|
868 | return *this;
|
---|
869 | }
|
---|
870 |
|
---|
871 | /*!
|
---|
872 | \fn QTransform QTransform::operator*(const QTransform &matrix) const
|
---|
873 | Returns the result of multiplying this matrix by the given \a
|
---|
874 | matrix.
|
---|
875 |
|
---|
876 | Note that matrix multiplication is not commutative, i.e. a*b !=
|
---|
877 | b*a.
|
---|
878 | */
|
---|
879 | QTransform QTransform::operator*(const QTransform &m) const
|
---|
880 | {
|
---|
881 | const TransformationType otherType = m.inline_type();
|
---|
882 | if (otherType == TxNone)
|
---|
883 | return *this;
|
---|
884 |
|
---|
885 | const TransformationType thisType = inline_type();
|
---|
886 | if (thisType == TxNone)
|
---|
887 | return m;
|
---|
888 |
|
---|
889 | QTransform t(true);
|
---|
890 | TransformationType type = qMax(thisType, otherType);
|
---|
891 | switch(type) {
|
---|
892 | case TxNone:
|
---|
893 | break;
|
---|
894 | case TxTranslate:
|
---|
895 | t.affine._dx = affine._dx + m.affine._dx;
|
---|
896 | t.affine._dy += affine._dy + m.affine._dy;
|
---|
897 | break;
|
---|
898 | case TxScale:
|
---|
899 | {
|
---|
900 | qreal m11 = affine._m11*m.affine._m11;
|
---|
901 | qreal m22 = affine._m22*m.affine._m22;
|
---|
902 |
|
---|
903 | qreal m31 = affine._dx*m.affine._m11 + m.affine._dx;
|
---|
904 | qreal m32 = affine._dy*m.affine._m22 + m.affine._dy;
|
---|
905 |
|
---|
906 | t.affine._m11 = m11;
|
---|
907 | t.affine._m22 = m22;
|
---|
908 | t.affine._dx = m31; t.affine._dy = m32;
|
---|
909 | break;
|
---|
910 | }
|
---|
911 | case TxRotate:
|
---|
912 | case TxShear:
|
---|
913 | {
|
---|
914 | qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21;
|
---|
915 | qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22;
|
---|
916 |
|
---|
917 | qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21;
|
---|
918 | qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22;
|
---|
919 |
|
---|
920 | qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m.affine._dx;
|
---|
921 | qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m.affine._dy;
|
---|
922 |
|
---|
923 | t.affine._m11 = m11; t.affine._m12 = m12;
|
---|
924 | t.affine._m21 = m21; t.affine._m22 = m22;
|
---|
925 | t.affine._dx = m31; t.affine._dy = m32;
|
---|
926 | break;
|
---|
927 | }
|
---|
928 | case TxProject:
|
---|
929 | {
|
---|
930 | qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21 + m_13*m.affine._dx;
|
---|
931 | qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22 + m_13*m.affine._dy;
|
---|
932 | qreal m13 = affine._m11*m.m_13 + affine._m12*m.m_23 + m_13*m.m_33;
|
---|
933 |
|
---|
934 | qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21 + m_23*m.affine._dx;
|
---|
935 | qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22 + m_23*m.affine._dy;
|
---|
936 | qreal m23 = affine._m21*m.m_13 + affine._m22*m.m_23 + m_23*m.m_33;
|
---|
937 |
|
---|
938 | qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m_33*m.affine._dx;
|
---|
939 | qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m_33*m.affine._dy;
|
---|
940 | qreal m33 = affine._dx*m.m_13 + affine._dy*m.m_23 + m_33*m.m_33;
|
---|
941 |
|
---|
942 | t.affine._m11 = m11; t.affine._m12 = m12; t.m_13 = m13;
|
---|
943 | t.affine._m21 = m21; t.affine._m22 = m22; t.m_23 = m23;
|
---|
944 | t.affine._dx = m31; t.affine._dy = m32; t.m_33 = m33;
|
---|
945 | }
|
---|
946 | }
|
---|
947 |
|
---|
948 | t.m_dirty = type;
|
---|
949 | t.m_type = type;
|
---|
950 |
|
---|
951 | return t;
|
---|
952 | }
|
---|
953 |
|
---|
954 | /*!
|
---|
955 | \fn QTransform & QTransform::operator*=(qreal scalar)
|
---|
956 | \overload
|
---|
957 |
|
---|
958 | Returns the result of performing an element-wise multiplication of this
|
---|
959 | matrix with the given \a scalar.
|
---|
960 | */
|
---|
961 |
|
---|
962 | /*!
|
---|
963 | \fn QTransform & QTransform::operator/=(qreal scalar)
|
---|
964 | \overload
|
---|
965 |
|
---|
966 | Returns the result of performing an element-wise division of this
|
---|
967 | matrix by the given \a scalar.
|
---|
968 | */
|
---|
969 |
|
---|
970 | /*!
|
---|
971 | \fn QTransform & QTransform::operator+=(qreal scalar)
|
---|
972 | \overload
|
---|
973 |
|
---|
974 | Returns the matrix obtained by adding the given \a scalar to each
|
---|
975 | element of this matrix.
|
---|
976 | */
|
---|
977 |
|
---|
978 | /*!
|
---|
979 | \fn QTransform & QTransform::operator-=(qreal scalar)
|
---|
980 | \overload
|
---|
981 |
|
---|
982 | Returns the matrix obtained by subtracting the given \a scalar from each
|
---|
983 | element of this matrix.
|
---|
984 | */
|
---|
985 |
|
---|
986 | /*!
|
---|
987 | Assigns the given \a matrix's values to this matrix.
|
---|
988 | */
|
---|
989 | QTransform & QTransform::operator=(const QTransform &matrix)
|
---|
990 | {
|
---|
991 | affine._m11 = matrix.affine._m11;
|
---|
992 | affine._m12 = matrix.affine._m12;
|
---|
993 | affine._m21 = matrix.affine._m21;
|
---|
994 | affine._m22 = matrix.affine._m22;
|
---|
995 | affine._dx = matrix.affine._dx;
|
---|
996 | affine._dy = matrix.affine._dy;
|
---|
997 | m_13 = matrix.m_13;
|
---|
998 | m_23 = matrix.m_23;
|
---|
999 | m_33 = matrix.m_33;
|
---|
1000 | m_type = matrix.m_type;
|
---|
1001 | m_dirty = matrix.m_dirty;
|
---|
1002 |
|
---|
1003 | return *this;
|
---|
1004 | }
|
---|
1005 |
|
---|
1006 | /*!
|
---|
1007 | Resets the matrix to an identity matrix, i.e. all elements are set
|
---|
1008 | to zero, except \c m11 and \c m22 (specifying the scale) and \c m33
|
---|
1009 | which are set to 1.
|
---|
1010 |
|
---|
1011 | \sa QTransform(), isIdentity(), {QTransform#Basic Matrix
|
---|
1012 | Operations}{Basic Matrix Operations}
|
---|
1013 | */
|
---|
1014 | void QTransform::reset()
|
---|
1015 | {
|
---|
1016 | affine._m11 = affine._m22 = m_33 = 1.0;
|
---|
1017 | affine._m12 = m_13 = affine._m21 = m_23 = affine._dx = affine._dy = 0;
|
---|
1018 | m_type = TxNone;
|
---|
1019 | m_dirty = TxNone;
|
---|
1020 | }
|
---|
1021 |
|
---|
1022 | #ifndef QT_NO_DATASTREAM
|
---|
1023 | /*!
|
---|
1024 | \fn QDataStream &operator<<(QDataStream &stream, const QTransform &matrix)
|
---|
1025 | \since 4.3
|
---|
1026 | \relates QTransform
|
---|
1027 |
|
---|
1028 | Writes the given \a matrix to the given \a stream and returns a
|
---|
1029 | reference to the stream.
|
---|
1030 |
|
---|
1031 | \sa {Serializing Qt Data Types}
|
---|
1032 | */
|
---|
1033 | QDataStream & operator<<(QDataStream &s, const QTransform &m)
|
---|
1034 | {
|
---|
1035 | s << double(m.m11())
|
---|
1036 | << double(m.m12())
|
---|
1037 | << double(m.m13())
|
---|
1038 | << double(m.m21())
|
---|
1039 | << double(m.m22())
|
---|
1040 | << double(m.m23())
|
---|
1041 | << double(m.m31())
|
---|
1042 | << double(m.m32())
|
---|
1043 | << double(m.m33());
|
---|
1044 | return s;
|
---|
1045 | }
|
---|
1046 |
|
---|
1047 | /*!
|
---|
1048 | \fn QDataStream &operator>>(QDataStream &stream, QTransform &matrix)
|
---|
1049 | \since 4.3
|
---|
1050 | \relates QTransform
|
---|
1051 |
|
---|
1052 | Reads the given \a matrix from the given \a stream and returns a
|
---|
1053 | reference to the stream.
|
---|
1054 |
|
---|
1055 | \sa {Serializing Qt Data Types}
|
---|
1056 | */
|
---|
1057 | QDataStream & operator>>(QDataStream &s, QTransform &t)
|
---|
1058 | {
|
---|
1059 | double m11, m12, m13,
|
---|
1060 | m21, m22, m23,
|
---|
1061 | m31, m32, m33;
|
---|
1062 |
|
---|
1063 | s >> m11;
|
---|
1064 | s >> m12;
|
---|
1065 | s >> m13;
|
---|
1066 | s >> m21;
|
---|
1067 | s >> m22;
|
---|
1068 | s >> m23;
|
---|
1069 | s >> m31;
|
---|
1070 | s >> m32;
|
---|
1071 | s >> m33;
|
---|
1072 | t.setMatrix(m11, m12, m13,
|
---|
1073 | m21, m22, m23,
|
---|
1074 | m31, m32, m33);
|
---|
1075 | return s;
|
---|
1076 | }
|
---|
1077 |
|
---|
1078 | #endif // QT_NO_DATASTREAM
|
---|
1079 |
|
---|
1080 | #ifndef QT_NO_DEBUG_STREAM
|
---|
1081 | QDebug 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 | */
|
---|
1117 | QPoint 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 | */
|
---|
1168 | QPointF 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 | */
|
---|
1237 | QLine 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 |
|
---|
1296 | QLineF 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 |
|
---|
1344 | static 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 | */
|
---|
1391 | QPolygonF 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 | */
|
---|
1421 | QPolygon 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 ®ion, 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 |
|
---|
1454 | extern QPainterPath qt_regionToPath(const QRegion ®ion);
|
---|
1455 |
|
---|
1456 | /*!
|
---|
1457 | \fn QRegion QTransform::map(const QRegion ®ion) 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 | */
|
---|
1466 | QRegion 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 |
|
---|
1485 | struct 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 |
|
---|
1500 | static 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 |
|
---|
1509 | static 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 | }
|
---|
1548 | Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
|
---|
1549 |
|
---|
1550 | static 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 |
|
---|
1569 | static 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 | */
|
---|
1626 | QPainterPath 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 | */
|
---|
1671 | QPolygon 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 | */
|
---|
1721 | bool 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 | */
|
---|
1786 | bool 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 | */
|
---|
1809 | bool 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 |
|
---|
1834 | void 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 |
|
---|
1845 | static 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 |
|
---|
1853 | QRect 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 | */
|
---|
1923 | QRectF 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 | */
|
---|
1997 | void 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 | */
|
---|
2011 | void 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 | */
|
---|
2026 | const 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 | */
|
---|
2043 | QTransform::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 | */
|
---|
2087 | QTransform::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
|
---|
2273 | Q_GUI_EXPORT
|
---|
2274 | bool 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 |
|
---|
2298 | QT_END_NAMESPACE
|
---|