bluesky8059

Quaternion.cs

Jul 31st, 2015
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.13 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. using System.IO;
  7. using System.Diagnostics;
  8.  
  9. namespace quaternionTest
  10. {
  11.     class Quaternion
  12.     {
  13.         public double X, Y, Z, W;
  14.         public double qs = 1.0;
  15.         public double [] qv = new double[3] { 0.0, 0.0, 0.0 };
  16.         double roll, pitch, yaw;
  17.         //Quaternion Initialization
  18.         public Quaternion(double w, double x, double y, double z)
  19.         {
  20.             W = w;
  21.             X = x;
  22.             Y = y;
  23.             Z = z;
  24.         }
  25.  
  26.         //Use Axis and Angle to get a Quaternion
  27.         public Quaternion(double [] Axis, double Angle)
  28.         {
  29.  
  30.         }
  31.  
  32.         //Normalise
  33.         public void Normalise()
  34.         {
  35.             double m = W * W + X * X + Y * Y + Z * Z;
  36.             if (m > 0.001)
  37.             {
  38.                 m = Math.Sqrt(m);
  39.                 W /= m;
  40.                 X /= m;
  41.                 Y /= m;
  42.                 Z /= m;
  43.             }
  44.             else
  45.             {
  46.                 W = 1; X = 0; Y = 0; Z = 0;
  47.             }
  48.         }
  49.  
  50.         //Quaternion Conjugate
  51.         public static Quaternion Conjugate(Quaternion q)
  52.         {
  53.             double nw = q.W;
  54.             double nx = -(q.X);
  55.             double ny = -(q.Y);
  56.             double nz = -(q.Z);
  57.             return new Quaternion(nw, nx, ny, nz);
  58.         }
  59.  
  60.         //Quaternion Addition
  61.         public static Quaternion operator +(Quaternion q1, Quaternion q2)
  62.         {
  63.             double nw = q1.W + q2.W;
  64.             double nx = q1.X + q2.X;
  65.             double ny = q1.Y + q2.Y;
  66.             double nz = q1.Z + q2.Z;
  67.             return new Quaternion(nw, nx, ny, nz);
  68.         }
  69.  
  70.         //Quaternion Substration
  71.         public static Quaternion operator -(Quaternion q1, Quaternion q2)
  72.         {
  73.             double nw = q1.W - q2.W;
  74.             double nx = q1.X - q2.X;
  75.             double ny = q1.Y - q2.Y;
  76.             double nz = q1.Z - q2.Z;
  77.             return new Quaternion(nw, nx, ny, nz);
  78.         }
  79.  
  80.         //Quaternion Multiplication
  81.         // Multiplying q1 with q2 is meaning of doing q2 firstly then q1
  82.         public static Quaternion operator *(Quaternion q1, Quaternion q2)
  83.         {
  84.             double nw = q1.W * q2.W - q1.X * q2.X - q1.Y * q2.Y - q1.Z * q2.Z;
  85.             double nx = q1.W * q2.X + q1.X * q2.W + q1.Y * q2.Z - q1.Z * q2.Y;
  86.             double ny = q1.W * q2.Y - q1.X * q2.Z + q1.Y * q2.W + q1.Z * q2.X;
  87.             double nz = q1.W * q2.Z + q1.X * q2.Y - q1.Y * q2.X + q1.Z * q2.W;
  88.             return new Quaternion(nw, nx, ny, nz);
  89.         }
  90.  
  91.         //Quaternion Division (Multiply by the inverse)
  92.         public static Quaternion operator /(Quaternion q1, Quaternion q2)
  93.         {
  94.             Quaternion q2Conj = Conjugate(q2);
  95.             double norm = Math.Sqrt(q2.W * q2.W + q2.X * q2.X + q2.Y * q2.Y + q2.Z * q2.Z);
  96.             Quaternion newQ = q1 * q2Conj;
  97.             double nw = newQ.W / norm;
  98.             double nx = newQ.X / norm;
  99.             double ny = newQ.Y / norm;
  100.             double nz = newQ.Z / norm;
  101.             return new Quaternion(nw, nx, ny, nz);
  102.         }
  103.  
  104.         //Update the quaternion using Euler angles(roll, pitch, yaw)
  105.         /*
  106.          * heading     theta    yaw
  107.            attitude    phi      pitch
  108.            bank        psi      roll
  109.          */
  110.         public void setRPY(double roll, double pitch, double yaw)
  111.         {
  112.             double cY = Math.Cos(yaw / 2.0);
  113.             double sY = Math.Sin(yaw / 2.0);
  114.             double cR = Math.Cos(roll / 2.0);
  115.             double sR = Math.Sin(roll / 2.0);
  116.             double cP = Math.Cos(pitch / 2.0);
  117.             double sP = Math.Sin(pitch / 2.0);
  118.             W = cR * cP * cY + sR * sP * sY;
  119.             X = sR * cP * cY - cR * sP * sY;
  120.             Y = cR * sP * cY + sR * cP * sY;
  121.             Z = cR * cP * sY - sR * sP * cY;
  122.         }
  123.  
  124.         //Get the RPY from Quaternion
  125.         public double [] getRPY()
  126.         {
  127.             double sqw = W * W;
  128.             double sqx = X * X;
  129.             double sqy = Y * Y;
  130.             double sqz = Z * Z;
  131.             double unit = X + Y + Z + W; //if normalised is one, otherwise is correction factor
  132.             double test = X * Y + Z * W;
  133.             double [] result = new double[3];
  134. #if true
  135.             if (test > 0.499 * unit)
  136.             {
  137.                 pitch = 2 * Math.Atan2(X, W);
  138.                 yaw = Math.PI / 2.0;
  139.                 roll = 0;
  140.                 result[0] = (roll * 180.0) / Math.PI;
  141.                 result[1] = (pitch * 180.0) / Math.PI;
  142.                 result[2] = (yaw * 180.0) / Math.PI;
  143.                 return result;
  144.             }
  145.             if (test < -0.499 * unit)
  146.             {
  147.                 pitch = -2 * Math.Atan2(X, W);
  148.                 yaw = -Math.PI / 2.0;
  149.                 roll = 0;
  150.                 result[0] = (roll * 180.0) / Math.PI;
  151.                 result[1] = (pitch * 180.0) / Math.PI;
  152.                 result[2] = (yaw * 180.0) / Math.PI;
  153.                 return result;
  154.             }
  155. #endif
  156.             yaw = Math.Atan2(2.0 * (W * Z + X * Y), sqw + sqx - sqy - sqz);
  157.             pitch = Math.Asin(2.0 * (W * Y - X * Z));
  158.             roll = Math.Atan2(2.0 * (W * X + Y * Z), sqw - sqx - sqy + sqz);
  159.             result[0] = (roll * 180.0) / Math.PI;
  160.             result[1] = (pitch * 180.0) / Math.PI;
  161.             result[2] = (yaw * 180.0) / Math.PI;
  162.    
  163.             return result;
  164.         }
  165.  
  166.         //Do the slerp
  167.         public static Quaternion Slerp(Quaternion q1, Quaternion q2, double t)
  168.         {
  169.             //w, x, y, z
  170.             double nw, nx, ny, nz;
  171.             //Calculate angle between them
  172.             double cosHalfTheta = q1.W * q2.W + q1.X * q2.X + q1.Y + q2.Y + q1.Z + q1.Z;
  173.                    
  174.            
  175.             //if q1 = q2 or q1 = -q2 then theta = 0, return q1
  176.             if (Math.Abs(cosHalfTheta) >= 1.0)
  177.             {
  178.                 nw = q2.W;
  179.                 nx = q2.X;
  180.                 ny = q2.Y;
  181.                 nz = q2.Z;
  182.                 return new Quaternion(nw, nx, ny, nz);
  183.             }
  184.  
  185.             //Calculate temporary values.
  186.             double halfTheta = Math.Acos(cosHalfTheta);
  187.             double sinHalfTheta = Math.Sqrt(1.0 - cosHalfTheta * cosHalfTheta);
  188.            
  189.             //if theta = 180 degrees then result is not fully defined
  190.             if(Math.Abs(sinHalfTheta) < 0.001){
  191.                 nw = (q1.W * 0.5 + q2.W * 0.5);
  192.                 nx = (q1.X * 0.5 + q2.X * 0.5);
  193.                 ny = (q1.Y * 0.5 + q2.Y * 0.5);
  194.                 nz = (q1.Z * 0.5 + q2.Z * 0.5);
  195.                 return new Quaternion(nw, nx, ny, nz);
  196.             }
  197.  
  198.             double ratioA = Math.Sin((1 - t) * halfTheta) / sinHalfTheta;
  199.             double ratioB = Math.Sin(t * halfTheta) / sinHalfTheta;  
  200.             //Calculate Quaternion
  201.             nw = (q1.W * ratioA + q2.W * ratioB);
  202.             nx = (q1.X * ratioA + q2.X * ratioB);
  203.             ny = (q1.Y * ratioA + q2.Y * ratioB);
  204.             nz = (q1.Z * ratioA + q2.Z * ratioB);
  205.             return new Quaternion(nw, nx, ny, nz);
  206.         }
  207.  
  208.     }
  209. }
Advertisement
Add Comment
Please, Sign In to add comment