Trasformazione di inclinazione

Scopri come la trasformazione asimmetria può creare oggetti grafici inclinati in SkiaSharp

In SkiaSharp la trasformazione asimmetria inclina oggetti grafici, ad esempio l'ombreggiatura in questa immagine:

Esempio di asimmetria dal programma Skew Shadow Text

L'asimmetria trasforma un rettangolo in un parallelogramma, ma un'ellisse asimmetrica è ancora un'ellisse.

Sebbene Xamarin.Forms definisca le proprietà per la conversione, il ridimensionamento e le rotazioni, non esiste alcuna proprietà corrispondente per Xamarin.Forms l'asimmetria.

Il Skew metodo di SKCanvas accetta due argomenti per l'asimmetria orizzontale e l'asimmetria verticale:

public void Skew (Single xSkew, Single ySkew)

Un secondo Skew metodo combina gli argomenti in un singolo SKPoint valore:

public void Skew (SKPoint skew)

Tuttavia, è improbabile che si usi uno di questi due metodi in isolamento.

La pagina Skew Experiment (Esperimento di asimmetria) consente di sperimentare valori di asimmetria compresi tra –10 e 10. Una stringa di testo viene posizionata nell'angolo superiore sinistro della pagina, con valori di asimmetria ottenuti da due Slider elementi. Ecco il PaintSurface gestore nella 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);
    }
}

I valori dell'argomento xSkew spostano la parte inferiore del testo a destra per i valori positivi o a sinistra per i valori negativi. I valori di ySkew spostamento a destra del testo verso il basso per i valori positivi o verso l'alto per i valori negativi:

Screenshot triplo della pagina Dell'esperimento di asimmetria

Se il xSkew valore è negativo del ySkew valore, il risultato è rotazione, ma anche ridimensionato in qualche modo.

Le formule di trasformazione sono le seguenti:

x' = x + xSkew · Y

y' = asimmetria · x + y

Ad esempio, per un valore positivo xSkew , il valore trasformato x' aumenta man mano che y aumenta. Questo è ciò che causa l'inclinazione.

Se un triangolo di 200 pixel di larghezza e un massimo di 100 pixel viene posizionato con l'angolo superiore sinistro nel punto (0, 0) e viene eseguito il rendering con un xSkew valore pari a 1,5, i risultati del parallelogramma seguente:

Effetto della trasformazione asimmetria su un rettangolo

Le coordinate del bordo inferiore hanno y valori pari a 100, quindi vengono spostati a destra 150 pixel.

Per i valori diversi da zero di xSkew o ySkew, solo il punto (0, 0) rimane invariato. Questo punto può essere considerato il centro dell'asimmetria. Se è necessario che il centro dell'asimmetria sia qualcos'altro (che in genere è il caso), non c'è alcun Skew metodo che fornisce questo. Sarà necessario combinare Translate in modo esplicito le chiamate con la Skew chiamata. Per centrare l'asimmetria in e pxpy, effettuare le chiamate seguenti:

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

Le formule di trasformazione composita sono:

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

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

Se ySkew è zero, il px valore non viene usato. Il valore è irrilevante e analogamente per ySkew e py.

Potrebbe risultare più confortevole specificare l'inclinazione come angolo di inclinazione, ad esempio l'angolo α in questo diagramma:

Effetto della trasformazione asimmetria su un rettangolo con un angolo di inclinazione indicato

Il rapporto tra 150 pixel e 100 pixel verticale è la tangente di tale angolo, in questo esempio di 56,3 gradi.

Il file XAML della pagina Skew Angle Experiment è simile alla pagina Skew Angle , ad eccezione del fatto che gli Slider elementi vanno da -90 gradi a 90 gradi. Il SkewAngleExperiment file code-behind centra il testo nella pagina e usa Translate per impostare un centro di inclinazione al centro della pagina. Un metodo breve SkewDegrees nella parte inferiore del codice converte gli angoli in valori di asimmetria:

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

Quando un angolo si avvicina a 90 gradi positivo o negativo, la tangente si avvicina all'infinito, ma gli angoli fino a circa 80 gradi o così sono utilizzabili:

Screenshot triplo della pagina Skew Angle Experiment

Una piccola asimmetria orizzontale negativa può simulare testo obliquo o corsivo, come dimostra la pagina Testo obliquo. La ObliqueTextPage classe mostra come viene eseguita:

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 proprietà di SKPaint è impostata su Center. Senza alcuna trasformazione, la DrawText chiamata con coordinate pari a (0, 0) posiziona il testo con il centro orizzontale della linea di base nell'angolo superiore sinistro. Inclina SkewDegrees il testo orizzontalmente di 20 gradi rispetto alla linea di base. La Translate chiamata sposta il centro orizzontale della linea di base del testo al centro dell'area di disegno:

Screenshot triplo della pagina Testo obliquo

Nella pagina Testo ombreggiatura asimmetria viene illustrato come usare una combinazione di asimmetria a 45 gradi e scala verticale per rendere un'ombreggiatura di testo che si inclina lontano dal testo. Ecco la parte pertinente del PaintSurface gestore:

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'ombreggiatura viene visualizzata prima e quindi il testo:

Screenshot triplo della pagina Testo ombreggiato asimmetria

La coordinata verticale passata al DrawText metodo indica la posizione del testo rispetto alla linea di base. Ovvero la stessa coordinata verticale utilizzata per il centro dell'asimmetria. Questa tecnica non funzionerà se la stringa di testo contiene discendenti. Ad esempio, sostituire la parola "stravanza" per "Shadow" e di seguito è riportato il risultato:

Screenshot triplo della pagina Testo ombreggiato asimmetria con una parola alternativa con discendenti

L'ombreggiatura e il testo sono ancora allineati alla linea di base, ma l'effetto sembra errato. Per correggerlo, è necessario ottenere i limiti di testo:

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

Le Translate chiamate devono essere regolate in base all'altezza dei discendenti:

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

Ora l'ombreggiatura si estende dalla parte inferiore dei discendenti:

Screenshot triplo della pagina Testo ombreggiatura asimmetria con regolazioni per i discendenti