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.

Cerchio composto da anelli concentrici di serie con colori alternati.

Nella figura precedente si noti che il centro e il terzo anello non vengono 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:

Diagramma che mostra i raggi EvenOdd disegnati nel cerchio.

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 la figura seguente come risultato:

Cerchio composto da una serie concentrica tutti riempiti con lo stesso colore.

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.

Diagramma che mostra il valore della proprietà FillRule uguale a Diverso da zero.

Per illustrare meglio il comportamento della Nonzero regola è necessaria una forma più complessa con segmenti in esecuzione in direzioni diverse. 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 piuttosto che 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.

Cerchio composto da anelli concentrici di serie con colori alternati con il terzo arco non riempito.

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.

Diagramma che mostra segmenti di attraversamento arbitrario dei raggi.

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 di FillRule) che lo chiude.

Diagramma che mostra i segmenti FillRule sempre chiusi.

Esempio

Vedere anche