Postupy: Řízení výplně složeného tvaru

Vlastnost FillRuleGeometryGroup nebo PathGeometry, určuje "pravidlo", které složený obrazec používá k určení, zda je daný bod součástí geometrie. Existují dvě možné hodnoty pro FillRule: EvenOdd a Nonzero. Následující části popisují, jak tato dvě pravidla používat.

EvenOdd: Toto pravidlo určuje, zda je bod v oblasti výplně vykreslením paprsku z tohoto bodu do nekonečna v libovolném směru a počítáním počtu segmentů cesty v daném tvaru, který paprsk protíná. Pokud je toto číslo liché, bod je uvnitř; je-li dokonce, bod je venku.

Kód XAML níže například vytvoří složený obrazec tvořený řadou soustředných kroužků (cíl) se FillRule sadou na EvenOddhodnotu .

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

Následující obrázek znázorňuje obrazec vytvořený v předchozím příkladu.

A circle made up of a series concentric rings with alternating colors.

Na předchozím obrázku si všimněte, že střed a třetí kruh nejsou vyplněné. Je to proto, že paprsk nakreslený z libovolného bodu v některém z těchto dvou kroužků prochází sudým počtem segmentů. Podívejte se na následující obrázek:

Diagram showing the EvenOdd rays drawn in the circle.

Nenulové: Toto pravidlo určuje, zda je bod v oblasti výplně cesty nakreslením paprsku z tohoto bodu do nekonečna v libovolném směru a následným zkoumáním míst, kde segment obrazce protíná paprsek. Počínaje počtem nul přidejte jeden, pokaždé, když segment protíná paprsek zleva doprava a odčítá ho pokaždé, když segment cesty protíná paprsek zprava doleva. Po počítání přechodů platí, že pokud je výsledek nula, bod je mimo cestu. Jinak je uvnitř.

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

V předchozím příkladu je výsledkem hodnota Nonzero pro FillRule následující obrázek:

A circle made up of a series concentric rings all filled with the same color.

Jak vidíte, všechny kroužky jsou vyplněné. Důvodem je to, že všechny segmenty běží ve stejném směru, a proto paprsk nakreslený z libovolného bodu protíná jeden nebo více segmentů a součet přechodů se nerovná nule. Například na následujícím obrázku znázorňují červené šipky směr vykreslení segmentů a bílá šipka představuje libovolný paprsek spuštěný z bodu v nejvnitřnějším kruhu. Počínaje hodnotou nuly, pro každý segment, který paprsek kříží, je přidána hodnota jednoho, protože segment protíná paprsek zleva doprava.

Diagram showing the FillRule property value equal to Nonzero.

K lepšímu předvedení chování Nonzero pravidla je potřeba složitější tvar se segmenty spuštěnými v různých směrech. Níže uvedený kód XAML vytvoří podobný obrazec jako v předchozím příkladu s tím rozdílem, že se vytvoří spíše se PathGeometry čtyřmi EllipseGeometry soustřednými oblouky a pak zcela uzavřenými soustřednými kruhy.

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

Následující obrázek znázorňuje obrazec vytvořený v předchozím příkladu.

A circle made up of a series concentric rings with alternating colors with the third arc not filled.

Všimněte si, že třetí oblouk ze středu není vyplněn. Následující obrázek ukazuje, proč to je. Na obrázku znázorňují červené šipky směr vykreslení segmentů. Dvě bílé šipky představují dva libovolné paprsky, které se přesouvají z bodu v "nezaplněné" oblasti. Jak je vidět na obrázku, součet hodnot z daného paprsku překračování segmentů v jeho cestě je nula. Jak je uvedeno výše, součet nuly znamená, že bod není součástí geometrie (nikoli část výplně), zatímco součet, který není nulový, včetně záporné hodnoty, je součástí geometrie.

Diagram showing arbitrary rays crossing segments.

Poznámka:

Pro účely FillRulejsou všechny obrazce považovány za uzavřené. Pokud je v segmentu mezera, nakreslete imaginární čáru a zavřete ji. V předchozím příkladu jsou v prstencích malé mezery. Vzhledem k tomu může jeden očekávat paprsek, který prochází mezerou, aby dal jiný výsledek, než ray běží v jiném směru. Níže je zvětšená ilustrace jedné z těchto mezer a "imaginárního segmentu" (segment, který je vykreslen pro účely použití FillRule), který ho zavře.

Diagram showing FillRule segments that are always closed.

Příklad

Viz také