Windows GDI中的座標系(二)
By leezy_2000
2003-10-21 16:13
一、邏輯空間的座標是如何轉化為裝置空間的座標的?
讓我們先來澄清邏輯座標空間內部是如何轉化的。
全局座標空間到頁面座標空間的變換(二維affine(注三)變換):
此過程中涉及到的各種變換,比如:相等、平移、縮放、映像、旋轉、剪下、合并等都是通過為affine矩陣的各個成員指定適當的值來實現的。
這個矩陣所對應的結構如下:
typedef struct _XFORM {
FLOAT eM11;
FLOAT eM12;
FLOAT eM21;
FLOAT eM22;
FLOAT eDx;
FLOAT eDy;
} XFORM, *PXFORM;
一個全局座標空間的點轉換為頁面座標空間的點的公式為:
xpage=xworld*eM11+yworld*eM21+eDx;
ypage=xworld*eM12+yworld*eM22+eDy;(公式一)
其中xworld、yworld為全局座標空間的點。xpage、ypage為上述點在頁面座標空間中對應的位置。至於與affine變換的數學屬性及如何才能實現頁面的相等、平移、縮放、映像、旋轉、剪下、合并此處不進行詳細說明,因為那樣將使這篇文章的規模膨脹許多(注四)。
頁面座標空間到裝置座標空間的轉換:
這個過程涉及到幾個概念,他們分別是:
視口原點:當前頁面座標空間所認為的裝置座標空間的原點位置。用SetViewportOrgEx、GetViewportOrgEx分別進行設定和讀取。用這兩個函數進行操作時,所涉及的座標為裝置空間的座標。
視口範圍: 視口範圍並不是一個絕對的用於表示裝置座標空間大小的值。而是一個相對值,它同視窗範圍的比例最終決定頁面座標空間到裝置座標空間是一種縮小還是放大的轉換。用SetViewportExtEx、GetViewportExtEx對視口範圍進行存取。
視窗原點:頁面座標空間的原點。用SetWindowOrgEx、GetWindowOrgEx對視窗原點進行存取,所涉及的座標為邏輯座標。
視窗範圍:見視口範圍的說明。用SetWindowExtEx、GetWindowExtEx進行存取。
由了兩個座標空間的原點值和範圍的比例值,在這兩個座標空間間進行座標轉換也就不是什麼太難的事了。比較容易的可以得出下面的公式:
頁面座標空間到裝置座標空間:
xdevice=(xpage-WOrgx)*VExtx /WExtx+VOrgx;
ydevice=(ypage-WOrgy)*VExty /WExty+VOrgy;(公式二)
其中(WOrgx,WOrgy)為視窗原點。(VOrgx VOrgy,)為視口原點。(WExtx, WExty)為視窗範圍。(VExtx,VExty)為視口範圍。
裝置座標空間到頁面座標空間的轉換大家可以自己推導。
為了更好的理解座標空間的轉換,我們將利用上述兩組公式,動手來實現自己的LPtoDP。我們的這個函數將只適合nt類的平台。(9x沒有全局座標空間,會更簡單)具體實現見源碼2。實現MyLPtoDP的過程比較簡單,此處僅對要用到的幾個主要函數做些說明。
int GetGraphicsMode(
HDC hdc // handle to device context
);
這個函數用來得到指定DC的圖形模式。圖形模式有兩種GM_COMPATIBLE和GM_ADVANCED
只有在GM_ADVANCED才可能使用全局座標空間。可以用SetGraphicsMode在兩者間切換。
BOOL GetWorldTransform(
HDC hdc, // handle to device context
LPXFORM lpXform // transformation
);
此函數用來得到與當前DC相關聯的affine矩陣。通過公式一,
應該可以知道預設的affine矩陣具有{1.0,0,0,1.0,0,0}的形式。
MyLPtoDP雖然有傳回值但此值無意義,並且實現過程中也並沒有進行任何出錯處理。
見源碼2。
二、關於GDI+的補充說明
就各種座標空間而言GDI+的更新更多的體現在操作方式上而非在本質上。理解了上述概念再看GDI+的座標空間,會有一種一目瞭然感覺。而本文更側重於概念的樹立,因此就不單獨再對GDI+進行特別說明了。
注一:這裡僅是一種可能的情形,具體的轉換後數值要由當前的座標空間來具體確定。
注二:我個人認為GDI的座標空間其實就是座標系,但由於對應英文術語為Coordinate Space,並且大多書籍譯為座標空間,所以此處亦如是。
注三:大家都知道通過乘上一個2x2的矩陣可以完成諸如縮放、旋轉、鏡像等操作。
如:
如上這幾種變換被稱作linear transformations。但通過乘上2x2的矩陣你無法完成平移一類的操作。為達到平移的目的就還需要加上一組位移量(分別對應於x軸和y軸)。一個2x2矩陣和一組位移量就構成了Affine矩陣。
注四:請參考Feng Yuan的《windows 圖形編程》