Partager via


La transformation de traduction

Découvrez comment utiliser la transformation de traduction pour décaler les graphiques SkiaSharp

Le type de transformation le plus simple dans SkiaSharp est la transformation de traduction ou de traduction . Cette transformation déplace les objets graphiques dans les directions horizontales et verticales. Dans un sens, la traduction est la transformation la plus inutile, car vous pouvez généralement accomplir le même effet en modifiant simplement les coordonnées que vous utilisez dans la fonction de dessin. Toutefois, lors du rendu d’un chemin, toutes les coordonnées sont encapsulées dans le chemin. Il est donc beaucoup plus facile d’appliquer une transformation de traduction pour déplacer l’intégralité du chemin.

La traduction est également utile pour l’animation et pour les effets de texte simples :

Ombre de texte, gravure et embossage avec traduction

La Translate méthode présente SKCanvas deux paramètres qui entraînent le déplacement horizontal et vertical des objets graphiques dessinés par la suite :

public void Translate (Single dx, Single dy)

Ces arguments peuvent être négatifs. Une deuxième Translate méthode combine les deux valeurs de traduction dans une seule SKPoint valeur :

public void Translate (SKPoint point)

La page Traduction cumulée de l’exemple de programme montre que plusieurs appels de la Translate méthode sont cumulatifs. La AccumulatedTranslatePage classe affiche 20 versions du même rectangle, chaque décalage du rectangle précédent suffit pour qu’ils s’étendent le long de la diagonale. Voici le PaintSurface gestionnaire d’événements :

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

Les rectangles successifs se déplacent vers le bas de la page :

Capture d’écran triple de la page Traduction cumulée

Si les facteurs de traduction cumulés sont dx et dyle point que vous spécifiez dans une fonction de dessin est (x, y), l’objet graphique est rendu au point (x', ), y'où :

x' = x + dx

y' = y + dy

Il s’agit des formules de transformation pour la traduction. Les valeurs par défaut et dxdy pour une nouvelle SKCanvas valeur sont 0.

Il est courant d’utiliser la transformation de traduction pour les effets d’ombre et des techniques similaires, comme le montre la page Traduire des effets de texte. Voici la partie pertinente du PaintSurface gestionnaire dans la 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);
}

Dans chacun des trois exemples, Translate on appelle l’affichage du texte pour le décaler de l’emplacement donné par les variables et y les x variables. Ensuite, le texte s’affiche à nouveau dans une autre couleur sans effet de traduction :

Capture d’écran triple de la page Traduire des effets de texte

Chacun des trois exemples montre un moyen différent de négation de l’appel Translate :

Le premier exemple appelle Translate simplement à nouveau, mais avec des valeurs négatives. Étant donné que les Translate appels sont cumulatifs, cette séquence d’appels restaure simplement la traduction totale en valeurs par défaut de zéro.

Le deuxième exemple appelle ResetMatrix. Ainsi, toutes les transformations retournent à leur état par défaut.

Le troisième exemple enregistre l’état de l’objet SKCanvas avec un appel, Save puis restaure l’état avec un appel à Restore. Il s’agit de la façon la plus polyvalente de manipuler des transformations pour une série d’opérations de dessin. Ces Save fonctions et Restore appellent comme une pile : vous pouvez appeler plusieurs fois, puis appeler RestoreSave dans la séquence inverse pour revenir aux états précédents. La Save méthode retourne un entier et vous pouvez passer cet entier pour RestoreToCount appeler Restore efficacement plusieurs fois. La SaveCount propriété retourne le nombre d’états actuellement enregistrés sur la pile.

Vous pouvez également utiliser la SKAutoCanvasRestore classe pour restaurer l’état du canevas. Le constructeur de cette classe est destiné à être appelé dans une using instruction ; l’état du canevas est automatiquement restauré à la fin du using bloc.

Toutefois, vous n’avez pas à vous soucier des transformations qui passent d’un appel du PaintSurface gestionnaire à l’autre. Chaque nouvel appel pour PaintSurface remettre un objet frais SKCanvas avec des transformations par défaut.

Une autre utilisation courante de la transformation consiste à restituer un objet visuel qui a été créé à l’origine Translate à l’aide de coordonnées pratiques pour le dessin. Par exemple, vous pouvez spécifier des coordonnées pour une horloge analogique avec un centre au point (0, 0). Vous pouvez ensuite utiliser des transformations pour afficher l’horloge où vous le souhaitez. Cette technique est illustrée dans la page [Hendecagram Array]. La HendecagramArrayPage classe commence par créer un SKPath objet pour une étoile à 11 pointes. L’objet HendecagramPath est défini comme public, statique et en lecture seule afin qu’il soit accessible à partir d’autres programmes de démonstration. Il est créé dans un constructeur statique :

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

Si le centre de l’étoile est le point (0, 0), tous les points de l’étoile se trouvent sur un cercle entourant ce point. Chaque point est une combinaison de valeurs de sinus et de cosinus d’un angle qui augmente de 5/11e de 360 degrés. (Il est également possible de créer une étoile à 11 pointes en augmentant l’angle par 2/11e, 3/11e ou 4/11e du cercle.) Le rayon de ce cercle est défini sur 100.

Si ce chemin d’accès est rendu sans transformation, le centre est positionné en haut à gauche du coin supérieur gauche, SKCanvaset seul un quart de celui-ci sera visible. Le PaintSurface gestionnaire d’utilisation à HendecagramPage la place pour Translate vignetter le canevas avec plusieurs copies de l’étoile, chacun d’eux couleur aléatoire :

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

Voici le résultat :

Capture d’écran triple de la page Tableau Hendecagram

Les animations impliquent souvent des transformations. La page Animation hendecagram déplace l’étoile à 11 pointes autour d’un cercle. La HendecagramAnimationPage classe commence par certains champs et remplacements des OnAppearing méthodes OnDisappearing pour démarrer et arrêter un Xamarin.Forms minuteur :

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

Le angle champ est animé de 0 degrés à 360 degrés toutes les 5 secondes. Le PaintSurface gestionnaire utilise la angle propriété de deux façons : pour spécifier la teinte de la couleur dans la SKColor.FromHsl méthode, et comme argument pour les méthodes et Math.Cos pour Math.Sin régir l’emplacement de l’étoile :

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

Le PaintSurface gestionnaire appelle la Translate méthode deux fois, d’abord pour se traduire au centre du canevas, puis pour traduire vers la circonférence d’un cercle centré autour (0, 0). Le rayon du cercle est aussi grand que possible tout en conservant l’étoile dans les limites de la page :

Capture d’écran triple de la page Animation Hendecagram

Notez que l’étoile conserve la même orientation qu’elle tourne autour du centre de la page. Il ne fait pas pivoter du tout. C’est un travail pour une transformation de rotation.