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

文章目录

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

1.概述

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

在这里插入图片描述
QTransform实现的矩阵乘法,点向量在前,乘以矩阵,依次实现变换效果。
在这里插入图片描述

2.内存结构

QTransform内部是一个二维的矩阵数据,如下图所示,由如下参数构成。
在这里插入图片描述

初始化方法
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) constReturns the result of multiplying this matrix by the given \amatrix.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;        // combineselsed->state->worldMatrix = matrix;                                // set new matrixd->state->WxF = true;d->updateMatrix();
}

6.总结

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/106172.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RK3399平台开发系列讲解(内核调试篇)spidev_test工具使用

🚀返回专栏总目录 文章目录 一、环境二、执行测试三、回环测试四、字节发送测试五、32位数据发送测试沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 在 Linux 系统上,“spidev_test” 是一个用于测试和配置 SPI(Serial Peripheral Interface)设备的命令行工具。…

嵌入式基础知识-信息安全与加密

本篇来介绍计算机领域的信息安全以及加密相关基础知识,这些在嵌入式软件开发中也同样会用到。 1 信息安全 1.1 信息安全的基本要素 保密性:确保信息不被泄露给未授权的实体。包括最小授权原则、防暴露、信息加密、物理加密。完整性:保证数…

AI绘画:Midjourney超详细教程Al表情包超简单制作,内附关键词和变现方式

大家好,本篇文章主要介绍AI绘画完成表情包的制作和变现方式分享。 你还不会AI表情包制作吗?下面我们详细的拆解制作过程。跟着这个教程做出一套属于自己的表情包。 核心工具Midjourney PS,你就可以得到一套自己的专属表情包啦~ 整体制作…

算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言

算法竞赛入门【码蹄集新手村600题】(MT1260-1280)C语言 目录MT1260 袋鼠躲猫猫MT1261 留下来的才是幸运数MT1262 约数MT1263 最大的三位约数MT1264 完数MT1265 区间完数MT1266 完数与因子MT1267 亏数MT1268 因数的因数MT1269 区间素数MT1270 素数计算MT1271 三生质数…

周杰伦十五张专辑(珍藏版)2000-2022年

用鞭子教不出人来。——高尔基《童年》 周杰伦十五张专辑 第一张专辑 同名《JAY》 2000年11月7日 可爱女人完美主义星晴娘子斗牛黑色幽默伊斯坦堡印地安老斑龙卷风反方向的钟 第二张专辑 《范特西》2001年9月20日 爱在西元前爸,我回来了简单爱忍者开不了口上海一九…

阿里云轻量应用服务器为什么便宜?CPU性能差吗?

阿里云轻量应用服务器2核2G3M带宽优惠价108元一年,轻量应用服务器为什么便宜?是因为性能差吗?并不是,轻量应用服务器不限制CPU基准性能,轻量有月流量限制,轻量不支持指定CPU处理器,阿里云轻量2核…

【深度学习】分类损失函数解析

【深度学习】分类相关的损失解析 文章目录 【深度学习】分类相关的损失解析1. 介绍2. 解析3. 代码示例 1. 介绍 在分类任务中,我们通常使用各种损失函数来衡量模型输出与真实标签之间的差异。有时候搞不清楚用什么,下面是几种常见的分类相关损失函数及其…

springcloud-Eureka

1.Eureka注册中心 1.1 简介与依赖导入 1.2 服务注册与发现 启动eureka模块 访问Eureka 将user-service,book-service,borrow-service作为eureka的客户端,先导包。三个导入方式一样。 配置文件,三个模块下都一样配置 然后分别启动三个模块 发现注册…

数仓学习之DWD学习

登录不是原子行为,而登录成功是, 而支付也不是原子,也分成功失败。 什么是原子型? 一条线 注意一下密码, mysql的密码是MD5加密,而MD5的长度为固定的32 1.怎么构建事务表? 1.确定表名 2.确定一行数据所表示的含义 3.确定列定义 4.确定度…

ingress

pathType pathType支持完整匹配(Exact)、默认(ImplementationSpecific)和前缀匹配(Prefix)三种匹配方式。 ImplementationSpecific默认与Prefix作用相同,阿里文档 annotations配置正则匹配 ngi…

【设计模式】组合模式实现部门树实践

1.前言 几乎在每一个系统的开发过程中,都会遇到一些树状结构的开发需求,例如:组织机构树,部门树,菜单树等。只要是需要开发这种树状结构的需求,我们都可以使用组合模式来完成。 本篇将结合组合模式与Mysq…

图像文件的操作MATLAB基础函数使用

简介 MATLAB中的图像处理工具箱体统了一套全方位的标准算法和图形工具,用于进行图像处理、分析、可视化和算法开发。这里仅仅对常用的基础函数做个使用介绍。 查询图像文件的信息 使用如下函数 imfinfo(filename,fmt) 函数imfinfo返回一个结构体的info&#xff…