Procedura: controllare il riempimento di una forma composta

La FillRule proprietà di un GeometryGroup oggetto o , PathGeometryspecifica una "regola" utilizzata dalla forma composita per determinare se un determinato punto fa parte della geometria. Esistono due valori possibili per FillRule: EvenOdd e Nonzero. Le sezioni seguenti descrivono come usare queste due regole.

EvenOdd: regola che determina se un punto si trova nell'area di riempimento tracciando un raggio da tale punto verso l'infinito in qualsiasi direzione e contando il numero dei segmenti di tracciato all'interno della forma data intersecati dal raggio. Se questo numero è dispari, il punto è all'interno. Se invece è pari, il punto è all'esterno.

Ad esempio, il codice XAML seguente crea una forma composita costituita da una serie di anelli concentrici (destinazione) con un FillRule oggetto impostato su 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>

La figura seguente mostra la forma creata nell'esempio precedente.

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

Nella figura precedente si noti che il centro e il terzo anello non sono riempiti. poiché un raggio tracciato da qualsiasi punto all'interno di uno di questi due anelli passa attraverso un numero pari di segmenti. Vedere la figura seguente:

Diagram showing the EvenOdd rays drawn in the circle.

NonZero: regola che determina se un punto si trova nell'area di riempimento del tracciato disegnando un raggio da tale punto verso l'infinito in qualsiasi direzione ed esaminando i punti in cui un segmento della forma interseca il raggio. Partendo da zero, aggiungere uno ogni volta che un segmento interseca il raggio da sinistra a destra e sottrarre uno ogni volta che un segmento del tracciato interseca il raggio da destra a sinistra. Contare le intersezioni. Se il risultato è zero, il punto è all'esterno del percorso. In caso contrario, è all'interno.

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

Usando l'esempio precedente, un valore di Nonzero per FillRule restituisce l'illustrazione seguente come risultato:

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

Come si può notare, tutti gli anelli sono riempiti, poiché tutti i segmenti scorrono nella stessa direzione, quindi un raggio tracciato da qualsiasi punto attraverserà uno o più segmenti e la somma delle intersecazioni non sarà uguale a zero. Nell'illustrazione seguente, ad esempio, le frecce rosse rappresentano la direzione in cui vengono tracciati i segmenti e la freccia bianca rappresenta un raggio arbitrario in esecuzione da un punto nell'anello più interno. A partire da un valore pari a zero, per ogni segmento intersecato dal raggio viene aggiunto un valore di uno, poiché il segmento interseca il raggio da sinistra a destra.

Diagram showing the FillRule property value equal to Nonzero.

Per illustrare meglio il comportamento della Nonzero regola, è necessaria una forma più complessa con segmenti in esecuzione in diverse direzioni. Il codice XAML seguente crea una forma simile all'esempio precedente, ad eccezione del fatto che viene creata con un PathGeometry oggetto piuttosto che un EllipseGeometry oggetto che crea quattro archi concentrici anziché cerchi concentrici completamente chiusi.

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

La figura seguente mostra la forma creata nell'esempio precedente.

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

Si noti che il terzo arco dal centro non viene riempito. Nella figura seguente viene illustrato il motivo per cui si tratta. Nella figura le frecce rosse rappresentano la direzione in cui vengono tracciati i segmenti. Le due frecce bianche rappresentano due raggi qualsiasi che partono da un punto nell'area "non riempita". Come si può notare dalla figura, la somma dei valori da un raggio specificato che interseca i segmenti nel suo tracciato è pari a zero. Come definito in precedenza, una somma pari a zero indica che il punto non fa parte della geometria (non fa parte del riempimento), mentre una somma diversa da zero, compresi i valori negativi, fa parte della geometria.

Diagram showing arbitrary rays crossing segments.

Nota

Ai fini di FillRule, tutte le forme vengono considerate chiuse. Se è presente una distanza in un segmento, disegnare una linea immaginaria per chiuderla. Nell'esempio precedente sono presenti piccole distanze negli anelli. In questo caso si potrebbe prevedere un raggio che attraversa la distanza per produrre un risultato diverso da un raggio in un'altra direzione. Di seguito è riportata un'illustrazione ingrandita di una di queste lacune e del "segmento immaginario" (segmento disegnato per l'applicazione FillRuledi ) che lo chiude.

Diagram showing FillRule segments that are always closed.

Esempio

Vedi anche