I'm trying to undo some transformations coming from an external tool*. I'm getting different results depending on subtle differences in the input and wondering how to convert to a rotation about the Z-axis only.

The transformations are expressed as a matrix = translation * rotation * -translation. I want to decompose the resulting matrix into a single translation and rotation around Z -- I know this is possible given the source material (2D plane).

My problem is coming from GLM decompose. Given a matrix that looks like this:

[         -0.5 |     0.866025 |            0 |            0 ]
[    -0.866025 |         -0.5 |            0 |            0 ]
[            0 |            0 |            1 |            0 ]
[            0 |            0 |            0 |            1 ]

If I call decompose, then take the eulerAngles of the Rotation I end up with either:

  • ( 0, -0, 2.09439 ) from quat( 0.5, 0, 0.866025, 0 )
  • ( 3.14159, 1.0472, 3.14159 ) from quat( 0.5, 0, 0, 0.866025 )

The difference depends on how the matrix was generated, whether the rotation was 120degrees or -240degrees. The display must be clipping the floating point, introducing a subtle change.

I'm assuming both these rotations are actually the same.

How do I force/convert the result to be a rotation about the Z axis only.

*The external tool is Inkscape which uses the CSS/SVG function rotate(r, cx, cy) instead of a rotation and transform. That function results in the matrix: translate(cx,cy,0) * rotate(r, (0,0,1)) * translate(-cx,cy,0)


1 Answer 1


If there is no shearing in play, then Atan2(matrix[0].y, matrix[0].x) gives you the angle of rotation about the z axis in radians.

This is because the first column gives you the direction that the local x-axis points after rotation. If it's (1, 0) then there's no rotation (or a multiple of 2 pi). If it's (0, 1) there's been a 90 degree rotation, etc. Atan2 is insensitive to the length of the vector, so we don't need to worry about scaling here.

  • \$\begingroup\$ Thanks, I believe this will work in the files I have now. I do have sheer in places, though in my immediate problem I do not. \$\endgroup\$ Commented Mar 16, 2021 at 16:28
  • \$\begingroup\$ With shearing in play, then there are multiple equally-valid ways to break down a given matrix into a rotation and a shear, so you'll need to provide some additional details we can use to select a canonical decomposition. \$\endgroup\$
    – DMGregory
    Commented Mar 16, 2021 at 16:33
  • \$\begingroup\$ Is there a way to project the final rotation onto the Z-axis maybe? The added knowledge we have is that we know it can be represented with a Z-axis rotation only. Also, I'm having trouble with the Atan2 approach, it's returning 30 degrees for the values in the question. \$\endgroup\$ Commented Mar 16, 2021 at 16:35
  • \$\begingroup\$ If you're saying that even rotation about Z is ambiguous with sheering, then I'll have to prevent sheering. \$\endgroup\$ Commented Mar 16, 2021 at 16:35
  • \$\begingroup\$ Sorry, I have the Atan2 backwards, it is correct. \$\endgroup\$ Commented Mar 16, 2021 at 16:36

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .