diff options
Diffstat (limited to 'src/gui/painting/qtransform.cpp')
-rw-r--r-- | src/gui/painting/qtransform.cpp | 944 |
1 files changed, 396 insertions, 548 deletions
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp index d75b66c50b..df57d2c190 100644 --- a/src/gui/painting/qtransform.cpp +++ b/src/gui/painting/qtransform.cpp @@ -1,52 +1,15 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtGui module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qtransform.h" #include "qdatastream.h" #include "qdebug.h" #include "qhashfunctions.h" -#include "qmatrix.h" #include "qregion.h" #include "qpainterpath.h" #include "qpainterpath_p.h" #include "qvariant.h" -#include <qmath.h> +#include "qmath_p.h" #include <qnumeric.h> #include <private/qbezier_p.h> @@ -76,22 +39,22 @@ static void nanWarning(const char *func) ny = FY_; \ break; \ case TxTranslate: \ - nx = FX_ + affine._dx; \ - ny = FY_ + affine._dy; \ + nx = FX_ + m_matrix[2][0]; \ + ny = FY_ + m_matrix[2][1]; \ break; \ case TxScale: \ - nx = affine._m11 * FX_ + affine._dx; \ - ny = affine._m22 * FY_ + affine._dy; \ + nx = m_matrix[0][0] * FX_ + m_matrix[2][0]; \ + ny = m_matrix[1][1] * FY_ + m_matrix[2][1]; \ break; \ case TxRotate: \ case TxShear: \ case TxProject: \ - nx = affine._m11 * FX_ + affine._m21 * FY_ + affine._dx; \ - ny = affine._m12 * FX_ + affine._m22 * FY_ + affine._dy; \ + nx = m_matrix[0][0] * FX_ + m_matrix[1][0] * FY_ + m_matrix[2][0]; \ + ny = m_matrix[0][1] * FX_ + m_matrix[1][1] * FY_ + m_matrix[2][1]; \ if (t == TxProject) { \ - qreal w = (m_13 * FX_ + m_23 * FY_ + m_33); \ + qreal w = (m_matrix[0][2] * FX_ + m_matrix[1][2] * FY_ + m_matrix[2][2]); \ if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \ - w = 1./w; \ + w = qreal(1.)/w; \ nx *= w; \ ny *= w; \ } \ @@ -109,14 +72,6 @@ static void nanWarning(const char *func) or project the coordinate system, and is typically used when rendering graphics. - QTransform differs from QMatrix in that it is a true 3x3 matrix, - allowing perspective transformations. QTransform's toAffine() - method allows casting QTransform to QMatrix. If a perspective - transformation has been specified on the matrix, then the - conversion will cause loss of data. - - QTransform is the recommended transformation class in Qt. - A QTransform object can be built using the setMatrix(), scale(), rotate(), translate() and shear() functions. Alternatively, it can be built by applying \l {QTransform#Basic Matrix @@ -222,6 +177,7 @@ static void nanWarning(const char *func) transformation is achieved by setting both the projection factors and the scaling factors. + \section2 Combining Transforms Here's the combined transformations example using basic matrix operations: @@ -232,6 +188,26 @@ static void nanWarning(const char *func) \snippet transform/main.cpp 2 \endtable + The combined transform first scales each operand, then rotates it, and + finally translates it, just as in the order in which the product of its + factors is written. This means the point to which the transforms are + applied is implicitly multiplied on the left with the transform + to its right. + + \section2 Relation to Matrix Notation + The matrix notation in QTransform is the transpose of a commonly-taught + convention which represents transforms and points as matrices and vectors. + That convention multiplies its matrix on the left and column vector to the + right. In other words, when several transforms are applied to a point, the + right-most matrix acts directly on the vector first. Then the next matrix + to the left acts on the result of the first operation - and so on. As a + result, that convention multiplies the matrices that make up a composite + transform in the reverse of the order in QTransform, as you can see in + \l {Combining Transforms}. Transposing the matrices, and combining them to + the right of a row vector that represents the point, lets the matrices of + transforms appear, in their product, in the order in which we think of the + transforms being applied to the point. + \sa QPainter, {Coordinate System}, {painting/affine}{Affine Transformations Example}, {Transformations Example} */ @@ -253,6 +229,8 @@ static void nanWarning(const char *func) */ /*! + \fn QTransform::QTransform() + Constructs an identity matrix. All elements are set to zero except \c m11 and \c m22 (specifying @@ -260,16 +238,6 @@ static void nanWarning(const char *func) \sa reset() */ -QTransform::QTransform() - : affine(true) - , m_13(0), m_23(0), m_33(1) - , m_type(TxNone) - , m_dirty(TxNone) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - , d(nullptr) -#endif -{ -} /*! \fn QTransform::QTransform(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33) @@ -279,18 +247,6 @@ QTransform::QTransform() \sa setMatrix() */ -QTransform::QTransform(qreal h11, qreal h12, qreal h13, - qreal h21, qreal h22, qreal h23, - qreal h31, qreal h32, qreal h33) - : affine(h11, h12, h21, h22, h31, h32, true) - , m_13(h13), m_23(h23), m_33(h33) - , m_type(TxNone) - , m_dirty(TxProject) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - , d(nullptr) -#endif -{ -} /*! \fn QTransform::QTransform(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) @@ -299,35 +255,6 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h13, \sa setMatrix() */ -QTransform::QTransform(qreal h11, qreal h12, qreal h21, - qreal h22, qreal dx, qreal dy) - : affine(h11, h12, h21, h22, dx, dy, true) - , m_13(0), m_23(0), m_33(1) - , m_type(TxNone) - , m_dirty(TxShear) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - , d(nullptr) -#endif -{ -} - -/*! - \fn QTransform::QTransform(const QMatrix &matrix) - - Constructs a matrix that is a copy of the given \a matrix. - Note that the \c m13, \c m23, and \c m33 elements are set to 0, 0, - and 1 respectively. - */ -QTransform::QTransform(const QMatrix &mtx) - : affine(mtx._m11, mtx._m12, mtx._m21, mtx._m22, mtx._dx, mtx._dy, true), - m_13(0), m_23(0), m_33(1) - , m_type(TxNone) - , m_dirty(TxShear) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - , d(nullptr) -#endif -{ -} /*! Returns the adjoint of this matrix. @@ -335,21 +262,21 @@ QTransform::QTransform(const QMatrix &mtx) QTransform QTransform::adjoint() const { qreal h11, h12, h13, - h21, h22, h23, - h31, h32, h33; - h11 = affine._m22*m_33 - m_23*affine._dy; - h21 = m_23*affine._dx - affine._m21*m_33; - h31 = affine._m21*affine._dy - affine._m22*affine._dx; - h12 = m_13*affine._dy - affine._m12*m_33; - h22 = affine._m11*m_33 - m_13*affine._dx; - h32 = affine._m12*affine._dx - affine._m11*affine._dy; - h13 = affine._m12*m_23 - m_13*affine._m22; - h23 = m_13*affine._m21 - affine._m11*m_23; - h33 = affine._m11*affine._m22 - affine._m12*affine._m21; + h21, h22, h23, + h31, h32, h33; + h11 = m_matrix[1][1] * m_matrix[2][2] - m_matrix[1][2] * m_matrix[2][1]; + h21 = m_matrix[1][2] * m_matrix[2][0] - m_matrix[1][0] * m_matrix[2][2]; + h31 = m_matrix[1][0] * m_matrix[2][1] - m_matrix[1][1] * m_matrix[2][0]; + h12 = m_matrix[0][2] * m_matrix[2][1] - m_matrix[0][1] * m_matrix[2][2]; + h22 = m_matrix[0][0] * m_matrix[2][2] - m_matrix[0][2] * m_matrix[2][0]; + h32 = m_matrix[0][1] * m_matrix[2][0] - m_matrix[0][0] * m_matrix[2][1]; + h13 = m_matrix[0][1] * m_matrix[1][2] - m_matrix[0][2] * m_matrix[1][1]; + h23 = m_matrix[0][2] * m_matrix[1][0] - m_matrix[0][0] * m_matrix[1][2]; + h33 = m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0]; return QTransform(h11, h12, h13, h21, h22, h23, - h31, h32, h33, true); + h31, h32, h33); } /*! @@ -357,9 +284,9 @@ QTransform QTransform::adjoint() const */ QTransform QTransform::transposed() const { - QTransform t(affine._m11, affine._m21, affine._dx, - affine._m12, affine._m22, affine._dy, - m_13, m_23, m_33, true); + QTransform t(m_matrix[0][0], m_matrix[1][0], m_matrix[2][0], + m_matrix[0][1], m_matrix[1][1], m_matrix[2][1], + m_matrix[0][2], m_matrix[1][2], m_matrix[2][2]); return t; } @@ -375,30 +302,30 @@ QTransform QTransform::transposed() const */ QTransform QTransform::inverted(bool *invertible) const { - QTransform invert(true); + QTransform invert; bool inv = true; switch(inline_type()) { case TxNone: break; case TxTranslate: - invert.affine._dx = -affine._dx; - invert.affine._dy = -affine._dy; + invert.m_matrix[2][0] = -m_matrix[2][0]; + invert.m_matrix[2][1] = -m_matrix[2][1]; break; case TxScale: - inv = !qFuzzyIsNull(affine._m11); - inv &= !qFuzzyIsNull(affine._m22); + inv = !qFuzzyIsNull(m_matrix[0][0]); + inv &= !qFuzzyIsNull(m_matrix[1][1]); if (inv) { - invert.affine._m11 = 1. / affine._m11; - invert.affine._m22 = 1. / affine._m22; - invert.affine._dx = -affine._dx * invert.affine._m11; - invert.affine._dy = -affine._dy * invert.affine._m22; + invert.m_matrix[0][0] = 1. / m_matrix[0][0]; + invert.m_matrix[1][1] = 1. / m_matrix[1][1]; + invert.m_matrix[2][0] = -m_matrix[2][0] * invert.m_matrix[0][0]; + invert.m_matrix[2][1] = -m_matrix[2][1] * invert.m_matrix[1][1]; } break; - case TxRotate: - case TxShear: - invert.affine = affine.inverted(&inv); - break; +// case TxRotate: +// case TxShear: +// invert.affine = affine.inverted(&inv); +// break; default: // general case qreal det = determinant(); @@ -431,7 +358,7 @@ QTransform &QTransform::translate(qreal dx, qreal dy) if (dx == 0 && dy == 0) return *this; #ifndef QT_NO_DEBUG - if (qIsNaN(dx) | qIsNaN(dy)) { + if (qIsNaN(dx) || qIsNaN(dy)) { nanWarning("translate"); return *this; } @@ -439,24 +366,24 @@ QTransform &QTransform::translate(qreal dx, qreal dy) switch(inline_type()) { case TxNone: - affine._dx = dx; - affine._dy = dy; + m_matrix[2][0] = dx; + m_matrix[2][1] = dy; break; case TxTranslate: - affine._dx += dx; - affine._dy += dy; + m_matrix[2][0] += dx; + m_matrix[2][1] += dy; break; case TxScale: - affine._dx += dx*affine._m11; - affine._dy += dy*affine._m22; + m_matrix[2][0] += dx * m_matrix[0][0]; + m_matrix[2][1] += dy * m_matrix[1][1]; break; case TxProject: - m_33 += dx*m_13 + dy*m_23; + m_matrix[2][2] += dx * m_matrix[0][2] + dy * m_matrix[1][2]; Q_FALLTHROUGH(); case TxShear: case TxRotate: - affine._dx += dx*affine._m11 + dy*affine._m21; - affine._dy += dy*affine._m22 + dx*affine._m12; + m_matrix[2][0] += dx * m_matrix[0][0] + dy * m_matrix[1][0]; + m_matrix[2][1] += dy * m_matrix[1][1] + dx * m_matrix[0][1]; break; } if (m_dirty < TxTranslate) @@ -474,12 +401,12 @@ QTransform &QTransform::translate(qreal dx, qreal dy) QTransform QTransform::fromTranslate(qreal dx, qreal dy) { #ifndef QT_NO_DEBUG - if (qIsNaN(dx) | qIsNaN(dy)) { + if (qIsNaN(dx) || qIsNaN(dy)) { nanWarning("fromTranslate"); return QTransform(); } #endif - QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1, true); + QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1); if (dx == 0 && dy == 0) transform.m_type = TxNone; else @@ -499,7 +426,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy) if (sx == 1 && sy == 1) return *this; #ifndef QT_NO_DEBUG - if (qIsNaN(sx) | qIsNaN(sy)) { + if (qIsNaN(sx) || qIsNaN(sy)) { nanWarning("scale"); return *this; } @@ -508,21 +435,21 @@ QTransform & QTransform::scale(qreal sx, qreal sy) switch(inline_type()) { case TxNone: case TxTranslate: - affine._m11 = sx; - affine._m22 = sy; + m_matrix[0][0] = sx; + m_matrix[1][1] = sy; break; case TxProject: - m_13 *= sx; - m_23 *= sy; + m_matrix[0][2] *= sx; + m_matrix[1][2] *= sy; Q_FALLTHROUGH(); case TxRotate: case TxShear: - affine._m12 *= sx; - affine._m21 *= sy; + m_matrix[0][1] *= sx; + m_matrix[1][0] *= sy; Q_FALLTHROUGH(); case TxScale: - affine._m11 *= sx; - affine._m22 *= sy; + m_matrix[0][0] *= sx; + m_matrix[1][1] *= sy; break; } if (m_dirty < TxScale) @@ -540,12 +467,12 @@ QTransform & QTransform::scale(qreal sx, qreal sy) QTransform QTransform::fromScale(qreal sx, qreal sy) { #ifndef QT_NO_DEBUG - if (qIsNaN(sx) | qIsNaN(sy)) { + if (qIsNaN(sx) || qIsNaN(sy)) { nanWarning("fromScale"); return QTransform(); } #endif - QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1, true); + QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1); if (sx == 1. && sy == 1.) transform.m_type = TxNone; else @@ -565,7 +492,7 @@ QTransform & QTransform::shear(qreal sh, qreal sv) if (sh == 0 && sv == 0) return *this; #ifndef QT_NO_DEBUG - if (qIsNaN(sh) | qIsNaN(sv)) { + if (qIsNaN(sh) || qIsNaN(sv)) { nanWarning("shear"); return *this; } @@ -574,28 +501,30 @@ QTransform & QTransform::shear(qreal sh, qreal sv) switch(inline_type()) { case TxNone: case TxTranslate: - affine._m12 = sv; - affine._m21 = sh; + m_matrix[0][1] = sv; + m_matrix[1][0] = sh; break; case TxScale: - affine._m12 = sv*affine._m22; - affine._m21 = sh*affine._m11; + m_matrix[0][1] = sv*m_matrix[1][1]; + m_matrix[1][0] = sh*m_matrix[0][0]; break; case TxProject: { - qreal tm13 = sv*m_23; - qreal tm23 = sh*m_13; - m_13 += tm13; - m_23 += tm23; + qreal tm13 = sv * m_matrix[1][2]; + qreal tm23 = sh * m_matrix[0][2]; + m_matrix[0][2] += tm13; + m_matrix[1][2] += tm23; } Q_FALLTHROUGH(); case TxRotate: case TxShear: { - qreal tm11 = sv*affine._m21; - qreal tm22 = sh*affine._m12; - qreal tm12 = sv*affine._m22; - qreal tm21 = sh*affine._m11; - affine._m11 += tm11; affine._m12 += tm12; - affine._m21 += tm21; affine._m22 += tm22; + qreal tm11 = sv * m_matrix[1][0]; + qreal tm22 = sh * m_matrix[0][1]; + qreal tm12 = sv * m_matrix[1][1]; + qreal tm21 = sh * m_matrix[0][0]; + m_matrix[0][0] += tm11; + m_matrix[0][1] += tm12; + m_matrix[1][0] += tm21; + m_matrix[1][1] += tm22; break; } } @@ -604,29 +533,33 @@ QTransform & QTransform::shear(qreal sh, qreal sv) return *this; } -const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 -const qreal inv_dist_to_plane = 1. / 1024.; - /*! - \fn QTransform &QTransform::rotate(qreal angle, Qt::Axis axis) + \since 6.5 - Rotates the coordinate system counterclockwise by the given \a angle - about the specified \a axis and returns a reference to the matrix. + Rotates the coordinate system counterclockwise by the given angle \a a + about the specified \a axis at distance \a distanceToPlane from the + screen and returns a reference to the matrix. +//! [transform-rotate-note] Note that if you apply a QTransform to a point defined in widget coordinates, the direction of the rotation will be clockwise because the y-axis points downwards. The angle is specified in degrees. +//! [transform-rotate-note] + + If \a distanceToPlane is zero, it will be ignored. This is suitable + for implementing orthographic projections where the z coordinate should + be dropped rather than projected. \sa setMatrix() */ -QTransform & QTransform::rotate(qreal a, Qt::Axis axis) +QTransform & QTransform::rotate(qreal a, Qt::Axis axis, qreal distanceToPlane) { if (a == 0) return *this; #ifndef QT_NO_DEBUG - if (qIsNaN(a)) { + if (qIsNaN(a) || qIsNaN(distanceToPlane)) { nanWarning("rotate"); return *this; } @@ -641,7 +574,7 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis) else if (a == 180.) cosa = -1.; else{ - qreal b = deg2rad*a; // convert to radians + qreal b = qDegreesToRadians(a); sina = qSin(b); // fast and convenient cosa = qCos(b); } @@ -650,48 +583,55 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis) switch(inline_type()) { case TxNone: case TxTranslate: - affine._m11 = cosa; - affine._m12 = sina; - affine._m21 = -sina; - affine._m22 = cosa; + m_matrix[0][0] = cosa; + m_matrix[0][1] = sina; + m_matrix[1][0] = -sina; + m_matrix[1][1] = cosa; break; case TxScale: { - qreal tm11 = cosa*affine._m11; - qreal tm12 = sina*affine._m22; - qreal tm21 = -sina*affine._m11; - qreal tm22 = cosa*affine._m22; - affine._m11 = tm11; affine._m12 = tm12; - affine._m21 = tm21; affine._m22 = tm22; + qreal tm11 = cosa * m_matrix[0][0]; + qreal tm12 = sina * m_matrix[1][1]; + qreal tm21 = -sina * m_matrix[0][0]; + qreal tm22 = cosa * m_matrix[1][1]; + m_matrix[0][0] = tm11; + m_matrix[0][1] = tm12; + m_matrix[1][0] = tm21; + m_matrix[1][1] = tm22; break; } case TxProject: { - qreal tm13 = cosa*m_13 + sina*m_23; - qreal tm23 = -sina*m_13 + cosa*m_23; - m_13 = tm13; - m_23 = tm23; + qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2]; + qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2]; + m_matrix[0][2] = tm13; + m_matrix[1][2] = tm23; Q_FALLTHROUGH(); } case TxRotate: case TxShear: { - qreal tm11 = cosa*affine._m11 + sina*affine._m21; - qreal tm12 = cosa*affine._m12 + sina*affine._m22; - qreal tm21 = -sina*affine._m11 + cosa*affine._m21; - qreal tm22 = -sina*affine._m12 + cosa*affine._m22; - affine._m11 = tm11; affine._m12 = tm12; - affine._m21 = tm21; affine._m22 = tm22; + qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0]; + qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1]; + qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0]; + qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1]; + m_matrix[0][0] = tm11; + m_matrix[0][1] = tm12; + m_matrix[1][0] = tm21; + m_matrix[1][1] = tm22; break; } } if (m_dirty < TxRotate) m_dirty = TxRotate; } else { + if (!qIsNull(distanceToPlane)) + sina /= distanceToPlane; + QTransform result; if (axis == Qt::YAxis) { - result.affine._m11 = cosa; - result.m_13 = -sina * inv_dist_to_plane; + result.m_matrix[0][0] = cosa; + result.m_matrix[0][2] = -sina; } else { - result.affine._m22 = cosa; - result.m_23 = -sina * inv_dist_to_plane; + result.m_matrix[1][1] = cosa; + result.m_matrix[1][2] = -sina; } result.m_type = TxProject; *this = result * *this; @@ -700,24 +640,49 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis) return *this; } +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) /*! - \fn QTransform & QTransform::rotateRadians(qreal angle, Qt::Axis axis) + \overload + + Rotates the coordinate system counterclockwise by the given angle \a a + about the specified \a axis at distance 1024.0 from the screen and + returns a reference to the matrix. - Rotates the coordinate system counterclockwise by the given \a angle - about the specified \a axis and returns a reference to the matrix. + \include qtransform.cpp transform-rotate-note + \sa setMatrix +*/ +QTransform &QTransform::rotate(qreal a, Qt::Axis axis) +{ + return rotate(a, axis, 1024.0); +} +#endif + +/*! + \since 6.5 + + Rotates the coordinate system counterclockwise by the given angle \a a + about the specified \a axis at distance \a distanceToPlane from the + screen and returns a reference to the matrix. + +//! [transform-rotate-radians-note] Note that if you apply a QTransform to a point defined in widget coordinates, the direction of the rotation will be clockwise because the y-axis points downwards. The angle is specified in radians. +//! [transform-rotate-radians-note] + + If \a distanceToPlane is zero, it will be ignored. This is suitable + for implementing orthographic projections where the z coordinate should + be dropped rather than projected. \sa setMatrix() */ -QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) +QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis, qreal distanceToPlane) { #ifndef QT_NO_DEBUG - if (qIsNaN(a)) { + if (qIsNaN(a) || qIsNaN(distanceToPlane)) { nanWarning("rotateRadians"); return *this; } @@ -729,48 +694,55 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) switch(inline_type()) { case TxNone: case TxTranslate: - affine._m11 = cosa; - affine._m12 = sina; - affine._m21 = -sina; - affine._m22 = cosa; + m_matrix[0][0] = cosa; + m_matrix[0][1] = sina; + m_matrix[1][0] = -sina; + m_matrix[1][1] = cosa; break; case TxScale: { - qreal tm11 = cosa*affine._m11; - qreal tm12 = sina*affine._m22; - qreal tm21 = -sina*affine._m11; - qreal tm22 = cosa*affine._m22; - affine._m11 = tm11; affine._m12 = tm12; - affine._m21 = tm21; affine._m22 = tm22; + qreal tm11 = cosa * m_matrix[0][0]; + qreal tm12 = sina * m_matrix[1][1]; + qreal tm21 = -sina * m_matrix[0][0]; + qreal tm22 = cosa * m_matrix[1][1]; + m_matrix[0][0] = tm11; + m_matrix[0][1] = tm12; + m_matrix[1][0] = tm21; + m_matrix[1][1] = tm22; break; } case TxProject: { - qreal tm13 = cosa*m_13 + sina*m_23; - qreal tm23 = -sina*m_13 + cosa*m_23; - m_13 = tm13; - m_23 = tm23; + qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2]; + qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2]; + m_matrix[0][2] = tm13; + m_matrix[1][2] = tm23; Q_FALLTHROUGH(); } case TxRotate: case TxShear: { - qreal tm11 = cosa*affine._m11 + sina*affine._m21; - qreal tm12 = cosa*affine._m12 + sina*affine._m22; - qreal tm21 = -sina*affine._m11 + cosa*affine._m21; - qreal tm22 = -sina*affine._m12 + cosa*affine._m22; - affine._m11 = tm11; affine._m12 = tm12; - affine._m21 = tm21; affine._m22 = tm22; + qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0]; + qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1]; + qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0]; + qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1]; + m_matrix[0][0] = tm11; + m_matrix[0][1] = tm12; + m_matrix[1][0] = tm21; + m_matrix[1][1] = tm22; break; } } if (m_dirty < TxRotate) m_dirty = TxRotate; } else { + if (!qIsNull(distanceToPlane)) + sina /= distanceToPlane; + QTransform result; if (axis == Qt::YAxis) { - result.affine._m11 = cosa; - result.m_13 = -sina * inv_dist_to_plane; + result.m_matrix[0][0] = cosa; + result.m_matrix[0][2] = -sina; } else { - result.affine._m22 = cosa; - result.m_23 = -sina * inv_dist_to_plane; + result.m_matrix[1][1] = cosa; + result.m_matrix[1][2] = -sina; } result.m_type = TxProject; *this = result * *this; @@ -778,6 +750,24 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) return *this; } +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +/*! + \overload + + Rotates the coordinate system counterclockwise by the given angle \a a + about the specified \a axis at distance 1024.0 from the screen and + returns a reference to the matrix. + + \include qtransform.cpp transform-rotate-radians-note + + \sa setMatrix() +*/ +QTransform &QTransform::rotateRadians(qreal a, Qt::Axis axis) +{ + return rotateRadians(a, axis, 1024.0); +} +#endif + /*! \fn bool QTransform::operator==(const QTransform &matrix) const Returns \c true if this matrix is equal to the given \a matrix, @@ -785,15 +775,15 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis) */ bool QTransform::operator==(const QTransform &o) const { - return affine._m11 == o.affine._m11 && - affine._m12 == o.affine._m12 && - affine._m21 == o.affine._m21 && - affine._m22 == o.affine._m22 && - affine._dx == o.affine._dx && - affine._dy == o.affine._dy && - m_13 == o.m_13 && - m_23 == o.m_23 && - m_33 == o.m_33; + return m_matrix[0][0] == o.m_matrix[0][0] && + m_matrix[0][1] == o.m_matrix[0][1] && + m_matrix[1][0] == o.m_matrix[1][0] && + m_matrix[1][1] == o.m_matrix[1][1] && + m_matrix[2][0] == o.m_matrix[2][0] && + m_matrix[2][1] == o.m_matrix[2][1] && + m_matrix[0][2] == o.m_matrix[0][2] && + m_matrix[1][2] == o.m_matrix[1][2] && + m_matrix[2][2] == o.m_matrix[2][2]; } /*! @@ -803,7 +793,7 @@ bool QTransform::operator==(const QTransform &o) const Returns the hash value for \a key, using \a seed to seed the calculation. */ -uint qHash(const QTransform &key, uint seed) noexcept +size_t qHash(const QTransform &key, size_t seed) noexcept { QtPrivate::QHashCombine hash; seed = hash(seed, key.m11()); @@ -851,56 +841,59 @@ QTransform & QTransform::operator*=(const QTransform &o) case TxNone: break; case TxTranslate: - affine._dx += o.affine._dx; - affine._dy += o.affine._dy; + m_matrix[2][0] += o.m_matrix[2][0]; + m_matrix[2][1] += o.m_matrix[2][1]; break; case TxScale: { - qreal m11 = affine._m11*o.affine._m11; - qreal m22 = affine._m22*o.affine._m22; + qreal m11 = m_matrix[0][0] * o.m_matrix[0][0]; + qreal m22 = m_matrix[1][1] * o.m_matrix[1][1]; - qreal m31 = affine._dx*o.affine._m11 + o.affine._dx; - qreal m32 = affine._dy*o.affine._m22 + o.affine._dy; + qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + o.m_matrix[2][0]; + qreal m32 = m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1]; - affine._m11 = m11; - affine._m22 = m22; - affine._dx = m31; affine._dy = m32; + m_matrix[0][0] = m11; + m_matrix[1][1] = m22; + m_matrix[2][0] = m31; m_matrix[2][1] = m32; break; } case TxRotate: case TxShear: { - qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21; - qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22; + qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0]; + qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1]; - qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21; - qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22; + qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0]; + qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1]; - qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + o.affine._dx; - qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + o.affine._dy; + 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]; + 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]; - affine._m11 = m11; affine._m12 = m12; - affine._m21 = m21; affine._m22 = m22; - affine._dx = m31; affine._dy = m32; + m_matrix[0][0] = m11; + m_matrix[0][1] = m12; + m_matrix[1][0] = m21; + m_matrix[1][1] = m22; + m_matrix[2][0] = m31; + m_matrix[2][1] = m32; break; } case TxProject: { - qreal m11 = affine._m11*o.affine._m11 + affine._m12*o.affine._m21 + m_13*o.affine._dx; - qreal m12 = affine._m11*o.affine._m12 + affine._m12*o.affine._m22 + m_13*o.affine._dy; - qreal m13 = affine._m11*o.m_13 + affine._m12*o.m_23 + m_13*o.m_33; + 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]; + 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]; + 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]; - qreal m21 = affine._m21*o.affine._m11 + affine._m22*o.affine._m21 + m_23*o.affine._dx; - qreal m22 = affine._m21*o.affine._m12 + affine._m22*o.affine._m22 + m_23*o.affine._dy; - qreal m23 = affine._m21*o.m_13 + affine._m22*o.m_23 + m_23*o.m_33; + 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]; + 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]; + 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]; - qreal m31 = affine._dx*o.affine._m11 + affine._dy*o.affine._m21 + m_33*o.affine._dx; - qreal m32 = affine._dx*o.affine._m12 + affine._dy*o.affine._m22 + m_33*o.affine._dy; - qreal m33 = affine._dx*o.m_13 + affine._dy*o.m_23 + m_33*o.m_33; + 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]; + 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]; + 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]; - affine._m11 = m11; affine._m12 = m12; m_13 = m13; - affine._m21 = m21; affine._m22 = m22; m_23 = m23; - affine._dx = m31; affine._dy = m32; m_33 = m33; + m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; + m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; + m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; } } @@ -928,62 +921,63 @@ QTransform QTransform::operator*(const QTransform &m) const if (thisType == TxNone) return m; - QTransform t(true); + QTransform t; TransformationType type = qMax(thisType, otherType); switch(type) { case TxNone: break; case TxTranslate: - t.affine._dx = affine._dx + m.affine._dx; - t.affine._dy += affine._dy + m.affine._dy; + t.m_matrix[2][0] = m_matrix[2][0] + m.m_matrix[2][0]; + t.m_matrix[2][1] = m_matrix[2][1] + m.m_matrix[2][1]; break; case TxScale: { - qreal m11 = affine._m11*m.affine._m11; - qreal m22 = affine._m22*m.affine._m22; + qreal m11 = m_matrix[0][0] * m.m_matrix[0][0]; + qreal m22 = m_matrix[1][1] * m.m_matrix[1][1]; - qreal m31 = affine._dx*m.affine._m11 + m.affine._dx; - qreal m32 = affine._dy*m.affine._m22 + m.affine._dy; + qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m.m_matrix[2][0]; + qreal m32 = m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1]; - t.affine._m11 = m11; - t.affine._m22 = m22; - t.affine._dx = m31; t.affine._dy = m32; + t.m_matrix[0][0] = m11; + t.m_matrix[1][1] = m22; + t.m_matrix[2][0] = m31; + t.m_matrix[2][1] = m32; break; } case TxRotate: case TxShear: { - qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21; - qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22; + qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0]; + qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1]; - qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21; - qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22; + qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0]; + qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1]; - qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m.affine._dx; - qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m.affine._dy; + 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]; + 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]; - t.affine._m11 = m11; t.affine._m12 = m12; - t.affine._m21 = m21; t.affine._m22 = m22; - t.affine._dx = m31; t.affine._dy = m32; + t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12; + t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22; + t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32; break; } case TxProject: { - qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21 + m_13*m.affine._dx; - qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22 + m_13*m.affine._dy; - qreal m13 = affine._m11*m.m_13 + affine._m12*m.m_23 + m_13*m.m_33; + 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]; + 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]; + 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]; - qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21 + m_23*m.affine._dx; - qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22 + m_23*m.affine._dy; - qreal m23 = affine._m21*m.m_13 + affine._m22*m.m_23 + m_23*m.m_33; + 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]; + 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]; + 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]; - qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m_33*m.affine._dx; - qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m_33*m.affine._dy; - qreal m33 = affine._dx*m.m_13 + affine._dy*m.m_23 + m_33*m.m_33; + 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]; + 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]; + 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]; - t.affine._m11 = m11; t.affine._m12 = m12; t.m_13 = m13; - t.affine._m21 = m21; t.affine._m22 = m22; t.m_23 = m23; - t.affine._dx = m31; t.affine._dy = m32; t.m_33 = m33; + t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12; t.m_matrix[0][2] = m13; + t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22; t.m_matrix[1][2] = m23; + t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32; t.m_matrix[2][2] = m33; } } @@ -1025,27 +1019,11 @@ QTransform QTransform::operator*(const QTransform &m) const element of this matrix. */ -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) /*! + \fn QTransform &QTransform::operator=(const QTransform &matrix) noexcept + Assigns the given \a matrix's values to this matrix. */ -QTransform & QTransform::operator=(const QTransform &matrix) noexcept -{ - affine._m11 = matrix.affine._m11; - affine._m12 = matrix.affine._m12; - affine._m21 = matrix.affine._m21; - affine._m22 = matrix.affine._m22; - affine._dx = matrix.affine._dx; - affine._dy = matrix.affine._dy; - m_13 = matrix.m_13; - m_23 = matrix.m_23; - m_33 = matrix.m_33; - m_type = matrix.m_type; - m_dirty = matrix.m_dirty; - - return *this; -} -#endif /*! Resets the matrix to an identity matrix, i.e. all elements are set @@ -1057,10 +1035,7 @@ QTransform & QTransform::operator=(const QTransform &matrix) noexcept */ void QTransform::reset() { - affine._m11 = affine._m22 = m_33 = 1.0; - affine._m12 = m_13 = affine._m21 = m_23 = affine._dx = affine._dy = 0; - m_type = TxNone; - m_dirty = TxNone; + *this = QTransform(); } #ifndef QT_NO_DATASTREAM @@ -1170,30 +1145,8 @@ QPoint QTransform::map(const QPoint &p) const qreal x = 0, y = 0; TransformationType t = inline_type(); - switch(t) { - case TxNone: - x = fx; - y = fy; - break; - case TxTranslate: - x = fx + affine._dx; - y = fy + affine._dy; - break; - case TxScale: - x = affine._m11 * fx + affine._dx; - y = affine._m22 * fy + affine._dy; - break; - case TxRotate: - case TxShear: - case TxProject: - x = affine._m11 * fx + affine._m21 * fy + affine._dx; - y = affine._m12 * fx + affine._m22 * fy + affine._dy; - if (t == TxProject) { - qreal w = 1./(m_13 * fx + m_23 * fy + m_33); - x *= w; - y *= w; - } - } + MAP(fx, fy, x, y); + return QPoint(qRound(x), qRound(y)); } @@ -1221,30 +1174,8 @@ QPointF QTransform::map(const QPointF &p) const qreal x = 0, y = 0; TransformationType t = inline_type(); - switch(t) { - case TxNone: - x = fx; - y = fy; - break; - case TxTranslate: - x = fx + affine._dx; - y = fy + affine._dy; - break; - case TxScale: - x = affine._m11 * fx + affine._dx; - y = affine._m22 * fy + affine._dy; - break; - case TxRotate: - case TxShear: - case TxProject: - x = affine._m11 * fx + affine._m21 * fy + affine._dx; - y = affine._m12 * fx + affine._m22 * fy + affine._dy; - if (t == TxProject) { - qreal w = 1./(m_13 * fx + m_23 * fy + m_33); - x *= w; - y *= w; - } - } + MAP(fx, fy, x, y); + return QPointF(x, y); } @@ -1292,41 +1223,9 @@ QLine QTransform::map(const QLine &l) const qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0; TransformationType t = inline_type(); - switch(t) { - case TxNone: - x1 = fx1; - y1 = fy1; - x2 = fx2; - y2 = fy2; - break; - case TxTranslate: - x1 = fx1 + affine._dx; - y1 = fy1 + affine._dy; - x2 = fx2 + affine._dx; - y2 = fy2 + affine._dy; - break; - case TxScale: - x1 = affine._m11 * fx1 + affine._dx; - y1 = affine._m22 * fy1 + affine._dy; - x2 = affine._m11 * fx2 + affine._dx; - y2 = affine._m22 * fy2 + affine._dy; - break; - case TxRotate: - case TxShear: - case TxProject: - x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx; - y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy; - x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx; - y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy; - if (t == TxProject) { - qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33); - x1 *= w; - y1 *= w; - w = 1./(m_13 * fx2 + m_23 * fy2 + m_33); - x2 *= w; - y2 *= w; - } - } + MAP(fx1, fy1, x1, y1); + MAP(fx2, fy2, x2, y2); + return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2)); } @@ -1351,66 +1250,12 @@ QLineF QTransform::map(const QLineF &l) const qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0; TransformationType t = inline_type(); - switch(t) { - case TxNone: - x1 = fx1; - y1 = fy1; - x2 = fx2; - y2 = fy2; - break; - case TxTranslate: - x1 = fx1 + affine._dx; - y1 = fy1 + affine._dy; - x2 = fx2 + affine._dx; - y2 = fy2 + affine._dy; - break; - case TxScale: - x1 = affine._m11 * fx1 + affine._dx; - y1 = affine._m22 * fy1 + affine._dy; - x2 = affine._m11 * fx2 + affine._dx; - y2 = affine._m22 * fy2 + affine._dy; - break; - case TxRotate: - case TxShear: - case TxProject: - x1 = affine._m11 * fx1 + affine._m21 * fy1 + affine._dx; - y1 = affine._m12 * fx1 + affine._m22 * fy1 + affine._dy; - x2 = affine._m11 * fx2 + affine._m21 * fy2 + affine._dx; - y2 = affine._m12 * fx2 + affine._m22 * fy2 + affine._dy; - if (t == TxProject) { - qreal w = 1./(m_13 * fx1 + m_23 * fy1 + m_33); - x1 *= w; - y1 *= w; - w = 1./(m_13 * fx2 + m_23 * fy2 + m_33); - x2 *= w; - y2 *= w; - } - } - return QLineF(x1, y1, x2, y2); -} - -static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &poly) -{ - if (poly.size() == 0) - return poly; - - if (poly.size() == 1) - return QPolygonF() << transform.map(poly.at(0)); - - QPainterPath path; - path.addPolygon(poly); + MAP(fx1, fy1, x1, y1); + MAP(fx2, fy2, x2, y2); - path = transform.map(path); - - QPolygonF result; - const int elementCount = path.elementCount(); - result.reserve(elementCount); - for (int i = 0; i < elementCount; ++i) - result << path.elementAt(i); - return result; + return QLineF(x1, y1, x2, y2); } - /*! \fn QPolygonF operator *(const QPolygonF &polygon, const QTransform &matrix) \since 4.3 @@ -1442,10 +1287,7 @@ QPolygonF QTransform::map(const QPolygonF &a) const { TransformationType t = inline_type(); if (t <= TxTranslate) - return a.translated(affine._dx, affine._dy); - - if (t >= QTransform::TxProject) - return mapProjective(*this, a); + return a.translated(m_matrix[2][0], m_matrix[2][1]); int size = a.size(); int i; @@ -1472,10 +1314,7 @@ QPolygon QTransform::map(const QPolygon &a) const { TransformationType t = inline_type(); if (t <= TxTranslate) - return a.translated(qRound(affine._dx), qRound(affine._dy)); - - if (t >= QTransform::TxProject) - return mapProjective(*this, QPolygonF(a)).toPolygon(); + return a.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1])); int size = a.size(); int i; @@ -1521,7 +1360,7 @@ QRegion QTransform::map(const QRegion &r) const if (t == TxTranslate) { QRegion copy(r); - copy.translate(qRound(affine._dx), qRound(affine._dy)); + copy.translate(qRound(m_matrix[2][0]), qRound(m_matrix[2][1])); return copy; } @@ -1529,22 +1368,22 @@ QRegion QTransform::map(const QRegion &r) const QRegion res; if (m11() < 0 || m22() < 0) { for (const QRect &rect : r) - res += mapRect(QRectF(rect)).toRect(); + res += qt_mapFillRect(QRectF(rect), *this); } else { QVarLengthArray<QRect, 32> rects; rects.reserve(r.rectCount()); for (const QRect &rect : r) { - QRect nr = mapRect(QRectF(rect)).toRect(); + QRect nr = qt_mapFillRect(QRectF(rect), *this); if (!nr.isEmpty()) rects.append(nr); } - res.setRects(rects.constData(), rects.count()); + res.setRects(rects.constData(), rects.size()); } return res; } QPainterPath p = map(qt_regionToPath(r)); - return p.toFillPolygon(QTransform()).toPolygon(); + return p.toFillPolygon().toPolygon(); } struct QHomogeneousCoordinate @@ -1700,7 +1539,7 @@ QPainterPath QTransform::map(const QPainterPath &path) const QPainterPath copy = path; if (t == TxTranslate) { - copy.translate(affine._dx, affine._dy); + copy.translate(m_matrix[2][0], m_matrix[2][1]); } else { copy.detach(); // Full xform @@ -1740,10 +1579,10 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const QPolygon a(4); qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 }; if (t <= TxScale) { - x[0] = affine._m11*rect.x() + affine._dx; - y[0] = affine._m22*rect.y() + affine._dy; - qreal w = affine._m11*rect.width(); - qreal h = affine._m22*rect.height(); + x[0] = m_matrix[0][0]*rect.x() + m_matrix[2][0]; + y[0] = m_matrix[1][1]*rect.y() + m_matrix[2][1]; + qreal w = m_matrix[0][0]*rect.width(); + qreal h = m_matrix[1][1]*rect.height(); if (w < 0) { w = -w; x[0] -= w; @@ -1767,7 +1606,7 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const MAP(rect.x(), bottom, x[3], y[3]); } - // all coordinates are correctly, tranform to a pointarray + // all coordinates are correctly, transform to a pointarray // (rounding to the next integer) a.setPoints(4, qRound(x[0]), qRound(y[0]), qRound(x[1]), qRound(y[1]), @@ -1785,7 +1624,7 @@ QPolygon QTransform::mapToPolygon(const QRect &rect) const */ bool QTransform::squareToQuad(const QPolygonF &quad, QTransform &trans) { - if (quad.count() != 4) + if (quad.size() != 4) return false; qreal dx0 = quad[0].x(); @@ -1900,32 +1739,24 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33) { - affine._m11 = m11; affine._m12 = m12; m_13 = m13; - affine._m21 = m21; affine._m22 = m22; m_23 = m23; - affine._dx = m31; affine._dy = m32; m_33 = m33; + m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13; + m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23; + m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33; m_type = TxNone; m_dirty = TxProject; } -static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform) -{ - const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right()); - const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom()); - - return wx + wy + transform.m33() < Q_NEAR_CLIP; -} - QRect QTransform::mapRect(const QRect &rect) const { TransformationType t = inline_type(); if (t <= TxTranslate) - return rect.translated(qRound(affine._dx), qRound(affine._dy)); + return rect.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1])); if (t <= TxScale) { - int x = qRound(affine._m11*rect.x() + affine._dx); - int y = qRound(affine._m22*rect.y() + affine._dy); - int w = qRound(affine._m11*rect.width()); - int h = qRound(affine._m22*rect.height()); + int x = qRound(m_matrix[0][0] * rect.x() + m_matrix[2][0]); + int y = qRound(m_matrix[1][1] * rect.y() + m_matrix[2][1]); + int w = qRound(m_matrix[0][0] * rect.width()); + int h = qRound(m_matrix[1][1] * rect.height()); if (w < 0) { w = -w; x -= w; @@ -1935,8 +1766,7 @@ QRect QTransform::mapRect(const QRect &rect) const y -= h; } return QRect(x, y, w, h); - } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) { - // see mapToPolygon for explanations of the algorithm. + } else { qreal x = 0, y = 0; MAP(rect.left(), rect.top(), x, y); qreal xmin = x; @@ -1958,11 +1788,7 @@ QRect QTransform::mapRect(const QRect &rect) const ymin = qMin(ymin, y); xmax = qMax(xmax, x); ymax = qMax(ymax, y); - return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin)); - } else { - QPainterPath path; - path.addRect(rect); - return map(path).boundingRect().toRect(); + return QRectF(xmin, ymin, xmax-xmin, ymax-ymin).toRect(); } } @@ -1989,13 +1815,13 @@ QRectF QTransform::mapRect(const QRectF &rect) const { TransformationType t = inline_type(); if (t <= TxTranslate) - return rect.translated(affine._dx, affine._dy); + return rect.translated(m_matrix[2][0], m_matrix[2][1]); if (t <= TxScale) { - qreal x = affine._m11*rect.x() + affine._dx; - qreal y = affine._m22*rect.y() + affine._dy; - qreal w = affine._m11*rect.width(); - qreal h = affine._m22*rect.height(); + qreal x = m_matrix[0][0] * rect.x() + m_matrix[2][0]; + qreal y = m_matrix[1][1] * rect.y() + m_matrix[2][1]; + qreal w = m_matrix[0][0] * rect.width(); + qreal h = m_matrix[1][1] * rect.height(); if (w < 0) { w = -w; x -= w; @@ -2005,7 +1831,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const y -= h; } return QRectF(x, y, w, h); - } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) { + } else { qreal x = 0, y = 0; MAP(rect.x(), rect.y(), x, y); qreal xmin = x; @@ -2028,10 +1854,6 @@ QRectF QTransform::mapRect(const QRectF &rect) const xmax = qMax(xmax, x); ymax = qMax(ymax, y); return QRectF(xmin, ymin, xmax-xmin, ymax - ymin); - } else { - QPainterPath path; - path.addRect(rect); - return map(path).boundingRect(); } } @@ -2083,17 +1905,6 @@ void QTransform::map(int x, int y, int *tx, int *ty) const } /*! - Returns the QTransform as an affine matrix. - - \warning If a perspective transformation has been specified, - then the conversion will cause loss of data. -*/ -const QMatrix &QTransform::toAffine() const -{ - return affine; -} - -/*! Returns the transformation type of this matrix. The transformation type is the highest enumeration value @@ -2107,20 +1918,20 @@ const QMatrix &QTransform::toAffine() const */ QTransform::TransformationType QTransform::type() const { - if(m_dirty == TxNone || m_dirty < m_type) + if (m_dirty == TxNone || m_dirty < m_type) return static_cast<TransformationType>(m_type); switch (static_cast<TransformationType>(m_dirty)) { case TxProject: - if (!qFuzzyIsNull(m_13) || !qFuzzyIsNull(m_23) || !qFuzzyIsNull(m_33 - 1)) { + if (!qFuzzyIsNull(m_matrix[0][2]) || !qFuzzyIsNull(m_matrix[1][2]) || !qFuzzyIsNull(m_matrix[2][2] - 1)) { m_type = TxProject; break; } Q_FALLTHROUGH(); case TxShear: case TxRotate: - if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) { - const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22; + if (!qFuzzyIsNull(m_matrix[0][1]) || !qFuzzyIsNull(m_matrix[1][0])) { + const qreal dot = m_matrix[0][0] * m_matrix[1][0] + m_matrix[0][1] * m_matrix[1][1]; if (qFuzzyIsNull(dot)) m_type = TxRotate; else @@ -2129,13 +1940,13 @@ QTransform::TransformationType QTransform::type() const } Q_FALLTHROUGH(); case TxScale: - if (!qFuzzyIsNull(affine._m11 - 1) || !qFuzzyIsNull(affine._m22 - 1)) { + if (!qFuzzyIsNull(m_matrix[0][0] - 1) || !qFuzzyIsNull(m_matrix[1][1] - 1)) { m_type = TxScale; break; } Q_FALLTHROUGH(); case TxTranslate: - if (!qFuzzyIsNull(affine._dx) || !qFuzzyIsNull(affine._dy)) { + if (!qFuzzyIsNull(m_matrix[2][0]) || !qFuzzyIsNull(m_matrix[2][1])) { m_type = TxTranslate; break; } @@ -2155,7 +1966,7 @@ QTransform::TransformationType QTransform::type() const */ QTransform::operator QVariant() const { - return QVariant(QVariant::Transform, this); + return QVariant::fromValue(*this); } @@ -2167,15 +1978,6 @@ QTransform::operator QVariant() const \sa inverted() */ -#if QT_DEPRECATED_SINCE(5, 13) -/*! - \fn qreal QTransform::det() const - \obsolete - - Returns the matrix's determinant. Use determinant() instead. -*/ -#endif - /*! \fn qreal QTransform::m11() const @@ -2384,4 +2186,50 @@ bool qt_scaleForTransform(const QTransform &transform, qreal *scale) } } +QDataStream & operator>>(QDataStream &s, QTransform::Affine &m) +{ + if (s.version() == 1) { + float m11, m12, m21, m22, dx, dy; + s >> m11; s >> m12; s >> m21; s >> m22; s >> dx; s >> dy; + + m.m_matrix[0][0] = m11; + m.m_matrix[0][1] = m12; + m.m_matrix[1][0] = m21; + m.m_matrix[1][1] = m22; + m.m_matrix[2][0] = dx; + m.m_matrix[2][1] = dy; + } else { + s >> m.m_matrix[0][0]; + s >> m.m_matrix[0][1]; + s >> m.m_matrix[1][0]; + s >> m.m_matrix[1][1]; + s >> m.m_matrix[2][0]; + s >> m.m_matrix[2][1]; + } + m.m_matrix[0][2] = 0; + m.m_matrix[1][2] = 0; + m.m_matrix[2][2] = 1; + return s; +} + +QDataStream &operator<<(QDataStream &s, const QTransform::Affine &m) +{ + if (s.version() == 1) { + s << (float)m.m_matrix[0][0] + << (float)m.m_matrix[0][1] + << (float)m.m_matrix[1][0] + << (float)m.m_matrix[1][1] + << (float)m.m_matrix[2][0] + << (float)m.m_matrix[2][1]; + } else { + s << m.m_matrix[0][0] + << m.m_matrix[0][1] + << m.m_matrix[1][0] + << m.m_matrix[1][1] + << m.m_matrix[2][0] + << m.m_matrix[2][1]; + } + return s; +} + QT_END_NAMESPACE |