不可不知的WPF幾何圖形(Geometry)

老码识途呀發表於2024-09-08

在軟體行業,經常會聽到一句話“文不如表,表不如圖”說明了圖形在軟體應用中的重要性。同樣在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實現直線,效果如下所示:

不可不知的WPF幾何圖形(Geometry)

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繪製圓,示例如下所示:

不可不知的WPF幾何圖形(Geometry)

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繪製矩形,示例如下所示:

不可不知的WPF幾何圖形(Geometry)

影像裁剪

透過將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實現影像裁剪,示例如下所示:

不可不知的WPF幾何圖形(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;

上述程式碼建立的形狀如下所示:

不可不知的WPF幾何圖形(Geometry)

與 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)

以上就是《不可不知的WPF幾何圖形(Geometry)》的全部內容,旨在拋磚引玉,一起學習,共同進步。

相關文章