Qt坐标系统

news2024/11/24 8:52:01

目录

概述

渲染

逻辑表示

锯齿绘制

转换

模拟时钟示例

 Window-Viewport转换


概述

坐标系统由QPainter类控制。与QPaintDevice和QPaintEngine类一起,QPainter构成了Qt绘画系统的基础。QPainter用于执行绘制操作,QPaintDevice是一个二维空间的抽象,可以使用QPainter在其上进行绘制,QPaintEngine提供了画家用于在不同类型设备上绘制的界面。

QPaintDevice类是可绘制对象的基类:它的绘制功能由QWidget、QImage、QPixmap、QPicture和QOpenGLPaintDevice类继承。绘制设备的默认坐标系统起源于左上角。x值向右增大,y值向下增大。在基于像素的设备上,默认单位是一个像素,在打印机上是一个点(1/72英寸)。

逻辑QPainter坐标到物理QPaintDevice坐标的映射是由QPainter的转换矩阵、视口和“窗口”处理的。逻辑坐标系统和物理坐标系统默认重合。QPainter还支持坐标变换(例如旋转和缩放)。

渲染

逻辑表示

一个图元的大小(宽度和高度)总是对应于它的数学模型,忽略渲染它的笔的宽度

QRect(QPoint(1, 2), QPoint(7, 6))QLine(QPoint(2, 7), QPoint(6, 1))
QLine(2, 7, 6, 1)
QRect(QPoint(1, 2), QSize(6, 4))
QRect(1, 2, 6, 4)

锯齿绘制

绘制时,像素渲染由QPainter::Antialiasing渲染提示控制。
RenderHint枚举用于指定QPainter的标志,这些标志可能被任何给定的引擎尊重,也可能不被尊重。QPainter::Antialiasing值表示引擎应该尽可能地消除锯齿的边缘,即通过使用不同的颜色强度平滑边缘。
但在默认情况下,painter是走样(有锯齿)的,其他规则也适用:当使用一个像素宽的笔渲染时,像素将被渲染到右边,并低于数学定义的点。例如:

QPainter painter(this);

painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);

painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

当使用具有偶数像素的笔进行渲染时,像素将围绕数学定义的点对称地渲染,而使用具有奇数像素的笔进行渲染时,多余的像素将像在一个像素的情况下一样呈现在数学点的右侧和下方。有关具体示例,请参见下面的QRectF图。

QRectF
逻辑表示一个像素宽的笔
两像素宽的笔三像素宽笔

请注意,由于历史原因,QRect::right()和QRect::bottom()函数的返回值偏离了矩形的真正右下角

QRect的right()函数返回left() + width() - 1,而bottom()函数返回top() + height() - 1。图中右下角的绿色点显示了这些函数的返回坐标。

我们建议你直接使用QRectF: QRectF类使用浮点坐标在平面中定义一个矩形来保证精度(QRect使用整数坐标),而QRectF::right()和QRectF::bottom()函数则返回真正的右下角。

或者,使用QRect,应用x() + width()和y() + height()来找到右下角,避免使用right()和bottom()函数。

抗锯齿的绘画
如果你设置了QPainter的抗锯齿渲染提示,像素将在数学定义的点的两边对称地渲染:

QPainter painter(this);
painter.setRenderHint(
    QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
// Using the (x  y  w  h) overload
painter.drawRect(1, 2, 6, 4);
QPainter painter(this);
painter.setRenderHint(
    QPainter::Antialiasing);
painter.setPen(Qt::darkGreen);
painter.drawLine(2, 7, 6, 1);

转换

默认情况下,QPainter在关联设备自己的坐标系统上操作,但它也完全支持仿射坐标变换。

您可以使用QPainter::scale()函数按给定的偏移量缩放坐标系统,您可以使用QPainter::rotate()函数顺时针旋转它,并且可以使用QPainter::translate()函数平移它(即向点添加给定的偏移量)。

noprotate()scale()translate()

你也可以使用QPainter::shear()函数围绕原点旋转坐标系统。所有的转换操作都是在QPainter的转换矩阵上进行的,你可以使用QPainter::worldTransform()函数来获取这个矩阵。矩阵将平面上的一个点变换为另一个点。

如果你需要反复使用相同的变换,你也可以使用QTransform对象以及QPainter::worldTransform()和QPainter::setWorldTransform()函数。你可以在任何时候通过调用QPainter::save()函数来保存QPainter的转换矩阵,该函数将矩阵保存在内部堆栈上。QPainter::restore()函数弹出它。

在各种绘图设备上重用相同的绘图代码时,经常需要转换矩阵。如果没有变换,结果将与绘制设备的分辨率紧密绑定。打印机的分辨率很高,例如每英寸600点,而屏幕的分辨率通常在每英寸72到100点之间。

模拟时钟示例

Analog Clock示例展示了如何使用QPainter的转换矩阵绘制自定义小部件的内容。
我们建议在进一步阅读之前编译并运行此示例。特别是,尝试将窗口大小调整为不同的大小。

Analog Clock Window Example | Qt GUI 5.15.17

void AnalogClockWindow::render(QPainter *p)
{
    static const QPoint hourHand[3] = {
        QPoint(7, 8),
        QPoint(-7, 8),
        QPoint(0, -40)
    };
    static const QPoint minuteHand[3] = {
        QPoint(7, 8),
        QPoint(-7, 8),
        QPoint(0, -70)
    };

    QColor hourColor(127, 0, 127);
    QColor minuteColor(0, 127, 127, 191);

    p->setRenderHint(QPainter::Antialiasing);
    p->translate(width() / 2, height() / 2);

    int side = qMin(width(), height());
    p->scale(side / 200.0, side / 200.0);

我们转换坐标系统,使点(0,0)位于小部件的中心,而不是位于左上角。我们还将系统按side / 100进行缩放,其中side是小部件的宽度或高度,以最短的为准。我们希望时钟是方的,即使设备不是方的。
这将给我们一个200 × 200的正方形区域,原点(0,0)在中心,我们可以在上面绘图。我们绘制的内容将显示在适合小部件的最大可能的正方形中。

    QTime time = QTime::currentTime();

    p->save();
    p->rotate(30.0 * ((time.hour() + time.minute() / 60.0)));
    p->drawConvexPolygon(hourHand, 3);
    p->restore();

我们通过旋转坐标系统并调用QPainter::drawConvexPolygon()来绘制时钟的时针。多亏了旋转,它指向了正确的方向。

多边形被指定为一个交替的x、y值数组,保存在静态变量hourHand中(在函数开始时定义),它对应四个点(2,0)、(0,2)、(- 2,0)和(0,-25)。

对代码周围的QPainter::save()和QPainter::restore()的调用保证了接下来的代码不会被我们使用的转换操作干扰。

    p->save();
    p->rotate(6.0 * (time.minute() + time.second() / 60.0));
    p->drawConvexPolygon(minuteHand, 3);
    p->restore();

我们对时钟的分针也是这样做的,分针由四个点(1,0)、(0,1)、(- 1,0)和(0,-40)定义。这些坐标指定了一个比分针更细更长的指针。

    p->setPen(minuteColor);

    for (int j = 0; j < 60; ++j) {
        if ((j % 5) != 0)
            p->drawLine(92, 0, 96, 0);
        p->rotate(6.0);
    }

最后,我们画出钟面,它由12条30度间隔的短线组成。最后,painter会以一种不太有用的方式旋转,但我们已经完成了绘制,所以这无关紧要。

有关转换矩阵的更多信息,请参阅 QTransform 文档。

 Window-Viewport转换

当使用QPainter绘图时,我们使用逻辑坐标指定点,然后将其转换为绘图设备的物理坐标。

逻辑坐标到物理坐标的映射由QPainter的世界变换worldTransform()(在转换部分中描述)以及QPainter的viewport()和window()处理。视口表示指定任意矩形的物理坐标。“窗口”在逻辑坐标中描述了相同的矩形。默认情况下,逻辑坐标系统和物理坐标系统是一致的,并且等价于绘制设备的矩形。

使用window-viewport转换,你可以让逻辑坐标系统符合你的偏好。该机制也可以用于使绘图代码独立于绘图设备。例如,你可以调用QPainter::setWindow()函数,将逻辑坐标从(-50,-50)扩展到(50,50),中心为(0,0):

QPainter painter(this);
painter.setWindow(QRect(-50, -50, 100, 100));

现在,逻辑坐标(-50,-50)对应于绘图设备的物理坐标(0,0)。独立于绘图设备,您的绘图代码将始终在指定的逻辑坐标上操作。

通过设置"window"或视口矩形,可以对坐标进行线性变换。注意,“窗口”的每个角落都映射到视口的相应角落,反之亦然。因此,让视口和“窗口”保持相同的宽高比以防止变形通常是一个好主意:

int side = qMin(width(), height())
int x = (width() - side / 2);
int y = (height() - side / 2);

painter.setViewport(x, y, side, side);

如果我们将逻辑坐标系统设置为一个正方形,那么我们也应该使用QPainter::setViewport()函数将视口设置为一个正方形。在上面的示例中,我们使其等同于适合绘制设备矩形的最大正方形。通过在设置窗口或视口时考虑绘图设备的尺寸,可以使绘图代码独立于绘图设备。

请注意,窗口-视口转换只是一个线性转换,即它不执行裁剪。这意味着,如果你在当前设置的“窗口”之外绘制,你的绘制仍然会使用相同的线性代数方法转换到视口。

视口、“窗口”和变换矩阵决定了逻辑QPainter坐标如何映射到绘制设备的物理坐标。默认情况下,世界变换矩阵是单位矩阵,“窗口”和视口设置等同于绘制设备的设置,即世界、“窗口”和设备坐标系是等效的,但正如我们所看到的,系统可以使用转换操作和窗口-视口转换来操纵。上面的插图描述了这个过程。

Coordinate System | Qt GUI 5.15.17

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

L54--- 404.左叶子之和(深搜)---Java版

1.题目描述 2.思路 递归遍历左子树 &#xff0c;然后再把左子树的和相加 3.代码实现 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val …

JavaScript之类(1)

class基础语法结构&#xff1a; 代码&#xff1a; class MyClass {constructor() { ... }method1() { ... }method2() { ... }method3() { ... }... } 解释&#xff1a; 属性解释class是我们定义的类型(类)MyClass是我们定义的类的名称 constructor()我们可以在其中初始化对象m…

linux中Java程序调用C程序中方法的实现方式浅析

在Linux中&#xff0c;Java程序可以通过JNI&#xff08;Java Native Interface&#xff09;来调用C程序的方法。 Linux系统环境&#xff0c;Java调用C的主要流程如下&#xff1a; 1、创建Java类文件&#xff0c;如NativeLibrary.java 2、编写Java代码&#xff0c;加载.so共享库…

HTTP 状态码详解及使用场景

目录 1xx 信息性状态码2xx 成功状态码3xx 重定向状态码4xx 客户端错误状态码5xx 服务器错误状态码 HTTP思维导图连接&#xff1a;https://note.youdao.com/s/A7QHimm0 1xx 信息性状态码 100 Continue&#xff1a;表示客户端应继续发送请求的其余部分。 使用场景&#xff1a;客…

20240621在飞凌的OK3588-C开发板的Buildroot系统中集成i2ctool工具

20240621在飞凌的OK3588-C开发板中打开i2ctool工具 2024/6/21 17:44 默认继承的i2c工具&#xff1a; rootrk3588-buildroot:/# rootrk3588-buildroot:/# i2c i2c-stub-from-dump i2cdump i2cset i2cdetect i2cget i2ctransfer rootrk3588-…

机器学习第四十四周周报 SAMformer

文章目录 week44 SAMformer摘要Abstract1. 题目2. Abstract3. 网络架构3.1 问题提出3.2 微型示例3.3 SAMformer 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程 5. 结论6.代码复现小结参考文献 week44 SAMformer 摘要 本周阅读了题为SAMformer: Unlocking the Potential…

开启文物保护新篇章——智能RFID文物藏品库房管理系统

在历史的长河中&#xff0c;文物不仅是见证文明的瑰宝&#xff0c;更是文化传承的重要载体。这些承载着丰富历史和文化价值的珍贵文物&#xff0c;需要得到科学、精细的保护和管理。为了更好地守护和传承我们的文化遗产&#xff0c;我们荣幸地推出智能RFID文物藏品库房管理系统…

(2024,Vision-RWKV,线性复杂度双向注意力,四向标记移位)通过类似 RWKV 的架构实现高效且可扩展的视觉感知

Vision-RWKV: Efficient and Scalable Visual Perception with RWKV-Like Architectures 公和众与号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 特征聚合机制 3. Vision-RWKV 3.…

怎么看电脑实时充电功率

因为我想测试不同的充电器给电脑充电的速度&#xff0c;所以就想找一款软件可以看电脑当前充电功率的软件&#xff0c;我给一个图 直接搜索就可以下载了&#xff0c;charge rate就是功率&#xff0c;这里是毫瓦&#xff0c;换算单位是 1000mw1w 所以我这里充电功率是65w&…

RocketMQ-记一次生产者发送消息存在超时异常

目录 1、背景说明 2、排查 2.1、防火墙 2.2、超时时间设置 2.3、服务器资源检查 2.3.1、内存、CPU等 2.3.2、磁盘空间 ​编辑 2.3.3、检查文件描述符 2.3.4、swap区 3、增加swap空间 3.1、创建目录 3.2、格式化 3.3、启动swap 3.4、查看效果 1、背景说明 在一次…

音视频开发—FFmpeg 打开摄像头进行RTMP推流

实验平台&#xff1a;Ubuntu20.04 摄像头&#xff1a;普通USB摄像头&#xff0c;输出格式为YUV422 1.配置RTMP服务器推流平台 使用Nginx 配置1935端口即可&#xff0c;贴上教程地址 ubuntu20.04搭建Nginxrtmp服务器) 2.配置FFmpeg开发环境 过程较为简单&#xff0c;这里不…

深度学习Week17——优化器对比实验

文章目录 深度学习Week17——优化器对比实验 一、前言 二、我的环境 三、前期工作 1、配置环境 2、导入数据 2.1 加载数据 2.2 检查数据 2.3 配置数据集 2.4 数据可视化 四、构建模型 五、训练模型 1、将其嵌入model中 2、在Dataset数据集中进行数据增强 六、模型评估 1、Accur…

IMU用于飞行坐姿校正

为了提升长途飞行的舒适度并预防乘客因不良坐姿导致的身体不适&#xff0c;来自荷兰上海两所大学的研究团队携手开发出一种创新的“舒适穿戴”设备&#xff0c;专为识别飞行中的坐姿设计。 研究团队制作了两种原型设备&#xff1a;一种追求极致舒适&#xff0c;另一种为紧身设…

增强-MIGO物料消耗需要将物料描述写到会计凭证的摘要里面

财务比较闲提的需求&#xff0c;有些物料消耗需要将物料描述写到会计凭证的摘要里面&#xff0c; 找了一下增强点&#xff0c;随便搞了一下&#xff0c;可以了。

20240620日志:TAS-MRAM的电阻开放分析

TAS-MRAM的电阻开放缺陷分析 1 MRAM介绍开放电阻的缺陷 1 MRAM介绍 MRAM(Magnetic random access memory)&#xff0c;磁随机存储器&#xff0c;利用磁性材料的状态来存储数据。MRAM的存储单元通常由一个磁隧道结&#xff08; M T J 茅台酒 MTJ^{茅台酒} MTJ茅台酒&#xff0c…

STM32小项目———感应垃圾桶

文章目录 前言一、超声波测距1.超声波简介2.超声波测距原理2.超声波测距步骤 二、舵机的控制三、硬件搭建及功能展示总结 前言 一个学习STM32的小白~ 有问题请评论区或私信指出 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、超声波测距 1.超声波…

通过 Setapp 使用 240 多款 Mac 生产力工具以及 GPT-4o

Setapp 是一项革命性的订阅服务&#xff0c;可以使用 240 多款 Mac 应用程序的综合套件&#xff0c;并配有强大的人工智能助手。 通过 Setapp 为你的工作效率和生产力增添魔力。 Setapp 官网&#xff1a;访问&#xff08;提供 7 天试用&#xff09; Setapp 的主要功能 AI 助手…

人工智能对决:ChatGLM与ChatGPT,探索发展历程

图: a robot is writing code on a horse, By 禅与计算机程序设计艺术 目录 ChatGLM:

数据结构-图的存储结构-邻接矩阵

图的结构十分复杂&#xff0c;不仅各个结点的度不同&#xff0c;各个顶点之间的路径也不尽相同。但是图的主要组成部分比较清晰&#xff0c;分为顶点信息和边或者弧的信息。 邻接矩阵 邻接矩阵就是用一维数组存储图中顶点的信息&#xff0c;用一个二维数组表示图中各个顶点之间…

区块链技术:重塑金融市场监管的新引擎

一、引言 随着金融市场的不断发展和创新&#xff0c;监管面临的挑战也日益严峻。传统的监管模式已难以满足现代金融市场的需要&#xff0c;而区块链技术的出现为金融市场监管带来了新的机遇。本文将探讨区块链技术在金融市场监管中的作用&#xff0c;以及它如何重塑监管模式&a…