Qt-QTransform-内存结构-仿射变换-工作原理-C++

文章目录

    • 1.概述
    • 2.内存结构
    • 3.矩阵乘法
    • 4.map函数
    • 5.QPaint-setWorldTransform
    • 6.总结

1.概述

QTransform是Qt中推荐的矩阵变换类。转换指定如何平移,缩放,剪切,旋转或投影坐标系,通常在渲染图形时使用。QTransform类支持矩阵乘法,加法和减法,并且可以流式传输和比较该类的对象。使用改对象时,需要清楚Qt视图使用的坐标系。逻辑视图和物理视图,都为x值向右增加; y值向下增加。QTransform类在此环境中使用。

Qt-QTransform-内存结构-仿射变换-工作原理-C++_第1张图片
QTransform实现的矩阵乘法,点向量在前,乘以矩阵,依次实现变换效果。
Qt-QTransform-内存结构-仿射变换-工作原理-C++_第2张图片

2.内存结构

QTransform内部是一个二维的矩阵数据,如下图所示,由如下参数构成。
Qt-QTransform-内存结构-仿射变换-工作原理-C++_第3张图片

初始化方法
a.直接使用参数构造。

QTransform(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy)
QTransform(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33 = 1.0)

b.QTransform()

m11、m22、m33设置为1,其他元素设置为零。

c.[static] QTransform fromScale(qreal sx, qreal sy)

创建一个QTransform,矩阵对应于水平sx和垂直sy的缩放比例。 这与scale(sx,sy)相同,但速度稍快。

d.[static] QTransform fromTranslate(qreal dx, qreal dy)

创建一个QTransform,阵对应于dx沿x轴和平移dy沿y轴平移。 这与translate(dx,dy)相同,但速度稍快。

3.矩阵乘法

矩阵乘法是连续仿射变换的基础。矩阵乘法一行乘以一列为对应矩阵元素的值,QTransform内部实现的乘法运算如下:

/*!
    \fn QTransform QTransform::operator*(const QTransform &matrix) const
    Returns the result of multiplying this matrix by the given \a
    matrix.

    Note that matrix multiplication is not commutative, i.e. a*b !=
    b*a.
*/
QTransform QTransform::operator*(const QTransform &m) const
{
    const TransformationType otherType = m.inline_type();
    if (otherType == TxNone)
        return *this;

    const TransformationType thisType = inline_type();
    if (thisType == TxNone)
        return m;

    QTransform t(true);
    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;
        break;
    case TxScale:
    {
        qreal m11 = affine._m11*m.affine._m11;
        qreal m22 = affine._m22*m.affine._m22;

        qreal m31 = affine._dx*m.affine._m11 + m.affine._dx;
        qreal m32 = affine._dy*m.affine._m22 + m.affine._dy;

        t.affine._m11 = m11;
        t.affine._m22 = m22;
        t.affine._dx = m31; t.affine._dy = 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 m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21;
        qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22;

        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;

        t.affine._m11 = m11; t.affine._m12 = m12;
        t.affine._m21 = m21; t.affine._m22 = m22;
        t.affine._dx = m31; t.affine._dy = 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 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 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;

        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_dirty = type;
    t.m_type = type;

    return t;
}

4.map函数

按矩阵变换修改几何位置数据。以变换点位置为基础。点的变换以左乘为基础。

QPoint QTransform::map(const QPoint &p) const
{
    qreal fx = p.x();
    qreal fy = p.y();

    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;
        }
    }
    return QPoint(qRound(x), qRound(y));
}

5.QPaint-setWorldTransform

修改绘图对象变换矩阵

void QPainter::setWorldTransform(const QTransform &matrix, bool combine )
{
    Q_D(QPainter);

    if (!d->engine) {
        qWarning("QPainter::setWorldTransform: Painter not active");
        return;
    }

    if (combine)
        d->state->worldMatrix = matrix * d->state->worldMatrix;        // combines
    else
        d->state->worldMatrix = matrix;                                // set new matrix

    d->state->WxF = true;
    d->updateMatrix();
}

6.总结

使用QTransform进行仿射变换时,一定要注意坐标空间,X向右为正,Y向下为正。否则容易出现各种莫名其妙的问题。一切线性变换皆为仿射变换,如果变换关系复杂,可以利用3个对应点来构建此仿射变换矩阵

你可能感兴趣的:(C++,Qt,qt,c++,开发语言,QTransform,内存结构-仿射变换-工作原理)