Partager via


La transformation d’inclinaison

Découvrez comment la transformation asymétrique peut créer des objets graphiques inclinés dans SkiaSharp

Dans SkiaSharp, la transformation asymétrique incline les objets graphiques, tels que l’ombre dans cette image :

Exemple d’ékewing à partir du programme Shadow Text skew

L’asymétrie transforme un rectangle en parallélisme, mais un ellipse asymétrique est toujours un ellipse.

Bien que Xamarin.Forms définit des propriétés pour la traduction, la mise à l’échelle et les rotations, il n’existe aucune propriété correspondante pour Xamarin.Forms l’asymétrie.

La Skew méthode d’acceptation de SKCanvas deux arguments pour l’asymétrie horizontale et l’asymétrie verticale :

public void Skew (Single xSkew, Single ySkew)

Une deuxième Skew méthode combine ces arguments dans une valeur unique SKPoint :

public void Skew (SKPoint skew)

Toutefois, il est peu probable que vous utilisiez l’une de ces deux méthodes séparément.

La page Expérience d’asymétrie vous permet d’expérimenter des valeurs d’asymétrie comprises entre –10 et 10. Une chaîne de texte est positionnée dans le coin supérieur gauche de la page, avec des valeurs d’asymétrie obtenues à partir de deux Slider éléments. Voici le PaintSurface gestionnaire dans la SkewExperimentPage classe :

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

    canvas.Clear();

    using (SKPaint textPaint = new SKPaint
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Blue,
        TextSize = 200
    })
    {
        string text = "SKEW";
        SKRect textBounds = new SKRect();
        textPaint.MeasureText(text, ref textBounds);

        canvas.Skew((float)xSkewSlider.Value, (float)ySkewSlider.Value);
        canvas.DrawText(text, 0, -textBounds.Top, textPaint);
    }
}

Les valeurs de l’argument xSkew déplacent le bas du texte à droite pour les valeurs positives ou à gauche pour les valeurs négatives. Valeurs de ySkew décalage vers le bas du texte pour les valeurs positives ou vers le haut pour les valeurs négatives :

Capture d’écran triple de la page Expérience d’asymétrie

Si la xSkew valeur est négative de la ySkew valeur, le résultat est la rotation, mais également mis à l’échelle un peu.

Les formules de transformation sont les suivantes :

x' = x + xSkew · y

y' = ySkew · x + y

Par exemple, pour une valeur positive xSkew , la valeur transformée x' augmente au fur et à mesure de y l’augmentation. C’est ce qui provoque l’inclinaison.

Si un triangle de 200 pixels large et 100 pixels de haut est positionné avec son angle supérieur gauche au point (0, 0) et est rendu avec une xSkew valeur de 1,5, les résultats de l’parallélisme suivant :

Effet de la transformation d’asymétrie sur un rectangle

Les coordonnées du bord inférieur ont y des valeurs de 100, de sorte qu’elles sont décalées de 150 pixels à droite.

Pour les valeurs non nulles ou xSkewySkew, seul le point (0, 0) reste le même. Ce point peut être considéré comme le centre de la broche. Si vous avez besoin du centre de la broche pour être quelque chose d’autre (ce qui est généralement le cas), il n’existe aucune Skew méthode qui fournit cela. Vous devez combiner explicitement les Translate appels avec l’appel Skew . Pour centrer l’ékewing à px et pyeffectuer les appels suivants :

canvas.Translate(px, py);
canvas.Skew(xSkew, ySkew);
canvas.Translate(-px, -py);

Les formules de transformation composite sont les suivantes :

x' = x + xSkew · (y – py)

y' = ySkew · (x – px) + y

Si ySkew elle est égale à zéro, la px valeur n’est pas utilisée. La valeur n’est pas pertinente, et de la même façon pour ySkew et py.

Vous pouvez vous sentir plus à l’aise en spécifiant l’asymétrie comme angle d’inclinaison, tel que l’angle α dans ce diagramme :

Effet de la transformation d’asymétrie sur un rectangle avec un angle de rotation indiqué

Le rapport du décalage de 150 pixels à la verticale de 100 pixels est la tangente de cet angle, dans cet exemple 56,3 degrés.

Le fichier XAML de la page Skew Angle Experiment est similaire à la page Angle asymétrique, sauf que les Slider éléments vont de –90 degrés à 90 degrés. Le SkewAngleExperiment fichier code-behind centre le texte de la page et utilise Translate pour définir un centre de brochet au centre de la page. Une méthode courte SkewDegrees en bas du code convertit les angles en valeurs d’asymétrie :

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

    canvas.Clear();

    using (SKPaint textPaint = new SKPaint
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Blue,
        TextSize = 200
    })
    {
        float xCenter = info.Width / 2;
        float yCenter = info.Height / 2;

        string text = "SKEW";
        SKRect textBounds = new SKRect();
        textPaint.MeasureText(text, ref textBounds);
        float xText = xCenter - textBounds.MidX;
        float yText = yCenter - textBounds.MidY;

        canvas.Translate(xCenter, yCenter);
        SkewDegrees(canvas, xSkewSlider.Value, ySkewSlider.Value);
        canvas.Translate(-xCenter, -yCenter);
        canvas.DrawText(text, xText, yText, textPaint);
    }
}

void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
    canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
                (float)Math.Tan(Math.PI * yDegrees / 180));
}

Comme un angle approche de 90 degrés positifs ou négatifs, la tangente approche de l’infini, mais les angles jusqu’à environ 80 degrés sont utilisables :

Capture d’écran triple de la page Expérience d’angle asymétrique

Une petite asymétrie horizontale négative peut imiter du texte oblique ou italique, comme le montre la page Texte oblique. La ObliqueTextPage classe montre comment elle est effectuée :

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

    canvas.Clear();

    using (SKPaint textPaint = new SKPaint()
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Maroon,
        TextAlign = SKTextAlign.Center,
        TextSize = info.Width / 8       // empirically determined
    })
    {
        canvas.Translate(info.Width / 2, info.Height / 2);
        SkewDegrees(canvas, -20, 0);
        canvas.DrawText(Title, 0, 0, textPaint);
    }
}

void SkewDegrees(SKCanvas canvas, double xDegrees, double yDegrees)
{
    canvas.Skew((float)Math.Tan(Math.PI * xDegrees / 180),
                (float)Math.Tan(Math.PI * yDegrees / 180));
}

La TextAlign propriété de SKPaint est définie sur Center. Sans transformation, l’appel DrawText avec des coordonnées de (0, 0) positionnerait le texte avec le centre horizontal de la ligne de base en haut à gauche. L’asymétrie SkewDegrees du texte horizontalement de 20 degrés par rapport à la ligne de base. L’appel Translate déplace le centre horizontal de la ligne de base du texte vers le centre du canevas :

Capture d’écran triple de la page Texte oblique

La page Texte d’ombre asymétrique montre comment utiliser une combinaison d’un décalage de 45 degrés et d’une échelle verticale pour faire une ombre de texte qui s’éloigne du texte. Voici la partie pertinente du PaintSurface gestionnaire :

using (SKPaint textPaint = new SKPaint())
{
    textPaint.Style = SKPaintStyle.Fill;
    textPaint.TextSize = info.Width / 6;   // empirically determined

    // Common to shadow and text
    string text = "Shadow";
    float xText = 20;
    float yText = info.Height / 2;

    // Shadow
    textPaint.Color = SKColors.LightGray;
    canvas.Save();
    canvas.Translate(xText, yText);
    canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
    canvas.Scale(1, 3);
    canvas.Translate(-xText, -yText);
    canvas.DrawText(text, xText, yText, textPaint);
    canvas.Restore();

    // Text
    textPaint.Color = SKColors.Blue;
    canvas.DrawText(text, xText, yText, textPaint);
}

L’ombre s’affiche en premier, puis le texte :

Capture d’écran triple de la page Texte de l’ombre asymétrique

La coordonnée verticale passée à la DrawText méthode indique la position du texte par rapport à la ligne de base. Il s’agit de la même coordonnée verticale que celle utilisée pour le centre de la broche. Cette technique ne fonctionnera pas si la chaîne de texte contient des décroissants. Par exemple, remplacez le mot « bizarre » par « Ombre » et voici le résultat :

Capture d’écran triple de la page De texte instantané asymétrique avec un mot de remplacement avec des décroissants

L’ombre et le texte sont toujours alignés au niveau de la ligne de base, mais l’effet semble juste incorrect. Pour le corriger, vous devez obtenir les limites de texte :

SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);

Les Translate appels doivent être ajustés par la hauteur des descendeurs :

canvas.Translate(xText, yText + textBounds.Bottom);
canvas.Skew((float)Math.Tan(-Math.PI / 4), 0);
canvas.Scale(1, 3);
canvas.Translate(-xText, -yText - textBounds.Bottom);

Maintenant, l’ombre s’étend du bas de ces descendeurs :

Capture d’écran triple de la page De texte instantané asymétrique avec des ajustements pour les décroissants