Comment : contrôler le remplissage d'une forme composite

La FillRule propriété d’un GeometryGroup ou d’un PathGeometry, spécifie une « règle » utilisée par la forme composite pour déterminer si un point donné fait partie de la géométrie. Il existe deux valeurs possibles pour FillRule: EvenOdd et Nonzero. Les sections suivantes décrivent comment utiliser ces deux règles.

EvenOdd : cette règle détermine si un point se trouve dans la région de remplissage en dessinant un rayon à partir de ce point vers l’infini dans n’importe quelle direction et en comptant le nombre de segments de tracé dans la forme donnée qui sont coupés par le rayon. Si ce nombre est impair, le point est à l’intérieur ; s’il est pair, le point est à l’extérieur.

Par exemple, le code XAML ci-dessous crée une forme composite composée d’une série d’anneaux concentriques (cible) avec une FillRule valeur définie EvenOddsur .

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

L’illustration suivante montre la forme créée dans l’exemple précédent.

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

Dans l’illustration précédente, notez que le centre et le troisième anneau ne sont pas remplis. En effet, un rayon dessiné à partir de n’importe quel point dans un de ces deux anneaux traverse un nombre pair de segments. Consultez l’illustration suivante :

Diagram showing the EvenOdd rays drawn in the circle.

NonZero : cette règle détermine si un point se trouve dans la région de remplissage du tracé en dessinant un rayon à partir de ce point vers l’infini dans n’importe quelle direction, puis en examinant les emplacements où un segment de la forme coupe le rayon. En commençant à zéro, comptez un point chaque fois qu’un segment coupe le rayon de gauche à droite, et soustrayez un point chaque fois qu’un segment de tracé traverse le rayon de droite à gauche. Comptez ensuite le nombre d’intersections : si le résultat est égal à zéro, le point est à l’extérieur du tracé. Sinon, il est à l’intérieur.

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

À l’aide de l’exemple précédent, une valeur pour NonzeroFillRule donner l’illustration suivante en conséquence :

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

Comme vous pouvez le voir, tous les anneaux sont remplis. En effet, tous les segments s’étendent dans la même direction, ce qui signifie qu’un rayon dessiné à partir de n’importe quel point traversera un ou plusieurs segments et que la somme des intersections ne sera pas égale à zéro. Par exemple, dans l’illustration suivante, les flèches rouges représentent la direction que les segments sont dessinés et la flèche blanche représente un rayon arbitraire s’exécutant à partir d’un point dans l’anneau le plus intérieur. En commençant par une valeur égale à zéro, pour chaque segment que le rayon traverse, une valeur de un est ajoutée car le segment traverse le rayon de gauche à droite.

Diagram showing the FillRule property value equal to Nonzero.

Pour mieux illustrer le comportement d’une Nonzero règle, une forme plus complexe avec des segments s’exécutant dans différentes directions est nécessaire. Le code XAML ci-dessous crée une forme similaire à l’exemple précédent, sauf qu’elle est créée avec un plutôt qu’un PathGeometry arc EllipseGeometry concentrique qui crée quatre arcs concentriques plutôt que des cercles concentriques entièrement fermés.

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

L’illustration suivante montre la forme créée dans l’exemple précédent.

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

Notez que le troisième arc partant du centre n’est pas rempli. L’illustration suivante montre pourquoi c’est le cas. Dans l’illustration, les flèches rouges représentent la direction dans laquelle les segments sont dessinés. Les deux flèches blanches représentent deux rayons arbitraires qui partent d’un point dans la région « non remplie ». Comme le montre l’illustration, la somme des valeurs d’un rayon donné qui traverse les segments dans son tracé est égale à zéro. Comme indiqué ci-dessus, une somme égale à zéro signifie que le point ne fait pas partie de la géométrie (il ne fait pas partie du remplissage) tandis qu’une somme qui n’est pas égale à zéro, y compris une valeur négative, fait partie de la géométrie.

Diagram showing arbitrary rays crossing segments.

Remarque

À des fins de FillRule, toutes les formes sont considérées comme fermées. S’il y a un écart dans un segment, dessinez une ligne imaginaire pour le fermer. Dans l’exemple ci-dessus, on observe existe de petits écarts au niveau des anneaux. On peut donc s’attendre à ce qu’un rayon qui traverse cet écart produise un résultat différent de celui d’un rayon qui s’étend dans une autre direction. Vous trouverez ci-dessous une illustration agrandie de l’une de ces lacunes et du « segment imaginaire » (segment dessiné à des fins d’application du FillRule) qui le ferme.

Diagram showing FillRule segments that are always closed.

Exemple

Voir aussi