Udostępnij za pośrednictwem


Przekład — przekształcenie

Dowiedz się, jak używać przekształcenia translate w celu przesunięcia grafiki SkiaSharp

Najprostszym typem transformacji w skiaSharp jest transformacja tłumaczenia lub tłumaczenia . Ta transformacja przesuwa obiekty graficzne w kierunkach poziomych i pionowych. W sensie tłumaczenie jest najbardziej niepotrzebnym przekształceniem, ponieważ zwykle można osiągnąć ten sam efekt, zmieniając współrzędne, których używasz w funkcji rysunku. Podczas renderowania ścieżki wszystkie współrzędne są jednak hermetyzowane w ścieżce, więc znacznie łatwiej jest zastosować przekształcenie translacji, aby przesunąć całą ścieżkę.

Tłumaczenie jest również przydatne w przypadku animacji i prostych efektów tekstowych:

Cień tekstu, grawerowanie i uwypuklenie z tłumaczeniem

Metoda Translate w metodzie SKCanvas ma dwa parametry, które powodują późniejsze przesunięcie obiektów graficznych w poziomie i w pionie:

public void Translate (Single dx, Single dy)

Te argumenty mogą być ujemne. Druga Translate metoda łączy dwie wartości tłumaczenia w jednej SKPoint wartości:

public void Translate (SKPoint point)

Strona Skumulowane tłumaczenie przykładowego programu pokazuje, że wiele wywołań Translate metody jest skumulowanych. Klasa AccumulatedTranslatePage wyświetla 20 wersji tego samego prostokąta, każde przesunięcie z poprzedniego prostokąta wystarczy, aby rozciągnąć wzdłuż przekątnej. Oto procedura obsługi zdarzeń PaintSurface :

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

Kolejne prostokąty wystąpą w dół strony:

Potrójny zrzut ekranu przedstawiający stronę Skumulowane tłumaczenie

Jeśli skumulowane czynniki tłumaczenia to dx i dy, a punkt określony w funkcji rysunku to (x, y), obiekt graficzny jest renderowany w punkcie (x', y'), gdzie:

x' = x + dx

y' = y + dy

Są one znane jako formuły przekształcania do tłumaczenia. Wartości domyślne dx i dy dla nowych SKCanvas to 0.

Często używa się transformacji translate w przypadku efektów cieni i podobnych technik, jak pokazano na stronie Translate Text Effects (Tłumaczenie efektów tekstowych). Oto odpowiednia PaintSurface część procedury obsługi w TranslateTextEffectsPage klasie:

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

W każdym z trzech przykładów Translate wywoływana jest funkcja wyświetlania tekstu w celu przesunięcia go z lokalizacji podanej x przez zmienne i y . Następnie tekst zostanie ponownie wyświetlony w innym kolorze bez efektu tłumaczenia:

Potrójny zrzut ekranu przedstawiający stronę Translate Text Effects (Tłumaczenie efektów tekstowych)

Każdy z trzech przykładów pokazuje inny sposób negowania wywołania Translate :

Pierwszy przykład po prostu wywołuje ponownie, Translate ale z wartościami ujemnymi. Translate Ponieważ wywołania są skumulowane, ta sekwencja wywołań po prostu przywraca całkowite tłumaczenie do wartości domyślnych zera.

Drugi przykład wywołuje metodę ResetMatrix. Spowoduje to powrót wszystkich przekształceń do stanu domyślnego.

Trzeci przykład zapisuje stan SKCanvas obiektu za pomocą wywołania metody Save , a następnie przywraca stan za pomocą wywołania metody Restore. Jest to najbardziej wszechstronny sposób manipulowania transformacjami dla serii operacji rysowania. Te Save metody i Restore wywołania działają jak stos: można wywołać Save wiele razy, a następnie wywołać Restore metodę w odwrotnej kolejności, aby powrócić do poprzednich stanów. Metoda Save zwraca liczbę całkowitą i można przekazać tę liczbę całkowitą, aby RestoreToCount skutecznie wywoływać Restore wiele razy. Właściwość SaveCount zwraca liczbę stanów aktualnie zapisanych na stosie.

Możesz również użyć SKAutoCanvasRestore klasy do przywrócenia stanu kanwy. Konstruktor tej klasy ma być wywoływany w using instrukcji; stan kanwy jest automatycznie przywracany na końcu using bloku.

Nie musisz jednak martwić się o przekształcenia przenoszone z jednego wywołania PaintSurface programu obsługi do następnego. Każde nowe wywołanie zapewnia PaintSurface nowy SKCanvas obiekt z domyślnymi przekształceniami.

Innym typowym zastosowaniem Translate transformacji jest renderowanie obiektu wizualnego, który został pierwotnie utworzony przy użyciu współrzędnych, które są wygodne do rysowania. Na przykład można określić współrzędne zegara analogowego z środek w punkcie (0, 0). Następnie możesz użyć przekształceń, aby wyświetlić zegar, w którym chcesz. Ta technika jest pokazana na stronie [Tablica Hendecagram]. Klasa HendecagramArrayPage zaczyna się od utworzenia SKPath obiektu dla 11-punktowej gwiazdki. Obiekt HendecagramPath jest definiowany jako publiczny, statyczny i tylko do odczytu, dzięki czemu można uzyskać do niego dostęp z innych programów demonstracyjnych. Jest on tworzony w konstruktorze statycznym:

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

Jeśli środek gwiazdy jest punktem (0, 0), wszystkie punkty gwiazdy znajdują się w okręgu wokół tego punktu. Każdy punkt jest kombinacją sinusu i cosinus wartości kąta, który zwiększa się o 5/11 i 360 stopni. (Można również utworzyć 11-punktową gwiazdę, zwiększając kąt o 2/11, 3/11 lub 4/11 okręgu). Promień tego okręgu jest ustawiony na 100.

Jeśli ta ścieżka jest renderowana bez żadnych przekształceń, środek zostanie umieszczony w lewym górnym rogu SKCanvasobiektu , a tylko jedna czwarta będzie widoczna. Program PaintSurface obsługi HendecagramPage zamiast tego używa Translate elementu do kafelka kanwy z wieloma kopiami gwiazdy, z których każda jest losowo kolorowana:

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

Oto wynik:

Potrójny zrzut ekranu przedstawiający stronę tablicy Hendecagram

Animacje często obejmują przekształcenia. Strona Animacja Hendecagram przenosi 11-punktową gwiazdę wokół w okręgu. Klasa HendecagramAnimationPage rozpoczyna się od niektórych pól i przesłonięć OnAppearing metod i OnDisappearing , aby uruchomić i zatrzymać Xamarin.Forms czasomierz:

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

Pole angle jest animowane od 0 stopni do 360 stopni co 5 sekund. Procedura PaintSurface obsługi używa angle właściwości na dwa sposoby: aby określić odcienie koloru w metodzie SKColor.FromHsl , oraz jako argument Math.Sin metody i Math.Cos do zarządzania lokalizacją gwiazdy:

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

Procedura PaintSurface obsługi wywołuje metodę Translate dwa razy, najpierw, aby przetłumaczyć na środek kanwy, a następnie przetłumaczyć na obwód okręgu wyśrodkowanego wokół (0, 0). Promień okręgu jest tak duży, jak to możliwe, zachowując gwiazdę w granicach strony:

Potrójny zrzut ekranu przedstawiający stronę animacji Hendecagram

Zwróć uwagę, że gwiazda zachowuje taką samą orientację, jak obraca się wokół środka strony. Nie obraca się w ogóle. Jest to zadanie przekształcenia rotacji.