在 使用 Direct2D 繪製中,我們看到 ID2D1RenderTarget::FillEllipse 方法繪製對齊 x 軸和 y 軸的橢圓形。 但假設您想要繪製傾斜角度的橢圓形嗎?
藉由使用轉換,您可以透過下列方式改變圖形。
- 繞點旋轉。
- 調整大小。
- 翻譯(X 或 Y 方向的位移)。
- 扭曲(也稱為 切變)。
轉換是一種數學運算,可將一組點對應至一組新的點。 例如,下圖顯示繞點 P3 旋轉的三角形。 套用旋轉之後,點 P1 會對應至 P1』、點 P2 對應至 P2',而點 P3 會對應至本身。
轉換是使用矩陣來實作。 不過,您不必瞭解矩陣的數學,才能使用這些矩陣。 如果您想要深入瞭解數學,請參閱 附錄:矩陣轉換。
若要在 Direct2D 中套用轉換,請呼叫 ID2D1RenderTarget::SetTransform 方法。 此方法會採用 定義轉換的D2D1_MATRIX_3X2_F 結構。 您可以在 D2D1::Matrix3x2F 類別上呼叫方法,以初始化這個結構。 這個類別包含靜態方法,這些方法會傳回每種轉換的矩陣:
例如,下列程式代碼會在點 (100, 100) 周圍套用 20 度旋轉。
pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Rotation(20, D2D1::Point2F(100,100)));
轉換會套用至所有稍後的繪圖作業,直到您再次呼叫 SetTransform 為止。 若要移除目前的轉換,請使用識別矩陣呼叫 SetTransform 。 若要建立識別矩陣,請呼叫 Matrix3x2F::Identity 函式 。
pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
繪製時鐘指針
讓我們透過使用轉換技術,將圓形程式改造成模擬時鐘。 我們可以藉由新增手部的線條來做到這一點。
與其計算線條的座標,我們可以計算角度,然後進行旋轉變換。 下列程式代碼顯示繪製一個時鐘手的函式。 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);
}
此程式代碼會繪製垂直線,從時鐘臉部的中心開始,並結束於點 endPoint。 線條會套用旋轉轉換,繞著橢圓形中央旋轉。 旋轉的中心點是形成時鐘面的橢圓形中心。
下列程式代碼示範如何繪製整個時鐘表面。
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 專案。 (只是為了有趣,下載版本會將星形漸層新增至時鐘表面。
結合轉換
四個基本轉換可以乘以兩個或多個矩陣來結合。 例如,下列程式代碼會結合旋轉與翻譯。
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。