| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- /* Copyright (C) <2009-2011> <Thorben Linneweber, Jitter Physics>
- *
- * This software is provided 'as-is', without any express or implied
- * warranty. In no event will the authors be held liable for any damages
- * arising from the use of this software.
- *
- * Permission is granted to anyone to use this software for any purpose,
- * including commercial applications, and to alter it and redistribute it
- * freely, subject to the following restrictions:
- *
- * 1. The origin of this software must not be misrepresented; you must not
- * claim that you wrote the original software. If you use this software
- * in a product, an acknowledgment in the product documentation would be
- * appreciated but is not required.
- * 2. Altered source versions must be plainly marked as such, and must not be
- * misrepresented as being the original software.
- * 3. This notice may not be removed or altered from any source distribution.
- */
- using System;
- namespace TrueSync
- {
- /// <summary>
- /// A Quaternion representing an orientation.
- /// </summary>
- [Serializable]
- public struct TSQuaternion
- {
- /// <summary>The X component of the quaternion.</summary>
- public FP x;
- /// <summary>The Y component of the quaternion.</summary>
- public FP y;
- /// <summary>The Z component of the quaternion.</summary>
- public FP z;
- /// <summary>The W component of the quaternion.</summary>
- public FP w;
- public static readonly TSQuaternion identity;
- static TSQuaternion() {
- identity = new TSQuaternion(0, 0, 0, 1);
- }
- /// <summary>
- /// Initializes a new instance of the JQuaternion structure.
- /// </summary>
- /// <param name="x">The X component of the quaternion.</param>
- /// <param name="y">The Y component of the quaternion.</param>
- /// <param name="z">The Z component of the quaternion.</param>
- /// <param name="w">The W component of the quaternion.</param>
- public TSQuaternion(FP x, FP y, FP z, FP w)
- {
- this.x = x;
- this.y = y;
- this.z = z;
- this.w = w;
- }
- public void Set(FP new_x, FP new_y, FP new_z, FP new_w) {
- this.x = new_x;
- this.y = new_y;
- this.z = new_z;
- this.w = new_w;
- }
- public void SetFromToRotation(TSVector fromDirection, TSVector toDirection) {
- TSQuaternion targetRotation = TSQuaternion.FromToRotation(fromDirection, toDirection);
- this.Set(targetRotation.x, targetRotation.y, targetRotation.z, targetRotation.w);
- }
- public TSVector eulerAngles {
- get {
- TSVector result = new TSVector();
- FP ysqr = y * y;
- FP t0 = -2.0f * (ysqr + z * z) + 1.0f;
- FP t1 = +2.0f * (x * y - w * z);
- FP t2 = -2.0f * (x * z + w * y);
- FP t3 = +2.0f * (y * z - w * x);
- FP t4 = -2.0f * (x * x + ysqr) + 1.0f;
- t2 = t2 > 1.0f ? 1.0f : t2;
- t2 = t2 < -1.0f ? -1.0f : t2;
- result.x = FP.Atan2(t3, t4) * FP.Rad2Deg;
- result.y = FP.Asin(t2) * FP.Rad2Deg;
- result.z = FP.Atan2(t1, t0) * FP.Rad2Deg;
- return result * -1;
- }
- }
- public static FP Angle(TSQuaternion a, TSQuaternion b) {
- TSQuaternion aInv = TSQuaternion.Inverse(a);
- TSQuaternion f = b * aInv;
- FP angle = FP.Acos(f.w) * 2 * FP.Rad2Deg;
- if (angle > 180) {
- angle = 360 - angle;
- }
- return angle;
- }
- /// <summary>
- /// Quaternions are added.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <returns>The sum of both quaternions.</returns>
- #region public static JQuaternion Add(JQuaternion quaternion1, JQuaternion quaternion2)
- public static TSQuaternion Add(TSQuaternion quaternion1, TSQuaternion quaternion2)
- {
- TSQuaternion result;
- TSQuaternion.Add(ref quaternion1, ref quaternion2, out result);
- return result;
- }
- public static TSQuaternion LookRotation(TSVector forward) {
- return CreateFromMatrix(TSMatrix.LookAt(forward, TSVector.up));
- }
- public static TSQuaternion LookRotation(TSVector forward, TSVector upwards) {
- return CreateFromMatrix(TSMatrix.LookAt(forward, upwards));
- }
- public static TSQuaternion Slerp(TSQuaternion from, TSQuaternion to, FP t) {
- t = TSMath.Clamp(t, 0, 1);
- FP dot = Dot(from, to);
- if (dot < 0.0f) {
- to = Multiply(to, -1);
- dot = -dot;
- }
- FP halfTheta = FP.Acos(dot);
- return Multiply(Multiply(from, FP.Sin((1 - t) * halfTheta)) + Multiply(to, FP.Sin(t * halfTheta)), 1 / FP.Sin(halfTheta));
- }
- public static TSQuaternion RotateTowards(TSQuaternion from, TSQuaternion to, FP maxDegreesDelta) {
- FP dot = Dot(from, to);
- if (dot < 0.0f) {
- to = Multiply(to, -1);
- dot = -dot;
- }
- FP halfTheta = FP.Acos(dot);
- FP theta = halfTheta * 2;
- maxDegreesDelta *= FP.Deg2Rad;
- if (maxDegreesDelta >= theta) {
- return to;
- }
- maxDegreesDelta /= theta;
- return Multiply(Multiply(from, FP.Sin((1 - maxDegreesDelta) * halfTheta)) + Multiply(to, FP.Sin(maxDegreesDelta * halfTheta)), 1 / FP.Sin(halfTheta));
- }
- public static TSQuaternion Euler(FP x, FP y, FP z) {
- x *= FP.Deg2Rad;
- y *= FP.Deg2Rad;
- z *= FP.Deg2Rad;
- TSQuaternion rotation;
- TSQuaternion.CreateFromYawPitchRoll(y, x, z, out rotation);
- return rotation;
- }
- public static TSQuaternion Euler(TSVector eulerAngles) {
- return Euler(eulerAngles.x, eulerAngles.y, eulerAngles.z);
- }
- public static TSQuaternion AngleAxis(FP angle, TSVector axis) {
- axis = axis * FP.Deg2Rad;
- axis.Normalize();
- FP halfAngle = angle * FP.Deg2Rad * FP.Half;
- TSQuaternion rotation;
- FP sin = FP.Sin(halfAngle);
- rotation.x = axis.x * sin;
- rotation.y = axis.y * sin;
- rotation.z = axis.z * sin;
- rotation.w = FP.Cos(halfAngle);
- return rotation;
- }
- public static void CreateFromYawPitchRoll(FP yaw, FP pitch, FP roll, out TSQuaternion result)
- {
- FP num9 = roll * FP.Half;
- FP num6 = FP.Sin(num9);
- FP num5 = FP.Cos(num9);
- FP num8 = pitch * FP.Half;
- FP num4 = FP.Sin(num8);
- FP num3 = FP.Cos(num8);
- FP num7 = yaw * FP.Half;
- FP num2 = FP.Sin(num7);
- FP num = FP.Cos(num7);
- result.x = ((num * num4) * num5) + ((num2 * num3) * num6);
- result.y = ((num2 * num3) * num5) - ((num * num4) * num6);
- result.z = ((num * num3) * num6) - ((num2 * num4) * num5);
- result.w = ((num * num3) * num5) + ((num2 * num4) * num6);
- }
- /// <summary>
- /// Quaternions are added.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <param name="result">The sum of both quaternions.</param>
- public static void Add(ref TSQuaternion quaternion1, ref TSQuaternion quaternion2, out TSQuaternion result)
- {
- result.x = quaternion1.x + quaternion2.x;
- result.y = quaternion1.y + quaternion2.y;
- result.z = quaternion1.z + quaternion2.z;
- result.w = quaternion1.w + quaternion2.w;
- }
- #endregion
- public static TSQuaternion Conjugate(TSQuaternion value)
- {
- TSQuaternion quaternion;
- quaternion.x = -value.x;
- quaternion.y = -value.y;
- quaternion.z = -value.z;
- quaternion.w = value.w;
- return quaternion;
- }
- public static FP Dot(TSQuaternion a, TSQuaternion b) {
- return a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
- }
- public static TSQuaternion Inverse(TSQuaternion rotation) {
- FP invNorm = FP.One / ((rotation.x * rotation.x) + (rotation.y * rotation.y) + (rotation.z * rotation.z) + (rotation.w * rotation.w));
- return TSQuaternion.Multiply(TSQuaternion.Conjugate(rotation), invNorm);
- }
- public static TSQuaternion FromToRotation(TSVector fromVector, TSVector toVector) {
- TSVector w = TSVector.Cross(fromVector, toVector);
- TSQuaternion q = new TSQuaternion(w.x, w.y, w.z, TSVector.Dot(fromVector, toVector));
- q.w += FP.Sqrt(fromVector.sqrMagnitude * toVector.sqrMagnitude);
- q.Normalize();
- return q;
- }
- public static TSQuaternion Lerp(TSQuaternion a, TSQuaternion b, FP t) {
- t = TSMath.Clamp(t, FP.Zero, FP.One);
- return LerpUnclamped(a, b, t);
- }
- public static TSQuaternion LerpUnclamped(TSQuaternion a, TSQuaternion b, FP t) {
- TSQuaternion result = TSQuaternion.Multiply(a, (1 - t)) + TSQuaternion.Multiply(b, t);
- result.Normalize();
- return result;
- }
- /// <summary>
- /// Quaternions are subtracted.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <returns>The difference of both quaternions.</returns>
- #region public static JQuaternion Subtract(JQuaternion quaternion1, JQuaternion quaternion2)
- public static TSQuaternion Subtract(TSQuaternion quaternion1, TSQuaternion quaternion2)
- {
- TSQuaternion result;
- TSQuaternion.Subtract(ref quaternion1, ref quaternion2, out result);
- return result;
- }
- /// <summary>
- /// Quaternions are subtracted.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <param name="result">The difference of both quaternions.</param>
- public static void Subtract(ref TSQuaternion quaternion1, ref TSQuaternion quaternion2, out TSQuaternion result)
- {
- result.x = quaternion1.x - quaternion2.x;
- result.y = quaternion1.y - quaternion2.y;
- result.z = quaternion1.z - quaternion2.z;
- result.w = quaternion1.w - quaternion2.w;
- }
- #endregion
- /// <summary>
- /// Multiply two quaternions.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <returns>The product of both quaternions.</returns>
- #region public static JQuaternion Multiply(JQuaternion quaternion1, JQuaternion quaternion2)
- public static TSQuaternion Multiply(TSQuaternion quaternion1, TSQuaternion quaternion2)
- {
- TSQuaternion result;
- TSQuaternion.Multiply(ref quaternion1, ref quaternion2, out result);
- return result;
- }
- /// <summary>
- /// Multiply two quaternions.
- /// </summary>
- /// <param name="quaternion1">The first quaternion.</param>
- /// <param name="quaternion2">The second quaternion.</param>
- /// <param name="result">The product of both quaternions.</param>
- public static void Multiply(ref TSQuaternion quaternion1, ref TSQuaternion quaternion2, out TSQuaternion result)
- {
- FP x = quaternion1.x;
- FP y = quaternion1.y;
- FP z = quaternion1.z;
- FP w = quaternion1.w;
- FP num4 = quaternion2.x;
- FP num3 = quaternion2.y;
- FP num2 = quaternion2.z;
- FP num = quaternion2.w;
- FP num12 = (y * num2) - (z * num3);
- FP num11 = (z * num4) - (x * num2);
- FP num10 = (x * num3) - (y * num4);
- FP num9 = ((x * num4) + (y * num3)) + (z * num2);
- result.x = ((x * num) + (num4 * w)) + num12;
- result.y = ((y * num) + (num3 * w)) + num11;
- result.z = ((z * num) + (num2 * w)) + num10;
- result.w = (w * num) - num9;
- }
- #endregion
- /// <summary>
- /// Scale a quaternion
- /// </summary>
- /// <param name="quaternion1">The quaternion to scale.</param>
- /// <param name="scaleFactor">Scale factor.</param>
- /// <returns>The scaled quaternion.</returns>
- #region public static JQuaternion Multiply(JQuaternion quaternion1, FP scaleFactor)
- public static TSQuaternion Multiply(TSQuaternion quaternion1, FP scaleFactor)
- {
- TSQuaternion result;
- TSQuaternion.Multiply(ref quaternion1, scaleFactor, out result);
- return result;
- }
- /// <summary>
- /// Scale a quaternion
- /// </summary>
- /// <param name="quaternion1">The quaternion to scale.</param>
- /// <param name="scaleFactor">Scale factor.</param>
- /// <param name="result">The scaled quaternion.</param>
- public static void Multiply(ref TSQuaternion quaternion1, FP scaleFactor, out TSQuaternion result)
- {
- result.x = quaternion1.x * scaleFactor;
- result.y = quaternion1.y * scaleFactor;
- result.z = quaternion1.z * scaleFactor;
- result.w = quaternion1.w * scaleFactor;
- }
- #endregion
- /// <summary>
- /// Sets the length of the quaternion to one.
- /// </summary>
- #region public void Normalize()
- public void Normalize()
- {
- FP num2 = (((this.x * this.x) + (this.y * this.y)) + (this.z * this.z)) + (this.w * this.w);
- FP num = 1 / (FP.Sqrt(num2));
- this.x *= num;
- this.y *= num;
- this.z *= num;
- this.w *= num;
- }
- #endregion
- /// <summary>
- /// Creates a quaternion from a matrix.
- /// </summary>
- /// <param name="matrix">A matrix representing an orientation.</param>
- /// <returns>JQuaternion representing an orientation.</returns>
- #region public static JQuaternion CreateFromMatrix(JMatrix matrix)
- public static TSQuaternion CreateFromMatrix(TSMatrix matrix)
- {
- TSQuaternion result;
- TSQuaternion.CreateFromMatrix(ref matrix, out result);
- return result;
- }
- /// <summary>
- /// Creates a quaternion from a matrix.
- /// </summary>
- /// <param name="matrix">A matrix representing an orientation.</param>
- /// <param name="result">JQuaternion representing an orientation.</param>
- public static void CreateFromMatrix(ref TSMatrix matrix, out TSQuaternion result)
- {
- FP num8 = (matrix.M11 + matrix.M22) + matrix.M33;
- if (num8 > FP.Zero)
- {
- FP num = FP.Sqrt((num8 + FP.One));
- result.w = num * FP.Half;
- num = FP.Half / num;
- result.x = (matrix.M23 - matrix.M32) * num;
- result.y = (matrix.M31 - matrix.M13) * num;
- result.z = (matrix.M12 - matrix.M21) * num;
- }
- else if ((matrix.M11 >= matrix.M22) && (matrix.M11 >= matrix.M33))
- {
- FP num7 = FP.Sqrt((((FP.One + matrix.M11) - matrix.M22) - matrix.M33));
- FP num4 = FP.Half / num7;
- result.x = FP.Half * num7;
- result.y = (matrix.M12 + matrix.M21) * num4;
- result.z = (matrix.M13 + matrix.M31) * num4;
- result.w = (matrix.M23 - matrix.M32) * num4;
- }
- else if (matrix.M22 > matrix.M33)
- {
- FP num6 = FP.Sqrt((((FP.One + matrix.M22) - matrix.M11) - matrix.M33));
- FP num3 = FP.Half / num6;
- result.x = (matrix.M21 + matrix.M12) * num3;
- result.y = FP.Half * num6;
- result.z = (matrix.M32 + matrix.M23) * num3;
- result.w = (matrix.M31 - matrix.M13) * num3;
- }
- else
- {
- FP num5 = FP.Sqrt((((FP.One + matrix.M33) - matrix.M11) - matrix.M22));
- FP num2 = FP.Half / num5;
- result.x = (matrix.M31 + matrix.M13) * num2;
- result.y = (matrix.M32 + matrix.M23) * num2;
- result.z = FP.Half * num5;
- result.w = (matrix.M12 - matrix.M21) * num2;
- }
- }
- #endregion
- /// <summary>
- /// Multiply two quaternions.
- /// </summary>
- /// <param name="value1">The first quaternion.</param>
- /// <param name="value2">The second quaternion.</param>
- /// <returns>The product of both quaternions.</returns>
- #region public static FP operator *(JQuaternion value1, JQuaternion value2)
- public static TSQuaternion operator *(TSQuaternion value1, TSQuaternion value2)
- {
- TSQuaternion result;
- TSQuaternion.Multiply(ref value1, ref value2,out result);
- return result;
- }
- #endregion
- /// <summary>
- /// Add two quaternions.
- /// </summary>
- /// <param name="value1">The first quaternion.</param>
- /// <param name="value2">The second quaternion.</param>
- /// <returns>The sum of both quaternions.</returns>
- #region public static FP operator +(JQuaternion value1, JQuaternion value2)
- public static TSQuaternion operator +(TSQuaternion value1, TSQuaternion value2)
- {
- TSQuaternion result;
- TSQuaternion.Add(ref value1, ref value2, out result);
- return result;
- }
- #endregion
- /// <summary>
- /// Subtract two quaternions.
- /// </summary>
- /// <param name="value1">The first quaternion.</param>
- /// <param name="value2">The second quaternion.</param>
- /// <returns>The difference of both quaternions.</returns>
- #region public static FP operator -(JQuaternion value1, JQuaternion value2)
- public static TSQuaternion operator -(TSQuaternion value1, TSQuaternion value2)
- {
- TSQuaternion result;
- TSQuaternion.Subtract(ref value1, ref value2, out result);
- return result;
- }
- #endregion
- /**
- * @brief Rotates a {@link TSVector} by the {@link TSQuanternion}.
- **/
- public static TSVector operator *(TSQuaternion quat, TSVector vec) {
- FP num = quat.x * 2f;
- FP num2 = quat.y * 2f;
- FP num3 = quat.z * 2f;
- FP num4 = quat.x * num;
- FP num5 = quat.y * num2;
- FP num6 = quat.z * num3;
- FP num7 = quat.x * num2;
- FP num8 = quat.x * num3;
- FP num9 = quat.y * num3;
- FP num10 = quat.w * num;
- FP num11 = quat.w * num2;
- FP num12 = quat.w * num3;
- TSVector result;
- result.x = (1f - (num5 + num6)) * vec.x + (num7 - num12) * vec.y + (num8 + num11) * vec.z;
- result.y = (num7 + num12) * vec.x + (1f - (num4 + num6)) * vec.y + (num9 - num10) * vec.z;
- result.z = (num8 - num11) * vec.x + (num9 + num10) * vec.y + (1f - (num4 + num5)) * vec.z;
- return result;
- }
- public override string ToString() {
- return string.Format("({0:f1}, {1:f1}, {2:f1}, {3:f1})", x.AsFloat(), y.AsFloat(), z.AsFloat(), w.AsFloat());
- }
- }
- }
|