/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