Formas de Xamarin.Forms: reglas de relleno

Varias clases de formas de Xamarin.Forms tienen propiedades FillRule, de tipo FillRule. Estas incluyen Polygon , Polyline y GeometryGroup .

La enumeración FillRule define los miembros EvenOdd y Nonzero. Cada miembro representa una regla diferente para determinar si un punto está en la región de relleno de una forma.

Importante

Para fines de reglas de relleno, todas las formas se consideran cerradas.

EvenOdd

La regla de relleno EvenOdd dibuja un rayo desde el punto hasta el infinito en cualquier dirección y cuenta el número de segmentos dentro de la forma que cruza el rayo. Si este número es impar, el punto está dentro. Si este número es par, el punto está fuera.

En el ejemplo de XAML siguiente se crea y se representa una forma compuesta, con FillRule estableciendo el valor predeterminado en 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>

En este ejemplo, se muestra una forma compuesta formada por una serie de anillos concéntricos:

Forma compuesta con regla de relleno EvenOdd

En la ilustración anterior, observa que el centro y el tercer anillo no se han rellenado. Esto se debe a que un radio dibujado desde cualquier punto dentro de esos dos anillos pasa a través de un número par de segmentos.

Forma compuesta anotada con regla de relleno EvenOdd

En la imagen anterior, los círculos rojos representan puntos y las líneas representan rayos arbitrarios. Para el punto superior, los dos rayos arbitrarios pasan a través de un número par de segmentos de línea. Por lo tanto, el anillo en el que está el punto no se rellena. Para el punto inferior, los dos rayos arbitrarios pasan a través de un número impar de segmentos de línea. Por lo tanto, el anillo en el que está el punto no se rellena.

Distinto a cero

La regla de relleno Nonzero dibuja un rayo desde ese punto hasta el infinito en cualquier dirección y examina después los lugares donde un segmento de la forma cruza el rayo. El recuento comienza en cero y se incrementa cada vez que un segmento cruza el rayo de izquierda a derecha y disminuye cada vez que un segmento cruza el rayo de derecha a izquierda. Después de contar los cruces, si el resultado es cero, el punto está fuera del polígono. De lo contrario, está dentro.

En el ejemplo de XAML siguiente se crea y se representa una forma compuesta, con FillRule establecido en Nonzero:

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

En este ejemplo, se muestra una forma compuesta formada por una serie de anillos concéntricos:

En el diagrama se muestran cuatro círculos concéntricos, todos rellenos.

En la forma compuesta, observa que todos los anillos se rellenan. Esto es porque todos los segmentos se ejecutan en la misma dirección de modo que un rayo dibujado desde cualquier punto cruzará uno o más segmentos y la suma de los cruces no será igual a cero.

El diagrama muestra los círculos del diagrama anterior con flechas direccionales y un rayo anotado con + 1 por cada círculo que atraviesa.

Por ejemplo, en la ilustración siguiente, las flechas rojas representan la dirección en que se dibujan los segmentos y la flecha blanca representa un rayo trazado desde un punto en el anillo más profundo. A partir de un valor de cero, para cada segmento que cruza el radio, se agrega un valor de uno porque el segmento cruza el radio de izquierda a derecha.

Para mostrar mejor el comportamiento de la regla de relleno Nonzero es necesaria una forma más compleja con segmentos que se ejecutan en diferentes direcciones. En el ejemplo de XAML siguiente se crea una forma similar al ejemplo anterior, salvo que se crea con un elemento PathGeometry en lugar de un EllipseGeometry:

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

En este ejemplo, se dibuja una serie de segmentos de arco, que no están cerrados:

En el diagrama se muestran cuatro círculos concéntricos, con el más externo y el tercero rellenos.

En la imagen anterior, el tercer arco del centro no se rellena. Como puede observarse en la ilustración, la suma de los valores de un rayo determinado que cruza los segmentos en su trazado es cero:

Diagrama que muestra los círculos del diagrama anterior con flechas direccionales y dos rayos anotados con + 1 o - 1 por cada círculo que atraviesan.

En la imagen anterior, el círculo rojo representa un punto, las líneas negras representan rayos arbitrarios que salen del punto de la región no rellenada y las flechas rojas representan la dirección en la que se dibujan los segmentos. Como puede observarse en la ilustración, la suma de los valores de los rayos que cruzan los segmentos es cero.

  • El rayo arbitrario que viaja diagonalmente a la derecha cruza dos segmentos que van en direcciones diferentes. Por lo tanto, los segmentos se cancelan entre sí, lo que proporciona un valor de cero.
  • El rayo arbitrario que viaja diagonalmente a la izquierda cruza un total de seis segmentos. Pero los cruces se cancelan entre sí para que cero sea la suma final.

Una suma de cero da como resultado que el anillo no se rellene.