Преобразование наклона
Узнайте, как преобразование смещением может создавать наклонированные графические объекты в SkiaSharp
В SkiaSharp преобразование смещением наклоняет графические объекты, такие как тень в этом изображении:
Скошение превращает прямоугольник в параллелограмму, но многоточие по-прежнему является многоточием.
Хотя Xamarin.Forms определяет свойства для преобразования, масштабирования и поворотов, для изменения не существует соответствующего свойства Xamarin.Forms .
Метод Skew
принимает два аргумента для горизонтального размыка и вертикального SKCanvas
размыка:
public void Skew (Single xSkew, Single ySkew)
Второй Skew
метод объединяет эти аргументы в одном SKPoint
значении:
public void Skew (SKPoint skew)
Однако вряд ли вы будете использовать один из этих двух методов в изоляции.
На странице "Эксперимент с отклонением" можно экспериментировать со значениями с размыкаемого диапазона от –10 до 10. Текстовая строка размещается в левом верхнем углу страницы с значениями с размыканиями, полученными из двух Slider
элементов. Ниже приведен PaintSurface
обработчик класса 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);
}
}
Значения аргумента xSkew
сдвигаются внизу текста вправо для положительных значений или влево для отрицательных значений. ySkew
Значения смещения справа от текста вниз для положительных значений или вверх для отрицательных значений:
xSkew
Если значение является отрицательным значениемySkew
, результатом является поворот, но также масштабируется несколько.
Формулы преобразования приведены следующим образом:
x ' = x + xSkew · Y
y' = ySkew · x + y
Например, для положительного xSkew
значения преобразованное x'
значение увеличивается по мере y
увеличения. Это то, что вызывает наклон.
Если треугольник шириной 200 пикселей и высотой 100 пикселей находится в левом верхнем углу в точке (0, 0) и отображается со xSkew
значением 1,5, следующие результаты параллелограммы:
Координаты нижнего края имеют y
значения 100, поэтому он сдвигается 150 пикселей вправо.
Для ненулевых значений xSkew
или ySkew
только точек (0, 0) остается неизменным. Этот момент можно считать центром размыкания. Если вам нужен центр перекоса, чтобы быть чем-то другим (как правило, это так), нет Skew
метода, который предоставляет это. Вам потребуется явно объединить Translate
вызовы с вызовом Skew
. Чтобы отцентрировать отклонение px
, py
выполните следующие вызовы:
canvas.Translate(px, py);
canvas.Skew(xSkew, ySkew);
canvas.Translate(-px, -py);
Составные формулы преобразования:
x ' = x + xSkew · (y – py)
y' = ySkew · (x – px) + y
Если ySkew
значение равно нулю, px
то значение не используется. Значение не имеет значения и аналогично ySkew
py
.
Вы можете чувствовать себя более комфортно, указывая наклон в виде угла наклона, например угол α на этой схеме:
Соотношение 150-пиксельного смещения к вертикали 100 пикселей является тангенсом этого угла, в этом примере 56,3 градуса.
XAML-файл страницы "Эксперимент с наклоном" похож на страницу "Угол с размыкания", за исключением того, что Slider
элементы варьируются от –90 градусов до 90 градусов. Файл SkewAngleExperiment
программной части размещает текст на странице и используется Translate
для задания центра перемежания в центр страницы. Короткий SkewDegrees
метод в нижней части кода преобразует угловые значения в отклонение значений:
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));
}
По мере того как угол приближается к положительным или отрицательным 90 градусам, тангенс приближается к бесконечности, но угол до около 80 градусов или так можно использовать:
Небольшое отрицательное горизонтальное отклонение может имитировать косый или курсивный текст, как показано на странице "Косый текст ". В ObliqueTextPage
классе показано, как это сделать:
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
свойства SKPaint
задано значение Center
. Без DrawText
каких-либо преобразований вызов с координатами (0, 0) будет размещать текст с горизонтальным центром базового плана в верхнем левом углу. Перекос SkewDegrees
текста по горизонтали 20 градусов относительно базового плана. Вызов Translate
перемещает горизонтальный центр базового плана текста в центр холста:
На странице "Теневой текст" показано, как использовать сочетание 45-градусного смещения и вертикального масштабирования для создания тени текста, которая наклоняется от текста. Ниже приведена соответствующая часть обработчика 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);
}
Сначала отображается тень, а затем текст:
Вертикальная координата, передаваемая DrawText
методу, указывает положение текста относительно базового плана. Это та же вертикальная координата, используемая для центра размыкания. Этот метод не будет работать, если текстовая строка содержит нисходящие элементы. Например, замените слово "причудливый" на "Тень" и вот результат:
Тени и текст по-прежнему выровнены на базовом уровне, но эффект просто выглядит неправильно. Чтобы исправить его, необходимо получить границы текста:
SKRect textBounds = new SKRect();
textPaint.MeasureText(text, ref textBounds);
Вызовы Translate
должны быть скорректированы высотой нисходящих элементов:
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);
Теперь тень простирается от нижней части этих нисходов: