How do I compose these two matrices in SkiaSharp?

I am being driven nuts by what should be a dead simple bit of matrix maths.

I am drawing a simple graph using SkiaSharp. I have a SKPath, which describes the plot of the graph. I have simulated this in the code below by a silly bit of code that just produces 50 drawable points. To draw the graph, I wish to scale it horizontally according to a value that is updated when the user pinches the screen and I want to offset the graph by a fixed amount to line it up with the x=0 point on the screen.

In the code below, the first version of the code that does two separate transforms works fine. So I thought, for efficiency, I would combine the two matrices and do one single transform. I have tried all four combinations of pre- and post- concatenation and none of them stays overlaid on the first correct line. In other words, no matter how I compose the matrices, I cannot get the same result I get by applying the matrices separately.

What am I doing wrong?

SKCanvas canvas = null; // This is passed into the drawing function.

SKPaint pen = new SKPaint()
{
    Style = SKPaintStyle.Stroke,
    StrokeWidth = 1.0f,
    Color = SKColor.Parse( "#B0FFDD00" )
};

float horizontalScale = 1.0f;
float x = 0.0f;
float y = 0.0f;

SKPath path = new SKPath();
path.MoveTo( x, y );
for( int i = 0; i < 50; ++i )
{
    x = (float)( i * 10 );
    y += ( i % 10 == 0 ) ? -5.0f : (float)i * 0.8f;
    path.LineTo( x, y );
}

// This one works fine.
SKMatrix scaleMatrix1 = SKMatrix.MakeScale( horizontalScale, 1.0f );
path.Transform( scaleMatrix1 );
SKMatrix translationMatrix1 = SKMatrix.MakeTranslation( 50.0f, 0.0f );
path.Transform( translationMatrix1 );
canvas.DrawPath( path, pen );

// This does not work as expected.
SKMatrix scaleMatrix2 = SKMatrix.MakeScale( horizontalScale, 1.0f );
SKMatrix translationMatrix2 = SKMatrix.MakeTranslation( 50.0f, 0.0f );
SKMatrix.PreConcat( ref translationMatrix2, scaleMatrix2 );
path.Transform( translationMatrix2 );
canvas.DrawPath( path, pen );

// Neither does this.
SKMatrix scaleMatrix3 = SKMatrix.MakeScale( horizontalScale, 1.0f );
SKMatrix translationMatrix3 = SKMatrix.MakeTranslation( 50.0f, 0.0f );
SKMatrix.PostConcat( ref translationMatrix3, scaleMatrix3 );
path.Transform( translationMatrix3 );
canvas.DrawPath( path, pen );

// Neither does this.
SKMatrix scaleMatrix4 = SKMatrix.MakeScale( horizontalScale, 1.0f );
SKMatrix translationMatrix4 = SKMatrix.MakeTranslation( 50.0f, 0.0f );
SKMatrix.PreConcat( ref scaleMatrix4, translationMatrix4 );
path.Transform( scaleMatrix4 );
canvas.DrawPath( path, pen );

// And neither does this.
SKMatrix scaleMatrix5 = SKMatrix.MakeScale( horizontalScale, 1.0f );
SKMatrix translationMatrix5 = SKMatrix.MakeTranslation( 50.0f, 0.0f );
SKMatrix.PostConcat( ref scaleMatrix5, translationMatrix5 );
path.Transform( scaleMatrix5 );
canvas.DrawPath( path, pen );
Tagged:

Best Answers

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    I must have been doing something stupid. This now works as expected. The two code fragments shown below both perform exactly the same compound transformation as the code above where I perform the scale and translate in two separate steps.

    So these code fragments both work fine (though personally I find the former to be more intuitive):

    SKMatrix scaleMatrixA = SKMatrix.MakeScale( horizontalScale, 1.0f );
    SKMatrix transformMatrixA = SKMatrix.MakeTranslation( 20.0f, 0.0f );
    SKMatrix.PostConcat( ref scaleMatrixA, transformMatrixA );
    plotA.Transform( scaleMatrixA );
    canvas.DrawPath( plotA, penA );
    
    SKMatrix scaleMatrixB = SKMatrix.MakeScale( horizontalScale, 1.0f );
    SKMatrix transformMatrixB = SKMatrix.MakeTranslation( 20.0f, 0.0f );
    SKMatrix.PreConcat( ref transformMatrixB, scaleMatrixB );
    plotB.Transform( transformMatrixB );
    canvas.DrawPath( plotB, penB );
    

    Thank you to anyone who has taken the time to look at this problem.

    Kind wishes ~ Patrick

Answers

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭
    Accepted Answer

    I must have been doing something stupid. This now works as expected. The two code fragments shown below both perform exactly the same compound transformation as the code above where I perform the scale and translate in two separate steps.

    So these code fragments both work fine (though personally I find the former to be more intuitive):

    SKMatrix scaleMatrixA = SKMatrix.MakeScale( horizontalScale, 1.0f );
    SKMatrix transformMatrixA = SKMatrix.MakeTranslation( 20.0f, 0.0f );
    SKMatrix.PostConcat( ref scaleMatrixA, transformMatrixA );
    plotA.Transform( scaleMatrixA );
    canvas.DrawPath( plotA, penA );
    
    SKMatrix scaleMatrixB = SKMatrix.MakeScale( horizontalScale, 1.0f );
    SKMatrix transformMatrixB = SKMatrix.MakeTranslation( 20.0f, 0.0f );
    SKMatrix.PreConcat( ref transformMatrixB, scaleMatrixB );
    plotB.Transform( transformMatrixB );
    canvas.DrawPath( plotB, penB );
    

    Thank you to anyone who has taken the time to look at this problem.

    Kind wishes ~ Patrick

  • EasyGoingPatEasyGoingPat GBMember ✭✭✭

    @mattleibow Thanks for the reply.

    Sorry, I don't think my answer was clear. (Maybe I can edit it.) I don't use both of the code fragments above at the same time. I just showed them both as they both work okay - i.e. I was just highlighting that the world have matrix maths hasn't suddenly gone mad in my code.

    Your later examples about transforming the canvas are very interesting. I will certainly play with them.

    Thanks again.

    • Patrick
Sign In or Register to comment.