Sdílet prostřednictvím


Transformace zkosení

Podívejte se, jak transformace nerovnoměrné distribuce může vytvářet nakloněné grafické objekty ve SkiaSharpu.

V skiaSharp transformuje nerovnoměrná transformace grafické objekty, jako je stín na tomto obrázku:

Příklad skewing z programu Šikmý stínový text

Nerovnoměrná distribuce změní obdélník na paralelogram, ale zkosené tři tečky jsou stále tři tečky.

Přestože Xamarin.Forms definuje vlastnosti pro překlad, škálování a otočení, neexistuje žádná odpovídající vlastnost Xamarin.Forms pro nerovnoměrnou distribuci.

Metoda SkewSKCanvas přijímá dva argumenty pro vodorovnou nerovnoměrnou a svislou nerovnoměrnou distribuci:

public void Skew (Single xSkew, Single ySkew)

Druhá Skew metoda kombinuje tyto argumenty v jedné SKPoint hodnotě:

public void Skew (SKPoint skew)

Je ale nepravděpodobné, že byste některou z těchto dvou metod používali izolovaně.

Na stránce Experiment nerovnoměrné distribuce můžete experimentovat se zkosenými hodnotami, které jsou v rozsahu od –10 do 10. Textový řetězec se umístí do levého horního rohu stránky se zkosenými hodnotami získanými ze dvou Slider prvků. Tady je obslužná rutina PaintSurfaceSkewExperimentPage ve třídě:

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

Hodnoty argumentu xSkew posunou dolní část textu doprava pro kladné hodnoty nebo doleva pro záporné hodnoty. Hodnoty posunu ySkew vpravo od textu dolů pro kladné hodnoty nebo nahoru pro záporné hodnoty:

Trojitý snímek obrazovky se stránkou Experiment nerovnoměrné distribuce

xSkew Pokud je hodnota zápornou hodnotouySkew, výsledek se otočí, ale také poněkud škáluje.

Vzorce transformace jsou následující:

x' = x + xSkew · Y

y' = ySkew · x + y

Například u kladné xSkew hodnoty se transformovaná x' hodnota zvyšuje při y nárůstu. To je to, co způsobuje naklonění.

Pokud je trojúhelník o šířce 200 pixelů a výšku 100 pixelů umístěn s jeho levým horním rohem v bodě (0, 0) a je vykreslen s xSkew hodnotou 1,5, výsledek následujícího paralelogramu:

Účinek transformace nerovnoměrné distribuce na obdélník

Souřadnice dolního okraje mají y hodnoty 100, takže se posunou o 150 pixelů doprava.

Pro nenulové hodnoty xSkew nebo ySkew, pouze bod (0, 0) zůstává stejný. Tento bod lze považovat za střed skewingu. Pokud potřebujete centrum skewingu být něco jiného (což je obvykle případ), neexistuje žádná Skew metoda, která to poskytuje. Volání budete muset explicitně zkombinovat Translate s voláním Skew . Chcete-li zacentrovat skewing na px a py, proveďte následující volání:

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

Složené vzorce transformace jsou:

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

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

Pokud ySkew je nula, px hodnota se nepoužije. Hodnota je irelevantní, a podobně pro ySkew a py.

Můžete se cítit pohodlněji určit nerovnoměrnou distribuci jako úhel naklonění, například úhel α v tomto diagramu:

Efekt transformace zkosení na obdélníku s vyznačeným úhlem skewing

Poměr posunu 150 pixelů na svislý 100 pixelů je tangens tohoto úhlu, v tomto příkladu 56,3 stupňů.

Soubor XAML stránky Šikmý experiment se podobá stránce Úhlová zkosení s tím rozdílem, že Slider prvky jsou v rozsahu –90 stupňů až 90 stupňů. SkewAngleExperiment Soubor kódu za středem stránky zacentruje text na stránce a používá Translate k nastavení středu skewing na střed stránky. Krátká SkewDegrees metoda v dolní části kódu převede úhly na zkosení hodnot:

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

Jako úhel se blíží kladné nebo záporné 90 stupňů, tangens přistupuje k nekonečnu, ale úhly až do 80 stupňů nebo tak jsou použitelné:

Trojitý snímek obrazovky se stránkou Experiment se zkosením úhlu

Malá záporná vodorovná zkosenost může napodobovat oblik nebo kurzívu, jak ukazuje stránka Oblique Text . Třída ObliqueTextPage ukazuje, jak se to dělá:

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

Vlastnost TextAlignSKPaint je nastavena na Centerhodnotu . Bez jakýchkoli transformací DrawText by volání se souřadnicemi (0, 0) umístilo text do vodorovného středu účaří v levém horním rohu. Zkosí SkewDegrees text vodorovně o 20 stupňů vzhledem ke směrnému plánu. Volání Translate přesune vodorovné středy směrného plánu textu na střed plátna:

Trojitý snímek obrazovky se stránkou Oblique Text

Stránka Zkosení stínového textu ukazuje, jak pomocí kombinace 45stupňové nerovnoměrné distribuce a vertikálního měřítka vytvořit stín textu, který se nakloní od textu. Tady je relevantní část obslužné rutiny 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);
}

Nejprve se zobrazí stín a pak text:

Trojitý snímek obrazovky se stránkou Stínový text nerovnoměrné distribuce

Svislá souřadnice předaná DrawText metodě označuje pozici textu vzhledem ke směrnému plánu. To je stejná svislá souřadnice používaná pro střed skewingu. Tato technika nebude fungovat, pokud textový řetězec obsahuje sestupné hodnoty. Například nahraďte slovo "quirky" slovem "Shadow" (Stín) a výsledek:

Triple screenshot of the Skew Shadow Text page with an alternative word with descenders

Stín a text jsou pořád zarovnané na účaří, ale efekt vypadá špatně. Pokud ho chcete opravit, musíte získat hranice textu:

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

Volání Translate je potřeba upravit výškou sestupných hodnot:

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

Stín se teď rozšiřuje od dolní části těchto sestupných:

Triple screenshot of the Skew Shadow Text page with adjustments for descenders