Decompose 2D Transformation Matrix
Asked Answered
L

3

11

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?

Lael answered 18/7, 2017 at 6:39 Comment(0)
L
14

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.

Lael answered 29/7, 2017 at 19:2 Comment(0)
T
6
  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:

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

Toe answered 18/7, 2017 at 7:50 Comment(0)
E
1

Store the primary transformations in a class with editable properites

   scaling
   rotation
   skewing
   translation

and then build the final transform matrix from those. It will be easier that way. However if you must there are algorithms for decomposing a matrix. They are not as simple as you might think.

System.Numerics has a method for decomposing 3D transform matrices

https://github.com/dotnet/corefx/blob/master/src/System.Numerics.Vectors/src/System/Numerics/Matrix4x4.cs#L1497

Ene answered 18/7, 2017 at 6:58 Comment(1)
The question asked about 2D matricesLael

© 2022 - 2024 — McMap. All rights reserved.