操作說明:控制複合圖案的填色
GeometryGroup 或 PathGeometry 的 FillRule 屬性會指定一個「規則」,以便組合圖形用來判斷指定點是否為幾何的一部分。 FillRule 有兩個可能的值:EvenOdd 和 Nonzero。 以下各節將說明如何使用這兩個規則。
EvenOdd:這個規則會從某個點朝任意方向繪製無限遠的光線,並且計算給定圖案中與光線相交的路徑線段數目,以判斷該點是否在填滿區域中。 如果這個數字是奇數,該點即是在區域內;如為偶數,該點即在區域外。
例如,下面的 XAML 會建立一個由一系列同心環組成的組合圖形 (目標),並將 FillRule 設定為 EvenOdd。
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<EllipseGeometry RadiusX="50" RadiusY="50" Center="75,75" />
<EllipseGeometry RadiusX="70" RadiusY="70" Center="75,75" />
<EllipseGeometry RadiusX="100" RadiusY="100" Center="75,75" />
<EllipseGeometry RadiusX="120" RadiusY="120" Center="75,75" />
</GeometryGroup>
</Path.Data>
</Path>
下圖顯示上一個範例中所建立的圖案。
在上圖中,請注意中間和第三個環形不會填滿。 這是因為從這兩個環形中的任何點所繪製的光線,會通過偶數數目的線段。 請參閱下圖:
NonZero:這個規則會從某個點朝任意方向繪製無限遠的光線,然後檢查圖案線段與光線相交的位置,以判斷該點是否在路徑填滿區域內。 從零開始計算,路徑線段每次從左到右與光線交會就加一,每次從右到左與光線交會就減一。 計算交會後,如果結果為零,則點即在路徑外。 否則就在路徑內。
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<EllipseGeometry RadiusX="50" RadiusY="50" Center="75,75" />
<EllipseGeometry RadiusX="70" RadiusY="70" Center="75,75" />
<EllipseGeometry RadiusX="100" RadiusY="100" Center="75,75" />
<EllipseGeometry RadiusX="120" RadiusY="120" Center="75,75" />
</GeometryGroup>
</Path.Data>
</Path>
使用上一個範例,FillRule 的 Nonzero 值結果如下圖所示:
如您所見,所有環形都會填滿。 這是因為所有的線段都是相同的方向,因此從任何點所繪製的光線會與一或多個線段交會,而相交的總和不等於零。 例如,在下圖中,紅色箭頭代表繪製線段的方向,而白色箭頭代表從最內側環形中的點射出的任意光線。 起始值為零,針對光線交會的每個線段,值會增加 1,因為線段由左至右與光線交會。
若要進一步示範 Nonzero 規則的行為,則需要一個更為複雜的圖形,包含不同方向的線段。 下面的 XAML 程式碼會建立一個類似於上一個範例的圖形,但此圖形是以 PathGeometry 而非 EllipseGeometry 所建立,這會建立四個同心弧而非完全封閉的同心圓。
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<PathGeometry>
<PathGeometry.Figures>
<!-- Inner Ring -->
<PathFigure StartPoint="10,120">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="50,50" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,120" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Second Ring -->
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="70,70" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Third Ring (Not part of path) -->
<PathFigure StartPoint="10,70">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="100,100" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,70" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Outer Ring -->
<PathFigure StartPoint="10,300">
<PathFigure.Segments>
<ArcSegment Size="130,130" IsLargeArc="True" SweepDirection="Clockwise" Point="25,300" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
下圖顯示上一個範例中所建立的圖案。
請注意,由中心開始的第三個弧形不會填滿。 下圖說明為何如此。 在圖中,紅色箭頭代表繪製線段的方向。 兩個白色箭頭代表兩個從「未填滿」區域中的點射出的任意光線。 從圖中可以看出,交會線段的指定光線,在其路徑中之值的總和為零。 如上面所定義,總和為零表示該點不屬於幾何的一部分 (並非填滿的一部分),而「非」零的總和 (包含負值) 則屬於幾何的一部分。
注意
基於 FillRule 的目的,所有圖形都視為封閉。 如果線段中有間隙,請繪製虛構線段將它封閉。 在上面的範例中,環形中有小型的間隙。 有鑑於此,我們可能會預期通過間隙射出的光線,會提供與另一個方向的光線不同的結果。 以下是其中一個間隙以及「虛構線段」(為了套用 FillRule 所繪製的線段) 放大後的圖例。