Qt坐标系统之三个坐标系和两个变换

2024-08-24 09:44

本文主要是介绍Qt坐标系统之三个坐标系和两个变换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Qt坐标系统由QPainter类控制。它和QPaintDeviceQPaintEngine类一起构成Qt绘图系统的基础。QPainter用于执行绘图操作,QPaintDeviceQPainter用来绘制的一个二维空间的抽象,QPaintEngine提供在不同设备绘图的接口。
Qt 的坐标分为逻辑坐标物理坐标。在我们绘制时,提供给QPainter的都是逻辑坐标。所谓物理坐标,就是绘制底层QPaintDevice的坐标。单单只有逻辑坐标,我们是不能在设备上进行绘制的。要想在设备上绘制,必须提供设备认识的物理坐标。Qt 使用viewport-window机制将我们提供的逻辑坐标转换成绘制设备使用的物理坐标,方法是,在逻辑坐标物理坐标之间提供一层“窗口”坐标。视口是由任意矩形指定的物理坐标窗口则是该矩形的逻辑坐标表示。默认情况下,物理坐标逻辑坐标一致的,都等于设备矩形。

正文

简述

三个坐标系

  • 逻辑坐标系(Logical Coordinate System
    也称为用户坐标系,是在编程时最常使用的坐标系。
    坐标原点(0,0)通常位于窗口的左上角,X轴向右增长,Y轴向下增长。
    通过逻辑坐标系来指定图形元素(如线条、矩形等)的位置和大小。
  • 窗口坐标系(Window Coordinate System
    是逻辑坐标系经过变换(如缩放、旋转等)后得到的坐标系。
    用于在绘制过程中表示图形元素在窗口中的实际位置。窗口决定了我是看你的一部分还是整体。
    QPainter内部使用的一个坐标系,用于将逻辑坐标转换为绘图设备(如屏幕、打印机等)上的物理坐标。
  • 物理坐标系(Physical Coordinate System
    也称为设备坐标系,代表了绘图设备(如屏幕、打印机等)上的实际坐标系统。
    物理坐标系的原点、坐标轴方向以及单位(通常是像素)由绘图设备决定。
    QPainter最终会将图形元素绘制到物理坐标系中。

也就是说我们在绘制图像的时候一般是先在逻辑坐标系上构建想法,然后调用相关代码进行绘制,然后编译器编译时会将我们绘制在逻辑坐标系上的图形转换到窗口坐标系,最后转换到物理坐标系
默认情况下这三种坐标系是等同的。
它们之间的转换关系

Logical Coordinate System—>Window Coordinate System—>Physical Coordinate System
逻辑坐标setWindow()变换窗口坐标setViewport()变换物理坐标

两个变换

  • setWindow() 变换
    用于设置窗口坐标系的范围。相当于给逻辑坐标系加一个方框,然后我只能看到这个方框里面的东西
    通过调用setWindow(xMin, yMin, xMax, yMax),可以指定窗口坐标系的左下角和右上角坐标。
    这个变换主要影响逻辑坐标系到窗口坐标系的映射关系,进而影响图形元素在窗口中的实际位置
  • setViewport() 变换
    用于设置物理坐标系中用于绘图的矩形区域(即视口(如屏幕))。
    通过调用setViewport(x, y, width, height),可以指定视口在物理坐标系中的位置和大小。
    这个变换主要影响窗口坐标系到物理坐标系的映射关系,进而影响图形元素在物理设备上的实际绘制位置。

例子

首先调用resize(300,300), 然后绘制窗口的两条对角线(注意我们现在所使用的就是逻辑坐标系)
在这里插入图片描述

使用setWindow()

在这里插入图片描述

可以看到窗口大小本身并没有变化,但是线段更细了(上面两条挨着的是新绘制的),我就添加了一行代码painter.setWindow(0,0,600,600);这行代码的意思是我设置了一个新的逻辑坐标系,在该逻辑坐标系下,窗口原点位于该逻辑坐标系的(0,0)位置,窗口的宽和高分别为600(原逻辑坐标系宽高为300,所以显得扩大了2倍;由于扩大了两倍,原先两个点相当于现在的一个点所以显得细了);然后我下面继续调用绘图时就会在这个新的逻辑坐标系下进行绘制,所以说300像素在新的逻辑坐标系中只能是中间的位置。

  • 如果设置painter.setWindow(0,0,600,600);painter.setWindow(0,0,150,150);会发生什么呢?
    在这里插入图片描述

可以看到窗口大小本身并没有变化,但是线条显得更加粗了;这是由于在新的逻辑坐标系中窗口的大小被设置成了150x150;原先在逻辑坐标中是300x300,相当于压缩了,原先的两个点相当于现在的一个点。

  • 如果将painter.setWindow(0,0,600,600);改成painter.setWindow(20,30,520,180);会发生什么呢?
    在这里插入图片描述
    为什么会这样呢?新画的对角线为什么会超出边界呢?此时的窗口坐标系的取值如何计算?其实这也很好理解,我有一条对角线,取它的两个端点(0,0),(75,75)这是它的逻辑坐标,它的窗口坐标怎么计算呢?
    对于(0,0):

((30 + 0 * 520/300),(20 + 0 * 180/300) = (30, 20 )

对于(75,75):

((30 + 75 * 520/300),(20 + 75 * 180/300) = (159.75, 65)

对于此时窗口坐标系的取值

横坐标的取值范围为[30, 490],纵坐标的取值范围为[20,160]
对于线段上的点总归有些计算完窗口坐标后会超出坐标取值范围,使得其不在窗口上

使用setViewport()

还是使用刚才的例子,不过有些变化
在这里插入图片描述
可以看到窗口大小本身并没有变化,但是线条显得更加粗了;这是因为painter.setViewport(0,0,600,600);意思是将绘图操作的视口设置为一个从 (0,0) 开始,宽度和高度都是 600 个单位(由于没有修改相应的窗口坐标,窗口坐标范围不变);这个代码相当于把整个物理坐标系翻倍了。也就是单位逻辑坐标变大了。原来逻辑坐标画1个像素点,现在相当于画2个。

  • 如果设置painter.setViewport(0,0,600,600);painter.setViewport(0,0,150,150);会发生什么呢?

在这里插入图片描述
可以看到窗口大小本身并没有变化,但是线条显得更加细了;这是因为painter.setViewport(0,0,150,150);意思是将绘图操作的视口设置为一个从 (0,0) 开始,宽度和高度都是 150 个单位(由于没有修改相应的窗口坐标,窗口坐标范围不变);这个代码相当于把整个物理坐标系缩小2倍了。也就是单位逻辑坐标变小了。比如(75,75)转换成窗口坐标后为

((0 + 75 * 150/300),(0 + 75 * 150/300)) = (37.5, 37.5)
而37.5在300*300的窗口坐标中只占了1/8

  • 如果设置painter.setViewport(0,0,600,600);painter.setViewport(20,30,540,120);会发生什么呢?

在这里插入图片描述
我们将物理坐标原点修改为 (20, 30),长540,高是 120 的矩形时,窗口坐标范围不变,也就是说,我们将物理宽 540px 映射成窗口宽 300px,物理高 120px 映射成窗口高 300px。那么坐标如何计算呢?
比如还是(0,0)与(75,75)
对于(0,0):

((20 + 0 * 540/300),(30 + 0 * 120/300) = (20, 30 )

对于(75,75):

((20 + 75 * 540/300),(30 + 75 * 120/300) = (155, 165)

对于此时窗口坐标系的取值

横坐标的取值范围为[20, 520],纵坐标的取值范围为[30,90]

遗留小问题,如果将paintEvent中的内容改成

	QPainter painter(this);painter.setViewport(0, 0, 150, 150);painter.fillRect(0, 0, 150, 150, Qt::green);

那么将会有多少窗口被填充?
答案是1/16

这篇关于Qt坐标系统之三个坐标系和两个变换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Linux系统之主机网络配置方式

《Linux系统之主机网络配置方式》:本文主要介绍Linux系统之主机网络配置方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、查看主机的网络参数1、查看主机名2、查看IP地址3、查看网关4、查看DNS二、配置网卡1、修改网卡配置文件2、nmcli工具【通用

Linux系统之dns域名解析全过程

《Linux系统之dns域名解析全过程》:本文主要介绍Linux系统之dns域名解析全过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、dns域名解析介绍1、DNS核心概念1.1 区域 zone1.2 记录 record二、DNS服务的配置1、正向解析的配置

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

Linux系统中配置静态IP地址的详细步骤

《Linux系统中配置静态IP地址的详细步骤》本文详细介绍了在Linux系统中配置静态IP地址的五个步骤,包括打开终端、编辑网络配置文件、配置IP地址、保存并重启网络服务,这对于系统管理员和新手都极具... 目录步骤一:打开终端步骤二:编辑网络配置文件步骤三:配置静态IP地址步骤四:保存并关闭文件步骤五:重

Qt 中 isHidden 和 isVisible 的区别与使用小结

《Qt中isHidden和isVisible的区别与使用小结》Qt中的isHidden()和isVisible()方法都用于查询组件显示或隐藏状态,然而,它们有很大的区别,了解它们对于正确操... 目录1. 基础概念2. 区别清见3. 实际案例4. 注意事项5. 总结1. 基础概念Qt 中的 isHidd

QT移植到RK3568开发板的方法步骤

《QT移植到RK3568开发板的方法步骤》本文主要介绍了QT移植到RK3568开发板的方法步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录前言一、获取SDK1. 安装依赖2. 获取SDK资源包3. SDK工程目录介绍4. 获取补丁包二