设置坐标映射
(1 ) Windows 坐标系统
Windows 坐标系 分为逻辑坐标系和设备坐标系两种, GDI 支持这两种坐标系。一般而言,
GDI 的文本和图形输出函数使用逻辑坐标,而在客户区移动或按下鼠标的鼠标位置是采用设备坐标。
<1> 逻辑坐标系 是面向 DC 的坐标系,这种坐标不考虑具体的设备类型,在绘图时, Windows 会根据当前设置的映射模式将逻辑坐标转换为设备坐标。
<2> 设备坐标系 是面向物理设备的坐标系,这种坐标以像素或设备所能表示的最小长度单位为单位, X 轴方向向右, Y 轴方向向下。设备坐标系的原点位置 (0, 0) 不限定在设备显示区域的左上角。
设备坐标系 分为屏幕坐标系、窗口坐标系和客户区坐标系三种相互独立的坐标系。
l 屏幕坐标系 以屏幕左上角为原点,一些与整个屏幕有关的函数均采用屏幕坐标,如 GetCursorPos() 、 SetCursorPos() 、 CreateWindow() 、 MoveWindow() 。弹出式菜单使用的也是屏幕坐标。
l 窗口坐标系 以窗口左上角为坐标原点,它包括窗口标题栏、菜单栏和工具栏等范围。
l 客户区坐标系 以窗口客户区左上角为原点,主要用于客户区的绘图输出和窗口消息的处理。鼠标消息的坐标参数使用客户区坐标, CDC 类绘图成员函数使用与客户区坐标对应的逻辑坐标。
( 2 )坐标之间的相互转换
l 编程时,有时需要根据当前的具体情况进行三种设备坐标之间或与逻辑坐标的相互转换。
l MFC 提供了两个函数 CDC::DPtoLP() 和 CDC:: LPtoDP() 用于设备坐标与逻辑坐标之间的相互转换。
l MFC 提供了两个函数 CWnd::ScreenToClient() 和 CWnd::ClientToScreen() 用于屏幕坐标与客户区坐标的相互转换。
( 3 )映射模式
l 映射模式确定了在绘制图形时所依据的坐标系,它定义了逻辑单位的实际大小、坐标增长方向,所有映射模式的坐标原点均在设备输出区域(如客户区或打印区)的左上角。此外,对于某些映射模式,用户还可以自定义窗口的长度和宽度,设置视图区的物理范围。
l Windows 定义了 8 种映射模式,见下表。
l 映射模式使得程序员可不必考虑输出设备的具体设备坐标系,而在一个统一的逻辑坐标系中进行图形的绘制。
映射方法( Mapping Mode ) | 逻辑单位 | 坐标轴方向 |
MM_TEXT (默认方式) | 1 pixel | X 轴正方向朝右, Y 轴正方向朝下 |
MM_LOMETRIC | 0.1 mm | X 轴正方向朝右, Y 轴正方向朝上 |
MM_HIMETRIC | 0.01 mm | X 轴正方向朝右, Y 轴正方向朝上 |
MM_LOENGLISH | 0.01 inch | X 轴正方向朝右, Y 轴正方向朝上 |
MM_HIENGLISH | 0.001 inch | X 轴正方向朝右, Y 轴正方向朝上 |
MM_TWIPS | 1/1440 inch | X 轴正方向朝右, Y 轴正方向朝上 |
MM_ISOTROPIC | 自定义 (X=Y) | 自定义 |
MM_ANISOTROPIC | 自定义 (X!=Y) | 自定义 |
当绘制的图形需要随着窗口的大小改变而自动改变的时候,一般选择 MM_ISOTROPIC 和 MM_ANISOTROPIC 映射方式。它们的唯一区别就是前者的 X 轴和 Y 轴的逻辑单位的大小是相同的,单词“ isotropic ”就是各个方向相等的意思,此映射方式适合绘制圆或正方形。而实际应用中,常常给 X 轴和 Y 轴取不同的比例,这时候选择 MM_ANISOTROPIC 映射方式。单词“ anisotropic ”就是各个方向相异的意思。
(4)自定义映射模式
“窗口”和“视口”的概念:
窗口( Window ): 对应逻辑坐标系上程序员设定的区域
视口( Viewport ): 对应实际输出设备上程序员设定的区域
l 窗口原点是指逻辑窗口坐标系的原点在视口(设备)坐标系中的位置,视口原点是指设备实际输出区域的原点。
l 除了映射模式,窗口和视口也是决定一个点的逻辑坐标如何转换为设备坐标的一个因素。一个点的逻辑坐标按照如下式子转换为设备坐标:
设备(视口)坐标 = 逻辑坐标 – 窗口原点坐标 + 视口原点坐标
// 定义坐标映射方式
WINGDIAPI int WINAPI SetMapMode (HDC, int );
此 API 函数在 MFC 中封装为 CDC::virtual int SetMapMode (int nMapMode);
// 定义逻辑窗口区域,单位为逻辑单位( Logical )
WINGDIAPI BOOL WINAPI SetWindowExtEx (HDC, int , int , LPSIZE);
此 API 函数在 MFC 中封装为 CDC::virtual CSize SetWindowExt (int cx, int cy);
// 设置逻辑窗口的原点坐标,缺省原点为( 0 , 0 )。
WINGDIAPI BOOL WINAPI SetWindowOrgEx (HDC, int , int , LPPOINT);
此 API 函数在 MFC 中封装为 CDC::CPoint SetWindowOrg (int x, int y);
注意: Set WindowOrg (Ex) 只有在映射模式为 MM_ANISOTROPIC 或 MM_ISOTROPIC 时才有意义。
// 定义视口的坐标轴方向及区域、定义域和值域,单位为像素( Pixel )
WINGDIAPI BOOL WINAPI SetViewportExtEx (HDC, int , int , LPSIZE);
此 API 函数在 MFC 中封装为 CDC::virtual CSize SetViewportExt (int cx, int cy);
注意: SetViewportExt(Ex) 只有在映射模式为 MM_ANISOTROPIC 或 MM_ISOTROPIC 时才有意义。
// 设置视口的原点坐标,缺省原点为( 0 , 0 )。
WINGDIAPI BOOL WINAPI SetViewportOrgEx (HDC, int , int , LPPOINT);
此 API 函数在 MFC 中封装为 CDC:: virtual CPoint SetViewportOrg (int x, int y);
参考:《 GDI 中的坐标映射问题》 http://dev.youkuaiyun.com/article/12/12013.shtm