00001 #region --- License ---
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #endregion
00024
00025 using System;
00026 using System.Runtime.InteropServices;
00027 using System.ComponentModel;
00028 using System.Xml.Serialization;
00029
00030 namespace OpenTK
00031 {
00035 [Serializable]
00036 [StructLayout(LayoutKind.Sequential)]
00037 public struct Quaternion : IEquatable<Quaternion>
00038 {
00039 #region Fields
00040
00041 Vector3 xyz;
00042 float w;
00043
00044 #endregion
00045
00046 #region Constructors
00047
00053 public Quaternion(Vector3 v, float w)
00054 {
00055 this.xyz = v;
00056 this.w = w;
00057 }
00058
00066 public Quaternion(float x, float y, float z, float w)
00067 : this(new Vector3(x, y, z), w)
00068 { }
00069
00070 #endregion
00071
00072 #region Public Members
00073
00074 #region Properties
00075
00079 [Obsolete("Use Xyz property instead.")]
00080 [CLSCompliant(false)]
00081 [EditorBrowsable(EditorBrowsableState.Never)]
00082 [XmlIgnore]
00083 public Vector3 XYZ { get { return Xyz; } set { Xyz = value; } }
00084
00088 public Vector3 Xyz { get { return xyz; } set { xyz = value; } }
00089
00093 [XmlIgnore]
00094 public float X { get { return xyz.X; } set { xyz.X = value; } }
00095
00099 [XmlIgnore]
00100 public float Y { get { return xyz.Y; } set { xyz.Y = value; } }
00101
00105 [XmlIgnore]
00106 public float Z { get { return xyz.Z; } set { xyz.Z = value; } }
00107
00111 public float W { get { return w; } set { w = value; } }
00112
00113 #endregion
00114
00115 #region Instance
00116
00117 #region ToAxisAngle
00118
00124 public void ToAxisAngle(out Vector3 axis, out float angle)
00125 {
00126 Vector4 result = ToAxisAngle();
00127 axis = result.Xyz;
00128 angle = result.W;
00129 }
00130
00135 public Vector4 ToAxisAngle()
00136 {
00137 Quaternion q = this;
00138 if (q.W > 1.0f)
00139 q.Normalize();
00140
00141 Vector4 result = new Vector4();
00142
00143 result.W = 2.0f * (float)System.Math.Acos(q.W);
00144 float den = (float)System.Math.Sqrt(1.0 - q.W * q.W);
00145 if (den > 0.0001f)
00146 {
00147 result.Xyz = q.Xyz / den;
00148 }
00149 else
00150 {
00151
00152
00153 result.Xyz = Vector3.UnitX;
00154 }
00155
00156 return result;
00157 }
00158
00159 #endregion
00160
00161 #region public float Length
00162
00167 public float Length
00168 {
00169 get
00170 {
00171 return (float)System.Math.Sqrt(W * W + Xyz.LengthSquared);
00172 }
00173 }
00174
00175 #endregion
00176
00177 #region public float LengthSquared
00178
00182 public float LengthSquared
00183 {
00184 get
00185 {
00186 return W * W + Xyz.LengthSquared;
00187 }
00188 }
00189
00190 #endregion
00191
00192 #region public void Normalize()
00193
00197 public void Normalize()
00198 {
00199 float scale = 1.0f / this.Length;
00200 Xyz *= scale;
00201 W *= scale;
00202 }
00203
00204 #endregion
00205
00206 #region public void Conjugate()
00207
00211 public void Conjugate()
00212 {
00213 Xyz = -Xyz;
00214 }
00215
00216 #endregion
00217
00218 #endregion
00219
00220 #region Static
00221
00222 #region Fields
00223
00227 public static Quaternion Identity = new Quaternion(0, 0, 0, 1);
00228
00229 #endregion
00230
00231 #region Add
00232
00239 public static Quaternion Add(Quaternion left, Quaternion right)
00240 {
00241 return new Quaternion(
00242 left.Xyz + right.Xyz,
00243 left.W + right.W);
00244 }
00245
00252 public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result)
00253 {
00254 result = new Quaternion(
00255 left.Xyz + right.Xyz,
00256 left.W + right.W);
00257 }
00258
00259 #endregion
00260
00261 #region Sub
00262
00269 public static Quaternion Sub(Quaternion left, Quaternion right)
00270 {
00271 return new Quaternion(
00272 left.Xyz - right.Xyz,
00273 left.W - right.W);
00274 }
00275
00282 public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result)
00283 {
00284 result = new Quaternion(
00285 left.Xyz - right.Xyz,
00286 left.W - right.W);
00287 }
00288
00289 #endregion
00290
00291 #region Mult
00292
00299 [Obsolete("Use Multiply instead.")]
00300 public static Quaternion Mult(Quaternion left, Quaternion right)
00301 {
00302 return new Quaternion(
00303 right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
00304 left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
00305 }
00306
00313 [Obsolete("Use Multiply instead.")]
00314 public static void Mult(ref Quaternion left, ref Quaternion right, out Quaternion result)
00315 {
00316 result = new Quaternion(
00317 right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
00318 left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
00319 }
00320
00327 public static Quaternion Multiply(Quaternion left, Quaternion right)
00328 {
00329 Quaternion result;
00330 Multiply(ref left, ref right, out result);
00331 return result;
00332 }
00333
00340 public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result)
00341 {
00342 result = new Quaternion(
00343 right.W * left.Xyz + left.W * right.Xyz + Vector3.Cross(left.Xyz, right.Xyz),
00344 left.W * right.W - Vector3.Dot(left.Xyz, right.Xyz));
00345 }
00346
00353 public static void Multiply(ref Quaternion quaternion, float scale, out Quaternion result)
00354 {
00355 result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
00356 }
00357
00364 public static Quaternion Multiply(Quaternion quaternion, float scale)
00365 {
00366 return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
00367 }
00368
00369 #endregion
00370
00371 #region Conjugate
00372
00378 public static Quaternion Conjugate(Quaternion q)
00379 {
00380 return new Quaternion(-q.Xyz, q.W);
00381 }
00382
00388 public static void Conjugate(ref Quaternion q, out Quaternion result)
00389 {
00390 result = new Quaternion(-q.Xyz, q.W);
00391 }
00392
00393 #endregion
00394
00395 #region Invert
00396
00402 public static Quaternion Invert(Quaternion q)
00403 {
00404 Quaternion result;
00405 Invert(ref q, out result);
00406 return result;
00407 }
00408
00414 public static void Invert(ref Quaternion q, out Quaternion result)
00415 {
00416 float lengthSq = q.LengthSquared;
00417 if (lengthSq != 0.0)
00418 {
00419 float i = 1.0f / lengthSq;
00420 result = new Quaternion(q.Xyz * -i, q.W * i);
00421 }
00422 else
00423 {
00424 result = q;
00425 }
00426 }
00427
00428 #endregion
00429
00430 #region Normalize
00431
00437 public static Quaternion Normalize(Quaternion q)
00438 {
00439 Quaternion result;
00440 Normalize(ref q, out result);
00441 return result;
00442 }
00443
00449 public static void Normalize(ref Quaternion q, out Quaternion result)
00450 {
00451 float scale = 1.0f / q.Length;
00452 result = new Quaternion(q.Xyz * scale, q.W * scale);
00453 }
00454
00455 #endregion
00456
00457 #region FromAxisAngle
00458
00465 public static Quaternion FromAxisAngle(Vector3 axis, float angle)
00466 {
00467 if (axis.LengthSquared == 0.0f)
00468 return Identity;
00469
00470 Quaternion result = Identity;
00471
00472 angle *= 0.5f;
00473 axis.Normalize();
00474 result.Xyz = axis * (float)System.Math.Sin(angle);
00475 result.W = (float)System.Math.Cos(angle);
00476
00477 return Normalize(result);
00478 }
00479
00480 #endregion
00481
00482 #region Slerp
00483
00491 public static Quaternion Slerp(Quaternion q1, Quaternion q2, float blend)
00492 {
00493
00494 if (q1.LengthSquared == 0.0f)
00495 {
00496 if (q2.LengthSquared == 0.0f)
00497 {
00498 return Identity;
00499 }
00500 return q2;
00501 }
00502 else if (q2.LengthSquared == 0.0f)
00503 {
00504 return q1;
00505 }
00506
00507
00508 float cosHalfAngle = q1.W * q2.W + Vector3.Dot(q1.Xyz, q2.Xyz);
00509
00510 if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f)
00511 {
00512
00513 return q1;
00514 }
00515 else if (cosHalfAngle < 0.0f)
00516 {
00517 q2.Xyz = -q2.Xyz;
00518 q2.W = -q2.W;
00519 cosHalfAngle = -cosHalfAngle;
00520 }
00521
00522 float blendA;
00523 float blendB;
00524 if (cosHalfAngle < 0.99f)
00525 {
00526
00527 float halfAngle = (float)System.Math.Acos(cosHalfAngle);
00528 float sinHalfAngle = (float)System.Math.Sin(halfAngle);
00529 float oneOverSinHalfAngle = 1.0f / sinHalfAngle;
00530 blendA = (float)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle;
00531 blendB = (float)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle;
00532 }
00533 else
00534 {
00535
00536 blendA = 1.0f - blend;
00537 blendB = blend;
00538 }
00539
00540 Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W);
00541 if (result.LengthSquared > 0.0f)
00542 return Normalize(result);
00543 else
00544 return Identity;
00545 }
00546
00547 #endregion
00548
00549 #endregion
00550
00551 #region Operators
00552
00559 public static Quaternion operator +(Quaternion left, Quaternion right)
00560 {
00561 left.Xyz += right.Xyz;
00562 left.W += right.W;
00563 return left;
00564 }
00565
00572 public static Quaternion operator -(Quaternion left, Quaternion right)
00573 {
00574 left.Xyz -= right.Xyz;
00575 left.W -= right.W;
00576 return left;
00577 }
00578
00585 public static Quaternion operator *(Quaternion left, Quaternion right)
00586 {
00587 Multiply(ref left, ref right, out left);
00588 return left;
00589 }
00590
00597 public static Quaternion operator *(Quaternion quaternion, float scale)
00598 {
00599 Multiply(ref quaternion, scale, out quaternion);
00600 return quaternion;
00601 }
00602
00609 public static Quaternion operator *(float scale, Quaternion quaternion)
00610 {
00611 return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
00612 }
00613
00620 public static bool operator ==(Quaternion left, Quaternion right)
00621 {
00622 return left.Equals(right);
00623 }
00624
00631 public static bool operator !=(Quaternion left, Quaternion right)
00632 {
00633 return !left.Equals(right);
00634 }
00635
00636 #endregion
00637
00638 #region Overrides
00639
00640 #region public override string ToString()
00641
00646 public override string ToString()
00647 {
00648 return String.Format("V: {0}, W: {1}", Xyz, W);
00649 }
00650
00651 #endregion
00652
00653 #region public override bool Equals (object o)
00654
00660 public override bool Equals(object other)
00661 {
00662 if (other is Quaternion == false) return false;
00663 return this == (Quaternion)other;
00664 }
00665
00666 #endregion
00667
00668 #region public override int GetHashCode ()
00669
00674 public override int GetHashCode()
00675 {
00676 return Xyz.GetHashCode() ^ W.GetHashCode();
00677 }
00678
00679 #endregion
00680
00681 #endregion
00682
00683 #endregion
00684
00685 #region IEquatable<Quaternion> Members
00686
00692 public bool Equals(Quaternion other)
00693 {
00694 return Xyz == other.Xyz && W == other.W;
00695 }
00696
00697 #endregion
00698 }
00699 }