A P
A P

Reputation: 377

Decomposing a matrix into scale, rotation, and translation with haskell

I am trying to decompose a matrix into a 3x3 rotation matrix, a scale vector, and a translation vector, using haskell. I am using the matrix from the linear package. Unfortunately, the package only exports functions for making a matrix from scale, rotation, and translation, not extracting those from a matrix. Therefore, I decided to write a function to do it myself.

However, even though I am using matrices without scaling in them, my function returns a scale vector other than V3 1.0 1.0 1.0.

import qualified Linear.Matrix     as LA
import qualified Linear.V4         as LA
import qualified Linear.V3         as LA
import qualified Linear.Vector     as LA
import qualified Linear.Quaternion as LA

import Control.Lens hiding (deep)

...

decomposeMatrix :: LA.M44 Double -> (LA.M33 Double, LA.V3 Double, LA.V3 Double)
decomposeMatrix m = (rot, scale, trans)
    where trans = (m ^.LA.column LA._w ^. LA._xyz)
          scale = LA.V3 sx sy sz
          sx    = vecLength (m ^.(LA.column LA._x) ^. LA._xyz)
          sy    = vecLength (m ^.(LA.column LA._y) ^. LA._xyz)
          sz    = vecLength (m ^.(LA.column LA._z) ^. LA._xyz)
          rot   = LA.V3 ((m ^. (LA.column LA._x) ^.LA._xyz) LA.^/ sx)
                        ((m ^. (LA.column LA._y) ^.LA._xyz) LA.^/ sy)
                        ((m ^. (LA.column LA._z) ^.LA._xyz) LA.^/ sz)

vecLength :: LA.V3 Double -> Double
vecLength (LA.V3 a b c) = sqrt (a*a + b*b + c*c)

Here is how I am running this function in the ghci:

decomposeMatrix $ LA.mkTransformation (LA.Quaternion 1 (LA.V3 1 2 3)) $ LA.V3 1 2 3

And this is what I get as the outcome (formatted so you can read it easier):

(V3 (V3 (-0.9259259259259259) 0.37037037037037035 7.407407407407407e-2)
    (V3 (-8.444006618414981e-2) (-0.8021806287494233) 0.5910804632890487) 
    (V3 0.5965499862718936 0.5965499862718936 (-0.5368949876447042)),
V3 27.0 23.68543856465402 16.76305461424021,
V3 1.0 2.0 3.0)

Thanks in advance.

Upvotes: 1

Views: 624

Answers (1)

K. A. Buhr
K. A. Buhr

Reputation: 50819

Your decomposeMatrix function seems fine (except the rotation matrix is transposed from what you want).

The big problem is your test case: the quaternion you're using (LA.Quarternion 1 (LA.V3 1 2 3) isn't a unit quaternion, so LA.mkTransformation isn't building a pure rotation. It's building a combination of rotation and scaling. Try the example:

decomposeMatrix $ LA.mkTransformation (LA.axisAngle (LA.V3 1 2 3) 1) 
                $ LA.V3 1 2 3

which uses LA.axisAngle to build a unit quaternion representing a pure rotation from a vector and angle, and it will work as expected.

Upvotes: 2

Related Questions