Condividi tramite


Procedura: Controllare il riempimento di una forma composita

La proprietà FillRule di un GeometryGroup o di un PathGeometry specifica una "regola" utilizzata dalla forma combinata 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: Questa regola determina se un punto si trova nell'area di riempimento disegnando un raggio da quel punto all'infinito in qualsiasi direzione e conteggiando il numero di segmenti di percorso all'interno della forma specificata che il raggio interseca. Se questo numero è dispari, il punto si trova all'interno; se anche, il punto è 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 una serie di anelli concentrici con colori alternati.

Nella figura precedente si noti che il centro e il terzo anello non sono riempiti. Questo perché un raggio disegnato 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.

Diverso da zero: Questa regola determina se un punto si trova nell'area di riempimento del percorso disegnando un raggio da quel punto all'infinito in qualsiasi direzione e quindi esaminando i punti in cui un segmento della forma attraversa il raggio. A partire da un conteggio pari a zero, aggiungere una ogni volta che un segmento attraversa il raggio da sinistra a destra e sottrae uno ogni volta che un segmento di percorso attraversa il raggio da destra a sinistra. Dopo aver conteggiato gli incroci, se il risultato è zero, il punto si trova all'esterno del percorso. In caso contrario, è dentro.

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

Cerchio composto da anelli concentrici di serie tutti riempiti con lo stesso colore.

Come si può vedere, tutti gli anelli sono riempiti. Ciò è dovuto al fatto che tutti i segmenti si muovono nella stessa direzione e quindi un raggio tracciato da qualsiasi punto intersecherà uno o più segmenti e la somma delle intersezioni 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 zero, per ogni segmento che attraversa il raggio, viene aggiunto un valore pari a uno perché il segmento attraversa il raggio da sinistra a destra.

Diagramma che mostra il valore della proprietà FillRule uguale a 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.

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 è riempito. Nella figura seguente viene illustrato il motivo per cui si tratta. Nella figura le frecce rosse rappresentano la direzione in cui vengono disegnati i segmenti. Le due frecce bianche rappresentano due raggi arbitrari che si spostano da un punto nell'area "non riempita". Come si può notare nella figura, la somma dei valori di un determinato raggio che attraversa i segmenti nel percorso è zero. Come definito in precedenza, una somma pari a zero indica che il punto non fa parte della geometria (non parte del riempimento) mentre una somma che non è zero, incluso un valore negativo, fa parte della geometria.

Diagramma che mostra i raggi arbitrari che attraversano i segmenti.

Annotazioni

Ai fini di FillRule, tutte le forme vengono considerate chiuse. Se c'è un divario in un segmento, disegnare una linea immaginaria per chiuderla. Nell'esempio precedente sono presenti piccole lacune negli anelli. Dato questo, si potrebbe aspettare che un raggio che attraversa il divario dia un risultato diverso rispetto a un raggio che si muove in un'altra direzione. Di seguito è riportata un'illustrazione ingrandita di una di queste lacune e del "segmento immaginario" (segmento disegnato ai fini dell'applicazione del FillRule) che la chiude.

Diagramma che mostra i segmenti FillRule sempre chiusi.

Esempio

Vedere anche