首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

GDI 座標空間轉換:World Space 到 Page Space 矩陣變換完整指南

     編輯:關於VC++

前言:四大座標空間

Windows GDI 繪圖涉及四個座標空間,繪圖指令經由層層轉換最終映射至實體裝置:

  1. 世界座標空間:應用程式邏輯座標,單位可為任意度量(公尺、英寸、像素)。
  2. 頁面座標空間:經世界轉換後的座標,仍為邏輯單位,供後續頁面/裝置轉換使用。
  3. 裝置座標空間:對應實體裝置(螢幕、印表機)的像素座標。
  4. 實體裝置座標空間:硬體層面的最終座標。

座標空間轉換流程圖

預設 GDI 模式下 無世界座標到頁面座標轉換,僅當呼叫 SetGraphicsMode(hdc, GM_ADVANCED) 並設定 SetWorldTransform 時才啟用。

核心結構與 API

XFORM 結構 — 3×3 齊次變換矩陣

typedef struct _XFORM {
    FLOAT eM11, eM12;  // 縮放、旋轉、剪切分量
    FLOAT eM21, eM22;
    FLOAT eDx,  eDy;   // 平移分量
} XFORM, *PXFORM;

關鍵 API

API用途
SetGraphicsMode(hdc, GM_ADVANCED)啟用進階圖形模式,允許世界轉換
SetWorldTransform(hdc, &xform)設定世界轉換矩陣
CombineTransform(&result, &x1, &x2)合併兩個轉換(矩陣相乘)
GetWorldTransform(hdc, &xform)取得目前世界轉換矩陣

變換數學原理

世界座標 (x, y) 經矩陣 XFORM 轉換為頁面座標 (x'', y''):

| x'' y'' 1 |   | x  y  1 |   | eM11 eM12  0  |
|           | = |       | * | eM21 eM22  0  |
|           |   |       |   | eDx  eDy   1  |

展開公式:

x'' = x * eM11 + y * eM21 + eDx
y'' = x * eM12 + y * eM22 + eDy

常見變換矩陣構造

變換類型矩陣參數 (eM11, eM12, eM21, eM22, eDx, eDy)
縮放(sx, 0, 0, sy, 0, 0)
平移(1, 0, 0, 1, tx, ty)
旋轉 (角度 θ)(cosθ, sinθ, -sinθ, cosθ, 0, 0)
X 軸剪切(1, k, 0, 1, 0, 0)
Y 軸剪切(1, 0, k, 1, 0, 0)
X 軸鏡像(-1, 0, 0, 1, 0, 0)
Y 軸鏡像(1, 0, 0, -1, 0, 0)

完整範例:互動式變換展示

變換效果示意圖

void TransformAndDraw(int iTransform, HWND hWnd)
{
    HDC hDC = ::GetDC(hWnd);
    RECT rect; ::GetClientRect(hWnd, &rect);

    // 畫座標軸參考線
    ::MoveToEx(hDC, rect.right/2, 0, NULL);  ::LineTo(hDC, rect.right/2, rect.bottom);
    ::MoveToEx(hDC, 0, rect.bottom/2, NULL); ::LineTo(hDC, rect.right, rect.bottom/2);

    ::SetGraphicsMode(hDC, GM_ADVANCED);
    XFORM xForm = {0};

    switch (iTransform)
    {
    case 0: // 原始
        break;
    case 1: // 縮放 1/2
        xForm.eM11 = 0.5f; xForm.eM22 = 0.5f; break;
    case 2: // 平移
        xForm.eM11 = 1.0f; xForm.eM22 = 1.0f; xForm.eDx = 75.0f; break;
    case 3: // 逆時針旋轉 30°
        xForm.eM11 =  0.8660f; xForm.eM12 =  0.5000f;
        xForm.eM21 = -0.5000f; xForm.eM22 =  0.8660f; break;
    case 4: // X 剪切
        xForm.eM11 = 1.0f; xForm.eM12 = 1.0f; xForm.eM22 = 1.0f; break;
    case 5: // 水平鏡像
        xForm.eM11 =  1.0f; xForm.eM22 = -1.0f; break;
    case 6: // 垂直鏡像
        xForm.eM11 = -1.0f; xForm.eM22 =  1.0f; break;
    }
    ::SetWorldTransform(hDC, &xForm);

    // 將邏輯座標轉裝置座標以便 BitBlt 定位
    ::DPtoLP(hDC, (LPPOINT)&rect, 2);

    // 繪製位圖於中心
    HBITMAP hBMP = ::LoadBitmap(AfxGetResourceHandle(), MAKEINTRESOURCE(IDB_BITMAP1));
    HDC hMemDC = ::CreateCompatibleDC(hDC);
    HBITMAP hOld = (HBITMAP)::SelectObject(hMemDC, hBMP);
    ::BitBlt(hDC, rect.right/2 - 40, rect.bottom/2 - 40, 80, 80, hMemDC, 0, 0, SRCCOPY);
    ::SelectObject(hMemDC, hOld);
    ::DeleteObject(hBMP); ::DeleteDC(hMemDC); ::ReleaseDC(hWnd, hDC);
}

進階應用提示

  • 組合變換:呼叫 CombineTransform 疊加多個效果(如先旋轉再平移),注意矩陣乘法順序影響結果。
  • 座標系統差異:GDI 預設 Y 軸向下,數學慣例 Y 軸向上,旋轉方向需留意。
  • 列印應用:世界轉換在列印預覽、縮放列印極具價值,可統一邏輯座標處理不同解析度裝置。

結語

World-to-Page 轉換雖較少直接使用,但掌握矩陣變換原理能靈活實現縮放、旋轉、鏡像等效果,且為理解完整 GDI 座標管線奠定基礎。詳細資訊請參閱 MSDN Coordinate Spaces and Transformations 章節。

本文配套原始碼可供下載。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved