Freigeben über


Die Verschiebungstransformation

Erfahren Sie, wie Sie die Übersetzungstransformation zum Verschieben von SkiaSharp-Grafiken verwenden.

Die einfachste Art der Transformation in SkiaSharp ist die Übersetzungs - oder Übersetzungstransformation . Diese Transformation verschiebt grafische Objekte in horizontaler und vertikaler Richtung. In einem Sinne ist die Übersetzung die unnötigste Transformation, da Sie in der Regel denselben Effekt erzielen können, indem Sie einfach die Koordinaten ändern, die Sie in der Zeichnungsfunktion verwenden. Beim Rendern eines Pfads werden jedoch alle Koordinaten im Pfad gekapselt, sodass es viel einfacher ist, eine Übersetzungstransformation anzuwenden, um den gesamten Pfad zu verschieben.

Übersetzung ist auch für Animationen und für einfache Texteffekte nützlich:

Textschatten, Gravieren und Prämieren mit Übersetzung

Die Translate Methode in SKCanvas weist zwei Parameter auf, die dazu führen, dass anschließend gezeichnete Grafikobjekte horizontal und vertikal verschoben werden:

public void Translate (Single dx, Single dy)

Diese Argumente können negativ sein. Eine zweite Translate Methode kombiniert die beiden Übersetzungswerte in einem einzelnen SKPoint Wert:

public void Translate (SKPoint point)

Auf der Seite "Kumulierte Übersetzung " des Beispielprogramms wird veranschaulicht, dass mehrere Aufrufe der Translate Methode kumulativ sind. Die AccumulatedTranslatePage Klasse zeigt 20 Versionen desselben Rechtecks an, wobei jeder Abstand vom vorherigen Rechteck nur ausreichend ist, sodass sie sich entlang der Diagonale erstrecken. Dies ist der PaintSurface Ereignishandler:

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

Die aufeinander folgenden Rechtecke verleiten auf der Seite:

Dreifacher Screenshot der Seite

Wenn die angesammelten Übersetzungsfaktoren dx und dyder punkt, den Sie in einer Zeichnungsfunktion angeben, ist (x, y), wird das grafische Objekt an dem Punkt (x', y'), wobei:

x' = x + dx

y' = y + dy

Diese werden als Transformationsformeln für die Übersetzung bezeichnet. Die Standardwerte und dxdy für ein neues SKCanvas sind 0.

Es ist üblich, die Übersetzungstransformation für Schatteneffekte und ähnliche Techniken zu verwenden, wie die Seite "Texteffekte übersetzen" veranschaulicht. Dies ist der relevante Teil des PaintSurface Handlers in der TranslateTextEffectsPage Klasse:

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 jedem der drei Beispiele wird die Anzeige des Texts aufgerufen, Translate um ihn von der von den und y den x Variablen angegebenen Position zu versatzen. Anschließend wird der Text wieder in einer anderen Farbe ohne Übersetzungseffekt angezeigt:

Dreifacher Screenshot der Seite

Jedes der drei Beispiele zeigt eine andere Methode zum Negieren des Translate Anrufs:

Im ersten Beispiel wird einfach wieder aufgerufen Translate , aber mit negativen Werten. Da die Translate Aufrufe kumulativ sind, stellt diese Aufrufsequenz einfach die Gesamtübersetzung in die Standardwerte null wieder her.

Das zweite Beispiel ruft .ResetMatrix Dies bewirkt, dass alle Transformationen zum Standardzustand zurückkehren.

Im dritten Beispiel wird der Zustand des SKCanvas Objekts mit einem Aufruf Save gespeichert und anschließend mit einem Aufruf wiederhergestellt Restore. Dies ist die vielseitigste Methode zum Bearbeiten von Transformationen für eine Reihe von Zeichnungsvorgängen. Diese Save und Restore Aufrufe funktionieren wie ein Stapel: Sie können mehrmals aufrufen Save und dann in umgekehrter Reihenfolge aufrufen Restore , um zu vorherigen Zuständen zurückzukehren. Die Save Methode gibt eine ganze Zahl zurück, und Sie können diese ganze Zahl RestoreToCount mehrmals übergeben, um sie effektiv aufzurufen Restore . Die SaveCount Eigenschaft gibt die Anzahl der Zustände zurück, die derzeit im Stapel gespeichert sind.

Sie können die SKAutoCanvasRestore Klasse auch zum Wiederherstellen des Canvaszustands verwenden. Der Konstruktor dieser Klasse soll in einer using Anweisung aufgerufen werden. Der Canvaszustand wird automatisch am Ende des using Blocks wiederhergestellt.

Sie müssen sich jedoch keine Gedanken über Transformationen machen, die von einem Aufruf des PaintSurface Handlers zur nächsten übertragen werden. Jeder neue Aufruf, um ein neues SKCanvas Objekt mit Standardtransformationen zu PaintSurface liefern.

Eine weitere häufige Verwendung der Translate Transformation ist das Rendern eines visuellen Objekts, das ursprünglich mithilfe von Koordinaten erstellt wurde, die für die Zeichnung geeignet sind. Sie können beispielsweise Koordinaten für eine analoge Uhr mit einer Mitte am Punkt (0, 0) angeben. Sie können dann Transformationen verwenden, um die Uhr an der gewünschten Stelle anzuzeigen. Diese Technik wird auf der Seite [Hendecagram Array] veranschaulicht. Die HendecagramArrayPage Klasse beginnt mit dem Erstellen eines SKPath Objekts für einen 11-spitzen Stern. Das HendecagramPath Objekt wird als öffentlich, statisch und schreibgeschützt definiert, sodass es von anderen Demonstrationsprogrammen aus aufgerufen werden kann. Sie wird in einem statischen Konstruktor erstellt:

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

Wenn die Mitte des Sterns der Punkt (0, 0) ist, befinden sich alle Punkte des Sterns auf einem Kreis, der diesen Punkt umgibt. Jeder Punkt ist eine Kombination aus Sinus- und Kosinuswerten eines Winkels, der um 5/11tel von 360 Grad zunimmt. (Es ist auch möglich, einen 11-spitzen Stern zu erstellen, indem der Winkel um 2/11, 3/11th oder 4/11th des Kreises erhöht wird.) Der Radius dieses Kreises wird als 100 festgelegt.

Wenn dieser Pfad ohne Transformationen gerendert wird, wird die Mitte in der oberen linken Ecke des SKCanvasBereichs positioniert, und nur ein Viertel davon ist sichtbar. Der PaintSurface Handler HendecagramPage verwendet Translate stattdessen, um den Zeichenbereich mit mehreren Kopien des Sterns zu kacheln, die jeweils zufällig gefärbt sind:

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

Das Ergebnis lautet wie folgt:

Dreifacher Screenshot der Seite

Animationen umfassen häufig Transformationen. Die Hendekagramanimationsseite verschiebt den 11-spitzen Stern in einem Kreis um. Die HendecagramAnimationPage Klasse beginnt mit einigen Feldern und Außerkraftsetzungen der OnAppearing methoden OnDisappearing , um einen Xamarin.Forms Timer zu starten und zu beenden:

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

Das angle Feld wird alle 5 Sekunden von 0 Grad bis 360 Grad animiert. Der PaintSurface Handler verwendet die angle Eigenschaft auf zwei Arten: zum Angeben des Farbtons in der SKColor.FromHsl Methode und als Argument für die Math.Sin Und Math.Cos Methoden zum Steuern der Position des Sterns:

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

Der PaintSurface Handler ruft die Translate Methode zweimal auf, zuerst in die Mitte des Zeichenbereichs zu übersetzen und dann in den Umfang eines kreiszentrierten Kreises (0, 0) zu übersetzen. Der Radius des Kreises ist so groß wie möglich, während der Stern weiterhin innerhalb der Grenzen der Seite bleibt:

Dreifacher Screenshot der Seite

Beachten Sie, dass der Stern Standard die gleiche Ausrichtung wie er sich um die Mitte der Seite dreht. Es dreht sich überhaupt nicht. Das ist ein Auftrag für eine Drehtransformation.