SkiaSharp のパスの基本
"つながった直線と曲線を組み合わせるための SkiaSharp SKPath について調べます"
グラフィックス パスの最も重要な機能の 1 つは、複数の線をつなげる必要がある場合とつなげることができない場合を定義する機能です。 次の 2 つの三角形の頂点が示すように、その違いが重要になる場合があります。
グラフィック パスは、SKPath
オブジェクトによってカプセル化されます。 パスは、1 つまたは複数の輪郭のコレクションです。 各輪郭は、つながった直線と曲線のコレクションです。 輪郭は互いにつながっていませんが、視覚的に重なる可能性があります。 場合によっては、1 つの輪郭がそれ自体と重なることがあります。
通常、輪郭は、SKPath
の次のメソッドを呼び出すことで開始されます。
MoveTo
: 新しい輪郭を開始する
このメソッドの引数は、単一の点です。これは、SKPoint
値として、または X と Y の個別の座標として表すことができます。 MoveTo
の呼び出しにより、輪郭の始点と最初の "現在の点" が確立されます。 次のメソッドを呼び出して、現在の点から、メソッドで指定された点 (これが新しい現在の点になります) まで直線または曲線で輪郭を続けることができます。
LineTo
: 直線をパスに追加するArcTo
: 弧 (円または楕円の円周上の線) を追加するCubicTo
: 3 次ベジェ スプラインを追加するQuadTo
: 2 次ベジエ スプラインを追加するConicTo
: 円錐曲線 (楕円、放物線、双曲線) を正確にレンダリングできる有理 2 次ベジエ スプラインを追加する
これら 5 つのメソッドには、直線または曲線を記述するために必要なすべての情報は含まれていません。 これら 5 つのメソッドはそれぞれ、その直前のメソッド呼び出しによって確立された現在の点と組み合わせて動作します。 たとえば、LineTo
メソッドは現在の点に基づいて輪郭に直線を追加するため、LineTo
へのパラメータは 1 つの点のみです。
SKPath
クラスは、これら 6 つのメソッドと同じ名前ですが、先頭に R
が付く次のメソッドも定義します。
R
は、"相対" を表します。 これらのメソッドは、R
が付かない対応するメソッドと構文は同じですが、現在の点に対して相対的です。 これらは、1 つのメソッドを複数回呼び出してパスの同様の部分を描画する場合に便利です。
輪郭は、新しい輪郭を開始する MoveTo
または RMoveTo
の別の呼び出し、または輪郭を閉じる Close
の呼び出しで終了します。 Close
メソッドは、現在の点から輪郭の最初の点まで直線を自動的に追加し、パスを閉じたものとしてマークします。これは、パスがストローク キャップなしでレンダリングされることを意味します。
開いた輪郭と閉じた輪郭の違いは、[2 つの三角形の輪郭]ページに示されています。このページでは、2 つの輪郭を持つ SKPath
オブジェクトを使用して 2 つの三角形をレンダリングします。 最初の輪郭は開いており、2 番目の輪郭は閉じています。 TwoTriangleContoursPage
クラスは次のようになります。
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
// Create the path
SKPath path = new SKPath();
// Define the first contour
path.MoveTo(0.5f * info.Width, 0.1f * info.Height);
path.LineTo(0.2f * info.Width, 0.4f * info.Height);
path.LineTo(0.8f * info.Width, 0.4f * info.Height);
path.LineTo(0.5f * info.Width, 0.1f * info.Height);
// Define the second contour
path.MoveTo(0.5f * info.Width, 0.6f * info.Height);
path.LineTo(0.2f * info.Width, 0.9f * info.Height);
path.LineTo(0.8f * info.Width, 0.9f * info.Height);
path.Close();
// Create two SKPaint objects
SKPaint strokePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Magenta,
StrokeWidth = 50
};
SKPaint fillPaint = new SKPaint
{
Style = SKPaintStyle.Fill,
Color = SKColors.Cyan
};
// Fill and stroke the path
canvas.DrawPath(path, fillPaint);
canvas.DrawPath(path, strokePaint);
}
最初の輪郭は、SKPoint
値ではなく X 座標と Y 座標を使用した MoveTo
の呼び出しと、それに続く三角形の 3 辺を描画するための LineTo
の 3 回の呼び出しで構成されます。 2 番目の輪郭には、LineTo
の呼び出しが 2 回だけありますが、輪郭を閉じる Close
の呼び出しで輪郭が終了します。 この違いは重要です。
ご覧のとおり、最初の輪郭は明らかに 3 本のつながった直線の連続ですが、終点と始点はつながっていません。 2 本の直線は頂点で重なっています。 2 番目の輪郭は明らかに閉じており、1 つ少ない LineTo
の呼び出しで実現されました。これは、Close
メソッドによって、輪郭を閉じるための最後の直線が自動的に追加されるためです。
SKCanvas
は DrawPath
メソッドを 1 つだけ定義します。このデモでは、パスを塗りつぶしてストロークするためにこのメソッドが 2 回呼び出されます。 閉じていない輪郭も含め、すべての輪郭は塗りつぶされます。 閉じていないパスを塗りつぶすために、輪郭の始点と終点の間に線が存在すると見なされます。 最初の輪郭から最後の LineTo
を削除するか、2 番目の輪郭から Close
呼び出しを削除すると、各輪郭には 2 つの辺しかありませんが、三角形のように塗りつぶされます。
SKPath
は、他にも多くのメソッドとプロパティを定義します。 次のメソッドは、パスに輪郭全体を追加します。パスは、メソッドに応じて閉じる場合と閉じない場合があります。
AddRect
AddRoundedRect
AddCircle
AddOval
AddArc
: 楕円の円周に曲線を追加するAddPath
: 現在のパスに別のパスを追加するAddPathReverse
: 別のパスを逆に追加する
SKPath
オブジェクトはジオメトリ (一連の点と接続) のみを定義することに注意してください。 SKPath
と SKPaint
オブジェクトを組み合わせる場合にのみ、パスは特定の色、ストローク幅などでレンダリングされます。 また、DrawPath
メソッドに渡される SKPaint
オブジェクトがパス全体の特性を定義することにも注意してください。 複数の色を必要とするものを描画する場合は、色ごとに個別のパスを使用する必要があります。
線の始点と終点の外観がストローク キャップによって定義されるのと同様に、2 本の線の間の接続の外観は "ストローク結合" によって定義されます。 これを指定するには、SKPaint
の StrokeJoin
プロパティを SKStrokeJoin
列挙体のメンバーに設定します。
Miter
: 点結合Round
: ラウンド結合Bevel
: 切り取り結合
[ストローク結合] ページには、これら 3 つのストローク結合が、[ストローク キャップ] ページと同様のコードで示されています。 これは、StrokeJoinsPage
クラスの PaintSurface
イベント ハンドラーです。
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
SKPaint textPaint = new SKPaint
{
Color = SKColors.Black,
TextSize = 75,
TextAlign = SKTextAlign.Right
};
SKPaint thickLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Orange,
StrokeWidth = 50
};
SKPaint thinLinePaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
StrokeWidth = 2
};
float xText = info.Width - 100;
float xLine1 = 100;
float xLine2 = info.Width - xLine1;
float y = 2 * textPaint.FontSpacing;
string[] strStrokeJoins = { "Miter", "Round", "Bevel" };
foreach (string strStrokeJoin in strStrokeJoins)
{
// Display text
canvas.DrawText(strStrokeJoin, xText, y, textPaint);
// Get stroke-join value
SKStrokeJoin strokeJoin;
Enum.TryParse(strStrokeJoin, out strokeJoin);
// Create path
SKPath path = new SKPath();
path.MoveTo(xLine1, y - 80);
path.LineTo(xLine1, y + 80);
path.LineTo(xLine2, y + 80);
// Display thick line
thickLinePaint.StrokeJoin = strokeJoin;
canvas.DrawPath(path, thickLinePaint);
// Display thin line
canvas.DrawPath(path, thinLinePaint);
y += 3 * textPaint.FontSpacing;
}
}
実行中のプログラムを次に示します。
マイター結合では、線がつながる部分が鋭角の点で構成されます。 2 本の線が小さい角度で結合すると、マイター結合は非常に長くなる可能性があります。 マイター結合が過度に長くなるのを防ぐには、マイター結合の長さを、SKPaint
の StrokeMiter
プロパティの値で制限します。 この長さを超えるマイター結合は切り取られ、ベベル結合になります。