PageRenderTime 478ms CodeModel.GetById 121ms app.highlight 177ms RepoModel.GetById 165ms app.codeStats 1ms

/Utilities/Datatypes/Vector.cs

#
C# | 1899 lines | 1064 code | 156 blank | 679 comment | 23 complexity | dbc9c7a13489d6a920ce13d23073319b MD5 | raw file

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

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

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