閱讀453 返回首頁    go 阿裏雲 go 技術社區[雲棲]


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

  上一篇:go QT 編碼 字符集
  下一篇:go evhttp處理POST請求的技巧