using System; using System.Runtime.InteropServices; namespace TrueCraft.API { /// /// Represents the location of an object in 3D space. /// [StructLayout(LayoutKind.Explicit)] public struct Vector3 : IEquatable { [FieldOffset(0)] public double X; [FieldOffset(8)] public double Y; [FieldOffset(16)] public double Z; public Vector3(double value) { X = Y = Z = value; } public Vector3(double x, double y, double z) { X = x; Y = y; Z = z; } public Vector3(Vector3 v) { X = v.X; Y = v.Y; Z = v.Z; } /// /// Converts this Vector3 to a string in the format <x,y,z>. /// /// public override string ToString() { return string.Format("<{0},{1},{2}>", X, Y, Z); } #region Math /// /// Truncates the decimal component of each part of this Vector3. /// public Vector3 Floor() { return new Vector3(Math.Floor(X), Math.Floor(Y), Math.Floor(Z)); } /// /// Clamps the vector to within the specified value. /// /// Value. public void Clamp(double value) { if (Math.Abs(X) > value) X = value * (X < 0 ? -1 : 1); if (Math.Abs(Y) > value) Y = value * (Y < 0 ? -1 : 1); if (Math.Abs(Z) > value) Z = value * (Z < 0 ? -1 : 1); } /// /// Calculates the distance between two Vector3 objects. /// public double DistanceTo(Vector3 other) { return Math.Sqrt(Square(other.X - X) + Square(other.Y - Y) + Square(other.Z - Z)); } /// /// Calculates the square of a num. /// private double Square(double num) { return num * num; } /// /// Finds the distance of this vector from Vector3.Zero /// public double Distance { get { return DistanceTo(Zero); } } public static Vector3 Min(Vector3 value1, Vector3 value2) { return new Vector3( Math.Min(value1.X, value2.X), Math.Min(value1.Y, value2.Y), Math.Min(value1.Z, value2.Z) ); } public static Vector3 Max(Vector3 value1, Vector3 value2) { return new Vector3( Math.Max(value1.X, value2.X), Math.Max(value1.Y, value2.Y), Math.Max(value1.Z, value2.Z) ); } #endregion #region Operators public static bool operator !=(Vector3 a, Vector3 b) { return !a.Equals(b); } public static bool operator ==(Vector3 a, Vector3 b) { return a.Equals(b); } public static Vector3 operator +(Vector3 a, Vector3 b) { return new Vector3( a.X + b.X, a.Y + b.Y, a.Z + b.Z); } public static Vector3 operator -(Vector3 a, Vector3 b) { return new Vector3( a.X - b.X, a.Y - b.Y, a.Z - b.Z); } public static Vector3 operator +(Vector3 a, Size b) { return new Vector3( a.X + b.Width, a.Y + b.Height, a.Z + b.Depth); } public static Vector3 operator -(Vector3 a, Size b) { return new Vector3( a.X - b.Width, a.Y - b.Height, a.Z - b.Depth); } public static Vector3 operator -(Vector3 a) { return new Vector3( -a.X, -a.Y, -a.Z); } public static Vector3 operator *(Vector3 a, Vector3 b) { return new Vector3( a.X * b.X, a.Y * b.Y, a.Z * b.Z); } public static Vector3 operator /(Vector3 a, Vector3 b) { return new Vector3( a.X / b.X, a.Y / b.Y, a.Z / b.Z); } public static Vector3 operator %(Vector3 a, Vector3 b) { return new Vector3(a.X % b.X, a.Y % b.Y, a.Z % b.Z); } public static Vector3 operator +(Vector3 a, double b) { return new Vector3( a.X + b, a.Y + b, a.Z + b); } public static Vector3 operator -(Vector3 a, double b) { return new Vector3( a.X - b, a.Y - b, a.Z - b); } public static Vector3 operator *(Vector3 a, double b) { return new Vector3( a.X * b, a.Y * b, a.Z * b); } public static Vector3 operator /(Vector3 a, double b) { return new Vector3( a.X / b, a.Y / b, a.Z / b); } public static Vector3 operator %(Vector3 a, double b) { return new Vector3(a.X % b, a.Y % b, a.Y % b); } public static Vector3 operator +(double a, Vector3 b) { return new Vector3( a + b.X, a + b.Y, a + b.Z); } public static Vector3 operator -(double a, Vector3 b) { return new Vector3( a - b.X, a - b.Y, a - b.Z); } public static Vector3 operator *(double a, Vector3 b) { return new Vector3( a * b.X, a * b.Y, a * b.Z); } public static Vector3 operator /(double a, Vector3 b) { return new Vector3( a / b.X, a / b.Y, a / b.Z); } public static Vector3 operator %(double a, Vector3 b) { return new Vector3(a % b.X, a % b.Y, a % b.Y); } #endregion #region Conversion operators public static implicit operator Vector3(Coordinates3D a) { return new Vector3(a.X, a.Y, a.Z); } public static explicit operator Vector3(Coordinates2D c) { return new Vector3(c.X, 0, c.Z); } public static implicit operator Vector3(Size s) { return new Vector3(s.Width, s.Height, s.Depth); } #endregion #region Constants public static readonly Vector3 Zero = new Vector3(0); public static readonly Vector3 One = new Vector3(1); public static readonly Vector3 Up = new Vector3(0, 1, 0); public static readonly Vector3 Down = new Vector3(0, -1, 0); public static readonly Vector3 Left = new Vector3(-1, 0, 0); public static readonly Vector3 Right = new Vector3(1, 0, 0); public static readonly Vector3 Backwards = new Vector3(0, 0, -1); public static readonly Vector3 Forwards = new Vector3(0, 0, 1); public static readonly Vector3 East = new Vector3(1, 0, 0); public static readonly Vector3 West = new Vector3(-1, 0, 0); public static readonly Vector3 North = new Vector3(0, 0, -1); public static readonly Vector3 South = new Vector3(0, 0, 1); #endregion public bool Equals(Vector3 other) { return other.X.Equals(X) && other.Y.Equals(Y) && other.Z.Equals(Z); } public override bool Equals(object obj) { return obj is Vector3 && Equals((Vector3)obj); } public override int GetHashCode() { unchecked { int result = X.GetHashCode(); result = (result * 397) ^ Y.GetHashCode(); result = (result * 397) ^ Z.GetHashCode(); return result; } } } }