Types de remplissage des tracés
Découvrir les différents effets possibles avec les types de remplissage de chemin d’accès 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 potentiellement être remplie, mais vous ne souhaiterez peut-être pas remplir toutes les zones fermées. Voici un exemple :
Vous avez 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éfautEvenOdd
InverseWinding
InverseEvenOdd
Les algorithmes d’enroulement et d’impairs pairs déterminent si une zone fermée est remplie ou non remplie en fonction d’une ligne hypothétique tirée de cette zone vers l’infini. Cette ligne traverse une ou plusieurs lignes limites qui composent le chemin d’accès. Avec le mode enroulement, si le nombre de lignes limites dessinées dans une direction équilibre le nombre de lignes dessinées dans l’autre sens, la zone n’est pas remplie. Sinon, la zone est remplie. L’algorithme pair-impair remplit une zone si le nombre de lignes limites est impair.
Avec de nombreux chemins de routine, l’algorithme de bobage remplit souvent toutes les zones fermées d’un chemin. L’algorithme pair-impair produit généralement des résultats plus intéressants.
L’exemple classique est une star à cinq branches, comme illustré dans la page Étoile à cinq branches. Le fichier FivePointedStarPage.xaml instancie deux Picker
affichages pour sélectionner le type de remplissage du chemin d’accès et déterminer 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 un star à cinq points :
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 des zones opposées afin que la zone située à l’extérieur du star soit remplie. Pour les traits, les deux Inverse
types colorent tout sauf le trait. L’utilisation de ces types de remplissage inverse peut produire des effets étranges, comme le montre la capture d’écran iOS :
La capture d’écran Android montre les effets pairs et sinistrés typiques, mais l’ordre du trait et du remplissage affecte également les résultats.
L’algorithme d’enroulement dépend de la direction dans laquelle 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 en spécifiant que les lignes sont dessinées d’un point à un autre. Toutefois, la SKPath
classe définit également des méthodes telles AddRect
que 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 dans SKPath
qui incluent un SKPathDirection
paramètre lui donnent la valeur par défaut .Clockwise
La page Cercles de chevauchement crée un chemin avec quatre cercles qui se chevauchent avec un type de remplissage de chemin impair 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 :