Windows 映射模式

一、 映射模式

 

 

这是一个初级话题,但好像很多人都没有弄明白,因为几乎每过几天就用人发帖问这个。半年前有人问我这个问题时就想写这篇文章了,但一直觉得没有时间(因为除了学习、工作和玩耍,几乎就没有多少空时间了)。本文现在其实只能算着《 Programming Windows 》中关于“映射模式”的加工,以咱们中国读者更易懂的方式写出;我将逐步往其中添加一些相关内容。 

 

首先,从一个十分简单但又很常用的函数开始: 

BOOL TextOut( HDC hdc , // handle to DC

int nXStart , // x-coordinate of starting position 

int nYStart , // y-coordinate of starting position 

LPCTSTR lpString , // character string 

int cbString // number of characters ); 

这里的( nXstart , nYStart )是字符串显示的起始座标点,这里的座标就是“逻辑座标”。为了最终将文字显示到设备(屏幕)上, Windows 必须将这些逻辑座标“翻译”成“设备座标” —— 其实就是“像素 (pixels) ”。 Windows 一共定义了 8 种映射模式,如下表所示: 

 

-----------------------------------------------------------------------------------

                                                                      Increasing Value 

Mapping Mode            Logical Unit           x-axis            y-axis 

 

MM_TEXT                       Pixel                      Right             Down 

MM_LOMETRIC            0.1 mm                  Right             Up 

MM_HIMETRIC              0.01 mm               Right             Up 

MM_LOENGLISH          0.01 in.                  Right             Up 

MM_HIENGLISH            0.001 in.               Right             Up 

MM_TWIPS                     1/1440 in.             Right             Up 

MM_ISOTROPIC           Arbitrary (x = y)     Selectable   Selectable 

MM_ANISOTROPIC      Arbitrary (x !=y)     Selectable   Selectable 

--------------------------------------------------------------------------------------

表 1 

 

注: in. 表 英寸 ; Windows 默认的映射模式是 MM_TEXT ,其实就是 设备座标 !!! 

 

趁热打铁,看一下例子:

 

例: 如果我们没有用 SetMapMode 设定 Windows 的映射模式,那么 Windows 将使用默认的 MM_TEXT 映射模式, 

 

TextOut (hdc, 8, 16, TEXT ("Hello"), 5); 

 

的结果是文字将从离客户区左边界 8 个像素、离上边界 16 个像素的位置从左向右输出文字。 

 

而 

 

SetMapMode (hdc, MM_LOENGLISH); 

 

TextOut (hdc, 50, -100, TEXT ("Hello"), 5); 

 

的结果将是 从离客户区左边界 50* 0.01 in .= 0.5 in . 、离上边界 100*0.01 = 1 in . 的位置从左向右输出文字。

 

但 TextOut 的第 3 个参数为什么是 -100 呢?因为客户区左上角的座标的默认值始终是 (0,0) 的(后面将详细讲到),而上面的列表不是写了吗 ? 在 MM_LOENGLISH 下, Y 轴值递增的方向是向上,也就是说向下递减,当然此时第 3 个参数为负值了。 

 

Windows 设定这些映射模式是为了让用户使用起来更方便,因此你选定合适的映射模式来简化你的工作;或者选用 MM_ISOTROPIC 、 MM_ANISOTROPIC 自己设定逻辑座标的单位,数值递增方向;或者干脆就用 MM_TEXT (相当于直接使用设备座标),需要缩放时用 GetDeviceCap 获得必要的信息后 自己去计算得了。 

 

二、座标原点 

 

常看到网友问 CDC::SetWindowOrg 和 CDC:: SetViewportOrg 的用法,它们实质是封装了 GDI 函数 SetWindowOrgEx 和 SetViewportOrgEx : 

 

而 CSDN 的解释是: 

 

The SetWindowOrgEx function specifies which window point maps to the viewport origin (0,0). The SetViewportOrgEx function specifies which device point maps to the window origin (0,0). 

 

初学者往往一头雾水。 

 

其实“映射模式”中的“映射”就是数学中的“映射”,一种对应关系或者说是一个数学表达式而已。这个表达式就是: 

 

公式一: 

xViewport = (xWindow - xWinOrg) × Kx + xViewOrg 

yViewport = (yWindow - yWinOrg)  × Ky + yViewOrg 

 

等价公式二: 

 

xWindow = (xViewport - xViewOrg) /Kx + xWinOrg 

yWindow = (yViewport - yViewOrg) /Ky + yWinOrg 

 

其中( xWinOrg,yWinOrg ),( xViewOrg,yViewOrg )分别表示逻辑座标和设备座标的原点,默认值均为( 0,0 ); 

 

( xWindow,yWindow )表示逻辑座标点,( xViewport,yViewport )表示与之对应的设备座标点(也就是说,在当前的映射模式下, Windows 将( xWindow,yWindow )影射为( xViewport,yViewport )。); 

 

常数 Kx,Ky 是缩放系数(后面将详细介绍),不同的映射模式下缩放系数不同。 

 

因此,在默认的情况下,( xWinOrg,yWinOrg ) = ( xViewOrg,yViewOrg ) = ( 0,0 ),公式一其实就是: 

 

xViewport = xWindow / Kx          yViewport = yWindow / Ky 。 

 

因此,可以看出,映射模式其实就是设定了一个比例而已,没有什么了不起的! 

 

例: 

 

SetMapMode(hdc,MM_TEXT); // 在 MM_TEXT 下缩放比例 Kx = Ky = 1; 

 

SetWindowOrgEx (hdc,100,100,NULL); // 此时( xWinOrg,yWinOrg )被赋值为( 100 , 100 ); 

 

                                                              // 而 ( xViewOrg,yViewOrg )保持不变为( 0 , 0 )。 

 

那么公式一即为: 

 

xViewport = xWindow -100       yViewport = yWindow -100 

 

因此 

 

TextOut (hdc, 520, 530, TEXT ("ILoveYou,MyGirl"), 15); 

                                                                            // ( xWindow,yWindow ) = ( 520 , 530 ) 

 

将会从( 520 , 530 ) - ( 100 , 100 ) = ( 220 , 230 )点开始在设备上显示。 

 

而 SetViewportOrgEx 是用来设定( xViewOrg,yViewOrg )的值的,使用方法与 SetWindowOrgEx 的使用类似。从公式一可以看出,在 MM_TEXT 中, 

 

SetWindowOrgEx (hdc, x, y , NULL) ; 

 

与 

 

SetViewportOrgEx (hdc, - x, - y, NULL); 

 

等价的。

 

三、缩放系数 

 

缩放系数 

Kx = xViewExt / xWinExt 

Ky = yViewExt / yWinExt 

 

(xViewExt,yViewExt)和(xWinExt,yWinExt)可分别由 GetViewportExt 和 GetWindowExtEx 得到。

 

在 MM_TEXT 下, Kx = Ky = 1 ;其它映射模式下Kx、Ky均为常数,它们可以由下表来计算(Window NT,显示设备:1024x768 pixels): 

--------------------------------------------------------------------------------------

Mapping Mode     Viewport Extents (x, y)      Window Extents (x, y) 

 

MM_LOMETRIC      (1024, -768)                    (3200, 2400) 

MM_HIMETRIC       (1024, -768)                    (32000, 24000) 

MM_LOENGLISH   (1024, -768)                    (1260, 945) 

MM_HIENGLISH     (1024, -768)                   (12598, 9449) 

MM_TWIPS              (1024, -768)                    (18142, 13606) 

------------------------------------------------------------------------------------

 

表 2 Windows NT Extents (1024 x 768)

 

 

参考文献: 

 

   MSDN by Microsoft 

 

《 Visual C++ 技术内幕》 by David J. Kruglinski et al 

 

《 Programming Windows 》 5 th Edition ,by Petzoldi

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章