Direct2D教程(六)图形也能做运算
概述
大家都学过集合运算,给定两个集合,可以求他们的并集,交集,差集等。其实图形之间也能做运算,今天就带大家开始图形运算之旅,讲讲如何合并图形。在D2D中有四种方法合并图形,分别是并(UNION),交(INTERSECT),差(EXCLUDE)和异或(XOR)。那么图形之间是如何合并的呢?两个图形之间进行Xor的结果是什么呢?为了便于理解,我先把效果图贴上来。下面图片中第一副图示两个圆的原始图,第二副图是UNION的结果,取两个圆所有的部分,但是公共部分只保留一份。第三幅图是INTERSECT的结果,取两个圆的公共部分。第四幅图是XOR的结果,取两个圆公共部分以外的部分。最后一幅图是EXCLUDE的结果,这个相当于集合的减法运算,在一个圆中去除两个圆的公共部分。
合并图形的基本步骤
图形的合并要经历以下几个步骤,合并后的图形是存放在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)画刷。这是我第一次认真的写一个系列,以前曾经多次尝试,但都是有始无终,这次我想坚持下去,所以希望大家多多给我提意见,我一直觉得写一篇通俗易懂的文章绝非易事,我也经常把以前写过的文章从新拿出来重新审视并作些修改。因为一个技术点,你自己明白了,不一定能给别人讲明白,所以无论是什么意见,技术上的,写作技巧上的,或者其他方面的,越多越好!
源文档 <http://www.cnblogs.com/graphics/archive/2011/06/01/2060480.html>