一、GDI+坐標系
GDI+坐標系有三個:World(世界坐標系)、Page(邏輯/頁面坐標系)、Device(設備坐標系)
下面的代碼將在設備上畫一條線:
MoveToEx(hdc,xw1,yw1,NULL);
LineTo(hdc,xw2,yw2,NULL);
(xw1,yw1) 和(xw2,yw2)是世界坐標系中的兩個點,Windows 首先將其轉換為邏輯坐標,然後再轉換為設備坐標,最後畫出一條直線段。
二、世界坐標轉換為邏輯坐標
在Win98下,世界坐標系與邏輯坐標系是重合的,沒有什麼分別。在WinNT下,世界坐標系與邏輯坐標系默認也是重合的,要將世界坐標系與邏輯坐標系分別開來,首先需要SetGraphicsMode(hdc,GM_ADVANCED),然後調用SetWorldTransform設定世界坐標系與邏輯坐標系之間的轉換關係。
SetWorldTransform的原型如下:
BOOL SetWorldTransform(HDC hdc,CONST XFORM *lpXform);
描述轉換關係的結構XFORM,其定義如下:
typedef struct _XFORM
{
FLOAT eM11;
FLOAT eM12;
FLOAT em21;
FLOAT eM22;
FLOAT eDx;
FLOAT eDy;
}XFORM;
各個參數就是變換矩陣中的元素:
(1)
其中,是邏輯坐標,是世界坐標
(1)式展開可得
(2)
設定轉換關係後,可以對轉換關係進行修改:
BOOL ModifyWorldTransform(HDC hdc,CONST XFORM *lpXform,DWORD iMode);
iMode 為 MWT_IDENTITY 表示世界坐標系與邏輯坐標系重合,此時lpXform無用;
iMode 為 MWT_LEFTMULTIPLY 表示增加lpXform變換,
新變換矩陣 = lpXform ×老變換矩陣
iMode 為 MWT_RIGHTMULTIPLY 表示增加lpXform變換,
新變換矩陣 =老變換矩陣×lpXform
還可以對變換進行合併:
BOOL CombineTransform(LPXFORM lpxformResult
,CONST XFORM *lpxform1,CONST XFORM *lpxform2);
lpxformResult = lpxform1×lpxform2
三、邏輯坐標與設備坐標的相互轉換
1、對於 MM_TEXT 而言,邏輯坐標系與設備坐標系僅有平移關係。
假定有一個點在邏輯坐標系下的坐標為,在設備坐標系下的坐標為,則轉換關係為:
代碼里應設定轉換關係:
SetWindowOrgEx(HDC hdc,xL0,yL0,NULL);
SetViewportOrgEx(HDC hdc,xD0,yD0,NULL);
2、對於MM_HIENGLISH、MM_HIMETRIC、MM_LOENGLISH、MM_LOMETRIC、MM_TWIPS而言,邏輯坐標系與設備坐標系有平移、縮放關係。
假定有一個點在邏輯坐標系下的坐標為,在設備坐標系下的坐標為,則轉換關係為:
代碼里應設定轉換關係:
SetWindowOrgEx(HDC hdc,xL0,yL0,NULL);
SetViewportOrgEx(HDC hdc,xD0,yD0,NULL);
表示橫向每毫米的像素數:
表示縱向每毫米的像素數:
Unit的取值因MM_HIENGLISH、MM_HIMETRIC、MM_LOENGLISH、MM_LOMETRIC、MM_TWIPS而異,詳見下表:
3、對於MM_ANISOTROPIC和MM_ISOTROPIC而言
假定:一段平行於x軸的直線段在邏輯坐標系下的長度為LenXL,在設備坐標系下的長度為LenXD;一段平行於y軸的直線段在邏輯坐標系下的長度為LenYL,在設備坐標系下的長度為LenYD;某一點在邏輯坐標系下的坐標為,在設備坐標系下的坐標為,則轉換關係如下:
代碼里應設定轉換關係:
SetWindowExtEx(HDC hdc,LenXL,LenYL,NULL);
SetViewportExtEx(HDC hdc,LenXD,LenYD,NULL);
SetWindowOrgEx(HDC hdc,xL0,yL0,NULL);
SetViewportOrgEx(HDC hdc,xD0,yD0,NULL);
注意:LenYL 與LenYD異號,則邏輯y軸與設備y軸方向將相反;LenXL 與LenXD異號,則邏輯x軸與設備x軸方向將相反。
這裡要特彆強調MM_ISOTROPIC,它的意思是各向同性,即:X、Y軸的比例相同。此時,必須先調用SetWindowExtEx,然後再調用SetViewportExtEx。因為調用後者時Windows會根據前者的設定值修改LenXD或LenYD,使得X、Y軸的比例相同。具體修改如下:
取和的最小值minScale,修改LenXD、LenYD如下:
此時,
這樣,既保證了比例尺相同,又能最大限度的顯示視窗(邏輯坐標系下的一個矩形)內容。
四、文字顯示
請看下面的代碼
void GDITest(HWND hwnd)
{
HDC hDC = GetDC(hwnd);
TCHAR* szStr = _T("GDI測試");
RECT rect;
LOGFONT logFont;
SetGraphicsMode(hDC,GM_ADVANCED); //(3)
SetMapMode(hDC, MM_ISOTROPIC);
SetWindowExtEx(hDC,5000, ±5000,NULL); //(4)
GetClientRect(hwnd,&rect);
SetViewportExtEx(hDC,rect.right,rect.bottom,NULL);
SetViewportOrgEx(hDC,rect.right >> 1,rect.bottom >> 1,NULL);
ZeroMemory(&logFont,sizeof(logFont));
logFont.lfCharSet = GB2312_CHARSET;
logFont.lfHeight = -1000;
lstrcpy(logFont.lfFaceName,_T("宋體"));
HFONT hFont = CreateFontIndirect(&logFont);
SelectObject(hDC,hFont);
TextOut(hDC,0,0,szStr,lstrlen(szStr));
DeleteObject(SelectObject(hDC,GetStockObject(SYSTEM_FONT)));
ReleaseDC(hwnd,hDC);
}
(4)中的±對輸出是有影響的,見下圖。亦即:當邏輯坐標系y軸與設備坐標系y軸方向相反時,會導致字型輸出的上下顛倒。
將(3)改為SetGraphicsMode(hDC,GM_COMPATIBLE);則±對輸出毫無影響。這些說明:
1、對於SetGraphicsMode(hDC,GM_COMPATIBLE)而言,Windows 僅將文字高度和文字參考點(reference point——輸出文字時的基準點)轉換到設備坐標系,然後在設備坐標系下進行文本輸出;
2、對於SetGraphicsMode(hDC,GM_ADVANCED)而言,對文本的處理就比較麻煩了:我猜測是將所有文本的輪廓點從世界坐標系轉換至設備坐標系,然後再內部填充處理。這樣的轉換更加徹底、完美!
五、套用實例
下面的代碼將在視窗客戶區畫一個傾斜橢圓
#include <MATH.H>
/*****************************************************************************\
在視窗的客戶區畫傾斜橢圓,橢圓中心在客戶區中心
hwnd [in] 視窗句柄
rotDeg [in] 旋轉角,逆時針旋轉為正,單位:度
a [in] 長半軸,單位:0.1mm
b [in] 短半軸,單位:0.1mm
\*****************************************************************************/
void DrawRotateEllipse(HWND hwnd,float rotDeg,int a,int b)
{
HDC hDC = GetDC(hwnd);
XFORM xForm;
//角度轉換為弧度
rotDeg *= 0.017453292519943295769236907684886f;
{//設定世界坐標系與邏輯坐標系的轉換關係
SetGraphicsMode(hDC, GM_ADVANCED);
xForm.eM11 =
xForm.eM22 = (FLOAT) cos(rotDeg);
xForm.eM12 = (FLOAT) sin(rotDeg);
xForm.eM21 = -xForm.eM12;
xForm.eDx =
xForm.eDy = 0.0f;
SetWorldTransform(hDC, &xForm);
}
SetMapMode(hDC, MM_LOMETRIC);
{//設定視口原點
RECT rect;
GetClientRect(hwnd,&rect);
SetViewportOrgEx(hDC,rect.right >> 1,rect.bottom >> 1,NULL);
}
//畫8cm*4cm的橢圓
#if 0
//橢圓中心邏輯坐標為(0,0)
Ellipse(hDC,-a,b,a,-b);
#else
//橢圓中心坐標為:世界坐標——(400,0) 邏輯坐標——(283,283)
SetWindowOrgEx(hDC,(int)(xForm.eM11 * a),(int)(xForm.eM12 * a),NULL);
Ellipse(hDC,0,b,2 * a,-b);
#endif
ReleaseDC(hwnd,hDC);
}
畫橢圓的時候有兩種方法:
1、世界坐標系下,橢圓中心坐標為(0,0),長軸在 X 軸上,短軸在 Y 軸上。此時,邏輯坐標系下,橢圓中心坐標也為(0,0)。所以只要一行代碼即可:
Ellipse(hDC,-a,b,a,-b);
2、世界坐標系下,橢圓中心坐標為(a,0),長軸在 X 軸上,短軸在 Y 軸上。此時,邏輯坐標系下,橢圓中心坐標為(,)。所以需要兩行代碼:
SetWindowOrgEx(hDC,(int)(xForm.eM11 * a),(int)(xForm.eM12 * a),NULL);
Ellipse(hDC,0,b,2 * a,-b);
這說明:SetWindowOrgEx中的坐標是邏輯坐標,而不是世界坐標。
實際運行結果:在Win98下,無法旋轉;在WinXP下,可以旋轉,見下圖。
上一篇:
道路斷鏈
下一篇:
VC編譯初步
相關詞條
-
GDI原理
GDI原理是Windows 98和Microsoft WindowsNT中的圖形主要由GDI32.DLL動態連結程式庫輸出的函式來處理,主要目的之一是支...
介紹 說明 -
GDI+坐標系
Lin 在Win SetWorldTran
-
坐標空間
:世界坐標系空間、頁面空間、設備空間、和物理設備空間。應用程式運用世界坐標系空間對圖形輸出進行旋轉、斜切或者反射。Win32 API把世界坐標系...SetWorldTransform函式,那么映射就從應用程式的世界坐標系空間開始...
簡介 VC中的坐標空間 -
SetWindowOrg
對象。說明視窗初始位置表明在設備坐標系統中的點,GDI將視圖連線埠初始位置...中指定的。GDI在映射其它點時遵從同樣的過程,這需要視窗初始位置與視圖...(0,0),設備的坐標系永遠不會變,變的是邏輯原點在設備坐標系中的位置和邏輯...
基本信息 說明 -
圖形加速器
的一些關鍵的GID功能使用硬連線的辦法.(GDI是Windows 實現必要...的應用程式送給圖形設備接口 (GDI)—個圖形功能調用請求,GDI就要求...對圖元的描述(往往是命令、函式和描述屬性的參數),執行坐標系的變換...
發展情況 結構 功能 加速原理 優點 -
嵌入式GUI開發設計——基於MiniGUI
滑鼠編程要點總結 第10章 MiniGUI的GDI編程... 10.1.2 MiniGUI中的GDI概念 10.2... 10.3.4 坐標系的偏移和縮放 10.4 顏色與調色板 10.4.1...
-
算機圖形學基礎教程
結構和GDI對象......................................................... ...
版權資訊 內容簡介 目錄 -
PostScript語言
歷史PostScript語言的思想起源於John Warnock1976年在著名的計算機圖形公司Evans and Suther...
歷史 列印套用 系統套用 程式語言 -
VisualC++MFC棋牌類遊戲編程實例
《VisualC++MFC棋牌類遊戲編程實例》由葛垚等所著,本書介紹了如何使用VisualC++來設計各種棋牌類遊戲,主要針對想學習遊戲設計的初學者。本...
版權資訊 內容簡介 目錄 -
SetViewportOrgEx
詞語釋義 SetViewportOrgEx說明哪個設備點映射到視窗原點(0,0)BOOL SetViewportOrgEx(...
詞語釋義 參數介紹