Condividi tramite


Trasformazione di traslazione

Informazioni su come usare la trasformazione translate per spostare la grafica SkiaSharp

Il tipo più semplice di trasformazione in SkiaSharp è la trasformazione traslazione o traslazione . Questa trasformazione sposta gli oggetti grafici nelle direzioni orizzontali e verticali. In un certo senso, la conversione è la trasformazione più superflua perché in genere è possibile ottenere lo stesso effetto semplicemente modificando le coordinate che si utilizzano nella funzione di disegno. Quando si esegue il rendering di un percorso, tuttavia, tutte le coordinate vengono incapsulate nel percorso, quindi è molto più semplice applicare una trasformazione di conversione per spostare l'intero percorso.

La traduzione è utile anche per l'animazione e per gli effetti di testo semplici:

Ombreggiatura del testo, incisione e rilievo con traduzione

Il Translate metodo in SKCanvas ha due parametri che determinano lo spostamento orizzontale e verticale degli oggetti grafici disegnati successivamente:

public void Translate (Single dx, Single dy)

Questi argomenti possono essere negativi. Un secondo Translate metodo combina i due valori di conversione in un singolo SKPoint valore:

public void Translate (SKPoint point)

La pagina Translate accumulata del programma di esempio dimostra che più chiamate del Translate metodo sono cumulative. La AccumulatedTranslatePage classe visualizza 20 versioni dello stesso rettangolo, ognuna delle quali rispetto al rettangolo precedente è sufficiente per estendersi lungo la diagonale. Ecco il PaintSurface gestore eventi:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    SKImageInfo info = args.Info;
    SKSurface surface = args.Surface;
    SKCanvas canvas = surface.Canvas;

    canvas.Clear();

    using (SKPaint strokePaint = new SKPaint())
    {
        strokePaint.Color = SKColors.Black;
        strokePaint.Style = SKPaintStyle.Stroke;
        strokePaint.StrokeWidth = 3;

        int rectangleCount = 20;
        SKRect rect = new SKRect(0, 0, 250, 250);
        float xTranslate = (info.Width - rect.Width) / (rectangleCount - 1);
        float yTranslate = (info.Height - rect.Height) / (rectangleCount - 1);

        for (int i = 0; i < rectangleCount; i++)
        {
            canvas.DrawRect(rect, strokePaint);
            canvas.Translate(xTranslate, yTranslate);
        }
    }
}

I rettangoli successivi si spostano verso il basso nella pagina:

Screenshot triplo della pagina Di traduzione accumulata

Se i fattori di traslazione accumulati sono dx e dye il punto specificato in una funzione di disegno è (x, y), il rendering dell'oggetto grafico viene eseguito nel punto (x', y'), dove:

x' = x + dx

y' = y + dy

Queste formule sono note come formule di trasformazione per la traduzione. I valori predefiniti di dx e dy per un nuovo SKCanvas sono 0.

È comune usare la trasformazione traduci per gli effetti di ombreggiatura e tecniche simili, come illustrato nella pagina Translate Text Effects .It is common to use the translate transform for shadow effects and similar techniques, as the Translate Text Effects page illustrate. Ecco la parte pertinente del PaintSurface gestore nella TranslateTextEffectsPage classe :

float textSize = 150;

using (SKPaint textPaint = new SKPaint())
{
    textPaint.Style = SKPaintStyle.Fill;
    textPaint.TextSize = textSize;
    textPaint.FakeBoldText = true;

    float x = 10;
    float y = textSize;

    // Shadow
    canvas.Translate(10, 10);
    textPaint.Color = SKColors.Black;
    canvas.DrawText("SHADOW", x, y, textPaint);
    canvas.Translate(-10, -10);
    textPaint.Color = SKColors.Pink;
    canvas.DrawText("SHADOW", x, y, textPaint);

    y += 2 * textSize;

    // Engrave
    canvas.Translate(-5, -5);
    textPaint.Color = SKColors.Black;
    canvas.DrawText("ENGRAVE", x, y, textPaint);
    canvas.ResetMatrix();
    textPaint.Color = SKColors.White;
    canvas.DrawText("ENGRAVE", x, y, textPaint);

    y += 2 * textSize;

    // Emboss
    canvas.Save();
    canvas.Translate(5, 5);
    textPaint.Color = SKColors.Black;
    canvas.DrawText("EMBOSS", x, y, textPaint);
    canvas.Restore();
    textPaint.Color = SKColors.White;
    canvas.DrawText("EMBOSS", x, y, textPaint);
}

In ognuno dei tre esempi viene Translate chiamato per visualizzare il testo per compensarlo dalla posizione specificata dalle x variabili e y . Il testo viene quindi visualizzato di nuovo in un altro colore senza alcun effetto di traduzione:

Screenshot triplo della pagina Traduci effetti di testo

Ognuno dei tre esempi mostra un modo diverso per negare la Translate chiamata:

Il primo esempio chiama Translate semplicemente di nuovo ma con valori negativi. Poiché le Translate chiamate sono cumulative, questa sequenza di chiamate ripristina semplicemente la conversione totale ai valori predefiniti pari a zero.

Il secondo esempio chiama ResetMatrix. In questo modo tutte le trasformazioni tornano allo stato predefinito.

Il terzo esempio salva lo stato dell'oggetto SKCanvas con una chiamata a Save e quindi ripristina lo stato con una chiamata a Restore. Questo è il modo più versatile per manipolare le trasformazioni per una serie di operazioni di disegno. Queste Save e Restore chiamano una funzione come uno stack: è possibile chiamare Save più volte e quindi chiamare Restore in sequenza inversa per tornare agli stati precedenti. Il Save metodo restituisce un numero intero ed è possibile passare tale intero a per RestoreToCount chiamare Restore in modo efficace più volte. La SaveCount proprietà restituisce il numero di stati attualmente salvati nello stack.

È anche possibile usare la SKAutoCanvasRestore classe per ripristinare lo stato dell'area di disegno. Il costruttore di questa classe deve essere chiamato in un'istruzione using . Lo stato dell'area di disegno viene ripristinato automaticamente alla fine del using blocco.

Tuttavia, non è necessario preoccuparsi delle trasformazioni che passano da una chiamata del PaintSurface gestore alla successiva. Ogni nuova chiamata a recapita PaintSurface un nuovo SKCanvas oggetto con trasformazioni predefinite.

Un altro uso comune della trasformazione consiste nel rendering di un oggetto visivo originariamente creato utilizzando coordinate utili per il Translate disegno. Ad esempio, è possibile specificare le coordinate per un orologio analogico con un centro nel punto (0, 0). È quindi possibile usare le trasformazioni per visualizzare l'orologio in cui si desidera. Questa tecnica è illustrata nella pagina [Hendecagram Array]. La HendecagramArrayPage classe inizia creando un SKPath oggetto per una stella a 11 punte. L'oggetto HendecagramPath è definito come pubblico, statico e di sola lettura in modo che sia accessibile da altri programmi dimostrativi. Viene creato in un costruttore statico:

public class HendecagramArrayPage : ContentPage
{
    ...
    public static readonly SKPath HendecagramPath;

    static HendecagramArrayPage()
    {
        // Create 11-pointed star
        HendecagramPath = new SKPath();
        for (int i = 0; i < 11; i++)
        {
            double angle = 5 * i * 2 * Math.PI / 11;
            SKPoint pt = new SKPoint(100 * (float)Math.Sin(angle),
                                    -100 * (float)Math.Cos(angle));
            if (i == 0)
            {
                HendecagramPath.MoveTo(pt);
            }
            else
            {
                HendecagramPath.LineTo(pt);
            }
        }
        HendecagramPath.Close();
    }
}

Se il centro della stella è il punto (0, 0), tutti i punti della stella si trovano su un cerchio che circonda quel punto. Ogni punto è una combinazione di valori seno e coseno di un angolo che aumenta di 5/11° di 360 gradi. È anche possibile creare una stella a 11 punte aumentando l'angolo di 2/11, 3/11 o 4/11 del cerchio. Il raggio del cerchio è impostato su 100.

Se il rendering di questo percorso viene eseguito senza alcuna trasformazione, il centro verrà posizionato nell'angolo superiore sinistro dell'oggetto SKCanvase sarà visibile solo un quarto di esso. Il PaintSurface gestore di HendecagramPage usa Translate invece per affiancare l'area di disegno con più copie della stella, ognuna colorata in modo casuale:

public class HendecagramArrayPage : ContentPage
{
    Random random = new Random();
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();

        using (SKPaint paint = new SKPaint())
        {
            for (int x = 100; x < info.Width + 100; x += 200)
                for (int y = 100; y < info.Height + 100; y += 200)
                {
                    // Set random color
                    byte[] bytes = new byte[3];
                    random.NextBytes(bytes);
                    paint.Color = new SKColor(bytes[0], bytes[1], bytes[2]);

                    // Display the hendecagram
                    canvas.Save();
                    canvas.Translate(x, y);
                    canvas.DrawPath(HendecagramPath, paint);
                    canvas.Restore();
                }
        }
    }
}

Il risultato è il seguente:

Screenshot triplo della pagina Matrice hendecagram

Le animazioni spesso comportano trasformazioni. La pagina Animazione hendecagram sposta la stella a 11 punte intorno in un cerchio. La HendecagramAnimationPage classe inizia con alcuni campi ed esegue l'override OnAppearing dei metodi e OnDisappearing per avviare e arrestare un Xamarin.Forms timer:

public class HendecagramAnimationPage : ContentPage
{
    const double cycleTime = 5000;      // in milliseconds

    SKCanvasView canvasView;
    Stopwatch stopwatch = new Stopwatch();
    bool pageIsActive;
    float angle;

    public HendecagramAnimationPage()
    {
        Title = "Hedecagram Animation";

        canvasView = new SKCanvasView();
        canvasView.PaintSurface += OnCanvasViewPaintSurface;
        Content = canvasView;
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        pageIsActive = true;
        stopwatch.Start();

        Device.StartTimer(TimeSpan.FromMilliseconds(33), () =>
        {
            double t = stopwatch.Elapsed.TotalMilliseconds % cycleTime / cycleTime;
            angle = (float)(360 * t);
            canvasView.InvalidateSurface();

            if (!pageIsActive)
            {
                stopwatch.Stop();
            }

            return pageIsActive;
        });
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        pageIsActive = false;
    }
    ...
}

Il angle campo viene animato da 0 a 360 gradi ogni 5 secondi. Il PaintSurface gestore usa la angle proprietà in due modi: per specificare la tonalità del colore nel SKColor.FromHsl metodo e come argomento per i Math.Sin metodi e Math.Cos per gestire la posizione della stella:

public class HendecagramAnimationPage : ContentPage
{
    ...
    void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
    {
        SKImageInfo info = args.Info;
        SKSurface surface = args.Surface;
        SKCanvas canvas = surface.Canvas;

        canvas.Clear();
        canvas.Translate(info.Width / 2, info.Height / 2);
        float radius = (float)Math.Min(info.Width, info.Height) / 2 - 100;

        using (SKPaint paint = new SKPaint())
        {
            paint.Style = SKPaintStyle.Fill;
            paint.Color = SKColor.FromHsl(angle, 100, 50);

            float x = radius * (float)Math.Sin(Math.PI * angle / 180);
            float y = -radius * (float)Math.Cos(Math.PI * angle / 180);
            canvas.Translate(x, y);
            canvas.DrawPath(HendecagramPage.HendecagramPath, paint);
        }
    }
}

Il PaintSurface gestore chiama il Translate metodo due volte, prima per convertirlo al centro dell'area di disegno e quindi per traslare nella circonferenza di un cerchio centrato intorno (0, 0). Il raggio del cerchio è impostato per essere il più grande possibile, mantenendo comunque la stella entro i confini della pagina:

Screenshot triplo della pagina Animazione hendecagram

Si noti che la stella mantiene lo stesso orientamento che ruota intorno al centro della pagina. Non ruota affatto. Si tratta di un processo per una trasformazione di rotazione.