Xamarin.Forms 図形: 塗りつぶしルール

いくつかの Xamarin.Forms 図形クラスには、FillRule 型の FillRule プロパティがあります。 これらには、 PolygonPolyline 、および GeometryGroup が含まれます。

FillRule 列挙は、EvenOddNonzero の要素を定義します。 各要素は、ポイントが図形の塗りつぶし領域にあるかどうかを判断するための異なるルールを表します。

重要

塗りつぶしルールの目的上、すべての図形は閉じていると見なされます。

EvenOdd

EvenOdd 塗りつぶしルールは、ポイントから無限大までの光線を任意の方向に描画し、光線が交差する図形内のセグメントの数をカウントします。 この数値が奇数の場合、ポイントは内側にあります。 この数値が偶数の場合、ポイントは外側にあります。

次の XAML の例では、複合図形を作成してレンダリングします。FillRule の既定値は EvenOdd です。

<Path Stroke="Black"
      Fill="#CCCCFF"
      Aspect="Uniform"
      HorizontalOptions="Start">
    <Path.Data>
        <!-- FillRule doesn't need to be set, because EvenOdd is the default. -->
        <GeometryGroup>
            <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>

この例では、一連の同心円リングで構成される複合図形が表示されます。

EvenOdd 塗りつぶしルールが設定された複合図形

この複合図形では、中央と 3 番目のリングが塗りつぶされていません。 これは、これら 2 つのリングの任意のポイントから引かれた射線が、偶数個のセグメントを通過するためです。

EvenOdd 塗りつぶしルールが設定された注釈付き複合図形

上の図では、赤い円はポイントを表し、線は任意の光線を表しています。 上側の点では、2 つの任意の光線がそれぞれ偶数個の線分を通過します。 そのため、ポイントがあるリングは塗りつぶされません。 下側の点では、2 つの任意の光線がそれぞれ奇数個の線分を通過します。 そのため、ポイントがあるリングは塗りつぶされます。

Nonzero

Nonzero のルールでは、あるポイントから任意の方向に無限に伸びる射線を引いてから、図形のセグメントがこの射線と交わる場所を調べます。 カウントは 0 から始まり、セグメントが射線を左から右に交差するごとに 1 を追加し、セグメントが射線を右から左に交差するごとに 1 を減算します。 交差のカウント後、結果が 0 の場合は、ポイントは多角形の外側にあります。 それ以外の場合は、内側にあります。

次の XAML の例では、FillRuleNonzero に設定して、複合図形を作成してレンダリングします。

<Path Stroke="Black"
      Fill="#CCCCFF"
      Aspect="Uniform"
      HorizontalOptions="Start">
    <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>

この例では、一連の同心円リングで構成される複合図形が表示されます。

図は、すべて塗りつぶされた 4 つの同心円を表しています。

複合図形では、すべてのリングが塗りつぶされます。 これは、すべてのセグメントが同じ方向で、任意のポイントから引かれた射線は少なくとも 1 つのセグメントと交わり、交差の合計が 0 にならないためです。

図は、前の図の円に有効矢印を付けたものと、円と交差するごとに + 1 という注釈が付けられた射線を表しています。

たとえば、上の図で、赤い矢印はセグメントの描画方向を表し、黒い矢印は最も内側のリング内のポイントから引いた任意の射線を表しています。 値 0 から開始し、セグメントは左から右に射線と交わるため、射線が交わるセグメントごとに値 1 が加算されます。

Nonzero の塗りつぶしルールの動作をよりわかりやすく説明するには、描画方向の異なる複数のセグメントから構成される、より複雑な図形が必要になります。 次の XAML の例では、前の例と同様の形状を作成しますが、EllipseGeometry ではなく PathGeometry を使用して作成される点が異なります。

<Path Stroke="Black"
      Fill="#CCCCFF">
     <Path.Data>
         <GeometryGroup FillRule="Nonzero">
             <PathGeometry>
                 <PathGeometry.Figures>
                     <!-- Inner ring -->
                     <PathFigure StartPoint="120,120">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="50,50"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,120" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Second ring -->
                     <PathFigure StartPoint="120,100">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="70,70"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,100" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Third ring  -->
                         <PathFigure StartPoint="120,70">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="100,100"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,70" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Outer ring -->
                     <PathFigure StartPoint="120,300">
                         <PathFigure.Segments>
                             <ArcSegment Size="130,130"
                                         IsLargeArc="True"
                                         SweepDirection="Clockwise"
                                         Point="140,300" />
                         </PathFigure.Segments>
                     </PathFigure>
                 </PathGeometry.Figures>
             </PathGeometry>
         </GeometryGroup>
     </Path.Data>
 </Path>

この例では、閉じていない一連の円弧セグメントが描画されます。

図は、一番外側と外側から 3 番目の円が塗りつぶされた 4 つの同心円を表しています。

上の図では、中心から 3 番目の円弧は塗りつぶされていません。 これは、射線がそのパスでセグメントと交わるときの値の合計が 0 であるためです。

図は、前の図の円に有効矢印を付けたものと、円と交差するごとに + 1 または - 1 という注釈が付けられた 2 つの射線を表しています。

上の図では、赤い円はポイントを表し、黒い線は塗りつぶされていない領域のポイントから移動する任意の光線を表し、赤い矢印はセグメントが描画される方向を表しています。 この図からわかるように、射線がセグメントと交わるときの値の合計はゼロです。

  • 斜め右に移動する任意の光線は、異なる方向に走る 2 つのセグメントを横切ります。 そのため、セグメントは互いに打ち消し合い、値はゼロになります。
  • 斜め左に移動する任意の光線は、合計 6 つのセグメントを横切ります。 ただし、交差は互いに打ち消し合い、最終的な合計はゼロになります。

合計がゼロの場合、リングは塗りつぶされません。