2

I have a 2d matrix created from position, scale and rotation (no skew). I would like to be able to decompose this matrix back to the original components and have managed to do so with the following pseudo code:

posX = matrix.tx
posY = matrix.ty

scaleX = Sqrt( matrix.a * matrix.a + matrix.b * matrix.b )
scaleY = Sqrt( matrix.c * matrix.c + matrix.d * matrix.d )

rotation = ATan2( -matrix.c / scaleY, matrix.a / scaleX )

However this obviously only works with positive scale values and I am unsure how to calculate the correct negative scales. I have attempted various suggestions found using google but so far none have worked correctly.

I have tried the accepted answer from here and the decomposition explained here, whilst they produce correct transformations, the components of scale and rotation do not match my original values.

I have tried taking the sign of the diagonal matrix.a * matrix.d which appears to work for the scale on the x axis but unsure if this is the correct approach and can't figure out how to handle the y axis.

Is this even possible? Will I have to accept that I will not get back the exact components and the best I can hope for is values that produce the same transformation?

Any help or pointers would be greatly appreciated.

Original

Translation = 204, 159

Rotation = -3.0168146900000044

Scale = -3, -2

Matrix = [ 2.976675975304773, 0.37336327891663146, -0.24890885261108764, 1.984450650203182, 204, 159 ]

Decomposition

Translation = 204, 159

Rotation = 0.1247779635897889

Scale = 3, 2

Matrix = [ 2.976675975304773, 0.3733632789166315, -0.24890885261108767, 1.984450650203182, 204, 159 ]

That was using the following decomposition code:

posX = matrix.tx
posY = matrix.ty

scaleX = Sgn( a ) * Sqrt( matrix.a * matrix.a + matrix.b * matrix.b )
scaleY = Sgn( d ) * Sqrt( matrix.c * matrix.c + matrix.d * matrix.d )

rotation = ATan2( -matrix.c / scaleY, matrix.a / scaleX )
NoOdle
  • 75
  • 1
  • 9
  • Could you provide some sample inputs and outputs? – meowgoesthedog Jan 29 '19 at 14:17
  • I have added a sample input and output to demonstrate the issue – NoOdle Feb 03 '19 at 11:26
  • There is no problem with your code - those two matrices are **identical** (within numerical error). A scaling of `-3, -2` is equivalent to a scaling of `3, 2` + rotation by `PI`, which is exactly equal to the difference between the original and decomposed angles. In case you *really* want results that "look right", if both of the scaling factors are positive you can flip their signs and add `PI` to the rotation angle. – meowgoesthedog Feb 03 '19 at 14:51
  • Yes I know they are identical, I was hoping to be able to decompose back to the exact original components rather than ones that produce the same transformation. I assume that isn't possible? – NoOdle Feb 03 '19 at 21:04

1 Answers1

0

Sometimes you can't tell flip (negative scale) from rotation, e.g. an image flipped horizontally and vertically is identical to the image rotated by 180 degrees.

So what you have to do is know whether the transformation matrix contains flips. With that knowledge, you can cancel out the flip first, decompose it as usual, and put the flip back into the decomposed scale factors.

Pseudo code:

Matrix m
hFlip = true
vFlip = true

if hFlip: m = compose(m, scale(-1, 1))
if vFlip: m = compose(m, scale(1, -1))

translation, rotation, scale = decompose(m)

if hFlip: scale.x = -scale.x
if vFlip: scale.y = -scale.y
hillin
  • 1,603
  • 15
  • 21