パスの塗りつぶしの種類
SkiaSharp パスの各塗りつぶしタイプで可能なさまざまな効果を検出する
パスの中の2つの輪郭が重なることもあれば、1つの輪郭を構成する線が重なることもあります。 囲まれた領域は塗りつぶすことができますが、囲まれた領域をすべて塗りつぶしたくない場合もあるでしょう。 次に例を示します。
これに関してコントロールできることは限られています。 塗りつぶしアルゴリズムは、SKPathFillType
列挙型のメンバーに設定した SKPath
の SKFillType
プロパティによって制御されます。
Winding
(既定値)EvenOdd
InverseWinding
InverseEvenOdd
巻き取りアルゴリズムと偶数奇数アルゴリズムの両方が、その領域から無限大まで引かれた仮定の線に基づいて、囲まれた領域が塗りつぶされるか、または塗りつぶされないかを決定します。 その線は、パスを構成する 1 つ以上の境界線を横切ります。 巻き取りモードでは、一方向に引かれた境界線の本数と、他方向に引かれた境界線の本数が釣り合っている場合、その領域は塗りつぶされません。 それ以外の場合は、その領域は塗りつぶされます。 境界線の数が奇数の場合、偶数奇数アルゴリズムによりその領域が塗りつぶされます。
多くのルーチン パスでは、多くの場合、巻き取りアルゴリズムによりパスの囲まれたすべての領域が塗りつぶされます。 偶数奇数アルゴリズムは、一般に、より興味深い結果を生成します。
典型的な例は、「五芒星」のページで示されているように、五芒星です。 FivePointedStarPage.xaml ファイルは、2 つの Picker
ビューのインスタンスを作成して、パスの塗りつぶしの種類と、パスがストロークされるか、塗りつぶされるか、またはその両方か、さらにその順序を選択します。
<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>
分離コード ファイルでは、両方の Picker
値を使用して、五芒星を描画します。
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;
}
}
通常、パスの塗りつぶしの種類はストロークではなく塗りつぶしにのみ影響しますが、2 つの Inverse
モードでは塗りつぶしとストロークの両方に影響します。 塗りつぶしの場合、2 つの Inverse
型は、星の外側の領域が塗りつぶされるように、反対方向に領域を塗りつぶします。 ストロークの場合、2 つの Inverse
型はストローク以外のすべてを色付けします。 iOS のスクリーンショットが示すように、これらの逆塗りつぶしタイプを使用すると、いくつかの変わった効果が得られます。
Android のスクリーンショットは、一般的な偶数奇数効果と巻き取り効果を示していますが、ストロークと塗りつぶしの順序も結果に影響します。
巻き取りアルゴリズムは、線が引かれる方向に依存します。 通常、パスを作成するときに、ある点から別の点へ線を引くように指定することで、その方向をコントロールできます。 ただし、SKPath
クラスでは、輪郭全体を描画する AddRect
や AddCircle
などのメソッドも定義されます。 これらのオブジェクトの描画方法をコントロールするために、これらのメソッドには 2 つのメンバーを持つ SKPathDirection
型のパラメーターが含まれています。
Clockwise
CounterClockwise
SKPath
のメソッドに SKPathDirection
パラメータが含まれている場合、既定値は Clockwise
になります。
[重なり合う円] ページでは、偶数奇数パスの塗りつぶしタイプを使用して、4つの円が重なり合うパスを作成します。
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);
}
これは、最小限のコードで作成された興味深いイメージです。