Qt坐标系转换过程的个人理解
QT坐标系转换机制的个人理解
对于一个给定的绘图设备,在绘图时有两个坐标系:物理坐标系,逻辑坐标系。物理坐标系是一个真实的坐标系,在QT中,其原点处于绘图设备的左上角,其单位长度为绘图设备上一像素长度,其X轴向右增长,Y轴向下增长。而逻辑坐标系是一个抽象的坐标系,其原点、单位长度没有实际意义,其X轴向右增长,Y轴向下增长。
绘图时,图像绘制在逻辑坐标系上,再通过窗口——视口映射,世界转换将逻辑坐标系映射到物理坐标系上。进而把绘制在逻辑坐标系上的图像映射到物理坐标系上。
注意:在个人理解中,是先进行窗口——视口映射,再进行世界转换。(但文档中描述是先进行世界转换,再进行窗口——视口映射,这点想不通。如果不先通过窗口——视口映射将抽象的逻辑坐标系具体化,对其进行世界转换有什么意义?将逻辑坐标系具体化意思是确定逻辑坐标系的原点与单位长度)。
首先进行窗口(window)——视口(viewport)转换:
首先需要了解的是:窗口基于逻辑坐标系,视口基于物理坐标系。使用以下两个函数可以得到一个基于逻辑坐标系的窗口矩形,与一个基于物理坐标系的视口矩形。
void QPainter::setWindow ( int x, int y, int width, int height )
void QPainter::setViewport ( int x, int y, int width, int height )
窗口——视口转换就是通过这两个矩形,将逻辑坐标系映射到物理坐标系上(也可以说是把逻辑坐标系具体化)。其确定方式是通过在物理坐标系上移动,拉伸逻辑坐标系,使得窗口矩形与视口矩形重合,此时经过移动拉伸得到的逻辑坐标系便是其在物理坐标系上的映射。
接着是世界转换。世界转换有以下四种方式(目前我了解的):
(1) translate( ) 平移。
(2) scale( ) 拉伸,缩放。
(3) rotate( ) 旋转。
(4) shear( ) 扭曲。
世界转换就是在已经具体化的逻辑坐标系的基础上,对其进行平移,拉伸,缩放,旋转,扭曲等操作。需要注意的是每次的世界转换都是在上一次世界转换的基础上进行的。世界转换的过程是一个状态机转换的过程。因此先平移再旋转,与先旋转再平移所得的结果是不同的。
通过上述映射,在逻辑坐标系上绘制的图像便能转换为物理坐标系上的图像。
注:窗口——视口转换只是提供一种从逻辑坐标系到物理坐标系的映射方式,并不起到剪切区域的作用,就是说画在逻辑坐标系窗口矩形外的图像也会映射到物理坐标系上,并显示出来。
如果不使用setWindow指定窗口矩形,则窗口矩形默认设置为绘图设备矩形。此默认设置同样适用于视口矩形(绘图设备为QWidget,QPixmap之类的东西)。
示例:逻辑坐标(窗口)
1 QPainter painter(this); 2 //逻辑坐标(-50,-50)映射到视口的(0,0)坐标上,窗口大小为(100,100) 3 painter.setWindow(-50,-50,100,100); 4 painter.setBrush(Qt::green); 5 //drawRect是在逻辑坐标上进行绘制图形的,而已随着视口的大小改变,逻辑坐标也会发生改变,达到自适应窗体效果; 6 painter.drawRect(0,0,20,20); 7 //窗体默认大小为(400,300),逻辑窗口自适应视口后,映射坐标为(200,150),矩形大小为(80,60);
示例:物理坐标(视口)
1 QPainter painter(this); 2 int side = qMin(width(),height()); 3 int x = (width()/2); 4 int y = (height()/2); 5 //将视口(绘制设备的物理坐标)设置为窗体原来的一半,起始坐标为原窗体的中心,大小取原窗体宽高的最小值; 6 painter.setViewport(x,y,side,side); 7 painter.setWindow(0,0,100,100); 8 painter.setBrush(Qt::green); 9 painter.drawRect(0,0,20,200);