Quaternion.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785
  1. #region --- License ---
  2. /*
  3. Copyright (c) 2006 - 2008 The Open Toolkit library.
  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. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. */
  20. #endregion --- License ---
  21. using System;
  22. using System.Runtime.InteropServices;
  23. namespace MatterHackers.VectorMath
  24. {
  25. /// <summary>
  26. /// Represents a double-precision Quaternion.
  27. /// </summary>
  28. [Serializable]
  29. [StructLayout(LayoutKind.Sequential)]
  30. public struct Quaternion : IEquatable<Quaternion>
  31. {
  32. #region Fields
  33. private Vector3 xyz;
  34. private double w;
  35. #endregion Fields
  36. #region Constructors
  37. /// <summary>
  38. /// Construct a new Quaternion from vector and w components
  39. /// </summary>
  40. /// <param name="v">The vector part</param>
  41. /// <param name="w">The w part</param>
  42. public Quaternion(Vector3 v, double w)
  43. {
  44. this.xyz = v;
  45. this.w = w;
  46. }
  47. /// <summary>
  48. /// Construct a new Quaternion
  49. /// </summary>
  50. /// <param name="x">The x component</param>
  51. /// <param name="y">The y component</param>
  52. /// <param name="z">The z component</param>
  53. /// <param name="w">The w component</param>
  54. public Quaternion(double x, double y, double z, double w)
  55. : this(new Vector3(x, y, z), w)
  56. { }
  57. /// <summary>
  58. /// Construct a new Quaternion
  59. /// </summary>
  60. /// <param name="matrix">The matrix to discover the rotation of</param>
  61. public Quaternion(Matrix4X4 m)
  62. : this()
  63. {
  64. this = m.GetRotation();
  65. }
  66. private double CopySign(double value, double sign)
  67. {
  68. if (sign < 0)
  69. {
  70. // return a negative number
  71. return value < 0 ? value : -value;
  72. }
  73. else
  74. {
  75. // return a positive number
  76. return value < 0 ? -value : value;
  77. }
  78. }
  79. /// <summary>
  80. /// Construct a quaternion that rotates from one direction to another
  81. /// </summary>
  82. /// <param name="startingDirection"></param>
  83. /// <param name="endingDirection"></param>
  84. public Quaternion(Vector3 startingDirection, Vector3 endingDirection)
  85. {
  86. if ((endingDirection + startingDirection).LengthSquared == 0)
  87. {
  88. endingDirection += new Vector3(.0000001, 0, 0);
  89. }
  90. this.xyz = Vector3Ex.Cross(endingDirection, startingDirection);
  91. this.w = Math.Sqrt(Math.Pow(endingDirection.Length, 2) * Math.Pow(startingDirection.Length, 2)) + Vector3Ex.Dot(endingDirection, startingDirection);
  92. Normalize();
  93. }
  94. /// <summary>
  95. /// Construct a quaternion that rotates from one direction to another
  96. /// </summary>
  97. /// <param name="startingDirection"></param>
  98. /// <param name="endingDirection"></param>
  99. public Quaternion(Vector3Float startingDirection, Vector3Float endingDirection)
  100. {
  101. if ((endingDirection + startingDirection).LengthSquared == 0)
  102. {
  103. endingDirection += new Vector3Float(.0000001, 0, 0);
  104. }
  105. this.xyz = new Vector3(endingDirection.Cross(startingDirection));
  106. this.w = Math.Sqrt(Math.Pow(endingDirection.Length, 2) * Math.Pow(startingDirection.Length, 2)) + endingDirection.Dot(startingDirection);
  107. Normalize();
  108. }
  109. #endregion Constructors
  110. #region Public Members
  111. #region Properties
  112. /// <summary>
  113. /// Gets or sets an OpenTK.Vector3d with the X, Y and Z components of this instance.
  114. /// </summary>
  115. public Vector3 Xyz { get { return xyz; } set { xyz = value; } }
  116. /// <summary>
  117. /// Gets or sets the X component of this instance.
  118. /// </summary>
  119. public double X { get { return xyz.X; } set { xyz.X = value; } }
  120. /// <summary>
  121. /// Gets or sets the Y component of this instance.
  122. /// </summary>
  123. public double Y { get { return xyz.Y; } set { xyz.Y = value; } }
  124. /// <summary>
  125. /// Gets or sets the Z component of this instance.
  126. /// </summary>
  127. public double Z { get { return xyz.Z; } set { xyz.Z = value; } }
  128. /// <summary>
  129. /// Gets or sets the W component of this instance.
  130. /// </summary>
  131. public double W { get { return w; } set { w = value; } }
  132. #endregion Properties
  133. #region Instance
  134. #region ToAxisAngle
  135. /// <summary>
  136. /// Convert the current quaternion to axis angle representation
  137. /// </summary>
  138. /// <param name="axis">The resultant axis</param>
  139. /// <param name="angle">The resultant angle</param>
  140. public void ToAxisAngle(out Vector3 axis, out double angle)
  141. {
  142. Vector4 result = ToAxisAngle();
  143. axis = result.Xyz;
  144. angle = result.W;
  145. }
  146. /// <summary>
  147. /// Convert this instance to an axis-angle representation.
  148. /// </summary>
  149. /// <returns>A Vector4 that is the axis-angle representation of this quaternion.</returns>
  150. public Vector4 ToAxisAngle()
  151. {
  152. #if true
  153. Vector4 axisAngle = new Vector4();
  154. Quaternion q1 = this;
  155. if (q1.w > 1) q1.Normalize(); // if w>1 acos and sqrt will produce errors, this cant happen if quaternion is normalized
  156. axisAngle.W = 2 * Math.Acos(q1.w);
  157. double s = Math.Sqrt(1 - q1.w * q1.w); // assuming quaternion normalized then w is less than 1, so term always positive.
  158. if (s < 0.001)
  159. { // test to avoid divide by zero, s is always positive due to sqrt
  160. // if s close to zero then direction of axis not important
  161. axisAngle.X = q1.X; // if it is important that axis is normalized then replace with x=1; y=z=0;
  162. axisAngle.Y = q1.Y;
  163. axisAngle.Z = q1.Z;
  164. }
  165. else
  166. {
  167. axisAngle.X = q1.X / s; // normalize axis
  168. axisAngle.Y = q1.Y / s;
  169. axisAngle.Z = q1.Z / s;
  170. }
  171. return axisAngle;
  172. #else
  173. Quaternion q = this;
  174. if (q.W > 1.0)
  175. q.Normalize();
  176. Vector4 result = new Vector4();
  177. result.W = 2.0 * (float)System.Math.Acos(q.W); // angle
  178. float den = (float)System.Math.Sqrt(1.0 - q.W * q.W);
  179. if (den > 0.0001f)
  180. {
  181. result.Xyz = q.Xyz / den;
  182. }
  183. else
  184. {
  185. // This occurs when the angle is zero.
  186. // Not a problem: just set an arbitrary normalized axis.
  187. result.Xyz = Vector3.UnitX;
  188. }
  189. return result;
  190. #endif
  191. }
  192. #endregion ToAxisAngle
  193. #region public double Length
  194. /// <summary>
  195. /// Gets the length (magnitude) of the Quaternion.
  196. /// </summary>
  197. /// <seealso cref="LengthSquared"/>
  198. public double Length
  199. {
  200. get
  201. {
  202. return (double)System.Math.Sqrt(W * W + Xyz.LengthSquared);
  203. }
  204. }
  205. #endregion public double Length
  206. #region public double LengthSquared
  207. /// <summary>
  208. /// Gets the square of the Quaternion length (magnitude).
  209. /// </summary>
  210. public double LengthSquared
  211. {
  212. get
  213. {
  214. return W * W + Xyz.LengthSquared;
  215. }
  216. }
  217. #endregion public double LengthSquared
  218. #region public void Normalize()
  219. /// <summary>
  220. /// Scales the Quaternion to unit length.
  221. /// </summary>
  222. public void Normalize()
  223. {
  224. double length = this.Length;
  225. if (length != 0)
  226. {
  227. double scale = 1.0 / length;
  228. Xyz *= scale;
  229. W *= scale;
  230. }
  231. }
  232. #endregion public void Normalize()
  233. #region public void Conjugate()
  234. /// <summary>
  235. /// Convert this Quaternion to its conjugate
  236. /// </summary>
  237. public void Conjugate()
  238. {
  239. Xyz = -Xyz;
  240. }
  241. #endregion public void Conjugate()
  242. #endregion Instance
  243. #region Static
  244. #region Fields
  245. /// <summary>
  246. /// Defines the identity quaternion.
  247. /// </summary>
  248. public readonly static Quaternion Identity = new Quaternion(0, 0, 0, 1);
  249. #endregion Fields
  250. #region Add
  251. /// <summary>
  252. /// Add two quaternions
  253. /// </summary>
  254. /// <param name="left">The first operand</param>
  255. /// <param name="right">The second operand</param>
  256. /// <returns>The result of the addition</returns>
  257. public static Quaternion Add(Quaternion left, Quaternion right)
  258. {
  259. return new Quaternion(
  260. left.Xyz + right.Xyz,
  261. left.W + right.W);
  262. }
  263. /// <summary>
  264. /// Add two quaternions
  265. /// </summary>
  266. /// <param name="left">The first operand</param>
  267. /// <param name="right">The second operand</param>
  268. /// <param name="result">The result of the addition</param>
  269. public static void Add(ref Quaternion left, ref Quaternion right, out Quaternion result)
  270. {
  271. result = new Quaternion(
  272. left.Xyz + right.Xyz,
  273. left.W + right.W);
  274. }
  275. #endregion Add
  276. #region Sub
  277. /// <summary>
  278. /// Subtracts two instances.
  279. /// </summary>
  280. /// <param name="left">The left instance.</param>
  281. /// <param name="right">The right instance.</param>
  282. /// <returns>The result of the operation.</returns>
  283. public static Quaternion Sub(Quaternion left, Quaternion right)
  284. {
  285. return new Quaternion(
  286. left.Xyz - right.Xyz,
  287. left.W - right.W);
  288. }
  289. /// <summary>
  290. /// Subtracts two instances.
  291. /// </summary>
  292. /// <param name="left">The left instance.</param>
  293. /// <param name="right">The right instance.</param>
  294. /// <param name="result">The result of the operation.</param>
  295. public static void Sub(ref Quaternion left, ref Quaternion right, out Quaternion result)
  296. {
  297. result = new Quaternion(
  298. left.Xyz - right.Xyz,
  299. left.W - right.W);
  300. }
  301. #endregion Sub
  302. #region Mult
  303. /// <summary>
  304. /// Multiplies two instances.
  305. /// </summary>
  306. /// <param name="left">The first instance.</param>
  307. /// <param name="right">The second instance.</param>
  308. /// <returns>A new instance containing the result of the calculation.</returns>
  309. [Obsolete("Use Multiply instead.")]
  310. public static Quaternion Mult(Quaternion left, Quaternion right)
  311. {
  312. return new Quaternion(
  313. right.W * left.Xyz + left.W * right.Xyz + Vector3Ex.Cross(left.Xyz, right.Xyz),
  314. left.W * right.W - Vector3Ex.Dot(left.Xyz, right.Xyz));
  315. }
  316. /// <summary>
  317. /// Multiplies two instances.
  318. /// </summary>
  319. /// <param name="left">The first instance.</param>
  320. /// <param name="right">The second instance.</param>
  321. /// <param name="result">A new instance containing the result of the calculation.</param>
  322. [Obsolete("Use Multiply instead.")]
  323. public static void Mult(ref Quaternion left, ref Quaternion right, out Quaternion result)
  324. {
  325. result = new Quaternion(
  326. right.W * left.Xyz + left.W * right.Xyz + Vector3Ex.Cross(left.Xyz, right.Xyz),
  327. left.W * right.W - Vector3Ex.Dot(left.Xyz, right.Xyz));
  328. }
  329. /// <summary>
  330. /// Multiplies two instances.
  331. /// </summary>
  332. /// <param name="left">The first instance.</param>
  333. /// <param name="right">The second instance.</param>
  334. /// <returns>A new instance containing the result of the calculation.</returns>
  335. public static Quaternion Multiply(Quaternion left, Quaternion right)
  336. {
  337. Quaternion result;
  338. Multiply(ref left, ref right, out result);
  339. return result;
  340. }
  341. /// <summary>
  342. /// Multiplies two instances.
  343. /// </summary>
  344. /// <param name="left">The first instance.</param>
  345. /// <param name="right">The second instance.</param>
  346. /// <param name="result">A new instance containing the result of the calculation.</param>
  347. public static void Multiply(ref Quaternion left, ref Quaternion right, out Quaternion result)
  348. {
  349. result = new Quaternion(
  350. right.W * left.Xyz + left.W * right.Xyz + Vector3Ex.Cross(left.Xyz, right.Xyz),
  351. left.W * right.W - Vector3Ex.Dot(left.Xyz, right.Xyz));
  352. }
  353. /// <summary>
  354. /// Multiplies an instance by a scalar.
  355. /// </summary>
  356. /// <param name="quaternion">The instance.</param>
  357. /// <param name="scale">The scalar.</param>
  358. /// <param name="result">A new instance containing the result of the calculation.</param>
  359. public static void Multiply(ref Quaternion quaternion, double scale, out Quaternion result)
  360. {
  361. result = new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
  362. }
  363. /// <summary>
  364. /// Multiplies an instance by a scalar.
  365. /// </summary>
  366. /// <param name="quaternion">The instance.</param>
  367. /// <param name="scale">The scalar.</param>
  368. /// <returns>A new instance containing the result of the calculation.</returns>
  369. public static Quaternion Multiply(Quaternion quaternion, double scale)
  370. {
  371. return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
  372. }
  373. #endregion Mult
  374. #region Conjugate
  375. /// <summary>
  376. /// Get the conjugate of the given Quaternion
  377. /// </summary>
  378. /// <param name="q">The Quaternion</param>
  379. /// <returns>The conjugate of the given Quaternion</returns>
  380. public static Quaternion Conjugate(Quaternion q)
  381. {
  382. return new Quaternion(-q.Xyz, q.W);
  383. }
  384. /// <summary>
  385. /// Get the conjugate of the given Quaternion
  386. /// </summary>
  387. /// <param name="q">The Quaternion</param>
  388. /// <param name="result">The conjugate of the given Quaternion</param>
  389. public static void Conjugate(ref Quaternion q, out Quaternion result)
  390. {
  391. result = new Quaternion(-q.Xyz, q.W);
  392. }
  393. #endregion Conjugate
  394. #region Invert
  395. /// <summary>
  396. /// Get the inverse of the given Quaternion
  397. /// </summary>
  398. /// <param name="q">The Quaternion to invert</param>
  399. /// <returns>The inverse of the given Quaternion</returns>
  400. public static Quaternion Invert(Quaternion q)
  401. {
  402. Quaternion result;
  403. Invert(ref q, out result);
  404. return result;
  405. }
  406. /// <summary>
  407. /// Get the inverse of the given Quaternion
  408. /// </summary>
  409. /// <param name="q">The Quaternion to invert</param>
  410. /// <param name="result">The inverse of the given Quaternion</param>
  411. public static void Invert(ref Quaternion q, out Quaternion result)
  412. {
  413. double lengthSq = q.LengthSquared;
  414. if (lengthSq != 0.0)
  415. {
  416. double i = 1.0 / lengthSq;
  417. result = new Quaternion(q.Xyz * -i, q.W * i);
  418. }
  419. else
  420. {
  421. result = q;
  422. }
  423. }
  424. #endregion Invert
  425. #region Normalize
  426. /// <summary>
  427. /// Scale the given Quaternion to unit length
  428. /// </summary>
  429. /// <param name="q">The Quaternion to normalize</param>
  430. /// <returns>The normalized Quaternion</returns>
  431. public static Quaternion Normalize(Quaternion q)
  432. {
  433. Quaternion result;
  434. Normalize(ref q, out result);
  435. return result;
  436. }
  437. /// <summary>
  438. /// Scale the given Quaternion to unit length
  439. /// </summary>
  440. /// <param name="q">The Quaternion to normalize</param>
  441. /// <param name="result">The normalized Quaternion</param>
  442. public static void Normalize(ref Quaternion q, out Quaternion result)
  443. {
  444. double scale = 1.0 / q.Length;
  445. result = new Quaternion(q.Xyz * scale, q.W * scale);
  446. }
  447. #endregion Normalize
  448. #region FromEulerAngles
  449. public static Quaternion FromEulerAngles(Vector3 rotation)
  450. {
  451. Quaternion xRotation = FromAxisAngle(Vector3.UnitX, rotation.X);
  452. Quaternion yRotation = FromAxisAngle(Vector3.UnitY, rotation.Y);
  453. Quaternion zRotation = FromAxisAngle(Vector3.UnitZ, rotation.Z);
  454. //return xRotation * yRotation * zRotation;
  455. return zRotation * yRotation * xRotation;
  456. }
  457. #endregion FromEulerAngles
  458. #region FromAxisAngle
  459. /// <summary>
  460. /// Build a Quaternion 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 Quaternion FromAxisAngle(Vector3 axis, double angle)
  466. {
  467. if (axis.LengthSquared == 0.0)
  468. {
  469. return Identity;
  470. }
  471. Quaternion result = Identity;
  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. return Normalize(result);
  477. }
  478. #endregion FromAxisAngle
  479. #region Slerp
  480. /// <summary>
  481. /// Do Spherical linear interpolation between two quaternions
  482. /// </summary>
  483. /// <param name="q1">The first Quaternion</param>
  484. /// <param name="q2">The second Quaternion</param>
  485. /// <param name="blend">The blend factor</param>
  486. /// <returns>A smooth blend between the given quaternions</returns>
  487. public static Quaternion Slerp(Quaternion q1, Quaternion q2, double blend)
  488. {
  489. // if either input is zero, return the other.
  490. if (q1.LengthSquared == 0.0)
  491. {
  492. if (q2.LengthSquared == 0.0)
  493. {
  494. return Identity;
  495. }
  496. return q2;
  497. }
  498. else if (q2.LengthSquared == 0.0)
  499. {
  500. return q1;
  501. }
  502. double cosHalfAngle = q1.W * q2.W + Vector3Ex.Dot(q1.Xyz, q2.Xyz);
  503. if (cosHalfAngle >= 1.0 || cosHalfAngle <= -1.0)
  504. {
  505. // angle = 0.0, so just return one input.
  506. return q1;
  507. }
  508. else if (cosHalfAngle < 0.0)
  509. {
  510. q2.Xyz = -q2.Xyz;
  511. q2.W = -q2.W;
  512. cosHalfAngle = -cosHalfAngle;
  513. }
  514. double blendA;
  515. double blendB;
  516. if (cosHalfAngle < 0.99f)
  517. {
  518. // do proper slerp for big angles
  519. double halfAngle = (double)System.Math.Acos(cosHalfAngle);
  520. double sinHalfAngle = (double)System.Math.Sin(halfAngle);
  521. double oneOverSinHalfAngle = 1.0 / sinHalfAngle;
  522. blendA = (double)System.Math.Sin(halfAngle * (1.0 - blend)) * oneOverSinHalfAngle;
  523. blendB = (double)System.Math.Sin(halfAngle * blend) * oneOverSinHalfAngle;
  524. }
  525. else
  526. {
  527. // do lerp if angle is really small.
  528. blendA = 1.0 - blend;
  529. blendB = blend;
  530. }
  531. Quaternion result = new Quaternion(blendA * q1.Xyz + blendB * q2.Xyz, blendA * q1.W + blendB * q2.W);
  532. if (result.LengthSquared > 0.0)
  533. return Normalize(result);
  534. else
  535. return Identity;
  536. }
  537. #endregion Slerp
  538. #endregion Static
  539. #region Operators
  540. /// <summary>
  541. /// Adds two instances.
  542. /// </summary>
  543. /// <param name="left">The first instance.</param>
  544. /// <param name="right">The second instance.</param>
  545. /// <returns>The result of the calculation.</returns>
  546. public static Quaternion operator +(Quaternion left, Quaternion right)
  547. {
  548. left.Xyz += right.Xyz;
  549. left.W += right.W;
  550. return left;
  551. }
  552. /// <summary>
  553. /// Subtracts two instances.
  554. /// </summary>
  555. /// <param name="left">The first instance.</param>
  556. /// <param name="right">The second instance.</param>
  557. /// <returns>The result of the calculation.</returns>
  558. public static Quaternion operator -(Quaternion left, Quaternion right)
  559. {
  560. left.Xyz -= right.Xyz;
  561. left.W -= right.W;
  562. return left;
  563. }
  564. /// <summary>
  565. /// Multiplies two instances.
  566. /// </summary>
  567. /// <param name="left">The first instance.</param>
  568. /// <param name="right">The second instance.</param>
  569. /// <returns>The result of the calculation.</returns>
  570. public static Quaternion operator *(Quaternion left, Quaternion right)
  571. {
  572. Multiply(ref left, ref right, out left);
  573. return left;
  574. }
  575. /// <summary>
  576. /// Multiplies an instance by a scalar.
  577. /// </summary>
  578. /// <param name="quaternion">The instance.</param>
  579. /// <param name="scale">The scalar.</param>
  580. /// <returns>A new instance containing the result of the calculation.</returns>
  581. public static Quaternion operator *(Quaternion quaternion, double scale)
  582. {
  583. Multiply(ref quaternion, scale, out quaternion);
  584. return quaternion;
  585. }
  586. /// <summary>
  587. /// Multiplies an instance by a scalar.
  588. /// </summary>
  589. /// <param name="quaternion">The instance.</param>
  590. /// <param name="scale">The scalar.</param>
  591. /// <returns>A new instance containing the result of the calculation.</returns>
  592. public static Quaternion operator *(double scale, Quaternion quaternion)
  593. {
  594. return new Quaternion(quaternion.X * scale, quaternion.Y * scale, quaternion.Z * scale, quaternion.W * scale);
  595. }
  596. /// <summary>
  597. /// Compares two instances for equality.
  598. /// </summary>
  599. /// <param name="left">The first instance.</param>
  600. /// <param name="right">The second instance.</param>
  601. /// <returns>True, if left equals right; false otherwise.</returns>
  602. public static bool operator ==(Quaternion left, Quaternion right)
  603. {
  604. return left.Equals(right);
  605. }
  606. /// <summary>
  607. /// Compares two instances for inequality.
  608. /// </summary>
  609. /// <param name="left">The first instance.</param>
  610. /// <param name="right">The second instance.</param>
  611. /// <returns>True, if left does not equal right; false otherwise.</returns>
  612. public static bool operator !=(Quaternion left, Quaternion right)
  613. {
  614. return !left.Equals(right);
  615. }
  616. #endregion Operators
  617. #region Overrides
  618. #region public override string ToString()
  619. /// <summary>
  620. /// Returns a System.String that represents the current Quaternion.
  621. /// </summary>
  622. /// <returns></returns>
  623. public override string ToString()
  624. {
  625. return String.Format("V: {0}, W: {1}", Xyz, W);
  626. }
  627. #endregion public override string ToString()
  628. #region public override bool Equals (object o)
  629. /// <summary>
  630. /// Compares this object instance to another object for equality.
  631. /// </summary>
  632. /// <param name="other">The other object to be used in the comparison.</param>
  633. /// <returns>True if both objects are Quaternions of equal value. Otherwise it returns false.</returns>
  634. public override bool Equals(object other)
  635. {
  636. if (other is Quaternion == false) return false;
  637. return this == (Quaternion)other;
  638. }
  639. #endregion public override bool Equals (object o)
  640. #region public override int GetHashCode ()
  641. /// <summary>
  642. /// Provides the hash code for this object.
  643. /// </summary>
  644. /// <returns>A hash code formed from the bitwise XOR of this objects members.</returns>
  645. public override int GetHashCode()
  646. {
  647. return new { Xyz.X, Xyz.Y, Xyz.Z, W }.GetHashCode();
  648. }
  649. #endregion public override int GetHashCode ()
  650. #endregion Overrides
  651. #endregion Public Members
  652. #region IEquatable<Quaterniond> Members
  653. /// <summary>
  654. /// Compares this Quaternion instance to another Quaternion for equality.
  655. /// </summary>
  656. /// <param name="other">The other Quaternion to be used in the comparison.</param>
  657. /// <returns>True if both instances are equal; false otherwise.</returns>
  658. public bool Equals(Quaternion other)
  659. {
  660. return Xyz == other.Xyz && W == other.W;
  661. }
  662. #endregion IEquatable<Quaterniond> Members
  663. }
  664. }