Nozioni di base sul percorso in SkiaSharp

Esplorare l'oggetto SKPath SkiaSharp per combinare linee e curve connesse

Una delle caratteristiche più importanti del percorso grafico è la possibilità di definire quando devono essere connesse più linee e quando non devono essere connesse. La differenza può essere significativa, come illustrato dai primi di questi due triangoli:

Due triangoli che mostrano la differenza tra le linee connesse e disconnesse

Un percorso grafico viene incapsulato dall'oggetto SKPath . Un percorso è una raccolta di uno o più contorni. Ogni contorno è una raccolta di linee e curve collegate. I contorni non sono collegati tra loro, ma potrebbero sovrapporsi visivamente. A volte un singolo contorno può sovrapporsi.

Un contorno inizia in genere con una chiamata al metodo seguente di SKPath:

  • MoveTo per iniziare un nuovo contorno

L'argomento di tale metodo è un singolo punto, che è possibile esprimere come SKPoint valore o come coordinate X e Y separate. La MoveTo chiamata stabilisce un punto all'inizio del contorno e un punto corrente iniziale. È possibile chiamare i metodi seguenti per continuare il contorno con una linea o una curva dal punto corrente a un punto specificato nel metodo, che diventa quindi il nuovo punto corrente:

  • LineTo per aggiungere una linea retta al percorso
  • ArcTo per aggiungere un arco, che è una linea sulla circonferenza di un cerchio o di un'ellisse
  • CubicTo per aggiungere una spline di Bezier cubica
  • QuadTo per aggiungere una spline di Bezier quadratica
  • ConicTo per aggiungere una spline di Bezier quadratica razionale, che può eseguire il rendering accurato di sezioni coniche (ellissi, parabole e iperbole)

Nessuno di questi cinque metodi contiene tutte le informazioni necessarie per descrivere la linea o la curva. Ognuno di questi cinque metodi funziona insieme al punto corrente stabilito dalla chiamata al metodo immediatamente precedente. Ad esempio, il LineTo metodo aggiunge una linea retta al contorno in base al punto corrente, quindi il parametro a LineTo è solo un singolo punto.

La SKPath classe definisce anche metodi che hanno gli stessi nomi di questi sei metodi, ma con un all'inizio R :

L'acronimo R di relative. Questi metodi hanno la stessa sintassi dei metodi corrispondenti senza R ma sono relativi al punto corrente. Questi sono utili per disegnare parti simili di un percorso in un metodo che chiami più volte.

Un contorno termina con un'altra chiamata a MoveTo o RMoveTo, che inizia una nuova contorno o una chiamata a Close, che chiude il contorno. Il Close metodo aggiunge automaticamente una linea retta dal punto corrente al primo punto del contorno e contrassegna il percorso come chiuso, il che significa che verrà eseguito il rendering senza estremità di tratto.

La differenza tra contorni aperti e chiusi è illustrata nella pagina Contorni a due triangoli, che usa un SKPath oggetto con due contorni per eseguire il rendering di due triangoli. Il primo contorno è aperto e il secondo è chiuso. Di seguito è riportata la classe 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);
}

Il primo contorno è costituito da una chiamata a MoveTo utilizzando coordinate X e Y anziché un SKPoint valore, seguite da tre chiamate per disegnare LineTo i tre lati del triangolo. Il secondo contorno ha solo due chiamate a LineTo , ma termina il contorno con una chiamata a Close, che chiude il contorno. La differenza è significativa:

Screenshot triplo della pagina Contorni a due triangoli

Come si può notare, il primo contorno è ovviamente una serie di tre linee collegate, ma la fine non si connette con l'inizio. Le due righe si sovrappongono nella parte superiore. Il secondo contorno è ovviamente chiuso ed è stato eseguito con un minor numero LineTo di chiamate perché il Close metodo aggiunge automaticamente una riga finale per chiudere il contorno.

SKCanvas definisce un DrawPath solo metodo, che in questa dimostrazione viene chiamato due volte per riempire e tracciare il percorso. Tutti i contorni sono riempiti, anche quelli che non sono chiusi. Ai fini del riempimento di percorsi non aperti, si presuppone che esista una linea retta tra i punti iniziale e finale dei contorni. Se si rimuove l'ultimo LineTo dal primo contorno o si rimuove la Close chiamata dal secondo contorno, ogni contorno avrà solo due lati, ma verrà riempito come se fosse un triangolo.

SKPath definisce molti altri metodi e proprietà. I metodi seguenti aggiungono intere contorni al percorso, che potrebbero essere chiusi o non chiusi a seconda del metodo :

Tenere presente che un SKPath oggetto definisce solo una geometria, ovvero una serie di punti e connessioni. Solo quando un oggetto SKPath viene combinato con un SKPaint oggetto è il percorso di cui viene eseguito il rendering con un particolare colore, larghezza del tratto e così via. Tenere inoltre presente che l'oggetto SKPaint passato al DrawPath metodo definisce le caratteristiche dell'intero percorso. Se si desidera disegnare un elemento che richiede diversi colori, è necessario utilizzare un percorso separato per ogni colore.

Proprio come l'aspetto dell'inizio e della fine di una linea è definito da un limite di tratto, l'aspetto della connessione tra due linee è definito da un join di tratto. Per specificare questa impostazione, impostare la StrokeJoin proprietà di SKPaint su un membro dell'enumerazione SKStrokeJoin :

  • Miter per un join pointy
  • Round per un join arrotondato
  • Bevel per un join tritato

La pagina Join tratti mostra questi tre join di tratti con codice simile alla pagina Tratti maiuscole . Questo è il PaintSurface gestore eventi nella StrokeJoinsPage classe :

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;
    }
}

Ecco il programma in esecuzione:

Screenshot triplo della pagina Join tratti

Il miter join è costituito da un punto appuntito in cui le linee si connettono. Quando due linee si uniscono ad un piccolo angolo, il miter join può diventare abbastanza lungo. Per evitare join di miter eccessivamente lunghi, la lunghezza del join del miter è limitata dal valore della StrokeMiter proprietà di SKPaint. Un miter join che supera questa lunghezza viene tagliato fuori per diventare un join di rilievo.