/Utilities/Datatypes/Vector.cs
C# | 1899 lines | 1064 code | 156 blank | 679 comment | 23 complexity | dbc9c7a13489d6a920ce13d23073319b MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.ComponentModel;
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using Delta.Utilities.Helpers;
- using Delta.Utilities.Profiling;
- using NUnit.Framework;
-
-
- // Disable warnings for some tests where we don't use created values
- #pragma warning disable 219
-
- namespace Delta.Utilities.Datatypes
- {
- /// <summary>
- /// Vector class, will be automatically merged with XNA, OpenTK and SlimDx
- /// vector classes by the build system for quick access and optimized code
- /// paths (as it turns out however it seems most of our own methods are
- /// faster than those from XNA, OpenTK or SlimDx, see results below in the
- /// VectorPerformance class or more importantly MatrixPerformance).
- /// </summary>
- [Serializable]
- [StructLayout(LayoutKind.Explicit)]
- [DebuggerDisplay("Vector=({X}, {Y}, {Z})")]
- [Description("Expand to edit this Vector")]
- [TypeConverter(typeof(ExpandableObjectConverter))]
- public struct Vector : ISaveLoadBinary, IEquatable<Vector>
- {
- #region Constants
- /// <summary>
- /// Represents the size in bytes of a Vector (3 * 4 = 12 bytes).
- /// </summary>
- public const int DataSize = 3 * 4;
-
- /// <summary>
- /// Returns a Vector with every value set to 0
- /// </summary>
- public static readonly Vector Zero =
- new Vector(0, 0, 0);
-
- /// <summary>
- /// Returns a Vector with every value set to 0.5
- /// </summary>
- public static readonly Vector Half =
- new Vector(0.5f, 0.5f, 0.5f);
-
- /// <summary>
- /// Returns a Vector with every value set to 1
- /// </summary>
- public static readonly Vector One =
- new Vector(1, 1, 1);
-
- /// <summary>
- /// Returns a unit vector on the X axis (1, 0, 0)
- /// </summary>
- public static readonly Vector UnitX =
- new Vector(1, 0, 0);
-
- /// <summary>
- /// Returns a unit vector on the Y axis (0, 1, 0)
- /// </summary>
- public static readonly Vector UnitY =
- new Vector(0, 1, 0);
-
- /// <summary>
- /// Returns a unit vector on the Z axis (0, 0, 1)
- /// </summary>
- public static readonly Vector UnitZ =
- new Vector(0, 0, 1);
- #endregion
-
- #region Add (Static)
- /// <summary>
- /// Add the components two vectors
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>
- /// New vector with X, Y and Z added from value1 and value2.
- /// </returns>
- public static Vector Add(Vector value1, Vector value2)
- {
- return new Vector(value1.X + value2.X, value1.Y + value2.Y,
- value1.Z + value2.Z);
- }
-
- /// <summary>
- /// Add the components two vectors
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="result">
- /// New vector with X, Y and Z added from value1 and value2.
- /// </param>
- public static void Add(ref Vector value1, ref Vector value2,
- out Vector result)
- {
- result = new Vector
- {
- X = value1.X + value2.X,
- Y = value1.Y + value2.Y,
- Z = value1.Z + value2.Z
- };
- }
- #endregion
-
- #region Subtract (Static)
- /// <summary>
- /// Subtract
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="result">
- /// New vector with X, Y and Z value2 values subtracted from value1.
- /// </param>
- public static void Subtract(ref Vector value1, ref Vector value2,
- out Vector result)
- {
- result = new Vector
- {
- X = value1.X - value2.X,
- Y = value1.Y - value2.Y,
- Z = value1.Z - value2.Z
- };
- }
- #endregion
-
- #region Multiply (Static)
- /// <summary>
- /// Multiply the components of a vector with the specified factor.
- /// </summary>
- /// <param name="scaleFactor">scale factor</param>
- /// <param name="value1">value 1</param>
- /// <returns>Multiplied vector</returns>
- public static Vector Multiply(Vector value1, float scaleFactor)
- {
- return new Vector
- {
- X = value1.X * scaleFactor,
- Y = value1.Y * scaleFactor,
- Z = value1.Z * scaleFactor
- };
- }
-
- /// <summary>
- /// Multiply the components of a vector with the specified factor.
- /// </summary>
- /// <param name="value">Vector value</param>
- /// <param name="scaleFactor">scale factor</param>
- /// <param name="result">Multiplied vector</param>
- public static void Multiply(ref Vector value, float scaleFactor,
- ref Vector result)
- {
- result.X = value.X * scaleFactor;
- result.Y = value.Y * scaleFactor;
- result.Z = value.Z * scaleFactor;
- }
-
- /// <summary>
- /// Multiply the components of two vectors
- /// </summary>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- /// <returns>Multiplied vector</returns>
- public static Vector Multiply(Vector value1, Vector value2)
- {
- return new Vector(value1.X * value2.X, value1.Y * value2.Y,
- value1.Z * value2.Z);
- }
- #endregion
-
- #region Divide (Static)
- /// <summary>
- /// Divide vector through a value
- /// </summary>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- /// <param name="result">Divided vector</param>
- public static void Divide(ref Vector value1, float value2,
- ref Vector result)
- {
- float num = 1.0f / value2;
- result.X = value1.X * num;
- result.Y = value1.Y * num;
- result.Z = value1.Z * num;
- }
- #endregion
-
- #region Negate (Static)
- /// <summary>
- /// Negate
- /// </summary>
- /// <param name="value">Vector value to negate</param>
- /// <param name="result">Negated vector</param>
- public static void Negate(ref Vector value, ref Vector result)
- {
- result.X = -value.X;
- result.Y = -value.Y;
- result.Z = -value.Z;
- }
- #endregion
-
- #region Min (Static)
- /// <summary>
- /// Return minimum values from 2 vectors (x, y, and z are checked
- /// separately). If you use XNA, SlimDX or Delta's fallback code than a
- /// vector containing the smallest values will be returned.
- /// OpenTK would return the vector with the smallest DistanceSquared,
- /// which is wrong for us and won't be used!
- /// </summary>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- /// <returns>minimum values from 2 vectors</returns>
- public static Vector Min(Vector value1, Vector value2)
- {
- return new Vector(
- value1.X < value2.X
- ? value1.X
- : value2.X,
- value1.Y < value2.Y
- ? value1.Y
- : value2.Y,
- value1.Z < value2.Z
- ? value1.Z
- : value2.Z);
- }
-
- /// <summary>
- /// Minimum
- /// </summary>
- /// <param name="result">result</param>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- public static void Min(ref Vector value1, ref Vector value2,
- ref Vector result)
- {
- result.X = (value1.X < value2.X)
- ? value1.X
- : value2.X;
- result.Y = (value1.Y < value2.Y)
- ? value1.Y
- : value2.Y;
- result.Z = (value1.Z < value2.Z)
- ? value1.Z
- : value2.Z;
- }
- #endregion
-
- #region Max (Static)
- /// <summary>
- /// Return maximum values from 2 vectors (largest x, y and z values).
- /// If you use XNA, SlimDX or Delta's fallback code than a vector
- /// containing the largest values will be returned.
- /// OpenTK would return the vector with the biggest DistanceSquared,
- /// which is wrong for us and won't be used!
- /// </summary>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- /// <returns>maximum values from 2 vectors</returns>
- public static Vector Max(Vector value1, Vector value2)
- {
- return new Vector(
- value1.X > value2.X
- ? value1.X
- : value2.X,
- value1.Y > value2.Y
- ? value1.Y
- : value2.Y,
- value1.Z > value2.Z
- ? value1.Z
- : value2.Z);
- }
-
- /// <summary>
- /// Maximum
- /// </summary>
- /// <param name="result">result</param>
- /// <param name="value1">value 1</param>
- /// <param name="value2">value 2</param>
- public static void Max(ref Vector value1, ref Vector value2,
- ref Vector result)
- {
- result.X = (value1.X > value2.X)
- ? value1.X
- : value2.X;
- result.Y = (value1.Y > value2.Y)
- ? value1.Y
- : value2.Y;
- result.Z = (value1.Z > value2.Z)
- ? value1.Z
- : value2.Z;
- }
- #endregion
-
- #region Dot (Static)
- /// <summary>
- /// Dot product of 2 vectors, will return 1 if vectors are equal,
- /// and 0 if vectors are orthogonal (90 degrees) and -1 if vectors
- /// pointing into opposite directions.
- /// </summary>
- /// <param name="vector1">Vector 1</param>
- /// <param name="vector2">Vector 2</param>
- /// <returns>Dot product</returns>
- public static float Dot(Vector vector1, Vector vector2)
- {
- return
- vector1.X * vector2.X +
- vector1.Y * vector2.Y +
- vector1.Z * vector2.Z;
- }
-
- /// <summary>
- /// Dot product of 2 vectors, will return 1 if vectors are equal,
- /// and 0 if vectors are orthogonal (90 degrees) and -1 if vectors
- /// pointing into opposite directions.
- /// </summary>
- /// <param name="vector1">Vector 1</param>
- /// <param name="vector2">Vector 2</param>
- /// <param name="result">Dot product</param>
- public static void Dot(ref Vector vector1, ref Vector vector2,
- out float result)
- {
- result = (vector1.X * vector2.X) + (vector1.Y * vector2.Y) +
- (vector1.Z * vector2.Z);
- }
- #endregion
-
- #region Clamp (Static)
- /// <summary>
- /// Clamp. Computing the closest point in an bounding box to a point.
- /// Notice that if the point is already inside the box, then this code
- /// returns the original point.
- /// </summary>
- /// <param name="value1">Vector value to clamp</param>
- /// <param name="max">
- /// Maximum vector (each component is checked individually)
- /// </param>
- /// <param name="min">
- /// Minimum vector (each component is checked individually)
- /// </param>
- /// <returns>
- /// Clamped vector that has all components between min and max.
- /// </returns>
- public static Vector Clamp(Vector value1, Vector min, Vector max)
- {
- float x = value1.X;
- x = (x > max.X)
- ? max.X
- : x;
- x = (x < min.X)
- ? min.X
- : x;
- float y = value1.Y;
- y = (y > max.Y)
- ? max.Y
- : y;
- y = (y < min.Y)
- ? min.Y
- : y;
- float z = value1.Z;
- z = (z > max.Z)
- ? max.Z
- : z;
- z = (z < min.Z)
- ? min.Z
- : z;
-
- return new Vector(x, y, z);
- }
-
- /// <summary>
- /// Clamp. Computing the closest point in an bounding box to a point.
- /// Notice that if the point is already inside the box, then this code
- /// returns the original point.
- /// </summary>
- /// <param name="value1">Vector value to clamp</param>
- /// <param name="max">
- /// Maximum vector (each component is checked individually)
- /// </param>
- /// <param name="min">
- /// Minimum vector (each component is checked individually)
- /// </param>
- /// <param name="result">
- /// Clamped vector that has all components between min and max.
- /// </param>
- public static void Clamp(ref Vector value1, ref Vector min,
- ref Vector max, ref Vector result)
- {
- float x = value1.X;
- x = (x > max.X)
- ? max.X
- : x;
- x = (x < min.X)
- ? min.X
- : x;
- float y = value1.Y;
- y = (y > max.Y)
- ? max.Y
- : y;
- y = (y < min.Y)
- ? min.Y
- : y;
- float z = value1.Z;
- z = (z > max.Z)
- ? max.Z
- : z;
- z = (z < min.Z)
- ? min.Z
- : z;
- result.X = x;
- result.Y = y;
- result.Z = z;
- }
- #endregion
-
- #region Cross (Static)
- /// <summary>
- /// Cross product of vector1 and vector2. Please note that if your vectors
- /// are not normalized or they are not orthogonal to each other, you should
- /// normalize the result if it is used for other calculations requiring
- /// normalized vectors (e.g. camera code or for billboards).
- /// </summary>
- /// <param name="vector1">Vector 1</param>
- /// <param name="vector2">Vector 2</param>
- /// <returns>Cross product between vector 1 and 2</returns>
- public static Vector Cross(Vector vector1, Vector vector2)
- {
- return new Vector(
- vector1.Y * vector2.Z - vector1.Z * vector2.Y,
- vector1.Z * vector2.X - vector1.X * vector2.Z,
- vector1.X * vector2.Y - vector1.Y * vector2.X);
- }
-
- /// <summary>
- /// Cross product of vector1 and vector2. Please note that if your vectors
- /// are not normalized or they are not orthogonal to each other, you should
- /// normalize the result if it is used for other calculations requiring
- /// normalized vectors (e.g. camera code or for billboards).
- /// </summary>
- /// <param name="vector1">Vector 1</param>
- /// <param name="vector2">Vector 2</param>
- /// <param name="result">Cross product between vector 1 and 2</param>
- public static void Cross(ref Vector vector1, ref Vector vector2,
- ref Vector result)
- {
- result.X = (vector1.Y * vector2.Z) - (vector1.Z * vector2.Y);
- result.Y = (vector1.Z * vector2.X) - (vector1.X * vector2.Z);
- result.Z = (vector1.X * vector2.Y) - (vector1.Y * vector2.X);
- }
- #endregion
-
- #region Distance (Static)
- /// <summary>
- /// Distance between two points (DistanceSquared is faster)
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>Distance between vectors</returns>
- public static float Distance(Vector value1, Vector value2)
- {
- float distX = value1.X - value2.X;
- float distY = value1.Y - value2.Y;
- float distZ = value1.Z - value2.Z;
- float distSquared = distX * distX + distY * distY + distZ * distZ;
- return MathHelper.Sqrt(distSquared);
- }
-
- /// <summary>
- /// Distance between two points (DistanceSquared is faster)
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="result">Distance between vectors</param>
- public static void Distance(ref Vector value1, ref Vector value2,
- out float result)
- {
- float distX = value1.X - value2.X;
- float distY = value1.Y - value2.Y;
- float distZ = value1.Z - value2.Z;
- float distSquared = distX * distX + distY * distY + distZ * distZ;
- result = MathHelper.Sqrt(distSquared);
- }
- #endregion
-
- #region DistanceSquared (Static)
- /// <summary>
- /// Distance squared
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>Squared distance between vectors</returns>
- public static float DistanceSquared(Vector value1, Vector value2)
- {
- float distX = value1.X - value2.X;
- float distY = value1.Y - value2.Y;
- float distZ = value1.Z - value2.Z;
- return distX * distX + distY * distY + distZ * distZ;
- }
-
- /// <summary>
- /// Distance squared
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="result">Squared distance between vectors</param>
- public static void DistanceSquared(ref Vector value1, ref Vector value2,
- out float result)
- {
- float distX = value1.X - value2.X;
- float distY = value1.Y - value2.Y;
- float distZ = value1.Z - value2.Z;
- result = (distX * distX) + (distY * distY) + (distZ * distZ);
- }
- #endregion
-
- #region Normalize (Static)
- /// <summary>
- /// Normalize the given vector and return the normalized version of it.
- /// </summary>
- /// <param name="value">Vector to normalize</param>
- /// <returns>Normalized vector</returns>
- public static Vector Normalize(Vector value)
- {
- float lengthSquared = value.LengthSquared;
- if (lengthSquared == 0)
- {
- return value;
- }
-
- float distanceInverse = 1.0f / MathHelper.Sqrt(lengthSquared);
-
- return new Vector(
- value.X * distanceInverse,
- value.Y * distanceInverse,
- value.Z * distanceInverse);
- }
-
- /// <summary>
- /// Normalize the given vector.
- /// </summary>
- /// <param name="value">
- /// Vector to normalize, will be normalized after calling this method.
- /// </param>
- public static void Normalize(ref Vector value)
- {
- float distanceSquared = value.LengthSquared;
-
- if (distanceSquared != 0.0f)
- {
- float distanceInverse = 1.0f / MathHelper.Sqrt(distanceSquared);
- value.X *= distanceInverse;
- value.Y *= distanceInverse;
- value.Z *= distanceInverse;
- }
- }
- #endregion
-
- #region TransformNormal (Static)
- /// <summary>
- /// Transform normal (a Vector3 version of Transform, that won't use the
- /// translation part of the matrix).
- /// </summary>
- /// <param name="normal">Normal to transform</param>
- /// <param name="matrix">Matrix for the transformation</param>
- /// <returns>Transformed normal vector</returns>
- public static Vector TransformNormal(Vector normal, Matrix matrix)
- {
- //Check performance difference again:
-
- return new Vector(
- // X
- (normal.X * matrix.M11) +
- (normal.Y * matrix.M21) +
- (normal.Z * matrix.M31),
- // Y
- (normal.X * matrix.M12) +
- (normal.Y * matrix.M22) +
- (normal.Z * matrix.M32),
- // Z
- (normal.X * matrix.M13) +
- (normal.Y * matrix.M23) +
- (normal.Z * matrix.M33));
- }
-
- /// <summary>
- /// Transform normal (a Vector3 version of Transform, that won't use the
- /// translation part of the matrix).
- /// </summary>
- /// <param name="normal">
- /// The normal vector which will be transformed by the matrix.
- /// </param>
- /// <param name="matrix">
- /// The matrix used for transforming the provided vector.
- /// </param>
- /// <param name="result">The resulting transformed normal vector.</param>
- public static void TransformNormal(ref Vector normal, ref Matrix matrix,
- ref Vector result)
- {
- //Check performance difference again:
-
- result.X =
- (normal.X * matrix.M11) +
- (normal.Y * matrix.M21) +
- (normal.Z * matrix.M31);
-
- result.Y =
- (normal.X * matrix.M12) +
- (normal.Y * matrix.M22) +
- (normal.Z * matrix.M32);
-
- result.Z =
- (normal.X * matrix.M13) +
- (normal.Y * matrix.M23) +
- (normal.Z * matrix.M33);
- }
- #endregion
-
- #region Transform (Static)
- /// <summary>
- /// Transform the given vector by the matrix. Note: This method is slower
- /// than the ref version, which should be used for performance critical
- /// code!
- /// </summary>
- /// <param name="position">Position vector to transform</param>
- /// <param name="matrix">Matrix for the transformation</param>
- /// <returns>Transformed vector</returns>
- public static Vector Transform(Vector position, Matrix matrix)
- {
- //Check performance difference again:
-
- return new Vector(
- // X
- (position.X * matrix.M11) + (position.Y * matrix.M21) +
- (position.Z * matrix.M31) + matrix.M41,
- // Y
- (position.X * matrix.M12) + (position.Y * matrix.M22) +
- (position.Z * matrix.M32) + matrix.M42,
- // Z
- (position.X * matrix.M13) + (position.Y * matrix.M23) +
- (position.Z * matrix.M33) + matrix.M43);
- }
-
- /// <summary>
- /// Transform the given vector by the matrix (faster ref version).
- /// </summary>
- /// <param name="position">Position vector to transform</param>
- /// <param name="matrix">Matrix for the transformation</param>
- /// <param name="result">Transformed vector</param>
- public static void Transform(ref Vector position, ref Matrix matrix,
- out Vector result)
- {
- //Check performance difference again:
-
- result.X =
- (position.X * matrix.M11) +
- (position.Y * matrix.M21) +
- (position.Z * matrix.M31) +
- matrix.M41;
-
- result.Y =
- (position.X * matrix.M12) +
- (position.Y * matrix.M22) +
- (position.Z * matrix.M32) +
- matrix.M42;
-
- result.Z =
- (position.X * matrix.M13) +
- (position.Y * matrix.M23) +
- (position.Z * matrix.M33) +
- matrix.M43;
- }
- #endregion
-
- #region AngleBetweenVectors (Static)
- /// <summary>
- /// Angle between vectors in degrees.
- /// http://www.euclideanspace.com/maths/algebra/vectors/angleBetween/index.htm
- /// RadiansToDegrees(atan2(a.y,a.x) - atan2(b.y,b.x)) would only give
- /// you 0-180 degrees, but we want full 0-360 degrees with Acos :)
- /// <para />
- /// Note: If one of the vectors is zero the method we will return 0.0f.
- /// </summary>
- /// <param name="a">First vector.</param>
- /// <param name="b">Second vector.</param>
- /// <returns>Angle between the two vectors in the range [0, 360]</returns>
- public static float AngleBetweenVectors(Vector a, Vector b)
- {
- #region Validation
- // Having a single zero vector in this method will cause the calculation
- // to return 90 degrees which is not right. So we simply return 0f.
- if (a == Zero ||
- b == Zero)
- {
- return 0f;
- }
- #endregion
-
- // We need to normalize the vectors so we get the cos from 0 to 1
- // the cos is the dot product of the vectors a and b
- float cos = Dot(Normalize(a), Normalize(b));
- cos = MathHelper.Clamp(cos, -1.0f, 1.0f);
-
- // NOTE: Special way for 2D vector handling of this
- // RadiansToDegrees(atan2(a.y,a.x) - atan2(b.y,b.x))
- Vector cross = Cross(a, b);
- return cross.Z < 0.0f
- ? // cross products directory is upwards
- 360 - MathHelper.Acos(cos)
- : // else
- MathHelper.Acos(cos);
- }
- #endregion
-
- #region Lerp (Static)
- /// <summary>
- /// Performs a linear interpolation between two vectors.
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="amount">Interpolation amount</param>
- /// <returns>Interpolated vector between vector 1 and 2</returns>
- public static Vector Lerp(Vector value1, Vector value2, float amount)
- {
- return new Vector(
- MathHelper.Lerp(value1.X, value2.X, amount),
- MathHelper.Lerp(value1.Y, value2.Y, amount),
- MathHelper.Lerp(value1.Z, value2.Z, amount));
- }
-
- /// <summary>
- /// Performs a linear interpolation between two vectors.
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <param name="amount">Interpolation amount</param>
- /// <param name="result">Interpolated vector between vector 1 and 2</param>
- public static void Lerp(ref Vector value1, ref Vector value2,
- float amount, out Vector result)
- {
- result = new Vector(
- MathHelper.Lerp(value1.X, value2.X, amount),
- MathHelper.Lerp(value1.Y, value2.Y, amount),
- MathHelper.Lerp(value1.Z, value2.Z, amount));
- }
- #endregion
-
- #region GetByIndex (Static)
- /// <summary>
- /// Get a vector side (X, Y or Z) by index (0, 1 or 2).
- /// </summary>
- /// <param name="index">
- /// Index, 0 for X, 1 for Y, 2 for Z, all other values will thrown an
- /// IndexOutOfRangeException
- /// </param>
- /// <param name="vec">Vector for the X, Y or Z values.</param>
- /// <exception cref="IndexOutOfRangeException">
- /// If index is outside of 0-2.
- /// </exception>
- /// <returns>X, Y or Z value depending on the index.</returns>
- /// <exception cref="IndexOutOfRangeException">
- /// Throws index out of range exception if index is not 0, 1 or 2.
- /// </exception>
- public static float GetByIndex(ref Vector vec, int index)
- {
- switch (index)
- {
- case 0:
- return vec.X;
-
- case 1:
- return vec.Y;
-
- case 2:
- return vec.Z;
-
- default:
- throw new IndexOutOfRangeException();
- }
- }
- #endregion
-
- #region FromString (Static)
- /// <summary>
- /// Convert a string to a Vector. The expected format is (x.x, y.y, z.z)
- /// </summary>
- /// <param name="vectorString">The string containing the values in the
- /// correct format.</param>
- /// <returns>Vector from string if possible, otherwise Zero</returns>
- public static Vector FromString(string vectorString)
- {
- // Remove the brackets and split the string up into separate values.
- vectorString = vectorString.Replace("(", "");
- vectorString = vectorString.Replace(")", "");
- string[] vectorStrings = vectorString.Split(new[]
- {
- ',', ' '
- },
- StringSplitOptions.RemoveEmptyEntries);
-
- // Then check if the length is 3 for 3 values and return the new vector.
- // If the length is not 3 than return Vector.Zero.
- if (vectorStrings.Length == 3)
- {
- return new Vector(
- vectorStrings[0].FromInvariantString(0.0f),
- vectorStrings[1].FromInvariantString(0.0f),
- vectorStrings[2].FromInvariantString(0.0f));
- }
-
- return Zero;
- }
- #endregion
-
- #region Framework Union Defines (Public)
- #endregion
-
- #region X (Public)
- /// <summary>
- /// X coordinate. FieldOffset means that we use the defined float in our
- /// union vector and value 0 means the first float
- /// </summary>
- [FieldOffset(0)]
- public float X;
- #endregion
-
- #region Y (Public)
- /// <summary>
- /// Y coordinate. FieldOffset means that we use the defined float in our
- /// union vector and value 4 means the second float (4 bytes per float).
- /// </summary>
- [FieldOffset(4)]
- public float Y;
- #endregion
-
- #region Z (Public)
- /// <summary>
- /// Z coordinate. FieldOffset means that we use the defined float in our
- /// union vector and value 8 means the third float (4 bytes per float).
- /// </summary>
- [FieldOffset(8)]
- public float Z;
- #endregion
-
- #region XProperty (Public)
- /// <summary>
- /// Property-wrapper for using the X field in the editor.
- /// </summary>
- [Browsable(true)]
- [DisplayName("X")]
- public float XProperty
- {
- get
- {
- return X;
- }
- set
- {
- X = value;
- }
- }
- #endregion
-
- #region YProperty (Public)
- /// <summary>
- /// Property-wrapper for using the Y field in the editor
- /// </summary>
- [Browsable(true)]
- [DisplayName("Y")]
- public float YProperty
- {
- get
- {
- return Y;
- }
- set
- {
- Y = value;
- }
- }
- #endregion
-
- #region ZProperty (Public)
- /// <summary>
- /// Property-wrapper for using the Z field in the editor
- /// </summary>
- [Browsable(true)]
- [DisplayName("Z")]
- public float ZProperty
- {
- get
- {
- return Z;
- }
- set
- {
- Z = value;
- }
- }
- #endregion
-
- #region Length (Public)
- /// <summary>
- /// The length of the vector. This takes the square root and thus is
- /// slower than using LengthSquared.
- /// </summary>
- [Browsable(false)]
- public float Length
- {
- get
- {
- return MathHelper.Sqrt(X * X + Y * Y + Z * Z);
- }
- }
- #endregion
-
- #region LengthSquared (Public)
- /// <summary>
- /// Length squared, much faster than using Length because we do not
- /// have to take the square root.
- /// </summary>
- [Browsable(false)]
- public float LengthSquared
- {
- get
- {
- return X * X + Y * Y + Z * Z;
- }
- }
- #endregion
-
- #region IsNormalized (Public)
- /// <summary>
- /// Is normalized? Will return true if the vector length is 1.0
- /// </summary>
- [Browsable(false)]
- public bool IsNormalized
- {
- get
- {
- return MathHelper.Abs(LengthSquared - 1.0f) <
- MathHelper.Epsilon * MathHelper.Epsilon;
- }
- }
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create vector
- /// </summary>
- /// <param name="value">value</param>
- /// <param name="z">z</param>
- public Vector(Point value, float z)
- : this()
- {
- X = value.X;
- Y = value.Y;
- Z = z;
- }
-
- /// <summary>
- /// Create vector
- /// </summary>
- /// <param name="setX">Set x</param>
- /// <param name="setY">Set y</param>
- /// <param name="setZ">Set z</param>
- public Vector(float setX, float setY, float setZ)
- : this()
- {
- X = setX;
- Y = setY;
- Z = setZ;
- }
-
- /// <summary>
- /// Create vector
- /// </summary>
- /// <param name="reader">reader</param>
- public Vector(BinaryReader reader)
- : this()
- {
- Load(reader);
- }
- #endregion
-
- #region IEquatable<Vector> Members
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="other">Other</param>
- /// <returns>Value indicating the equality of two vectors</returns>
- public bool Equals(Vector other)
- {
- return X == other.X &&
- Y == other.Y &&
- Z == other.Z;
- }
- #endregion
-
- #region ISaveLoadBinary Members
- /// <summary>
- /// Load all vector values from a stream (reads 12 bytes, 3 floats)
- /// </summary>
- /// <param name="reader">The stream that will be used.</param>
- public void Load(BinaryReader reader)
- {
- X = reader.ReadSingle();
- Y = reader.ReadSingle();
- Z = reader.ReadSingle();
- }
-
- /// <summary>
- /// Saves this vector to a stream (12 bytes, 3 floats).
- /// </summary>
- /// <param name="writer">The stream that will be used.</param>
- public void Save(BinaryWriter writer)
- {
- writer.Write(X);
- writer.Write(Y);
- writer.Write(Z);
- }
- #endregion
-
- #region op_Equality (Operator)
- /// <summary>
- /// Check for equality
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>True if the vectors are equal</returns>
- public static bool operator ==(Vector value1, Vector value2)
- {
- return
- value1.X == value2.X &&
- value1.Y == value2.Y &&
- value1.Z == value2.Z;
- }
- #endregion
-
- #region op_Inequality (Operator)
- /// <summary>
- /// Check for inequality
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>True if the vectors are not equal.</returns>
- public static bool operator !=(Vector value1, Vector value2)
- {
- return
- value1.X != value2.X ||
- value1.Y != value2.Y ||
- value1.Z != value2.Z;
- }
- #endregion
-
- #region op_Addition (Operator)
- /// <summary>
- /// Operator for addition
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>
- /// New vector with X, Y and Z values added from value1 and value2.
- /// </returns>
- public static Vector operator +(Vector value1, Vector value2)
- {
- return new Vector(
- value1.X + value2.X,
- value1.Y + value2.Y,
- value1.Z + value2.Z);
- }
- #endregion
-
- #region op_UnaryNegation (Operator)
- /// <summary>
- /// Operator for unary negation
- /// </summary>
- /// <param name="value">Vector value</param>
- /// <returns>Negated vector</returns>
- public static Vector operator -(Vector value)
- {
- return new Vector(-value.X, -value.Y, -value.Z);
- }
- #endregion
-
- #region op_Subtraction (Operator)
- /// <summary>
- /// Operator for subtraction
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>X, Y and Z of value2 subtracted from value1</returns>
- public static Vector operator -(Vector value1, Vector value2)
- {
- return new Vector(
- value1.X - value2.X,
- value1.Y - value2.Y,
- value1.Z - value2.Z);
- }
- #endregion
-
- #region op_Multiply (Operator)
- /// <summary>
- /// Operator for multiplication
- /// </summary>
- /// <param name="value1">Vector 1</param>
- /// <param name="value2">Vector 2</param>
- /// <returns>Dot product, which is the multiplication result</returns>
- public static float operator *(Vector value1, Vector value2)
- {
- float result;
- Dot(ref value1, ref value2, out result);
- return result;
- }
-
- /// <summary>
- /// Operator for multiplication
- /// </summary>
- /// <param name="value">Vector value</param>
- /// <param name="scaleFactor">Scale factor</param>
- /// <returns>Multiplication result</returns>
- public static Vector operator *(Vector value, float scaleFactor)
- {
- return new Vector(
- value.X * scaleFactor,
- value.Y * scaleFactor,
- value.Z * scaleFactor);
- }
-
- /// <summary>
- /// Operator for multiplication
- /// </summary>
- /// <param name="scaleFactor">Scale factor</param>
- /// <param name="value">Vector value</param>
- /// <returns>Multiplication result</returns>
- public static Vector operator *(float scaleFactor, Vector value)
- {
- return value * scaleFactor;
- }
-
- /// <summary>
- /// Operator for multiplication
- /// </summary>
- /// <param name="value">Vector value</param>
- /// <param name="transformMatrix">Transformation matrix</param>
- /// <returns>Multiplication result</returns>
- public static Vector operator *(Vector value, Matrix transformMatrix)
- {
- Vector rotatedVector = TransformNormal(value, transformMatrix);
- return transformMatrix.Translation + rotatedVector;
- }
- #endregion
-
- #region op_Division (Operator)
- /// <summary>
- /// Operator for division
- /// </summary>
- /// <param name="value">Vector value</param>
- /// <param name="scaleFactor">Scale factor</param>
- /// <returns>Division result</returns>
- public static Vector operator /(Vector value, float scaleFactor)
- {
- return new Vector(
- value.X / scaleFactor,
- value.Y / scaleFactor,
- value.Z / scaleFactor);
- }
-
- /// <summary>
- /// Op multiply
- /// </summary>
- /// <param name="scaleFactor">Scale factor</param>
- /// <param name="value">Vector value</param>
- /// <returns>Division result</returns>
- public static Vector operator /(float scaleFactor, Vector value)
- {
- return value / scaleFactor;
- }
- #endregion
-
- #region Normalize (Public)
- /// <summary>
- /// Normalize this vector.
- /// </summary>
- public void Normalize()
- {
- float distanceSquared = LengthSquared;
- if (distanceSquared != 0)
- {
- float distanceInverse = 1.0f / MathHelper.Sqrt(distanceSquared);
- X *= distanceInverse;
- Y *= distanceInverse;
- Z *= distanceInverse;
- }
- }
- #endregion
-
- #region GetByIndex (Public)
- /// <summary>
- /// Get a vector side (X, Y or Z) by index (0, 1 or 2).
- /// </summary>
- /// <param name="index">
- /// Index, 0 for X, 1 for Y, 2 for Z, all other values will thrown an
- /// IndexOutOfRangeException
- /// </param>
- /// <exception cref="IndexOutOfRangeException">
- /// If index is outside of 0-2.
- /// </exception>
- /// <returns>X, Y or Z value depending on the index.</returns>
- /// <exception cref="IndexOutOfRangeException">Unsupported index</exception>
- public float GetByIndex(int index)
- {
- switch (index)
- {
- case 0:
- return X;
- case 1:
- return Y;
- case 2:
- return Z;
- default:
- throw new IndexOutOfRangeException();
- }
- }
- #endregion
-
- #region GetHashCode (Public)
- /// <summary>
- /// Get hash code
- /// </summary>
- /// <returns>Hash code from X, Y and Z</returns>
- public override int GetHashCode()
- {
- return X.GetHashCode() ^ Y.GetHashCode() ^ Z.GetHashCode();
- }
- #endregion
-
- #region NearlyEquals (Public)
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="other">Other</param>
- /// <param name="epsilon">Epsilon difference we allow for
- /// floating imprecission</param>
- /// <returns>Value indicating the equality of two vectors</returns>
- public bool NearlyEquals(Vector other, float epsilon)
- {
- return
- // Allow a difference of the Epsilon (in both directions)
- // for the X value range
- X - epsilon <= other.X &&
- X + epsilon >= other.X &&
- // and Y value range
- Y - epsilon <= other.Y &&
- Y + epsilon >= other.Y &&
- // and Z value range
- Z - epsilon <= other.Z &&
- Z + epsilon >= other.Z;
- }
- #endregion
-
- #region Equals (Public)
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="obj">Object to check against</param>
- /// <returns>True if obj is a Vector and is equal to this vector.</returns>
- public override bool Equals(object obj)
- {
- if (obj is Vector)
- {
- return Equals((Vector)obj);
- }
- return base.Equals(obj);
- }
- #endregion
-
- #region ToPoint (Public)
- /// <summary>
- /// Creates a Point from the X and Y values
- /// </summary>
- /// <returns>Point created from X and Y values of this vector.</returns>
- public Point ToPoint()
- {
- return new Point(X, Y);
- }
- #endregion
-
- #region ToArray (Public)
- /// <summary>
- /// Returns the vector as float array (X, Y, Z)
- /// </summary>
- /// <returns>
- /// Array with just X, Y and Z float values created from this Vector.
- /// </returns>
- public float[] ToArray()
- {
- return new[]
- {
- X, Y, Z
- };
- }
- #endregion
-
- #region ToString (Public)
- /// <summary>
- /// To string, also used for the old ToColladaString method, this
- /// is precise enough to be used for saving collada files.
- /// </summary>
- /// <returns>
- /// Text string with the vector in braces, e.g. "(0.4, 2.8)"
- /// </returns>
- public override string ToString()
- {
- return ToString("(", ")");
- }
-
- /// <summary>
- /// To string, also used for the old ToColladaString method, this
- /// is precise enough to be used for saving collada files.
- /// </summary>
- /// <param name="openBrace">Add open brace string, e.g. "("</param>
- /// <param name="closeBrace">Add close brace string, e.g. ")"</param>
- /// <returns>String with X, Y and Z values with the format 0.0000</returns>
- public string ToString(string openBrace, string closeBrace)
- {
- return
- openBrace + X.ToInvariantString("0.0000") +
- ", " + Y.ToInvariantString("0.0000") +
- ", " + Z.ToInvariantString("0.0000") + closeBrace;
- }
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class VectorTests
- {
- #region SizeOf (Static)
- /// <summary>
- /// Checks if the size of Point is exactly 8 bytes (2 floats: X and Y)
- /// </summary>
- [Test]
- public static void SizeOf()
- {
- // Vector consists of 3 floats: X, Y and Z
- Assert.Equal(3 * 4, Marshal.SizeOf(typeof(Vector)));
- }
- #endregion
-
- #region Length (Static)
- /// <summary>
- /// Length
- /// </summary>
- [Test]
- public static void Length()
- {
- Assert.Equal(5, new Vector(0, 0, 5).Length);
- Assert.Equal(1, new Vector(0, 1, 0).Length);
- Assert.Equal(4, new Vector(4, 0, 0).Length);
-
- Assert.Equal(MathHelper.Sqrt(18), new Vector(3, 3, 0).Length);
- }
- #endregion
-
- #region LengthSquared (Static)
- /// <summary>
- /// Length squared
- /// </summary>
- [Test]
- public static void LengthSquared()
- {
- Assert.Equal(25, new Vector(0, 0, 5).LengthSquared);
- Assert.Equal(1, new Vector(0, 1, 0).LengthSquared);
- Assert.Equal(16, new Vector(4, 0, 0).LengthSquared);
- Assert.Equal(18, new Vector(3, 3, 0).LengthSquared);
- }
- #endregion
-
- #region AngleBetweenVectors (Static)
- /// <summary>
- /// Angle between vectors
- /// </summary>
- [Test]
- public static void AngleBetweenVectors()
- {
- Assert.NearlyEqual(0,
- Vector.AngleBetweenVectors(UnitX, UnitX));
-
- Assert.NearlyEqual(180,
- Vector.AngleBetweenVectors(UnitX, -UnitX));
-
- Assert.NearlyEqual(90,
- Vector.AngleBetweenVectors(UnitX, UnitY));
-
- Assert.NearlyEqual(270,
- Vector.AngleBetweenVectors(UnitX, -UnitY));
-
- Assert.NearlyEqual(225,
- Vector.AngleBetweenVectors(UnitX, new Vector(-1, -1, 0)));
-
- // Special cases with zero vectors!
- Assert.NearlyEqual(0,
- Vector.AngleBetweenVectors(Zero, UnitX));
-
- Assert.NearlyEqual(0,
- Vector.AngleBetweenVectors(Zero, Zero));
- }
- #endregion
-
- #region NearlyEqual (Static)
- /// <summary>
- /// Nearly equal
- /// </summary>
- [Test]
- public static void NearlyEqual()
- {
- // We need here for testing a smaller epsilon, because of the float
- // incorrectness
- const float testEpsilon = MathHelper.Epsilon * 0.01f;
-
- Vector testVector = new Vector(5, 12, 5);
- //test the equality normally
- Assert.True(new Vector(5, 12, 5).Equals(testVector));
- //test the vector as "object"
- Assert.True(new Vector(5, 12, 5).Equals((object)testVector));
-
- //check the vectors with epsilon as allowed difference
- Assert.True(testVector.NearlyEquals(
- new Vector(5 + testEpsilon, 12, 5 - testEpsilon), testEpsilon));
-
- //check the bad case
- Assert.False(testVector.NearlyEquals(
- new Vector(5 + (2 * testEpsilon), 12, 5 - testEpsilon),
- testEpsilon));
- }
- #endregion
-
- #region ToPoint (Static)
- /// <summary>
- /// To string
- /// </summary>
- [Test]
- public static void ToPoint()
- {
- Assert.Equal(new Point(23, 45),
- new Vector(23, 45, 14).ToPoint());
- }
- #endregion
-
- #region Equality
- /// <summary>
- /// Equality
- /// </summary>
- [Test]
- public void Equality()
- {
- Vector testVector = new Vector(32, 65, 32);
-
- Assert.Equal(new Vector(32, 65, 32), testVector);
- Assert.NotEqual(testVector, new Vector(0, 65, 32));
- }
- #endregion
-
- #region Addition
- /// <summary>
- /// Addition
- /// </summary>
- [Test]
- public void Addition()
- {
- Vector testVector = new Vector(32, 65, 32);
- Assert.Equal(new Vector(64, 130, 64), testVector + testVector);
- Assert.Equal(new Vector(32, 66.45f, 34),
- testVector + new Vector(0, 1.45f, 2f));
- }
- #endregion
-
- #region Substraction
- /// <summary>
- /// Substraction
- /// </summary>
- [Test]
- public void Substraction()
- {
- Vector testVector = new Vector(32, 65, 32);
- Assert.Equal(new Vector(0, 0, 0), testVector - testVector);
- Assert.Equal(new Vector(32, 63.55f, 30),
- testVector - new Vector(0, 1.45f, 2f));
- }
- #endregion
-
- #region Multiplication
- /// <summary>
- /// Multiplication
- /// </summary>
- [Test]
- public void Multiplication()
- {
- Assert.Equal(Vector.Dot(new Vector(5, 5, 5), new Vector(2, 2.5f, 4)),
- new Vector(5, 5, 5) * new Vector(2, 2.5f, 4));
-
- //check with vector and scale factor
- Assert.Equal(new Vector(5, 2.5f, 16), new Vector(10, 5, 32) * 0.5f);
- //check with vector and scale factor
- Assert.Equal(new Vector(5, 2.5f, 16), 0.5f * new Vector(10, 5, 32));
- }
- #endregion
-
- #region Division
- /// <summary>
- /// Multiplication
- /// </summary>
- [Test]
- public void Division()
- {
- //check with vector and scale factor
- Assert.Equal(new Vector(20, 10, 64), new Vector(10, 5, 32) / 0.5f);
- //check with vector and scale factor
- Assert.Equal(new Vector(20, 10, 64), 0.5f / new Vector(10, 5, 32));
- }
- #endregion
-
- #region Min
- /// <summary>
- /// Minimum
- /// </summary>
- [Test]
- public void Min()
- {
- Assert.Equal(new Vector(43, 0, 32),
- Vector.Min(new Vector(43, 3, 32), new Vector(50, 0, 40)));
- }
- #endregion
-
- #region Max
- /// <summary>
- /// Maximum
- /// </summary>
- [Test]
- public void Max()
- {
- Assert.Equal(new Vector(50, 3, 40),
- Vector.Max(new Vector(43, 3, 32), new Vector(50, 0, 40)));
- }
- #endregion
-
- #region Dot
- /// <summary>
- /// Dot
- /// </summary>
- [Test]
- public void Dot()
- {
- Assert.Equal(42.5f,
- Vector.Dot(new Vector(5, 5, 5), new Vector(2, 2.5f, 4)));
- }
- #endregion
-
- #region Clamp
- /// <summary>
- /// Clamp
- /// </summary>
- [Test]
- public void Clamp()
- {
- Assert.Equal(new Vector(6, 2.6f, 86),
- Vector.Clamp(new Vector(5, 3, 86), new Vector(6, 2, 50),
- new Vector(10, 2.6f, 86)));
- }
- #endregion
-
- #region Cross
- /// <summary>
- /// Cross
- /// </summary>
- [Test]
- public void Cross()
- {
- Assert.Equal(new Vector(-11, -7, 20),
- Vector.Cross(new Vector(4, 8, 5), new Vector(1, 7, 3)));
- }
- #endregion
-
- #region Distance
- /// <summary>
- /// Distance
- /// </summary>
- [Test]
- public void Distance()
- {
- Vector testVector1 = new Vector(5, 10, 4);
- Vector testVector2 = new Vector(1, 5, 3);
- Assert.Equal(MathHelper.Sqrt(42), Vector.Distance(testVector1, testVector2));
- }
- #endregion
-
- #region DistanceSquared
- /// <summary>
- /// Distance squared
- /// </summary>
- [Test]
- public void DistanceSquared()
- {
- Vector testVector1 = new Vector(5, 10, 4);
- Vector testVector2 = new Vector(1, 5, 3);
- Assert.Equal(42, Vector.DistanceSquared(testVector1, testVector2));
- }
- #endregion
-
- #region Normalize
- /// <summary>
- /// Normalize
- /// </summary>
- [Test]
- public void Normalize()
- {
- Vector testVector = new Vector(1, 5, 3);
-
- testVector.Normalize();
- Assert.NotEqual(new Vector(1, 5, 3), testVector);
- testVector = new Vector(0, 0, -100);
- testVector.Normalize();
- Assert.Equal(new Vector(0, 0, -1), testVector);
- }
- #endregion
-
- #region TransformNormal
- /// <summary>
- /// Transform normal
- /// </summary>
- [Test]
- public void TransformNormal()
- {
- Matrix testMatrix = new Matrix(
- 4, 7, 2, 0,
- 4, 3, 8, 5,
- 4, 2, 8, 4,
- 2, 1, 8, 4);
- Vector testVector = new Vector(4, 8, 1);
- Assert.Equal(new Vector(52, 54, 80),
- Vector.TransformNormal(testVector, testMatrix));
- }
- #endregion
-
- #region VectorToString
- /// <summary>
- /// To string
- /// </summary>
- [Test]
- public void VectorToString()
- {
- Assert.Equal("(23.0000, 45.0000, 5.0000)",
- new Vector(23, 45, 5).ToString());
- }
- #endregion
- }
-
- /// <summary>
- /// Vector performance class to figure out performance differences between
- /// different implementations of Vector methods available on different
- /// platforms and in different frameworks.
- /// </summary>
- [NUnit.Framework.Category("LongRunning")]
- public class VectorPerformance
- {
- #region TestLength Performance
- /// <summary>
- /// Test the length property of the Vector class.
- /// </summary>
- [Test]
- public static void TestLength()
- {
- Vector testVector = new Vector(10, 20, 30);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- float length = 0;
- PerformanceTester.Profile10MilionTimes("Vector.Length", delegate
- {
- length = testVector.Length;
- });
- Assert.Equal(length, testVector.Length);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- float lengthSquared = 0;
- PerformanceTester.Profile10MilionTimes("Vector.LengthSquared", delegate
- {
- lengthSquared = testVector.LengthSquared;
- });
- Assert.Equal(lengthSquared, testVector.LengthSquared);
- }
- #endregion
-
- #region TestDot Performance
- /// <summary>
- /// Test the dot method of the vector struct.
- /// </summary>
- [Test]
- public static void TestDot()
- {
- Vector testVector1 = new Vector(10, 20, 30);
- Vector testVector2 = new Vector(3, 2, 1);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- float dot = 0;
- PerformanceTester.Profile10MilionTimes("Vector.Dot", delegate
- {
- dot = Dot(testVector1, testVector2);
- });
- Assert.Equal(dot, Dot(testVector1, testVector2));
- }
- #endregion
-
- #region TestCross Performance
- /// <summary>
- /// Test the cross method of the vector struct.
- /// </summary>
- [Test]
- public static void TestCross()
- {
- Vector testVector1 = new Vector(10, 20, 30);
- Vector testVector2 = new Vector(3, 2, 1);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- Vector cross = Zero;
- PerformanceTester.Profile10MilionTimes("Vector.Cross", delegate
- {
- cross = Cross(testVector1, testVector2);
- });
- Assert.Equal(cross, Cross(testVector1, testVector2));
- }
- #endregion
-
- #region TestDistance Performance
- /// <summary>
- /// Test the distance method of the vector struct.
- /// </summary>
- [Test]
- public static void TestDistance()
- {
- Vector testVector1 = new Vector(10, 20, 30);
- Vector testVector2 = new Vector(3, 2, 1);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- float distance = 0;
- PerformanceTester.Profile10MilionTimes("Vector.Distance", delegate
- {
- distance = Distance(testVector1, testVector2);
- });
- Assert.Equal(distance, Distance(testVector1, testVector2));
- }
- #endregion
-
- #region TestNormalize Performance
- /// <summary>
- /// Test the normalize method of the vector struct.
- /// </summary>
- [Test]
- public static void TestNormalize()
- {
- Vector testVector1 = new Vector(10, 20, 30);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- Vector vector = Zero;
- PerformanceTester.Profile10MilionTimes("Vector.Normalize", delegate
- {
- vector = Normalize(testVector1);
- });
- Assert.Equal(vector, Normalize(testVector1));
- }
- #endregion
-
- #region TestTransformNormal Performance
- /// <summary>
- /// Test the transform normal method of the vector struct.
- /// </summary>
- [Test]
- public static void TestTransformNormal()
- {
- Vector testVector1 = new Vector(10, 20, 30);
- Matrix testMatrix = Matrix.CreateRotationX(90);
-
- // Results (Release)
- // -------
- // 2010-04-08
- // Delta: x ms
- // XNA: 350 ms
- // OpenTK: x ms
- // SlimDx: x ms
-
- Vector vector = Zero;
- PerformanceTester.Profile10MilionTimes(
- "Vector.TransformNormal", delegate
- {
- vector = TransformNormal(testVector1, testMatrix);
- });
- Assert.Equal(vector, TransformNormal(testVector1, testMatrix));
- }
- #endregion
-
- #region ExecuteAllForPerformanceOverview Performance
- /// <summary>
- /// Execute all vector tests for a performance overview.
- /// </summary>
- [Test]
- public static void ExecuteAllForPerformanceOverview()
- {
- // Also doing now some Vector and Point tests now, used heavily
- // in the engine.
-
- // Warm up the CPU with some stress testing (for several secs) :)
- TestLength();
- PerformanceTester.ShowTotalProfileRuns();
- Log.Test("Starting testing again after warming up!");
-
- //Log.Test("Delta Vector test:");
- Log.Test("XNA Vector test:");
- //Log.Test("OpenTK Vector test:");
- //Log.Test("SlimDX Vector test:");
- TestLength();
- TestDot();
- TestCross();
- TestDistance();
- TestNormalize();
- TestTransformNormal();
- PerformanceTester.ShowTotalProfileRuns();
-
- // Result: In all cases our code is faster than calling XNA code!
- // This could be different on certain platforms (e.g. Xbox 360),
- // we still need to check that!
-
- // Vector performance:
- /*XNA Vector test (all disabled now):
- 140ms for Vector.Length (10 million calls)
- 66ms for Vector.LengthSquared (10 million calls)
- 207ms for Vector.Dot (10 million calls)
- 224ms for Vector.Cross (10 million calls)
- 231ms for Vector.Distance (10 million calls)
- 291ms for Vector.Normalize (10 million calls)
- 438ms for Vector.TransformNormal (10 million calls)
- In total 7 Tests were executed. Total time=1597ms, Average time=228.1ms.
- */
- /*Delta Vector test:
- 109ms for Vector.Length (10 million calls)
- 47ms for Vector.LengthSquared (10 million calls)
- 91ms for Vector.Dot (10 million calls)
- 111ms for Vector.Cross (10 million calls)
- 110ms for Vector.Distance (10 million calls)
- 276ms for Vector.Normalize (10 million calls)
- 232ms for Vector.TransformNormal (10 million calls)
- In total 7 Tests were executed. Total time=976ms, Average time=139.4ms.
- */
- }
- #endregion
- }
- }
- }