// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved. // ----------------------------------------------------------------------------- // Original code from SharpDX project. https://github.com/sharpdx/SharpDX/ // Greetings to Alexandre Mutel. Original code published with the following license: // ----------------------------------------------------------------------------- // Copyright (c) 2010-2014 SharpDX - Alexandre Mutel // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // ----------------------------------------------------------------------------- // Original code from SlimMath project. http://code.google.com/p/slimmath/ // Greetings to SlimDX Group. Original code published with the following license: // ----------------------------------------------------------------------------- /* * Copyright (c) 2007-2011 SlimDX Group * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ using System; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace FlaxEngine { [Serializable] #if FLAX_EDITOR [System.ComponentModel.TypeConverter(typeof(TypeConverters.Float2Converter))] #endif partial struct Float2 : IEquatable, IFormattable { private static readonly string _formatString = "X:{0:F2} Y:{1:F2}"; /// /// The size of the type, in bytes. /// public static readonly int SizeInBytes = Marshal.SizeOf(typeof(Float2)); /// /// A with all of its components set to zero. /// public static readonly Float2 Zero; /// /// The X unit (1, 0). /// public static readonly Float2 UnitX = new Float2(1.0f, 0.0f); /// /// The Y unit (0, 1). /// public static readonly Float2 UnitY = new Float2(0.0f, 1.0f); /// /// A with all of its components set to half. /// public static readonly Float2 Half = new Float2(0.5f, 0.5f); /// /// A with all of its components set to one. /// public static readonly Float2 One = new Float2(1.0f, 1.0f); /// /// A with all components equal to . /// public static readonly Float2 Minimum = new Float2(float.MinValue); /// /// A with all components equal to . /// public static readonly Float2 Maximum = new Float2(float.MaxValue); /// /// Initializes a new instance of the struct. /// /// The value that will be assigned to all components. public Float2(float value) { X = value; Y = value; } /// /// Initializes a new instance of the struct. /// /// Initial value for the X component of the vector. /// Initial value for the Y component of the vector. public Float2(float x, float y) { X = x; Y = y; } /// /// Initializes a new instance of the struct. /// /// A vector containing the values with which to initialize the X, Y and Z components. public Float2(Vector2 value) { X = (float)value.X; Y = (float)value.Y; } /// /// Initializes a new instance of the struct. /// /// A vector containing the values with which to initialize the X, Y and Z components. public Float2(Double2 value) { X = (float)value.X; Y = (float)value.Y; } /// /// Initializes a new instance of the struct. /// /// A vector containing the values with which to initialize the X and Y components. public Float2(Float3 value) { X = value.X; Y = value.Y; } /// /// Initializes a new instance of the struct. /// /// A vector containing the values with which to initialize the X and Y components. public Float2(Float4 value) { X = value.X; Y = value.Y; } /// /// Initializes a new instance of the struct. /// /// The values to assign to the X and Y components of the vector. This must be an array with two elements. /// Thrown when is null. /// Thrown when contains more or less than two elements. public Float2(float[] values) { if (values == null) throw new ArgumentNullException(nameof(values)); if (values.Length != 2) throw new ArgumentOutOfRangeException(nameof(values), "There must be two and only two input values for Float2."); X = values[0]; Y = values[1]; } /// /// Gets a value indicting whether this instance is normalized. /// public bool IsNormalized => Mathf.IsOne(X * X + Y * Y); /// /// Gets a value indicting whether this vector is zero /// public bool IsZero => Mathf.IsZero(X) && Mathf.IsZero(Y); /// /// Gets a minimum component value /// public float MinValue => Mathf.Min(X, Y); /// /// Gets a maximum component value /// public float MaxValue => Mathf.Max(X, Y); /// /// Gets an arithmetic average value of all vector components. /// public float AvgValue => (X + Y) * (1.0f / 2.0f); /// /// Gets a sum of the component values. /// public float ValuesSum => X + Y; /// /// Gets a vector with values being absolute values of that vector. /// public Float2 Absolute => new Float2(Mathf.Abs(X), Mathf.Abs(Y)); /// /// Gets a vector with values being opposite to values of that vector. /// public Float2 Negative => new Float2(-X, -Y); /// /// Gets or sets the component at the specified index. /// /// The value of the X or Y component, depending on the index. /// The index of the component to access. Use 0 for the X component and 1 for the Y component. /// The value of the component at the specified index. /// Thrown when the is out of the range [0,1]. public float this[int index] { get { switch (index) { case 0: return X; case 1: return Y; } throw new ArgumentOutOfRangeException(nameof(index), "Indices for Float2 run from 0 to 1, inclusive."); } set { switch (index) { case 0: X = value; break; case 1: Y = value; break; default: throw new ArgumentOutOfRangeException(nameof(index), "Indices for Float2 run from 0 to 1, inclusive."); } } } /// /// Calculates the length of the vector. /// /// The length of the vector. /// may be preferred when only the relative length is needed and speed is of the essence. public float Length => (float)Math.Sqrt(X * X + Y * Y); /// /// Calculates the squared length of the vector. /// /// The squared length of the vector. /// This method may be preferred to when only a relative length is needed and speed is of the essence. public float LengthSquared => X * X + Y * Y; /// /// Gets the normalized vector. Returned vector has length equal 1. /// public Float2 Normalized { get { Float2 result = this; result.Normalize(); return result; } } /// /// Converts the vector into a unit vector. /// public void Normalize() { float length = Length; if (length >= Mathf.Epsilon) { float inv = 1.0f / length; X *= inv; Y *= inv; } } /// /// Creates an array containing the elements of the vector. /// public float[] ToArray() { return new[] { X, Y }; } /// /// Adds two vectors. /// /// The first vector to add. /// The second vector to add. /// When the method completes, contains the sum of the two vectors. public static void Add(ref Float2 left, ref Float2 right, out Float2 result) { result = new Float2(left.X + right.X, left.Y + right.Y); } /// /// Adds two vectors. /// /// The first vector to add. /// The second vector to add. /// The sum of the two vectors. public static Float2 Add(Float2 left, Float2 right) { return new Float2(left.X + right.X, left.Y + right.Y); } /// /// Performs a component-wise addition. /// /// The input vector /// The scalar value to be added to elements /// The vector with added scalar for each element. public static void Add(ref Float2 left, ref float right, out Float2 result) { result = new Float2(left.X + right, left.Y + right); } /// /// Performs a component-wise addition. /// /// The input vector /// The scalar value to be added to elements /// The vector with added scalar for each element. public static Float2 Add(Float2 left, float right) { return new Float2(left.X + right, left.Y + right); } /// /// Subtracts two vectors. /// /// The first vector to subtract. /// The second vector to subtract. /// When the method completes, contains the difference of the two vectors. public static void Subtract(ref Float2 left, ref Float2 right, out Float2 result) { result = new Float2(left.X - right.X, left.Y - right.Y); } /// /// Subtracts two vectors. /// /// The first vector to subtract. /// The second vector to subtract. /// The difference of the two vectors. public static Float2 Subtract(Float2 left, Float2 right) { return new Float2(left.X - right.X, left.Y - right.Y); } /// /// Performs a component-wise subtraction. /// /// The input vector /// The scalar value to be subtracted from elements /// The vector with subtracted scalar for each element. public static void Subtract(ref Float2 left, ref float right, out Float2 result) { result = new Float2(left.X - right, left.Y - right); } /// /// Performs a component-wise subtraction. /// /// The input vector /// The scalar value to be subtracted from elements /// The vector with subtracted scalar for each element. public static Float2 Subtract(Float2 left, float right) { return new Float2(left.X - right, left.Y - right); } /// /// Performs a component-wise subtraction. /// /// The scalar value to be subtracted from elements /// The input vector /// The vector with subtracted scalar for each element. public static void Subtract(ref float left, ref Float2 right, out Float2 result) { result = new Float2(left - right.X, left - right.Y); } /// /// Performs a component-wise subtraction. /// /// The scalar value to be subtracted from elements /// The input vector /// The vector with subtracted scalar for each element. public static Float2 Subtract(float left, Float2 right) { return new Float2(left - right.X, left - right.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// When the method completes, contains the scaled vector. public static void Multiply(ref Float2 value, float scale, out Float2 result) { result = new Float2(value.X * scale, value.Y * scale); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 Multiply(Float2 value, float scale) { return new Float2(value.X * scale, value.Y * scale); } /// /// Multiplies a vector with another by performing component-wise multiplication. /// /// The first vector to multiply. /// The second vector to multiply. /// When the method completes, contains the multiplied vector. public static void Multiply(ref Float2 left, ref Float2 right, out Float2 result) { result = new Float2(left.X * right.X, left.Y * right.Y); } /// /// Multiplies a vector with another by performing component-wise multiplication. /// /// The first vector to multiply. /// The second vector to multiply. /// The multiplied vector. public static Float2 Multiply(Float2 left, Float2 right) { return new Float2(left.X * right.X, left.Y * right.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// When the method completes, contains the scaled vector. public static void Divide(ref Float2 value, float scale, out Float2 result) { result = new Float2(value.X / scale, value.Y / scale); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 Divide(Float2 value, float scale) { return new Float2(value.X / scale, value.Y / scale); } /// /// Scales a vector by the given value. /// /// The amount by which to scale the vector. /// The vector to scale. /// When the method completes, contains the scaled vector. public static void Divide(float scale, ref Float2 value, out Float2 result) { result = new Float2(scale / value.X, scale / value.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 Divide(float scale, Float2 value) { return new Float2(scale / value.X, scale / value.Y); } /// /// Reverses the direction of a given vector. /// /// The vector to negate. /// When the method completes, contains a vector facing in the opposite direction. public static void Negate(ref Float2 value, out Float2 result) { result = new Float2(-value.X, -value.Y); } /// /// Reverses the direction of a given vector. /// /// The vector to negate. /// A vector facing in the opposite direction. public static Float2 Negate(Float2 value) { return new Float2(-value.X, -value.Y); } /// /// Returns a containing the 2D Cartesian coordinates of a point specified in Barycentric /// coordinates relative to a 2D triangle. /// /// A containing the 2D Cartesian coordinates of vertex 1 of the triangle. /// A containing the 2D Cartesian coordinates of vertex 2 of the triangle. /// A containing the 2D Cartesian coordinates of vertex 3 of the triangle. /// Barycentric coordinate b2, which expresses the weighting factor toward vertex 2 (specified in ). /// Barycentric coordinate b3, which expresses the weighting factor toward vertex 3 (specified in ). /// When the method completes, contains the 2D Cartesian coordinates of the specified point. public static void Barycentric(ref Float2 value1, ref Float2 value2, ref Float2 value3, float amount1, float amount2, out Float2 result) { result = new Float2(value1.X + amount1 * (value2.X - value1.X) + amount2 * (value3.X - value1.X), value1.Y + amount1 * (value2.Y - value1.Y) + amount2 * (value3.Y - value1.Y)); } /// /// Returns a containing the 2D Cartesian coordinates of a point specified in Barycentric /// coordinates relative to a 2D triangle. /// /// A containing the 2D Cartesian coordinates of vertex 1 of the triangle. /// A containing the 2D Cartesian coordinates of vertex 2 of the triangle. /// A containing the 2D Cartesian coordinates of vertex 3 of the triangle. /// Barycentric coordinate b2, which expresses the weighting factor toward vertex 2 (specified in ). /// Barycentric coordinate b3, which expresses the weighting factor toward vertex 3 (specified in ). /// A new containing the 2D Cartesian coordinates of the specified point. public static Float2 Barycentric(Float2 value1, Float2 value2, Float2 value3, float amount1, float amount2) { Barycentric(ref value1, ref value2, ref value3, amount1, amount2, out Float2 result); return result; } /// /// Restricts a value to be within a specified range. /// /// The value to clamp. /// The minimum value. /// The maximum value. /// When the method completes, contains the clamped value. public static void Clamp(ref Float2 value, ref Float2 min, ref Float2 max, out Float2 result) { float x = value.X; x = x > max.X ? max.X : x; x = x < min.X ? min.X : x; float y = value.Y; y = y > max.Y ? max.Y : y; y = y < min.Y ? min.Y : y; result = new Float2(x, y); } /// /// Restricts a value to be within a specified range. /// /// The value to clamp. /// The minimum value. /// The maximum value. /// The clamped value. public static Float2 Clamp(Float2 value, Float2 min, Float2 max) { Clamp(ref value, ref min, ref max, out Float2 result); return result; } /// /// Saturates this instance in the range [0,1]. /// public void Saturate() { X = X < 0.0f ? 0.0f : X > 1.0f ? 1.0f : X; Y = Y < 0.0f ? 0.0f : Y > 1.0f ? 1.0f : Y; } /// /// Calculates the area of the triangle. /// /// The first triangle vertex. /// The second triangle vertex. /// The third triangle vertex. /// The triangle area. public static float TriangleArea(ref Float2 v0, ref Float2 v1, ref Float2 v2) { return Mathf.Abs((v0.X * (v1.Y - v2.Y) + v1.X * (v2.Y - v0.Y) + v2.X * (v0.Y - v1.Y)) / 2); } /// /// Calculates the distance between two vectors. /// /// The first vector. /// The second vector. /// When the method completes, contains the distance between the two vectors. /// may be preferred when only the relative distance is needed and speed is of the essence. public static void Distance(ref Float2 value1, ref Float2 value2, out float result) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; result = (float)Math.Sqrt(x * x + y * y); } /// /// Calculates the distance between two vectors. /// /// The first vector. /// The second vector. /// The distance between the two vectors. /// may be preferred when only the relative distance is needed and speed is of the essence. public static float Distance(Float2 value1, Float2 value2) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; return (float)Math.Sqrt(x * x + y * y); } /// /// Calculates the distance between two vectors. /// /// The first vector. /// The second vector. /// The distance between the two vectors. /// may be preferred when only the relative distance is needed and speed is of the essence. public static float Distance(ref Float2 value1, ref Float2 value2) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; return (float)Math.Sqrt(x * x + y * y); } /// /// Calculates the squared distance between two vectors. /// /// The first vector. /// The second vector /// When the method completes, contains the squared distance between the two vectors. public static void DistanceSquared(ref Float2 value1, ref Float2 value2, out float result) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; result = x * x + y * y; } /// /// Calculates the squared distance between two vectors. /// /// The first vector. /// The second vector /// The squared distance between the two vectors. public static float DistanceSquared(ref Float2 value1, ref Float2 value2) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; return x * x + y * y; } /// /// Calculates the squared distance between two vectors. /// /// The first vector. /// The second vector. /// The squared distance between the two vectors. public static float DistanceSquared(Float2 value1, Float2 value2) { float x = value1.X - value2.X; float y = value1.Y - value2.Y; return x * x + y * y; } /// /// Tests whether one vector is near another vector. /// /// The left vector. /// The right vector. /// The epsilon. /// true if left and right are near, false otherwise public static bool NearEqual(Float2 left, Float2 right, float epsilon = Mathf.Epsilon) { return NearEqual(ref left, ref right, epsilon); } /// /// Tests whether one vector is near another vector. /// /// The left vector. /// The right vector. /// The epsilon. /// true if left and right are near another, false otherwise public static bool NearEqual(ref Float2 left, ref Float2 right, float epsilon = Mathf.Epsilon) { return Mathf.WithinEpsilon(left.X, right.X, epsilon) && Mathf.WithinEpsilon(left.Y, right.Y, epsilon); } /// /// Calculates the dot product of two vectors. /// /// First source vector. /// Second source vector. /// When the method completes, contains the dot product of the two vectors. public static void Dot(ref Float2 left, ref Float2 right, out float result) { result = left.X * right.X + left.Y * right.Y; } /// /// Calculates the dot product of two vectors. /// /// First source vector. /// Second source vector. /// The dot product of the two vectors. public static float Dot(ref Float2 left, ref Float2 right) { return left.X * right.X + left.Y * right.Y; } /// /// Calculates the dot product of two vectors. /// /// First source vector. /// Second source vector. /// The dot product of the two vectors. public static float Dot(Float2 left, Float2 right) { return left.X * right.X + left.Y * right.Y; } /// /// Calculates the cross product of two vectors. /// /// First source vector. /// Second source vector. /// When the method completes, contains the cross product of the two vectors. public static void Cross(ref Float2 left, ref Float2 right, out float result) { result = left.X * right.Y - left.Y * right.X; } /// /// Calculates the cross product of two vectors. /// /// First source vector. /// Second source vector. /// The cross product of the two vectors. public static float Cross(ref Float2 left, ref Float2 right) { return left.X * right.Y - left.Y * right.X; } /// /// Calculates the cross product of two vectors. /// /// First source vector. /// Second source vector. /// The cross product of the two vectors. public static float Cross(Float2 left, Float2 right) { return left.X * right.Y - left.Y * right.X; } /// /// Converts the vector into a unit vector. /// /// The vector to normalize. /// When the method completes, contains the normalized vector. public static void Normalize(ref Float2 value, out Float2 result) { result = value; result.Normalize(); } /// /// Converts the vector into a unit vector. /// /// The vector to normalize. /// The normalized vector. public static Float2 Normalize(Float2 value) { value.Normalize(); return value; } /// /// Makes sure that Length of the output vector is always below max and above 0. /// /// Input vector. /// Max Length public static Float2 ClampLength(Float2 vector, float max) { return ClampLength(vector, 0, max); } /// /// Makes sure that Length of the output vector is always below max and above min. /// /// Input vector. /// Min Length /// Max Length public static Float2 ClampLength(Float2 vector, float min, float max) { ClampLength(vector, min, max, out Float2 result); return result; } /// /// Makes sure that Length of the output vector is always below max and above min. /// /// Input vector. /// Min Length /// Max Length /// The result value. public static void ClampLength(Float2 vector, float min, float max, out Float2 result) { result = vector; float lenSq = result.LengthSquared; if (lenSq > max * max) { float scaleFactor = max / (float)Math.Sqrt(lenSq); result.X *= scaleFactor; result.Y *= scaleFactor; } if (lenSq < min * min) { float scaleFactor = min / (float)Math.Sqrt(lenSq); result.X *= scaleFactor; result.Y *= scaleFactor; } } /// /// Returns the vector with components rounded to the nearest integer. /// /// The value. /// The result. public static Float2 Round(Float2 v) { return new Float2(Mathf.Round(v.X), Mathf.Round(v.Y)); } /// /// Returns the vector with components containing the smallest integer greater to or equal to the original value. /// /// The value. /// The result. public static Float2 Ceil(Float2 v) { return new Float2(Mathf.Ceil(v.X), Mathf.Ceil(v.Y)); } /// /// Breaks the components of the vector into an integral and a fractional part. Returns vector made of fractional parts. /// /// The value. /// The result. public static Float2 Mod(Float2 v) { return new Float2(v.X - (int)v.X, v.Y - (int)v.Y); } /// /// Performs a linear interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// When the method completes, contains the linear interpolation of the two vectors. /// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned. public static void Lerp(ref Float2 start, ref Float2 end, float amount, out Float2 result) { result.X = Mathf.Lerp(start.X, end.X, amount); result.Y = Mathf.Lerp(start.Y, end.Y, amount); } /// /// Performs a linear interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// The linear interpolation of the two vectors. /// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned. public static Float2 Lerp(Float2 start, Float2 end, float amount) { Lerp(ref start, ref end, amount, out Float2 result); return result; } /// /// Performs a linear interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// When the method completes, contains the linear interpolation of the two vectors. /// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned. public static void Lerp(ref Float2 start, ref Float2 end, ref Float2 amount, out Float2 result) { result.X = Mathf.Lerp(start.X, end.X, amount.X); result.Y = Mathf.Lerp(start.Y, end.Y, amount.Y); } /// /// Performs a linear interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// The linear interpolation of the two vectors. /// Passing a value of 0 will cause to be returned; a value of 1 will cause to be returned. public static Float2 Lerp(Float2 start, Float2 end, Float2 amount) { Lerp(ref start, ref end, ref amount, out Float2 result); return result; } /// /// Performs a cubic interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// When the method completes, contains the cubic interpolation of the two vectors. public static void SmoothStep(ref Float2 start, ref Float2 end, float amount, out Float2 result) { amount = Mathf.SmoothStep(amount); Lerp(ref start, ref end, amount, out result); } /// /// Performs a cubic interpolation between two vectors. /// /// Start vector. /// End vector. /// Value between 0 and 1 indicating the weight of . /// The cubic interpolation of the two vectors. public static Float2 SmoothStep(Float2 start, Float2 end, float amount) { SmoothStep(ref start, ref end, amount, out Float2 result); return result; } /// /// Performs a Hermite spline interpolation. /// /// First source position vector. /// First source tangent vector. /// Second source position vector. /// Second source tangent vector. /// Weighting factor. /// When the method completes, contains the result of the Hermite spline interpolation. public static void Hermite(ref Float2 value1, ref Float2 tangent1, ref Float2 value2, ref Float2 tangent2, float amount, out Float2 result) { float squared = amount * amount; float cubed = amount * squared; float part1 = 2.0f * cubed - 3.0f * squared + 1.0f; float part2 = -2.0f * cubed + 3.0f * squared; float part3 = cubed - 2.0f * squared + amount; float part4 = cubed - squared; result.X = value1.X * part1 + value2.X * part2 + tangent1.X * part3 + tangent2.X * part4; result.Y = value1.Y * part1 + value2.Y * part2 + tangent1.Y * part3 + tangent2.Y * part4; } /// /// Performs a Hermite spline interpolation. /// /// First source position vector. /// First source tangent vector. /// Second source position vector. /// Second source tangent vector. /// Weighting factor. /// The result of the Hermite spline interpolation. public static Float2 Hermite(Float2 value1, Float2 tangent1, Float2 value2, Float2 tangent2, float amount) { Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out Float2 result); return result; } /// /// Calculates the 2D vector perpendicular to the given 2D vector. The result is always rotated 90-degrees in a counter-clockwise direction for a 2D coordinate system where the positive Y axis goes up. /// /// The input direction. /// The result. public static Float2 Perpendicular(Float2 inDirection) { return new Float2(-inDirection.Y, inDirection.X); } /// /// Calculates the 2D vector perpendicular to the given 2D vector. The result is always rotated 90-degrees in a counter-clockwise direction for a 2D coordinate system where the positive Y axis goes up. /// /// The in direction. /// When the method completes, contains the result of the calculation. public static void Perpendicular(ref Float2 inDirection, out Float2 result) { result = new Float2(-inDirection.Y, inDirection.X); } /// /// Performs a Catmull-Rom interpolation using the specified positions. /// /// The first position in the interpolation. /// The second position in the interpolation. /// The third position in the interpolation. /// The fourth position in the interpolation. /// Weighting factor. /// When the method completes, contains the result of the Catmull-Rom interpolation. public static void CatmullRom(ref Float2 value1, ref Float2 value2, ref Float2 value3, ref Float2 value4, float amount, out Float2 result) { float squared = amount * amount; float cubed = amount * squared; result.X = 0.5f * (2.0f * value2.X + (-value1.X + value3.X) * amount + (2.0f * value1.X - 5.0f * value2.X + 4.0f * value3.X - value4.X) * squared + (-value1.X + 3.0f * value2.X - 3.0f * value3.X + value4.X) * cubed); result.Y = 0.5f * (2.0f * value2.Y + (-value1.Y + value3.Y) * amount + (2.0f * value1.Y - 5.0f * value2.Y + 4.0f * value3.Y - value4.Y) * squared + (-value1.Y + 3.0f * value2.Y - 3.0f * value3.Y + value4.Y) * cubed); } /// /// Performs a Catmull-Rom interpolation using the specified positions. /// /// The first position in the interpolation. /// The second position in the interpolation. /// The third position in the interpolation. /// The fourth position in the interpolation. /// Weighting factor. /// A vector that is the result of the Catmull-Rom interpolation. public static Float2 CatmullRom(Float2 value1, Float2 value2, Float2 value3, Float2 value4, float amount) { CatmullRom(ref value1, ref value2, ref value3, ref value4, amount, out Float2 result); return result; } /// /// Returns a vector containing the largest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// When the method completes, contains an new vector composed of the largest components of the source vectors. public static void Max(ref Float2 left, ref Float2 right, out Float2 result) { result.X = left.X > right.X ? left.X : right.X; result.Y = left.Y > right.Y ? left.Y : right.Y; } /// /// Returns a vector containing the largest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// A vector containing the largest components of the source vectors. public static Float2 Max(Float2 left, Float2 right) { Max(ref left, ref right, out Float2 result); return result; } /// /// Returns a vector containing the smallest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// When the method completes, contains an new vector composed of the smallest components of the source vectors. public static void Min(ref Float2 left, ref Float2 right, out Float2 result) { result.X = left.X < right.X ? left.X : right.X; result.Y = left.Y < right.Y ? left.Y : right.Y; } /// /// Returns a vector containing the smallest components of the specified vectors. /// /// The first source vector. /// The second source vector. /// A vector containing the smallest components of the source vectors. public static Float2 Min(Float2 left, Float2 right) { Min(ref left, ref right, out Float2 result); return result; } /// /// Returns the absolute value of a vector. /// /// The value. /// A vector which components are less or equal to 0. public static Float2 Abs(Float2 v) { return new Float2(Math.Abs(v.X), Math.Abs(v.Y)); } /// /// Returns the reflection of a vector off a surface that has the specified normal. /// /// The source vector. /// Normal of the surface. /// When the method completes, contains the reflected vector. /// Reflect only gives the direction of a reflection off a surface, it does not determine whether the original vector was close enough to the surface to hit it. public static void Reflect(ref Float2 vector, ref Float2 normal, out Float2 result) { float dot = vector.X * normal.X + vector.Y * normal.Y; result.X = vector.X - 2.0f * dot * normal.X; result.Y = vector.Y - 2.0f * dot * normal.Y; } /// /// Returns the reflection of a vector off a surface that has the specified normal. /// /// The source vector. /// Normal of the surface. /// The reflected vector. /// Reflect only gives the direction of a reflection off a surface, it does not determine whether the original vector was close enough to the surface to hit it. public static Float2 Reflect(Float2 vector, Float2 normal) { Reflect(ref vector, ref normal, out Float2 result); return result; } /// /// Transforms a 2D vector by the given rotation. /// /// The vector to rotate. /// The rotation to apply. /// When the method completes, contains the transformed . public static void Transform(ref Float2 vector, ref Quaternion rotation, out Float2 result) { float x = rotation.X + rotation.X; float y = rotation.Y + rotation.Y; float z = rotation.Z + rotation.Z; float wz = rotation.W * z; float xx = rotation.X * x; float xy = rotation.X * y; float yy = rotation.Y * y; float zz = rotation.Z * z; result = new Float2(vector.X * (1.0f - yy - zz) + vector.Y * (xy - wz), vector.X * (xy + wz) + vector.Y * (1.0f - xx - zz)); } /// /// Transforms a 2D vector by the given rotation. /// /// The vector to rotate. /// The rotation to apply. /// The transformed . public static Float2 Transform(Float2 vector, Quaternion rotation) { Transform(ref vector, ref rotation, out Float2 result); return result; } /// /// Transforms a 2D vector by the given . /// /// The source vector. /// The transformation . /// When the method completes, contains the transformed . public static void Transform(ref Float2 vector, ref Matrix transform, out Float4 result) { result = new Float4(vector.X * transform.M11 + vector.Y * transform.M21 + transform.M41, vector.X * transform.M12 + vector.Y * transform.M22 + transform.M42, vector.X * transform.M13 + vector.Y * transform.M23 + transform.M43, vector.X * transform.M14 + vector.Y * transform.M24 + transform.M44); } /// /// Transforms a 2D vector by the given . /// /// The source vector. /// The transformation . /// The transformed . public static Float4 Transform(Float2 vector, Matrix transform) { Transform(ref vector, ref transform, out Float4 result); return result; } /// /// Performs a coordinate transformation using the given . /// /// The coordinate vector to transform. /// The transformation . /// When the method completes, contains the transformed coordinates. /// /// A coordinate transform performs the transformation with the assumption that the w component /// is one. The four dimensional vector obtained from the transformation operation has each /// component in the vector divided by the w component. This forces the w component to be one and /// therefore makes the vector homogeneous. The homogeneous vector is often preferred when working /// with coordinates as the w component can safely be ignored. /// public static void TransformCoordinate(ref Float2 coordinate, ref Matrix transform, out Float2 result) { var vector = new Float4 { X = coordinate.X * transform.M11 + coordinate.Y * transform.M21 + transform.M41, Y = coordinate.X * transform.M12 + coordinate.Y * transform.M22 + transform.M42, Z = coordinate.X * transform.M13 + coordinate.Y * transform.M23 + transform.M43, W = 1f / (coordinate.X * transform.M14 + coordinate.Y * transform.M24 + transform.M44) }; result = new Float2(vector.X * vector.W, vector.Y * vector.W); } /// /// Performs a coordinate transformation using the given . /// /// The coordinate vector to transform. /// The transformation . /// The transformed coordinates. /// /// A coordinate transform performs the transformation with the assumption that the w component /// is one. The four dimensional vector obtained from the transformation operation has each /// component in the vector divided by the w component. This forces the w component to be one and /// therefore makes the vector homogeneous. The homogeneous vector is often preferred when working /// with coordinates as the w component can safely be ignored. /// public static Float2 TransformCoordinate(Float2 coordinate, Matrix transform) { TransformCoordinate(ref coordinate, ref transform, out Float2 result); return result; } /// /// Performs a normal transformation using the given . /// /// The normal vector to transform. /// The transformation . /// When the method completes, contains the transformed normal. /// /// A normal transform performs the transformation with the assumption that the w component /// is zero. This causes the fourth row and fourth column of the matrix to be unused. The /// end result is a vector that is not translated, but all other transformation properties /// apply. This is often preferred for normal vectors as normals purely represent direction /// rather than location because normal vectors should not be translated. /// public static void TransformNormal(ref Float2 normal, ref Matrix transform, out Float2 result) { result = new Float2(normal.X * transform.M11 + normal.Y * transform.M21, normal.X * transform.M12 + normal.Y * transform.M22); } /// /// Performs a normal transformation using the given . /// /// The normal vector to transform. /// The transformation . /// The transformed normal. /// /// A normal transform performs the transformation with the assumption that the w component /// is zero. This causes the fourth row and fourth column of the matrix to be unused. The /// end result is a vector that is not translated, but all other transformation properties /// apply. This is often preferred for normal vectors as normals purely represent direction /// rather than location because normal vectors should not be translated. /// public static Float2 TransformNormal(Float2 normal, Matrix transform) { TransformNormal(ref normal, ref transform, out Float2 result); return result; } /// /// funcion for grid snaping snap to absolute world grid ///
desined for snaping using a ray / draging object
///
/// /// /// out = Ceil(((A - (GridSize * 0.5f)) / GridSize) * GridSize public static Float2 SnapToGrid(Float2 Translation, Float2 GridSize) { Translation.X = Mathf.Ceil((Translation.X - (GridSize.X * 0.5f)) / GridSize.Y) * GridSize.X; Translation.Y = Mathf.Ceil((Translation.Y - (GridSize.Y * 0.5f)) / GridSize.X) * GridSize.Y; return Translation; } /// /// funcion for grid snaping snap to absolute world grid ///
desined for snaping using a ray / draging object
///
/// /// /// out = Ceil(((A - (GridSize * 0.5f)) / GridSize) * GridSize public static Float2 SnapToGrid(Float2 Translation, float GridSize) { Translation.X = Mathf.Ceil((Translation.X - (GridSize * 0.5f)) / GridSize) * GridSize; Translation.Y = Mathf.Ceil((Translation.Y - (GridSize * 0.5f)) / GridSize) * GridSize; return Translation; } /// /// Adds two vectors. /// /// The first vector to add. /// The second vector to add. /// The sum of the two vectors. public static Float2 operator +(Float2 left, Float2 right) { return new Float2(left.X + right.X, left.Y + right.Y); } /// /// Multiplies a vector with another by performing component-wise multiplication equivalent to . /// /// The first vector to multiply. /// The second vector to multiply. /// The multiplication of the two vectors. public static Float2 operator *(Float2 left, Float2 right) { return new Float2(left.X * right.X, left.Y * right.Y); } /// /// Assert a vector (return it unchanged). /// /// The vector to assert (unchanged). /// The asserted (unchanged) vector. public static Float2 operator +(Float2 value) { return value; } /// /// Subtracts two vectors. /// /// The first vector to subtract. /// The second vector to subtract. /// The difference of the two vectors. public static Float2 operator -(Float2 left, Float2 right) { return new Float2(left.X - right.X, left.Y - right.Y); } /// /// Reverses the direction of a given vector. /// /// The vector to negate. /// A vector facing in the opposite direction. public static Float2 operator -(Float2 value) { return new Float2(-value.X, -value.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator *(float scale, Float2 value) { return new Float2(value.X * scale, value.Y * scale); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator *(Float2 value, float scale) { return new Float2(value.X * scale, value.Y * scale); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator /(Float2 value, float scale) { return new Float2(value.X / scale, value.Y / scale); } /// /// Scales a vector by the given value. /// /// The amount by which to scale the vector. /// The vector to scale. /// The scaled vector. public static Float2 operator /(float scale, Float2 value) { return new Float2(scale / value.X, scale / value.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator *(double scale, Float2 value) { var s = (float)scale; return new Float2(value.X * s, value.Y * s); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator *(Float2 value, double scale) { var s = (float)scale; return new Float2(value.X * s, value.Y * s); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator /(Float2 value, double scale) { var s = (float)scale; return new Float2(value.X / s, value.Y / s); } /// /// Scales a vector by the given value. /// /// The amount by which to scale the vector. /// The vector to scale. /// The scaled vector. public static Float2 operator /(double scale, Float2 value) { var s = (float)scale; return new Float2(s / value.X, s / value.Y); } /// /// Scales a vector by the given value. /// /// The vector to scale. /// The amount by which to scale the vector. /// The scaled vector. public static Float2 operator /(Float2 value, Float2 scale) { return new Float2(value.X / scale.X, value.Y / scale.Y); } /// /// Remainder of value divided by scale. /// /// The vector to scale. /// The amount by which to scale the vector. /// The remained vector. public static Float2 operator %(Float2 value, float scale) { return new Float2(value.X % scale, value.Y % scale); } /// /// Remainder of value divided by scale. /// /// The amount by which to scale the vector. /// The vector to scale. /// The remained vector. public static Float2 operator %(float value, Float2 scale) { return new Float2(value % scale.X, value % scale.Y); } /// /// Remainder of value divided by scale. /// /// The vector to scale. /// The amount by which to scale the vector. /// The remained vector. public static Float2 operator %(Float2 value, Float2 scale) { return new Float2(value.X % scale.X, value.Y % scale.Y); } /// /// Performs a component-wise addition. /// /// The input vector. /// The scalar value to be added on elements /// The vector with added scalar for each element. public static Float2 operator +(Float2 value, float scalar) { return new Float2(value.X + scalar, value.Y + scalar); } /// /// Performs a component-wise addition. /// /// The input vector. /// The scalar value to be added on elements /// The vector with added scalar for each element. public static Float2 operator +(float scalar, Float2 value) { return new Float2(scalar + value.X, scalar + value.Y); } /// /// Performs a component-wise subtraction. /// /// The input vector. /// The scalar value to be subtracted from elements /// The vector with subtracted scalar from each element. public static Float2 operator -(Float2 value, float scalar) { return new Float2(value.X - scalar, value.Y - scalar); } /// /// Performs a component-wise subtraction. /// /// The input vector. /// The scalar value to be subtracted from elements /// The vector with subtracted scalar from each element. public static Float2 operator -(float scalar, Float2 value) { return new Float2(scalar - value.X, scalar - value.Y); } /// /// Tests for equality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has the same value as ; otherwise,false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Float2 left, Float2 right) { return Mathf.NearEqual(left.X, right.X) && Mathf.NearEqual(left.Y, right.Y); } /// /// Tests for inequality between two objects. /// /// The first value to compare. /// The second value to compare. /// true if has a different value than ; otherwise,false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Float2 left, Float2 right) { return !Mathf.NearEqual(left.X, right.X) || !Mathf.NearEqual(left.Y, right.Y); } /// /// Performs an implicit conversion from to . /// /// The value. /// The result of the conversion. public static implicit operator Vector2(Float2 value) { return new Vector2(value.X, value.Y); } /// /// Performs an implicit conversion from to . /// /// The value. /// The result of the conversion. public static implicit operator Double2(Float2 value) { return new Double2(value.X, value.Y); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator Float3(Float2 value) { return new Float3(value, 0.0f); } /// /// Performs an explicit conversion from to . /// /// The value. /// The result of the conversion. public static explicit operator Float4(Float2 value) { return new Float4(value, 0.0f, 0.0f); } /// /// Returns a that represents this instance. /// /// A that represents this instance. public override string ToString() { return string.Format(CultureInfo.CurrentCulture, "X:{0} Y:{1}", X, Y); } /// /// Returns a that represents this instance. /// /// The format. /// A that represents this instance. public string ToString(string format) { if (format == null) return ToString(); return string.Format(CultureInfo.CurrentCulture, _formatString, X.ToString(format, CultureInfo.CurrentCulture), Y.ToString(format, CultureInfo.CurrentCulture)); } /// /// Returns a that represents this instance. /// /// The format provider. /// A that represents this instance. public string ToString(IFormatProvider formatProvider) { return string.Format(formatProvider, _formatString, X, Y); } /// /// Returns a that represents this instance. /// /// The format. /// The format provider. /// A that represents this instance. public string ToString(string format, IFormatProvider formatProvider) { if (format == null) return ToString(formatProvider); return string.Format(formatProvider, _formatString, X.ToString(format, formatProvider), Y.ToString(format, formatProvider)); } /// /// Returns a hash code for this instance. /// public override int GetHashCode() { unchecked { return (X.GetHashCode() * 397) ^ Y.GetHashCode(); } } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(ref Float2 other) { return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); } /// /// Determines whether the specified are equal. /// public static bool Equals(ref Float2 a, ref Float2 b) { return Mathf.NearEqual(a.X, b.X) && Mathf.NearEqual(a.Y, b.Y); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Float2 other) { return Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); } /// /// Determines whether the specified is equal to this instance. /// /// The to compare with this instance. /// true if the specified is equal to this instance; otherwise, false. public override bool Equals(object value) { return value is Float2 other && Mathf.NearEqual(other.X, X) && Mathf.NearEqual(other.Y, Y); } } }