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)


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\$ – edA-qa mort-ora-y Mar 16 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 Mar 16 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\$ – edA-qa mort-ora-y Mar 16 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\$ – edA-qa mort-ora-y Mar 16 at 16:35
  • \$\begingroup\$ Sorry, I have the Atan2 backwards, it is correct. \$\endgroup\$ – edA-qa mort-ora-y Mar 16 at 16:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.