Windows桌面应用程序(1-2-4-9th) 在Direct2D中应用转换

使用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。要移除当前变换,请使用由Matrix3x2F::Identity函数返回的单位矩阵调用SetTransform

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
    );
}

此代码绘制一条垂直线,从钟面的中心开始,到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 Clock Sample下载完整的Visual Studio项目。(只是为了好玩,下载版本在钟面上增加了一个放射状渐变)。
结合变换
四个基本的变换可以通过乘以两个或更多的矩阵来组合。例如,下面的代码将旋转和翻译结合起来。

const D2D1::Matrix3x2F rot=D2D1::Matrix3x2F::Rotation(20);
const D2D1::Matrix3x2F trans=D2D1::Matrix3x2F::Translation(40,10);
pRenderTarget->SetTransform(rot*trans);

Matrix3x2F类为矩阵乘法提供operator*()。矩阵乘法的顺序很重要。设置变换(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×NN×M M × N ≠ N × M
下一个
附录:矩阵变换


原文链接:Applying Transforms in Direct2D

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值