using System; #if UNITY_5_3_OR_NEWER using Vector3Float = UnityEngine.Vector3; #endif namespace LinearAlgebra { /// /// A direction in 3D space /// /// A direction is represented using two angles: /// * The horizontal angle ranging from -180 (inclusive) to 180 (exclusive) /// degrees which is a rotation in the horizontal plane /// * A vertical angle ranging from -90 (inclusive) to 90 (exclusive) degrees /// which is the rotation in the up/down direction applied after the horizontal /// rotation has been applied. /// The angles are automatically normalized to stay within the abovenmentioned /// ranges. public class Direction { public float horizontal; public float vertical; public Direction() { horizontal = 0; vertical = 0; } public Direction(Angle horizontal, Angle vertical) { this.horizontal = horizontal.inDegrees; this.vertical = vertical.inDegrees; this.Normalize(); } public static Direction Degrees(float horizontal, float vertical) { Direction d = new() { horizontal = horizontal, vertical = vertical }; d.Normalize(); return d; } public static Direction Radians(float horizontal, float vertical) { Direction d = new() { horizontal = horizontal * Angle.Rad2Deg, vertical = vertical * Angle.Rad2Deg }; d.Normalize(); return d; } public readonly static Direction forward = Degrees(0, 0); public readonly static Direction backward = Degrees(-180, 0); public readonly static Direction up = Degrees(0, 90); public readonly static Direction down = Degrees(0, -90); public readonly static Direction left = Degrees(-90, 0); public readonly static Direction right = Degrees(90, 0); public void Normalize() { this.vertical = Angles.Normalize(this.vertical); if (this.vertical > 90 || this.vertical < -90) { this.horizontal += 180; this.vertical = 180 - this.vertical; } this.horizontal = Angles.Normalize(this.horizontal); } public Vector3Float ToVector3() { float verticalRad = ((float)Math.PI / 2) - this.vertical * Angle.Deg2Rad; float horizontalRad = this.horizontal * Angle.Deg2Rad; float cosVertical = (float)Math.Cos(verticalRad); float sinVertical = (float)Math.Sin(verticalRad); float cosHorizontal = (float)Math.Cos(horizontalRad); float sinHorizontal = (float)Math.Sin(horizontalRad); float x = sinVertical * sinHorizontal; float y = cosVertical; float z = sinVertical * cosHorizontal; Vector3Float v = new(x, y, z); return v; } public static bool operator ==(Direction d1, Direction d2) { bool horizontalEq = d1.horizontal == d2.horizontal; bool verticalEq = d1.vertical == d2.vertical; return horizontalEq && verticalEq; } public static bool operator !=(Direction d1, Direction d2) { bool horizontalNEq = d1.horizontal != d2.horizontal; bool verticalNEq = d1.vertical != d2.vertical; return horizontalNEq || verticalNEq; } public override bool Equals(object obj) { if (obj is not Direction d) return false; bool horizontalEq = this.horizontal == d.horizontal; bool verticalEq = this.vertical == d.vertical; return horizontalEq && verticalEq; } public override int GetHashCode() { return (this.horizontal, this.vertical).GetHashCode(); } } }