在 Direct2D 中套用轉換
在 使用 Direct2D 繪製中,我們發現 ID2D1RenderTarget::FillEllipse 方法繪製對齊 X 軸和 y 軸的橢圓形。 但假設您想要繪製傾斜角度的橢圓形嗎?
藉由使用轉換,您可以透過下列方式改變圖形。
- 繞點旋轉。
- 縮放。
- X 或 Y 方向) 的轉譯 (位移。
- 扭曲 (也稱為 ) 。
轉換是一種數學運算,可將一組點對應至一組新的點。 例如,下圖顯示繞點 P3 旋轉的三角形。 套用旋轉之後,點 P1 會對應至 P1'、點 P2 對應至 P2',而點 P3 會對應至本身。
轉換是使用矩陣來實作。 不過,您不需要瞭解矩陣的數學,才能使用這些矩陣。 如果您想要深入瞭解數學,請參閱 附錄:矩陣轉換。
若要在 Direct2D 中套用轉換,請呼叫 ID2D1RenderTarget::SetTransform 方法。 這個方法會採用 定義轉換的D2D1_MATRIX_3X2_F 結構。 您可以在 D2D1::Matrix3x2F 類別上呼叫方法來初始化這個結構。 這個類別包含靜態方法,這些方法會傳回每種轉換的矩陣:
例如,下列程式碼會套用 20 度旋轉繞點 (100,100) 。
pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Rotation(20, D2D1::Point2F(100,100)));
轉換會套用至所有稍後的繪圖作業,直到您再次呼叫 SetTransform 為止。 若要移除目前的轉換,請使用識別矩陣呼叫 SetTransform 。 若要建立識別矩陣,請呼叫 Matrix3x2F::Identity 函式 。
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
繪製時鐘手
讓我們將 Circle 程式轉換成類比時鐘,以使用轉換。 我們可以藉由為手部新增線條來執行此動作。
我們可以計算角度,然後套用旋轉轉換,而不是計算線條的座標。 下列程式碼顯示繪製一個時鐘手的函式。 fAngle參數會以度為單位提供手部的角度。
void Scene::DrawClockHand(float fHandLength, float fAngle, float fStrokeWidth)
{
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Rotation(fAngle, m_ellipse.point)
);
// endPoint defines one end of the hand.
D2D_POINT_2F endPoint = D2D1::Point2F(
m_ellipse.point.x,
m_ellipse.point.y - (m_ellipse.radiusY * fHandLength)
);
// Draw a line from the center of the ellipse to endPoint.
m_pRenderTarget->DrawLine(
m_ellipse.point, endPoint, m_pStroke, fStrokeWidth);
}
此程式碼會繪製垂直線,從時鐘臉部的中心開始,並結束于 端點點。 線條會套用旋轉轉換,繞橢圓形的中心旋轉。 旋轉的中心點是形成時鐘表面的橢圓中心。
下列程式碼示範如何繪製整個時鐘面。
void Scene::RenderScene()
{
m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::SkyBlue));
m_pRenderTarget->FillEllipse(m_ellipse, m_pFill);
m_pRenderTarget->DrawEllipse(m_ellipse, m_pStroke);
// Draw hands
SYSTEMTIME time;
GetLocalTime(&time);
// 60 minutes = 30 degrees, 1 minute = 0.5 degree
const float fHourAngle = (360.0f / 12) * (time.wHour) + (time.wMinute * 0.5f);
const float fMinuteAngle =(360.0f / 60) * (time.wMinute);
DrawClockHand(0.6f, fHourAngle, 6);
DrawClockHand(0.85f, fMinuteAngle, 4);
// Restore the identity transformation.
m_pRenderTarget->SetTransform( D2D1::Matrix3x2F::Identity() );
}
您可以從 Direct2D 時鐘範例下載完整的 Visual Studio 專案。 (Just for fun,下載版本會在時鐘臉部中新增星形光色。)
合併轉換
四個基本轉換可以藉由乘以兩個或多個矩陣來結合。 例如,下列程式碼會結合旋轉與翻譯。
const D2D1::Matrix3x2F rot = D2D1::Matrix3x2F::Rotation(20);
const D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(40, 10);
pRenderTarget->SetTransform(rot * trans);
Matrix3x2F類別提供運算子* () 進行矩陣乘法。 您相乘矩陣的順序很重要。 設定轉換 (M × N) 表示「先套用 M,後面接著 N」。例如,以下是旋轉,後面接著轉譯:
以下是此轉換的程式碼:
const D2D1::Matrix3x2F rot = D2D1::Matrix3x2F::Rotation(45, center);
const D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(x, 0);
pRenderTarget->SetTransform(rot * trans);
現在,請以反向順序比較該轉換與轉換,然後轉譯後接旋轉。
旋轉會繞原始矩形的中心執行。 以下是此轉換的程式碼。
D2D1::Matrix3x2F rot = D2D1::Matrix3x2F::Rotation(45, center);
D2D1::Matrix3x2F trans = D2D1::Matrix3x2F::Translation(x, 0);
pRenderTarget->SetTransform(trans * rot);
如您所見,矩陣相同,但作業順序已變更。 這是因為矩陣乘法不是通通的:M × N ≠ N × M。