在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明了圖形在軟體應用中的重要性。同樣在WPF開發中,為了程式美觀或者業務需要,經常會用到各種個樣的圖形。今天以一些簡單的小例子,簡述WPF開發中幾何圖形(Geometry)相關內容,僅供學習分享使用,如有不足之處,還請指正。
什麼是幾何圖形(Geometry)
幾何圖形可以隨意和進行縮放而不變形,這是和點陣圖最大的差異。Geometry類及其派生類(PathGeometry,EllipseGeometry,CombinedGeometry)可以用於描述2D形狀的幾何圖形。Geometry物件可以是矩形和橢圓形等簡單圖形,也可以是由兩個或者多個幾何物件建立的複合圖形,如:PathGeometry和StreamGeometry等,可以用於繪製曲線或其他複雜圖形。Geometry類繼承自Freezable類,因此可以宣告為資源,物件之間共享,變為只讀提高效能,或者克隆及執行緒安全等。具體可瞭解Freezable相關知識。
幾何圖形與形狀的區別
上一篇文章瞭解了Shape類也是在頁面繪製圖形,那Shape和Geometry有什麼區別和聯絡呢?
首先Geometry和Shape類都是用於描述2D形狀(如:EllipseGeometry和Ellipse),但它們之間存在一些重要的區別。具體如下:
- Geometry繼承自Freezable類,而Shape繼承自FrameworkElement。所以Shape及其派生類可以在UI頁面中獨立存在並參與頁面佈局,而Geometry及其派生類則不能。
- 由於Shape類是UI無素,所以Shape類比Geometry更易於使用,但是Geometry卻更通用,Shape用於呈現2D圖形,但是Geometry可用於定義2D圖形的幾何區域,定義裁剪的區域或命中測試區域等。
- Shape派生類Path的Data屬性,就是Geometry型別。所以可以理解為Shape是外在呈現形狀,而Geometry是其內容,而Fill和Stroke屬性,則對應畫筆。
簡單的幾何圖形
Geometry是abstract修飾的抽象類,所以只能使用其派生類進行繪製幾何圖形,而Geometry的派生類可以分為三個類別:簡單幾何,路徑幾何,複合幾何。
簡單幾何圖形,WPF系統自帶了幾個預設的幾何圖形,如LineGeometry,RectangleGeometry,和 EllipseGeometry,用於建立基本的幾何圖形,如:線條,矩形,橢圓等。
- LineGeometry,透過指定直線的起點和終點來定義線條。
- RectangleGeometry使有Rect結構來定義,指定矩形的相對位置,及高度和寬度。也可以使用RadiusX,RadiusY屬性來建立圓角矩形。
- EllipseGeometry由中心點,x軸半徑,y軸半徑來建立橢圓,如果x軸半徑和y軸半徑相等,則為圓形。
雖然PathGeometry也能實現基本的幾何圖形,但是用WPF預設提供的類,則更簡單,也方便理解。
LineGeometry
由於Geometry不是UI元素,不能獨立進行自我繪製並呈現 ,所以使用Path形狀來呈現。LineGeometry透過設定起始點座標(StartPoint)和結束座標(EndPoint)來定義直線。
如下所示:
<Path Stroke="Black" StrokeThickness="1" >
<Path.Data>
<LineGeometry StartPoint="10,20" EndPoint="100,130" />
</Path.Data>
</Path>
上述程式碼透過C#程式碼實現,如下所示:
LineGeometry lineGeometry = new LineGeometry();
lineGeometry.StartPoint = new Point(10, 20);
lineGeometry.EndPoint = new Point(100, 130);
Path path = new Path();
path.Stroke = Brushes.Black;
path.StrokeThickness = 1;
path.Data = lineGeometry;
透過LineGeometry實現直線,效果如下所示:
EllipseGeometry
EllipseGeometry透過設定中心點的座標(Center)和x半徑(RadiusX),y軸半徑(RadiusY)來繪製橢圓。
繪製一個座標相等的圓,如下所示:
<Path Fill="Gold" Stroke="Black" StrokeThickness="1">
<Path.Data>
<EllipseGeometry Center="50,50" RadiusX="50" RadiusY="50" />
</Path.Data>
</Path>
上述程式碼透過C#程式碼實現,如下所示:
EllipseGeometry ellipseGeometry = new EllipseGeometry();
ellipseGeometry.Center = new Point(50, 50);
ellipseGeometry.RadiusX = 50;
ellipseGeometry.RadiusY = 50;
Path path = new Path();
path.Fill = Brushes.Gold;
path.Stroke = Brushes.Black;
path.StrokeThickness = 1;
path.Data = ellipseGeometry;
透過EllipseGeometry繪製圓,示例如下所示:
RectangleGeometry
RectangleGeometry通會Rect結構來描述矩形,分別是起始座標和寬度,高度來定義矩形,如下所示:
<Path Fill="LemonChiffon" Stroke="Black" StrokeThickness="1">
<Path.Data>
<RectangleGeometry Rect="50,50,100,60" />
</Path.Data>
</Path>
上述程式碼用C#實現,如下所示:
RectangleGeometry rectangleGeometry = new RectangleGeometry();
rectangleGeometry.Rect = new Rect(50, 50, 100, 60);
Path path = new Path();
path.Fill = Brushes.LemonChiffon;
path.Stroke = Brushes.Black;
path.StrokeThickness = 1;
path.Data = rectangleGeometry;
透過RectangleGeometry繪製矩形,示例如下所示:
影像裁剪
透過將Geometry應用到Image的Clip屬性,可以實現影像的裁剪功能,如下所示:
<StackPanel Orientation="Vertical" Margin="10">
<TextBlock Text="原圖"></TextBlock>
<Image Source="imgs\bingdundun.jpeg" Width="300" Height="200" HorizontalAlignment="Left">
</Image>
<TextBlock Text="裁剪後"></TextBlock>
<Image Source="imgs\bingdundun.jpeg" Width="300" Height="200" HorizontalAlignment="Left">
<Image.Clip>
<EllipseGeometry RadiusX="130" RadiusY="80" Center="150,100"/>
</Image.Clip>
</Image>
</StackPanel>
上述程式碼用C#實現如下所示:
Image image = new Image();
Uri imageUri = new Uri(@"imgs\bingdundun.jpeg", UriKind.RelativeOrAbsolute);
image.Source = new BitmapImage(imageUri);
image.Width = 300;
image.Height = 200;
image.HorizontalAlignment = HorizontalAlignment.Left;
// 用橢圓定義裁剪區域.
EllipseGeometry ellipseGeometry = new EllipseGeometry();
ellipseGeometry.Center = new Point(150, 10);
ellipseGeometry.RadiusX = 130;
ellipseGeometry.RadiusY = 80;
image.Clip = ellipseGeometry;
透過Geometry實現影像裁剪,示例如下所示:
路徑幾何
PathGeometry類及其輕型等效項(StreamGeometry類)主要用於描述弧線,曲線,直線組成的多個複雜圖形的方法。PathGeometry的核心是PathFigure對你的集合。每一個PathFigure本身由一個或多個PathSegment物件組成,每一個PathSegment描述圖形的一個小部分。常見的PathSegment主要有以下幾種:
- ArcSegment,表示兩點之間建立一條橢圓弧。
- BezierSegment,表示兩個點之間的三次方貝塞爾曲線。
- LineSegment,表示兩個點之間的直線。
- PolyBezierSegment,表示建立一系列的三次方貝塞爾曲線。
- PolyLineSegment,表示建立一系列直線。
- PolyQuadraticBezierSegment ,表示建立一系列二次貝塞爾曲線。
- QuadraticBezierSegment,表示建立一條貝塞爾曲線。
關於PathFigure有以下幾點說明:
- PathFigure內的多個線段組合成單個幾何形狀,每個線段的終點,就是下一個線段的起點。
- PathFigure的StartPoint屬性指定繪製第一個線段的起點。
- 每一個線段都從上一個線段的終點開始。
關於PathGeometry的示例程式碼如下所示:
<Path Stroke="Black" StrokeThickness="1" >
<Path.Data>
<PathGeometry>
<PathGeometry.Figures>
<PathFigure StartPoint="10,50">
<PathFigure.Segments>
<BezierSegment Point1="100,0" Point2="200,200" Point3="300,100"/>
<LineSegment Point="400,100" />
<ArcSegment Size="50,50" RotationAngle="45" IsLargeArc="True" SweepDirection="Clockwise" Point="200,100"/>
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</Path.Data>
</Path>
上述XAML程式碼用C#實現,如下所示:
PathFigure pathFigure = new PathFigure();
pathFigure.StartPoint = new Point(10, 50);
pathFigure.Segments.Add(
new BezierSegment(
new Point(100, 0),
new Point(200, 200),
new Point(300, 100),
true /* IsStroked */ ));
pathFigure.Segments.Add(
new LineSegment(
new Point(400, 100),
true /* IsStroked */ ));
pathFigure.Segments.Add(
new ArcSegment(
new Point(200, 100),
new Size(50, 50),
45,
true, /* IsLargeArc */
SweepDirection.Clockwise,
true /* IsStroked */ ));
/// Create a PathGeometry to contain the figure.
PathGeometry pathGeometry = new PathGeometry();
pathGeometry.Figures.Add(pathFigure);
// Display the PathGeometry.
Path path = new Path();
path.Stroke = Brushes.Black;
path.StrokeThickness = 1;
path.Data = pathGeometry;
上述程式碼建立的形狀如下所示:
與 PathGeometry 類一樣,StreamGeometry 定義可能包含曲線、弧線和直線的複雜幾何形狀。 與 PathGeometry 不同,StreamGeometry 的內容不支援資料繫結、動畫或修改。 當需要描述複雜幾何圖形,但又不希望產生支援資料繫結、動畫或修改的開銷時,請使用 StreamGeometry。 由於 StreamGeometry 類的高效性,該類是描述裝飾器的不錯選擇。
複合幾何
使用 GeometryGroup、CombinedGeometry 或透過呼叫靜態 Geometry 方法 Combine,可以建立複合幾何物件。兩者之間的差異如下:
- CombinedGeometry 物件和 Combine 方法執行布林運算,以合併由兩個幾何圖形定義的面積。 沒有面積的 Geometry 物件將被放棄。 只能合併兩個 Geometry 物件(儘管這兩個幾何圖形也可能是複合幾何)。
- GeometryGroup 類建立其包含的 Geometry 物件的合併,而不合並其面積。 可以將任意數量的 Geometry 物件新增到 GeometryGroup。由於它們不執行合併操作,因此使用 GeometryGroup 物件的效能比使用 CombinedGeometry 物件或 Combine 方法的效能高。
簡單點來說:GeometryGroup是進行物件的合併,CombinedGeometry是進行合併物件的布林運算。
下面示例CombinedGeometry的“並集”,如下所示:
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Union">
<CombinedGeometry.Geometry1>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="75,75" />
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry RadiusX="50" RadiusY="50" Center="125,75" />
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
CombinedGeometry並集示例如下所示:
以上就是《不可不知的WPF幾何圖形(Geometry)》的全部內容,旨在拋磚引玉,一起學習,共同進步。