# Rotating an object about local angles/axes

The functions SetAngle and Rotate rotate objects about the world axes. In order to apply local rotations, the angles need to be derived first. It is possible to rotate an object about local angles by first specifying the local angles, then extracting the world angles from the local rotation and applying those to the object.

Any local rotation is dependent on the order in which the individual rotations are applied. This is true because the local axes are dependent on each other.

Because of this, it is important to specify the axis order prior to calculating the world rotation.

An axis order of XYZ means that the X rotation is applied first, then the Y and lastly the Z rotation.

These declarations are needed:

```;the object one wishes to rotate
ref myObject

;specifes order of rotations.
float axisOrder
;1 = xyz
;2 = xzy
;3 = yxz
;4 = yzx
;5 = zxy
;6 = zyx

;the local angles
float localAngX
float localAngY
float localAngZ

;the world angles
float worldAngX
float worldAngY
float worldAngZ

;sine and cosine of local x, y, z angles
float sx
float cx
float sy
float cy
float sz
float cz

;the cells of the rotation matrix
float r11
float r12
float r13
float r21
float r22
float r23
float r31
float r32
float r33

```

The actual rotation code:

```  set axisOrder to 3
```
```  set sx to sin localAngX
set cx to cos localAngX
set sy to sin localAngY
set cy to cos localAngY
set sz to sin localAngZ
set cz to cos localAngZ

;creation of rotation matrix in axis order
if     (axisOrder == 1)
;XYZ
set r11 to ( cy *  cz)
set r12 to ( cy * -sz)
set r13 to (    sy   )
set r21 to ( sx *  sy *  cz +  cx *  sz)
set r22 to ( sx *  sy * -sz +  cx *  cz)
set r23 to (-sx *  cy)
set r31 to ( cx * -sy *  cz +  sx *  sz)
set r32 to ( cx *  sy *  sz +  sx *  cz)
set r33 to ( cx *  cy)

elseif (axisOrder == 2)
;XZY
set r11 to ( cz *  cy)
set r12 to (   -sz   )
set r13 to ( cz *  sy)
set r21 to ( cx *  sz *  cy +  cx *  cz)
set r22 to ( cx *  cz)
set r23 to ( cx *  sz *  sy + -sx *  cy)
set r31 to ( sx *  sz *  cy +  cx * -sy)
set r32 to ( sx *  cz)
set r33 to ( sx *  sz *  sy +  cx *  cy)

elseif (axisOrder == 3)
;YXZ
set r11 to ( cy *  cz +  sy *  sx *  sz)
set r12 to ( cy * -sz +  sy *  sx *  cz)
set r13 to ( sy *  cx)
set r21 to ( cx *  sz)
set r22 to ( cx *  cz)
set r23 to (   -sx   )
set r31 to (-sy *  cz +  cy *  sx *  sz)
set r32 to ( sy *  sz +  cy *  sx *  cz)
set r33 to ( cy *  cx)

elseif (axisOrder == 4)
;YZX
set r11 to ( cy *  cz)
set r12 to ( cy * -sz *  cx +  sy *  sx)
set r13 to ( cy * -sz * -sx +  sy *  cx)
set r21 to (    sz   )
set r22 to ( cz *  cx)
set r23 to ( cz * -sx)
set r31 to (-sy *  cz)
set r32 to ( sy *  sz *  cx +  cy *  sx)
set r33 to ( sy *  sz * -sx +  cy *  cx)

elseif (axisOrder == 5)
;ZXY
set r11 to ( cz *  cy +  sz *  sx * -sy)
set r12 to (-sz *  cx)
set r13 to ( cz *  sy +  sz *  sx *  cy)
set r21 to ( sz *  cy +  cz *  sx *  sy)
set r22 to ( cz *  cx)
set r23 to ( sz *  sy +  cz * -sx *  cy)
set r31 to ( cx * -sy)
set r32 to (   sx    )
set r33 to ( cx *  cy)

else
;ZYX
set r11 to ( cz *  cy)
set r12 to (-sz *  cx +  cz *  sy *  sx)
set r13 to ( sz *  sx +  cz *  sy *  cx)
set r21 to ( sz *  cy)
set r22 to ( cz *  cx +  sz *  sy *  sx)
set r23 to ( cz * -sx +  sz *  sy *  cx)
set r31 to (   -sy   )
set r32 to ( cy *  sx)
set r33 to ( cy *  cx)

endif

;Extraction of worldangles from rotation matrix
if     (r13 >  0.9998)
;positive gimbal lock

set worldAngX to -ATan2 r32 r22
set worldAngY to -90
set worldAngZ to 0

elseif (r13 < -0.9998)
;negative gimbal lock

set worldAngX to -ATan2 r32 r22
set worldAngY to 90
set worldAngZ to 0

else
;no gimbal lock

set r23 to -r23
set r12 to -r12
set worldAngX to -ATan2 r23 r33
set worldAngY to -ASin r13
set worldAngZ to -ATan2 r12 r11

endif

;apply extracted rotation
myObject.setAngle x worldAngX
myObject.setAngle y worldAngY
myObject.setAngle z worldAngZ

```

## Special Note

This code has been tested ingame and works reliably well. It is advided to pay special attention to the axis order.