ddd6cda651bcf9aa601c3da5481750d764ff5f18
[platform/core/csapi/opentk.git] / src / OpenTK / Math / Quaternion.cs
1 /*
2 Copyright (c) 2006 - 2008 The Open Toolkit library.
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21  */
22
23 using System;
24 using System.Runtime.InteropServices;
25 using System.Xml.Serialization;
26
27 namespace OpenTK
28 {
29     /// <summary>
30     /// Represents a Quaternion.
31     /// </summary>
32     [Serializable]
33     [StructLayout(LayoutKind.Sequential)]
34     public struct Quaternion : IEquatable<Quaternion>
35     {
36         /// <summary>
37         /// The X, Y and Z components of this instance.
38         /// </summary>
39         public Vector3 Xyz;
40
41         /// <summary>
42         /// The W component of this instance.
43         /// </summary>
44         public float W;
45
46         /// <summary>
47         /// Construct a new Quaternion from vector and w components
48         /// </summary>
49         /// <param name="v">The vector part</param>
50         /// <param name="w">The w part</param>
51         public Quaternion(Vector3 v, float w)
52         {
53             Xyz = v;
54             W = w;
55         }
56
57         /// <summary>
58         /// Construct a new Quaternion
59         /// </summary>
60         /// <param name="x">The x component</param>
61         /// <param name="y">The y component</param>
62         /// <param name="z">The z component</param>
63         /// <param name="w">The w component</param>
64         public Quaternion(float x, float y, float z, float w)
65             : this(new Vector3(x, y, z), w)
66         { }
67
68         /// <summary>
69         /// Construct a new Quaternion from given Euler angles. The rotations will get applied in following order:
70         /// 1. Around X, 2. Around Y, 3. Around Z
71         /// </summary>
72         /// <param name="rotationX">Counterclockwise rotation around X axis in radian</param>
73         /// <param name="rotationY">Counterclockwise rotation around Y axis in radian</param>
74         /// <param name="rotationZ">Counterclockwise rotation around Z axis in radian</param>
75         public Quaternion(float rotationX, float rotationY, float rotationZ)
76         {
77             rotationX *= 0.5f;
78             rotationY *= 0.5f;
79             rotationZ *= 0.5f;
80
81             float c1 = (float)Math.Cos(rotationX);
82             float c2 = (float)Math.Cos(rotationY);
83             float c3 = (float)Math.Cos(rotationZ);
84             float s1 = (float)Math.Sin(rotationX);
85             float s2 = (float)Math.Sin(rotationY);
86             float s3 = (float)Math.Sin(rotationZ);
87
88             W = c1 * c2 * c3 - s1 * s2 * s3;
89             Xyz.X = s1 * c2 * c3 + c1 * s2 * s3;
90             Xyz.Y = c1 * s2 * c3 - s1 * c2 * s3;
91             Xyz.Z = c1 * c2 * s3 + s1 * s2 * c3;
92         }
93
94         /// <summary>
95         /// Construct a new Quaternion from given Euler angles. The rotations will get applied in following order:
96         /// 1. Around X, 2. Around Y, 3. Around Z
97         /// </summary>
98         /// <param name="eulerAngles">The counterclockwise euler angles as a Vector3</param>
99         public Quaternion(Vector3 eulerAngles)
100             : this(eulerAngles.X, eulerAngles.Y, eulerAngles.Z)
101         { }
102
103         /// <summary>
104         /// Gets or sets the X component of this instance.
105         /// </summary>
106         [XmlIgnore]
107         public float X { get { return Xyz.X; } set { Xyz.X = value; } }
108
109         /// <summary>
110         /// Gets or sets the Y component of this instance.
111         /// </summary>
112         [XmlIgnore]
113         public float Y { get { return Xyz.Y; } set { Xyz.Y = value; } }
114
115         /// <summary>
116         /// Gets or sets the Z component of this instance.
117         /// </summary>
118         [XmlIgnore]
119         public float Z { get { return Xyz.Z; } set { Xyz.Z = value; } }
120
121         /// <summary>
122         /// Convert the current quaternion to axis angle representation
123         /// </summary>
124         /// <param name="axis">The resultant axis</param>
125         /// <param name="angle">The resultant angle</param>
126         public void ToAxisAngle(out Vector3 axis, out float angle)
127         {
128             Vector4 result = ToAxisAngle();
129             axis = result.Xyz;
130             angle = result.W;
131         }
132
133         /// <summary>
134         /// Convert this instance to an axis-angle representation.
135         /// </summary>
136         /// <returns>A Vector4 that is the axis-angle representation of this quaternion.</returns>
137         public Vector4 ToAxisAngle()
138         {
139             Quaternion q = this;
140             if (Math.Abs(q.W) > 1.0f)
141             {
142                 q.Normalize();
143             }
144
145             Vector4 result = new Vector4();
146
147             result.W = 2.0f * (float)System.Math.Acos(q.W); // angle
148             float den = (float)System.Math.Sqrt(1.0 - q.W * q.W);
149             if (den > 0.0001f)
150             {
151                 result.Xyz = q.Xyz / den;
152             }
153             else
154             {
155                 // This occurs when the angle is zero.
156                 // Not a problem: just set an arbitrary normalized axis.
157                 result.Xyz = Vector3.UnitX;
158             }
159
160             return result;
161         }
162
163         /// <summary>
164         /// Gets the length (magnitude) of the quaternion.
165         /// </summary>
166         /// <seealso cref="LengthSquared"/>
167         public float Length
168         {
169             get
170             {
171                 return (float)System.Math.Sqrt(W * W + Xyz.LengthSquared);
172             }
173         }
174
175         /// <summary>
176         /// Gets the square of the quaternion length (magnitude).
177         /// </summary>
178         public float LengthSquared
179         {
180             get
181             {
182                 return W * W + Xyz.LengthSquared;
183             }
184         }
185
186         /// <summary>
187         /// Returns a copy of the Quaternion scaled to unit length.
188         /// </summary>
189         public Quaternion Normalized()
190         {
191             Quaternion q = this;
192             q.Normalize();
193             return q;
194         }
195
196         /// <summary>
197         /// Reverses the rotation angle of this Quaterniond.
198         /// </summary>
199         public void Invert()
200         {
201             W = -W;
202         }
203
204         /// <summary>
205         /// Returns a copy of this Quaterniond with its rotation angle reversed.
206         /// </summary>
207         public Quaternion Inverted()
208         {
209             var q = this;
210             q.Invert();
211             return q;
212         }
213
214         /// <summary>
215         /// Scales the Quaternion to unit length.
216         /// </summary>
217         public void Normalize()
218         {
219             float scale = 1.0f / this.Length;
220             Xyz *= scale;
221             W *= scale;
222         }
223
224         /// <summary>
225         /// Inverts the Vector3 component of this Quaternion.
226         /// </summary>
227         public void Conjugate()
228         {
229             Xyz = -Xyz;
230         }
231
232         /// <summary>
233         /// Defines the identity quaternion.
234         /// </summary>
235         public static readonly Quaternion Identity = new Quaternion(0, 0, 0, 1);
236
237         /// <summary>
238         /// Add two quaternions
239         /// </summary>
240         /// <param name="left">The first operand</param>
241         /// <param name="right">The second operand</param>
242         /// <returns>The result of the addition</returns>
243         public static Quaternion Add(Quaternion left, Quaternion right)
244         {
245             return new Quaternion(
246                 left.Xyz + right.Xyz,
247                 left.W + right.W);
248         }
249
250         /// <summary>
251         /// Add two quaternions
252         /// </summary>
253         /// <param name="left">The first operand</param>
254         /// <param name="right">The second operand</param>
255         /// <param name="result">The result of the addition</param>
256         public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result)
257         {
258             result = new Quaternion(
259                 left.Xyz + right.Xyz,
260                 left.W + right.W);
261         }
262
263         /// <summary>
264         /// Subtracts two instances.
265         /// </summary>
266         /// <param name="left">The left instance.</param>
267         /// <param name="right">The right instance.</param>
268         /// <returns>The result of the operation.</returns>
269         public static Quaternion Sub(Quaternion left, Quaternion right)
270         {
271             return  new Quaternion(
272                 left.Xyz - right.Xyz,
273                 left.W - right.W);
274         }
275
276         /// <summary>
277         /// Subtracts two instances.
278         /// </summary>
279         /// <param name="left">The left instance.</param>
280         /// <param name="right">The right instance.</param>
281         /// <param name="result">The result of the operation.</param>
282         public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result)
283         {
284             result = new Quaternion(
285                 left.Xyz - right.Xyz,
286                 left.W - right.W);
287         }
288
289         /// <summary>
290         /// Multiplies two instances.
291         /// </summary>
292         /// <param name="left">The first instance.</param>
293         /// <param name="right">The second instance.</param>
294         /// <returns>A new instance containing the result of the calculation.</returns>
295         public static Quaternion Multiply(Quaternion left, Quaternion right)
296         {
297             Quaternion result;
298             Multiply(ref left, ref right, out result);
299             return result;
300         }
301
302         /// <summary>
303         /// Multiplies two instances.
304         /// </summary>
305         /// <param name="left">The first instance.</param>
306         /// <param name="right">The second instance.</param>
307         /// <param name="result">A new instance containing the result of the calculation.</param>
308         public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result)
309         {
310             result = new Quaternion(
311                 right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
312                 left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
313         }
314
315         /// <summary>
316         /// Multiplies an instance by a scalar.
317         /// </summary>
318         /// <param name="quaternion">The instance.</param>
319         /// <param name="scale">The scalar.</param>
320         /// <param name="result">A new instance containing the result of the calculation.</param>
321         public static void Multiply(ref Quaternion quaternion, float scale, out Quaternion result)
322         {
323             result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
324         }
325
326         /// <summary>
327         /// Multiplies an instance by a scalar.
328         /// </summary>
329         /// <param name="quaternion">The instance.</param>
330         /// <param name="scale">The scalar.</param>
331         /// <returns>A new instance containing the result of the calculation.</returns>
332         public static Quaternion Multiply(Quaternion quaternion, float scale)
333         {
334             return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
335         }
336
337         /// <summary>
338         /// Get the conjugate of the given quaternion
339         /// </summary>
340         /// <param name="q">The quaternion</param>
341         /// <returns>The conjugate of the given quaternion</returns>
342         public static Quaternion Conjugate(Quaternion q)
343         {
344             return new Quaternion(-q.Xyz, q.W);
345         }
346
347         /// <summary>
348         /// Get the conjugate of the given quaternion
349         /// </summary>
350         /// <param name="q">The quaternion</param>
351         /// <param name="result">The conjugate of the given quaternion</param>
352         public static void Conjugate(ref Quaternion q, out Quaternion result)
353         {
354             result = new Quaternion(-q.Xyz, q.W);
355         }
356
357         /// <summary>
358         /// Get the inverse of the given quaternion
359         /// </summary>
360         /// <param name="q">The quaternion to invert</param>
361         /// <returns>The inverse of the given quaternion</returns>
362         public static Quaternion Invert(Quaternion q)
363         {
364             Quaternion result;
365             Invert(ref q, out result);
366             return result;
367         }
368
369         /// <summary>
370         /// Get the inverse of the given quaternion
371         /// </summary>
372         /// <param name="q">The quaternion to invert</param>
373         /// <param name="result">The inverse of the given quaternion</param>
374         public static void Invert(ref Quaternion q, out Quaternion result)
375         {
376             float lengthSq = q.LengthSquared;
377             if (lengthSq != 0.0)
378             {
379                 float i = 1.0f / lengthSq;
380                 result = new Quaternion(q.Xyz * -i, q.W * i);
381             }
382             else
383             {
384                 result = q;
385             }
386         }
387
388         /// <summary>
389         /// Scale the given quaternion to unit length
390         /// </summary>
391         /// <param name="q">The quaternion to normalize</param>
392         /// <returns>The normalized quaternion</returns>
393         public static Quaternion Normalize(Quaternion q)
394         {
395             Quaternion result;
396             Normalize(ref q, out result);
397             return result;
398         }
399
400         /// <summary>
401         /// Scale the given quaternion to unit length
402         /// </summary>
403         /// <param name="q">The quaternion to normalize</param>
404         /// <param name="result">The normalized quaternion</param>
405         public static void Normalize(ref Quaternion q, out Quaternion result)
406         {
407             float scale = 1.0f / q.Length;
408             result = new Quaternion(q.Xyz * scale, q.W * scale);
409         }
410
411         /// <summary>
412         /// Build a quaternion from the given axis and angle
413         /// </summary>
414         /// <param name="axis">The axis to rotate about</param>
415         /// <param name="angle">The rotation angle in radians</param>
416         /// <returns>The equivalent quaternion</returns>
417         public static Quaternion FromAxisAngle(Vector3 axis, float angle)
418         {
419             if (axis.LengthSquared == 0.0f)
420             {
421                 return Identity;
422             }
423
424             Quaternion result = Identity;
425
426             angle *= 0.5f;
427             axis.Normalize();
428             result.Xyz = axis * (float)System.Math.Sin(angle);
429             result.W = (float)System.Math.Cos(angle);
430
431             return Normalize(result);
432         }
433
434         /// <summary>
435         /// Builds a Quaternion from the given euler angles
436         /// The rotations will get applied in following order:
437         /// 1. pitch, 2. yaw, 3. roll
438         /// </summary>
439         /// <param name="pitch">The pitch (attitude), counterclockwise rotation around X axis</param>
440         /// <param name="yaw">The yaw (heading), counterclockwise rotation around Y axis</param>
441         /// <param name="roll">The roll (bank), counterclockwise rotation around Z axis</param>
442         /// <returns></returns>
443         public static Quaternion FromEulerAngles(float pitch, float yaw, float roll)
444         {
445             return new Quaternion(pitch, yaw, roll);
446         }
447
448         /// <summary>
449         /// Builds a Quaternion from the given euler angles
450         /// The rotations will get applied in following order:
451         /// 1. Around X, 2. Around Y, 3. Around Z
452         /// </summary>
453         /// <param name="eulerAngles">The counterclockwise euler angles as a vector</param>
454         /// <returns>The equivalent Quaternion</returns>
455         public static Quaternion FromEulerAngles(Vector3 eulerAngles)
456         {
457             return new Quaternion(eulerAngles);
458         }
459
460         /// <summary>
461         /// Builds a Quaternion from the given euler angles in radians.
462         /// The rotations will get applied in following order:
463         /// 1. Around X, 2. Around Y, 3. Around Z
464         /// </summary>
465         /// <param name="eulerAngles">The counterclockwise euler angles a vector</param>
466         /// <param name="result">The equivalent Quaternion</param>
467         public static void FromEulerAngles(ref Vector3 eulerAngles, out Quaternion result)
468         {
469
470             float c1 = (float)Math.Cos(eulerAngles.X * 0.5f);
471             float c2 = (float)Math.Cos(eulerAngles.Y * 0.5f);
472             float c3 = (float)Math.Cos(eulerAngles.Z * 0.5f);
473             float s1 = (float)Math.Sin(eulerAngles.X * 0.5f);
474             float s2 = (float)Math.Sin(eulerAngles.Y * 0.5f);
475             float s3 = (float)Math.Sin(eulerAngles.Z * 0.5f);
476
477             result.W = c1 * c2 * c3 - s1 * s2 * s3;
478             result.Xyz.X = s1 * c2 * c3 + c1 * s2 * s3;
479             result.Xyz.Y = c1 * s2 * c3 - s1 * c2 * s3;
480             result.Xyz.Z = c1 * c2 * s3 + s1 * s2 * c3;
481         }
482
483         /// <summary>
484         /// Builds a quaternion from the given rotation matrix
485         /// </summary>
486         /// <param name="matrix">A rotation matrix</param>
487         /// <returns>The equivalent quaternion</returns>
488         public static Quaternion FromMatrix(Matrix3 matrix)
489         {
490             Quaternion result;
491             FromMatrix(ref matrix, out result);
492             return result;
493         }
494
495         /// <summary>
496         /// Builds a quaternion from the given rotation matrix
497         /// </summary>
498         /// <param name="matrix">A rotation matrix</param>
499         /// <param name="result">The equivalent quaternion</param>
500         public static void FromMatrix(ref Matrix3 matrix, out Quaternion result)
501         {
502             float trace = matrix.Trace;
503
504             if (trace > 0)
505             {
506                 float s = (float)Math.Sqrt(trace + 1) * 2;
507                 float invS = 1f / s;
508
509                 result.W = s * 0.25f;
510                 result.Xyz.X = (matrix.Row2.Y - matrix.Row1.Z) * invS;
511                 result.Xyz.Y = (matrix.Row0.Z - matrix.Row2.X) * invS;
512                 result.Xyz.Z = (matrix.Row1.X - matrix.Row0.Y) * invS;
513             }
514             else
515             {
516                 float m00 = matrix.Row0.X, m11 = matrix.Row1.Y, m22 = matrix.Row2.Z;
517
518                 if (m00 > m11 && m00 > m22)
519                 {
520                     float s = (float)Math.Sqrt(1 + m00 - m11 - m22) * 2;
521                     float invS = 1f / s;
522
523                     result.W = (matrix.Row2.Y - matrix.Row1.Z) * invS;
524                     result.Xyz.X = s * 0.25f;
525                     result.Xyz.Y = (matrix.Row0.Y + matrix.Row1.X) * invS;
526                     result.Xyz.Z = (matrix.Row0.Z + matrix.Row2.X) * invS;
527                 }
528                 else if (m11 > m22)
529                 {
530                     float s = (float)Math.Sqrt(1 + m11 - m00 - m22) * 2;
531                     float invS = 1f / s;
532
533                     result.W = (matrix.Row0.Z - matrix.Row2.X) * invS;
534                     result.Xyz.X = (matrix.Row0.Y + matrix.Row1.X) * invS;
535                     result.Xyz.Y = s * 0.25f;
536                     result.Xyz.Z = (matrix.Row1.Z + matrix.Row2.Y) * invS;
537                 }
538                 else
539                 {
540                     float s = (float)Math.Sqrt(1 + m22 - m00 - m11) * 2;
541                     float invS = 1f / s;
542
543                     result.W = (matrix.Row1.X - matrix.Row0.Y) * invS;
544                     result.Xyz.X = (matrix.Row0.Z + matrix.Row2.X) * invS;
545                     result.Xyz.Y = (matrix.Row1.Z + matrix.Row2.Y) * invS;
546                     result.Xyz.Z = s * 0.25f;
547                 }
548             }
549         }
550
551         /// <summary>
552         /// Do Spherical linear interpolation between two quaternions
553         /// </summary>
554         /// <param name="q1">The first quaternion</param>
555         /// <param name="q2">The second quaternion</param>
556         /// <param name="blend">The blend factor</param>
557         /// <returns>A smooth blend between the given quaternions</returns>
558         public static Quaternion Slerp(Quaternion q1, Quaternion q2, float blend)
559         {
560             // if either input is zero, return the other.
561             if (q1.LengthSquared == 0.0f)
562             {
563                 if (q2.LengthSquared == 0.0f)
564                 {
565                     return Identity;
566                 }
567                 return q2;
568             }
569             else if (q2.LengthSquared == 0.0f)
570             {
571                 return q1;
572             }
573
574
575             float cosHalfAngle = q1.W * q2.W + Vector3.Dot(q1.Xyz, q2.Xyz);
576
577             if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f)
578             {
579                 // angle = 0.0f, so just return one input.
580                 return q1;
581             }
582             else if (cosHalfAngle < 0.0f)
583             {
584                 q2.Xyz = -q2.Xyz;
585                 q2.W = -q2.W;
586                 cosHalfAngle = -cosHalfAngle;
587             }
588
589             float blendA;
590             float blendB;
591             if (cosHalfAngle < 0.99f)
592             {
593                 // do proper slerp for big angles
594                 float halfAngle = (float)System.Math.Acos(cosHalfAngle);
595                 float sinHalfAngle = (float)System.Math.Sin(halfAngle);
596                 float oneOverSinHalfAngle = 1.0f / sinHalfAngle;
597                 blendA = (float)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle;
598                 blendB = (float)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle;
599             }
600             else
601             {
602                 // do lerp if angle is really small.
603                 blendA = 1.0f - blend;
604                 blendB = blend;
605             }
606
607             Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W);
608             if (result.LengthSquared > 0.0f)
609             {
610                 return Normalize(result);
611             }
612             else
613             {
614                 return Identity;
615             }
616         }
617
618         /// <summary>
619         /// Adds two instances.
620         /// </summary>
621         /// <param name="left">The first instance.</param>
622         /// <param name="right">The second instance.</param>
623         /// <returns>The result of the calculation.</returns>
624         public static Quaternion operator +(Quaternion left, Quaternion right)
625         {
626             left.Xyz += right.Xyz;
627             left.W += right.W;
628             return left;
629         }
630
631         /// <summary>
632         /// Subtracts two instances.
633         /// </summary>
634         /// <param name="left">The first instance.</param>
635         /// <param name="right">The second instance.</param>
636         /// <returns>The result of the calculation.</returns>
637         public static Quaternion operator -(Quaternion left, Quaternion right)
638         {
639             left.Xyz -= right.Xyz;
640             left.W -= right.W;
641             return left;
642         }
643
644         /// <summary>
645         /// Multiplies two instances.
646         /// </summary>
647         /// <param name="left">The first instance.</param>
648         /// <param name="right">The second instance.</param>
649         /// <returns>The result of the calculation.</returns>
650         public static Quaternion operator *(Quaternion left, Quaternion right)
651         {
652             Multiply(ref left, ref right, out left);
653             return left;
654         }
655
656         /// <summary>
657         /// Multiplies an instance by a scalar.
658         /// </summary>
659         /// <param name="quaternion">The instance.</param>
660         /// <param name="scale">The scalar.</param>
661         /// <returns>A new instance containing the result of the calculation.</returns>
662         public static Quaternion operator *(Quaternion quaternion, float scale)
663         {
664             Multiply(ref quaternion, scale, out quaternion);
665             return quaternion;
666         }
667
668         /// <summary>
669         /// Multiplies an instance by a scalar.
670         /// </summary>
671         /// <param name="quaternion">The instance.</param>
672         /// <param name="scale">The scalar.</param>
673         /// <returns>A new instance containing the result of the calculation.</returns>
674         public static Quaternion operator *(float scale, Quaternion quaternion)
675         {
676             return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
677         }
678
679         /// <summary>
680         /// Compares two instances for equality.
681         /// </summary>
682         /// <param name="left">The first instance.</param>
683         /// <param name="right">The second instance.</param>
684         /// <returns>True, if left equals right; false otherwise.</returns>
685         public static bool operator ==(Quaternion left, Quaternion right)
686         {
687             return left.Equals(right);
688         }
689
690         /// <summary>
691         /// Compares two instances for inequality.
692         /// </summary>
693         /// <param name="left">The first instance.</param>
694         /// <param name="right">The second instance.</param>
695         /// <returns>True, if left does not equal right; false otherwise.</returns>
696         public static bool operator !=(Quaternion left, Quaternion right)
697         {
698             return !left.Equals(right);
699         }
700
701         /// <summary>
702         /// Returns a System.String that represents the current Quaternion.
703         /// </summary>
704         /// <returns></returns>
705         public override string ToString()
706         {
707             return String.Format("V: {0}, W: {1}", Xyz, W);
708         }
709
710         /// <summary>
711         /// Compares this object instance to another object for equality.
712         /// </summary>
713         /// <param name="other">The other object to be used in the comparison.</param>
714         /// <returns>True if both objects are Quaternions of equal value. Otherwise it returns false.</returns>
715         public override bool Equals(object other)
716         {
717             if (other is Quaternion == false)
718             {
719                 return false;
720             }
721             return this == (Quaternion)other;
722         }
723
724         /// <summary>
725         /// Provides the hash code for this object.
726         /// </summary>
727         /// <returns>A hash code formed from the bitwise XOR of this objects members.</returns>
728         public override int GetHashCode()
729         {
730             unchecked
731             {
732                 return (this.Xyz.GetHashCode() * 397) ^ this.W.GetHashCode();
733             }
734         }
735
736         /// <summary>
737         /// Compares this Quaternion instance to another Quaternion for equality.
738         /// </summary>
739         /// <param name="other">The other Quaternion to be used in the comparison.</param>
740         /// <returns>True if both instances are equal; false otherwise.</returns>
741         public bool Equals(Quaternion other)
742         {
743             return Xyz == other.Xyz && W == other.W;
744         }
745     }
746 }