Partager via


Types de remplissage des tracés

Découvrir les différents effets possibles avec les types de remplissage de chemin SkiaSharp

Deux contours d’un chemin peuvent se chevaucher et les lignes qui composent un seul contour peuvent se chevaucher. Toute zone fermée peut être remplie, mais vous ne souhaiterez peut-être pas remplir toutes les zones fermées. Voici un exemple :

Étoile à cinq pointes partiellement filles

Tu as un peu de contrôle sur ça. L’algorithme de remplissage est régi par la SKFillType propriété de SKPath, que vous définissez sur un membre de l’énumération SKPathFillType :

  • Winding, valeur par défaut
  • EvenOdd
  • InverseWinding
  • InverseEvenOdd

Les algorithmes ventinés et impairs déterminent si une zone fermée est remplie ou non remplie en fonction d’une ligne hypothétique tirée de cette zone à l’infini. Cette ligne traverse une ou plusieurs lignes de limite qui composent le chemin d’accès. Avec le mode d’enroulement, si le nombre de lignes de limite dessinées dans une direction équilibre le nombre de lignes dessinées dans l’autre direction, la zone n’est pas remplie. Sinon, la zone est remplie. L’algorithme impair remplit une zone si le nombre de lignes de limite est impair.

Avec de nombreux chemins de routine, l’algorithme enroulement remplit souvent toutes les zones fermées d’un chemin. L’algorithme pair produit généralement des résultats plus intéressants.

L’exemple classique est une étoile à cinq pointes, comme illustré dans la page Étoile à cinq pointes . Le fichier FivePointedStarPage.xaml instancie deux Picker affichages pour sélectionner le type de remplissage du chemin et si le chemin est tracé ou rempli ou les deux, et dans quel ordre :

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:skia="clr-namespace:SkiaSharp;assembly=SkiaSharp"
             xmlns:skiaforms="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="SkiaSharpFormsDemos.Paths.FivePointedStarPage"
             Title="Five-Pointed Star">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Picker x:Name="fillTypePicker"
                Title="Path Fill Type"
                Grid.Row="0"
                Grid.Column="0"
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type skia:SKPathFillType}">
                    <x:Static Member="skia:SKPathFillType.Winding" />
                    <x:Static Member="skia:SKPathFillType.EvenOdd" />
                    <x:Static Member="skia:SKPathFillType.InverseWinding" />
                    <x:Static Member="skia:SKPathFillType.InverseEvenOdd" />
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <Picker x:Name="drawingModePicker"
                Title="Drawing Mode"
                Grid.Row="0"
                Grid.Column="1"
                Margin="10"
                SelectedIndexChanged="OnPickerSelectedIndexChanged">
            <Picker.ItemsSource>
                <x:Array Type="{x:Type x:String}">
                    <x:String>Fill only</x:String>
                    <x:String>Stroke only</x:String>
                    <x:String>Stroke then Fill</x:String>
                    <x:String>Fill then Stroke</x:String>
                </x:Array>
            </Picker.ItemsSource>
            <Picker.SelectedIndex>
                0
            </Picker.SelectedIndex>
        </Picker>

        <skiaforms:SKCanvasView x:Name="canvasView"
                                Grid.Row="1"
                                Grid.Column="0"
                                Grid.ColumnSpan="2"
                                PaintSurface="OnCanvasViewPaintSurface" />
    </Grid>
</ContentPage>

Le fichier code-behind utilise les deux Picker valeurs pour dessiner une étoile à cinq pointes :

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
    float radius = 0.45f * Math.Min(info.Width, info.Height);

    SKPath path = new SKPath
    {
        FillType = (SKPathFillType)fillTypePicker.SelectedItem
    };
    path.MoveTo(info.Width / 2, info.Height / 2 - radius);

    for (int i = 1; i < 5; i++)
    {
        // angle from vertical
        double angle = i * 4 * Math.PI / 5;
        path.LineTo(center + new SKPoint(radius * (float)Math.Sin(angle),
                                        -radius * (float)Math.Cos(angle)));
    }
    path.Close();

    SKPaint strokePaint = new SKPaint
    {
        Style = SKPaintStyle.Stroke,
        Color = SKColors.Red,
        StrokeWidth = 50,
        StrokeJoin = SKStrokeJoin.Round
    };

    SKPaint fillPaint = new SKPaint
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Blue
    };

    switch ((string)drawingModePicker.SelectedItem)
    {
        case "Fill only":
            canvas.DrawPath(path, fillPaint);
            break;

        case "Stroke only":
            canvas.DrawPath(path, strokePaint);
            break;

        case "Stroke then Fill":
            canvas.DrawPath(path, strokePaint);
            canvas.DrawPath(path, fillPaint);
            break;

        case "Fill then Stroke":
            canvas.DrawPath(path, fillPaint);
            canvas.DrawPath(path, strokePaint);
            break;
    }
}

Normalement, le type de remplissage de chemin doit affecter uniquement les remplissages et non les traits, mais les deux Inverse modes affectent à la fois les remplissages et les traits. Pour les remplissages, les deux Inverse types remplissent les zones opposées afin que la zone en dehors de l’étoile soit remplie. Pour les traits, les deux Inverse types colorent tout sauf le trait. L’utilisation de ces types de remplissage inverses peut produire des effets impairs, car la capture d’écran iOS montre :

Capture d’écran triple de la page Étoile à cinq pointes

La capture d’écran Android montre les effets typiques pairs et ventlants, mais l’ordre du trait et le remplissage affectent également les résultats.

L’algorithme d’enroulement dépend de la direction que les lignes sont dessinées. En règle générale, lorsque vous créez un chemin d’accès, vous pouvez contrôler cette direction lorsque vous spécifiez que les lignes sont dessinées d’un point à un autre. Toutefois, la SKPath classe définit également des méthodes comme AddRect et AddCircle qui dessinent des contours entiers. Pour contrôler la façon dont ces objets sont dessinés, les méthodes incluent un paramètre de type SKPathDirection, qui a deux membres :

  • Clockwise
  • CounterClockwise

Les méthodes qui SKPath incluent un SKPathDirection paramètre lui donnent une valeur Clockwisepar défaut .

La page Cercles qui se chevauchent crée un chemin avec quatre cercles qui se chevauchent avec un type de remplissage de chemin pair :

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    SKPoint center = new SKPoint(info.Width / 2, info.Height / 2);
    float radius = Math.Min(info.Width, info.Height) / 4;

    SKPath path = new SKPath
    {
        FillType = SKPathFillType.EvenOdd
    };

    path.AddCircle(center.X - radius / 2, center.Y - radius / 2, radius);
    path.AddCircle(center.X - radius / 2, center.Y + radius / 2, radius);
    path.AddCircle(center.X + radius / 2, center.Y - radius / 2, radius);
    path.AddCircle(center.X + radius / 2, center.Y + radius / 2, radius);

    SKPaint paint = new SKPaint()
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Cyan
    };

    canvas.DrawPath(path, paint);

    paint.Style = SKPaintStyle.Stroke;
    paint.StrokeWidth = 10;
    paint.Color = SKColors.Magenta;

    canvas.DrawPath(path, paint);
}

Il s’agit d’une image intéressante créée avec un minimum de code :

Capture d’écran triple de la page Cercles qui se chevauchent