using System; namespace Nanomesh { public readonly struct Vector3F : IEquatable, IInterpolable { public readonly float x; public readonly float y; public readonly float z; public Vector3F(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } public Vector3F(float x, float y) { this.x = x; this.y = y; z = 0F; } public float this[int index] { get { switch (index) { case 0: return x; case 1: return y; case 2: return z; default: throw new IndexOutOfRangeException("Invalid Vector3F index!"); } } } public override int GetHashCode() { return Vector3FComparer.Default.GetHashCode(this); //return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2); } public override bool Equals(object other) { if (!(other is Vector3F)) { return false; } return Equals((Vector3F)other); } public bool Equals(Vector3F other) { return Vector3FComparer.Default.Equals(this, other); //return x == other.x && y == other.y && z == other.z; } public static Vector3F operator +(in Vector3F a, in Vector3F b) { return new Vector3F(a.x + b.x, a.y + b.y, a.z + b.z); } public static Vector3F operator -(in Vector3F a, in Vector3F b) { return new Vector3F(a.x - b.x, a.y - b.y, a.z - b.z); } public static Vector3F operator -(in Vector3F a) { return new Vector3F(-a.x, -a.y, -a.z); } public static Vector3F operator *(in Vector3F a, float d) { return new Vector3F(a.x * d, a.y * d, a.z * d); } public static Vector3F operator *(float d, in Vector3F a) { return new Vector3F(a.x * d, a.y * d, a.z * d); } public static Vector3 operator *(double d, in Vector3F a) { return new Vector3(a.x * d, a.y * d, a.z * d); } public static Vector3F operator /(in Vector3F a, float d) { return new Vector3F(MathUtils.DivideSafe(a.x, d), MathUtils.DivideSafe(a.y, d), MathUtils.DivideSafe(a.z, d)); } public static bool operator ==(in Vector3F lhs, in Vector3F rhs) { float diff_x = lhs.x - rhs.x; float diff_y = lhs.y - rhs.y; float diff_z = lhs.z - rhs.z; float sqrmag = diff_x * diff_x + diff_y * diff_y + diff_z * diff_z; return sqrmag < MathUtils.EpsilonFloat; } public static bool operator !=(in Vector3F lhs, in Vector3F rhs) { return !(lhs == rhs); } public static Vector3F Cross(in Vector3F lhs, in Vector3F rhs) { return new Vector3F( lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x); } public static float Dot(in Vector3F lhs, in Vector3F rhs) { return lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z; } public static Vector3F Normalize(in Vector3F value) { float mag = Magnitude(value); return value / mag; } public Vector3F Normalized => Vector3F.Normalize(this); public static float Distance(in Vector3F a, in Vector3F b) { float diff_x = a.x - b.x; float diff_y = a.y - b.y; float diff_z = a.z - b.z; return MathF.Sqrt(diff_x * diff_x + diff_y * diff_y + diff_z * diff_z); } public static float Magnitude(in Vector3F vector) { return MathF.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); } public float SqrMagnitude => x * x + y * y + z * z; public static Vector3F Min(in Vector3F lhs, in Vector3F rhs) { return new Vector3F(MathF.Min(lhs.x, rhs.x), MathF.Min(lhs.y, rhs.y), MathF.Min(lhs.z, rhs.z)); } public static Vector3F Max(in Vector3F lhs, in Vector3F rhs) { return new Vector3F(MathF.Max(lhs.x, rhs.x), MathF.Max(lhs.y, rhs.y), MathF.Max(lhs.z, rhs.z)); } public static readonly Vector3F zeroVector = new Vector3F(0f, 0f, 0f); public static readonly Vector3F oneVector = new Vector3F(1f, 1f, 1f); public static readonly Vector3F positiveInfinityVector = new Vector3F(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); public static readonly Vector3F negativeInfinityVector = new Vector3F(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity); public static Vector3F Zero => zeroVector; public static Vector3F One => oneVector; public static Vector3F PositiveInfinity => positiveInfinityVector; public static Vector3F NegativeInfinity => negativeInfinityVector; public static float AngleRadians(in Vector3F from, in Vector3F to) { float denominator = MathF.Sqrt(from.SqrMagnitude * to.SqrMagnitude); if (denominator < 1e-15F) { return 0F; } float dot = MathF.Clamp(Dot(from, to) / denominator, -1F, 1F); return MathF.Acos(dot); } public static float AngleDegrees(in Vector3F from, in Vector3F to) { return AngleRadians(from, to) / MathF.PI * 180f; } public override string ToString() { return $"{x}, {y}, {z}"; } public Vector3F Interpolate(Vector3F other, double ratio) => (ratio * this + (1 - ratio) * other).Normalized; } }