转载自http://www.lgwimonday.cn/archives/1383
Qt入门教程(4) 窗口与视口原理解析
图形绘制的坐标变换流程
学习窗口、视口,我们首先从下面这张图讲起。
这张图讲述的是Qt中坐标的变换方式,也是在Qt中绘图的基本原理。绘制图形会传入坐标,如painter.drawRect(20,20,50,50);这里的坐标即是世界坐标;世界坐标经过矩阵变换,得到窗口坐标,窗口坐标经过窗口-视口变换,得到设备坐标(物理坐标)。
窗口视口等重要概念
上面的看图说话中涉及了很多概念,这些概念因其专业性,变得晦涩难懂,让我们下面来对这些概念进行讲解。
世界坐标:也叫逻辑坐标,使用的单位叫做逻辑单位,是人类世界中的坐标,如北京在地图中的坐标为(700km,899km)。这种坐标系统可大可小,大可至几万千米,小至几毫米,随你设置,该系统中坐标大小与显示设备大小无关。一般来说,逻辑坐标系在左下角,正X轴向又,正Y轴向上。
窗口坐标:窗口坐标和世界坐标其实没有太大区别,都使用逻辑坐标进行表示。只是世界坐标和窗口坐标之间可能会存在一些变换,如平移、缩放、旋转、扭曲。
设备坐标:也叫物理坐标,原点在左上角,正X轴向右,正Y轴向下,显示器中,坐标单位通常为像素,打印机中,坐标单位通常为点。其X、Y的负半轴为虚设,超出设备的部分无法显示或无法打印图形。设备坐标系和设备大小密切相关的,超出设备大小之外的图形是不予显示或打印的。
窗口:逻辑环境中的一个矩形框,使用逻辑坐标,图中世界坐标和窗口坐标外围的虚线框即为窗口。窗口具有原点和长宽,这也就决定了窗口的位置和大小。窗口存在的意义即是为了确定人类世界中的某个物体需要显示的位置和范围。如我要显示地图中的江苏部分,我就需要将窗口的原点位置设置为江苏,长宽设置为江苏省的外接矩形大小。如果我要显示地图中的中国部分,则将窗口扩大,原点设置为中国,长宽设置为中国的外接矩形大小。在视口不变的情况下,扩大窗口其实就是相当于对地图进行了缩小。
视口:设备环境中的一个矩形框,使用物理坐标,和设备的大小密切相关,超出设备外的视口区域不予显示。视口存在的意义是指定在显示设备的哪个地方,以多大的范围完全显示指定的窗口内容。
世界变换
世界变换的目的是直接对逻辑坐标进行矩阵变换,最常见的变换操作是:
- translate()函数,进行平移变换;
- scale()函数,进行比例变换;
- rotate()函数,进行旋转变换;
- shear()函数,进行扭曲变换。
窗口视口变换
窗口视口变换的目的是提供一种变换方式,让逻辑坐标能够在设备坐标中进行显示。用户输入的坐标一定是逻辑坐标,最终用来绘制的一定是经过窗口-视口变换后的视口坐标,也就是设备坐标(物理坐标)。
如果不显示的用代码指定窗口和视口的大小,默认的窗口和视口坐标原点都是(0,0),大小都是设备的长和宽。用代码指定窗口和视口大小的方式分别为:
setWindow(-300,-300,600,600)// 指定窗口位置和大小
setViewPort(-100,-100,600,600)// 指定视口位置和大小。
窗口和视口的变换关系其实就是一对线性函数。
X'=aX+b;
Y'=cY+d。
其中,a,b,c,d为四个待确定的系数,X、Y是窗口坐标,X'、Y'是视口坐标。a,b,c,d如何确定?在窗口(-300,-300,600,600)中,实际上是指定了窗口的两个坐标,左上角(-300,-300),右下角(300,300);在视口(-100,-100,600,600)中,指定了视口左上角坐标(-100,-100),视口右下角(500,500).根据左上角对应左上角,右下角对应右下角的关系,得到:x方向上有:-100=-300a+b,500=300a+b,解得a=1,b=200;y方向有:-100=-300c+d,500=300c+d,解得c=1,d=200。
得到关系后再来绘图则是经过该关系变换后的值了。比如painter.drawPoint(0,10),对应x=0,得到x'=0*a+b=200;对应y=10,得到y'=10*c+d=210;即实际上是在显示设备的(200,210)处绘制了一个点。