Eğme Dönüşümü

Eğme dönüştürmesinin SkiaSharp'ta eğimli grafik nesneleri nasıl oluşturabileceğini görün

SkiaSharp'ta eğme dönüşümü, bu görüntüdeki gölge gibi grafik nesneleri eğir:

Gölge Metni Eğ programından eğme örneği

Eğme, dikdörtgeni paralelograma dönüştürür, ancak eğik elips yine de üç noktadır.

Çeviri, ölçeklendirme ve döndürme özelliklerini tanımlasa Xamarin.Forms da, eğme için içinde Xamarin.Forms buna karşılık gelen özellik yoktur.

yöntemiSKCanvas, Skew yatay eğme ve dikey eğme için iki bağımsız değişken kabul eder:

public void Skew (Single xSkew, Single ySkew)

İkinci Skew bir yöntem bu bağımsız değişkenleri tek SKPoint bir değerde birleştirir:

public void Skew (SKPoint skew)

Ancak, bu iki yöntemden birini yalıtarak kullanmanız pek olası değildir.

Eğme Denemesi sayfası, –10 ile 10 arasında değişen eğriltme değerleriyle deneme yapmanıza olanak tanır. Metin dizesi, iki Slider öğeden alınan eğme değerleriyle sayfanın sol üst köşesine konumlandırılır. sınıfındaki PaintSurface işleyici aşağıdadır SkewExperimentPage :

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

Bağımsız değişkeninin xSkew değerleri, pozitif değerler için metnin alt kısmını sağa veya negatif değerler için sola kaydırıyor. Pozitif değerler ySkew için metnin sağını aşağı veya negatif değerler için yukarı kaydırma değerleri:

Eğme Denemesi sayfasının üç kez ekran görüntüsü

xSkew Değer değerin negatifiyse ySkew sonuç döndürmedir, ancak bir şekilde ölçeklendirilir.

Dönüşüm formülleri aşağıdaki gibidir:

x' = x + xSkew · Y

y' = ySkew · x + y

Örneğin, pozitif xSkew bir değer için, dönüştürülmüş x' değer arttıkça y artar. Eğime neden olan da bu.

200 piksel genişliğinde ve 100 piksel yüksekliğinde bir üçgen, sol üst köşesi noktasında (0, 0) konumlandırılır ve 1,5 değeriyle xSkew işlenirse, aşağıdaki paralelkenar sonuçlanır:

Eğme dönüşümünün dikdörtgen üzerindeki etkisi

Alt kenarın koordinatları 100 değerine sahip y olduğundan 150 piksel sağa kaydırılır.

sıfır olmayan veya ySkewdeğerleri xSkew için yalnızca nokta (0, 0) aynı kalır. Bu nokta, dengesizlik merkezi olarak kabul edilebilir. Eğriltme merkezinin başka bir şey olması gerekiyorsa (genellikle böyledir), bunu sağlayan bir yöntem yoktur Skew . Çağrıları çağrıyla Skew açıkça birleştirmeniz Translate gerekir. ve konumundaki dengesizliği pxpyortalamak için aşağıdaki çağrıları yapın:

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

Bileşik dönüştürme formülleri şunlardır:

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

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

Sıfır ise ySkew , px değer kullanılmaz. Değeri ilgisizdir ve benzer şekilde ve pyiçin ySkew de olur.

Bu diyagramdaki açı α gibi eğme açısı olarak eğmeyi belirtmeyi daha rahat hissedebilirsiniz:

Eğriltme dönüşümünün, eğme açısı belirtilen bir dikdörtgen üzerindeki etkisi

150 piksellik kaydırmanın 100 piksellik dikeye oranı, bu açının tanjantını oluşturur ve bu örnekte 56,3 derecedir.

Eğme Açısı Denemesi sayfasının XAML dosyası, Eğriltme Açısı sayfasına benzer, ancak Slider öğelerin –90 derece ile 90 derece arasında olması gerekir. Arka SkewAngleExperiment planda kod dosyası, sayfadaki metni ortalar ve çarpıklık merkezini sayfanın ortasına ayarlamak için kullanır Translate . Kodun en altındaki kısa SkewDegrees yöntem açıları eğme değerlerine dönüştürür:

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

Açı pozitif veya negatif 90 dereceye yaklaştıkça tanjant sonsuzluğa yaklaşır, ancak yaklaşık 80 dereceye kadar olan açılar kullanılabilir:

Eğme Açısı Denemesi sayfasının üç kez ekran görüntüsü

Küçük bir negatif yatay eğme, Eğik Metin sayfasında gösterildiği gibi eğik veya italik metinleri taklit edebilir. ObliqueTextPage sınıfı bunun nasıl yapıldığını gösterir:

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

TextAlign özelliği SKPaint olarak Centerayarlanır. Herhangi bir dönüşüm olmadan, DrawText koordinatları (0, 0) olan çağrı metni taban çizgisinin yatay ortasını sol üst köşeye konumlandırabilir. metni SkewDegrees taban çizgisine göre yatay olarak 20 derece eğer. Çağrı, Translate metnin taban çizgisinin yatay ortasını tuvalin ortasına taşır:

Eğik Metin sayfasının üçlü ekran görüntüsü

Gölge Metni Eğ sayfası, metinden uzaklaşan bir metin gölgesi oluşturmak için 45 derece eğme ve dikey ölçek birleşiminin nasıl kullanılacağını gösterir. İşleyicinin ilgili bölümü aşağıdadır PaintSurface :

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

Önce gölge, sonra da metin görüntülenir:

Gölge Metni Eğ sayfasının üç kez ekran görüntüsü

Yöntemine DrawText geçirilen dikey koordinat, metnin taban çizgisine göre konumunu gösterir. Bu, eğriltme merkezi için kullanılan dikey koordinatla aynıdır. Metin dizesi alt öğeleri içeriyorsa bu teknik çalışmaz. Örneğin, "quirky" sözcüğünü "Gölge" olarak değiştirin ve sonuç şu şekilde olur:

Gölge Metni Eğ sayfasının, alt öğeleri olan alternatif bir sözcükle üç kez ekran görüntüsü

Gölge ve metin hala taban çizgisine hizalanır, ancak efekt yanlış görünür. Bunu düzeltmek için metin sınırlarını edinmeniz gerekir:

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

Çağrıların Translate altların yüksekliğine göre ayarlanması gerekir:

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

Şimdi gölge, bu alt türlerin altından genişler:

Gölge Metni Eğ sayfasının alt öğeleri için ayarlamalar içeren üçlü ekran görüntüsü