%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  Solution to Problem 7 of
%  Achieving a Common Viewpoint: Yaw, Pitch, and Roll
%  Dianne P. O'Leary and David A. Schug
%  Computing in Science and Engineering
%
%  In this problem, we illustrate two facts:
%
%    1. If the given points are co-planar, then
%       the transformation Q is not uniquely defined.
%
%    2. If the pitch is near vertical, the Euler
%       angles cannot be determined in a stable manner,
%       even though Q is stable.  This is called
%       "gymbal lock".
%
%  problem7.m   06/2004
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

anglsav = [];
qerror = [];
aerror = [];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 1.  Illustration of a degenerate case; the data points
%     lie in a plane.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     Here is the given data.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

A = [1 2 3 4 5 6 7;
     1 2 3 4 5 6 7;
     0 0 0 0 0 0 0];
Qtrue = compute_Q_from_angles([pi/3,pi/6,5*pi/6]);
B = Qtrue * A

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%     Here we compute a solution to the problem.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  [rmsd,angl,t,Q,newB] = viewpoint(A,B,0);

  qerror = [qerror,norm(Qtrue-Q,'fro')];
  aerror = [aerror,rmsd];

disp('Illustration of degenerate case in which the')
disp('matrix Q is not uniquely defined.')
disp('    Original Q                    Computed Q')
disp([Qtrue,Q])
disp('Original angles (radians)')
disp([pi/3,pi/6,5*pi/6])
disp('Computed angles')
disp(angl')
disp('RMSD using computed angles')
disp(rmsd)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% 2.  Illustration of gymbal lock.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

  angl_orig = [pi/4;pi/2-.001;pi/9];
  [A,B,Q_orig] = makedata(angl_orig);
  [rmsd,angl,t,Q,newB] = viewpoint(A,B,0);

  angltrue_p = [pi/4;pi/2+.001;pi/9];
  [A,B,Qtrue_p] = makedata(angltrue_p);
  [rmsd_p,angl_p,t_p,Q_p,newB_p] = viewpoint(A,B,0);
  QQ_p = compute_Q_from_angles(angl_p);

disp('Illustration of gymbal lock, in which the')
disp('matrix Q is uniquely defined but the angles are')
disp('not stable with respect to perturbations.')
disp('Case 1: theta just less than pi/2')
disp('    Original Q                    Computed Q')
disp([Q_orig,Q])
disp(sprintf('Change in Q = %e',norm(Q_orig-Q,'fro')))
disp('Original angles (radians)')
disp(angl_orig')
disp('Computed angles')
disp(angl')
disp('Case 2: theta just greater than pi/2')
disp('    Original Q                    Computed Q')
disp([Qtrue_p,Q_p])
disp(sprintf('Change in Q = %e',norm(Qtrue_p-Q_p,'fro')))
disp('Original angles (radians)')
disp(angltrue_p')
disp('Computed angles')
disp(angl_p')
disp('Note the large change in the angles')
disp('  between Case 1 and Case 2, despite the small')
disp('  change in theta and in Q.')

