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:
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:
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:
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 px
py
, 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:
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:
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:
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:
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:
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: