Direct2D教程(六)图形也能做运算

概述

大家都学过集合运算,给定两个集合,可以求他们的并集,交集,差集等。其实图形之间也能做运算,今天就带大家开始图形运算之旅,讲讲如何合并图形。在D2D中有四种方法合并图形,分别是并(UNION),交(INTERSECT),差(EXCLUDE)和异或(XOR)。那么图形之间是如何合并的呢?两个图形之间进行Xor的结果是什么呢?为了便于理解,我先把效果图贴上来。下面图片中第一副图示两个圆的原始图,第二副图是UNION的结果,取两个圆所有的部分,但是公共部分只保留一份。第三幅图是INTERSECT的结果,取两个圆的公共部分。第四幅图是XOR的结果,取两个圆公共部分以外的部分。最后一幅图是EXCLUDE的结果,这个相当于集合的减法运算,在一个圆中去除两个圆的公共部分。

Direct2D教程(六)图形也能做运算

合并图形的基本步骤

图形的合并要经历以下几个步骤,合并后的图形是存放在path geometry中的。

  • 创建待合并的图形
  • 创建path geometry
  • 获取path geometry中的sink对象
  • 调用CombineWithGeometry函数进行合并

下面以UNION操作为例,详细演示如何合并图形。首先声明几个变量,pPathGeometryUnion用来存放合并后的图形,pCircleGeometry1和pCircleGeometry2表示待合并的两个圆。

ID2D1PathGeometry * pPathGeometryUnion = NULL ;
ID2D1EllipseGeometry
* pCircleGeometry1 = NULL ;
ID2D1EllipseGeometry
* pCircleGeometry2 = NULL ;

 创建待合并的图形

这里创建两个圆,半径都是50.0f,一个圆心在(75.0f, 75.0f),另一个圆心在(125.0f, 75.0f),也就是说这两个圆是相交的。对应上面图片中第一副图。

// 第一个圆
const D2D1_ELLIPSE circle1 = D2D1::Ellipse(
    D2D1::Point2F(
75.0f , 75.0f ),
    50.0f ,
    50.0f
) ;

pD2DFactory -> CreateEllipseGeometry(
    & circle1,
    & pCircleGeometry1
) ;

// 第二个圆
const D2D1_ELLIPSE circle2 = D2D1::Ellipse(
    D2D1::Point2F(
125.0f , 75.0f ),
    50.0f ,
    50.0f
) ;

pD2DFactory -> CreateEllipseGeometry(
    & circle2,
    & pCircleGeometry2
) ;

创建path geometry

hr = pD2DFactory -> CreatePathGeometry( & pPathGeometryUnion) ;

获取path geometry的sink对象

if (SUCCEEDED(hr))
{
    ID2D1GeometrySink
* pGeometrySink = NULL;
    hr
= pPathGeometryUnion -> Open( & pGeometrySink) ;
}

调用CombineWithGeometry进行合并

CombineWithGeometry是ID2D1SimplifiedGeometrySink接口里面的一个函数,所以任何类型的geometry都可以进行合并操作,合并的方式就是一个图形调用这个函数,将另一个图形作为参数传进去,比如要合并A和B两个图形,调用方法就是A->CombineWithGeometry(B, ...)。看一下这个函数的定义。

HRESULT CombineWithGeometry(
    [
in ] ID2D1Geometry * inputGeometry,
    D2D1_COMBINE_MODE combineMode,
    [
ref ] const D2D1_MATRIX_3X2_F & inputGeometryTransform,
    [
in ] ID2D1SimplifiedGeometrySink * geometrySink
)
const ;

第一个参数是待合并的图形,相当于上面例子中的B,第二个参数是合并的方式,目前有下面四种。

  • D2D1_COMBINE_MODE_UNION (并-两个图形的所有部分)
  • D2D1_COMBINE_MODE_INTERSECT (交-两个图形的公共部分)
  • D2D1_COMBINE_MODE_XOR (异或-两个图形的所有部分,但公共部分除外)
  • D2D1_COMBINE_MODE_EXCLUDE (差-属于一个图形而不属于另外一个图形的部分)

第三个参数是一个变换矩阵,可以在合并之前对参数一进行一些变换。最后一个参数是path geometry的sink对象,用来接收合并后的图形。调用代码如下,这里我们选择UNION合并方式,合并前不做任何变换,所以第三个参数传入NULL。

hr = pPathGeometryUnion -> Open( & pGeometrySink) ;
if (SUCCEEDED(hr))
{
    hr
= pCircleGeometry1 -> CombineWithGeometry(
        pCircleGeometry2,
        D2D1_COMBINE_MODE_UNION,
        NULL,
        pGeometrySink
    ) ;
}

绘制

由于图形已经合并,并且合并的结果已经存放到path geometry中,所以直接调用对应的path geometry即可进行绘制,也就是上面的pPathGeometryUnion。

pRenderTarget -> SetTransform(D2D1::Matrix3x2F::Translation( 100 , 100 ));
pRenderTarget
-> DrawGeometry(pPathGeometryUnion, pBlackBrush) ;
pRenderTarget
-> FillGeometry(pPathGeometryUnion, pFillBrush) ;

总结

学习Direct2D已经有两个月的时间了,断断续续,现在的学习还比较浅,主要停留在如何使用API层面上,在随后的系列中,我会逐渐加入一些Demo,把相关的知识点整合到一起,这样也能一些整体的认识,对各种资源之间的协调有更深刻的认识。另外,这一篇也是Geometry系列的最后一篇,从下一篇开始学习(Brush)画刷。这是我第一次认真的写一个系列,以前曾经多次尝试,但都是有始无终,这次我想坚持下去,所以希望大家多多给我提意见,我一直觉得写一篇通俗易懂的文章绝非易事,我也经常把以前写过的文章从新拿出来重新审视并作些修改。因为一个技术点,你自己明白了,不一定能给别人讲明白,所以无论是什么意见,技术上的,写作技巧上的,或者其他方面的,越多越好!

你可能感兴趣的:(教程)