Windows GDI中的坐标系(二)
By leezy_2000
2003-10-21 16:13
一、逻辑空间的坐标是如何转化为设备空间的坐标的?
让我们先来澄清逻辑坐标空间内部是如何转化的。
世界坐标空间到页面坐标空间的变换(二维affine(注三)变换):
此过程中涉及到的各种变换,比如:相等、平移、缩放、映像、旋转、剪切、合并等都是通过为affine矩阵的各个成员指定适当的值来实现的。
这个矩阵所对应的结构如下:
typedef struct _XFORM {
FLOAT eM11;
FLOAT eM12;
FLOAT eM21;
FLOAT eM22;
FLOAT eDx;
FLOAT eDy;
} XFORM, *PXFORM;
一个世界坐标空间的点转换为页面坐标空间的点的公式为:
xpage=xworld*eM11+yworld*eM21+eDx;
ypage=xworld*eM12+yworld*eM22+eDy;(公式一)
其中xworld、yworld为世界坐标空间的点。xpage、ypage为上述点在页面坐标空间中对应的位置。至于与affine变换的数学属性及如何才能实现页面的相等、平移、缩放、映像、旋转、剪切、合并此处不进行详细说明,因为那样将使这篇文章的规模膨胀许多(注四)。
页面坐标空间到设备坐标空间的转换:
这个过程涉及到几个概念,他们分别是:
视口原点:当前页面坐标空间所认为的设备坐标空间的原点位置。用SetViewportOrgEx、GetViewportOrgEx分别进行设置和读取。用这两个函数进行操作时,所涉及的坐标为设备空间的坐标。
视口范围: 视口范围并不是一个绝对的用于表示设备坐标空间大小的值。而是一个相对值,它同窗口范围的比例最终决定页面坐标空间到设备坐标空间是一种缩小还是放大的转换。用SetViewportExtEx、GetViewportExtEx对视口范围进行存取。
窗口原点:页面坐标空间的原点。用SetWindowOrgEx、GetWindowOrgEx对窗口原点进行存取,所涉及的坐标为逻辑坐标。
窗口范围:见视口范围的说明。用SetWindowExtEx、GetWindowExtEx进行存取。
由了两个坐标空间的原点值和范围的比例值,在这两个坐标空间间进行坐标转换也就不是什么太难的事了。比较容易的可以得出下面的公式:
页面坐标空间到设备坐标空间:
xdevice=(xpage-WOrgx)*VExtx /WExtx+VOrgx;
ydevice=(ypage-WOrgy)*VExty /WExty+VOrgy;(公式二)
其中(WOrgx,WOrgy)为窗口原点。(VOrgx VOrgy,)为视口原点。(WExtx, WExty)为窗口范围。(VExtx,VExty)为视口范围。
设备坐标空间到页面坐标空间的转换大家可以自己推导。
为了更好的理解坐标空间的转换,我们将利用上述两组公式,动手来实现自己的LPtoDP。我们的这个函数将只适合nt类的平台。(9x没有世界坐标空间,会更简单)具体实现见源码2。实现MyLPtoDP的过程比较简单,此处仅对要用到的几个主要函数做些说明。
int GetGraphicsMode(
HDC hdc // handle to device context
);
这个函数用来得到指定DC的图形模式。图形模式有两种GM_COMPATIBLE和GM_ADVANCED
只有在GM_ADVANCED才可能使用世界坐标空间。可以用SetGraphicsMode在两者间切换。
BOOL GetWorldTransform(
HDC hdc, // handle to device context
LPXFORM lpXform // transformation
);
此函数用来得到与当前DC相关联的affine矩阵。通过公式一,
应该可以知道缺省的affine矩阵具有{1.0,0,0,1.0,0,0}的形式。
MyLPtoDP虽然有返回值但此值无意义,并且实现过程中也并没有进行任何出错处理。
见源码2。
二、关于GDI+的补充说明
就各种坐标空间而言GDI+的更新更多的体现在操作方式上而非在本质上。理解了上述概念再看GDI+的坐标空间,会有一种一目了然感觉。而本文更侧重于概念的树立,因此就不单独再对GDI+进行特别说明了。
注一:这里仅是一种可能的情形,具体的转换后数值要由当前的坐标空间来具体确定。
注二:我个人认为GDI的坐标空间其实就是坐标系,但由于对应英文术语为Coordinate Space,并且大多书籍译为坐标空间,所以此处亦如是。
注三:大家都知道通过乘上一个2x2的矩阵可以完成诸如缩放、旋转、镜像等操作。
如下图:
如上这几种变换被称作linear transformations。但通过乘上2x2的矩阵你无法完成平移一类的操作。为达到平移的目的就还需要加上一组偏移量(分别对应于x轴和y轴)。一个2x2矩阵和一组偏移量就构成了Affine矩阵。
注四:请参考Feng Yuan的《windows 图形编程》