# question

## SkiaSharp/Skia - Rotating shapes around their own axis

I am learning SkiaSharp and I'd like to have N shapes rotating around their own vertical axis, but I can't find a way to do it.

This is the result of my OnDraw method (rotationView is updated every N milliseconds):

``````  protected override void OnDraw(SKCanvas canvas, int width, int height)
{
int i = 0;
int step = 0;
List<SKRect> rects = new List<SKRect>();

// get the 2D equivalent of the 3D matrix
var rotationMatrix = rotationView.Matrix;

// get the properties of the rectangle
var length = Math.Min(width / 6, height / 6);

canvas.Clear(EffectMedia.Colors.XamarinLightBlue);

foreach (var n in numbers)
{
var rect = new SKRect(0 + step, 0, 100 + step, 100);
step += 120;
}

//var sideHoriz = rotationMatrix.MapPoint(new SKPoint(0, 1)).Y > 0;
var sideVert = rotationMatrix.MapPoint(new SKPoint(1, 0)).X > 0;

var paint = new SKPaint
{
Color = sideVert ? EffectMedia.Colors.XamarinPurple : EffectMedia.Colors.XamarinGreen,
Style = SKPaintStyle.Fill,
IsAntialias = true
};

// first do 2D translation to the center of the screen
canvas.Translate((width - (120 * numbers.Count)) / 2, height / 2);

// The following line is disabled because it makes the whole canvas rotate!
// canvas.Concat(ref rotationMatrix);

foreach (var n in numbers)
{
canvas.RotateDegrees((float)-3);
canvas.DrawRoundRect(rects[i], 30, 30, paint);

new SKPoint(0, 0), new SKPoint(0, length * 2),
new[] { paint.Color.WithAlpha(127), paint.Color.WithAlpha(0) },
null,

{
Style = SKPaintStyle.Fill,
IsAntialias = true,
BlendMode = SKBlendMode.SoftLight
};

foreach (var r in rects)
{
r.Offset(0, 105);
}

i++;
}
}
``````

I tried using SKPath + Transform, saving&restoring the rotationMatrix and/or the canvas but I can't find a way to have 6 rotating boxes around their own axis.

Do you have any hint on how that can be achieved? Do I need N rotation matrices?

Thanks!

cho7x.png (53.5 KiB)
· 2

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi, Sal-Datoccio. The animation you want is hard to develop this SKMatrix transform working solely within two dimensions, try using 3d animation instead. You could check the following the doc to get the details about the function.
https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/graphics/skiasharp/transforms/3d-rotation

Here is the related sample code, you could refer to it.
https://github.com/xamarin/xamarin-forms-samples/blob/master/SkiaSharpForms/Demos/Demos/SkiaSharpFormsDemos/Transforms/AnimatedRotation3DPage.cs

1 Vote 1 ·
JarvanZhang-MSFT

Thank you!

I am going to check the AnimatedRotation3DPage demo, for now I am able to rotate those figures around their own Z-axis with:

canvas.Save();
canvas.RotateDegrees(degrees, rects[i].MidX, rects[i].MidY);
canvas.DrawRoundRect(rects[i], 30, 30, paint);
canvas.Restore();

I was also using a Skia3DView, but I can't manage to make it work without rotating the whole canvas. I also tried with paths and related transforms, with no luck.

Thanks

`

My goal would be to have N shapes rotating around their axes, something like:

Would could be a viable approach in SkiaSharp (I'd just need some directions)?

Thanks :)

untitled.png (67.8 KiB)

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Hi, Sal-Datoccio. According to my search, it doesn't provide a way to get the drawing sharp. A workaround is using SKCanvasView to draw each sharp one separately, and rotate the skCanvasViews.

Here is the related code, you could refer to it.

``````public partial class TestPage : ContentPage
{
public TestPage()
{
Title = "Testing for Animated Rotation";

canvasView1 = new SKCanvasView() { AutomationId = "1" };
canvasView2 = new SKCanvasView() { AutomationId = "2" };
canvasView3 = new SKCanvasView() { AutomationId = "3" };
canvasView4 = new SKCanvasView() { AutomationId = "4" };
canvasView5 = new SKCanvasView() { AutomationId = "5" };
canvasView6 = new SKCanvasView() { AutomationId = "6" };

canvasView1.PaintSurface += OnCanvasViewPaintSurface;
canvasView2.PaintSurface += OnCanvasViewPaintSurface;
canvasView3.PaintSurface += OnCanvasViewPaintSurface;
canvasView4.PaintSurface += OnCanvasViewPaintSurface;
canvasView5.PaintSurface += OnCanvasViewPaintSurface;
canvasView6.PaintSurface += OnCanvasViewPaintSurface;
Content = new StackLayout()
{
HorizontalOptions = LayoutOptions.Center,
Orientation = StackOrientation.Horizontal,
Children = { canvasView1, canvasView2, canvasView3, canvasView4, canvasView5, canvasView6 }
};

// Measure the text
textPaint.MeasureText(text1, ref textBounds);
}

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

new Animation((value) =>
{
yRotationDegrees = 360 * (float)value;
canvasView1.InvalidateSurface();
canvasView2.InvalidateSurface();
canvasView3.InvalidateSurface();
canvasView4.InvalidateSurface();
canvasView5.InvalidateSurface();
canvasView6.InvalidateSurface();
}).Commit(this, "yRotationAnimation", length: 1000, repeat: () => true);
}
protected override void OnDisappearing()
{
base.OnDisappearing();
//this.AbortAnimation("xRotationAnimation");
this.AbortAnimation("yRotationAnimation");
//this.AbortAnimation("zRotationAnimation");
}
void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs args)
{
SKImageInfo info = args.Info;
SKSurface surface = args.Surface;
SKCanvas canvas = surface.Canvas;

canvas.Clear();

// Find center of canvas
float xCenter = info.Width / 2;
float yCenter = info.Height / 2;

// Translate center to origin
SKMatrix matrix = SKMatrix.MakeTranslation(-xCenter, -yCenter);

float scale = 1;
SKMatrix.PostConcat(ref matrix, SKMatrix.MakeScale(scale, scale));

// Calculate composite 3D transforms
float depth = 0.75f * scale * textBounds.Width;

SKMatrix44 matrix44 = SKMatrix44.CreateIdentity();
//matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(1, 0, 0, xRotationDegrees));
matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 1, 0, yRotationDegrees));
//matrix44.PostConcat(SKMatrix44.CreateRotationDegrees(0, 0, 1, zRotationDegrees));

SKMatrix44 perspectiveMatrix = SKMatrix44.CreateIdentity();
perspectiveMatrix[3, 2] = -1 / depth;
matrix44.PostConcat(perspectiveMatrix);

// Concatenate with 2D matrix
SKMatrix.PostConcat(ref matrix, matrix44.Matrix);

// Translate back to center
SKMatrix.PostConcat(ref matrix,
SKMatrix.MakeTranslation(xCenter, yCenter));

// Set the matrix and display the text
canvas.SetMatrix(matrix);
float xText = xCenter - textBounds.MidX;
float yText = yCenter - textBounds.MidY;

SKCanvasView view = sender as SKCanvasView;
switch (view.AutomationId)
{
case "1":
canvas.DrawText(text1, xText, yText, textPaint);
break;
case "2":
canvas.DrawText(text2, xText, yText, textPaint);
break;
case "3":
canvas.DrawText(text3, xText, yText, textPaint);
break;
case "4":
canvas.DrawText(text4, xText, yText, textPaint);
break;
case "5":
canvas.DrawText(text5, xText, yText, textPaint);
break;
case "6":
canvas.DrawText(text6, xText, yText, textPaint);
break;
}
}
}``````

· 1

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

The related parameters of the above page.

``````SKCanvasView canvasView1;
SKCanvasView canvasView2;
SKCanvasView canvasView3;
SKCanvasView canvasView4;
SKCanvasView canvasView5;
SKCanvasView canvasView6;

float yRotationDegrees;

string text1 = "S";
string text2 = "k";
string text3 = "S";
string text4 = "h";
string text5 = "r";
string text6 = "p";

SKPaint textPaint = new SKPaint
{
Style = SKPaintStyle.Stroke,
Color = SKColors.Black,
TextSize = 100,
StrokeWidth = 3,
};
SKRect textBounds;``````