共用方式為


在 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。

下一個

附錄:矩陣轉換