V_ROTEUCODE decodes a string specifying a rotation axis sequence M(n) 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 [radians] '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 Outputs: mv(7,k) where k-1 is the number of non-control characters in the input string m mv(1,j) = Code for the j'th rotation: 1,2,3 for x,y,z rotation and 4 to 12 for the fixed rotations listed above. All entries are in the range [1,12] except for mv(1,k)=0. mv(2,j) = index into euler angle array for x,y,z rotations. mv(2,k) gives total number of euler angles needed mv(3,j) = rotation class before rotation j. mv(3,k) is the final rotation class and equals 52 for arbitrary rotations. mv(4,j) = index into a vectorized matrix of the entry that becomes non-zero after rotation j mv(5,j) = index into a vectorized matrix of the other changing element in the same column mv(6,j) = +-1 = sign of the sine term affecting entry mv(4,j). For mv(1,j) in [1,3], mv(6,j)=0 if the rotation is unnecessary mv(7,j) = +-1 = sign of entry mv(5,j) before rotation j if known Special entries: mv(7,k) = -1 to invert the rotation (i.e. transpose the matrix) or +1 otherwise mv(4,k) = scale factor for euler angles: +-1 or +-pi/180 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 (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.
0001 function mv=v_roteucode(m) 0002 %V_ROTEUCODE decodes a string specifying a rotation axis sequence 0003 % M(n) a string of n characters from the set determining the order of rotation axes 0004 % as listed below. Note that the control characters 'rdoOaA' may occur anywhere in the string: 0005 % 'x','y','z' rotate around the given axis by the corresponding angle 0006 % given in e() 0007 % '1','2','3' 90 degree rotation around x,y or z axis; doesn't use a value from e() 0008 % '4','5','6' 180 degree rotation around x,y or z axis; doesn't use a value from e() 0009 % '7','8','9' 270 degree rotation around x,y or z axis; doesn't use a value from e() 0010 % 'r','d' all angles are given in radians or degrees [radians] 0011 % 'o','O','a','A' selects whether to rotate the object or the coordinate axes and 0012 % whether the rotation axes remain fixed in space for consecutive 0013 % rotations (extrinsic) or else move with each rotation (intrinsic). 0014 % 'o' = object-extrinsic [default] 0015 % 'O' = object-intrinsic 0016 % 'a' = axes-extrinsic 0017 % 'A' = axes-intrinsic 0018 % Outputs: 0019 % 0020 % mv(7,k) where k-1 is the number of non-control characters in the input string m 0021 % mv(1,j) = Code for the j'th rotation: 1,2,3 for x,y,z rotation and 4 to 12 for the fixed rotations listed above. 0022 % All entries are in the range [1,12] except for mv(1,k)=0. 0023 % mv(2,j) = index into euler angle array for x,y,z rotations. mv(2,k) gives total number of euler angles needed 0024 % mv(3,j) = rotation class before rotation j. mv(3,k) is the final rotation class and equals 52 for arbitrary rotations. 0025 % mv(4,j) = index into a vectorized matrix of the entry that becomes non-zero after rotation j 0026 % mv(5,j) = index into a vectorized matrix of the other changing element in the same column 0027 % mv(6,j) = +-1 = sign of the sine term affecting entry mv(4,j). For mv(1,j) in [1,3], mv(6,j)=0 if the rotation is unnecessary 0028 % mv(7,j) = +-1 = sign of entry mv(5,j) before rotation j if known 0029 % Special entries: 0030 % mv(7,k) = -1 to invert the rotation (i.e. transpose the matrix) or +1 otherwise 0031 % mv(4,k) = scale factor for euler angles: +-1 or +-pi/180 0032 % 0033 % 0034 % The string M specifies the seqeunce of axes about which the rotations are performed. There are 12 0035 % possible 3-character sequences that avoid consecutive repetitions. These are 'Euler angles' if 0036 % there is a repeated axis or 'Tait-Bryan angles' if not. Common choices are: 0037 % (1) 'zxz' the most common Euler angle set 0038 % (2) 'xyz' corresponds to 'roll, pitch, yaw' for an aeroplane heading in the x direction with y to 0039 % the right and z down. The intrinsic equivalent is 'Ozyx' corresponding to 'yaw, pitch, roll'. 0040 % (3) 'z1z1z' involves 5 rotations, in which all the non-fixed rotations are around the z axis. 0041 % 0042 0043 % Copyright (C) Mike Brookes 2007-2020 0044 % Version: $Id: v_roteucode.m 11260 2020-07-18 20:07:58Z dmb $ 0045 % 0046 % VOICEBOX is a MATLAB toolbox for speech processing. 0047 % Home page: http://www.ee.ic.ac.uk/hp/staff/dmb/voicebox/voicebox.html 0048 % 0049 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0050 % This program is free software; you can redistribute it and/or modify 0051 % it under the terms of the GNU General Public License as published by 0052 % the Free Software Foundation; either version 2 of the License, or 0053 % (at your option) any later version. 0054 % 0055 % This program is distributed in the hope that it will be useful, 0056 % but WITHOUT ANY WARRANTY; without even the implied warranty of 0057 % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0058 % GNU General Public License for more details. 0059 % 0060 % You can obtain a copy of the GNU General Public License from 0061 % http://www.gnu.org/copyleft/gpl.html or by writing to 0062 % Free Software Foundation, Inc.,675 Mass Ave, Cambridge, MA 02139, USA. 0063 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0064 0065 persistent mes trmap zel mch mvch jch nch 0066 if isempty(mes) % setup fixed arrays and initialize cache of mode strings 0067 nch=5; % size of cache 0068 mch=cell(nch,1); % cache of input character strings 0069 mvch=cell(nch,1); % cache of output mv codes 0070 flefch=zeros(nch,2); % cache of output flef codes 0071 jch=(1:nch); % cache usage order jch(1) is the most recent, jch(nch) the oldest 0072 for i=1:nch 0073 mch{i}=''; 0074 mvch{i}=[0;0;1;1;0;0;1]; 0075 end 0076 mes=[1:3 10:12 7:9 4:6]; % sign reversal look-up table 0077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0078 % The trmap and zel arrays contain information about each of 52 different % 0079 % patterns of -1,0,+1 that may exist in a rotation matrix as follows: % 0080 % % 0081 % 1-3 : identity matrix rows in order: 123, 231, 312 % 0082 % 4-6 : negated identity matrix rows in order: 132, 213, 321 % 0083 % 7-12: As 1-6 but with rows 2,3 negated % 0084 % 13-18: As 1-6 but with rows 1,3 negated % 0085 % 19-24: As 1-6 but with rows 1,2 negated % 0086 % 25-33: +1 in position (i-24) and 0's in remainder of this row and col % 0087 % 34-42: -1 in position (i-24) and 0's in remainder of this row and col % 0088 % 43-51: 0 in position (i-42) % 0089 % 52: no special symmetry % 0090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0091 % trmap(i,j) gives the pattern that i is transformed into by rotation j % 0092 % where j=1:3 corresponds to x,y,z and j=4:12 corresponds to the 9 % 0093 % multiples of 90 degree rotations listed in the main comments. % 0094 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0095 trmap=[ 25 29 33 16 24 11 7 13 19 22 12 17; 0096 28 32 27 17 22 12 8 14 20 23 10 18; 0097 31 26 30 18 23 10 9 15 21 24 11 16; 0098 34 41 39 13 20 9 10 16 22 19 8 15; 0099 37 35 42 14 21 7 11 17 23 20 9 13; 0100 40 38 36 15 19 8 12 18 24 21 7 14; 0101 25 38 42 22 6 23 1 19 13 16 18 5; 0102 28 41 36 23 4 24 2 20 14 17 16 6; 0103 31 35 39 24 5 22 3 21 15 18 17 4; 0104 34 32 30 19 2 21 4 22 16 13 14 3; 0105 37 26 33 20 3 19 5 23 17 14 15 1; 0106 40 29 27 21 1 20 6 24 18 15 13 2; 0107 34 29 42 10 12 5 19 1 7 4 24 23; 0108 37 32 36 11 10 6 20 2 8 5 22 24; 0109 40 26 39 12 11 4 21 3 9 6 23 22; 0110 25 41 30 7 8 3 22 4 10 1 20 21; 0111 28 35 33 8 9 1 23 5 11 2 21 19; 0112 31 38 27 9 7 2 24 6 12 3 19 20; 0113 34 38 33 4 18 17 13 7 1 10 6 11; 0114 37 41 27 5 16 18 14 8 2 11 4 12; 0115 40 35 30 6 17 16 15 9 3 12 5 10; 0116 25 32 39 1 14 15 16 10 4 7 2 9; 0117 28 26 42 2 15 13 17 11 5 8 3 7; 0118 31 29 36 3 13 14 18 12 6 9 1 8; 0119 25 44 45 25 36 26 25 34 34 25 27 35; 0120 43 26 45 27 26 34 35 26 35 36 26 25; 0121 43 44 27 35 25 27 36 36 27 26 34 27; 0122 28 47 48 28 39 29 28 37 37 28 30 38; 0123 46 29 48 30 29 37 38 29 38 39 29 28; 0124 46 47 30 38 28 30 39 39 30 29 37 30; 0125 31 50 51 31 42 32 31 40 40 31 33 41; 0126 49 32 51 33 32 40 41 32 41 42 32 31; 0127 49 50 33 41 31 33 42 42 33 32 40 33; 0128 34 44 45 34 27 35 34 25 25 34 36 26; 0129 43 35 45 36 35 25 26 35 26 27 35 34; 0130 43 44 36 26 34 36 27 27 36 35 25 36; 0131 37 47 48 37 30 38 37 28 28 37 39 29; 0132 46 38 48 39 38 28 29 38 29 30 38 37; 0133 46 47 39 29 37 39 30 30 39 38 28 39; 0134 40 50 51 40 33 41 40 31 31 40 42 32; 0135 49 41 51 42 41 31 32 41 32 33 41 40; 0136 49 50 42 32 40 42 33 33 42 41 31 42; 0137 43 52 52 43 45 44 43 43 43 43 45 44; 0138 52 44 52 45 44 43 44 44 44 45 44 43; 0139 52 52 45 44 43 45 45 45 45 44 43 45; 0140 46 52 52 46 48 47 46 46 46 46 48 47; 0141 52 47 52 48 47 46 47 47 47 48 47 46; 0142 52 52 48 47 46 48 48 48 48 47 46 48; 0143 49 52 52 49 51 50 49 49 49 49 51 50; 0144 52 50 52 51 50 49 50 50 50 51 50 49; 0145 52 52 51 50 49 51 51 51 51 50 49 51; 0146 52 52 52 52 52 52 52 52 52 52 52 52]; 0147 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0148 % Each Euler angle is chosen so that the inverse rotation forces a specific element % 0149 % of the rotation matrix to zero. zel(k,j,i) gives information about which element % 0150 % ceases to be zero when a rotation around axis j is applied to pattern i. % 0151 % k=1 gives the index into a vectorized matrix of the entry that becomes non-zero % 0152 % k=2 gives the index of the other element in the same column that changes % 0153 % k=3 gives the sign of the sine term affecting the first of these entries % 0154 % k=4 gives the sign of the initial value of the second of these entries if known % 0155 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0156 zel=reshape([ 6 5 1 1 3 1 -1 1 2 1 1 1; 0157 2 3 -1 1 1 3 1 1 5 4 1 1; 0158 3 2 1 1 4 6 1 1 1 2 -1 1; 0159 5 6 -1 -1 3 1 -1 -1 2 1 1 -1; 0160 3 2 1 -1 6 4 -1 -1 1 2 -1 -1; 0161 2 3 -1 -1 1 3 1 -1 4 5 -1 -1; 0162 6 5 1 -1 3 1 -1 1 2 1 1 1; 0163 2 3 -1 -1 1 3 1 -1 5 4 1 1; 0164 3 2 1 -1 4 6 1 -1 1 2 -1 -1; 0165 5 6 -1 1 3 1 -1 -1 2 1 1 -1; 0166 3 2 1 1 6 4 -1 -1 1 2 -1 1; 0167 2 3 -1 1 1 3 1 1 4 5 -1 1; 0168 6 5 1 1 3 1 -1 -1 2 1 1 -1; 0169 2 3 -1 -1 1 3 1 -1 5 4 1 -1; 0170 3 2 1 1 4 6 1 -1 1 2 -1 1; 0171 5 6 -1 1 3 1 -1 1 2 1 1 1; 0172 3 2 1 -1 6 4 -1 1 1 2 -1 -1; 0173 2 3 -1 1 1 3 1 1 4 5 -1 -1; 0174 6 5 1 -1 3 1 -1 -1 2 1 1 -1; 0175 2 3 -1 1 1 3 1 1 5 4 1 -1; 0176 3 2 1 -1 4 6 1 1 1 2 -1 -1; 0177 5 6 -1 -1 3 1 -1 1 2 1 1 1; 0178 3 2 1 1 6 4 -1 1 1 2 -1 1; 0179 2 3 -1 -1 1 3 1 -1 4 5 -1 1; 0180 0 0 0 0 3 1 -1 1 2 1 1 1; 0181 3 2 1 1 0 0 0 0 1 2 -1 1; 0182 2 3 -1 1 1 3 1 1 0 0 0 0; 0183 0 0 0 0 6 4 -1 1 5 4 1 1; 0184 6 5 1 1 0 0 0 0 4 5 -1 1; 0185 5 6 -1 1 4 6 1 1 0 0 0 0; 0186 0 0 0 0 9 7 -1 1 8 7 1 1; 0187 9 8 1 1 0 0 0 0 7 8 -1 1; 0188 8 9 -1 1 7 9 1 1 0 0 0 0; 0189 0 0 0 0 3 1 -1 -1 2 1 1 -1; 0190 3 2 1 -1 0 0 0 0 1 2 -1 -1; 0191 2 3 -1 -1 1 3 1 -1 0 0 0 0; 0192 0 0 0 0 6 4 -1 -1 5 4 1 -1; 0193 6 5 1 -1 0 0 0 0 4 5 -1 -1; 0194 5 6 -1 -1 4 6 1 -1 0 0 0 0; 0195 0 0 0 0 9 7 -1 -1 8 7 1 -1; 0196 9 8 1 -1 0 0 0 0 7 8 -1 -1; 0197 8 9 -1 -1 7 9 1 -1 0 0 0 0; 0198 0 0 0 0 1 3 1 1 1 2 -1 1; 0199 2 3 -1 1 0 0 0 0 2 1 1 1; 0200 3 2 1 1 3 1 -1 1 0 0 0 0; 0201 0 0 0 0 4 6 1 1 4 5 -1 1; 0202 5 6 -1 1 0 0 0 0 5 4 1 1; 0203 6 5 1 1 6 4 -1 1 0 0 0 0; 0204 0 0 0 0 7 9 1 1 7 8 -1 1; 0205 8 9 -1 1 0 0 0 0 8 7 1 1; 0206 9 8 1 1 9 7 -1 1 0 0 0 0; 0207 0 0 0 0 0 0 0 0 0 0 0 0]',4,3,52); 0208 end 0209 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0210 % Convert the m string 0211 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 0212 if ~ischar(m) % lecacy call with integer m argument 0213 m=char(m+'w'); % convert to characters 0214 end 0215 ich=find(strcmp(m,mch),1); % check if already in the cache 0216 if isempty(ich) % not yet in the cache 0217 mm=m-'w'; % convert to integers with x -> 1 0218 mi=mm>=-31 & mm<=-29; % find characters XYZ 0219 mm(mi)=mm(mi)+32; % convert XYZ to xyz (for compatibility) 0220 mi=mm>=-70 & mm<=-62; % find digits 1:9 0221 mm(mi)=mm(mi)+74; % convert to 4:12 0222 mi=mm<=0; % select control characters 0223 mc=mm(mi); % controls 0224 mm=mm(~mi); % rotations 0225 ef=1; % angle scale factor 0226 es=1; % angle sign 0227 fl=1; % default to no rotation matrix tranposing 0228 for i=1:length(mc) 0229 switch mc(i) 0230 case -5 % 'r' = radians 0231 case -19 % 'd' = degrees 0232 ef=pi/180; % scale factor to convert to radians 0233 case -37 % 'R' = negated radians 0234 ef=-1; 0235 case -51 % 'D' = negated degrees 0236 ef=-pi/180; % scale factor to convert to radians 0237 case -8 % 'o' = object-extrinsic 0238 case -40 % 'O' = object-intrinsic 0239 fl=-1; 0240 es=-1; 0241 case -22 % 'a' = axes-extrinsic 0242 fl=-1; 0243 case -54 % 'A' = axes-intrinsic 0244 es=-1; 0245 otherwise 0246 error('Invalid character: %s',mc(i)+'w') 0247 end 0248 end 0249 ef=ef*es; % change sign of scale factor if necessary 0250 if es<0 0251 mm=mes(mm); % sign-reverse: interchage 4,5,6 with 10,11,12 0252 end 0253 nm=length(mm); 0254 mv=zeros(7,nm+1); 0255 mv(1,:)=[mm 0]; 0256 mv(2,:)=cumsum([mm<=3 0]); % index into euler angle array 0257 mv(3,1)=1; % initial pattern is the identity matrix 0258 for i=1:nm % loop for each rotation 0259 mmi=mm(i); % rotation code 0260 mv(3,i+1)=trmap(mv(3,i),mmi); % pattern ID after rotation 0261 if mmi<4 0262 mv(4:7,i)=zel(:,mmi,mv(3,i)); % information about which matrix elements change from zero 0263 end 0264 end 0265 mv(end)=fl; 0266 mv(end-3)=ef; 0267 % now save in the cache 0268 ich=jch(nch); % find oldest cache entry 0269 mch{ich}=m; % save input string 0270 mvch{ich}=mv; % save parameters 0271 jch=[ich jch(1:nch-1)]; % age all the other cache entries 0272 else % already in the cache 0273 kch=find(jch==ich,1); % find existing ich entry 0274 jch(1:kch)=[ich jch(1:kch-1)]; 0275 mv=mvch{ich}; % retrieve from cache 0276 end