Coverage Report

Created: 2025-07-16 07:53

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