目前博客園中成系列的Direct2D的教程有
1、萬一的 Direct2D 系列,用的是Delphi 2009
2、zdd的 Direct2D 系列,用的是VS中的C++
3、本文所在的 Direct2D教程 系列,用的是VS2010的Visual Basic語言(可以很方便的轉為C#),基於Windows API Code Pack 1.1。
還有官方的說明文檔 Direct2D ,用的是C++。
幾何(Geometry)對象
歷數微軟的圖形開發技術,幾何(Geometry)對象就不停的在發展,不斷完善,越來越強大。
在GDI和GDI+中,區域(Region)和路徑(Path)就是幾何(Geometry)對象的雛形。WPF中已經有專門幾何(Geometry)對象的概念,包含有直線幾何(LineGeometry)、矩形幾何(RectangleGeometry)、橢圓幾何(EllipseGeometry)、路徑幾何(PathGeometry)、流幾何(StreamGeometry)(輕量級的PathGeometry)、合並幾何(CombinedGeometry)、幾何組(GeometryGroup)等
在Direct2D更加完善了幾何(Geometry)對象的概念。
在Direct2D中,所有的幾何(Geometry)對象都繼承自基類Geometry類(是個抽象類)。包括:矩形幾何(RectangleGeometry)、圓角矩形幾何(RoundedRectangleGeometry)、橢圓幾何(EllipseGeometry)、路徑幾何(PathGeometry)、幾何組(GeometryGroup)、變換幾何(TransformedGeometry)。
這些幾何(Geometry)對象都不能直接創建,必須通過D2DFactory對象的相應的方法創建。
Direct2D強大的是其繪圖功能。有人會疑惑,既然有RenderTarget對象的繪圖函數(以Draw和Fill開頭的函數),那還需要幾何(Geometry)對象么?
答案是肯定的,Direct2D提供了幾何(Geometry)類,必然提供了許多強大的功能。這些功能自己去實現的話,可能要頗費一番功夫。讓我們看看幾何(Geometry)對象提供了哪些實用、強大的功能
計算方法:
計算幾何(Geometry)對象的面積:ComputerArea
計算幾何(Geometry)對象線段展開的長度:ComputerLength
計算幾何(Geometry)對象上指定距離處的點和正切矢量:ComputerPointAtLength
獲得幾何(Geometry)對象的邊界:GetBounds
獲得幾何(Geometry)對象按指定筆畫寬度和樣式加寬並按指定矩陣轉換后的邊界:GetWidentdBounds
判定方法:
判定幾何(Geometry)對象是否包含指定點:FillContainsPoint
判定幾何(Geometry)對象的描邊筆畫是否包含指定的點:StrokeContainsPoint
判定該幾何(Geometry)對象和指定幾何(Geometry)對象的交集的類型的結果:CompareWithGeometry
運算方法:
該幾何(Geometry)對象和指定幾何(Geometry)對象的合並結果:CombineWithGeometry
按照指定筆畫加寬幾何(Geometry)對象:Widen
優化方法:
獲得幾何(Geometry)對象的輪廓:Outline
獲得幾何(Geometry)對象的簡化版本(僅包含直線和三次貝塞爾曲線):Simplify
獲得幾何(Geometry)對象的簡化成一組三角形:Tesselate
注:優化方法中的函數能在精度要求不高的情況下,大幅提升幾何(Geometry)對象的顯示效率(犧牲精度換取效率)。
下面是各個方法的原型定義:
Public Function ComputeArea() As Single
Public Function ComputeArea(flatteningTolerance As Single) As Single
Public Function ComputeArea(flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Single
Public Function ComputeLength() As Single
Public Function ComputeLength(flatteningTolerance As Single) As Single
Public Function ComputeLength(flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Single
Public Function ComputePointAtLength(length As Single) As Direct2D1. PointAndTangent
Public Function ComputePointAtLength(length As Single, flatteningTolerance As Single) As Direct2D1. PointAndTangent
Public Function ComputePointAtLength(length As Single, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Direct2D1. PointAndTangent
Direct2D1. PointAndTangent(point As Direct2D1. Point2F, tangent As Direct2D1. Point2F)
Public Function GetBounds() As Direct2D1. RectF
Public Function GetBounds(worldTransform As Direct2D1. Matrix3x2F) As Direct2D1. RectF
Public Function GetWidenedBounds(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle) As Direct2D1. RectF
Public Function GetWidenedBounds(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, flatteningTolerance As Single) As Direct2D1. RectF
Public Function GetWidenedBounds(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Direct2D1. RectF
Public Function FillContainsPoint(point As Direct2D1. Point2F) As Boolean
Public Function FillContainsPoint(point As Direct2D1. Point2F, flatteningTolerance As Single) As Boolean
Public Function FillContainsPoint(point As Direct2D1. Point2F, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Boolean
Public Function StrokeContainsPoint(point As Direct2D1. Point2F, strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle) As Boolean
Public Function StrokeContainsPoint(point As Direct2D1. Point2F, strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, flatteningTolerance As Single) As Boolean
Public Function StrokeContainsPoint(point As Direct2D1. Point2F, strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F) As Boolean
Public Function CompareWithGeometry(inputGeometry As Direct2D1. Geometry) As Direct2D1. GeometryRelation
Public Function CompareWithGeometry(inputGeometry As Direct2D1. Geometry, flatteningTolerance As Single) As Direct2D1. GeometryRelation
Public Function CompareWithGeometry(inputGeometry As Direct2D1. Geometry, flatteningTolerance As Single, inputGeometryTransform As Direct2D1. Matrix3x2F) As Direct2D1. GeometryRelation
Public Enum GeometryRelation
Unknown = 0
Disjoint = 1
IsContained = 2
Contains = 3
Overlap = 4
End Enum
Public Sub CombineWithGeometry(inputGeometry As Direct2D1. Geometry, combineMode As Direct2D1. CombineMode, geometrySink As Direct2D1. ISimplifiedGeometrySink)
Public Sub CombineWithGeometry(inputGeometry As Direct2D1. Geometry, combineMode As Direct2D1. CombineMode, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single)
Public Sub CombineWithGeometry(inputGeometry As Direct2D1. Geometry, combineMode As Direct2D1. CombineMode, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single, inputGeometryTransform As Direct2D1. Matrix3x2F)
Public Enum CombineMode
Union = 0
Intersect = 1
Xor = 2
Exclude = 3
End Enum
Public Sub Widen(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, geometrySink As Direct2D1. ISimplifiedGeometrySink)
Public Sub Widen(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single)
Public Sub Widen(strokeWidth As Single, strokeStyle As Direct2D1. StrokeStyle, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F)
Public Sub Outline(geometrySink As Direct2D1. ISimplifiedGeometrySink)
Public Sub Outline(geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single)
Public Sub Outline(geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F)
Public Sub Simplify(simplificationOption As Direct2D1. GeometrySimplificationOption, geometrySink As Direct2D1. ISimplifiedGeometrySink)
Public Sub Simplify(simplificationOption As Direct2D1. GeometrySimplificationOption, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single)
Public Sub Simplify(simplificationOption As Direct2D1. GeometrySimplificationOption, geometrySink As Direct2D1. ISimplifiedGeometrySink, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F)
Public Enum GeometrySimplificationOption
CubicsAndLines = 0
Lines = 1
End Enum
Public Sub Tessellate(tessellationSink As Direct2D1. ITessellationSink)
Public Sub Tessellate(tessellationSink As Direct2D1. ITessellationSink, flatteningTolerance As Single)
Public Sub Tessellate(tessellationSink As Direct2D1. ITessellationSink, flatteningTolerance As Single, worldTransform As Direct2D1. Matrix3x2F)
從上面的原型定義可以看出,基本上每個函數都有一個基本的調用方法,然后增加了兩個擴展的調用方法(一個增加了參數flatteningTolerance;一個增加了參數flatteningTolerance和參數worldTransform,至於這兩個參數的意義,留待后文講解)
幾何(Geometry)對象有一個特性,一旦創建完成就不能修改(要么使用、要么銷毀、要么通過運算獲得新的幾何(Geometry)對象)。這個特性和String對象類似,雖然理解上有點困難,但是這樣定義必定有其合理性。
雖然我們有矩形幾何(RectangleGeometry)、圓角矩形幾何(RoundedRectangleGeometry)、橢圓幾何(EllipseGeometry)對象,但這些對象對一些比較復雜的圖像就無能為力了。因此,還得引入路徑幾何(PathGeometry)對象
路徑幾何(PathGeometry)對象
路徑幾何(PathGeometry)對象指的是由弧線、曲線(三次貝塞爾曲線、二次貝塞爾曲線)和線條組成的復雜形狀。
路徑幾何(PathGeometry)對象必須包含一個(只能一個)可包含線條、弧線、曲線(三次貝塞爾曲線和二次貝塞爾曲線)的幾何路徑(GeometrySink)對象
而幾何路徑(GeometrySink)對象可以包含一組(一條或若干條)的線(直線、曲線)
創建路徑幾何(PathGeometry)對象的步驟為
1、定義路徑幾何(PathGeometry)對象,並從D2DFactory對象的CreatePathGeometry方法獲得該對象的實例
2、定義幾何路徑(GeometrySink)對象,並從PathGeometry對象的Open方法獲得該對象的實例(該方法只能執行一次)
3、通過GeometrySink對象的BeginFigure方法獲得一條線的起點(以及填充模式)
4、通過GeometrySink對象的AddLine(添加直線)、AddArc(添加弧線)、AddBezier(添加三次貝塞爾曲線)、AddQuadraticBezier(添加二次貝塞爾曲線)等方法依次添加線(每條線的起點是上條線的終點,第一條直線的起點是步驟3中定義的起點)
5、通過GeometrySink對象的EndFigure方法完成一條線(設置封閉模式)。
6、如果還要給GeometrySink對象添加其他線,請重復步驟3、4、5
7、通過調用GeometrySink對象的Close方法,完成創建路徑幾何(PathGeometry)對象的步驟
一旦路徑幾何(PathGeometry)對象創建完成,則不能對其修改。
下面是幾何路徑(GeometrySink)對象的添加線的方法的原型定義:
Public Sub AddLine(point As Direct2D1. Point2F)
Public Sub AddBezier(bezier As Direct2D1. BezierSegment)
Direct2D1. BezierSegment(point1 As Direct2D1. Point2F, point2 As Direct2D1. Point2F, point3 As Direct2D1. Point2F)
Public Sub AddQuardraticBezier(bezier As Direct2D1. QuadraticBezierSegment)
Direct2D1. QuadraticBezierSegment(point1 As Direct2D1. Point2F, point2 As Direct2D1. Point2F)
Public Sub AddLines(points As IEnumerable( Of Direct2D1. Point2F))
Public Sub AddBeziers(beziers As IEnumerable( Of Direct2D1. BezierSegment))
Public Sub AddQuardraticBezier(beziers As IEnumerable( Of Direct2D1. QuadraticBezierSegment))
Public Sub AddArc(arc As Direct2D1. ArcSegment)
Direct2D1. ArcSegment(point As Direct2D1. Point2F, size As Direct2D1. SizeF, rotationAngle As Single, sweepDirection As Direct2D1. SweepDirection, arcSize As Direct2D1. ArcSize)
Direct2D1. SizeF(width As Single, height As Single)
Public Enum SweepDirection
Counterclockwise = 0
Clockwise = 1
End Enum
Public Enum ArcSize
Small = 0
Large = 1
End Enum
每個方法都省略了起點(起點是上一條線的終點或者是BeginFigure方法定義的起點)。所以AddLine方法的參數只有一個點(終點),AddBezier方法參數有三個點(兩個控制點,一個終點),AddQuardraticBezier方法有兩個點(一個控制點,一個終點)
這里講講AddArc方法(添加弧線),參數是ArcSegment結構,它有這幾個屬性,分別代表
point:終點,Point2F結構
size:弧線所在的橢圓的橫軸半徑和縱軸半徑,參數SizeF結構,width表示橫軸半徑,height表示縱軸半徑
rotationAngle:弧線所在的橢圓旋轉角度
sweepDirection:從起點到終點的弧線的方向(順時針或逆時針),參數是SweepDirection枚舉,Counterclockwise表示逆時針,Clockwise表示順時針。
arcSize:表示選取橢圓的大弧還是小弧,參數是ArcSize枚舉,Small表示小弧,Large表示大弧。(注:配圖是WPF的IsLargeArc,True對應Large,False對應Small)
這幾個參數的意義和WPF中的ArcSegment對象的對應的參數幾乎一樣。上面微軟官網上的幾張圖(WPF幫助文檔中的圖)很好的闡述了這些參數的意義。
接下來看看幾何路徑(GeometrySink)對象的BeginFigure方法和EndFigure方法的原型定義
Public Sub BeginFigure(point As Direct2D1. Point2F, figureBegin As Direct2D1. FigureBegin)
Public Enum FigureBegin
Filled = 0
Hollow = 1
End Enum
Public Sub EndFigure(figureEnd As Direct2D1. FigureEnd)
Public Enum FigureEnd
Open = 0
Closed = 1
End Enum
幾何路徑(GeometrySink)對象的BeginFigure方法,第一個參數標明了起點;第二個參數是FigureBegin枚舉,表明線圍成區域的填充方式,Filled表示填充,Hollow這個參數表示的意義在后文再解釋。EndFigure方法中的參數是FigureEnd枚舉,表明線是否封閉,Open表示不封閉,線從起點到終點;Closed表示封閉,從終點到起點再連一條直線。
下面的代碼是一段示例代碼
Public Class clsDirect2DSample5
Inherits clsDirect2DSample
Public Shadows Sub Render()
If Not _renderTarget Is Nothing Then
With _renderTarget
.BeginDraw()
Dim B As Direct2D1. SolidColorBrush = _renderTarget.CreateSolidColorBrush( New Direct2D1. ColorF(1, 0, 0))
Dim SP As New Direct2D1. StrokeStyleProperties()
Dim S As Direct2D1. StrokeStyle
Dim PG As Direct2D1. PathGeometry
Dim sink As Direct2D1. GeometrySink
PG = _d2DFactory.CreatePathGeometry
sink = PG.Open
sink.BeginFigure( New Direct2D1. Point2F(30, 30), Direct2D1. FigureBegin.Filled)
sink.AddLine( New Direct2D1. Point2F(240, 30))
sink.AddArc( New Direct2D1. ArcSegment( _
New Direct2D1. Point2F(240, 240), _
New Direct2D1. SizeF(60, 100), _
45, _
Direct2D1. SweepDirection.Clockwise,
Direct2D1. ArcSize.Large))
sink.AddBezier( New Direct2D1. BezierSegment( _
New Direct2D1. Point2F(170, 120), _
New Direct2D1. Point2F(100, 360), _
New Direct2D1. Point2F(30, 240)))
sink.EndFigure(Direct2D1. FigureEnd.Closed)
sink.Close()
SP.LineJoin = Direct2D1. LineJoin.MiterOrBevel
S = _d2DFactory.CreateStrokeStyle(SP)
.DrawGeometry(PG, B, 6, S)
.EndDraw()
End With
End If
End Sub
End Class
下圖是該示例代碼的運行結果圖
該代碼一共添加了三條線,一條水平直線,一條弧線(右傾45度的橢圓弧線),一條三次貝塞爾曲線。最后通過EndFigure方法中的參數Direct2D1.FigureEnd.Closed設置為封閉曲線,在終點和起點之間自動添加了一條直線。