좌표 이동 변환
변환 변환을 사용하여 SkiaSharp 그래픽을 이동하는 방법 알아보기
SkiaSharp에서 가장 간단한 변환 유형은 번역 또는 번역 변환입니다. 이 변환은 그래픽 개체를 가로 및 세로 방향으로 이동합니다. 어떤 의미에서 변환은 그리기 함수에서 사용하는 좌표를 단순히 변경하여 동일한 효과를 달성할 수 있기 때문에 가장 불필요한 변환입니다. 그러나 경로를 렌더링할 때는 모든 좌표가 경로에 캡슐화되므로 변환 변환을 적용하여 전체 경로를 이동하는 것이 훨씬 쉽습니다.
번역은 애니메이션 및 간단한 텍스트 효과에도 유용합니다.
메서드에는 Translate
SKCanvas
이후에 그려진 그래픽 개체가 가로 및 세로로 이동되도록 하는 두 개의 매개 변수가 있습니다.
public void Translate (Single dx, Single dy)
이러한 인수는 음수일 수 있습니다. 두 번째 Translate
메서드는 두 변환 값을 단일 SKPoint
값으로 결합합니다.
public void Translate (SKPoint point)
샘플 프로그램의 누적 번역 페이지는 메서드의 여러 호출이 누적됨을 Translate
보여 줍니다. 클래스는 AccumulatedTranslatePage
동일한 사각형의 20개 버전을 표시하며, 각 버전은 대각선을 따라 뻗어 있을 정도로 이전 사각형의 오프셋입니다. PaintSurface
이벤트 처리기는 다음과 같습니다.
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())
{
strokePaint.Color = SKColors.Black;
strokePaint.Style = SKPaintStyle.Stroke;
strokePaint.StrokeWidth = 3;
int rectangleCount = 20;
SKRect rect = new SKRect(0, 0, 250, 250);
float xTranslate = (info.Width - rect.Width) / (rectangleCount - 1);
float yTranslate = (info.Height - rect.Height) / (rectangleCount - 1);
for (int i = 0; i < rectangleCount; i++)
{
canvas.DrawRect(rect, strokePaint);
canvas.Translate(xTranslate, yTranslate);
}
}
}
연속 사각형이 페이지 아래로 흘러내립니다.
누적된 변환 요소와 dy
그리기 함수에서 지정한 점이 (x
, y
),이면 그래픽 개체가 지점(x'
, y'
)에서 렌더링됩니다. 여기서 다음을 수행합니다dx
.
x' = x + dx
y' = y + dy
이를 번역을 위한 변환 수식이라고 합니다 . 새 SKCanvas
항목의 dx
기본값은 dy
0입니다.
텍스트 효과 번역 페이지에서 볼 수 있듯이 그림자 효과 및 유사한 기술에 번역 변환을 사용하는 것이 일반적입니다. 클래스의 처리기의 TranslateTextEffectsPage
관련 부분은 PaintSurface
다음과 같습니다.
float textSize = 150;
using (SKPaint textPaint = new SKPaint())
{
textPaint.Style = SKPaintStyle.Fill;
textPaint.TextSize = textSize;
textPaint.FakeBoldText = true;
float x = 10;
float y = textSize;
// Shadow
canvas.Translate(10, 10);
textPaint.Color = SKColors.Black;
canvas.DrawText("SHADOW", x, y, textPaint);
canvas.Translate(-10, -10);
textPaint.Color = SKColors.Pink;
canvas.DrawText("SHADOW", x, y, textPaint);
y += 2 * textSize;
// Engrave
canvas.Translate(-5, -5);
textPaint.Color = SKColors.Black;
canvas.DrawText("ENGRAVE", x, y, textPaint);
canvas.ResetMatrix();
textPaint.Color = SKColors.White;
canvas.DrawText("ENGRAVE", x, y, textPaint);
y += 2 * textSize;
// Emboss
canvas.Save();
canvas.Translate(5, 5);
textPaint.Color = SKColors.Black;
canvas.DrawText("EMBOSS", x, y, textPaint);
canvas.Restore();
textPaint.Color = SKColors.White;
canvas.DrawText("EMBOSS", x, y, textPaint);
}
세 가지 Translate
예제 각각에서 지정한 위치 x
와 y
변수에서 오프셋하는 텍스트를 표시하기 위해 호출됩니다. 그런 다음 번역 효과가 없는 다른 색으로 텍스트가 다시 표시됩니다.
세 가지 예제 각각은 호출을 부정하는 Translate
다른 방법을 보여 줍니다.
첫 번째 예제에서는 단순히 다시 호출 Translate
하지만 음수 값을 사용합니다. 호출은 Translate
누적되므로 이 호출 시퀀스는 단순히 전체 변환을 기본값 0으로 복원합니다.
두 번째 예제에서는 .를 호출합니다 ResetMatrix
. 이렇게 하면 모든 변환이 기본 상태로 돌아갑니다.
세 번째 예제에서는 호출 Save
을 사용하여 개체의 SKCanvas
상태를 저장한 다음 호출을 사용하여 Restore
상태를 복원합니다. 이 방법은 일련의 그리기 작업에 대한 변환을 조작하는 가장 다양한 방법입니다. 이러한 Save
호출은 스택과 Restore
같은 함수입니다. 여러 번 호출 Save
한 다음 역순으로 호출 Restore
하여 이전 상태로 돌아갈 수 있습니다. 이 메서드는 Save
정수를 반환하며, 이 정수는 여러 번 효과적으로 호출 Restore
하도록 RestoreToCount
전달할 수 있습니다. 이 속성은 SaveCount
현재 스택에 저장된 상태 수를 반환합니다.
캔버스 상태를 복원하는 데 클래스를 사용할 SKAutoCanvasRestore
수도 있습니다. 이 클래스의 생성자는 문에서 using
호출됩니다. 캔버스 상태는 블록의 using
끝에서 자동으로 복원됩니다.
그러나 처리기의 한 호출에서 다음 호출로 전달되는 변환에 PaintSurface
대해 걱정할 필요가 없습니다. 각 새 호출은 PaintSurface
기본 변환을 사용하여 새 SKCanvas
개체를 제공합니다.
변환의 Translate
또 다른 일반적인 용도는 그리기에 편리한 좌표를 사용하여 원래 만들어진 시각적 개체를 렌더링하는 것입니다. 예를 들어 중심이 점(0, 0)인 아날로그 클록의 좌표를 지정할 수 있습니다. 그런 다음 변환을 사용하여 원하는 위치에 시계를 표시할 수 있습니다. 이 기술은 [헨데카그램 배열] 페이지에서 설명합니다. 클래스는 HendecagramArrayPage
11개의 뾰족한 별에 대한 개체를 만들어 SKPath
시작합니다. 개체는 HendecagramPath
공용, 정적 및 읽기 전용으로 정의되므로 다른 데모 프로그램에서 액세스할 수 있습니다. 정적 생성자에서 생성됩니다.
public class HendecagramArrayPage : ContentPage
{
...
public static readonly SKPath HendecagramPath;
static HendecagramArrayPage()
{
// Create 11-pointed star
HendecagramPath = new SKPath();
for (int i = 0; i < 11; i++)
{
double angle = 5 * i * 2 * Math.PI / 11;
SKPoint pt = new SKPoint(100 * (float)Math.Sin(angle),
-100 * (float)Math.Cos(angle));
if (i == 0)
{
HendecagramPath.MoveTo(pt);
}
else
{
HendecagramPath.LineTo(pt);
}
}
HendecagramPath.Close();
}
}
별의 중심이 점(0, 0)이면 별의 모든 점이 해당 지점을 둘러싼 원에 있습니다. 각 지점은 360도의 5/11까지 증가하는 각도의 사인 값과 코사인 값의 조합입니다. (원의 각도를 2/11, 3/11 또는 4/11까지 늘려 11개의 뾰족한 별을 만들 수도 있습니다.) 해당 원의 반지름은 100으로 설정됩니다.
이 경로가 변환 없이 렌더링되는 경우 가운데는 왼쪽 위 모서리 SKCanvas
에 배치되고 그 중 4분의 1만 표시됩니다. PaintSurface
대신 처리기는 HendecagramPage
별의 여러 복사본을 사용하여 캔버스에 타일을 지정하는 데 사용합니다Translate
. 각 개체는 임의로 색이 지정됩니다.
public class HendecagramArrayPage : ContentPage
{
Random random = new Random();
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
using (SKPaint paint = new SKPaint())
{
for (int x = 100; x < info.Width + 100; x += 200)
for (int y = 100; y < info.Height + 100; y += 200)
{
// Set random color
byte[] bytes = new byte[3];
random.NextBytes(bytes);
paint.Color = new SKColor(bytes[0], bytes[1], bytes[2]);
// Display the hendecagram
canvas.Save();
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPath, paint);
canvas.Restore();
}
}
}
}
결과:
애니메이션에는 종종 변환이 포함됩니다. 헨데카그램 애니메이션 페이지는 원을 그리며 11-뾰족한 별을 이동합니다. 클래스는 HendecagramAnimationPage
타이머를 시작하고 중지하기 위한 일부 필드와 OnDisappearing
메서드의 재정의 OnAppearing
로 Xamarin.Forms 시작합니다.
public class HendecagramAnimationPage : ContentPage
{
const double cycleTime = 5000; // in milliseconds
SKCanvasView canvasView;
Stopwatch stopwatch = new Stopwatch();
bool pageIsActive;
float angle;
public HendecagramAnimationPage()
{
Title = "Hedecagram Animation";
canvasView = new SKCanvasView();
canvasView.PaintSurface += OnCanvasViewPaintSurface;
Content = canvasView;
}
protected override void OnAppearing()
{
base.OnAppearing();
pageIsActive = true;
stopwatch.Start();
Device.StartTimer(TimeSpan.FromMilliseconds(33), () =>
{
double t = stopwatch.Elapsed.TotalMilliseconds % cycleTime / cycleTime;
angle = (float)(360 * t);
canvasView.InvalidateSurface();
if (!pageIsActive)
{
stopwatch.Stop();
}
return pageIsActive;
});
}
protected override void OnDisappearing()
{
base.OnDisappearing();
pageIsActive = false;
}
...
}
angle
필드는 5초마다 0도에서 360도로 애니메이션됩니다. PaintSurface
처리기는 두 가지 방법으로 속성을 사용 합니다angle
. 메서드에서 SKColor.FromHsl
색의 색조를 지정 하 고 별의 위치를 제어 하는 Math.Sin
Math.Cos
및 메서드에 대 한 인수로:
public class HendecagramAnimationPage : ContentPage
{
...
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;
canvas.Clear();
canvas.Translate(info.Width / 2, info.Height / 2);
float radius = (float)Math.Min(info.Width, info.Height) / 2 - 100;
using (SKPaint paint = new SKPaint())
{
paint.Style = SKPaintStyle.Fill;
paint.Color = SKColor.FromHsl(angle, 100, 50);
float x = radius * (float)Math.Sin(Math.PI * angle / 180);
float y = -radius * (float)Math.Cos(Math.PI * angle / 180);
canvas.Translate(x, y);
canvas.DrawPath(HendecagramPage.HendecagramPath, paint);
}
}
}
PaintSurface
처리기는 메서드를 Translate
두 번 호출하고, 먼저 캔버스의 중심으로 변환한 다음, 가운데에 있는 원의 둘레(0, 0)로 변환합니다. 원의 반지름은 페이지의 범위 내에서 별을 유지하면서 가능한 한 크게 설정됩니다.
별은 기본 페이지의 가운데를 중심으로 회전할 때와 동일한 방향을 지정합니다. 전혀 회전하지 않습니다. 회전 변환에 대한 작업입니다.