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

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