0001 function varargout = rotation3dToEulerAngles(mat, varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 p = inputParser;
0041 validStrings = {...
0042 'ZYX','ZXY','YXZ','YZX','XYZ','XZY',...
0043 'ZYZ','ZXZ','YZY','YXY','XZX','XYX'};
0044 addOptional(p,'convention','ZYX',@(x) any(validatestring(x,validStrings)));
0045 logParValidFunc = @(x) (islogical(x) || isequal(x,1) || isequal(x,0));
0046 addParameter(p,'IsRotation', 1, logParValidFunc);
0047 valTol = @(x) validateattributes(x,{'numeric'},{'scalar', '>=',eps(class(mat)), '<=',1});
0048 addParameter(p,'tolerance', 1e-8, valTol);
0049 parse(p,varargin{:});
0050 convention=p.Results.convention;
0051 isRotation = p.Results.IsRotation;
0052 tolerance = p.Results.tolerance;
0053
0054 if isRotation
0055 if ~isTransform3d(mat(1:3,1:3), 'rotation', 1, 'tolerance', tolerance)
0056 warning(['Rotation matrix contains reflection or scaling ' ...
0057 'tested with a tolerance of ' num2str(tolerance) '.' newline ...
0058 'Calculation of euler angles might be incorrect.'])
0059 end
0060 end
0061
0062 switch convention
0063 case 'ZYX'
0064
0065 cy = hypot(mat(1,1), mat(2,1));
0066
0067 if cy > 16*eps
0068
0069 phi = atan2( mat(2,1), mat(1,1));
0070 theta = atan2(-mat(3,1), cy);
0071 psi = atan2( mat(3,2), mat(3,3));
0072 else
0073 phi = 0;
0074 theta = atan2(-mat(3,1), cy);
0075 psi = atan2(-mat(2,3), mat(2,2));
0076 end
0077 case 'ZXY'
0078 cy = hypot(mat(2,2), mat(1,2));
0079 if cy > 16*eps
0080 phi = -atan2( mat(1,2), mat(2,2));
0081 theta = -atan2(-mat(3,2), cy);
0082 psi = -atan2( mat(3,1), mat(3,3));
0083 else
0084 phi = 0;
0085 theta = -atan2(-mat(3,2), cy);
0086 psi = -atan2(-mat(1,3), mat(1,1));
0087 end
0088 case 'YXZ'
0089 cy = hypot(mat(3,3), mat(1,3));
0090 if cy > 16*eps
0091 phi = atan2( mat(1,3), mat(3,3));
0092 theta = atan2(-mat(2,3), cy);
0093 psi = atan2( mat(2,1), mat(2,2));
0094 else
0095 phi = 0;
0096 theta = atan2(-mat(2,3), cy);
0097 psi = atan2(-mat(1,2), mat(1,1));
0098 end
0099 case 'YZX'
0100 cy = hypot(mat(1,1), mat(3,1));
0101 if cy > 16*eps
0102 phi = -atan2( mat(3,1), mat(1,1));
0103 theta = -atan2(-mat(2,1), cy);
0104 psi = -atan2( mat(2,3), mat(2,2));
0105 else
0106 phi = 0;
0107 theta = -atan2(-mat(2,1), cy);
0108 psi = -atan2(-mat(3,2), mat(3,3));
0109 end
0110 case 'XYZ'
0111 cy = hypot(mat(3,3), mat(2,3));
0112 if cy > 16*eps
0113 phi = -atan2( mat(2,3), mat(3,3));
0114 theta = -atan2(-mat(1,3), cy);
0115 psi = -atan2( mat(1,2), mat(1,1));
0116 else
0117 phi = 0;
0118 theta = -atan2(-mat(1,3), cy);
0119 psi = -atan2(-mat(2,1), mat(2,2));
0120 end
0121 case 'XZY'
0122 cy = hypot(mat(2,2), mat(3,2));
0123 if cy > 16*eps
0124 phi = atan2( mat(3,2), mat(2,2));
0125 theta = atan2(-mat(1,2), cy);
0126 psi = atan2( mat(1,3), mat(1,1));
0127 else
0128 phi = 0;
0129 theta = atan2(-mat(1,2), cy);
0130 psi = atan2(-mat(3,1), mat(3,3));
0131 end
0132
0133 case 'ZYZ'
0134 cy = hypot(mat(3,2), mat(3,1));
0135 if cy > 16*eps
0136 phi = -atan2(mat(2,3), -mat(1,3));
0137 theta = -atan2(cy, mat(3,3));
0138 psi = -atan2(mat(3,2), mat(3,1));
0139 else
0140 phi = 0;
0141 theta = -atan2(cy, mat(3,3));
0142 psi = -atan2(-mat(2,1), mat(2,2));
0143 end
0144 case 'ZXZ'
0145 cy = hypot(mat(3,2), mat(3,1));
0146 if cy > 16*eps
0147 phi = atan2(mat(1,3), -mat(2,3));
0148 theta = atan2(cy, mat(3,3));
0149 psi = atan2(mat(3,1), mat(3,2));
0150 else
0151 phi = 0;
0152 theta = atan2(cy, mat(3,3));
0153 psi = atan2(-mat(1,2), mat(1,1));
0154 end
0155 case 'YZY'
0156 cy = hypot(mat(2,3), mat(2,1));
0157 if cy > 16*eps
0158 phi = atan2(mat(3,2), -mat(1,2));
0159 theta = atan2(cy, mat(2,2));
0160 psi = atan2(mat(2,3), mat(2,1));
0161 else
0162 phi = 0;
0163 theta = atan2(cy, mat(2,2));
0164 psi = atan2(-mat(3,1), mat(3,3));
0165 end
0166 case 'YXY'
0167 cy = hypot(mat(2,3), mat(2,1));
0168 if cy > 16*eps
0169 phi = -atan2(mat(1,2), -mat(3,2));
0170 theta = -atan2(cy, mat(2,2));
0171 psi = -atan2(mat(2,1), mat(2,3));
0172 else
0173 phi = 0;
0174 theta = -atan2(cy, mat(2,2));
0175 psi = -atan2(-mat(1,3), mat(1,1));
0176 end
0177 case 'XZX'
0178 cy = hypot(mat(1,3), mat(1,2));
0179 if cy > 16*eps
0180 phi = -atan2(mat(3,1), -mat(2,1));
0181 theta = -atan2(cy, mat(1,1));
0182 psi = -atan2(mat(1,3), mat(1,2));
0183 else
0184 phi = 0;
0185 theta = -atan2(cy, mat(1,1));
0186 psi = -atan2(-mat(3,2), mat(3,3));
0187 end
0188 case 'XYX'
0189 cy = hypot(mat(1,2), mat(1,3));
0190 if cy > 16*eps
0191 phi = atan2(mat(2,1), -mat(3,1));
0192 theta = atan2(cy, mat(1,1));
0193 psi = atan2(mat(1,2), mat(1,3));
0194 else
0195 phi = 0;
0196 theta = atan2(cy, mat(1,1));
0197 psi = atan2(-mat(2,3), mat(2,2));
0198 end
0199 end
0200
0201
0202 if nargout <= 1
0203
0204 varargout{1} = rad2deg([phi theta psi]);
0205 else
0206
0207 varargout = cellfun(@rad2deg, {phi theta psi},'uni',0);
0208 end