Qt坐标系统

目录

概述

渲染

逻辑表示

锯齿绘制

坐标转换

模拟时钟示例

 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转换

  • world坐标:转换(移动,缩放,旋转)后的逻辑坐标(没有转换则等于逻辑坐标)
  • 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),宽高是100,那么右下角是(50,50);

现在,逻辑坐标(-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);//左上角是(50,50),宽高是100,右下角是(150,150)

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

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

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

Coordinate System | Qt GUI 5.15.17

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

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

相关文章

番外篇 | YOLOv8算法解析和实战应用:车辆检测 + 车辆追踪 + 行驶速度计算

前言:Hello大家好,我是小哥谈。YOLOv8是ultralytics公司在2023年1月10号开源的,是YOLOv5的下一个重大更新版本,目前支持图像分类、物体检测和实例分割任务,在还没有开源时就收到了用户的广泛关注。它是一个SOTA模型,建立在以前YOLO版本的成功基础上,并引入了新的功能和改…

开发中遇到的错误 - @SpringBootTest 注解爆红

我在使用 SpringBootTest 注解的时候爆红了&#xff0c;ait 回车也导不了包&#xff0c;后面发现是因为没有加依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId>…

【shell脚本速成】函数

文章目录 一、函数1.1、函数介绍1.2、函数定义1.3、函数调用 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&#xff01;&#x1f60a; &#x1f338;愿您在此停留的每一刻&#xf…

网络虚拟化考题

vrrp讲过吗&#xff1f;&#xff1f;&#xff1f; d 每一层都是什么设备啊 abcd 为啥流量不可控不可视 c是啥意思 讲过吗 abc aNET网络虚拟化是啥啊 为啥&#xff1f;&#xff1f; 啥是CDN&#xff1f;&#xff1f;&#xff1f;&#xff1f;&#xff1f;

Java数据类型与运算符

1. 变量和类型 变量指的是程序运行时可变的量&#xff0c;相当于开辟一块空间来保存一些数据。 类型则是对变量的种类进行了划分&#xff0c;不同类型的变量具有不同的特性。 1.1 整型变量&#xff08;重点&#xff09; 基本语法格式&#xff1a; int 变量名 初始值;代码示…

舔狗日记Puls微信小程序源码

源码介绍&#xff1a; 这是一款舔狗日记Puls微信小程序源码&#xff0c;提供每日一舔的功能&#xff0c;让你舔到最后&#xff0c;什么都有&#xff01; 源码通过API获取一些舔狗日记&#xff0c;内置了100多句舔狗日记&#xff0c;让你摆脱上班摸鱼的无聊时光&#xff0c; …

TIM: A Time Interval Machine for Audio-Visual Action Recognition

标题&#xff1a;TIM&#xff1a;一种用于视听动作识别的时间间隔机器 源文链接&#xff1a;openaccess.thecvf.com/content/CVPR2024/papers/Chalk_TIM_A_Time_Interval_Machine_for_Audio-Visual_Action_Recognition_CVPR_2024_paper.pdfhttps://openaccess.thecvf.com/cont…

社区项目-项目介绍环境搭建

文章目录 1.技术选型2.原型设计1.安装AxureRP2.进行汉化3.载入元件库4.基本设计 3.元数建模1.安装元数建模软件2.新建项目3.新增一个刷题模块主题域4.新增数据表 subject_category5.新增关系图&#xff0c;将表拖过来6.新增题目标签表7.新增题目信息表8.新增单选表、多选表、判…

​Claude 3.5 最新体验:助力硕博生与科研人员高效完成论文,超越ChatGPT4o !

我是娜姐 迪娜学姐 &#xff0c;一个SCI医学期刊编辑&#xff0c;探索用AI工具提效论文写作和发表。 要不说AI领域的进展真的是日新月异&#xff0c;发展速度已经大大超过预期进度。娜姐本来在准备AI降重工具的测评文章&#xff08;最近好多小伙伴需要&#xff09;。 昨天晚上…

ECharts 词云图案例二:创意蒙版应用

ECharts 词云图案例二&#xff1a;创意蒙版应用 引言 在数据可视化领域&#xff0c;ECharts 以其强大的功能性和灵活性&#xff0c;成为开发者和设计师的首选工具之一。继上一篇关于 ECharts 词云图的详细介绍后&#xff0c;本文将探索词云图的进阶应用——使用蒙版来创造更具…

【C#上位机应用开发实战】—— UI界面设计与实践代码

在C#上位机应用开发中&#xff0c;UI界面设计是至关重要的一环。一个好的UI设计不仅可以提升应用的用户体验&#xff0c;还可以提高应用的易用性和效率。本文将介绍一些UI界面设计的实战经验和技巧。 在这个示例中&#xff0c;我们创建了一个名为MainForm的窗体类。该窗体包含了…

AI在线免费视频工具2:视频配声音;图片说话hedra

1、视频配声音 https://deepmind.google/discover/blog/generating-audio-for-video/ https://www.videotosoundeffects.com/ &#xff08;免费在线使用&#xff09; 2、图片说话在线图片生成播报hedra hedra 上传音频与图片即可合成 https://www.hedra.com/ https://www.…

如何使用Windows备份轻松将数据转移到新电脑?这里有详细步骤

序言 我们都知道那种买了一台新电脑,就想直接上手的感觉。我记得在过去的日子里,要花几个小时传输我的文件,并试图复制我的设置。在当今传输数据的众多方法中,Windows备份提供了一个简单可靠的解决方案。 登录到你的Microsoft帐户 Microsoft在传输过程中使用其云存储来保…

英文字母表

目录 一 设计原型 二 后台源码 一 设计原型 二 后台源码 namespace 英文字母表 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e){foreach (var item in panel1.Controls){if (item ! null)…

A股3000点失守是出局还是机会?

今天的大A失守300点&#xff0c;那么A股3000点失守是出局还是机会&#xff1f; 1、今天两市低开&#xff0c;盘中一度跌破3000点&#xff0c;最低回踩到了2985点&#xff0c;盘面出现了两个罕见现象&#xff0c;意味着即将探底回升。 2、盘面出现两个罕见现象&#xff1a; 一是…

buuctf----firmware

- -一定不能再ubutu22进行,我是在18(血泪教训) binwalk安装 buuctf firmware(binwalk和firmware-mod-kit的使用)_buu firmware-CSDN博客 参考博客 指令 sudo apt-get update sudo apt-get install python3-dev python3-setuptools python3-pip zlib1g-dev libmagic-dev pi…

云计算技术高速发展,优势凸显

云计算是一种分布式计算技术&#xff0c;其特点是通过网络“云”将巨大的数据计算处理程序分解成无数个小程序&#xff0c;并通过多部服务器组成的系统进行处理和分析这些小程序&#xff0c;最后将结果返回给用户。它融合了分布式计算、效用计算、负载均衡、并行计算、网络存储…

竞赛选题 LSTM的预测算法 - 股票预测 天气预测 房价预测

0 简介 今天学长向大家介绍LSTM基础 基于LSTM的预测算法 - 股票预测 天气预测 房价预测 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/postgraduate 1 基于 Ke…

k8s部署wordpress及性能优化

镜像版本&#xff1a;wordpress mysql版本&#xff1a;mysql:8.0.27 部署wordpress&#xff1a;v1 此版本包含wordpress基础服务&#xff0c;可访问&#xff0c;但是一旦pod重新创建会丢失数据&#xff0c;文章中的图片等也会丢失&#xff0c;且只又一个pod&#xff0c;性能…

高通Android 12 aapt报错问题踩坑

背景 最近因为要做多module模块&#xff0c;出现aapt报错&#xff0c;于是简单记录下&#xff0c;踩坑过程。 1、我一开始项目中三个module&#xff0c;然后在build.gradle设置androidApplication plugins {alias(libs.plugins.androidApplication) }2、运行完之后都是报下面…