using System; using System.Numerics; namespace LinearAlgebra { /* public struct Vector2Int { public int horizontal; public int vertical; public Vector2Int(int horizontal, int vertical) { this.horizontal = horizontal; this.vertical = vertical; } /// /// A vector with zero for all axis /// public static readonly Vector2Int zero = new(0, 0); /// /// A vector with values (1, 1) /// public static readonly Vector2Int one = new(1, 1); /// /// A vector with values (0, 1) /// public static readonly Vector2Int up = new(0, 1); /// /// A vector with values (0, -1) /// public static readonly Vector2Int down = new(0, -1); /// /// A vector with values (0, 1) /// public static readonly Vector2Int forward = new(0, 1); /// /// A vector with values (0, -1) /// public static readonly Vector2Int back = new(0, -1); /// /// A vector3 with values (-1, 0) /// public static readonly Vector2Int left = new(-1, 0); /// /// A vector with values (1, 0) /// public static readonly Vector2Int right = new(1, 0); /// /// Tests if the vector has equal values as the given vector /// /// The vector to compare to /// true if the vector values are equal public readonly bool Equals(Vector2Int v) => this.horizontal == v.horizontal && vertical == v.vertical; /// /// Tests if the vector is equal to the given object /// /// The object to compare to /// false when the object is not a Vector2 or does not have equal values public override readonly bool Equals(object obj) { if (obj is not Vector2Int v) return false; return (this.horizontal == v.horizontal && this.vertical == v.vertical); } /// /// Tests if the two vectors have equal values /// /// The first vector /// The second vector /// truewhen the vectors have equal values /// Note that this uses a Float equality check which cannot be not exact in all cases. /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon public static bool operator ==(Vector2Int v1, Vector2Int v2) { return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); } /// /// Tests if two vectors have different values /// /// The first vector /// The second vector /// truewhen the vectors have different values /// Note that this uses a Float equality check which cannot be not exact in all case. /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon public static bool operator !=(Vector2Int v1, Vector2Int v2) { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } public readonly float magnitude { get { int h = this.horizontal; int v = this.vertical; return MathF.Sqrt(h * h + v * v); } } public static float MagnitudeOf(Vector2Int v) { return v.magnitude; } public static Vector2Int operator -(Vector2Int v1, Vector2Int v2) { return new Vector2Int(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); } public static Vector2Int operator +(Vector2Int v1, Vector2Int v2) { return new Vector2Int(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); } public static float Distance(Vector2Int v1, Vector2Int v2) { return (v1 - v2).magnitude; } } public struct Vector2Float { public float horizontal; public float vertical; public Vector2Float(float horizontal, float vertical) { this.horizontal = horizontal; this.vertical = vertical; } public readonly float magnitude { get { float h = this.horizontal; float v = this.vertical; return MathF.Sqrt(h * h + v * v); } } public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { return new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); } public static float Distance(Vector2Float v1, Vector2Float v2) { return (v1 - v2).magnitude; } } */ /// /// 2-dimensional vectors /// public struct Vector2Float { /// /// The right axis of the vector /// public float horizontal; // left/right /// /// The upward/forward axis of the vector /// public float vertical; // forward/backward // directions are to be inline with Vector3 as much as possible... /// /// Create a new 2-dimensional vector /// /// x axis value /// y axis value public Vector2Float(float x, float y) { this.horizontal = x; this.vertical = y; } /// /// Convert a Vector2Int into a Vector2Float /// /// The Vector2Int public Vector2Float(Vector2Int v) { this.horizontal = v.horizontal; this.vertical = v.vertical; } /// /// A vector with zero for all axis /// public static readonly Vector2Float zero = new Vector2Float(0, 0); /// /// A vector with values (1, 1) /// public static readonly Vector2Float one = new Vector2Float(1, 1); /// /// A vector with values (0, 1) /// public static readonly Vector2Float up = new Vector2Float(0, 1); /// /// A vector with values (0, -1) /// public static readonly Vector2Float down = new Vector2Float(0, -1); /// /// A vector with values (0, 1) /// public static readonly Vector2Float forward = new Vector2Float(0, 1); /// /// A vector with values (0, -1) /// public static readonly Vector2Float back = new Vector2Float(0, -1); /// /// A vector3 with values (-1, 0) /// public static readonly Vector2Float left = new Vector2Float(-1, 0); /// /// A vector with values (1, 0) /// public static readonly Vector2Float right = new Vector2Float(1, 0); /// /// The squared length of this vector /// /// The squared length /// The squared length is computationally simpler than the real length. /// Think of Pythagoras A^2 + B^2 = C^2. /// This leaves out the calculation of the squared root of C. public readonly float sqrMagnitude => horizontal * horizontal + vertical * vertical; public static float SqrMagnitudeOf(Vector2Float v) { return v.sqrMagnitude; } /// /// The length of this vector /// /// The length of this vector public readonly float magnitude => MathF.Sqrt(horizontal * horizontal + vertical * vertical); public static float MagnitudeOf(Vector2Float v) { return v.magnitude; } /// /// Convert the vector to a length of a 1 /// /// The vector with length 1 public Vector2Float normalized { get { float l = magnitude; Vector2Float v = zero; if (l > Float.epsilon) v = this / l; return v; } } public static Vector2Float Normalize(Vector2Float v) { return v.normalized; } /// /// Add two vectors /// /// The first vector /// The second vector /// The result of adding the two vectors public static Vector2Float operator +(Vector2Float v1, Vector2Float v2) { Vector2Float v = new Vector2Float(v1.horizontal + v2.horizontal, v1.vertical + v2.vertical); return v; } /// /// Subtract two vectors /// /// The first vector /// The second vector /// The result of adding the two vectors public static Vector2Float operator -(Vector2Float v1, Vector2Float v2) { Vector2Float v = new Vector2Float(v1.horizontal - v2.horizontal, v1.vertical - v2.vertical); return v; } /// /// Negate the vector /// /// The vector to negate /// The negated vector /// This will result in a vector pointing in the opposite direction public static Vector2Float operator -(Vector2Float v1) { Vector2Float v = new Vector2Float(-v1.horizontal, -v1.vertical); return v; } /// /// Scale a vector uniformly down /// /// The vector to scale /// The scaling factor /// The scaled vector /// Each component of the vector will be devided by the same factor. public static Vector2Float operator /(Vector2Float v, float f) { Vector2Float r = new(v.horizontal / f, v.vertical / f); return r; } /// /// Scale a vector uniformly up /// /// The vector to scale /// The scaling factor /// The scaled vector /// Each component of the vector will be multipled with the same factor. public static Vector2Float operator *(Vector2Float v1, float f) { Vector2Float v = new Vector2Float(v1.horizontal * f, v1.vertical * f); return v; } /// /// Scale a vector uniformly up /// /// The scaling factor /// The vector to scale /// The scaled vector /// Each component of the vector will be multipled with the same factor. public static Vector2Float operator *(float f, Vector2Float v1) { Vector2Float v = new Vector2Float(f * v1.horizontal, f * v1.vertical); return v; } /// @brief Scale the vector using another vector /// @param v1 The vector to scale /// @param v2 A vector with the scaling factors /// @return The scaled vector /// @remark Each component of the vector v1 will be multiplied with the /// matching component from the scaling vector v2. public static Vector2Float Scale(Vector2Float v1, Vector2Float v2) { return new Vector2Float(v1.horizontal * v2.horizontal, v1.vertical * v2.vertical); } /// /// Tests if the vector has equal values as the given vector /// /// The vector to compare to /// true if the vector values are equal //public readonly bool Equals(Vector2Float v1) => horizontal == v1.horizontal && vertical == v1.vertical; /// /// Tests if the two vectors have equal values /// /// The first vector /// The second vector /// truewhen the vectors have equal values /// Note that this uses a Float equality check which cannot be not exact in all cases. /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon public static bool operator ==(Vector2Float v1, Vector2Float v2) { return (v1.horizontal == v2.horizontal && v1.vertical == v2.vertical); } /// /// Tests if two vectors have different values /// /// The first vector /// The second vector /// truewhen the vectors have different values /// Note that this uses a Float equality check which cannot be not exact in all case. /// In most cases it is better to check if the Vector2.Distance between the vectors is smaller than Float.epsilon. /// Or more efficient: (v1 - v2).sqrMagnitude < Float.sqrEpsilon public static bool operator !=(Vector2Float v1, Vector2Float v2) { return (v1.horizontal != v2.horizontal || v1.vertical != v2.vertical); } /// /// Tests if the vector is equal to the given object /// /// The object to compare to /// false when the object is not a Vector2 or does not have equal values public override readonly bool Equals(object obj) { if (obj is not Vector2Float v) return false; return (horizontal == v.horizontal && vertical == v.vertical); } /// /// Get an hash code for the vector /// /// The hash code public override readonly int GetHashCode() { return HashCode.Combine(horizontal, vertical); } /// /// Get the distance between two vectors /// /// The first vector /// The second vector /// The distance between the two vectors public static float Distance(Vector2Float v1, Vector2Float v2) { float x = v1.horizontal - v2.horizontal; float y = v1.vertical - v2.vertical; float d = (float)Math.Sqrt(x * x + y * y); return d; } /// /// The dot product of two vectors /// /// The first vector /// The second vector /// The dot product of the two vectors public static float Dot(Vector2Float v1, Vector2Float v2) { return v1.horizontal * v2.horizontal + v1.vertical * v2.vertical; } /// /// Calculate the signed angle between two vectors. /// /// The starting vector /// The ending vector /// The axis to rotate around /// The signed angle in degrees public static float SignedAngle(Vector2Float from, Vector2Float to) { //float sign = Math.Sign(v1.y * v2.x - v1.x * v2.y); //return Vector2.Angle(v1, v2) * sign; float sqrMagFrom = from.sqrMagnitude; float sqrMagTo = to.sqrMagnitude; if (sqrMagFrom == 0 || sqrMagTo == 0) return 0; //if (!isfinite(sqrMagFrom) || !isfinite(sqrMagTo)) // return nanf(""); float angleFrom = (float)Math.Atan2(from.vertical, from.horizontal); float angleTo = (float)Math.Atan2(to.vertical, to.horizontal); return -(angleTo - angleFrom) * AngleFloat.Rad2Deg; } public static float UnsignedAngle(Vector2Float from, Vector2Float to) { return MathF.Abs(SignedAngle(from, to)); } /// /// Rotates the vector with the given angle /// /// The vector to rotate /// The angle in degrees /// public static Vector2Float Rotate(Vector2Float v1, AngleFloat angle) { float sin = (float)Math.Sin(angle.inRadians); float cos = (float)Math.Cos(angle.inRadians); // float sin = AngleFloat.Sin(angle); // float cos = AngleFloat.Cos(angle); float tx = v1.horizontal; float ty = v1.vertical; Vector2Float v = new Vector2Float() { horizontal = (cos * tx) - (sin * ty), vertical = (sin * tx) + (cos * ty) }; return v; } /// /// Lerp between two vectors /// /// The from vector /// The to vector /// The interpolation distance [0..1] /// The lerped vector /// The factor f is unclamped. Value 0 matches the *v1* vector, Value 1 /// matches the *v2* vector Value -1 is *v1* vector minus the difference /// between *v1* and *v2* etc. public static Vector2Float Lerp(Vector2Float v1, Vector2Float v2, float f) { Vector2Float v = v1 + (v2 - v1) * f; return v; } /// /// Map interval of angles between vectors [0..Pi] to interval [0..1] /// /// The first vector /// The second vector /// The resulting factor in interval [0..1] /// Vectors a and b must be normalized public static float ToFactor(Vector2Float v1, Vector2Float v2) { return (1 - Vector2Float.Dot(v1, v2)) / 2; } } }