Qt之坐标系统

简述

坐标系统是由QPainter类控制的,再加上QPaintDevice和QPaintEngine类,就形成了Qt的绘图体系。

  • QPainter:用于执行绘图操作。
  • QPaintDevice:二维空间的抽象层,可以使用QPainter在它上面进行绘制。
  • QPaintEngine:提供了统一的接口,用于QPainter在不同的设备上进行绘制。

QPaintDevice类是可以被绘制的对象的基类,它的绘图功能由QWidget、QImage、QPixmap、QPicture和QOpenGLPaintDevice继承。默认坐标系统位于设备的左上角,即坐标原点(0, 0)。X轴由左向右增加,Y轴由上向下增加。在基于像素的设备上(比如:显示器),坐标的默认单位是1像素;在打印机上则是1点(1/72 英寸)。

QPainter逻辑坐标与QPaintDevice物理坐标的映射,由QPainter的变换矩阵(transformation matrix)、视口(viewport)和窗口(window)完成。默认情况下,物理坐标与逻辑坐标系统是重合的,QPainter也支持坐标转换,例如:旋转、缩放。

  • 简述
  • 渲染
    • 逻辑表示
    • 锯齿绘制
    • 抗锯齿绘制
  • 坐标转换
  • 窗口-视口转换
  • 更多参考

渲染

逻辑表示

一个图形图元的大小(宽度和高度)总是对应于它的数学模型,忽略绘制时画笔的宽度:

锯齿绘制

绘制的时候,像素渲染由QPainter::Antialiasing来控制。

枚举RenderHint用于指定QPainter的渲染标志,绘图引擎会用到。QPainter::Antialiasing表示引擎应该尽可能的让图元边缘抗锯齿,即:使用不同的颜色亮度让边缘平滑。

默认情况下,QPainter绘制时有锯齿,并且有其它规则:当用1像素宽的画笔绘制时,像素会被绘制在右下角。例如:

绘制时,如果画笔的宽度像素是偶数,则实际绘制会包裹住逻辑坐标值;如果是奇数,则是包裹住逻辑坐标值,再加上右下角1个像素的偏移。具体请看下面QRectF图示:

注意:由于历史原因,QRect::right()和QRect::bottom()的返回值并不是矩形右下角的真实坐标值。

QRect::right()返回:left() + width() – 1;QRect::bottom()返回:top() + height() – 1。上图中右下角的绿色点指出了这两个函数返回的坐标值。

为避免这个问题,建议是使用QRectF。QRectF使用浮点精度的坐标来定义一个平面矩形(QRect则使用整形坐标)。函数QRectF::right()和QRectF::bottom()会返回真正的右下角坐标值。

如果要使用QRect,可以利用x() + width()和y() + height()来替代right()和bottom()。

抗锯齿绘制

如果设置了QPainter的抗锯齿标志,像素就会被均匀地绘制在两侧。

坐标转换

默认情况下,QPainter操作相关设备自身的坐标系统,但它也完全支持仿射坐标转换。

你可以缩放坐标系统,使用QPainter::scale()函数并指定一个偏移量;可以使用QPainter::rotate()函数来顺时针旋转它;可以使用QPainter::translate()函数来平移它。

还可以使用QPainter::shear()函数绕着原点扭曲坐标系统,所有的转换操作都作用在QPainter的转换矩阵上,可以使用QPainter::worldTransform()进行检索,一个矩阵转换平面上的一个点到另一个点。

如果你需要进行反复的相同转换,可以使用QTransform对象和QPainter::worldTransform()、QPainter::setWorldTransform()函数。通过调用QPainter::save()函数(保存矩阵在内部堆栈上),你可以随时保存QPainter的转换矩阵,QPainter::restore()函数用于恢复上次的结果。

矩阵转换的频繁需求是在不同的绘图设备上使用相同的绘制代码。没有转换,结果被紧密地结合到绘图设备的分辨率上。打印机具有高分辨率,例如:600 DPI(每英寸点数),而屏幕的通常为72 - 100 DPI。

窗口-视口转换

当使用QPainter绘制时,我们规定了使用逻辑坐标的点,然后转换成绘图设备的物理坐标。

逻辑坐标到物理坐标的映射,由QPainter世界变换worldTransform()(“坐标转换”中所描述的部分)、及QPainter的viewport()、window()处理。视口表示由任意矩形指定的物理坐标;窗口则用逻辑坐标描述了相同的矩形。默认情况下,物理坐标和逻辑坐标一致,都等于绘图设备的矩形。

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

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

现在,逻辑坐标的(-50,-50)对应绘图设备物理坐标的(0, 0)点。独立于绘图设备,你的绘制代码在指定的逻辑坐标上总能运行。

通过设置窗口或视口矩形,执行一个线性变换的坐标。注意:每个窗口的角落映射到相应的视口的角落,反之亦然。因此,这通常是一个好方法,让视口和窗口保持相同的长宽比,防止变形:

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 - 助手
时间: 2025-01-01 05:35:20

Qt之坐标系统的相关文章

[Qt教程] 第16篇 2D绘图(六)坐标系统

[Qt教程] 第16篇 2D绘图(六)坐标系统 楼主  发表于 2013-5-2 20:08:12 | 查看: 738| 回复: 0 坐标系统 版权声明 该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处! 导语 前面一节我们讲解了图片的显示,其中很多地方都用到了坐标的变化.这一节我们将讲解Qt的坐标系统,分为两部分来讲解:第一部分主要讲解前面一节的那几个函数,它们分别是translate()平移变换.scale()比例变换.rotate()旋转变

《Qt 实战一二三》

简介 "我们来自Qt分享&&交流,我们来自Qt Quick分享&&交流",不管你是笑了,还是笑了,反正我们是认真的.我们就是要找寻一种Hold不住的状态,来开始每一天的点滴分享,我们是一个有激情,有态度的部队. 但是我们还是我们,我们只是多了一份责任.古语有云:"不积跬步无以至千里,不积小流无以成江海",所以每一个伟大事务的产生都不是一蹴而就的.现在我们要立足眼下,把第一站放在地球,"<Qt 实战一二三>&quo

[Qt教程] 第17篇 2D绘图(七)涂鸦板

[Qt教程] 第17篇 2D绘图(七)涂鸦板 楼主  发表于 2013-5-2 21:37:41 | 查看: 1255| 回复: 16 涂鸦板 版权声明 该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处! 导语        通过前面几节的学习,大家应该已经对Qt中2D绘图有了一定的认识,这一节我们将应用前面讲到的内容,编写一个简单的涂鸦板程序,这一节只是实现最基本的鼠标画线功能. 环境:Windows Xp + Qt 4.8.4+QtCreat

Qt学习之路(28):坐标变换

经过前面的章节,我们已经能够画出一些东西来,主要就是使用QPainter的相关函数.今天,我们要看的是QPainter的坐标系统. 同很多坐标系统一样,QPainter的默认坐标的原点(0, 0)位于屏幕的左上角,X轴正方向是水平向右,Y轴正方向是竖直向下.在这个坐标系统中,每个像素占据1 x 1的空间.你可以把它想象成是一张坐标值,其中的每个小格都是1个像素.这么说来,一个像素的中心实际上是一个"半像素坐标系",也就是说,像素(x, y)的中心位置其实是在(x + 0.5, y +

[Qt教程] 第13篇 2D绘图(三)绘制文字

[Qt教程] 第13篇 2D绘图(三)绘制文字 楼主  发表于 2013-4-25 23:04:46 | 查看: 720| 回复: 0 绘制文字 版权声明 该文章原创于Qter开源社区,作者yafeilinux,转载请注明出处! 导语 Qt中除了绘制图形以外,还可以使用QPainter::darwText()函数来绘制文字,也可以使用QPainter::setFont()设置文字所使用的字体,使用QPainter::fontInfo()函数可以获取字体的信息,它返回QFontInfo类对象.在绘

[Qt教程] 第15篇 2D绘图(五)绘制图片

[Qt教程] 第15篇 2D绘图(五)绘制图片 楼主  发表于 2013-5-2 17:59:00 | 查看: 886| 回复: 3 绘制图片 版权声明 该文章原创于Qter开源社区(www.qter.org),作者yafeilinux,转载请注明出处! 导语 Qt提供了四个类来处理图像数据:QImage.QPixmap.QBitmap和QPicture,它们也都是常用的绘图设备.其中QImage主要用来进行I/O处理,它对I/O处理操作进行了优化,而且也可以用来直接访问和操作像素:QPixma

Qt之对象树与所有权

简述 QObjects在一个对象树中组织他们自己.当创建一个QObject时,如果使用了其他对象作为其父对象,那么,它就会被添加到父对象的children()列表中.这样一来,当父对象被销毁时,这个QObject也会被销毁.事实表明,这个机制非常适合于管理GUI对象.例如:一个QShortcut(键盘快捷键)对象是相关窗口的一个子对象,所以,当用户关闭了这个窗口时,快捷键也会被销毁. 简述 详细描述 QObjects的构造销毁顺序 详细描述 QQuickItem是Qt Quick模块的基本视觉元

Qt之图形视图框架

简述 图形视图(Graphics View)提供了一个平台,用于大量自定义2D图元的管理与交互,并提供了一个视图部件(view widget)来显示可以缩放和旋转的图元. 框架包括一个事件传播架构,支持场景(Scene)中的图元(Item)进行精确的双精度交互功能.图元可以处理键盘事件.鼠标按下.移动.释放和双击事件,同时也能跟踪鼠标移动. 图形视图使用一个BSP(Binary Space Partitioning - 二叉空间分割)树,以提供对图形元素的快速查找,正因为如此,它可以使超大的场景

Qt之图形(转换)

简述 QTransform类指定坐标系的2D转换,可以指定平移.缩放.扭曲(剪切).旋转或投影坐标系.绘制图形时,通常会使用. QTransform与QMatrix的不同之处在于,它是一个真正的3x3矩阵,允许视角转换,QTransform的 toAffine()方法允许将QTransform转换到QMatrix.如果视角转换已在矩阵指定,则转换将导致数据丢失. 简述 常用接口 正常 效果 源码 平移 效果 源码 旋转 效果 源码 缩放 效果 源码 扭曲 效果 源码 常用接口 函数 描述 tra