function [out,dout]=rodrigues(in) % % RODRIGUES Transform rotation matrix into rotation vector. % % Syntax: [out,d_out_d_in]=RODRIGUES(in) % If IN is a 3x3 rotation matrix then OUT is the % corresponding 3x1 rotation vector % % if IN is a rotation 3-vector then OUT is the % corresponding 3x3 rotation matrix % % d_out_d_in is the derivative of the output wrt the input % % % Makes use of the following subroutines: % % -> ~/src/matlab/detensor.m % -> ~/src/matlab/dABdA.m % -> ~/src/matlab/dABdB.m % Written by Andrea Mennucci 7/28/93 % Modified by Stefano Soatto % Copyright (c) California Institute of Technology [m,n] = size(in); bigeps = (10e+5)*eps; if ((m==1) & (n==3)) | ((m==3) & (n==1)) %% it is a rotation vector theta = norm(in); if n==length(in) in=in'; end; %% make it a column vec. if necess. omega = in; if theta < sqrt(eps)*1e2, theta2 = in' * in ; sinthetatheta =1-theta2/6; onecosthetatheta2=1-theta2/24; if nargout>1, dsinthetatheta_domega=- omega'/3; donecosthetatheta2_domega= -omega'/12; end; else; theta2 = theta * theta ; onecosthetatheta2=(1-cos(theta))/theta2; sinthetatheta=sin(theta)/theta; if nargout>1, dtheta_domega=omega'/theta; dsinthetatheta_dt=(cos(theta)*theta - sin(theta))/theta2; donecosthetatheta2_dt= ... (sin(theta)*theta2-(1-cos(theta))*theta*2)/theta2/theta2; dsinthetatheta_domega=dsinthetatheta_dt * dtheta_domega; donecosthetatheta2_domega=donecosthetatheta2_dt * dtheta_domega; end; end; omegav=skew3(omega); R = eye(3) + omegav*sinthetatheta + omegav*omegav*onecosthetatheta2 ; if nargout>1, domegav_domega=[[0 0 0];[0 0 -1];[0 1 0];[0 0 1];[0 0 0]; ... [-1 0 0];[0 -1 0];[1 0 0];[0 0 0]]; domegav2_domegav=dABdA(omegav,omegav)+dABdB(omegav,omegav); dRdomega=domegav_domega*sinthetatheta + ... detensor(omegav)* dsinthetatheta_domega + ... domegav2_domegav*domegav_domega* onecosthetatheta2 + ... detensor(omegav*omegav)*donecosthetatheta2_domega; dout=dRdomega; end; out = R; %% it is a rot matrix elseif ((m==n) & (m==3)), if (norm(in' * in - eye(3),Inf) >bigeps) | (abs(det(in)-1) > bigeps) , disp('( rodrigues: matrix is not a rotation matrix)'); end; R = in; trc=trace(R); trc2=(trc-1)/2; sinacostrc2=sqrt(1- trc2*trc2); s=[R(3,2)-R(2,3), R(1,3)-R(3,1), R(2,1)-R(1,2)]'; if (1- trc2*trc2) >= eps, tHeta = (acos(trc2)); tHetaf=tHeta/ (2 *sin(tHeta)); dtHetaf_dt=(2*sin(tHeta)-tHeta*2*cos(tHeta)) ... / (2 *sin(tHeta))/(2 *sin(tHeta)); if nargout>1, dtrcdR=[ 1 0 0 0 1 0 0 0 1]; dtHetadtrc=-0.5 / sinacostrc2 ; dtHetadR = dtHetadtrc * dtrcdR; end; else; tHeta = real(acos(trc2)); tHetaf=0.5/(1-tHeta/6); % = ~ 1/2+tHeta/12 dtHetaf_dt=1/12; dtHetadR=zeros(1,9);% this is infinity disp('approximate result in rodrigues'); end; omega = tHetaf * s; out=omega; if nargout>1, dsdR=[ [ 0 0 0 0 0 -1 0 1 0 ];[ 0 0 1 0 0 0 -1 0 0 ]; ... [ 0 -1 0 1 0 0 0 0 0 ]] ; domegadR = tHetaf * dsdR + s * dtHetaf_dt * dtHetadR ; dout=domegadR; end; else error('Rodrigues: Neither a matrix nor a rotation vector were provided'); end; return; % differece tests Rtest = eye(3)+ skew3(csi)/norm(csi)*sin(norm(csi)) + skew3(csi)^2/(norm(csi)^2)*(1-cos(norm(csi))) % Test for rotation vectors -> rotation matrices for i = 1: 10, epsilon = 10^(-i); ddelta(i) = epsilon; csi = .01*randn(3,1); for (k = 1:3), csip = csi; csip(k) = csip(k)+epsilon; diff = (rodrigues(csip)-rodrigues(csi))/epsilon; diff = diff'; dFdcsi_test(:,k) = diff(:); end; [F,dFdcsi] = rodrigues(csi); nnorm(i)=norm(dFdcsi-dFdcsi_test); end; plot(log10(ddelta),log10(nnorm)); % Test for rotation matrices -> vectors epsilon = 1e-6; csi = randn(3,1); csirod = dordigues(csi); csirod = csirod'; csirod = csirod(:); for (k = 1:9), csirodp = csirod; csirodp(k) = csirodp(k)+epsilon; diff = (rodrigues(csip)-rodrigues(csi))/epsilon; diff = diff' dFdcsi_test(:,k) = diff(:); end; [F,dFdcsi] = rodrigues(csi); dFdcsi-dFdcsi_test, norm(ans) %%%%%%%%% test o=[ 0.3 0.1 0.2]'; o=rand(3,1)*pi; o=rand(3,1)*1e-5; minidelta=1e-7; R=rodrigues(o); [temp,OORR]=rodrigues(R); %temp'-o' o=temp; for i=1:3, for j=1:3, R2=R; R2(i,j)=R2(i,j)+ minidelta; [o2]=rodrigues(R2); OORR2(:,(i-1)*3+j)=(o2-o)/minidelta; end; end; (OORR2 -OORR)/pi max(max(OORR))/pi %%%%%%%%% test 2 o=[ 0.3 0.1 0.2]'; o=rand(3,1)/pi; minidelta=1e-6; o=[ 0. 0. pi/4]'; o=rand(3,1)*pi; o=rand(3,1)*1e-8; o=rand(3,1)*1e-3; [R,RROO]=rodrigues(o); for i=1:3, o2=o; o2(i)=o2(i)+ minidelta; [R2]=rodrigues(o2); RROO2(:,i)=detensor(R2-R)/minidelta; end; (RROO2 -RROO) max(max(RROO)) for j=1:30 o=rand(3,1)*pi*2; if norm(o-rodrigues(rodrigues(o)))>1e-19, error(''); end; end;