// 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 { /// /// A structure encapsulating two single precision floating point values and provides hardware accelerated methods. /// public partial struct Vector2 : IEquatable, IFormattable { #region Public Static Properties /// /// Returns the vector (0,0). /// public static Vector2 Zero { get { return new Vector2(); } } /// /// Returns the vector (1,1). /// public static Vector2 One { get { return new Vector2(1.0f, 1.0f); } } /// /// Returns the vector (1,0). /// public static Vector2 UnitX { get { return new Vector2(1.0f, 0.0f); } } /// /// Returns the vector (0,1). /// public static Vector2 UnitY { get { return new Vector2(0.0f, 1.0f); } } #endregion Public Static Properties #region Public instance methods /// /// Returns the hash code for this instance. /// /// The hash code. public override int GetHashCode() { int hash = this.X.GetHashCode(); hash = HashCodeHelper.CombineHashCodes(hash, this.Y.GetHashCode()); return hash; } /// /// Returns a boolean indicating whether the given Object is equal to this Vector2 instance. /// /// The Object to compare against. /// True if the Object is equal to this Vector2; False otherwise. [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { if (!(obj is Vector2)) return false; return Equals((Vector2)obj); } /// /// Returns a String representing this Vector2 instance. /// /// The string representation. public override string ToString() { return ToString("G", CultureInfo.CurrentCulture); } /// /// Returns a String representing this Vector2 instance, using the specified format to format individual elements. /// /// The format of individual elements. /// The string representation. public string ToString(string format) { return ToString(format, CultureInfo.CurrentCulture); } /// /// Returns a String representing this Vector2 instance, using the specified format to format individual elements /// and the given IFormatProvider. /// /// The format of individual elements. /// The format provider to use when formatting elements. /// The string representation. 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('>'); return sb.ToString(); } /// /// Returns the length of the vector. /// /// The vector's length. [MethodImpl(MethodImplOptions.AggressiveInlining)] public float Length() { if (Vector.IsHardwareAccelerated) { float ls = Vector2.Dot(this, this); return (float)Math.Sqrt(ls); } else { float ls = X * X + Y * Y; return (float)Math.Sqrt((double)ls); } } /// /// Returns the length of the vector squared. This operation is cheaper than Length(). /// /// The vector's length squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] public float LengthSquared() { if (Vector.IsHardwareAccelerated) { return Vector2.Dot(this, this); } else { return X * X + Y * Y; } } #endregion Public Instance Methods #region Public Static Methods /// /// Returns the Euclidean distance between the two given points. /// /// The first point. /// The second point. /// The distance. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Distance(Vector2 value1, Vector2 value2) { if (Vector.IsHardwareAccelerated) { Vector2 difference = value1 - value2; float ls = Vector2.Dot(difference, difference); return (float)System.Math.Sqrt(ls); } else { float dx = value1.X - value2.X; float dy = value1.Y - value2.Y; float ls = dx * dx + dy * dy; return (float)Math.Sqrt((double)ls); } } /// /// Returns the Euclidean distance squared between the two given points. /// /// The first point. /// The second point. /// The distance squared. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float DistanceSquared(Vector2 value1, Vector2 value2) { if (Vector.IsHardwareAccelerated) { Vector2 difference = value1 - value2; return Vector2.Dot(difference, difference); } else { float dx = value1.X - value2.X; float dy = value1.Y - value2.Y; return dx * dx + dy * dy; } } /// /// Returns a vector with the same direction as the given vector, but with a length of 1. /// /// The vector to normalize. /// The normalized vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Normalize(Vector2 value) { if (Vector.IsHardwareAccelerated) { float length = value.Length(); return value / length; } else { float ls = value.X * value.X + value.Y * value.Y; float invNorm = 1.0f / (float)Math.Sqrt((double)ls); return new Vector2( value.X * invNorm, value.Y * invNorm); } } /// /// Returns the reflection of a vector off a surface that has the specified normal. /// /// The source vector. /// The normal of the surface being reflected off. /// The reflected vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Reflect(Vector2 vector, Vector2 normal) { if (Vector.IsHardwareAccelerated) { float dot = Vector2.Dot(vector, normal); return vector - (2 * dot * normal); } else { float dot = vector.X * normal.X + vector.Y * normal.Y; return new Vector2( vector.X - 2.0f * dot * normal.X, vector.Y - 2.0f * dot * normal.Y); } } /// /// Restricts a vector between a min and max value. /// /// The source vector. /// The minimum value. /// The maximum value. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 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; return new Vector2(x, y); } /// /// Linearly interpolates between two vectors based on the given weighting. /// /// The first source vector. /// The second source vector. /// Value between 0 and 1 indicating the weight of the second source vector. /// The interpolated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) { return new Vector2( value1.X + (value2.X - value1.X) * amount, value1.Y + (value2.Y - value1.Y) * amount); } /// /// Transforms a vector by the given matrix. /// /// The source vector. /// The transformation matrix. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Transform(Vector2 position, Matrix3x2 matrix) { return new Vector2( position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M31, position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M32); } /// /// Transforms a vector by the given matrix. /// /// The source vector. /// The transformation matrix. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Transform(Vector2 position, Matrix4x4 matrix) { return new Vector2( position.X * matrix.M11 + position.Y * matrix.M21 + matrix.M41, position.X * matrix.M12 + position.Y * matrix.M22 + matrix.M42); } /// /// Transforms a vector normal by the given matrix. /// /// The source vector. /// The transformation matrix. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 TransformNormal(Vector2 normal, Matrix3x2 matrix) { return new Vector2( normal.X * matrix.M11 + normal.Y * matrix.M21, normal.X * matrix.M12 + normal.Y * matrix.M22); } /// /// Transforms a vector normal by the given matrix. /// /// The source vector. /// The transformation matrix. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 TransformNormal(Vector2 normal, Matrix4x4 matrix) { return new Vector2( normal.X * matrix.M11 + normal.Y * matrix.M21, normal.X * matrix.M12 + normal.Y * matrix.M22); } /// /// Transforms a vector by the given Quaternion rotation value. /// /// The source vector to be rotated. /// The rotation to apply. /// The transformed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Transform(Vector2 value, Quaternion rotation) { float x2 = rotation.X + rotation.X; float y2 = rotation.Y + rotation.Y; float z2 = rotation.Z + rotation.Z; float wz2 = rotation.W * z2; float xx2 = rotation.X * x2; float xy2 = rotation.X * y2; float yy2 = rotation.Y * y2; float zz2 = rotation.Z * z2; return new Vector2( value.X * (1.0f - yy2 - zz2) + value.Y * (xy2 - wz2), value.X * (xy2 + wz2) + value.Y * (1.0f - xx2 - zz2)); } #endregion Public Static Methods #region Public operator methods // all the below methods should be inlined as they are // implemented over JIT intrinsics /// /// Adds two vectors together. /// /// The first source vector. /// The second source vector. /// The summed vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Add(Vector2 left, Vector2 right) { return left + right; } /// /// Subtracts the second vector from the first. /// /// The first source vector. /// The second source vector. /// The difference vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Subtract(Vector2 left, Vector2 right) { return left - right; } /// /// Multiplies two vectors together. /// /// The first source vector. /// The second source vector. /// The product vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Multiply(Vector2 left, Vector2 right) { return left * right; } /// /// Multiplies a vector by the given scalar. /// /// The source vector. /// The scalar value. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Multiply(Vector2 left, Single right) { return left * right; } /// /// Multiplies a vector by the given scalar. /// /// The scalar value. /// The source vector. /// The scaled vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Multiply(Single left, Vector2 right) { return left * right; } /// /// Divides the first vector by the second. /// /// The first source vector. /// The second source vector. /// The vector resulting from the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Divide(Vector2 left, Vector2 right) { return left / right; } /// /// Divides the vector by the given scalar. /// /// The source vector. /// The scalar value. /// The result of the division. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Divide(Vector2 left, Single divisor) { return left / divisor; } /// /// Negates a given vector. /// /// The source vector. /// The negated vector. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Negate(Vector2 value) { return -value; } #endregion Public operator methods } }