e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
521 lines
21 KiB
C#
521 lines
21 KiB
C#
// Copyright (c) Microsoft. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
using System.Globalization;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Text;
|
|
|
|
namespace System.Numerics
|
|
{
|
|
/// <summary>
|
|
/// A structure encapsulating four single precision floating point values and provides hardware accelerated methods.
|
|
/// </summary>
|
|
public partial struct Vector4 : IEquatable<Vector4>, IFormattable
|
|
{
|
|
#region Public Static Properties
|
|
/// <summary>
|
|
/// Returns the vector (0,0,0,0).
|
|
/// </summary>
|
|
public static Vector4 Zero { get { return new Vector4(); } }
|
|
/// <summary>
|
|
/// Returns the vector (1,1,1,1).
|
|
/// </summary>
|
|
public static Vector4 One { get { return new Vector4(1.0f, 1.0f, 1.0f, 1.0f); } }
|
|
/// <summary>
|
|
/// Returns the vector (1,0,0,0).
|
|
/// </summary>
|
|
public static Vector4 UnitX { get { return new Vector4(1.0f, 0.0f, 0.0f, 0.0f); } }
|
|
/// <summary>
|
|
/// Returns the vector (0,1,0,0).
|
|
/// </summary>
|
|
public static Vector4 UnitY { get { return new Vector4(0.0f, 1.0f, 0.0f, 0.0f); } }
|
|
/// <summary>
|
|
/// Returns the vector (0,0,1,0).
|
|
/// </summary>
|
|
public static Vector4 UnitZ { get { return new Vector4(0.0f, 0.0f, 1.0f, 0.0f); } }
|
|
/// <summary>
|
|
/// Returns the vector (0,0,0,1).
|
|
/// </summary>
|
|
public static Vector4 UnitW { get { return new Vector4(0.0f, 0.0f, 0.0f, 1.0f); } }
|
|
#endregion Public Static Properties
|
|
|
|
#region Public instance methods
|
|
/// <summary>
|
|
/// Returns the hash code for this instance.
|
|
/// </summary>
|
|
/// <returns>The hash code.</returns>
|
|
public override int GetHashCode()
|
|
{
|
|
int hash = this.X.GetHashCode();
|
|
hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode());
|
|
hash = HashCodeHelper.CombineHashCodes(hash, this.Z.GetHashCode());
|
|
hash = HashCodeHelper.CombineHashCodes(hash, this.W.GetHashCode());
|
|
return hash;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a boolean indicating whether the given Object is equal to this Vector4 instance.
|
|
/// </summary>
|
|
/// <param name="obj">The Object to compare against.</param>
|
|
/// <returns>True if the Object is equal to this Vector4; False otherwise.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public override bool Equals(object obj)
|
|
{
|
|
if (!(obj is Vector4))
|
|
return false;
|
|
return Equals((Vector4)obj);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a String representing this Vector4 instance.
|
|
/// </summary>
|
|
/// <returns>The string representation.</returns>
|
|
public override string ToString()
|
|
{
|
|
return ToString("G", CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements.
|
|
/// </summary>
|
|
/// <param name="format">The format of individual elements.</param>
|
|
/// <returns>The string representation.</returns>
|
|
public string ToString(string format)
|
|
{
|
|
return ToString(format, CultureInfo.CurrentCulture);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a String representing this Vector4 instance, using the specified format to format individual elements
|
|
/// and the given IFormatProvider.
|
|
/// </summary>
|
|
/// <param name="format">The format of individual elements.</param>
|
|
/// <param name="formatProvider">The format provider to use when formatting elements.</param>
|
|
/// <returns>The string representation.</returns>
|
|
public string ToString(string format, IFormatProvider formatProvider)
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
|
|
sb.Append('<');
|
|
sb.Append(this.X.ToString(format, formatProvider));
|
|
sb.Append(separator);
|
|
sb.Append(' ');
|
|
sb.Append(this.Y.ToString(format, formatProvider));
|
|
sb.Append(separator);
|
|
sb.Append(' ');
|
|
sb.Append(this.Z.ToString(format, formatProvider));
|
|
sb.Append(separator);
|
|
sb.Append(' ');
|
|
sb.Append(this.W.ToString(format, formatProvider));
|
|
sb.Append('>');
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the length of the vector. This operation is cheaper than Length().
|
|
/// </summary>
|
|
/// <returns>The vector's length.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public float Length()
|
|
{
|
|
if (Vector.IsHardwareAccelerated)
|
|
{
|
|
float ls = Vector4.Dot(this, this);
|
|
return (float)System.Math.Sqrt(ls);
|
|
}
|
|
else
|
|
{
|
|
float ls = X * X + Y * Y + Z * Z + W * W;
|
|
|
|
return (float)Math.Sqrt((double)ls);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the length of the vector squared.
|
|
/// </summary>
|
|
/// <returns>The vector's length squared.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public float LengthSquared()
|
|
{
|
|
if (Vector.IsHardwareAccelerated)
|
|
{
|
|
return Vector4.Dot(this, this);
|
|
}
|
|
else
|
|
{
|
|
return X * X + Y * Y + Z * Z + W * W;
|
|
}
|
|
}
|
|
#endregion Public Instance Methods
|
|
|
|
#region Public Static Methods
|
|
/// <summary>
|
|
/// Returns the Euclidean distance between the two given points.
|
|
/// </summary>
|
|
/// <param name="value1">The first point.</param>
|
|
/// <param name="value2">The second point.</param>
|
|
/// <returns>The distance.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static float Distance(Vector4 value1, Vector4 value2)
|
|
{
|
|
if (Vector.IsHardwareAccelerated)
|
|
{
|
|
Vector4 difference = value1 - value2;
|
|
float ls = Vector4.Dot(difference, difference);
|
|
return (float)System.Math.Sqrt(ls);
|
|
}
|
|
else
|
|
{
|
|
float dx = value1.X - value2.X;
|
|
float dy = value1.Y - value2.Y;
|
|
float dz = value1.Z - value2.Z;
|
|
float dw = value1.W - value2.W;
|
|
|
|
float ls = dx * dx + dy * dy + dz * dz + dw * dw;
|
|
|
|
return (float)Math.Sqrt((double)ls);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the Euclidean distance squared between the two given points.
|
|
/// </summary>
|
|
/// <param name="value1">The first point.</param>
|
|
/// <param name="value2">The second point.</param>
|
|
/// <returns>The distance squared.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static float DistanceSquared(Vector4 value1, Vector4 value2)
|
|
{
|
|
if (Vector.IsHardwareAccelerated)
|
|
{
|
|
Vector4 difference = value1 - value2;
|
|
return Vector4.Dot(difference, difference);
|
|
}
|
|
else
|
|
{
|
|
float dx = value1.X - value2.X;
|
|
float dy = value1.Y - value2.Y;
|
|
float dz = value1.Z - value2.Z;
|
|
float dw = value1.W - value2.W;
|
|
|
|
return dx * dx + dy * dy + dz * dz + dw * dw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns a vector with the same direction as the given vector, but with a length of 1.
|
|
/// </summary>
|
|
/// <param name="vector">The vector to normalize.</param>
|
|
/// <returns>The normalized vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Normalize(Vector4 vector)
|
|
{
|
|
if (Vector.IsHardwareAccelerated)
|
|
{
|
|
float length = vector.Length();
|
|
return vector / length;
|
|
}
|
|
else
|
|
{
|
|
float ls = vector.X * vector.X + vector.Y * vector.Y + vector.Z * vector.Z + vector.W * vector.W;
|
|
float invNorm = 1.0f / (float)Math.Sqrt((double)ls);
|
|
|
|
return new Vector4(
|
|
vector.X * invNorm,
|
|
vector.Y * invNorm,
|
|
vector.Z * invNorm,
|
|
vector.W * invNorm);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restricts a vector between a min and max value.
|
|
/// </summary>
|
|
/// <param name="value1">The source vector.</param>
|
|
/// <param name="min">The minimum value.</param>
|
|
/// <param name="max">The maximum value.</param>
|
|
/// <returns>The restricted vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max)
|
|
{
|
|
// This compare order is very important!!!
|
|
// We must follow HLSL behavior in the case user specified min value is bigger than max value.
|
|
|
|
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;
|
|
|
|
float w = value1.W;
|
|
w = (w > max.W) ? max.W : w;
|
|
w = (w < min.W) ? min.W : w;
|
|
|
|
return new Vector4(x, y, z, w);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Linearly interpolates between two vectors based on the given weighting.
|
|
/// </summary>
|
|
/// <param name="value1">The first source vector.</param>
|
|
/// <param name="value2">The second source vector.</param>
|
|
/// <param name="amount">Value between 0 and 1 indicating the weight of the second source vector.</param>
|
|
/// <returns>The interpolated vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount)
|
|
{
|
|
return new Vector4(
|
|
value1.X + (value2.X - value1.X) * amount,
|
|
value1.Y + (value2.Y - value1.Y) * amount,
|
|
value1.Z + (value2.Z - value1.Z) * amount,
|
|
value1.W + (value2.W - value1.W) * amount);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given matrix.
|
|
/// </summary>
|
|
/// <param name="position">The source vector.</param>
|
|
/// <param name="matrix">The transformation matrix.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector2 position, Matrix4x4 matrix)
|
|
{
|
|
return new Vector4(
|
|
position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41,
|
|
position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42,
|
|
position.X * matrix.M13 + position.Y * matrix.M23 + matrix.M43,
|
|
position.X * matrix.M14 + position.Y * matrix.M24 + matrix.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given matrix.
|
|
/// </summary>
|
|
/// <param name="position">The source vector.</param>
|
|
/// <param name="matrix">The transformation matrix.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector3 position, Matrix4x4 matrix)
|
|
{
|
|
return new Vector4(
|
|
position.X * matrix.M11 + position.Y * matrix.M21 + position.Z * matrix.M31 + matrix.M41,
|
|
position.X * matrix.M12 + position.Y * matrix.M22 + position.Z * matrix.M32 + matrix.M42,
|
|
position.X * matrix.M13 + position.Y * matrix.M23 + position.Z * matrix.M33 + matrix.M43,
|
|
position.X * matrix.M14 + position.Y * matrix.M24 + position.Z * matrix.M34 + matrix.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given matrix.
|
|
/// </summary>
|
|
/// <param name="vector">The source vector.</param>
|
|
/// <param name="matrix">The transformation matrix.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector4 vector, Matrix4x4 matrix)
|
|
{
|
|
return new Vector4(
|
|
vector.X * matrix.M11 + vector.Y * matrix.M21 + vector.Z * matrix.M31 + vector.W * matrix.M41,
|
|
vector.X * matrix.M12 + vector.Y * matrix.M22 + vector.Z * matrix.M32 + vector.W * matrix.M42,
|
|
vector.X * matrix.M13 + vector.Y * matrix.M23 + vector.Z * matrix.M33 + vector.W * matrix.M43,
|
|
vector.X * matrix.M14 + vector.Y * matrix.M24 + vector.Z * matrix.M34 + vector.W * matrix.M44);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given Quaternion rotation value.
|
|
/// </summary>
|
|
/// <param name="value">The source vector to be rotated.</param>
|
|
/// <param name="rotation">The rotation to apply.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector2 value, Quaternion rotation)
|
|
{
|
|
float x2 = rotation.X + rotation.X;
|
|
float y2 = rotation.Y + rotation.Y;
|
|
float z2 = rotation.Z + rotation.Z;
|
|
|
|
float wx2 = rotation.W * x2;
|
|
float wy2 = rotation.W * y2;
|
|
float wz2 = rotation.W * z2;
|
|
float xx2 = rotation.X * x2;
|
|
float xy2 = rotation.X * y2;
|
|
float xz2 = rotation.X * z2;
|
|
float yy2 = rotation.Y * y2;
|
|
float yz2 = rotation.Y * z2;
|
|
float zz2 = rotation.Z * z2;
|
|
|
|
return new Vector4(
|
|
value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2),
|
|
value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2),
|
|
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2),
|
|
1.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given Quaternion rotation value.
|
|
/// </summary>
|
|
/// <param name="value">The source vector to be rotated.</param>
|
|
/// <param name="rotation">The rotation to apply.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector3 value, Quaternion rotation)
|
|
{
|
|
float x2 = rotation.X + rotation.X;
|
|
float y2 = rotation.Y + rotation.Y;
|
|
float z2 = rotation.Z + rotation.Z;
|
|
|
|
float wx2 = rotation.W * x2;
|
|
float wy2 = rotation.W * y2;
|
|
float wz2 = rotation.W * z2;
|
|
float xx2 = rotation.X * x2;
|
|
float xy2 = rotation.X * y2;
|
|
float xz2 = rotation.X * z2;
|
|
float yy2 = rotation.Y * y2;
|
|
float yz2 = rotation.Y * z2;
|
|
float zz2 = rotation.Z * z2;
|
|
|
|
return new Vector4(
|
|
value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
|
|
value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2) + value.Z * (yz2 - wx2),
|
|
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0f - xx2 - yy2),
|
|
1.0f);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Transforms a vector by the given Quaternion rotation value.
|
|
/// </summary>
|
|
/// <param name="value">The source vector to be rotated.</param>
|
|
/// <param name="rotation">The rotation to apply.</param>
|
|
/// <returns>The transformed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Transform(Vector4 value, Quaternion rotation)
|
|
{
|
|
float x2 = rotation.X + rotation.X;
|
|
float y2 = rotation.Y + rotation.Y;
|
|
float z2 = rotation.Z + rotation.Z;
|
|
|
|
float wx2 = rotation.W * x2;
|
|
float wy2 = rotation.W * y2;
|
|
float wz2 = rotation.W * z2;
|
|
float xx2 = rotation.X * x2;
|
|
float xy2 = rotation.X * y2;
|
|
float xz2 = rotation.X * z2;
|
|
float yy2 = rotation.Y * y2;
|
|
float yz2 = rotation.Y * z2;
|
|
float zz2 = rotation.Z * z2;
|
|
|
|
return new Vector4(
|
|
value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2) + value.Z * (xz2 + wy2),
|
|
value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2) + value.Z * (yz2 - wx2),
|
|
value.X * (xz2 - wy2) + value.Y * (yz2 + wx2) + value.Z * (1.0f - xx2 - yy2),
|
|
value.W);
|
|
}
|
|
#endregion Public Static Methods
|
|
|
|
#region Public operator methods
|
|
// All these methods should be inlines as they are implemented
|
|
// over JIT intrinsics
|
|
|
|
/// <summary>
|
|
/// Adds two vectors together.
|
|
/// </summary>
|
|
/// <param name="left">The first source vector.</param>
|
|
/// <param name="right">The second source vector.</param>
|
|
/// <returns>The summed vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Add(Vector4 left, Vector4 right)
|
|
{
|
|
return left + right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Subtracts the second vector from the first.
|
|
/// </summary>
|
|
/// <param name="left">The first source vector.</param>
|
|
/// <param name="right">The second source vector.</param>
|
|
/// <returns>The difference vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Subtract(Vector4 left, Vector4 right)
|
|
{
|
|
return left - right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiplies two vectors together.
|
|
/// </summary>
|
|
/// <param name="left">The first source vector.</param>
|
|
/// <param name="right">The second source vector.</param>
|
|
/// <returns>The product vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Multiply(Vector4 left, Vector4 right)
|
|
{
|
|
return left * right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiplies a vector by the given scalar.
|
|
/// </summary>
|
|
/// <param name="left">The source vector.</param>
|
|
/// <param name="right">The scalar value.</param>
|
|
/// <returns>The scaled vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Multiply(Vector4 left, Single right)
|
|
{
|
|
return left * new Vector4(right, right, right, right);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Multiplies a vector by the given scalar.
|
|
/// </summary>
|
|
/// <param name="left">The scalar value.</param>
|
|
/// <param name="right">The source vector.</param>
|
|
/// <returns>The scaled vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Multiply(Single left, Vector4 right)
|
|
{
|
|
return new Vector4(left, left, left, left) * right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Divides the first vector by the second.
|
|
/// </summary>
|
|
/// <param name="left">The first source vector.</param>
|
|
/// <param name="right">The second source vector.</param>
|
|
/// <returns>The vector resulting from the division.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Divide(Vector4 left, Vector4 right)
|
|
{
|
|
return left / right;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Divides the vector by the given scalar.
|
|
/// </summary>
|
|
/// <param name="left">The source vector.</param>
|
|
/// <param name="divisor">The scalar value.</param>
|
|
/// <returns>The result of the division.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Divide(Vector4 left, Single divisor)
|
|
{
|
|
return left / divisor;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Negates a given vector.
|
|
/// </summary>
|
|
/// <param name="value">The source vector.</param>
|
|
/// <returns>The negated vector.</returns>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Vector4 Negate(Vector4 value)
|
|
{
|
|
return -value;
|
|
}
|
|
#endregion Public operator methods
|
|
}
|
|
}
|