PageRenderTime 58ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Datatypes/Vector.cs

#
C# | 1899 lines | 1064 code | 156 blank | 679 comment | 23 complexity | dbc9c7a13489d6a920ce13d23073319b MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. using System;
  2. using System.ComponentModel;
  3. using System.Diagnostics;
  4. using System.IO;
  5. using System.Runtime.InteropServices;
  6. using Delta.Utilities.Helpers;
  7. using Delta.Utilities.Profiling;
  8. using NUnit.Framework;
  9. // Disable warnings for some tests where we don't use created values
  10. #pragma warning disable 219
  11. namespace Delta.Utilities.Datatypes
  12. {
  13. /// <summary>
  14. /// Vector class, will be automatically merged with XNA, OpenTK and SlimDx
  15. /// vector classes by the build system for quick access and optimized code
  16. /// paths (as it turns out however it seems most of our own methods are
  17. /// faster than those from XNA, OpenTK or SlimDx, see results below in the
  18. /// VectorPerformance class or more importantly MatrixPerformance).
  19. /// </summary>
  20. [Serializable]
  21. [StructLayout(LayoutKind.Explicit)]
  22. [DebuggerDisplay("Vector=({X}, {Y}, {Z})")]
  23. [Description("Expand to edit this Vector")]
  24. [TypeConverter(typeof(ExpandableObjectConverter))]
  25. public struct Vector : ISaveLoadBinary, IEquatable<Vector>
  26. {
  27. #region Constants
  28. /// <summary>
  29. /// Represents the size in bytes of a Vector (3 * 4 = 12 bytes).
  30. /// </summary>
  31. public const int DataSize = 3 * 4;
  32. /// <summary>
  33. /// Returns a Vector with every value set to 0
  34. /// </summary>
  35. public static readonly Vector Zero =
  36. new Vector(0, 0, 0);
  37. /// <summary>
  38. /// Returns a Vector with every value set to 0.5
  39. /// </summary>
  40. public static readonly Vector Half =
  41. new Vector(0.5f, 0.5f, 0.5f);
  42. /// <summary>
  43. /// Returns a Vector with every value set to 1
  44. /// </summary>
  45. public static readonly Vector One =
  46. new Vector(1, 1, 1);
  47. /// <summary>
  48. /// Returns a unit vector on the X axis (1, 0, 0)
  49. /// </summary>
  50. public static readonly Vector UnitX =
  51. new Vector(1, 0, 0);
  52. /// <summary>
  53. /// Returns a unit vector on the Y axis (0, 1, 0)
  54. /// </summary>
  55. public static readonly Vector UnitY =
  56. new Vector(0, 1, 0);
  57. /// <summary>
  58. /// Returns a unit vector on the Z axis (0, 0, 1)
  59. /// </summary>
  60. public static readonly Vector UnitZ =
  61. new Vector(0, 0, 1);
  62. #endregion
  63. #region Add (Static)
  64. /// <summary>
  65. /// Add the components two vectors
  66. /// </summary>
  67. /// <param name="value1">Vector 1</param>
  68. /// <param name="value2">Vector 2</param>
  69. /// <returns>
  70. /// New vector with X, Y and Z added from value1 and value2.
  71. /// </returns>
  72. public static Vector Add(Vector value1, Vector value2)
  73. {
  74. return new Vector(value1.X + value2.X, value1.Y + value2.Y,
  75. value1.Z + value2.Z);
  76. }
  77. /// <summary>
  78. /// Add the components two vectors
  79. /// </summary>
  80. /// <param name="value1">Vector 1</param>
  81. /// <param name="value2">Vector 2</param>
  82. /// <param name="result">
  83. /// New vector with X, Y and Z added from value1 and value2.
  84. /// </param>
  85. public static void Add(ref Vector value1, ref Vector value2,
  86. out Vector result)
  87. {
  88. result = new Vector
  89. {
  90. X = value1.X + value2.X,
  91. Y = value1.Y + value2.Y,
  92. Z = value1.Z + value2.Z
  93. };
  94. }
  95. #endregion
  96. #region Subtract (Static)
  97. /// <summary>
  98. /// Subtract
  99. /// </summary>
  100. /// <param name="value1">Vector 1</param>
  101. /// <param name="value2">Vector 2</param>
  102. /// <param name="result">
  103. /// New vector with X, Y and Z value2 values subtracted from value1.
  104. /// </param>
  105. public static void Subtract(ref Vector value1, ref Vector value2,
  106. out Vector result)
  107. {
  108. result = new Vector
  109. {
  110. X = value1.X - value2.X,
  111. Y = value1.Y - value2.Y,
  112. Z = value1.Z - value2.Z
  113. };
  114. }
  115. #endregion
  116. #region Multiply (Static)
  117. /// <summary>
  118. /// Multiply the components of a vector with the specified factor.
  119. /// </summary>
  120. /// <param name="scaleFactor">scale factor</param>
  121. /// <param name="value1">value 1</param>
  122. /// <returns>Multiplied vector</returns>
  123. public static Vector Multiply(Vector value1, float scaleFactor)
  124. {
  125. return new Vector
  126. {
  127. X = value1.X * scaleFactor,
  128. Y = value1.Y * scaleFactor,
  129. Z = value1.Z * scaleFactor
  130. };
  131. }
  132. /// <summary>
  133. /// Multiply the components of a vector with the specified factor.
  134. /// </summary>
  135. /// <param name="value">Vector value</param>
  136. /// <param name="scaleFactor">scale factor</param>
  137. /// <param name="result">Multiplied vector</param>
  138. public static void Multiply(ref Vector value, float scaleFactor,
  139. ref Vector result)
  140. {
  141. result.X = value.X * scaleFactor;
  142. result.Y = value.Y * scaleFactor;
  143. result.Z = value.Z * scaleFactor;
  144. }
  145. /// <summary>
  146. /// Multiply the components of two vectors
  147. /// </summary>
  148. /// <param name="value1">value 1</param>
  149. /// <param name="value2">value 2</param>
  150. /// <returns>Multiplied vector</returns>
  151. public static Vector Multiply(Vector value1, Vector value2)
  152. {
  153. return new Vector(value1.X * value2.X, value1.Y * value2.Y,
  154. value1.Z * value2.Z);
  155. }
  156. #endregion
  157. #region Divide (Static)
  158. /// <summary>
  159. /// Divide vector through a value
  160. /// </summary>
  161. /// <param name="value1">value 1</param>
  162. /// <param name="value2">value 2</param>
  163. /// <param name="result">Divided vector</param>
  164. public static void Divide(ref Vector value1, float value2,
  165. ref Vector result)
  166. {
  167. float num = 1.0f / value2;
  168. result.X = value1.X * num;
  169. result.Y = value1.Y * num;
  170. result.Z = value1.Z * num;
  171. }
  172. #endregion
  173. #region Negate (Static)
  174. /// <summary>
  175. /// Negate
  176. /// </summary>
  177. /// <param name="value">Vector value to negate</param>
  178. /// <param name="result">Negated vector</param>
  179. public static void Negate(ref Vector value, ref Vector result)
  180. {
  181. result.X = -value.X;
  182. result.Y = -value.Y;
  183. result.Z = -value.Z;
  184. }
  185. #endregion
  186. #region Min (Static)
  187. /// <summary>
  188. /// Return minimum values from 2 vectors (x, y, and z are checked
  189. /// separately). If you use XNA, SlimDX or Delta's fallback code than a
  190. /// vector containing the smallest values will be returned.
  191. /// OpenTK would return the vector with the smallest DistanceSquared,
  192. /// which is wrong for us and won't be used!
  193. /// </summary>
  194. /// <param name="value1">value 1</param>
  195. /// <param name="value2">value 2</param>
  196. /// <returns>minimum values from 2 vectors</returns>
  197. public static Vector Min(Vector value1, Vector value2)
  198. {
  199. return new Vector(
  200. value1.X < value2.X
  201. ? value1.X
  202. : value2.X,
  203. value1.Y < value2.Y
  204. ? value1.Y
  205. : value2.Y,
  206. value1.Z < value2.Z
  207. ? value1.Z
  208. : value2.Z);
  209. }
  210. /// <summary>
  211. /// Minimum
  212. /// </summary>
  213. /// <param name="result">result</param>
  214. /// <param name="value1">value 1</param>
  215. /// <param name="value2">value 2</param>
  216. public static void Min(ref Vector value1, ref Vector value2,
  217. ref Vector result)
  218. {
  219. result.X = (value1.X < value2.X)
  220. ? value1.X
  221. : value2.X;
  222. result.Y = (value1.Y < value2.Y)
  223. ? value1.Y
  224. : value2.Y;
  225. result.Z = (value1.Z < value2.Z)
  226. ? value1.Z
  227. : value2.Z;
  228. }
  229. #endregion
  230. #region Max (Static)
  231. /// <summary>
  232. /// Return maximum values from 2 vectors (largest x, y and z values).
  233. /// If you use XNA, SlimDX or Delta's fallback code than a vector
  234. /// containing the largest values will be returned.
  235. /// OpenTK would return the vector with the biggest DistanceSquared,
  236. /// which is wrong for us and won't be used!
  237. /// </summary>
  238. /// <param name="value1">value 1</param>
  239. /// <param name="value2">value 2</param>
  240. /// <returns>maximum values from 2 vectors</returns>
  241. public static Vector Max(Vector value1, Vector value2)
  242. {
  243. return new Vector(
  244. value1.X > value2.X
  245. ? value1.X
  246. : value2.X,
  247. value1.Y > value2.Y
  248. ? value1.Y
  249. : value2.Y,
  250. value1.Z > value2.Z
  251. ? value1.Z
  252. : value2.Z);
  253. }
  254. /// <summary>
  255. /// Maximum
  256. /// </summary>
  257. /// <param name="result">result</param>
  258. /// <param name="value1">value 1</param>
  259. /// <param name="value2">value 2</param>
  260. public static void Max(ref Vector value1, ref Vector value2,
  261. ref Vector result)
  262. {
  263. result.X = (value1.X > value2.X)
  264. ? value1.X
  265. : value2.X;
  266. result.Y = (value1.Y > value2.Y)
  267. ? value1.Y
  268. : value2.Y;
  269. result.Z = (value1.Z > value2.Z)
  270. ? value1.Z
  271. : value2.Z;
  272. }
  273. #endregion
  274. #region Dot (Static)
  275. /// <summary>
  276. /// Dot product of 2 vectors, will return 1 if vectors are equal,
  277. /// and 0 if vectors are orthogonal (90 degrees) and -1 if vectors
  278. /// pointing into opposite directions.
  279. /// </summary>
  280. /// <param name="vector1">Vector 1</param>
  281. /// <param name="vector2">Vector 2</param>
  282. /// <returns>Dot product</returns>
  283. public static float Dot(Vector vector1, Vector vector2)
  284. {
  285. return
  286. vector1.X * vector2.X +
  287. vector1.Y * vector2.Y +
  288. vector1.Z * vector2.Z;
  289. }
  290. /// <summary>
  291. /// Dot product of 2 vectors, will return 1 if vectors are equal,
  292. /// and 0 if vectors are orthogonal (90 degrees) and -1 if vectors
  293. /// pointing into opposite directions.
  294. /// </summary>
  295. /// <param name="vector1">Vector 1</param>
  296. /// <param name="vector2">Vector 2</param>
  297. /// <param name="result">Dot product</param>
  298. public static void Dot(ref Vector vector1, ref Vector vector2,
  299. out float result)
  300. {
  301. result = (vector1.X * vector2.X) + (vector1.Y * vector2.Y) +
  302. (vector1.Z * vector2.Z);
  303. }
  304. #endregion
  305. #region Clamp (Static)
  306. /// <summary>
  307. /// Clamp. Computing the closest point in an bounding box to a point.
  308. /// Notice that if the point is already inside the box, then this code
  309. /// returns the original point.
  310. /// </summary>
  311. /// <param name="value1">Vector value to clamp</param>
  312. /// <param name="max">
  313. /// Maximum vector (each component is checked individually)
  314. /// </param>
  315. /// <param name="min">
  316. /// Minimum vector (each component is checked individually)
  317. /// </param>
  318. /// <returns>
  319. /// Clamped vector that has all components between min and max.
  320. /// </returns>
  321. public static Vector Clamp(Vector value1, Vector min, Vector max)
  322. {
  323. float x = value1.X;
  324. x = (x > max.X)
  325. ? max.X
  326. : x;
  327. x = (x < min.X)
  328. ? min.X
  329. : x;
  330. float y = value1.Y;
  331. y = (y > max.Y)
  332. ? max.Y
  333. : y;
  334. y = (y < min.Y)
  335. ? min.Y
  336. : y;
  337. float z = value1.Z;
  338. z = (z > max.Z)
  339. ? max.Z
  340. : z;
  341. z = (z < min.Z)
  342. ? min.Z
  343. : z;
  344. return new Vector(x, y, z);
  345. }
  346. /// <summary>
  347. /// Clamp. Computing the closest point in an bounding box to a point.
  348. /// Notice that if the point is already inside the box, then this code
  349. /// returns the original point.
  350. /// </summary>
  351. /// <param name="value1">Vector value to clamp</param>
  352. /// <param name="max">
  353. /// Maximum vector (each component is checked individually)
  354. /// </param>
  355. /// <param name="min">
  356. /// Minimum vector (each component is checked individually)
  357. /// </param>
  358. /// <param name="result">
  359. /// Clamped vector that has all components between min and max.
  360. /// </param>
  361. public static void Clamp(ref Vector value1, ref Vector min,
  362. ref Vector max, ref Vector result)
  363. {
  364. float x = value1.X;
  365. x = (x > max.X)
  366. ? max.X
  367. : x;
  368. x = (x < min.X)
  369. ? min.X
  370. : x;
  371. float y = value1.Y;
  372. y = (y > max.Y)
  373. ? max.Y
  374. : y;
  375. y = (y < min.Y)
  376. ? min.Y
  377. : y;
  378. float z = value1.Z;
  379. z = (z > max.Z)
  380. ? max.Z
  381. : z;
  382. z = (z < min.Z)
  383. ? min.Z
  384. : z;
  385. result.X = x;
  386. result.Y = y;
  387. result.Z = z;
  388. }
  389. #endregion
  390. #region Cross (Static)
  391. /// <summary>
  392. /// Cross product of vector1 and vector2. Please note that if your vectors
  393. /// are not normalized or they are not orthogonal to each other, you should
  394. /// normalize the result if it is used for other calculations requiring
  395. /// normalized vectors (e.g. camera code or for billboards).
  396. /// </summary>
  397. /// <param name="vector1">Vector 1</param>
  398. /// <param name="vector2">Vector 2</param>
  399. /// <returns>Cross product between vector 1 and 2</returns>
  400. public static Vector Cross(Vector vector1, Vector vector2)
  401. {
  402. return new Vector(
  403. vector1.Y * vector2.Z - vector1.Z * vector2.Y,
  404. vector1.Z * vector2.X - vector1.X * vector2.Z,
  405. vector1.X * vector2.Y - vector1.Y * vector2.X);
  406. }
  407. /// <summary>
  408. /// Cross product of vector1 and vector2. Please note that if your vectors
  409. /// are not normalized or they are not orthogonal to each other, you should
  410. /// normalize the result if it is used for other calculations requiring
  411. /// normalized vectors (e.g. camera code or for billboards).
  412. /// </summary>
  413. /// <param name="vector1">Vector 1</param>
  414. /// <param name="vector2">Vector 2</param>
  415. /// <param name="result">Cross product between vector 1 and 2</param>
  416. public static void Cross(ref Vector vector1, ref Vector vector2,
  417. ref Vector result)
  418. {
  419. result.X = (vector1.Y * vector2.Z) - (vector1.Z * vector2.Y);
  420. result.Y = (vector1.Z * vector2.X) - (vector1.X * vector2.Z);
  421. result.Z = (vector1.X * vector2.Y) - (vector1.Y * vector2.X);
  422. }
  423. #endregion
  424. #region Distance (Static)
  425. /// <summary>
  426. /// Distance between two points (DistanceSquared is faster)
  427. /// </summary>
  428. /// <param name="value1">Vector 1</param>
  429. /// <param name="value2">Vector 2</param>
  430. /// <returns>Distance between vectors</returns>
  431. public static float Distance(Vector value1, Vector value2)
  432. {
  433. float distX = value1.X - value2.X;
  434. float distY = value1.Y - value2.Y;
  435. float distZ = value1.Z - value2.Z;
  436. float distSquared = distX * distX + distY * distY + distZ * distZ;
  437. return MathHelper.Sqrt(distSquared);
  438. }
  439. /// <summary>
  440. /// Distance between two points (DistanceSquared is faster)
  441. /// </summary>
  442. /// <param name="value1">Vector 1</param>
  443. /// <param name="value2">Vector 2</param>
  444. /// <param name="result">Distance between vectors</param>
  445. public static void Distance(ref Vector value1, ref Vector value2,
  446. out float result)
  447. {
  448. float distX = value1.X - value2.X;
  449. float distY = value1.Y - value2.Y;
  450. float distZ = value1.Z - value2.Z;
  451. float distSquared = distX * distX + distY * distY + distZ * distZ;
  452. result = MathHelper.Sqrt(distSquared);
  453. }
  454. #endregion
  455. #region DistanceSquared (Static)
  456. /// <summary>
  457. /// Distance squared
  458. /// </summary>
  459. /// <param name="value1">Vector 1</param>
  460. /// <param name="value2">Vector 2</param>
  461. /// <returns>Squared distance between vectors</returns>
  462. public static float DistanceSquared(Vector value1, Vector value2)
  463. {
  464. float distX = value1.X - value2.X;
  465. float distY = value1.Y - value2.Y;
  466. float distZ = value1.Z - value2.Z;
  467. return distX * distX + distY * distY + distZ * distZ;
  468. }
  469. /// <summary>
  470. /// Distance squared
  471. /// </summary>
  472. /// <param name="value1">Vector 1</param>
  473. /// <param name="value2">Vector 2</param>
  474. /// <param name="result">Squared distance between vectors</param>
  475. public static void DistanceSquared(ref Vector value1, ref Vector value2,
  476. out float result)
  477. {
  478. float distX = value1.X - value2.X;
  479. float distY = value1.Y - value2.Y;
  480. float distZ = value1.Z - value2.Z;
  481. result = (distX * distX) + (distY * distY) + (distZ * distZ);
  482. }
  483. #endregion
  484. #region Normalize (Static)
  485. /// <summary>
  486. /// Normalize the given vector and return the normalized version of it.
  487. /// </summary>
  488. /// <param name="value">Vector to normalize</param>
  489. /// <returns>Normalized vector</returns>
  490. public static Vector Normalize(Vector value)
  491. {
  492. float lengthSquared = value.LengthSquared;
  493. if (lengthSquared == 0)
  494. {
  495. return value;
  496. }
  497. float distanceInverse = 1.0f / MathHelper.Sqrt(lengthSquared);
  498. return new Vector(
  499. value.X * distanceInverse,
  500. value.Y * distanceInverse,
  501. value.Z * distanceInverse);
  502. }
  503. /// <summary>
  504. /// Normalize the given vector.
  505. /// </summary>
  506. /// <param name="value">
  507. /// Vector to normalize, will be normalized after calling this method.
  508. /// </param>
  509. public static void Normalize(ref Vector value)
  510. {
  511. float distanceSquared = value.LengthSquared;
  512. if (distanceSquared != 0.0f)
  513. {
  514. float distanceInverse = 1.0f / MathHelper.Sqrt(distanceSquared);
  515. value.X *= distanceInverse;
  516. value.Y *= distanceInverse;
  517. value.Z *= distanceInverse;
  518. }
  519. }
  520. #endregion
  521. #region TransformNormal (Static)
  522. /// <summary>
  523. /// Transform normal (a Vector3 version of Transform, that won't use the
  524. /// translation part of the matrix).
  525. /// </summary>
  526. /// <param name="normal">Normal to transform</param>
  527. /// <param name="matrix">Matrix for the transformation</param>
  528. /// <returns>Transformed normal vector</returns>
  529. public static Vector TransformNormal(Vector normal, Matrix matrix)
  530. {
  531. //Check performance difference again:
  532. return new Vector(
  533. // X
  534. (normal.X * matrix.M11) +
  535. (normal.Y * matrix.M21) +
  536. (normal.Z * matrix.M31),
  537. // Y
  538. (normal.X * matrix.M12) +
  539. (normal.Y * matrix.M22) +
  540. (normal.Z * matrix.M32),
  541. // Z
  542. (normal.X * matrix.M13) +
  543. (normal.Y * matrix.M23) +
  544. (normal.Z * matrix.M33));
  545. }
  546. /// <summary>
  547. /// Transform normal (a Vector3 version of Transform, that won't use the
  548. /// translation part of the matrix).
  549. /// </summary>
  550. /// <param name="normal">
  551. /// The normal vector which will be transformed by the matrix.
  552. /// </param>
  553. /// <param name="matrix">
  554. /// The matrix used for transforming the provided vector.
  555. /// </param>
  556. /// <param name="result">The resulting transformed normal vector.</param>
  557. public static void TransformNormal(ref Vector normal, ref Matrix matrix,
  558. ref Vector result)
  559. {
  560. //Check performance difference again:
  561. result.X =
  562. (normal.X * matrix.M11) +
  563. (normal.Y * matrix.M21) +
  564. (normal.Z * matrix.M31);
  565. result.Y =
  566. (normal.X * matrix.M12) +
  567. (normal.Y * matrix.M22) +
  568. (normal.Z * matrix.M32);
  569. result.Z =
  570. (normal.X * matrix.M13) +
  571. (normal.Y * matrix.M23) +
  572. (normal.Z * matrix.M33);
  573. }
  574. #endregion
  575. #region Transform (Static)
  576. /// <summary>
  577. /// Transform the given vector by the matrix. Note: This method is slower
  578. /// than the ref version, which should be used for performance critical
  579. /// code!
  580. /// </summary>
  581. /// <param name="position">Position vector to transform</param>
  582. /// <param name="matrix">Matrix for the transformation</param>
  583. /// <returns>Transformed vector</returns>
  584. public static Vector Transform(Vector position, Matrix matrix)
  585. {
  586. //Check performance difference again:
  587. return new Vector(
  588. // X
  589. (position.X * matrix.M11) + (position.Y * matrix.M21) +
  590. (position.Z * matrix.M31) + matrix.M41,
  591. // Y
  592. (position.X * matrix.M12) + (position.Y * matrix.M22) +
  593. (position.Z * matrix.M32) + matrix.M42,
  594. // Z
  595. (position.X * matrix.M13) + (position.Y * matrix.M23) +
  596. (position.Z * matrix.M33) + matrix.M43);
  597. }
  598. /// <summary>
  599. /// Transform the given vector by the matrix (faster ref version).
  600. /// </summary>
  601. /// <param name="position">Position vector to transform</param>
  602. /// <param name="matrix">Matrix for the transformation</param>
  603. /// <param name="result">Transformed vector</param>
  604. public static void Transform(ref Vector position, ref Matrix matrix,
  605. out Vector result)
  606. {
  607. //Check performance difference again:
  608. result.X =
  609. (position.X * matrix.M11) +
  610. (position.Y * matrix.M21) +
  611. (position.Z * matrix.M31) +
  612. matrix.M41;
  613. result.Y =
  614. (position.X * matrix.M12) +
  615. (position.Y * matrix.M22) +
  616. (position.Z * matrix.M32) +
  617. matrix.M42;
  618. result.Z =
  619. (position.X * matrix.M13) +
  620. (position.Y * matrix.M23) +
  621. (position.Z * matrix.M33) +
  622. matrix.M43;
  623. }
  624. #endregion
  625. #region AngleBetweenVectors (Static)
  626. /// <summary>
  627. /// Angle between vectors in degrees.
  628. /// http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
  629. /// RadiansToDegrees(atan2(a.y,a.x) - atan2(b.y,b.x)) would only give
  630. /// you 0-180 degrees, but we want full 0-360 degrees with Acos :)
  631. /// <para />
  632. /// Note: If one of the vectors is zero the method we will return 0.0f.
  633. /// </summary>
  634. /// <param name="a">First vector.</param>
  635. /// <param name="b">Second vector.</param>
  636. /// <returns>Angle between the two vectors in the range [0, 360]</returns>
  637. public static float AngleBetweenVectors(Vector a, Vector b)
  638. {
  639. #region Validation
  640. // Having a single zero vector in this method will cause the calculation
  641. // to return 90 degrees which is not right. So we simply return 0f.
  642. if (a == Zero ||
  643. b == Zero)
  644. {
  645. return 0f;
  646. }
  647. #endregion
  648. // We need to normalize the vectors so we get the cos from 0 to 1
  649. // the cos is the dot product of the vectors a and b
  650. float cos = Dot(Normalize(a), Normalize(b));
  651. cos = MathHelper.Clamp(cos, -1.0f, 1.0f);
  652. // NOTE: Special way for 2D vector handling of this
  653. // RadiansToDegrees(atan2(a.y,a.x) - atan2(b.y,b.x))
  654. Vector cross = Cross(a, b);
  655. return cross.Z < 0.0f
  656. ? // cross products directory is upwards
  657. 360 - MathHelper.Acos(cos)
  658. : // else
  659. MathHelper.Acos(cos);
  660. }
  661. #endregion
  662. #region Lerp (Static)
  663. /// <summary>
  664. /// Performs a linear interpolation between two vectors.
  665. /// </summary>
  666. /// <param name="value1">Vector 1</param>
  667. /// <param name="value2">Vector 2</param>
  668. /// <param name="amount">Interpolation amount</param>
  669. /// <returns>Interpolated vector between vector 1 and 2</returns>
  670. public static Vector Lerp(Vector value1, Vector value2, float amount)
  671. {
  672. return new Vector(
  673. MathHelper.Lerp(value1.X, value2.X, amount),
  674. MathHelper.Lerp(value1.Y, value2.Y, amount),
  675. MathHelper.Lerp(value1.Z, value2.Z, amount));
  676. }
  677. /// <summary>
  678. /// Performs a linear interpolation between two vectors.
  679. /// </summary>
  680. /// <param name="value1">Vector 1</param>
  681. /// <param name="value2">Vector 2</param>
  682. /// <param name="amount">Interpolation amount</param>
  683. /// <param name="result">Interpolated vector between vector 1 and 2</param>
  684. public static void Lerp(ref Vector value1, ref Vector value2,
  685. float amount, out Vector result)
  686. {
  687. result = new Vector(
  688. MathHelper.Lerp(value1.X, value2.X, amount),
  689. MathHelper.Lerp(value1.Y, value2.Y, amount),
  690. MathHelper.Lerp(value1.Z, value2.Z, amount));
  691. }
  692. #endregion
  693. #region GetByIndex (Static)
  694. /// <summary>
  695. /// Get a vector side (X, Y or Z) by index (0, 1 or 2).
  696. /// </summary>
  697. /// <param name="index">
  698. /// Index, 0 for X, 1 for Y, 2 for Z, all other values will thrown an
  699. /// IndexOutOfRangeException
  700. /// </param>
  701. /// <param name="vec">Vector for the X, Y or Z values.</param>
  702. /// <exception cref="IndexOutOfRangeException">
  703. /// If index is outside of 0-2.
  704. /// </exception>
  705. /// <returns>X, Y or Z value depending on the index.</returns>
  706. /// <exception cref="IndexOutOfRangeException">
  707. /// Throws index out of range exception if index is not 0, 1 or 2.
  708. /// </exception>
  709. public static float GetByIndex(ref Vector vec, int index)
  710. {
  711. switch (index)
  712. {
  713. case 0:
  714. return vec.X;
  715. case 1:
  716. return vec.Y;
  717. case 2:
  718. return vec.Z;
  719. default:
  720. throw new IndexOutOfRangeException();
  721. }
  722. }
  723. #endregion
  724. #region FromString (Static)
  725. /// <summary>
  726. /// Convert a string to a Vector. The expected format is (x.x, y.y, z.z)
  727. /// </summary>
  728. /// <param name="vectorString">The string containing the values in the
  729. /// correct format.</param>
  730. /// <returns>Vector from string if possible, otherwise Zero</returns>
  731. public static Vector FromString(string vectorString)
  732. {
  733. // Remove the brackets and split the string up into separate values.
  734. vectorString = vectorString.Replace("(", "");
  735. vectorString = vectorString.Replace(")", "");
  736. string[] vectorStrings = vectorString.Split(new[]
  737. {
  738. ',', ' '
  739. },
  740. StringSplitOptions.RemoveEmptyEntries);
  741. // Then check if the length is 3 for 3 values and return the new vector.
  742. // If the length is not 3 than return Vector.Zero.
  743. if (vectorStrings.Length == 3)
  744. {
  745. return new Vector(
  746. vectorStrings[0].FromInvariantString(0.0f),
  747. vectorStrings[1].FromInvariantString(0.0f),
  748. vectorStrings[2].FromInvariantString(0.0f));
  749. }
  750. return Zero;
  751. }
  752. #endregion
  753. #region Framework Union Defines (Public)
  754. #endregion
  755. #region X (Public)
  756. /// <summary>
  757. /// X coordinate. FieldOffset means that we use the defined float in our
  758. /// union vector and value 0 means the first float
  759. /// </summary>
  760. [FieldOffset(0)]
  761. public float X;
  762. #endregion
  763. #region Y (Public)
  764. /// <summary>
  765. /// Y coordinate. FieldOffset means that we use the defined float in our
  766. /// union vector and value 4 means the second float (4 bytes per float).
  767. /// </summary>
  768. [FieldOffset(4)]
  769. public float Y;
  770. #endregion
  771. #region Z (Public)
  772. /// <summary>
  773. /// Z coordinate. FieldOffset means that we use the defined float in our
  774. /// union vector and value 8 means the third float (4 bytes per float).
  775. /// </summary>
  776. [FieldOffset(8)]
  777. public float Z;
  778. #endregion
  779. #region XProperty (Public)
  780. /// <summary>
  781. /// Property-wrapper for using the X field in the editor.
  782. /// </summary>
  783. [Browsable(true)]
  784. [DisplayName("X")]
  785. public float XProperty
  786. {
  787. get
  788. {
  789. return X;
  790. }
  791. set
  792. {
  793. X = value;
  794. }
  795. }
  796. #endregion
  797. #region YProperty (Public)
  798. /// <summary>
  799. /// Property-wrapper for using the Y field in the editor
  800. /// </summary>
  801. [Browsable(true)]
  802. [DisplayName("Y")]
  803. public float YProperty
  804. {
  805. get
  806. {
  807. return Y;
  808. }
  809. set
  810. {
  811. Y = value;
  812. }
  813. }
  814. #endregion
  815. #region ZProperty (Public)
  816. /// <summary>
  817. /// Property-wrapper for using the Z field in the editor
  818. /// </summary>
  819. [Browsable(true)]
  820. [DisplayName("Z")]
  821. public float ZProperty
  822. {
  823. get
  824. {
  825. return Z;
  826. }
  827. set
  828. {
  829. Z = value;
  830. }
  831. }
  832. #endregion
  833. #region Length (Public)
  834. /// <summary>
  835. /// The length of the vector. This takes the square root and thus is
  836. /// slower than using LengthSquared.
  837. /// </summary>
  838. [Browsable(false)]
  839. public float Length
  840. {
  841. get
  842. {
  843. return MathHelper.Sqrt(X * X + Y * Y + Z * Z);
  844. }
  845. }
  846. #endregion
  847. #region LengthSquared (Public)
  848. /// <summary>
  849. /// Length squared, much faster than using Length because we do not
  850. /// have to take the square root.
  851. /// </summary>
  852. [Browsable(false)]
  853. public float LengthSquared
  854. {
  855. get
  856. {
  857. return X * X + Y * Y + Z * Z;
  858. }
  859. }
  860. #endregion
  861. #region IsNormalized (Public)
  862. /// <summary>
  863. /// Is normalized? Will return true if the vector length is 1.0
  864. /// </summary>
  865. [Browsable(false)]
  866. public bool IsNormalized
  867. {
  868. get
  869. {
  870. return MathHelper.Abs(LengthSquared - 1.0f) <
  871. MathHelper.Epsilon * MathHelper.Epsilon;
  872. }
  873. }
  874. #endregion
  875. #region Constructors
  876. /// <summary>
  877. /// Create vector
  878. /// </summary>
  879. /// <param name="value">value</param>
  880. /// <param name="z">z</param>
  881. public Vector(Point value, float z)
  882. : this()
  883. {
  884. X = value.X;
  885. Y = value.Y;
  886. Z = z;
  887. }
  888. /// <summary>
  889. /// Create vector
  890. /// </summary>
  891. /// <param name="setX">Set x</param>
  892. /// <param name="setY">Set y</param>
  893. /// <param name="setZ">Set z</param>
  894. public Vector(float setX, float setY, float setZ)
  895. : this()
  896. {
  897. X = setX;
  898. Y = setY;
  899. Z = setZ;
  900. }
  901. /// <summary>
  902. /// Create vector
  903. /// </summary>
  904. /// <param name="reader">reader</param>
  905. public Vector(BinaryReader reader)
  906. : this()
  907. {
  908. Load(reader);
  909. }
  910. #endregion
  911. #region IEquatable<Vector> Members
  912. /// <summary>
  913. /// Equals
  914. /// </summary>
  915. /// <param name="other">Other</param>
  916. /// <returns>Value indicating the equality of two vectors</returns>
  917. public bool Equals(Vector other)
  918. {
  919. return X == other.X &&
  920. Y == other.Y &&
  921. Z == other.Z;
  922. }
  923. #endregion
  924. #region ISaveLoadBinary Members
  925. /// <summary>
  926. /// Load all vector values from a stream (reads 12 bytes, 3 floats)
  927. /// </summary>
  928. /// <param name="reader">The stream that will be used.</param>
  929. public void Load(BinaryReader reader)
  930. {
  931. X = reader.ReadSingle();
  932. Y = reader.ReadSingle();
  933. Z = reader.ReadSingle();
  934. }
  935. /// <summary>
  936. /// Saves this vector to a stream (12 bytes, 3 floats).
  937. /// </summary>
  938. /// <param name="writer">The stream that will be used.</param>
  939. public void Save(BinaryWriter writer)
  940. {
  941. writer.Write(X);
  942. writer.Write(Y);
  943. writer.Write(Z);
  944. }
  945. #endregion
  946. #region op_Equality (Operator)
  947. /// <summary>
  948. /// Check for equality
  949. /// </summary>
  950. /// <param name="value1">Vector 1</param>
  951. /// <param name="value2">Vector 2</param>
  952. /// <returns>True if the vectors are equal</returns>
  953. public static bool operator ==(Vector value1, Vector value2)
  954. {
  955. return
  956. value1.X == value2.X &&
  957. value1.Y == value2.Y &&
  958. value1.Z == value2.Z;
  959. }
  960. #endregion
  961. #region op_Inequality (Operator)
  962. /// <summary>
  963. /// Check for inequality
  964. /// </summary>
  965. /// <param name="value1">Vector 1</param>
  966. /// <param name="value2">Vector 2</param>
  967. /// <returns>True if the vectors are not equal.</returns>
  968. public static bool operator !=(Vector value1, Vector value2)
  969. {
  970. return
  971. value1.X != value2.X ||
  972. value1.Y != value2.Y ||
  973. value1.Z != value2.Z;
  974. }
  975. #endregion
  976. #region op_Addition (Operator)
  977. /// <summary>
  978. /// Operator for addition
  979. /// </summary>
  980. /// <param name="value1">Vector 1</param>
  981. /// <param name="value2">Vector 2</param>
  982. /// <returns>
  983. /// New vector with X, Y and Z values added from value1 and value2.
  984. /// </returns>
  985. public static Vector operator +(Vector value1, Vector value2)
  986. {
  987. return new Vector(
  988. value1.X + value2.X,
  989. value1.Y + value2.Y,
  990. value1.Z + value2.Z);
  991. }
  992. #endregion
  993. #region op_UnaryNegation (Operator)
  994. /// <summary>
  995. /// Operator for unary negation
  996. /// </summary>
  997. /// <param name="value">Vector value</param>
  998. /// <returns>Negated vector</returns>
  999. public static Vector operator -(Vector value)
  1000. {
  1001. return new Vector(-value.X, -value.Y, -value.Z);
  1002. }
  1003. #endregion
  1004. #region op_Subtraction (Operator)
  1005. /// <summary>
  1006. /// Operator for subtraction
  1007. /// </summary>
  1008. /// <param name="value1">Vector 1</param>
  1009. /// <param name="value2">Vector 2</param>
  1010. /// <returns>X, Y and Z of value2 subtracted from value1</returns>
  1011. public static Vector operator -(Vector value1, Vector value2)
  1012. {
  1013. return new Vector(
  1014. value1.X - value2.X,
  1015. value1.Y - value2.Y,
  1016. value1.Z - value2.Z);
  1017. }
  1018. #endregion
  1019. #region op_Multiply (Operator)
  1020. /// <summary>
  1021. /// Operator for multiplication
  1022. /// </summary>
  1023. /// <param name="value1">Vector 1</param>
  1024. /// <param name="value2">Vector 2</param>
  1025. /// <returns>Dot product, which is the multiplication result</returns>
  1026. public static float operator *(Vector value1, Vector value2)
  1027. {
  1028. float result;
  1029. Dot(ref value1, ref value2, out result);
  1030. return result;
  1031. }
  1032. /// <summary>
  1033. /// Operator for multiplication
  1034. /// </summary>
  1035. /// <param name="value">Vector value</param>
  1036. /// <param name="scaleFactor">Scale factor</param>
  1037. /// <returns>Multiplication result</returns>
  1038. public static Vector operator *(Vector value, float scaleFactor)
  1039. {
  1040. return new Vector(
  1041. value.X * scaleFactor,
  1042. value.Y * scaleFactor,
  1043. value.Z * scaleFactor);
  1044. }
  1045. /// <summary>
  1046. /// Operator for multiplication
  1047. /// </summary>
  1048. /// <param name="scaleFactor">Scale factor</param>
  1049. /// <param name="value">Vector value</param>
  1050. /// <returns>Multiplication result</returns>
  1051. public static Vector operator *(float scaleFactor, Vector value)
  1052. {
  1053. return value * scaleFactor;
  1054. }
  1055. /// <summary>
  1056. /// Operator for multiplication
  1057. /// </summary>
  1058. /// <param name="value">Vector value</param>
  1059. /// <param name="transformMatrix">Transformation matrix</param>
  1060. /// <returns>Multiplication result</returns>
  1061. public static Vector operator *(Vector value, Matrix transformMatrix)
  1062. {
  1063. Vector rotatedVector = TransformNormal(value, transformMatrix);
  1064. return transformMatrix.Translation + rotatedVector;
  1065. }
  1066. #endregion
  1067. #region op_Division (Operator)
  1068. /// <summary>
  1069. /// Operator for division
  1070. /// </summary>
  1071. /// <param name="value">Vector value</param>
  1072. /// <param name="scaleFactor">Scale factor</param>
  1073. /// <returns>Division result</returns>
  1074. public static Vector operator /(Vector value, float scaleFactor)
  1075. {
  1076. return new Vector(
  1077. value.X / scaleFactor,
  1078. value.Y / scaleFactor,
  1079. value.Z / scaleFactor);
  1080. }
  1081. /// <summary>
  1082. /// Op multiply
  1083. /// </summary>
  1084. /// <param name="scaleFactor">Scale factor</param>
  1085. /// <param name="value">Vector value</param>
  1086. /// <returns>Division result</returns>
  1087. public static Vector operator /(float scaleFactor, Vector value)
  1088. {
  1089. return value / scaleFactor;
  1090. }
  1091. #endregion
  1092. #region Normalize (Public)
  1093. /// <summary>
  1094. /// Normalize this vector.
  1095. /// </summary>
  1096. public void Normalize()
  1097. {
  1098. float distanceSquared = LengthSquared;
  1099. if (distanceSquared != 0)
  1100. {
  1101. float distanceInverse = 1.0f / MathHelper.Sqrt(distanceSquared);
  1102. X *= distanceInverse;
  1103. Y *= distanceInverse;
  1104. Z *= distanceInverse;
  1105. }
  1106. }
  1107. #endregion
  1108. #region GetByIndex (Public)
  1109. /// <summary>
  1110. /// Get a vector side (X, Y or Z) by index (0, 1 or 2).
  1111. /// </summary>
  1112. /// <param name="index">
  1113. /// Index, 0 for X, 1 for Y, 2 for Z, all other values will thrown an
  1114. /// IndexOutOfRangeException
  1115. /// </param>
  1116. /// <exception cref="IndexOutOfRangeException">
  1117. /// If index is outside of 0-2.
  1118. /// </exception>
  1119. /// <returns>X, Y or Z value depending on the index.</returns>
  1120. /// <exception cref="IndexOutOfRangeException">Unsupported index</exception>
  1121. public float GetByIndex(int index)
  1122. {
  1123. switch (index)
  1124. {
  1125. case 0:
  1126. return X;
  1127. case 1:
  1128. return Y;
  1129. case 2:
  1130. return Z;
  1131. default:
  1132. throw new IndexOutOfRangeException();
  1133. }
  1134. }
  1135. #endregion
  1136. #region GetHashCode (Public)
  1137. /// <summary>
  1138. /// Get hash code
  1139. /// </summary>
  1140. /// <returns>Hash code from X, Y and Z</returns>
  1141. public override int GetHashCode()
  1142. {
  1143. return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();
  1144. }
  1145. #endregion
  1146. #region NearlyEquals (Public)
  1147. /// <summary>
  1148. /// Equals
  1149. /// </summary>
  1150. /// <param name="other">Other</param>
  1151. /// <param name="epsilon">Epsilon difference we allow for
  1152. /// floating imprecission</param>
  1153. /// <returns>Value indicating the equality of two vectors</returns>
  1154. public bool NearlyEquals(Vector other, float epsilon)
  1155. {
  1156. return
  1157. // Allow a difference of the Epsilon (in both directions)
  1158. // for the X value range
  1159. X - epsilon <= other.X &&
  1160. X + epsilon >= other.X &&
  1161. // and Y value range
  1162. Y - epsilon <= other.Y &&
  1163. Y + epsilon >= other.Y &&
  1164. // and Z value range
  1165. Z - epsilon <= other.Z &&
  1166. Z + epsilon >= other.Z;
  1167. }
  1168. #endregion
  1169. #region Equals (Public)
  1170. /// <summary>
  1171. /// Equals
  1172. /// </summary>
  1173. /// <param name="obj">Object to check against</param>
  1174. /// <returns>True if obj is a Vector and is equal to this vector.</returns>
  1175. public override bool Equals(object obj)
  1176. {
  1177. if (obj is Vector)
  1178. {
  1179. return Equals((Vector)obj);
  1180. }
  1181. return base.Equals(obj);
  1182. }
  1183. #endregion
  1184. #region ToPoint (Public)
  1185. /// <summary>
  1186. /// Creates a Point from the X and Y values
  1187. /// </summary>
  1188. /// <returns>Point created from X and Y values of this vector.</returns>
  1189. public Point ToPoint()
  1190. {
  1191. return new Point(X, Y);
  1192. }
  1193. #endregion
  1194. #region ToArray (Public)
  1195. /// <summary>
  1196. /// Returns the vector as float array (X, Y, Z)
  1197. /// </summary>
  1198. /// <returns>
  1199. /// Array with just X, Y and Z float values created from this Vector.
  1200. /// </returns>
  1201. public float[] ToArray()
  1202. {
  1203. return new[]
  1204. {
  1205. X, Y, Z
  1206. };
  1207. }
  1208. #endregion
  1209. #region ToString (Public)
  1210. /// <summary>
  1211. /// To string, also used for the old ToColladaString method, this
  1212. /// is precise enough to be used for saving collada files.
  1213. /// </summary>
  1214. /// <returns>
  1215. /// Text string with the vector in braces, e.g. "(0.4, 2.8)"
  1216. /// </returns>
  1217. public override string ToString()
  1218. {
  1219. return ToString("(", ")");
  1220. }
  1221. /// <summary>
  1222. /// To string, also used for the old ToColladaString method, this
  1223. /// is precise enough to be used for saving collada files.
  1224. /// </summary>
  1225. /// <param name="openBrace">Add open brace string, e.g. "("</param>
  1226. /// <param name="closeBrace">Add close brace string, e.g. ")"</param>
  1227. /// <returns>String with X, Y and Z values with the format 0.0000</returns>
  1228. public string ToString(string openBrace, string closeBrace)
  1229. {
  1230. return
  1231. openBrace + X.ToInvariantString("0.0000") +
  1232. ", " + Y.ToInvariantString("0.0000") +
  1233. ", " + Z.ToInvariantString("0.0000") + closeBrace;
  1234. }
  1235. #endregion
  1236. /// <summary>
  1237. /// Tests
  1238. /// </summary>
  1239. internal class VectorTests
  1240. {
  1241. #region SizeOf (Static)
  1242. /// <summary>
  1243. /// Checks if the size of Point is exactly 8 bytes (2 floats: X and Y)
  1244. /// </summary>
  1245. [Test]
  1246. public static void SizeOf()
  1247. {
  1248. // Vector consists of 3 floats: X, Y and Z
  1249. Assert.Equal(3 * 4, Marshal.SizeOf(typeof(Vector)));
  1250. }
  1251. #endregion
  1252. #region Length (Static)
  1253. /// <summary>
  1254. /// Length
  1255. /// </summary>
  1256. [Test]
  1257. public static void Length()
  1258. {
  1259. Assert.Equal(5, new Vector(0, 0, 5).Length);
  1260. Assert.Equal(1, new Vector(0, 1, 0).Length);
  1261. Assert.Equal(4, new Vector(4, 0, 0).Length);
  1262. Assert.Equal(MathHelper.Sqrt(18), new Vector(3, 3, 0).Length);
  1263. }
  1264. #endregion
  1265. #region LengthSquared (Static)
  1266. /// <summary>
  1267. /// Length squared
  1268. /// </summary>
  1269. [Test]
  1270. public static void LengthSquared()
  1271. {
  1272. Assert.Equal(25, new Vector(0, 0, 5).LengthSquared);
  1273. Assert.Equal(1, new Vector(0, 1, 0).LengthSquared);
  1274. Assert.Equal(16, new Vector(4, 0, 0).LengthSquared);
  1275. Assert.Equal(18, new Vector(3, 3, 0).LengthSquared);
  1276. }
  1277. #endregion
  1278. #region AngleBetweenVectors (Static)
  1279. /// <summary>
  1280. /// Angle between vectors
  1281. /// </summary>
  1282. [Test]
  1283. public static void AngleBetweenVectors()
  1284. {
  1285. Assert.NearlyEqual(0,
  1286. Vector.AngleBetweenVectors(UnitX, UnitX));
  1287. Assert.NearlyEqual(180,
  1288. Vector.AngleBetweenVectors(UnitX, -UnitX));
  1289. Assert.NearlyEqual(90,
  1290. Vector.AngleBetweenVectors(UnitX, UnitY));
  1291. Assert.NearlyEqual(270,
  1292. Vector.AngleBetweenVectors(UnitX, -UnitY));
  1293. Assert.NearlyEqual(225,
  1294. Vector.AngleBetweenVectors(UnitX, new Vector(-1, -1, 0)));
  1295. // Special cases with zero vectors!
  1296. Assert.NearlyEqual(0,
  1297. Vector.AngleBetweenVectors(Zero, UnitX));
  1298. Assert.NearlyEqual(0,
  1299. Vector.AngleBetweenVectors(Zero, Zero));
  1300. }
  1301. #endregion
  1302. #region NearlyEqual (Static)
  1303. /// <summary>
  1304. /// Nearly equal
  1305. /// </summary>
  1306. [Test]
  1307. public static void NearlyEqual()
  1308. {
  1309. // We need here for testing a smaller epsilon, because of the float
  1310. // incorrectness
  1311. const float testEpsilon = MathHelper.Epsilon * 0.01f;
  1312. Vector testVector = new Vector(5, 12, 5);
  1313. //test the equality normally
  1314. Assert.True(new Vector(5, 12, 5).Equals(testVector));
  1315. //test the vector as "object"
  1316. Assert.True(new Vector(5, 12, 5).Equals((object)testVector));
  1317. //check the vectors with epsilon as allowed difference
  1318. Assert.True(testVector.NearlyEquals(
  1319. new Vector(5 + testEpsilon, 12, 5 - testEpsilon), testEpsilon));
  1320. //check the bad case
  1321. Assert.False(testVector.NearlyEquals(
  1322. new Vector(5 + (2 * testEpsilon), 12, 5 - testEpsilon),
  1323. testEpsilon));
  1324. }
  1325. #endregion
  1326. #region ToPoint (Static)
  1327. /// <summary>
  1328. /// To string
  1329. /// </summary>
  1330. [Test]
  1331. public static void ToPoint()
  1332. {
  1333. Assert.Equal(new Point(23, 45),
  1334. new Vector(23, 45, 14).ToPoint());
  1335. }
  1336. #endregion
  1337. #region Equality
  1338. /// <summary>
  1339. /// Equality
  1340. /// </summary>
  1341. [Test]
  1342. public void Equality()
  1343. {
  1344. Vector testVector = new Vector(32, 65, 32);
  1345. Assert.Equal(new Vector(32, 65, 32), testVector);
  1346. Assert.NotEqual(testVector, new Vector(0, 65, 32));
  1347. }
  1348. #endregion
  1349. #region Addition
  1350. /// <summary>
  1351. /// Addition
  1352. /// </summary>
  1353. [Test]
  1354. public void Addition()
  1355. {
  1356. Vector testVector = new Vector(32, 65, 32);
  1357. Assert.Equal(new Vector(64, 130, 64), testVector + testVector);
  1358. Assert.Equal(new Vector(32, 66.45f, 34),
  1359. testVector + new Vector(0, 1.45f, 2f));
  1360. }
  1361. #endregion
  1362. #region Substraction
  1363. /// <summary>
  1364. /// Substraction
  1365. /// </summary>
  1366. [Test]
  1367. public void Substraction()
  1368. {
  1369. Vector testVector = new Vector(32, 65, 32);
  1370. Assert.Equal(new Vector(0, 0, 0), testVector - testVector);
  1371. Assert.Equal(new Vector(32, 63.55f, 30),
  1372. testVector - new Vector(0, 1.45f, 2f));
  1373. }
  1374. #endregion
  1375. #region Multiplication
  1376. /// <summary>
  1377. /// Multiplication
  1378. /// </summary>
  1379. [Test]
  1380. public void Multiplication()
  1381. {
  1382. Assert.Equal(Vector.Dot(new Vector(5, 5, 5), new Vector(2, 2.5f, 4)),
  1383. new Vector(5, 5, 5) * new Vector(2, 2.5f, 4));
  1384. //check with vector and scale factor
  1385. Assert.Equal(new Vector(5, 2.5f, 16), new Vector(10, 5, 32) * 0.5f);
  1386. //check with vector and scale factor
  1387. Assert.Equal(new Vector(5, 2.5f, 16), 0.5f * new Vector(10, 5, 32));
  1388. }
  1389. #endregion
  1390. #region Division
  1391. /// <summary>
  1392. /// Multiplication
  1393. /// </summary>
  1394. [Test]
  1395. public void Division()
  1396. {
  1397. //check with vector and scale factor
  1398. Assert.Equal(new Vector(20, 10, 64), new Vector(10, 5, 32) / 0.5f);
  1399. //check with vector and scale factor
  1400. Assert.Equal(new Vector(20, 10, 64), 0.5f / new Vector(10, 5, 32));
  1401. }
  1402. #endregion
  1403. #region Min
  1404. /// <summary>
  1405. /// Minimum
  1406. /// </summary>
  1407. [Test]
  1408. public void Min()
  1409. {
  1410. Assert.Equal(new Vector(43, 0, 32),
  1411. Vector.Min(new Vector(43, 3, 32), new Vector(50, 0, 40)));
  1412. }
  1413. #endregion
  1414. #region Max
  1415. /// <summary>
  1416. /// Maximum
  1417. /// </summary>
  1418. [Test]
  1419. public void Max()
  1420. {
  1421. Assert.Equal(new Vector(50, 3, 40),
  1422. Vector.Max(new Vector(43, 3, 32), new Vector(50, 0, 40)));
  1423. }
  1424. #endregion
  1425. #region Dot
  1426. /// <summary>
  1427. /// Dot
  1428. /// </summary>
  1429. [Test]
  1430. public void Dot()
  1431. {
  1432. Assert.Equal(42.5f,
  1433. Vector.Dot(new Vector(5, 5, 5), new Vector(2, 2.5f, 4)));
  1434. }
  1435. #endregion
  1436. #region Clamp
  1437. /// <summary>
  1438. /// Clamp
  1439. /// </summary>
  1440. [Test]
  1441. public void Clamp()
  1442. {
  1443. Assert.Equal(new Vector(6, 2.6f, 86),
  1444. Vector.Clamp(new Vector(5, 3, 86), new Vector(6, 2, 50),
  1445. new Vector(10, 2.6f, 86)));
  1446. }
  1447. #endregion
  1448. #region Cross
  1449. /// <summary>
  1450. /// Cross
  1451. /// </summary>
  1452. [Test]
  1453. public void Cross()
  1454. {
  1455. Assert.Equal(new Vector(-11, -7, 20),
  1456. Vector.Cross(new Vector(4, 8, 5), new Vector(1, 7, 3)));
  1457. }
  1458. #endregion
  1459. #region Distance
  1460. /// <summary>
  1461. /// Distance
  1462. /// </summary>
  1463. [Test]
  1464. public void Distance()
  1465. {
  1466. Vector testVector1 = new Vector(5, 10, 4);
  1467. Vector testVector2 = new Vector(1, 5, 3);
  1468. Assert.Equal(MathHelper.Sqrt(42), Vector.Distance(testVector1, testVector2));
  1469. }
  1470. #endregion
  1471. #region DistanceSquared
  1472. /// <summary>
  1473. /// Distance squared
  1474. /// </summary>
  1475. [Test]
  1476. public void DistanceSquared()
  1477. {
  1478. Vector testVector1 = new Vector(5, 10, 4);
  1479. Vector testVector2 = new Vector(1, 5, 3);
  1480. Assert.Equal(42, Vector.DistanceSquared(testVector1, testVector2));
  1481. }
  1482. #endregion
  1483. #region Normalize
  1484. /// <summary>
  1485. /// Normalize
  1486. /// </summary>
  1487. [Test]
  1488. public void Normalize()
  1489. {
  1490. Vector testVector = new Vector(1, 5, 3);
  1491. testVector.Normalize();
  1492. Assert.NotEqual(new Vector(1, 5, 3), testVector);
  1493. testVector = new Vector(0, 0, -100);
  1494. testVector.Normalize();
  1495. Assert.Equal(new Vector(0, 0, -1), testVector);
  1496. }
  1497. #endregion
  1498. #region TransformNormal
  1499. /// <summary>
  1500. /// Transform normal
  1501. /// </summary>
  1502. [Test]
  1503. public void TransformNormal()
  1504. {
  1505. Matrix testMatrix = new Matrix(
  1506. 4, 7, 2, 0,
  1507. 4, 3, 8, 5,
  1508. 4, 2, 8, 4,
  1509. 2, 1, 8, 4);
  1510. Vector testVector = new Vector(4, 8, 1);
  1511. Assert.Equal(new Vector(52, 54, 80),
  1512. Vector.TransformNormal(testVector, testMatrix));
  1513. }
  1514. #endregion
  1515. #region VectorToString
  1516. /// <summary>
  1517. /// To string
  1518. /// </summary>
  1519. [Test]
  1520. public void VectorToString()
  1521. {
  1522. Assert.Equal("(23.0000, 45.0000, 5.0000)",
  1523. new Vector(23, 45, 5).ToString());
  1524. }
  1525. #endregion
  1526. }
  1527. /// <summary>
  1528. /// Vector performance class to figure out performance differences between
  1529. /// different implementations of Vector methods available on different
  1530. /// platforms and in different frameworks.
  1531. /// </summary>
  1532. [NUnit.Framework.Category("LongRunning")]
  1533. public class VectorPerformance
  1534. {
  1535. #region TestLength Performance
  1536. /// <summary>
  1537. /// Test the length property of the Vector class.
  1538. /// </summary>
  1539. [Test]
  1540. public static void TestLength()
  1541. {
  1542. Vector testVector = new Vector(10, 20, 30);
  1543. // Results (Release)
  1544. // -------
  1545. // 2010-04-08
  1546. // Delta: x ms
  1547. // XNA: 350 ms
  1548. // OpenTK: x ms
  1549. // SlimDx: x ms
  1550. float length = 0;
  1551. PerformanceTester.Profile10MilionTimes("Vector.Length", delegate
  1552. {
  1553. length = testVector.Length;
  1554. });
  1555. Assert.Equal(length, testVector.Length);
  1556. // Results (Release)
  1557. // -------
  1558. // 2010-04-08
  1559. // Delta: x ms
  1560. // XNA: 350 ms
  1561. // OpenTK: x ms
  1562. // SlimDx: x ms
  1563. float lengthSquared = 0;
  1564. PerformanceTester.Profile10MilionTimes("Vector.LengthSquared", delegate
  1565. {
  1566. lengthSquared = testVector.LengthSquared;
  1567. });
  1568. Assert.Equal(lengthSquared, testVector.LengthSquared);
  1569. }
  1570. #endregion
  1571. #region TestDot Performance
  1572. /// <summary>
  1573. /// Test the dot method of the vector struct.
  1574. /// </summary>
  1575. [Test]
  1576. public static void TestDot()
  1577. {
  1578. Vector testVector1 = new Vector(10, 20, 30);
  1579. Vector testVector2 = new Vector(3, 2, 1);
  1580. // Results (Release)
  1581. // -------
  1582. // 2010-04-08
  1583. // Delta: x ms
  1584. // XNA: 350 ms
  1585. // OpenTK: x ms
  1586. // SlimDx: x ms
  1587. float dot = 0;
  1588. PerformanceTester.Profile10MilionTimes("Vector.Dot", delegate
  1589. {
  1590. dot = Dot(testVector1, testVector2);
  1591. });
  1592. Assert.Equal(dot, Dot(testVector1, testVector2));
  1593. }
  1594. #endregion
  1595. #region TestCross Performance
  1596. /// <summary>
  1597. /// Test the cross method of the vector struct.
  1598. /// </summary>
  1599. [Test]
  1600. public static void TestCross()
  1601. {
  1602. Vector testVector1 = new Vector(10, 20, 30);
  1603. Vector testVector2 = new Vector(3, 2, 1);
  1604. // Results (Release)
  1605. // -------
  1606. // 2010-04-08
  1607. // Delta: x ms
  1608. // XNA: 350 ms
  1609. // OpenTK: x ms
  1610. // SlimDx: x ms
  1611. Vector cross = Zero;
  1612. PerformanceTester.Profile10MilionTimes("Vector.Cross", delegate
  1613. {
  1614. cross = Cross(testVector1, testVector2);
  1615. });
  1616. Assert.Equal(cross, Cross(testVector1, testVector2));
  1617. }
  1618. #endregion
  1619. #region TestDistance Performance
  1620. /// <summary>
  1621. /// Test the distance method of the vector struct.
  1622. /// </summary>
  1623. [Test]
  1624. public static void TestDistance()
  1625. {
  1626. Vector testVector1 = new Vector(10, 20, 30);
  1627. Vector testVector2 = new Vector(3, 2, 1);
  1628. // Results (Release)
  1629. // -------
  1630. // 2010-04-08
  1631. // Delta: x ms
  1632. // XNA: 350 ms
  1633. // OpenTK: x ms
  1634. // SlimDx: x ms
  1635. float distance = 0;
  1636. PerformanceTester.Profile10MilionTimes("Vector.Distance", delegate
  1637. {
  1638. distance = Distance(testVector1, testVector2);
  1639. });
  1640. Assert.Equal(distance, Distance(testVector1, testVector2));
  1641. }
  1642. #endregion
  1643. #region TestNormalize Performance
  1644. /// <summary>
  1645. /// Test the normalize method of the vector struct.
  1646. /// </summary>
  1647. [Test]
  1648. public static void TestNormalize()
  1649. {
  1650. Vector testVector1 = new Vector(10, 20, 30);
  1651. // Results (Release)
  1652. // -------
  1653. // 2010-04-08
  1654. // Delta: x ms
  1655. // XNA: 350 ms
  1656. // OpenTK: x ms
  1657. // SlimDx: x ms
  1658. Vector vector = Zero;
  1659. PerformanceTester.Profile10MilionTimes("Vector.Normalize", delegate
  1660. {
  1661. vector = Normalize(testVector1);
  1662. });
  1663. Assert.Equal(vector, Normalize(testVector1));
  1664. }
  1665. #endregion
  1666. #region TestTransformNormal Performance
  1667. /// <summary>
  1668. /// Test the transform …

Large files files are truncated, but you can click here to view the full file