# v_roteu2qr

## PURPOSE

ROTEU2QR converts a sequence of Euler angles to a real unit quaternion

## SYNOPSIS

function q=v_roteu2qr(m,e)

## DESCRIPTION

    ROTEU2QR converts a sequence of Euler angles to a real unit quaternion
     Inputs:

         M        a string of n characters from the set determining the order of rotation axes
                  as listed below. Note that the control characters 'rdoOaA' may occur anywhere in the string:
                    'x','y','z'    rotate around the given axis by the corresponding angle
                                   given in e()
                    '1','2','3'    90 degree rotation around x,y or z axis; doesn't use a value from e()
                    '4','5','6'    180 degree rotation around x,y or z axis; doesn't use a value from e()
                    '7','8','9'    270 degree rotation around x,y or z axis; doesn't use a value from e()
                    'r','d'        all angles are given in radians or degrees  [default='r']
                    'R','D'        all angles are given in radians or degrees and are negated
                 'o','O','a','A'   selects whether to rotate the object or the coordinate axes and
                                   whether the rotation axes remain fixed in space for consecutive
                                   rotations (extrinsic) or else move with each rotation (intrinsic).
                                      'o' = object-extrinsic [default]
                                      'O' = object-intrinsic
                                      'a' = axes-extrinsic
                                      'A' = axes-intrinsic

         E(K,...)  K Euler angles in radians (or degrees if 'd' or 'D' specified) per quaternion where K is the number of 'xyz' characters in M.
                   A positive rotation is clockwise if looking along the +ve axis away from the origin or anti-clockwise if 'R' or 'D' is given.
                   The x, y, z axes form a right-handed triple.

     Outputs:

         Q(4,...)   output quaternion. Q is normalized to have magnitude 1 with
                    its first non-zero coefficient positive.

     The string M specifies the seqeunce of axes about which the rotations are performed. There are 12
     possible 3-character sequences that avoid consecutive repetitions. These are 'Euler angles' if
     there is a repeated axis or 'Tait-Bryan angles' if not. Common choices are:
     (1) 'zxz' the most common Euler angle set (including a replicated axis, z)
     (2) 'xyz' corresponds to 'roll, pitch, yaw' for an aeroplane heading in the x direction with y to
         the right and z down. The intrinsic equivalent is 'Ozyx' corresponding to 'yaw, pitch, roll'.
     (3) 'z1z1z' involves 5 rotations, in which all the non-fixed rotations are around the z axis.

     Inverse conversion: If m has length 3 with adjacent characters distinct,
                         then v_rotqr2eu(m,v_roteu2qr(m,e))=e.

     Inverse rotation:   qrmult(roteu2qr(m,e),roteu2qr(fliplr(m),-fliplr(e)))=+-[ 1 0 0 0]'

## CROSS-REFERENCE INFORMATION

This function calls:

- v_roteucode V_ROTEUCODE decodes a string specifying a rotation axis sequence
- v_rotqr2ro ROTQR2RO converts a real quaternion to a 3x3 rotation matrix

This function is called by:

- v_roteu2ro V_ROTEU2QR converts a sequence of Euler angles to a rotation matrix

## SOURCE CODE

    0001 function q=v_roteu2qr(m,e)
    0002 %ROTEU2QR converts a sequence of Euler angles to a real unit quaternion
    0003 % Inputs:
    0004 %
    0005 %     M        a string of n characters from the set determining the order of rotation axes
    0006 %              as listed below. Note that the control characters 'rdoOaA' may occur anywhere in the string:
    0007 %                'x','y','z'    rotate around the given axis by the corresponding angle
    0008 %                               given in e()
    0009 %                '1','2','3'    90 degree rotation around x,y or z axis; doesn't use a value from e()
    0010 %                '4','5','6'    180 degree rotation around x,y or z axis; doesn't use a value from e()
    0011 %                '7','8','9'    270 degree rotation around x,y or z axis; doesn't use a value from e()
    0012 %                'r','d'        all angles are given in radians or degrees  [default='r']
    0013 %                'R','D'        all angles are given in radians or degrees and are negated
    0014 %             'o','O','a','A'   selects whether to rotate the object or the coordinate axes and
    0015 %                               whether the rotation axes remain fixed in space for consecutive
    0016 %                               rotations (extrinsic) or else move with each rotation (intrinsic).
    0017 %                                  'o' = object-extrinsic [default]
    0018 %                                  'O' = object-intrinsic
    0019 %                                  'a' = axes-extrinsic
    0020 %                                  'A' = axes-intrinsic
    0021 %
    0022 %     E(K,...)  K Euler angles in radians (or degrees if 'd' or 'D' specified) per quaternion where K is the number of 'xyz' characters in M.
    0023 %               A positive rotation is clockwise if looking along the +ve axis away from the origin or anti-clockwise if 'R' or 'D' is given.
    0024 %               The x, y, z axes form a right-handed triple.
    0025 %
    0026 % Outputs:
    0027 %
    0028 %     Q(4,...)   output quaternion. Q is normalized to have magnitude 1 with
    0029 %                its first non-zero coefficient positive.
    0030 %
    0031 % The string M specifies the seqeunce of axes about which the rotations are performed. There are 12
    0032 % possible 3-character sequences that avoid consecutive repetitions. These are 'Euler angles' if
    0033 % there is a repeated axis or 'Tait-Bryan angles' if not. Common choices are:
    0034 % (1) 'zxz' the most common Euler angle set (including a replicated axis, z)
    0035 % (2) 'xyz' corresponds to 'roll, pitch, yaw' for an aeroplane heading in the x direction with y to
    0036 %     the right and z down. The intrinsic equivalent is 'Ozyx' corresponding to 'yaw, pitch, roll'.
    0037 % (3) 'z1z1z' involves 5 rotations, in which all the non-fixed rotations are around the z axis.
    0038 %
    0039 % Inverse conversion: If m has length 3 with adjacent characters distinct,
    0040 %                     then v_rotqr2eu(m,v_roteu2qr(m,e))=e.
    0041 %
    0042 % Inverse rotation:   qrmult(roteu2qr(m,e),roteu2qr(fliplr(m),-fliplr(e)))=+-[ 1 0 0 0]'
    0043
    0044 %
    0045 %      Copyright (C) Mike Brookes 2007-2020
    0046 %      Version: $Id: v_roteu2qr.m 11260 2020-07-18 20:07:58Z dmb $
    0047 %
    0048 %   VOICEBOX is a MATLAB toolbox for speech processing.
    0049 %   Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html
    0050 %
    0051 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0052 %   This program is free software; you can redistribute it and/or modify
    0053 %   it under the terms of the GNU Lesser General Public License as published by
    0054 %   the Free Software Foundation; either version 3 of the License, or
    0055 %   (at your option) any later version.
    0056 %
    0057 %   This program is distributed in the hope that it will be useful,
    0058 %   but WITHOUT ANY WARRANTY; without even the implied warranty of
    0059 %   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    0060 %   GNU Lesser General Public License for more details.
    0061 %
    0062 %   You can obtain a copy of the GNU Lesser General Public License from
    0063 %   https://www.gnu.org/licenses/ .
    0064 %
    0065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0066 persistent y cb sb mch mvch
    0067 if isempty(y)
    0068     y=repmat([2 4 1 3 1 3 2 4; 3 2 1 4 1 4 3 2; 3 4 2 1 1 2 4 3],4,1);
    0069     cb=cos([0 0 0 1 1 1 2 2 2 3 3 3]*pi/4);
    0070     sb=sin([0 0 0 1 1 1 2 2 2 3 3 3]*pi/4);
    0071     mch=''; % cached rotation code string
    0072     mvch=[0;0;1;1;0;0;1];
    0073 end
    0074 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0075 % Convert the m string
    0076 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    0077 if ischar(m) && strcmp(m,mch) % check if the rotation code string is cached
    0078     mv=mvch;
    0079 else
    0080     mv=v_roteucode(m); % else decode the string
    0081     mch=m; % and save the result in the cache for next time.
    0082     mvch=mv;
    0083 end
    0084 ne=mv(2,end); % number of elements required in e per output
    0085 if ne==0
    0086     sz=[1 1]; % change sz to give a single output
    0087     q=zeros(4,1); % space for single output quaternion
    0088 else
    0089     sz=size(e);
    0090     if sz(1)==1 && numel(e)==ne % allow legacy call with row-vector input
    0091         e=e(:);
    0092         sz=size(e);
    0093     else
    0094         e=reshape(e,sz(1),[]); % put each set of angles in a separate column
    0095     end
    0096     q=zeros(4,size(e,2)); % space for output quaternions
    0097 end
    0098 q(1,:)=1; % initialize output quaternions to the value 1
    0099 r=q; % space for temporary quaternion
    0100 ef=0.5*mv(end-3); % signed euler angle scale factor include 0.5 factor
    0101 nm=size(mv,2)-1; % number of rotations to do
    0102 for i=1:nm
    0103     mvi=mv(:,i);
    0104     mi=mvi(1);
    0105     x=y(mi,:); % index for x,y,or z axes
    0106     if mi<4
    0107         b=ef*e(mvi(2),:); % semi-rotation angle in radians
    0108         c=cos(b);
    0109         s=sin(b);
    0110     else
    0111         c=cb(mi);
    0112         s=sb(mi);
    0113     end
    0114     r(x(1:2),:)=q(x(3:4),:);
    0115     r(x(5:6),:)=-q(x(7:8),:);
    0116     q=repmat(c,4,1).*q+repmat(s,4,1).*r;
    0117 end
    0118 q(1,:)=q(1,:)*mv(end); % invert rotation if necessary
    0119 if ~nargout
    0120     v_rotqr2ro(q(:,1)); % plot a cube
    0121 else
    0122     sz(1)=4; % each rotation needs 4 outputs
    0123     q=reshape(q.*repmat(sign([8 4 2 1]*sign(q)),4,1),sz); % force leading coefficient to be positive and reshape
    0124 end