From 8285b225349aa97ee8de61cb35e1f750f0cc1660 Mon Sep 17 00:00:00 2001
From: Oliver Sander <sander@igpm.rwth-aachen.de>
Date: Wed, 11 Jan 2012 17:43:44 +0000
Subject: [PATCH] make the 'distance' method simpler and faster

[[Imported from SVN: r8366]]
---
 dune/gfe/rotation.hh | 19 +++++++------------
 1 file changed, 7 insertions(+), 12 deletions(-)

diff --git a/dune/gfe/rotation.hh b/dune/gfe/rotation.hh
index 6ddf2b1c..6a52b7d7 100644
--- a/dune/gfe/rotation.hh
+++ b/dune/gfe/rotation.hh
@@ -544,22 +544,17 @@ public:
     }
 
     static T distance(const Rotation<T,3>& a, const Rotation<T,3>& b) {
-        Quaternion<T> diff = a;
+        
+        // Distance in the unit quaternions: 2*arccos( ((a^{-1) b)_3 )
+        // But note that (a^{-1}b)_3 is actually <a,b> (in R^4)
+        T sp = a.globalCoordinates() * b.globalCoordinates();
 
-        diff.invert();
-        diff = diff.mult(b);
+        // Scalar product may be larger than 1.0, due to numerical dirt
+        T dist = 2*std::acos( std::min(sp,1.0) );
 
         // Make sure we do the right thing if a and b are not in the same sheet
         // of the double covering of the unit quaternions over SO(3)
-        T dist = 2*std::acos( std::min(diff[3],1.0) );
-
-        if (dist>=M_PI)
-            return 2*M_PI - dist;
- 
-        // Compute the geodesical distance between a and b on SO(3)
-        // Due to numerical dirt, diff[3] may be larger than 1. 
-        // In that case, use 1 instead of diff[3].
-        return 2*std::acos( std::min(diff[3],1.0) );
+        return (dist>=M_PI) ? (2*M_PI - dist) : dist;
     }
 
     /** \brief Compute the vector in T_aSO(3) that is mapped by the exponential map
-- 
GitLab