From 261ff062aebb53d8edbe0f1379f1de31ce7baa4f Mon Sep 17 00:00:00 2001
From: Henry <Henry>
Date: Thu, 19 Jul 2012 17:55:43 +0100
Subject: [PATCH] quaternion: added constructor from angle cosine and slerp

---
 .../primitives/quaternion/quaternion.C        | 25 +++++++++++++++++
 .../primitives/quaternion/quaternion.H        | 17 ++++++++++++
 .../primitives/quaternion/quaternionI.H       | 27 ++++++++++++++++---
 3 files changed, 66 insertions(+), 3 deletions(-)

diff --git a/src/OpenFOAM/primitives/quaternion/quaternion.C b/src/OpenFOAM/primitives/quaternion/quaternion.C
index f7ff1904c90..0e7b1b8c3a1 100644
--- a/src/OpenFOAM/primitives/quaternion/quaternion.C
+++ b/src/OpenFOAM/primitives/quaternion/quaternion.C
@@ -51,6 +51,31 @@ Foam::word Foam::name(const quaternion& q)
 }
 
 
+Foam::quaternion Foam::slerp
+(
+    const quaternion& qa,
+    const quaternion& qb,
+    const scalar t
+)
+{
+    // Calculate angle between the quaternions
+    scalar cosHalfTheta = qa & qb;
+
+    if (mag(cosHalfTheta) >= 1)
+    {
+        return qa;
+    }
+
+    scalar halfTheta = acos(cosHalfTheta);
+    scalar sinHalfTheta = sqrt(1.0 - sqr(cosHalfTheta));
+
+    scalar wa = sin((1 - t)*halfTheta)/sinHalfTheta;
+    scalar wb = sin(t*halfTheta)/sinHalfTheta;
+
+    return wa*qa + wb*qb;
+}
+
+
 // * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
 
 Foam::Istream& Foam::operator>>(Istream& is, quaternion& q)
diff --git a/src/OpenFOAM/primitives/quaternion/quaternion.H b/src/OpenFOAM/primitives/quaternion/quaternion.H
index 730e86d68df..dbe7ad15b52 100644
--- a/src/OpenFOAM/primitives/quaternion/quaternion.H
+++ b/src/OpenFOAM/primitives/quaternion/quaternion.H
@@ -106,6 +106,15 @@ public:
         //  and angle theta
         inline quaternion(const vector& d, const scalar theta);
 
+        //- Construct a rotation quaternion given the direction d
+        //  and cosine angle cosTheta and a if d is normalized
+        inline quaternion
+        (
+            const vector& d,
+            const scalar cosTheta,
+            const bool normalized
+        );
+
         //- Construct given scalar part, the vector part = vector::zero
         inline explicit quaternion(const scalar w);
 
@@ -209,6 +218,14 @@ inline quaternion inv(const quaternion& q);
 //- Return a string representation of a quaternion
 word name(const quaternion&);
 
+//- Spherical linear interpolation of quaternions
+quaternion slerp
+(
+    const quaternion& qa,
+    const quaternion& qb,
+    const scalar t
+);
+
 //- Data associated with quaternion type are contiguous
 template<>
 inline bool contiguous<quaternion>() {return true;}
diff --git a/src/OpenFOAM/primitives/quaternion/quaternionI.H b/src/OpenFOAM/primitives/quaternion/quaternionI.H
index 709ee52b6d9..1582f5c7337 100644
--- a/src/OpenFOAM/primitives/quaternion/quaternionI.H
+++ b/src/OpenFOAM/primitives/quaternion/quaternionI.H
@@ -40,6 +40,26 @@ inline Foam::quaternion::quaternion(const vector& d, const scalar theta)
     v_((sin(0.5*theta)/mag(d))*d)
 {}
 
+inline Foam::quaternion::quaternion
+(
+    const vector& d,
+    const scalar cosTheta,
+    const bool normalized
+)
+{
+    scalar cosHalfTheta2 = 0.5*(cosTheta + 1);
+    w_ = sqrt(cosHalfTheta2);
+
+    if (normalized)
+    {
+        v_ = sqrt(1 - cosHalfTheta2)*d;
+    }
+    else
+    {
+        v_ = (sqrt(1 - cosHalfTheta2)/mag(d))*d;
+    }
+}
+
 inline Foam::quaternion::quaternion(const scalar w)
 :
     w_(w),
@@ -69,9 +89,10 @@ inline Foam::quaternion::quaternion
     const tensor& rotationTensor
 )
 {
-    scalar trace = rotationTensor.xx()
-                 + rotationTensor.yy()
-                 + rotationTensor.zz();
+    scalar trace =
+        rotationTensor.xx()
+      + rotationTensor.yy()
+      + rotationTensor.zz();
 
     if (trace > 0)
     {
-- 
GitLab