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 下縮放比例 K = 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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~The End
最後更新:2017-04-02 06:51:27