Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1452 | chris | 1 | #region --- License --- |
| 2 | /* |
||
| 3 | Copyright (c) 2006 - 2008 The Open Toolkit library. |
||
| 4 | |||
| 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of |
||
| 6 | this software and associated documentation files (the "Software"), to deal in |
||
| 7 | the Software without restriction, including without limitation the rights to |
||
| 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
||
| 9 | of the Software, and to permit persons to whom the Software is furnished to do |
||
| 10 | so, subject to the following conditions: |
||
| 11 | |||
| 12 | The above copyright notice and this permission notice shall be included in all |
||
| 13 | copies or substantial portions of the Software. |
||
| 14 | |||
| 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||
| 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||
| 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||
| 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||
| 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||
| 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||
| 21 | SOFTWARE. |
||
| 22 | */ |
||
| 23 | #endregion |
||
| 24 | |||
| 25 | using System; |
||
| 26 | using System.Runtime.InteropServices; |
||
| 27 | using System.ComponentModel; |
||
| 28 | using System.Xml.Serialization; |
||
| 29 | |||
| 30 | namespace OpenTK |
||
| 31 | { |
||
| 32 | /// <summary> |
||
| 33 | /// Represents a double-precision Quaternion. |
||
| 34 | /// </summary> |
||
| 35 | [Serializable] |
||
| 36 | [StructLayout(LayoutKind.Sequential)] |
||
| 37 | public struct Quaterniond : IEquatable<Quaterniond> |
||
| 38 | { |
||
| 39 | #region Fields |
||
| 40 | |||
| 41 | Vector3d xyz; |
||
| 42 | double w; |
||
| 43 | |||
| 44 | #endregion |
||
| 45 | |||
| 46 | #region Constructors |
||
| 47 | |||
| 48 | /// <summary> |
||
| 49 | /// Construct a new Quaterniond from vector and w components |
||
| 50 | /// </summary> |
||
| 51 | /// <param name="v">The vector part</param> |
||
| 52 | /// <param name="w">The w part</param> |
||
| 53 | public Quaterniond(Vector3d v, double w) |
||
| 54 | { |
||
| 55 | this.xyz = v; |
||
| 56 | this.w = w; |
||
| 57 | } |
||
| 58 | |||
| 59 | /// <summary> |
||
| 60 | /// Construct a new Quaterniond |
||
| 61 | /// </summary> |
||
| 62 | /// <param name="x">The x component</param> |
||
| 63 | /// <param name="y">The y component</param> |
||
| 64 | /// <param name="z">The z component</param> |
||
| 65 | /// <param name="w">The w component</param> |
||
| 66 | public Quaterniond(double x, double y, double z, double w) |
||
| 67 | : this(new Vector3d(x, y, z), w) |
||
| 68 | { } |
||
| 69 | |||
| 70 | #endregion |
||
| 71 | |||
| 72 | #region Public Members |
||
| 73 | |||
| 74 | #region Properties |
||
| 75 | |||
| 76 | /// <summary> |
||
| 77 | /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance. |
||
| 78 | /// </summary> |
||
| 79 | [Obsolete("Use Xyz property instead.")] |
||
| 80 | [CLSCompliant(false)] |
||
| 81 | [EditorBrowsable(EditorBrowsableState.Never)] |
||
| 82 | [XmlIgnore] |
||
| 83 | public Vector3d XYZ { get { return Xyz; } set { Xyz = value; } } |
||
| 84 | |||
| 85 | /// <summary> |
||
| 86 | /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance. |
||
| 87 | /// </summary> |
||
| 88 | public Vector3d Xyz { get { return xyz; } set { xyz = value; } } |
||
| 89 | |||
| 90 | /// <summary> |
||
| 91 | /// Gets or sets the X component of this instance. |
||
| 92 | /// </summary> |
||
| 93 | [XmlIgnore] |
||
| 94 | public double X { get { return xyz.X; } set { xyz.X = value; } } |
||
| 95 | |||
| 96 | /// <summary> |
||
| 97 | /// Gets or sets the Y component of this instance. |
||
| 98 | /// </summary> |
||
| 99 | [XmlIgnore] |
||
| 100 | public double Y { get { return xyz.Y; } set { xyz.Y = value; } } |
||
| 101 | |||
| 102 | /// <summary> |
||
| 103 | /// Gets or sets the Z component of this instance. |
||
| 104 | /// </summary> |
||
| 105 | [XmlIgnore] |
||
| 106 | public double Z { get { return xyz.Z; } set { xyz.Z = value; } } |
||
| 107 | |||
| 108 | /// <summary> |
||
| 109 | /// Gets or sets the W component of this instance. |
||
| 110 | /// </summary> |
||
| 111 | public double W { get { return w; } set { w = value; } } |
||
| 112 | |||
| 113 | #endregion |
||
| 114 | |||
| 115 | #region Instance |
||
| 116 | |||
| 117 | #region ToAxisAngle |
||
| 118 | |||
| 119 | /// <summary> |
||
| 120 | /// Convert the current quaternion to axis angle representation |
||
| 121 | /// </summary> |
||
| 122 | /// <param name="axis">The resultant axis</param> |
||
| 123 | /// <param name="angle">The resultant angle</param> |
||
| 124 | public void ToAxisAngle(out Vector3d axis, out double angle) |
||
| 125 | { |
||
| 126 | Vector4d result = ToAxisAngle(); |
||
| 127 | axis = result.Xyz; |
||
| 128 | angle = result.W; |
||
| 129 | } |
||
| 130 | |||
| 131 | /// <summary> |
||
| 132 | /// Convert this instance to an axis-angle representation. |
||
| 133 | /// </summary> |
||
| 134 | /// <returns>A Vector4 that is the axis-angle representation of this quaternion.</returns> |
||
| 135 | public Vector4d ToAxisAngle() |
||
| 136 | { |
||
| 137 | Quaterniond q = this; |
||
| 138 | if (q.W > 1.0f) |
||
| 139 | q.Normalize(); |
||
| 140 | |||
| 141 | Vector4d result = new Vector4d(); |
||
| 142 | |||
| 143 | result.W = 2.0f * (float)System.Math.Acos(q.W); // angle |
||
| 144 | float den = (float)System.Math.Sqrt(1.0 - q.W * q.W); |
||
| 145 | if (den > 0.0001f) |
||
| 146 | { |
||
| 147 | result.Xyz = q.Xyz / den; |
||
| 148 | } |
||
| 149 | else |
||
| 150 | { |
||
| 151 | // This occurs when the angle is zero. |
||
| 152 | // Not a problem: just set an arbitrary normalized axis. |
||
| 153 | result.Xyz = Vector3d.UnitX; |
||
| 154 | } |
||
| 155 | |||
| 156 | return result; |
||
| 157 | } |
||
| 158 | |||
| 159 | #endregion |
||
| 160 | |||
| 161 | #region public double Length |
||
| 162 | |||
| 163 | /// <summary> |
||
| 164 | /// Gets the length (magnitude) of the Quaterniond. |
||
| 165 | /// </summary> |
||
| 166 | /// <seealso cref="LengthSquared"/> |
||
| 167 | public double Length |
||
| 168 | { |
||
| 169 | get |
||
| 170 | { |
||
| 171 | return (double)System.Math.Sqrt(W * W + Xyz.LengthSquared); |
||
| 172 | } |
||
| 173 | } |
||
| 174 | |||
| 175 | #endregion |
||
| 176 | |||
| 177 | #region public double LengthSquared |
||
| 178 | |||
| 179 | /// <summary> |
||
| 180 | /// Gets the square of the Quaterniond length (magnitude). |
||
| 181 | /// </summary> |
||
| 182 | public double LengthSquared |
||
| 183 | { |
||
| 184 | get |
||
| 185 | { |
||
| 186 | return W * W + Xyz.LengthSquared; |
||
| 187 | } |
||
| 188 | } |
||
| 189 | |||
| 190 | #endregion |
||
| 191 | |||
| 192 | #region public void Normalize() |
||
| 193 | |||
| 194 | /// <summary> |
||
| 195 | /// Scales the Quaterniond to unit length. |
||
| 196 | /// </summary> |
||
| 197 | public void Normalize() |
||
| 198 | { |
||
| 199 | double scale = 1.0f / this.Length; |
||
| 200 | Xyz *= scale; |
||
| 201 | W *= scale; |
||
| 202 | } |
||
| 203 | |||
| 204 | #endregion |
||
| 205 | |||
| 206 | #region public void Conjugate() |
||
| 207 | |||
| 208 | /// <summary> |
||
| 209 | /// Convert this Quaterniond to its conjugate |
||
| 210 | /// </summary> |
||
| 211 | public void Conjugate() |
||
| 212 | { |
||
| 213 | Xyz = -Xyz; |
||
| 214 | } |
||
| 215 | |||
| 216 | #endregion |
||
| 217 | |||
| 218 | #endregion |
||
| 219 | |||
| 220 | #region Static |
||
| 221 | |||
| 222 | #region Fields |
||
| 223 | |||
| 224 | /// <summary> |
||
| 225 | /// Defines the identity quaternion. |
||
| 226 | /// </summary> |
||
| 227 | public readonly static Quaterniond Identity = new Quaterniond(0, 0, 0, 1); |
||
| 228 | |||
| 229 | #endregion |
||
| 230 | |||
| 231 | #region Add |
||
| 232 | |||
| 233 | /// <summary> |
||
| 234 | /// Add two quaternions |
||
| 235 | /// </summary> |
||
| 236 | /// <param name="left">The first operand</param> |
||
| 237 | /// <param name="right">The second operand</param> |
||
| 238 | /// <returns>The result of the addition</returns> |
||
| 239 | public static Quaterniond Add(Quaterniond left, Quaterniond right) |
||
| 240 | { |
||
| 241 | return new Quaterniond( |
||
| 242 | left.Xyz + right.Xyz, |
||
| 243 | left.W + right.W); |
||
| 244 | } |
||
| 245 | |||
| 246 | /// <summary> |
||
| 247 | /// Add two quaternions |
||
| 248 | /// </summary> |
||
| 249 | /// <param name="left">The first operand</param> |
||
| 250 | /// <param name="right">The second operand</param> |
||
| 251 | /// <param name="result">The result of the addition</param> |
||
| 252 | public static void Add(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 253 | { |
||
| 254 | result = new Quaterniond( |
||
| 255 | left.Xyz + right.Xyz, |
||
| 256 | left.W + right.W); |
||
| 257 | } |
||
| 258 | |||
| 259 | #endregion |
||
| 260 | |||
| 261 | #region Sub |
||
| 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 Quaterniond Sub(Quaterniond left, Quaterniond right) |
||
| 270 | { |
||
| 271 | return new Quaterniond( |
||
| 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 Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 283 | { |
||
| 284 | result = new Quaterniond( |
||
| 285 | left.Xyz - right.Xyz, |
||
| 286 | left.W - right.W); |
||
| 287 | } |
||
| 288 | |||
| 289 | #endregion |
||
| 290 | |||
| 291 | #region Mult |
||
| 292 | |||
| 293 | /// <summary> |
||
| 294 | /// Multiplies two instances. |
||
| 295 | /// </summary> |
||
| 296 | /// <param name="left">The first instance.</param> |
||
| 297 | /// <param name="right">The second instance.</param> |
||
| 298 | /// <returns>A new instance containing the result of the calculation.</returns> |
||
| 299 | [Obsolete("Use Multiply instead.")] |
||
| 300 | public static Quaterniond Mult(Quaterniond left, Quaterniond right) |
||
| 301 | { |
||
| 302 | return new Quaterniond( |
||
| 303 | right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), |
||
| 304 | left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); |
||
| 305 | } |
||
| 306 | |||
| 307 | /// <summary> |
||
| 308 | /// Multiplies two instances. |
||
| 309 | /// </summary> |
||
| 310 | /// <param name="left">The first instance.</param> |
||
| 311 | /// <param name="right">The second instance.</param> |
||
| 312 | /// <param name="result">A new instance containing the result of the calculation.</param> |
||
| 313 | [Obsolete("Use Multiply instead.")] |
||
| 314 | public static void Mult(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 315 | { |
||
| 316 | result = new Quaterniond( |
||
| 317 | right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), |
||
| 318 | left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); |
||
| 319 | } |
||
| 320 | |||
| 321 | /// <summary> |
||
| 322 | /// Multiplies two instances. |
||
| 323 | /// </summary> |
||
| 324 | /// <param name="left">The first instance.</param> |
||
| 325 | /// <param name="right">The second instance.</param> |
||
| 326 | /// <returns>A new instance containing the result of the calculation.</returns> |
||
| 327 | public static Quaterniond Multiply(Quaterniond left, Quaterniond right) |
||
| 328 | { |
||
| 329 | Quaterniond result; |
||
| 330 | Multiply(ref left, ref right, out result); |
||
| 331 | return result; |
||
| 332 | } |
||
| 333 | |||
| 334 | /// <summary> |
||
| 335 | /// Multiplies two instances. |
||
| 336 | /// </summary> |
||
| 337 | /// <param name="left">The first instance.</param> |
||
| 338 | /// <param name="right">The second instance.</param> |
||
| 339 | /// <param name="result">A new instance containing the result of the calculation.</param> |
||
| 340 | public static void Multiply(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 341 | { |
||
| 342 | result = new Quaterniond( |
||
| 343 | right.W * left.Xyz + left.W * right.Xyz + Vector3d.Cross(left.Xyz, right.Xyz), |
||
| 344 | left.W * right.W - Vector3d.Dot(left.Xyz, right.Xyz)); |
||
| 345 | } |
||
| 346 | |||
| 347 | /// <summary> |
||
| 348 | /// Multiplies an instance by a scalar. |
||
| 349 | /// </summary> |
||
| 350 | /// <param name="quaternion">The instance.</param> |
||
| 351 | /// <param name="scale">The scalar.</param> |
||
| 352 | /// <param name="result">A new instance containing the result of the calculation.</param> |
||
| 353 | public static void Multiply(ref Quaterniond quaternion, double scale, out Quaterniond result) |
||
| 354 | { |
||
| 355 | result = new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); |
||
| 356 | } |
||
| 357 | |||
| 358 | /// <summary> |
||
| 359 | /// Multiplies an instance by a scalar. |
||
| 360 | /// </summary> |
||
| 361 | /// <param name="quaternion">The instance.</param> |
||
| 362 | /// <param name="scale">The scalar.</param> |
||
| 363 | /// <returns>A new instance containing the result of the calculation.</returns> |
||
| 364 | public static Quaterniond Multiply(Quaterniond quaternion, double scale) |
||
| 365 | { |
||
| 366 | return new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); |
||
| 367 | } |
||
| 368 | |||
| 369 | #endregion |
||
| 370 | |||
| 371 | #region Conjugate |
||
| 372 | |||
| 373 | /// <summary> |
||
| 374 | /// Get the conjugate of the given Quaterniond |
||
| 375 | /// </summary> |
||
| 376 | /// <param name="q">The Quaterniond</param> |
||
| 377 | /// <returns>The conjugate of the given Quaterniond</returns> |
||
| 378 | public static Quaterniond Conjugate(Quaterniond q) |
||
| 379 | { |
||
| 380 | return new Quaterniond(-q.Xyz, q.W); |
||
| 381 | } |
||
| 382 | |||
| 383 | /// <summary> |
||
| 384 | /// Get the conjugate of the given Quaterniond |
||
| 385 | /// </summary> |
||
| 386 | /// <param name="q">The Quaterniond</param> |
||
| 387 | /// <param name="result">The conjugate of the given Quaterniond</param> |
||
| 388 | public static void Conjugate(ref Quaterniond q, out Quaterniond result) |
||
| 389 | { |
||
| 390 | result = new Quaterniond(-q.Xyz, q.W); |
||
| 391 | } |
||
| 392 | |||
| 393 | #endregion |
||
| 394 | |||
| 395 | #region Invert |
||
| 396 | |||
| 397 | /// <summary> |
||
| 398 | /// Get the inverse of the given Quaterniond |
||
| 399 | /// </summary> |
||
| 400 | /// <param name="q">The Quaterniond to invert</param> |
||
| 401 | /// <returns>The inverse of the given Quaterniond</returns> |
||
| 402 | public static Quaterniond Invert(Quaterniond q) |
||
| 403 | { |
||
| 404 | Quaterniond result; |
||
| 405 | Invert(ref q, out result); |
||
| 406 | return result; |
||
| 407 | } |
||
| 408 | |||
| 409 | /// <summary> |
||
| 410 | /// Get the inverse of the given Quaterniond |
||
| 411 | /// </summary> |
||
| 412 | /// <param name="q">The Quaterniond to invert</param> |
||
| 413 | /// <param name="result">The inverse of the given Quaterniond</param> |
||
| 414 | public static void Invert(ref Quaterniond q, out Quaterniond result) |
||
| 415 | { |
||
| 416 | double lengthSq = q.LengthSquared; |
||
| 417 | if (lengthSq != 0.0) |
||
| 418 | { |
||
| 419 | double i = 1.0f / lengthSq; |
||
| 420 | result = new Quaterniond(q.Xyz * -i, q.W * i); |
||
| 421 | } |
||
| 422 | else |
||
| 423 | { |
||
| 424 | result = q; |
||
| 425 | } |
||
| 426 | } |
||
| 427 | |||
| 428 | #endregion |
||
| 429 | |||
| 430 | #region Normalize |
||
| 431 | |||
| 432 | /// <summary> |
||
| 433 | /// Scale the given Quaterniond to unit length |
||
| 434 | /// </summary> |
||
| 435 | /// <param name="q">The Quaterniond to normalize</param> |
||
| 436 | /// <returns>The normalized Quaterniond</returns> |
||
| 437 | public static Quaterniond Normalize(Quaterniond q) |
||
| 438 | { |
||
| 439 | Quaterniond result; |
||
| 440 | Normalize(ref q, out result); |
||
| 441 | return result; |
||
| 442 | } |
||
| 443 | |||
| 444 | /// <summary> |
||
| 445 | /// Scale the given Quaterniond to unit length |
||
| 446 | /// </summary> |
||
| 447 | /// <param name="q">The Quaterniond to normalize</param> |
||
| 448 | /// <param name="result">The normalized Quaterniond</param> |
||
| 449 | public static void Normalize(ref Quaterniond q, out Quaterniond result) |
||
| 450 | { |
||
| 451 | double scale = 1.0f / q.Length; |
||
| 452 | result = new Quaterniond(q.Xyz * scale, q.W * scale); |
||
| 453 | } |
||
| 454 | |||
| 455 | #endregion |
||
| 456 | |||
| 457 | #region FromAxisAngle |
||
| 458 | |||
| 459 | /// <summary> |
||
| 460 | /// Build a Quaterniond from the given axis and angle |
||
| 461 | /// </summary> |
||
| 462 | /// <param name="axis">The axis to rotate about</param> |
||
| 463 | /// <param name="angle">The rotation angle in radians</param> |
||
| 464 | /// <returns></returns> |
||
| 465 | public static Quaterniond FromAxisAngle(Vector3d axis, double angle) |
||
| 466 | { |
||
| 467 | if (axis.LengthSquared == 0.0f) |
||
| 468 | return Identity; |
||
| 469 | |||
| 470 | Quaterniond result = Identity; |
||
| 471 | |||
| 472 | angle *= 0.5f; |
||
| 473 | axis.Normalize(); |
||
| 474 | result.Xyz = axis * (double)System.Math.Sin(angle); |
||
| 475 | result.W = (double)System.Math.Cos(angle); |
||
| 476 | |||
| 477 | return Normalize(result); |
||
| 478 | } |
||
| 479 | |||
| 480 | #endregion |
||
| 481 | |||
| 482 | #region Slerp |
||
| 483 | |||
| 484 | /// <summary> |
||
| 485 | /// Do Spherical linear interpolation between two quaternions |
||
| 486 | /// </summary> |
||
| 487 | /// <param name="q1">The first Quaterniond</param> |
||
| 488 | /// <param name="q2">The second Quaterniond</param> |
||
| 489 | /// <param name="blend">The blend factor</param> |
||
| 490 | /// <returns>A smooth blend between the given quaternions</returns> |
||
| 491 | public static Quaterniond Slerp(Quaterniond q1, Quaterniond q2, double blend) |
||
| 492 | { |
||
| 493 | // if either input is zero, return the other. |
||
| 494 | if (q1.LengthSquared == 0.0f) |
||
| 495 | { |
||
| 496 | if (q2.LengthSquared == 0.0f) |
||
| 497 | { |
||
| 498 | return Identity; |
||
| 499 | } |
||
| 500 | return q2; |
||
| 501 | } |
||
| 502 | else if (q2.LengthSquared == 0.0f) |
||
| 503 | { |
||
| 504 | return q1; |
||
| 505 | } |
||
| 506 | |||
| 507 | |||
| 508 | double cosHalfAngle = q1.W * q2.W + Vector3d.Dot(q1.Xyz, q2.Xyz); |
||
| 509 | |||
| 510 | if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) |
||
| 511 | { |
||
| 512 | // angle = 0.0f, so just return one input. |
||
| 513 | return q1; |
||
| 514 | } |
||
| 515 | else if (cosHalfAngle < 0.0f) |
||
| 516 | { |
||
| 517 | q2.Xyz = -q2.Xyz; |
||
| 518 | q2.W = -q2.W; |
||
| 519 | cosHalfAngle = -cosHalfAngle; |
||
| 520 | } |
||
| 521 | |||
| 522 | double blendA; |
||
| 523 | double blendB; |
||
| 524 | if (cosHalfAngle < 0.99f) |
||
| 525 | { |
||
| 526 | // do proper slerp for big angles |
||
| 527 | double halfAngle = (double)System.Math.Acos(cosHalfAngle); |
||
| 528 | double sinHalfAngle = (double)System.Math.Sin(halfAngle); |
||
| 529 | double oneOverSinHalfAngle = 1.0f / sinHalfAngle; |
||
| 530 | blendA = (double)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle; |
||
| 531 | blendB = (double)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle; |
||
| 532 | } |
||
| 533 | else |
||
| 534 | { |
||
| 535 | // do lerp if angle is really small. |
||
| 536 | blendA = 1.0f - blend; |
||
| 537 | blendB = blend; |
||
| 538 | } |
||
| 539 | |||
| 540 | Quaterniond result = new Quaterniond(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W); |
||
| 541 | if (result.LengthSquared > 0.0f) |
||
| 542 | return Normalize(result); |
||
| 543 | else |
||
| 544 | return Identity; |
||
| 545 | } |
||
| 546 | |||
| 547 | #endregion |
||
| 548 | |||
| 549 | #endregion |
||
| 550 | |||
| 551 | #region Operators |
||
| 552 | |||
| 553 | /// <summary> |
||
| 554 | /// Adds two instances. |
||
| 555 | /// </summary> |
||
| 556 | /// <param name="left">The first instance.</param> |
||
| 557 | /// <param name="right">The second instance.</param> |
||
| 558 | /// <returns>The result of the calculation.</returns> |
||
| 559 | public static Quaterniond operator +(Quaterniond left, Quaterniond right) |
||
| 560 | { |
||
| 561 | left.Xyz += right.Xyz; |
||
| 562 | left.W += right.W; |
||
| 563 | return left; |
||
| 564 | } |
||
| 565 | |||
| 566 | /// <summary> |
||
| 567 | /// Subtracts two instances. |
||
| 568 | /// </summary> |
||
| 569 | /// <param name="left">The first instance.</param> |
||
| 570 | /// <param name="right">The second instance.</param> |
||
| 571 | /// <returns>The result of the calculation.</returns> |
||
| 572 | public static Quaterniond operator -(Quaterniond left, Quaterniond right) |
||
| 573 | { |
||
| 574 | left.Xyz -= right.Xyz; |
||
| 575 | left.W -= right.W; |
||
| 576 | return left; |
||
| 577 | } |
||
| 578 | |||
| 579 | /// <summary> |
||
| 580 | /// Multiplies two instances. |
||
| 581 | /// </summary> |
||
| 582 | /// <param name="left">The first instance.</param> |
||
| 583 | /// <param name="right">The second instance.</param> |
||
| 584 | /// <returns>The result of the calculation.</returns> |
||
| 585 | public static Quaterniond operator *(Quaterniond left, Quaterniond right) |
||
| 586 | { |
||
| 587 | Multiply(ref left, ref right, out left); |
||
| 588 | return left; |
||
| 589 | } |
||
| 590 | |||
| 591 | /// <summary> |
||
| 592 | /// Multiplies an instance by a scalar. |
||
| 593 | /// </summary> |
||
| 594 | /// <param name="quaternion">The instance.</param> |
||
| 595 | /// <param name="scale">The scalar.</param> |
||
| 596 | /// <returns>A new instance containing the result of the calculation.</returns> |
||
| 597 | public static Quaterniond operator *(Quaterniond quaternion, double scale) |
||
| 598 | { |
||
| 599 | Multiply(ref quaternion, scale, out quaternion); |
||
| 600 | return quaternion; |
||
| 601 | } |
||
| 602 | |||
| 603 | /// <summary> |
||
| 604 | /// Multiplies an instance by a scalar. |
||
| 605 | /// </summary> |
||
| 606 | /// <param name="quaternion">The instance.</param> |
||
| 607 | /// <param name="scale">The scalar.</param> |
||
| 608 | /// <returns>A new instance containing the result of the calculation.</returns> |
||
| 609 | public static Quaterniond operator *(double scale, Quaterniond quaternion) |
||
| 610 | { |
||
| 611 | return new Quaterniond(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale); |
||
| 612 | } |
||
| 613 | |||
| 614 | /// <summary> |
||
| 615 | /// Compares two instances for equality. |
||
| 616 | /// </summary> |
||
| 617 | /// <param name="left">The first instance.</param> |
||
| 618 | /// <param name="right">The second instance.</param> |
||
| 619 | /// <returns>True, if left equals right; false otherwise.</returns> |
||
| 620 | public static bool operator ==(Quaterniond left, Quaterniond right) |
||
| 621 | { |
||
| 622 | return left.Equals(right); |
||
| 623 | } |
||
| 624 | |||
| 625 | /// <summary> |
||
| 626 | /// Compares two instances for inequality. |
||
| 627 | /// </summary> |
||
| 628 | /// <param name="left">The first instance.</param> |
||
| 629 | /// <param name="right">The second instance.</param> |
||
| 630 | /// <returns>True, if left does not equal right; false otherwise.</returns> |
||
| 631 | public static bool operator !=(Quaterniond left, Quaterniond right) |
||
| 632 | { |
||
| 633 | return !left.Equals(right); |
||
| 634 | } |
||
| 635 | |||
| 636 | #endregion |
||
| 637 | |||
| 638 | #region Overrides |
||
| 639 | |||
| 640 | #region public override string ToString() |
||
| 641 | |||
| 642 | /// <summary> |
||
| 643 | /// Returns a System.String that represents the current Quaterniond. |
||
| 644 | /// </summary> |
||
| 645 | /// <returns></returns> |
||
| 646 | public override string ToString() |
||
| 647 | { |
||
| 648 | return String.Format("V: {0}, W: {1}", Xyz, W); |
||
| 649 | } |
||
| 650 | |||
| 651 | #endregion |
||
| 652 | |||
| 653 | #region public override bool Equals (object o) |
||
| 654 | |||
| 655 | /// <summary> |
||
| 656 | /// Compares this object instance to another object for equality. |
||
| 657 | /// </summary> |
||
| 658 | /// <param name="other">The other object to be used in the comparison.</param> |
||
| 659 | /// <returns>True if both objects are Quaternions of equal value. Otherwise it returns false.</returns> |
||
| 660 | public override bool Equals(object other) |
||
| 661 | { |
||
| 662 | if (other is Quaterniond == false) return false; |
||
| 663 | return this == (Quaterniond)other; |
||
| 664 | } |
||
| 665 | |||
| 666 | #endregion |
||
| 667 | |||
| 668 | #region public override int GetHashCode () |
||
| 669 | |||
| 670 | /// <summary> |
||
| 671 | /// Provides the hash code for this object. |
||
| 672 | /// </summary> |
||
| 673 | /// <returns>A hash code formed from the bitwise XOR of this objects members.</returns> |
||
| 674 | public override int GetHashCode() |
||
| 675 | { |
||
| 676 | return Xyz.GetHashCode() ^ W.GetHashCode(); |
||
| 677 | } |
||
| 678 | |||
| 679 | #endregion |
||
| 680 | |||
| 681 | #endregion |
||
| 682 | |||
| 683 | #endregion |
||
| 684 | |||
| 685 | #if false |
||
| 686 | |||
| 687 | #region Fields |
||
| 688 | |||
| 689 | /// <summary>The W component of the Quaterniond.</summary> |
||
| 690 | public double W; |
||
| 691 | |||
| 692 | /// <summary>The X component of the Quaterniond.</summary> |
||
| 693 | public double X; |
||
| 694 | |||
| 695 | /// <summary>The Y component of the Quaterniond.</summary> |
||
| 696 | public double Y; |
||
| 697 | |||
| 698 | /// <summary>The Z component of the Quaterniond.</summary> |
||
| 699 | public double Z; |
||
| 700 | |||
| 701 | #endregion |
||
| 702 | |||
| 703 | #region Constructors |
||
| 704 | |||
| 705 | /// <summary>Constructs left Quaterniond that is left copy of the given Quaterniond.</summary> |
||
| 706 | /// <param name="quaterniond">The Quaterniond to copy.</param> |
||
| 707 | public Quaterniond(ref Quaterniond Quaterniond) : this(Quaterniond.W, Quaterniond.X, Quaterniond.Y, Quaterniond.Z) { } |
||
| 708 | |||
| 709 | /// <summary>Constructs left Quaterniond from the given components.</summary> |
||
| 710 | /// <param name="w">The W component for the Quaterniond.</param> |
||
| 711 | /// <param name="vector3d">A Vector representing the X, Y, and Z componets for the quaterion.</param> |
||
| 712 | public Quaterniond(double w, ref Vector3d vector3d) : this(w, vector3d.X, vector3d.Y, vector3d.Z) { } |
||
| 713 | |||
| 714 | /// <summary>Constructs left Quaterniond from the given axis and angle.</summary> |
||
| 715 | /// <param name="axis">The axis for the Quaterniond.</param> |
||
| 716 | /// <param name="angle">The angle for the quaternione.</param> |
||
| 717 | public Quaterniond(ref Vector3d axis, double angle) |
||
| 718 | { |
||
| 719 | double halfAngle = Functions.DTOR * angle / 2; |
||
| 720 | |||
| 721 | this.W = System.Math.Cos(halfAngle); |
||
| 722 | |||
| 723 | double sin = System.Math.Sin(halfAngle); |
||
| 724 | Vector3d axisNormalized; |
||
| 725 | Vector3d.Normalize(ref axis, out axisNormalized); |
||
| 726 | this.X = axisNormalized.X * sin; |
||
| 727 | this.Y = axisNormalized.Y * sin; |
||
| 728 | this.Z = axisNormalized.Z * sin; |
||
| 729 | } |
||
| 730 | |||
| 731 | /// <summary>Constructs left Quaterniond from the given components.</summary> |
||
| 732 | /// <param name="w">The W component for the Quaterniond.</param> |
||
| 733 | /// <param name="x">The X component for the Quaterniond.</param> |
||
| 734 | /// <param name="y">The Y component for the Quaterniond.</param> |
||
| 735 | /// <param name="z">The Z component for the Quaterniond.</param> |
||
| 736 | public Quaterniond(double w, double x, double y, double z) |
||
| 737 | { |
||
| 738 | this.W = w; |
||
| 739 | this.X = x; |
||
| 740 | this.Y = y; |
||
| 741 | this.Z = z; |
||
| 742 | } |
||
| 743 | |||
| 744 | /// <summary>Constructs left Quaterniond from the given array of double-precision floating-point numbers.</summary> |
||
| 745 | /// <param name="doubleArray">The array of doubles for the components of the Quaterniond.</param> |
||
| 746 | public Quaterniond(double[] doubleArray) |
||
| 747 | { |
||
| 748 | if (doubleArray == null || doubleArray.GetLength(0) < 4) throw new MissingFieldException(); |
||
| 749 | |||
| 750 | this.W = doubleArray[0]; |
||
| 751 | this.X = doubleArray[1]; |
||
| 752 | this.Y = doubleArray[2]; |
||
| 753 | this.Z = doubleArray[3]; |
||
| 754 | } |
||
| 755 | |||
| 756 | /// <summary>Constructs left Quaterniond from the given matrix. Only contains rotation information.</summary> |
||
| 757 | /// <param name="matrix">The matrix for the components of the Quaterniond.</param> |
||
| 758 | public Quaterniond(ref Matrix4d matrix) |
||
| 759 | { |
||
| 760 | double scale = System.Math.Pow(matrix.Determinant, 1.0d/3.0d); |
||
| 761 | |||
| 762 | W = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2; |
||
| 763 | X = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])) / 2; |
||
| 764 | Y = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] + matrix[1, 1] - matrix[2, 2])) / 2; |
||
| 765 | Z = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] - matrix[1, 1] + matrix[2, 2])) / 2; |
||
| 766 | if( matrix[2,1] - matrix[1,2] < 0 ) X = -X; |
||
| 767 | if( matrix[0,2] - matrix[2,0] < 0 ) Y = -Y; |
||
| 768 | if( matrix[1,0] - matrix[0,1] < 0 ) Z = -Z; |
||
| 769 | } |
||
| 770 | |||
| 771 | public Quaterniond(ref Matrix3d matrix) |
||
| 772 | { |
||
| 773 | double scale = System.Math.Pow(matrix.Determinant, 1.0d / 3.0d); |
||
| 774 | |||
| 775 | W = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] + matrix[1, 1] + matrix[2, 2])) / 2; |
||
| 776 | X = System.Math.Sqrt(System.Math.Max(0, scale + matrix[0, 0] - matrix[1, 1] - matrix[2, 2])) / 2; |
||
| 777 | Y = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] + matrix[1, 1] - matrix[2, 2])) / 2; |
||
| 778 | Z = System.Math.Sqrt(System.Math.Max(0, scale - matrix[0, 0] - matrix[1, 1] + matrix[2, 2])) / 2; |
||
| 779 | if (matrix[2, 1] - matrix[1, 2] < 0) X = -X; |
||
| 780 | if (matrix[0, 2] - matrix[2, 0] < 0) Y = -Y; |
||
| 781 | if (matrix[1, 0] - matrix[0, 1] < 0) Z = -Z; |
||
| 782 | } |
||
| 783 | |||
| 784 | #endregion |
||
| 785 | |||
| 786 | #region Arithmetic Operators |
||
| 787 | |||
| 788 | public void Add(ref Quaterniond Quaterniond) |
||
| 789 | { |
||
| 790 | W = W + Quaterniond.W; |
||
| 791 | X = X + Quaterniond.X; |
||
| 792 | Y = Y + Quaterniond.Y; |
||
| 793 | Z = Z + Quaterniond.Z; |
||
| 794 | } |
||
| 795 | public void Add(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 796 | { |
||
| 797 | result.W = W + Quaterniond.W; |
||
| 798 | result.X = X + Quaterniond.X; |
||
| 799 | result.Y = Y + Quaterniond.Y; |
||
| 800 | result.Z = Z + Quaterniond.Z; |
||
| 801 | } |
||
| 802 | public static void Add(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 803 | { |
||
| 804 | result.W = left.W + right.W; |
||
| 805 | result.X = left.X + right.X; |
||
| 806 | result.Y = left.Y + right.Y; |
||
| 807 | result.Z = left.Z + right.Z; |
||
| 808 | } |
||
| 809 | |||
| 810 | public void Subtract(ref Quaterniond Quaterniond) |
||
| 811 | { |
||
| 812 | W = W - Quaterniond.W; |
||
| 813 | X = X - Quaterniond.X; |
||
| 814 | Y = Y - Quaterniond.Y; |
||
| 815 | Z = Z - Quaterniond.Z; |
||
| 816 | } |
||
| 817 | public void Subtract(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 818 | { |
||
| 819 | result.W = W - Quaterniond.W; |
||
| 820 | result.X = X - Quaterniond.X; |
||
| 821 | result.Y = Y - Quaterniond.Y; |
||
| 822 | result.Z = Z - Quaterniond.Z; |
||
| 823 | } |
||
| 824 | public static void Subtract(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 825 | { |
||
| 826 | result.W = left.W - right.W; |
||
| 827 | result.X = left.X - right.X; |
||
| 828 | result.Y = left.Y - right.Y; |
||
| 829 | result.Z = left.Z - right.Z; |
||
| 830 | } |
||
| 831 | |||
| 832 | public void Multiply(ref Quaterniond Quaterniond) |
||
| 833 | { |
||
| 834 | double w = W * Quaterniond.W - X * Quaterniond.X - Y * Quaterniond.Y - Z * Quaterniond.Z; |
||
| 835 | double x = W * Quaterniond.X + X * Quaterniond.W + Y * Quaterniond.Z - Z * Quaterniond.Y; |
||
| 836 | double y = W * Quaterniond.Y + Y * Quaterniond.W + Z * Quaterniond.X - X * Quaterniond.Z; |
||
| 837 | Z = W * Quaterniond.Z + Z * Quaterniond.W + X * Quaterniond.Y - Y * Quaterniond.X; |
||
| 838 | W = w; |
||
| 839 | X = x; |
||
| 840 | Y = y; |
||
| 841 | } |
||
| 842 | public void Multiply(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 843 | { |
||
| 844 | result.W = W * Quaterniond.W - X * Quaterniond.X - Y * Quaterniond.Y - Z * Quaterniond.Z; |
||
| 845 | result.X = W * Quaterniond.X + X * Quaterniond.W + Y * Quaterniond.Z - Z * Quaterniond.Y; |
||
| 846 | result.Y = W * Quaterniond.Y + Y * Quaterniond.W + Z * Quaterniond.X - X * Quaterniond.Z; |
||
| 847 | result.Z = W * Quaterniond.Z + Z * Quaterniond.W + X * Quaterniond.Y - Y * Quaterniond.X; |
||
| 848 | } |
||
| 849 | public static void Multiply(ref Quaterniond left, ref Quaterniond right, out Quaterniond result) |
||
| 850 | { |
||
| 851 | result.W = left.W * right.W - left.X * right.X - left.Y * right.Y - left.Z * right.Z; |
||
| 852 | result.X = left.W * right.X + left.X * right.W + left.Y * right.Z - left.Z * right.Y; |
||
| 853 | result.Y = left.W * right.Y + left.Y * right.W + left.Z * right.X - left.X * right.Z; |
||
| 854 | result.Z = left.W * right.Z + left.Z * right.W + left.X * right.Y - left.Y * right.X; |
||
| 855 | } |
||
| 856 | |||
| 857 | public void Multiply(double scalar) |
||
| 858 | { |
||
| 859 | W = W * scalar; |
||
| 860 | X = X * scalar; |
||
| 861 | Y = Y * scalar; |
||
| 862 | Z = Z * scalar; |
||
| 863 | } |
||
| 864 | public void Multiply(double scalar, out Quaterniond result) |
||
| 865 | { |
||
| 866 | result.W = W * scalar; |
||
| 867 | result.X = X * scalar; |
||
| 868 | result.Y = Y * scalar; |
||
| 869 | result.Z = Z * scalar; |
||
| 870 | } |
||
| 871 | public static void Multiply(ref Quaterniond Quaterniond, double scalar, out Quaterniond result) |
||
| 872 | { |
||
| 873 | result.W = Quaterniond.W * scalar; |
||
| 874 | result.X = Quaterniond.X * scalar; |
||
| 875 | result.Y = Quaterniond.Y * scalar; |
||
| 876 | result.Z = Quaterniond.Z * scalar; |
||
| 877 | } |
||
| 878 | |||
| 879 | public void Divide(double scalar) |
||
| 880 | { |
||
| 881 | if (scalar == 0) throw new DivideByZeroException(); |
||
| 882 | W = W / scalar; |
||
| 883 | X = X / scalar; |
||
| 884 | Y = Y / scalar; |
||
| 885 | Z = Z / scalar; |
||
| 886 | } |
||
| 887 | public void Divide(double scalar, out Quaterniond result) |
||
| 888 | { |
||
| 889 | if (scalar == 0) throw new DivideByZeroException(); |
||
| 890 | result.W = W / scalar; |
||
| 891 | result.X = X / scalar; |
||
| 892 | result.Y = Y / scalar; |
||
| 893 | result.Z = Z / scalar; |
||
| 894 | } |
||
| 895 | public static void Divide(ref Quaterniond Quaterniond, double scalar, out Quaterniond result) |
||
| 896 | { |
||
| 897 | if (scalar == 0) throw new DivideByZeroException(); |
||
| 898 | result.W = Quaterniond.W / scalar; |
||
| 899 | result.X = Quaterniond.X / scalar; |
||
| 900 | result.Y = Quaterniond.Y / scalar; |
||
| 901 | result.Z = Quaterniond.Z / scalar; |
||
| 902 | } |
||
| 903 | |||
| 904 | #endregion |
||
| 905 | |||
| 906 | #region Functions |
||
| 907 | |||
| 908 | public double Modulus |
||
| 909 | { |
||
| 910 | get |
||
| 911 | { |
||
| 912 | return System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); |
||
| 913 | } |
||
| 914 | } |
||
| 915 | public double ModulusSquared |
||
| 916 | { |
||
| 917 | get |
||
| 918 | { |
||
| 919 | return W * W + X * X + Y * Y + Z * Z; |
||
| 920 | } |
||
| 921 | } |
||
| 922 | |||
| 923 | public static double DotProduct(Quaterniond left, Quaterniond right) |
||
| 924 | { |
||
| 925 | return left.W * right.W + left.X * right.X + left.Y * right.Y + left.Z * right.Z; |
||
| 926 | } |
||
| 927 | |||
| 928 | public void Normalize() |
||
| 929 | { |
||
| 930 | double modulus = System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); |
||
| 931 | if (modulus == 0) throw new DivideByZeroException(); |
||
| 932 | W = W / modulus; |
||
| 933 | X = X / modulus; |
||
| 934 | Y = Y / modulus; |
||
| 935 | Z = Z / modulus; |
||
| 936 | } |
||
| 937 | public void Normalize( out Quaterniond result ) |
||
| 938 | { |
||
| 939 | double modulus = System.Math.Sqrt(W * W + X * X + Y * Y + Z * Z); |
||
| 940 | if (modulus == 0) throw new DivideByZeroException(); |
||
| 941 | result.W = W / modulus; |
||
| 942 | result.X = X / modulus; |
||
| 943 | result.Y = Y / modulus; |
||
| 944 | result.Z = Z / modulus; |
||
| 945 | } |
||
| 946 | public static void Normalize(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 947 | { |
||
| 948 | double modulus = System.Math.Sqrt(Quaterniond.W * Quaterniond.W + Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z); |
||
| 949 | if (modulus == 0) throw new DivideByZeroException(); |
||
| 950 | result.W = Quaterniond.W / modulus; |
||
| 951 | result.X = Quaterniond.X / modulus; |
||
| 952 | result.Y = Quaterniond.Y / modulus; |
||
| 953 | result.Z = Quaterniond.Z / modulus; |
||
| 954 | } |
||
| 955 | |||
| 956 | public void Conjugate() |
||
| 957 | { |
||
| 958 | X = -X; |
||
| 959 | Y = -Y; |
||
| 960 | Z = -Z; |
||
| 961 | } |
||
| 962 | public void Conjugate( out Quaterniond result ) |
||
| 963 | { |
||
| 964 | result.W = W; |
||
| 965 | result.X = -X; |
||
| 966 | result.Y = -Y; |
||
| 967 | result.Z = -Z; |
||
| 968 | } |
||
| 969 | public static void Conjugate(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 970 | { |
||
| 971 | result.W = Quaterniond.W; |
||
| 972 | result.X = -Quaterniond.X; |
||
| 973 | result.Y = -Quaterniond.Y; |
||
| 974 | result.Z = -Quaterniond.Z; |
||
| 975 | } |
||
| 976 | |||
| 977 | public void Inverse() |
||
| 978 | { |
||
| 979 | double modulusSquared = W * W + X * X + Y * Y + Z * Z; |
||
| 980 | if (modulusSquared <= 0) throw new InvalidOperationException(); |
||
| 981 | double inverseModulusSquared = 1.0 / modulusSquared; |
||
| 982 | W = W * inverseModulusSquared; |
||
| 983 | X = X * -inverseModulusSquared; |
||
| 984 | Y = Y * -inverseModulusSquared; |
||
| 985 | Z = Z * -inverseModulusSquared; |
||
| 986 | } |
||
| 987 | public void Inverse( out Quaterniond result ) |
||
| 988 | { |
||
| 989 | double modulusSquared = W * W + X * X + Y * Y + Z * Z; |
||
| 990 | if (modulusSquared <= 0) throw new InvalidOperationException(); |
||
| 991 | double inverseModulusSquared = 1.0 / modulusSquared; |
||
| 992 | result.W = W * inverseModulusSquared; |
||
| 993 | result.X = X * -inverseModulusSquared; |
||
| 994 | result.Y = Y * -inverseModulusSquared; |
||
| 995 | result.Z = Z * -inverseModulusSquared; |
||
| 996 | } |
||
| 997 | public static void Inverse(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 998 | { |
||
| 999 | double modulusSquared = Quaterniond.W * Quaterniond.W + Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z; |
||
| 1000 | if (modulusSquared <= 0) throw new InvalidOperationException(); |
||
| 1001 | double inverseModulusSquared = 1.0 / modulusSquared; |
||
| 1002 | result.W = Quaterniond.W * inverseModulusSquared; |
||
| 1003 | result.X = Quaterniond.X * -inverseModulusSquared; |
||
| 1004 | result.Y = Quaterniond.Y * -inverseModulusSquared; |
||
| 1005 | result.Z = Quaterniond.Z * -inverseModulusSquared; |
||
| 1006 | } |
||
| 1007 | |||
| 1008 | public void Log() |
||
| 1009 | { |
||
| 1010 | if (System.Math.Abs(W) < 1.0) |
||
| 1011 | { |
||
| 1012 | double angle = System.Math.Acos(W); |
||
| 1013 | double sin = System.Math.Sin(angle); |
||
| 1014 | |||
| 1015 | if (System.Math.Abs(sin) >= 0) |
||
| 1016 | { |
||
| 1017 | double coefficient = angle / sin; |
||
| 1018 | X = X * coefficient; |
||
| 1019 | Y = Y * coefficient; |
||
| 1020 | Z = Z * coefficient; |
||
| 1021 | } |
||
| 1022 | } |
||
| 1023 | else |
||
| 1024 | { |
||
| 1025 | X = 0; |
||
| 1026 | Y = 0; |
||
| 1027 | Z = 0; |
||
| 1028 | } |
||
| 1029 | |||
| 1030 | W = 0; |
||
| 1031 | } |
||
| 1032 | public void Log( out Quaterniond result ) |
||
| 1033 | { |
||
| 1034 | if (System.Math.Abs(W) < 1.0) |
||
| 1035 | { |
||
| 1036 | double angle = System.Math.Acos(W); |
||
| 1037 | double sin = System.Math.Sin(angle); |
||
| 1038 | |||
| 1039 | if (System.Math.Abs(sin) >= 0) |
||
| 1040 | { |
||
| 1041 | double coefficient = angle / sin; |
||
| 1042 | result.X = X * coefficient; |
||
| 1043 | result.Y = Y * coefficient; |
||
| 1044 | result.Z = Z * coefficient; |
||
| 1045 | } |
||
| 1046 | else |
||
| 1047 | { |
||
| 1048 | result.X = X; |
||
| 1049 | result.Y = Y; |
||
| 1050 | result.Z = Z; |
||
| 1051 | } |
||
| 1052 | } |
||
| 1053 | else |
||
| 1054 | { |
||
| 1055 | result.X = 0; |
||
| 1056 | result.Y = 0; |
||
| 1057 | result.Z = 0; |
||
| 1058 | } |
||
| 1059 | |||
| 1060 | result.W = 0; |
||
| 1061 | } |
||
| 1062 | public static void Log(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 1063 | { |
||
| 1064 | if (System.Math.Abs(Quaterniond.W) < 1.0) |
||
| 1065 | { |
||
| 1066 | double angle = System.Math.Acos(Quaterniond.W); |
||
| 1067 | double sin = System.Math.Sin(angle); |
||
| 1068 | |||
| 1069 | if (System.Math.Abs(sin) >= 0) |
||
| 1070 | { |
||
| 1071 | double coefficient = angle / sin; |
||
| 1072 | result.X = Quaterniond.X * coefficient; |
||
| 1073 | result.Y = Quaterniond.Y * coefficient; |
||
| 1074 | result.Z = Quaterniond.Z * coefficient; |
||
| 1075 | } |
||
| 1076 | else |
||
| 1077 | { |
||
| 1078 | result.X = Quaterniond.X; |
||
| 1079 | result.Y = Quaterniond.Y; |
||
| 1080 | result.Z = Quaterniond.Z; |
||
| 1081 | } |
||
| 1082 | } |
||
| 1083 | else |
||
| 1084 | { |
||
| 1085 | result.X = 0; |
||
| 1086 | result.Y = 0; |
||
| 1087 | result.Z = 0; |
||
| 1088 | } |
||
| 1089 | |||
| 1090 | result.W = 0; |
||
| 1091 | } |
||
| 1092 | |||
| 1093 | public void Exp() |
||
| 1094 | { |
||
| 1095 | double angle = System.Math.Sqrt(X * X + Y * Y + Z * Z); |
||
| 1096 | double sin = System.Math.Sin(angle); |
||
| 1097 | |||
| 1098 | if (System.Math.Abs(sin) > 0) |
||
| 1099 | { |
||
| 1100 | double coefficient = angle / sin; |
||
| 1101 | W = 0; |
||
| 1102 | X = X * coefficient; |
||
| 1103 | Y = Y * coefficient; |
||
| 1104 | Z = Z * coefficient; |
||
| 1105 | } |
||
| 1106 | else |
||
| 1107 | { |
||
| 1108 | W = 0; |
||
| 1109 | } |
||
| 1110 | } |
||
| 1111 | public void Exp(out Quaterniond result) |
||
| 1112 | { |
||
| 1113 | double angle = System.Math.Sqrt(X * X + Y * Y + Z * Z); |
||
| 1114 | double sin = System.Math.Sin(angle); |
||
| 1115 | |||
| 1116 | if (System.Math.Abs(sin) > 0) |
||
| 1117 | { |
||
| 1118 | double coefficient = angle / sin; |
||
| 1119 | result.W = 0; |
||
| 1120 | result.X = X * coefficient; |
||
| 1121 | result.Y = Y * coefficient; |
||
| 1122 | result.Z = Z * coefficient; |
||
| 1123 | } |
||
| 1124 | else |
||
| 1125 | { |
||
| 1126 | result.W = 0; |
||
| 1127 | result.X = X; |
||
| 1128 | result.Y = Y; |
||
| 1129 | result.Z = Z; |
||
| 1130 | } |
||
| 1131 | } |
||
| 1132 | public static void Exp(ref Quaterniond Quaterniond, out Quaterniond result) |
||
| 1133 | { |
||
| 1134 | double angle = System.Math.Sqrt(Quaterniond.X * Quaterniond.X + Quaterniond.Y * Quaterniond.Y + Quaterniond.Z * Quaterniond.Z); |
||
| 1135 | double sin = System.Math.Sin(angle); |
||
| 1136 | |||
| 1137 | if (System.Math.Abs(sin) > 0) |
||
| 1138 | { |
||
| 1139 | double coefficient = angle / sin; |
||
| 1140 | result.W = 0; |
||
| 1141 | result.X = Quaterniond.X * coefficient; |
||
| 1142 | result.Y = Quaterniond.Y * coefficient; |
||
| 1143 | result.Z = Quaterniond.Z * coefficient; |
||
| 1144 | } |
||
| 1145 | else |
||
| 1146 | { |
||
| 1147 | result.W = 0; |
||
| 1148 | result.X = Quaterniond.X; |
||
| 1149 | result.Y = Quaterniond.Y; |
||
| 1150 | result.Z = Quaterniond.Z; |
||
| 1151 | } |
||
| 1152 | } |
||
| 1153 | |||
| 1154 | /// <summary>Returns left matrix for this Quaterniond.</summary> |
||
| 1155 | public void Matrix4d(out Matrix4d result) |
||
| 1156 | { |
||
| 1157 | // TODO Expand |
||
| 1158 | result = new Matrix4d(ref this); |
||
| 1159 | } |
||
| 1160 | |||
| 1161 | public void GetAxisAndAngle(out Vector3d axis, out double angle) |
||
| 1162 | { |
||
| 1163 | Quaterniond Quaterniond; |
||
| 1164 | Normalize(out Quaterniond); |
||
| 1165 | double cos = Quaterniond.W; |
||
| 1166 | angle = System.Math.Acos(cos) * 2 * Functions.RTOD; |
||
| 1167 | double sin = System.Math.Sqrt( 1.0d - cos * cos ); |
||
| 1168 | if ( System.Math.Abs( sin ) < 0.0001 ) sin = 1; |
||
| 1169 | axis = new Vector3d(X / sin, Y / sin, Z / sin); |
||
| 1170 | } |
||
| 1171 | |||
| 1172 | public static void Slerp(ref Quaterniond start, ref Quaterniond end, double blend, out Quaterniond result) |
||
| 1173 | { |
||
| 1174 | if (start.W == 0 && start.X == 0 && start.Y == 0 && start.Z == 0) |
||
| 1175 | { |
||
| 1176 | if (end.W == 0 && end.X == 0 && end.Y == 0 && end.Z == 0) |
||
| 1177 | { |
||
| 1178 | result.W = 1; |
||
| 1179 | result.X = 0; |
||
| 1180 | result.Y = 0; |
||
| 1181 | result.Z = 0; |
||
| 1182 | } |
||
| 1183 | else |
||
| 1184 | { |
||
| 1185 | result = end; |
||
| 1186 | } |
||
| 1187 | } |
||
| 1188 | else if (end.W == 0 && end.X == 0 && end.Y == 0 && end.Z == 0) |
||
| 1189 | { |
||
| 1190 | result = start; |
||
| 1191 | } |
||
| 1192 | |||
| 1193 | Vector3d startVector = new Vector3d(start.X, start.Y, start.Z); |
||
| 1194 | Vector3d endVector = new Vector3d(end.X, end.Y, end.Z); |
||
| 1195 | double cosHalfAngle = start.W * end.W + Vector3d.Dot(startVector, endVector); |
||
| 1196 | |||
| 1197 | if (cosHalfAngle >= 1.0f || cosHalfAngle <= -1.0f) |
||
| 1198 | { |
||
| 1199 | // angle = 0.0f, so just return one input. |
||
| 1200 | result = start; |
||
| 1201 | } |
||
| 1202 | else if (cosHalfAngle < 0.0f) |
||
| 1203 | { |
||
| 1204 | end.W = -end.W; |
||
| 1205 | end.X = -end.X; |
||
| 1206 | end.Y = -end.Y; |
||
| 1207 | end.Z = -end.Z; |
||
| 1208 | cosHalfAngle = -cosHalfAngle; |
||
| 1209 | } |
||
| 1210 | |||
| 1211 | double blendA; |
||
| 1212 | double blendB; |
||
| 1213 | if (cosHalfAngle < 0.99f) |
||
| 1214 | { |
||
| 1215 | // do proper slerp for big angles |
||
| 1216 | double halfAngle = (double)System.Math.Acos(cosHalfAngle); |
||
| 1217 | double sinHalfAngle = (double)System.Math.Sin(halfAngle); |
||
| 1218 | double oneOverSinHalfAngle = 1.0f / sinHalfAngle; |
||
| 1219 | blendA = (double)System.Math.Sin(halfAngle * (1.0f - blend)) * oneOverSinHalfAngle; |
||
| 1220 | blendB = (double)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle; |
||
| 1221 | } |
||
| 1222 | else |
||
| 1223 | { |
||
| 1224 | // do lerp if angle is really small. |
||
| 1225 | blendA = 1.0f - blend; |
||
| 1226 | blendB = blend; |
||
| 1227 | } |
||
| 1228 | |||
| 1229 | result.W = blendA * start.W + blendB * end.W; |
||
| 1230 | result.X = blendA * start.X + blendB * end.X; |
||
| 1231 | result.Y = blendA * start.Y + blendB * end.Y; |
||
| 1232 | result.Z = blendA * start.Z + blendB * end.Z; |
||
| 1233 | |||
| 1234 | if (result.W != 0 || result.X != 0 || result.Y != 0 || result.Z != 0) |
||
| 1235 | { |
||
| 1236 | result.Normalize(); |
||
| 1237 | } |
||
| 1238 | else |
||
| 1239 | { |
||
| 1240 | result.W = 1; |
||
| 1241 | result.X = 0; |
||
| 1242 | result.Y = 0; |
||
| 1243 | result.Z = 0; |
||
| 1244 | } |
||
| 1245 | } |
||
| 1246 | |||
| 1247 | #endregion |
||
| 1248 | |||
| 1249 | #region HashCode |
||
| 1250 | |||
| 1251 | /// <summary>Returns the hash code for this instance.</summary> |
||
| 1252 | /// <returns>A 32-bit signed integer that is the hash code for this instance.</returns> |
||
| 1253 | public override int GetHashCode() |
||
| 1254 | { |
||
| 1255 | base.GetHashCode(); |
||
| 1256 | return W.GetHashCode() ^ X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode(); |
||
| 1257 | } |
||
| 1258 | |||
| 1259 | #endregion |
||
| 1260 | |||
| 1261 | #region String and Parse |
||
| 1262 | |||
| 1263 | /// <summary>Returns the fully qualified type name of this instance.</summary> |
||
| 1264 | /// <returns>A System.String containing left fully qualified type name.</returns> |
||
| 1265 | public override string ToString() |
||
| 1266 | { |
||
| 1267 | return string.Format("({0}, {1}, {2}, {3})", W, X, Y, Z); |
||
| 1268 | } |
||
| 1269 | |||
| 1270 | /// <summary>Parses left string, converting it to left Quaterniond.</summary> |
||
| 1271 | /// <param name="str">The string to parse.</param> |
||
| 1272 | /// <returns>The Quaterniond represented by the string.</returns> |
||
| 1273 | public static void Parse(string str, out Quaterniond result) |
||
| 1274 | { |
||
| 1275 | Match match = new Regex(@"\((?<w>.*),(?<x>.*),(?<y>.*),(?<z>.*)\)", RegexOptions.None).Match(str); |
||
| 1276 | if (!match.Success) throw new Exception("Parse failed!"); |
||
| 1277 | |||
| 1278 | result.W = double.Parse(match.Result("${w}")); |
||
| 1279 | result.X = double.Parse(match.Result("${x}")); |
||
| 1280 | result.Y = double.Parse(match.Result("${y}")); |
||
| 1281 | result.Z = double.Parse(match.Result("${z}")); |
||
| 1282 | } |
||
| 1283 | |||
| 1284 | #endregion |
||
| 1285 | |||
| 1286 | #region Constants |
||
| 1287 | |||
| 1288 | /// <summary>A quaterion with all zero components.</summary> |
||
| 1289 | public static readonly Quaterniond Zero = new Quaterniond(0, 0, 0, 0); |
||
| 1290 | |||
| 1291 | /// <summary>A quaterion representing an identity.</summary> |
||
| 1292 | public static readonly Quaterniond Identity = new Quaterniond(1, 0, 0, 0); |
||
| 1293 | |||
| 1294 | /// <summary>A quaterion representing the W axis.</summary> |
||
| 1295 | public static readonly Quaterniond WAxis = new Quaterniond(1, 0, 0, 0); |
||
| 1296 | |||
| 1297 | /// <summary>A quaterion representing the X axis.</summary> |
||
| 1298 | public static readonly Quaterniond XAxis = new Quaterniond(0, 1, 0, 0); |
||
| 1299 | |||
| 1300 | /// <summary>A quaterion representing the Y axis.</summary> |
||
| 1301 | public static readonly Quaterniond YAxis = new Quaterniond(0, 0, 1, 0); |
||
| 1302 | |||
| 1303 | /// <summary>A quaterion representing the Z axis.</summary> |
||
| 1304 | public static readonly Quaterniond ZAxis = new Quaterniond(0, 0, 0, 1); |
||
| 1305 | |||
| 1306 | #endregion |
||
| 1307 | |||
| 1308 | #endif |
||
| 1309 | |||
| 1310 | #region IEquatable<Quaterniond> Members |
||
| 1311 | |||
| 1312 | /// <summary> |
||
| 1313 | /// Compares this Quaterniond instance to another Quaterniond for equality. |
||
| 1314 | /// </summary> |
||
| 1315 | /// <param name="other">The other Quaterniond to be used in the comparison.</param> |
||
| 1316 | /// <returns>True if both instances are equal; false otherwise.</returns> |
||
| 1317 | public bool Equals(Quaterniond other) |
||
| 1318 | { |
||
| 1319 | return Xyz == other.Xyz && W == other.W; |
||
| 1320 | } |
||
| 1321 | |||
| 1322 | #endregion |
||
| 1323 | } |
||
| 1324 | } |