次の方法で共有


SkiaSharp のパスの基本

"つながった直線と曲線を組み合わせるための SkiaSharp SKPath について調べます"

グラフィックス パスの最も重要な機能の 1 つは、複数の線をつなげる必要がある場合とつなげることができない場合を定義する機能です。 次の 2 つの三角形の頂点が示すように、その違いが重要になる場合があります。

接続された線と切断された線の違いを示す 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 の呼び出しで輪郭が終了します。 この違いは重要です。

[2 つの三角形の輪郭] ページのトリプル スクリーンショット

ご覧のとおり、最初の輪郭は明らかに 3 本のつながった直線の連続ですが、終点と始点はつながっていません。 2 本の直線は頂点で重なっています。 2 番目の輪郭は明らかに閉じており、1 つ少ない LineTo の呼び出しで実現されました。これは、Close メソッドによって、輪郭を閉じるための最後の直線が自動的に追加されるためです。

SKCanvasDrawPath メソッドを 1 つだけ定義します。このデモでは、パスを塗りつぶしてストロークするためにこのメソッドが 2 回呼び出されます。 閉じていない輪郭も含め、すべての輪郭は塗りつぶされます。 閉じていないパスを塗りつぶすために、輪郭の始点と終点の間に線が存在すると見なされます。 最初の輪郭から最後の LineTo を削除するか、2 番目の輪郭から Close 呼び出しを削除すると、各輪郭には 2 つの辺しかありませんが、三角形のように塗りつぶされます。

SKPath は、他にも多くのメソッドとプロパティを定義します。 次のメソッドは、パスに輪郭全体を追加します。パスは、メソッドに応じて閉じる場合と閉じない場合があります。

SKPath オブジェクトはジオメトリ (一連の点と接続) のみを定義することに注意してください。 SKPathSKPaint オブジェクトを組み合わせる場合にのみ、パスは特定の色、ストローク幅などでレンダリングされます。 また、DrawPath メソッドに渡される SKPaint オブジェクトがパス全体の特性を定義することにも注意してください。 複数の色を必要とするものを描画する場合は、色ごとに個別のパスを使用する必要があります。

線の始点と終点の外観がストローク キャップによって定義されるのと同様に、2 本の線の間の接続の外観は "ストローク結合" によって定義されます。 これを指定するには、SKPaintStrokeJoin プロパティを 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;
    }
}

実行中のプログラムを次に示します。

[Stroke Joins] ページのトリプル スクリーンショット

マイター結合では、線がつながる部分が鋭角の点で構成されます。 2 本の線が小さい角度で結合すると、マイター結合は非常に長くなる可能性があります。 マイター結合が過度に長くなるのを防ぐには、マイター結合の長さを、SKPaintStrokeMiter プロパティの値で制限します。 この長さを超えるマイター結合は切り取られ、ベベル結合になります。