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;
}
}
}