从GDI到GDI+使用的坐标系看微软二维绘图思路的进步

来源:互联网 发布:php就业班 编辑:程序博客网 时间:2024/05/19 13:15

1 微软Windows绘图系统使用的三种坐标系

为了便于绘制,微软在其绘图系统中引入了三种不同的坐标系,这三种坐标系都是平面直角坐标系,下面从坐标系的三要素即度量单位、坐标原点、坐标轴方向分别对其进行说明。

1.1 设备坐标系

顾名思义,设备坐标系是依据绘图使用的硬件设备而定义的。其度量单位为像素,x轴向右为正,y轴向下为正。至于坐标原点则可以通过SetViewPortOrg()进行设定。

1.2 逻辑坐标系

这个坐标系的度量单位以及坐标轴方向可以通过SetMapMode()来设定。例如 MM_TEXT模式对应的度量单位就是像素,坐标轴方向右、下为正。而MM_LOMETRIC模式对应的度量单位就是0.1mm,坐标轴方向右、上为正。至于其原点则可以通过SetWindowOrg()来进行设定。需要注意的是,逻辑坐标系的坐标轴必须是水平和上下方向的,不能旋转。

1.3 世界坐标系

也叫做物理坐标系,或者建模坐标系,或者用户自定义坐标系。这个坐标系是有程序员自己来定义的,比如可以把原点设定为一个汽车的质心,车灯方向为x轴正向,y轴则指向天空。总之,这个坐标系是相当自由的,没有任何限制。

2 两种不同的绘制过程

无论使用何种坐标系,图形的坐标最终必须要映射到设备坐标系中进行实际的绘制。而这个映射的过程就是绘图系统的关键。

2.1 GDI的传统绘图过程

正如微软自己在MSDN中所说的那样,GDI中的大部分绘制API,如LineTo(), TextOut()中的位置参数都是逻辑坐标系中的坐标值,实际绘制时由GDI系统把逻辑坐标转化为设备坐标,然后进行实际输出。从逻辑坐标到设备坐标的转换,其思路非常简单,两个坐标系的原点必须一一对应,然后根据坐标轴方向进行简单的比例运算。
这种绘图方式是很多Windows程序员使用的方式,也是GDI默认的方式。

在这种方式下,程序员要在逻辑坐标系中进行建模,由于逻辑坐标系总是横平竖直的,而这与现实世界非常吻合,如树木、房屋,高山等,在横平竖直的坐标系中建模非常自然。然而也有很多的物体不太适合在逻辑坐标系中建模,如被风吹倒的房屋。这就需要程序员自己完成物理坐标系到逻辑坐标系的转换了。对于复杂的物体,这种横平竖直的坐标系也很不方便。

2.2 GDI高级绘图过程

我们注意到GDI中提供了一个SetGraphicsMode(),用来设置GDI的绘图模式,一共有两种模式:GM_COMPATIBLE和GM_ADVANCED。如果我们没有调用这个API,那么GDI就工作在默认的GM_COMPATIBLE模式下,也就是2.1中的传统绘图过程。然而,当我们使用这个API设定到第二种绘图模式时,整个世界就会发生变化。因为当GDI工作在GM_ADVANCED模式下时,所有的绘图API,如LineTo(),TextOut()中的位置参数不再是逻辑坐标系坐标了,而是世界坐标系坐标。这里不得不批评一下微软的MSDN,它根本没有提醒用户这种变化!

这种方式下,首先需要用户定义自己世界(建模)坐标系,然后进行建模,通常会忽略逻辑坐标到设备坐标的转化。绘制过程中,程序员提供世界坐标系到逻辑坐标系的转换逻辑,GDI据此完成世界坐标到逻辑坐标的转换。在GDI中只提供了一个API来设定世界坐标系到逻辑坐标系的映射关系,那就是SetWorldTransform(),其参数就是坐标系转换矩阵。这种转换可以是任意的缩放、旋转、平移,以及它们的任意组合。

事情看起来很好,可是GDI的API确实不太给力,毕竟对于大多数程序员来说,直接使用矩阵非常不方便。所以尽管这种模式很好,却在GDI时代没有被广泛使用。当然没被广泛采用的另外一个原因就是绘制复杂图形时,往往倾向于使用OpenGL或者DirectX而不是GDI了。

3 GDI+的时代

微软终于觉察到GDI中使用世界坐标系的不便了,于是开发出了升级版的GDI+。在GDI+中默认就工作于上面提到的GM_ADVANCED模式,最重要的是,GDI+提供了丰富的API用于构造世界坐标系到逻辑坐标系的转换矩阵。如TranslateTransform()用于平移,RotateTransform()用于旋转,ScaleTransform()用于缩放。这大大方便了广大程序员使用世界坐标系建模,也缩小了GDI+与其他先进绘图API的差距。

不过GDI+的API是针对C++的,对于传统的C语言来说不能直接使用。当然,微软也早已把GDI+封装到了FCL中,所以使用C#开发GDI+程序也非常方便。
0 0