Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Decompose 2D Transformation Matrix

Tags:

c#

math

direct2d

So, I have a Direct2D Matrix3x2F that I use to store transformations on geometries. I want these transformations to be user-editable, and I don't want the user to have to edit a matrix directly. Is it possible to decompose a 3x2 matrix into scaling, rotation, skewing, and translation?

like image 874
laptou Avatar asked Dec 23 '22 16:12

laptou


2 Answers

This is the solution I found for a Direct2D transformation matrix:

  • scale x = sqrt(M11 * M11 + M12 * M12)

  • scale y = sqrt(M21 * M21 + M22 * M22) * cos(shear)

  • rotation = atan2(M12, M11)

  • shear (y) = atan2(M22, M21) - PI/2 - rotation

  • translation x = M31

  • translation y = M32

If you multiply these values back together in the order scale(x, y) * skew(0, shear) * rotate(angle) * translate(x, y) you will get a matrix that performs an equivalent transformation.

like image 90
laptou Avatar answered Dec 28 '22 10:12

laptou


  1. Decomposition

    yes you can (at least partially). 3x2 transform matrix represents 2D homogenuous 3x3 transform matrix without projections. Such transform matrix is either OpenGL style:

     | Xx Yx Ox |
     | Xy Yy Oy |
    

    or DirectX style:

     | Xx Xy |
     | Yx Yy |
     | Ox Oy |
    

    As you tagged Direct2D and using 3x2 matrix then the second is the one you got. There are 3 vectors:


    X=(Xx,Xy) X axis vector
    Y=(Yx,Yy) Y axis vector
    O=(Ox,Oy) Origin of coordinate system.

    Now lets assume that there is no skew present and the matrix is orthogonal...

  2. Scaling

    is very simple just obtain the axises basis vectors lengths.

     scalex = sqrt( Xx^2 + Xy^2 );
     scaley = sqrt( Yx^2 + Yy^2 );
    

    if scale coefficient is >1 the matrix scales up and if <1 scales down.

  3. rotation

    You can use:

     rotation_ang=atan2(Xy,Yx);
    
  4. translation

    The offset is O so if it is non zero you got translation present.

  5. Skew

    In 2D skew does not complicate things too much and the bullets above still apply (not the case for 3D). The skew angle is the angle between axises minus 90 degrees so:

     skew_angle = acos((X.Y)/(|X|.|Y|)) - 0.5*PI;
     skew_angle = acos((Xx*Yx + Xy*Yy)/sqrt(( Xx^2 + Xy^2 )*( Yx^2 + Yy^2 ))) - 0.5*PI;
    

Also beware if your transform matrix does not represent your coordinate system but its inverse then you need to inverse your matrix before applying this...

So compute first inverse of:

| Xx Xy 0 |
| Yx Yy 0 |
| Ox Oy 1 |

And apply the above on the result.

For more info about this topic see:

  • Understanding 4x4 homogenous transform matrices

Especially the difference between column major and row major orders (OpenGL vs. DirectX notation)

like image 26
Spektre Avatar answered Dec 28 '22 09:12

Spektre