Euler angles, Quaternion and mobile device rotation

I've written a JS SDK that listens to mobile device rotation, providing $3$ inputs:

$\alpha$ : An angle can range between $0$ and $360$ degrees
$\beta$ : An Angle between $-180$ and $180$ degrees
$\gamma$ : An Angle between $-90$ to $90$ degrees

Documentation for device rotation

I have tried using Euler Angles to determine the device orientation but encountered the gimbal lock effect, that made calculation explode when the device was pointing up. That lead me to use Quaternion, that does not suffer from the gimbal effect.

I've found a library that converts $\alpha, \beta$ and $\gamma$ to a Quaternion, so for the following values:

$\alpha : 40.3476$
$\beta : 70.3120$
$\gamma : -62.9454$

I get this Quaternion ($ZXY$ order):

$w: 0.7582073853451148$
$x: 0.608178427083661$
$y: -0.23130444560993935$
$z: -0.04169910165995308$

Visualizing the device orientation (Demo, use mobile):
enter image description here

I would like to write a method that gets a Quaternion as an input and outputs if the device is on portrait or landscape mode.

Defining portrait and landscape as a range of $\pm 45^\circ$ around the relevant axes.

What approach should I take?

Update: To elaborate further, my goals are:
To write a method that gets $\alpha, \beta$ and $\gamma$ and outputs if the device is in one of the following orientations:

  • portrait
  • portrait upside down
  • landscape left
  • landscape right
  • display up
  • display down

Not a complete solution, but this should provide a method with some tweaks.

Some details are left out in the article, so I cannot say exactly what rotation method is being used. I'll make an example where the rotation order is the extrinsic $xyz$-order.

The quaternion product of quaternions $\mathbf{p}$ and $\mathbf{q}$ is defined as $$ \begin{equation} \begin{split} \mathbf{p} \otimes \mathbf{q} &= \left( p_0 + p_1 i + p_2 j + p_3 k\right) \left( q_0 + q_1 i + q_2 j + q_3 k\right) \\ &= p_0q_0 + p_0q_1 i + p_0q_2 j + p_0q_3 k \\ & + p_1 q_0 i - p_1 q_1 + p_1 q_2 k - p_1 q_3 j \\ & + p_2 q_0 j - p_2 q_1 k - p_2 q_2 + p_2 q_3 i \\ & + p_3 q_0 k + p_3 q_1 j - p_3 q_2 i - p_3 q_3 \\ &= ( p_0 q_0 - p_1 q_1 - p_2 q_2 - p_3 q_3) \\ &+ ({\color{blue} p_0q_1} + {\color{red}p_1 q_0} + p_2 q_3 - p_3 q_2)i \\ &+ ({\color{blue} p_0 q_2} - p_1 q_3 + {\color{red} p_2 q_0} + p_3 q_1)j \\ &+ ({\color{blue} p_0 q_3} + p_1 q_2 - p_2 q_1 + {\color{red}p_3 q_0})k \end{split} \end{equation} $$ This can be written in a matrix form as \begin{equation} \begin{split} \mathbf{p} \otimes \mathbf{q} &= \left[ \begin{array}{cccc} % This is the correct matrix p_0 & -p_1 & -p_2 & -p_3 \\ p_1 & p_0 & -p_3 & p_2 \\ p_2 & p_3 & p_0 & -p_1 \\ p_3 & -p_2 & p_1 & p_0 \\ \end{array} \right] \left[ \begin{array}{c} q_0 \\ q_1 \\ q_2 \\ q_3 \\ \end{array} \right] \\ &= {\color{blue} p_0 } \left[ \begin{array}{c} q_0 \\ {\color{blue} q_1 } \\ {\color{blue} q_2 } \\ {\color{blue} q_3 } \\ \end{array} \right] + \left[ \begin{array}{c|ccc} 0 & -p_1 & -p_2 & -p_3 \\ \hline {\color{red} p_1} & 0 & -p_3 & p_2 \\ {\color{red} p_2} & p_3 & 0 & -p_1 \\ {\color{red} p_3} & -p_2 & p_1 & 0 \\ \end{array} \right] \left[ \begin{array}{c} q_0 \\ q_1 \\ q_2 \\ q_3 \\ \end{array} \right] \end{split} \end{equation} Now we at least know how to multiply quaternions. So what does this have to do with rotations?

Define a vector quaternion $(0,\vec{v}) = \mathbf{v}$ and a rotation quaternion $\mathbf{r} = (\cos{\tfrac{\theta}{2}}, \sin{\tfrac{\theta}{2}} \vec{r})$ for some unit vector $\vec{r}$. Now we can calculate the conjugation of $\mathbf{v}$ by $\mathbf{r}$ \begin{equation}\label{eq:euler-rodrigues-derivation} \begin{split} \mathbf{r} \star \mathbf{v} &= \mathbf{r} \otimes \mathbf{v} \otimes \mathbf{r}^* = \mathbf{r} \otimes (0,\vec{v}) \otimes (\cos{\tfrac{\theta}{2}}, - \sin{\tfrac{\theta}{2}} \vec{r}) \\ &= \mathbf{r} \otimes (0 + \vec{v} \cdot \sin{\tfrac{\theta}{2}} \vec{r} , 0 + \cos{\tfrac{\theta}{2}} \vec{v} + \vec{v}\times (- \sin{\tfrac{\theta}{2}} \vec{r})) \\ &= \mathbf{r} \otimes (\sin{\tfrac{\theta}{2}}\vec{v} \cdot \vec{r} , \cos{\tfrac{\theta}{2}} \vec{v} + \sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v}) \\ &= (\cos{\tfrac{\theta}{2}}, \sin{\tfrac{\theta}{2} \vec{r}}) \otimes (\sin{\tfrac{\theta}{2}}\vec{v} \cdot \vec{r} , \cos{\tfrac{\theta}{2}} \vec{v} + \sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v}) \\ &= (\cos{\tfrac{\theta}{2}}\sin{\tfrac{\theta}{2}}\vec{v} \cdot \vec{r} - (\sin{\tfrac{\theta}{2} \vec{r}})\cdot(\cos{\tfrac{\theta}{2}} \vec{v} + \sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v}), \\ & \cos{\tfrac{\theta}{2}}(\cos{\tfrac{\theta}{2}} \vec{v} + \sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v}) + (\sin{\tfrac{\theta}{2}}\vec{v} \cdot \vec{r} )(\sin{\tfrac{\theta}{2} \vec{r}}) + (\sin{\tfrac{\theta}{2} \vec{r}}) \times (\cos{\tfrac{\theta}{2}} \vec{v} + \sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v})) \\ &= (\cos{\tfrac{\theta}{2}}\sin{\tfrac{\theta}{2}}\vec{v} \cdot \vec{r} - \cos{\tfrac{\theta}{2}} \sin{\tfrac{\theta}{2} \vec{r}} \cdot \vec{v} - \sin^2{\tfrac{\theta}{2}} \vec{r} \cdot(\vec{r}\times \vec{v}), \\ & \cos^2{\tfrac{\theta}{2}} \vec{v} + \cos{\tfrac{\theta}{2}}\sin{\tfrac{\theta}{2}}\vec{r}\times \vec{v} + \sin^2{\tfrac{\theta}{2}}(\vec{v} \cdot \vec{r} )\vec{r} + \sin{\tfrac{\theta}{2} \cos{\tfrac{\theta}{2}} \vec{r}} \times \vec{v} + \sin^2{\tfrac{\theta}{2} \vec{r}} \times (\vec{r}\times \vec{v})) \\ &= (0, \\ & \cos^2{\tfrac{\theta}{2}} \vec{v} + \sin^2{\tfrac{\theta}{2}}(\vec{v} \cdot \vec{r} )\vec{r} + 2\sin{\tfrac{\theta}{2}} \cos{\tfrac{\theta}{2}} \vec{r} \times \vec{v} + \sin^2{\tfrac{\theta}{2}} \vec{r} \times (\vec{r}\times \vec{v})) \\ \end{split} \end{equation} Additionally, it is known that $\vec{r} \times ( \vec{r} \times \vec{v}) = (\vec{r} \cdot \vec{v})\vec{r} - (\vec{r} \cdot \vec{r}) \vec{v} = (\vec{r} \cdot \vec{v})\vec{r} - \vec{v} \Rightarrow \sin^2{\tfrac{\theta}{2}}(\vec{r} \cdot \vec{v})\vec{r} = \sin^2{\tfrac{\theta}{2}}\vec{r} \times ( \vec{r} \times \vec{v}) + \sin^2{\tfrac{\theta}{2}}\vec{v}$, resulting in \begin{equation}\label{eq:euler-rodrigues} \mathbf{r} \star \mathbf{v} = \vec{v} + 2\sin{\tfrac{\theta}{2} \cos{\tfrac{\theta}{2}}} \vec{r} \times \vec{v} + 2\sin^2{\tfrac{\theta}{2}} \vec{r} \times (\vec{r}\times \vec{v}) \end{equation} or the so called Euler-Rodrigues formula for rotation. The resulting vector quaternion $\mathbf{v}^{'} = (0,\vec{v}^{'})$ represents the rotation of $\vec{v}$ around an arbitrary vector $\vec{r}$ by angle $\theta$ to produce the rotated vector $\vec{v}^{'}$.

Therefore, this kind of multiplication can be used to represent a rotation about an axis. Now we can use the previous results to actually compute a sequence of rotations. As mentioned in the beginning, the extrinsic $xyz$-rotation will be calculated.

Two quaternion rotations can be coalesced by \begin{equation} \begin{split} \mathbf{r}_2 \star \left(\mathbf{r}_1 \star \mathbf{v} \right) &= \mathbf{r}_2 \otimes \left(\mathbf{r}_1 \otimes \mathbf{v} \otimes \mathbf{r}_1^{-1} \right) \otimes \mathbf{r}^{-1}_2 \\ &= \left(\mathbf{r}_2 \otimes \mathbf{r}_1 \right) \otimes \mathbf{v} \otimes \left(\mathbf{r}_2 \otimes \mathbf{r}_1 \right)^{-1} \\ &=\left( \mathbf{r}_2 \otimes \mathbf{r}_1 \right) \star \mathbf{v} \\\ \end{split} \end{equation} In other words, coalescing two rotation quaternions can be carried out by taking the quaternion product of the two rotation quaternions. The idea is the same as in matrix algebra. Now the formula corresponding to a Euler angle rotation can be derived. As an example, the quaternion corresponding to the $xyz$-rotation order is computed as follows:

\begin{equation} \begin{split} \mathbf{p}_{E \rightarrow Q}^{xyz} = & \left( \left[ \begin{array}{c}\cos{\frac{\psi}{2}} \\ 0 \\ 0 \\ \sin{\frac{\psi}{2}} \\ \end{array} \right] \otimes \left[ \begin{array}{c} \cos{\frac{\theta}{2}} \\ 0 \\ \sin{\frac{\theta}{2}} \\ 0 \\ \end{array} \right] \right) \otimes \left[ \begin{array}{c} \cos{\frac{\phi}{2}} \\ \sin{\frac{\phi}{2}} \\ 0 \\ 0 \\ \end{array} \right] \\ = & \left( \left[ \begin{array}{cccc} \cos{\frac{\psi}{2}} & 0 & 0 & -\sin{\frac{\psi}{2}} \\ 0 & \cos{\frac{\psi}{2}} & -\sin{\frac{\psi}{2}} & 0 \\ 0 & \sin{\frac{\psi}{2}} & \cos{\frac{\psi}{2}} & 0 \\ \sin{\frac{\psi}{2}} & 0 & 0 & \cos{\frac{\psi}{2}} \\ \end{array} \right] \left[ \begin{array}{c} \cos{\frac{\theta}{2}} \\ 0 \\ \sin{\frac{\theta}{2}} \\ 0 \end{array} \right] \right) \otimes \left[ \begin{array}{c} \cos{\frac{\phi}{2}} \\ \sin{\frac{\phi}{2}} \\ 0 \\ 0 \\ \end{array} \right] \\ = & \left[ \begin{array}{c} \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ -\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ \cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ \sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ \end{array} \right] \otimes \left[ \begin{array}{c} \cos{\frac{\phi}{2}} \\ \sin{\frac{\phi}{2}} \\ 0 \\ 0 \\ \end{array} \right] \\ = & \left[ \begin{array}{cccc} \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & \sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & -\cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & -\sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ -\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & -\sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & \cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ \cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & \sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & \sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ \sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} & -\cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & -\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} & \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ \end{array} \right] \left[ \begin{array}{c} \cos{\frac{\phi}{2}} \\ \sin{\frac{\phi}{2}} \\ 0 \\ 0 \\ \end{array} \right] \\ = & \left[ \begin{array}{c} \cos{\frac{\phi}{2}}\cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} + \sin{\frac{\phi}{2}}\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ -\cos{\frac{\phi}{2}}\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}} + \sin{\frac{\phi}{2}}\cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ \cos{\frac{\phi}{2}}\cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} + \sin{\frac{\phi}{2}}\sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} \\ \cos{\frac{\phi}{2}}\sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}} - \sin{\frac{\phi}{2}}\cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}} \\ \end{array} \right] \end{split} \end{equation}

It is fairly easy to see that the quaternion returned by this process is always unitary length. Next, we are interested in reversing this process, or extracting the Euler angles from this result. Without going throught a proof, the solution is

$$\left\{ \begin{array}{ccc} \tan{\phi} &=& \frac{2\left(p_0 p_1 + p_2 p_3 \right)}{p_0^2 - p_1^2 - p_2^2 + p_3^2} \\ \sin{\theta}&=& 2 \left( p_0 p_2 - p_1 p_3 \right) \\ \tan{\psi} &=& \frac{ 2 \left( p_0 p_3 + p_1 p_2 \right) }{ p_0^2 + p_1^2 - p_2^2 - p_3^2 } \end{array} \right.$$ where $p_i$ are the components of the orientation quaternion. I'm not completely sure which of these angles would represent the angle that you're interested in, but this should give you plenty of material to work with.

POST SCRIPTUM

I figured out that the rotation order used in the library that you used, it's probably the extrinsic $yxz$-rotation order. This would give the transformations $$ \mathbf{p}^{yxz} = \left[ \begin{array}{c} \cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}}\cos{\frac{\phi}{2}} -\sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}}\sin{\frac{\phi}{2}} \\ \cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}}\cos{\frac{\phi}{2}} -\sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}}\sin{\frac{\phi}{2}} \\ \sin{\frac{\psi}{2}} \sin{\frac{\theta}{2}}\cos{\frac{\phi}{2}} +\cos{\frac{\psi}{2}} \cos{\frac{\theta}{2}}\sin{\frac{\phi}{2}} \\ \sin{\frac{\psi}{2}} \cos{\frac{\theta}{2}}\cos{\frac{\phi}{2}} +\cos{\frac{\psi}{2}} \sin{\frac{\theta}{2}}\sin{\frac{\phi}{2}} \\ \end{array} \right] $$ and to extract the Euler angles, you use $$ \left\{ \begin{array}{ccc} \tan{\phi} &=& \frac{2\left(p_0 p_2 - p_1 p_3 \right)}{p_0^2 - p_1^2 - p_2^2 + p_3^2} \\ \sin{\theta}&=& 2 \left( p_0 p_1 + p_2 p_3 \right) \\ \tan{\psi} &=& \frac{ 2 \left( p_0 p_3 - p_1 p_2 \right) }{ p_0^2 - p_1^2 + p_2^2 - p_3^2 } \end{array} \right. $$ You can double-check to see if these equations work.