Coverage Report

Created: 2026-02-26 07:48

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