From e9470ec26d964c31af61619cc57c6a9f10fe3149 Mon Sep 17 00:00:00 2001
From: Jean-Yves TINEVEZ <jean-yves.tinevez@pasteur.fr>
Date: Fri, 3 Jul 2020 16:37:37 +0200
Subject: [PATCH] Finally found a good way to go to meaningful Euler angles
 from rotation matrix.

and back.
---
 src/euleurZXZ2rot.m | 36 ++++++++++++++++++++++++++++++++++++
 src/fit_ellipse.m   | 22 +---------------------
 src/rot2eulerZXZ.m  | 30 ++++++++++++++++++++++++++++++
 3 files changed, 67 insertions(+), 21 deletions(-)
 create mode 100644 src/euleurZXZ2rot.m
 create mode 100644 src/rot2eulerZXZ.m

diff --git a/src/euleurZXZ2rot.m b/src/euleurZXZ2rot.m
new file mode 100644
index 0000000..58ea885
--- /dev/null
+++ b/src/euleurZXZ2rot.m
@@ -0,0 +1,36 @@
+function R = euleurZXZ2rot( E )
+%% EULERZYZ2ROT Convert euler ZX'Z' angles to rotation matrix.
+% See https://www.geometrictools.com/Documentation/EulerAngles.pdf to have
+% a final answer to this madness.
+
+    alpha = E( 1 );
+    beta = E( 2 );
+    gamma = E( 3 );
+    
+    c1 = cos( alpha );
+    s1 = sin( alpha );
+
+    c2 = cos( beta );
+    s2 = sin( beta );
+
+    c3 = cos( gamma );
+    s3 = sin( gamma );
+    
+    r11 = c1 * c3 - c2 * s1 * s3;
+    r12 = - c1 * s3 - c2 * c3 * s1;
+    r13 = s1 * s2;
+    
+    r21 = c3 * s1 + c1 * c2 * s3;
+    r22 = c1 * c2 * c3 - s1 * s3;
+    r23 = - c1 * s2;
+    
+    r31 = s2 * s3;
+    r32 = c3 * s2;
+    r33 = c2;
+    
+    R = [
+        r11 r12 r13
+        r21 r22 r23
+        r31 r32 r33 ];
+
+end
\ No newline at end of file
diff --git a/src/fit_ellipse.m b/src/fit_ellipse.m
index 0770443..2922dcc 100644
--- a/src/fit_ellipse.m
+++ b/src/fit_ellipse.m
@@ -12,7 +12,7 @@ function [ f, E ] = fit_ellipse( o )
     
     % Fit a plane to these points.
     [ ~, ~, v ] = svd( p );
-    E = to_euler( v );
+    E = rot2eulerZXZ( v );
     
     % Rotate the points into the principal axes frame.
     p = p * v;
@@ -24,26 +24,6 @@ function [ f, E ] = fit_ellipse( o )
     
     %% Subfunctions
     
-    function E = to_euler( R )
-        if R( 1, 3 ) == 1 || R( 1, 3 ) == -1
-            E3 = 0;
-            dlta = atan2(R(1,2),R(1,3));
-            if R(1,3) == -1
-                E2 = pi/2;
-                E1 = E3 + dlta;
-            else
-                E2 = -pi/2;
-                E1 = -E3 + dlta;
-            end
-        else
-            E2 = - asin( R( 1, 3 ) );
-            E1 = atan2( R( 2, 3 ) / cos( E2 ), R( 3, 3 ) / cos( E2 ) );
-            E3 = atan2( R( 1, 2 ) / cos( E2 ), R( 1, 1 ) / cos( E2 ) );
-        end
-        E = [ E1, E2, E3 ];
-        
-    end
-
     function f = quadratic_to_cartesian( A )
     % Equations taken from Wolfram website.
         
diff --git a/src/rot2eulerZXZ.m b/src/rot2eulerZXZ.m
new file mode 100644
index 0000000..7ef5820
--- /dev/null
+++ b/src/rot2eulerZXZ.m
@@ -0,0 +1,30 @@
+function[E,E_deg]=rot2eulerZXZ(R)
+%ROT2EULERZXZ Convert rotation matrix to ZX'Z' Euler angles.
+
+    r13 = R( 1, 3 );
+    r31 = R( 3, 1 );
+    r22 = R( 2, 2 );
+    r23 = R( 2, 3 );
+    r32 = R( 3, 2 );
+    r33 = R( 3, 3 );
+
+    if r22 < +1
+        if r22 > -1
+            thetaX = acos( r33 );
+            thetaZ0 = atan2( r13, -r23 );
+            thetaZ1 = atan2( r31, r32 );
+        else            
+            thetaX = pi;
+            thetaZ0 = -atan2( -r12, r11 );
+            thetaZ1 = 0;
+        end
+    else
+        thetaX = 0;
+        thetaZ0 = atan2( -r12, r11 );
+        thetaZ1 = 0;
+    end
+    
+    E = double( [ thetaZ0, thetaX, thetaZ1 ] );
+    E_deg = rad2deg( E );
+end
+
-- 
GitLab