Aracılığıyla paylaş


Döndürme Dönüşümü

SkiaSharp döndürme dönüşümüyle mümkün olan efektleri ve animasyonları keşfedin

Döndürme dönüşümüyle, SkiaSharp grafik nesneleri yatay ve dikey eksenlerle hizalama kısıtlamasını azaltmaz:

Ortalanmış metin

Bir grafik nesnesini nokta etrafında döndürmek için (0, 0), SkiaSharp hem bir RotateDegrees yöntemi hem de bir RotateRadians yöntemi destekler:

public void RotateDegrees (Single degrees)

public Void RotateRadians (Single radians)

360 derecelik bir daire 2π radyan ile aynıdır, bu nedenle iki birim arasında kolayca dönüştürülebilir. Uygun olanı kullanın. .NET Math sınıfındaki tüm trigonometrik işlevler radyan birimlerini kullanır.

Döndürme, açıları artırmak için saat yönündedir. (Kartezyen koordinat sistemindeki döndürme, kural gereği saat yönünün tersine olsa da, Y koordinatlarının SkiaSharp'ta olduğu gibi aşağı inmesiyle tutarlıdır.) Negatif açılara ve 360 dereceden büyük açılara izin verilir.

Döndürmeye yönelik dönüştürme formülleri, çeviri ve ölçeklendirmeye yönelik formüllerden daha karmaşıktır. α açısı için dönüşüm formülleri şunlardır:

x' = x•cos(α) – y•sin(α)

y' = x•sin(α) + y•cos(α)

Temel Döndürme sayfasında yöntemi gösterilirRotateDegrees. BasicRotate.xaml.cs dosyası, taban çizgisi sayfada ortalanmış bir metin görüntüler ve –360 ile 360 arasında bir aralığı temel alarak Slider döndürür. İşleyicinin ilgili bölümü aşağıdadır PaintSurface :

using (SKPaint textPaint = new SKPaint
{
    Style = SKPaintStyle.Fill,
    Color = SKColors.Blue,
    TextAlign = SKTextAlign.Center,
    TextSize = 100
})
{
    canvas.RotateDegrees((float)rotateSlider.Value);
    canvas.DrawText(Title, info.Width / 2, info.Height / 2, textPaint);
}

Döndürme tuvalin sol üst köşesinde ortalandığından, bu programda ayarlanan çoğu açı için metin ekrandan döndürülür:

Temel Döndürme sayfasının üçlü ekran görüntüsü

Çoğu zaman ve RotateRadians yöntemlerinin şu sürümlerini kullanarak belirli bir özet noktasının etrafında ortalanmış bir şeyi döndürmek RotateDegrees istersiniz:

public void RotateDegrees (Single degrees, Single px, Single py)

public void RotateRadians (Single radians, Single px, Single py)

Ortalanmış Döndürme sayfası, Temel Döndürme'ye benzer, ancak genişletilmiş sürümü RotateDegrees döndürme merkezini metni konumlandırmak için kullanılan noktaya ayarlamak için kullanılır:

using (SKPaint textPaint = new SKPaint
{
    Style = SKPaintStyle.Fill,
    Color = SKColors.Blue,
    TextAlign = SKTextAlign.Center,
    TextSize = 100
})
{
    canvas.RotateDegrees((float)rotateSlider.Value, info.Width / 2, info.Height / 2);
    canvas.DrawText(Title, info.Width / 2, info.Height / 2, textPaint);
}

Artık metin, metni konumlandırmak için kullanılan nokta etrafında döner ve bu, metnin temelinin yatay orta noktasıdır:

Ortalanmış Döndürme sayfasının üçlü ekran görüntüsü

Yöntemin ortalanmış sürümünde Scale olduğu gibi, çağrının ortalanmış sürümü RotateDegrees bir kısayoldur. Yöntemi şu şekildedir:

RotateDegrees (degrees, px, py);

Bu çağrı aşağıdakine eşdeğerdir:

canvas.Translate(px, py);
canvas.RotateDegrees(degrees);
canvas.Translate(-px, -py);

Bazen aramaları aramalarla Rotate birleştirebileceğinizi Translate keşfedeceksiniz. Örneğin, Ortalanmış Döndürme sayfasındaki ve çağrıları aşağıda verilmiştir; RotateDegrees DrawText

canvas.RotateDegrees((float)rotateSlider.Value, info.Width / 2, info.Height / 2);
canvas.DrawText(Title, info.Width / 2, info.Height / 2, textPaint);

Çağrı RotateDegrees iki Translate çağrıya ve ortalanmamış RotateDegreesbir çağrıya eşdeğerdir:

canvas.Translate(info.Width / 2, info.Height / 2);
canvas.RotateDegrees((float)rotateSlider.Value);
canvas.Translate(-info.Width / 2, -info.Height / 2);
canvas.DrawText(Title, info.Width / 2, info.Height / 2, textPaint);

DrawText Belirli bir konumda metin görüntüleme çağrısı, bu konumun DrawText çağrısına Translate eşdeğerdir ve ardından noktada (0, 0):

canvas.Translate(info.Width / 2, info.Height / 2);
canvas.RotateDegrees((float)rotateSlider.Value);
canvas.Translate(-info.Width / 2, -info.Height / 2);
canvas.Translate(info.Width / 2, info.Height / 2);
canvas.DrawText(Title, 0, 0, textPaint);

Birbirini izleyen Translate iki çağrı birbirini iptal eder:

canvas.Translate(info.Width / 2, info.Height / 2);
canvas.RotateDegrees((float)rotateSlider.Value);
canvas.DrawText(Title, 0, 0, textPaint);

Kavramsal olarak, iki dönüşüm kodda nasıl göründüklerinin tam tersi sırayla uygulanır. Arama, DrawText metni tuvalin sol üst köşesinde görüntüler. Çağrı, RotateDegrees metni sol üst köşeye göre döndürür. Translate Ardından çağrı metni tuvalin ortasına taşır.

Döndürme ve çeviriyi birleştirmenin genellikle birkaç yolu vardır. Döndürülmüş Metin sayfası aşağıdaki ekranı oluşturur:

Döndürülmüş Metin sayfasının üç kez ekran görüntüsü

Sınıfın PaintSurface işleyicisi aşağıdadır RotatedTextPage :

static readonly string text = "    ROTATE";
...
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
    {
        Color = SKColors.Black,
        TextSize = 72
    })
    {
        float xCenter = info.Width / 2;
        float yCenter = info.Height / 2;

        SKRect textBounds = new SKRect();
        textPaint.MeasureText(text, ref textBounds);
        float yText = yCenter - textBounds.Height / 2 - textBounds.Top;

        for (int degrees = 0; degrees < 360; degrees += 30)
        {
            canvas.Save();
            canvas.RotateDegrees(degrees, xCenter, yCenter);
            canvas.DrawText(text, xCenter, yText, textPaint);
            canvas.Restore();
        }
    }
}

xCenter ve yCenter değerleri tuvalin merkezini gösterir. Değer yText , bundan biraz uzaklıktır. Bu değer, metni sayfada gerçekten dikey olarak ortalanmış olacak şekilde konumlandırmak için gereken Y koordinatıdır. Döngü daha for sonra tuvalin merkezine göre bir döndürme ayarlar. Döndürme 30 derecelik artışlarla yapılır. Metin değeri kullanılarak yText çizilir. Değerdeki "ROTATE" sözcüğünden önceki boşlukların text sayısı, bu 12 metin dizesi arasındaki bağlantının bir dodekagon gibi görünmesi için ampirik olarak belirlendi.

Bu kodu basitleştirmenin bir yolu, çağrıdan sonra DrawText döngü boyunca döndürme açısını her seferinde 30 derece artırmaktır. Bu, ve Restoreçağrısı gereksinimini Save ortadan kaldırır. Değişkenin degrees artık bloğun for gövdesinde kullanılmadığını göreceksiniz:

for (int degrees = 0; degrees < 360; degrees += 30)
{
    canvas.DrawText(text, xCenter, yText, textPaint);
    canvas.RotateDegrees(30, xCenter, yCenter);
}

Ayrıca, her şeyi tuvalin ortasına taşımak için Translate bir çağrıyla döngüye önceden haber vererek basit biçimini RotateDegrees kullanmak da mümkündür:

float yText = -textBounds.Height / 2 - textBounds.Top;

canvas.Translate(xCenter, yCenter);

for (int degrees = 0; degrees < 360; degrees += 30)
{
    canvas.DrawText(text, 0, yText, textPaint);
    canvas.RotateDegrees(30);
}

Değiştirilen yText hesaplama artık öğesini içermiyor yCenter. Artık çağrı metni DrawText tuvalin en üstünde dikey olarak ortalar.

Dönüşümler kavramsal olarak kodda görünme şeklinin tersine uygulandığından, genellikle daha fazla genel dönüşümle ve ardından daha fazla yerel dönüşümle başlamak mümkündür. Bu genellikle döndürme ve çeviriyi birleştirmenin en kolay yoludur.

Örneğin, ekseninde dönen bir gezegen gibi merkezinde dönen bir grafik nesne çizmek istediğinizi varsayalım. Ama aynı zamanda bu nesnenin güneş etrafında dönen bir gezegen gibi ekranın merkezinde dönmesini istiyorsunuz.

Bunu yapmak için, nesneyi tuvalin sol üst köşesine konumlandırabilir ve ardından bir animasyon kullanarak bu köşenin etrafında döndürebilirsiniz. Ardından nesneyi yörünge yarıçapı gibi yatay olarak çevirin. Şimdi de kaynağın etrafına ikinci bir animasyonlu döndürme uygulayın. Bu, nesnenin köşede döndürülmesini sağlar. Şimdi tuvalin merkezine çeviri yapın.

Bu dönüştürme çağrılarını PaintSurface ters sırada içeren işleyici aşağıdadır:

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

    canvas.Clear();

    using (SKPaint fillPaint = new SKPaint
    {
        Style = SKPaintStyle.Fill,
        Color = SKColors.Red
    })
    {
        // Translate to center of canvas
        canvas.Translate(info.Width / 2, info.Height / 2);

        // Rotate around center of canvas
        canvas.RotateDegrees(revolveDegrees);

        // Translate horizontally
        float radius = Math.Min(info.Width, info.Height) / 3;
        canvas.Translate(radius, 0);

        // Rotate around center of object
        canvas.RotateDegrees(rotateDegrees);

        // Draw a square
        canvas.DrawRect(new SKRect(-50, -50, 50, 50), fillPaint);
    }
}

revolveDegrees ve rotateDegrees alanları animasyonlu. Bu program, sınıfını Xamarin.FormsAnimation temel alan farklı bir animasyon tekniği kullanır. (Bu sınıf,ile Mobil UygulamaXamarin.Forms Oluşturma'nın ücretsiz PDF indirmesi ) Geçersiz OnAppearing kılma, geri çağırma yöntemleriyle iki Animation nesne oluşturur ve animasyon süresi boyunca bu nesneleri çağırır:Commit

protected override void OnAppearing()
{
    base.OnAppearing();

    new Animation((value) => revolveDegrees = 360 * (float)value).
        Commit(this, "revolveAnimation", length: 10000, repeat: () => true);

    new Animation((value) =>
    {
        rotateDegrees = 360 * (float)value;
        canvasView.InvalidateSurface();
    }).Commit(this, "rotateAnimation", length: 1000, repeat: () => true);
}

İlk Animation nesne 10 saniye boyunca 0 dereceden 360 dereceye kadar animasyon revolveDegrees ekler. İkincisi her 1 saniyede bir 0 dereceden 360 dereceye kadar animasyon rotateDegrees ekler ve ayrıca işleyiciye başka bir çağrı oluşturmak için PaintSurface yüzeyi geçersiz kılmaktadır. Geçersiz OnDisappearing kılma şu iki animasyonu iptal eder:

protected override void OnDisappearing()
{
    base.OnDisappearing();
    this.AbortAnimation("revolveAnimation");
    this.AbortAnimation("rotateAnimation");
}

Çirkin Analog Saat programı (daha çekici bir analog saat sonraki bir makalede açıklanacağı için denir), saatin dakika ve saat işaretlerini çizmek ve elleri döndürmek için döndürmeyi kullanır. Program, 100 yarıçapı olan noktada (0, 0) ortalanmış bir daireyi temel alan rastgele bir koordinat sistemi kullanarak saati çizer. Bu daireyi sayfada genişletmek ve ortalamak için çeviri ve ölçeklendirme kullanır.

Translate ve Scale çağrıları genel olarak saate uygulanır, bu nedenle nesnelerin başlatılmasından SKPaint sonra çağrılan ilk çağrılar şunlardır:

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())
    using (SKPaint fillPaint = new SKPaint())
    {
        strokePaint.Style = SKPaintStyle.Stroke;
        strokePaint.Color = SKColors.Black;
        strokePaint.StrokeCap = SKStrokeCap.Round;

        fillPaint.Style = SKPaintStyle.Fill;
        fillPaint.Color = SKColors.Gray;

        // Transform for 100-radius circle centered at origin
        canvas.Translate(info.Width / 2f, info.Height / 2f);
        canvas.Scale(Math.Min(info.Width / 200f, info.Height / 200f));
        ...
    }
}

2 farklı boyutta 60 mark vardır ve 24 saat daire içinde çizilmelidir. Çağrı, DrawCircle bu daireyi saatin merkezine göre 12:00'a karşılık gelen noktada (0, –90) çizer. Çağrı, RotateDegrees her değer işaretinden sonra döndürme açısını 6 derece artırır. angle değişkeni yalnızca büyük bir dairenin mi yoksa küçük bir dairenin mi çizileceğini belirlemek için kullanılır:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
        // Hour and minute marks
        for (int angle = 0; angle < 360; angle += 6)
        {
            canvas.DrawCircle(0, -90, angle % 30 == 0 ? 4 : 2, fillPaint);
            canvas.RotateDegrees(6);
        }
    ...
    }
}

Son olarak işleyici PaintSurface geçerli saati alır ve saat, dakika ve ikinci eller için döndürme derecelerini hesaplar. Döndürme açısının buna göre olması için her el 12:00 konumunda çizilir:

void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
    ...
        DateTime dateTime = DateTime.Now;

        // Hour hand
        strokePaint.StrokeWidth = 20;
        canvas.Save();
        canvas.RotateDegrees(30 * dateTime.Hour + dateTime.Minute / 2f);
        canvas.DrawLine(0, 0, 0, -50, strokePaint);
        canvas.Restore();

        // Minute hand
        strokePaint.StrokeWidth = 10;
        canvas.Save();
        canvas.RotateDegrees(6 * dateTime.Minute + dateTime.Second / 10f);
        canvas.DrawLine(0, 0, 0, -70, strokePaint);
        canvas.Restore();

        // Second hand
        strokePaint.StrokeWidth = 2;
        canvas.Save();
        canvas.RotateDegrees(6 * dateTime.Second);
        canvas.DrawLine(0, 10, 0, -80, strokePaint);
        canvas.Restore();
    }
}

Eller oldukça kaba olmasına rağmen saat kesinlikle işlevseldir:

Çirkin Analog Saat Metni sayfasının üçlü ekran görüntüsü

Daha çekici bir saat için SkiaSharp'ta SVG Yol Verileri makalesine bakın.