2022-04-17 13:43:38 -04:00

125 lines
5.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Nerd_STF.Mathematics
{
public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
{
public static Angle Full => new(360);
public static Angle Half => new(180);
public static Angle One => new(1);
public static Angle Quarter => new(90);
public static Angle Zero => new(0);
public double Degrees
{
get => p_deg;
set => p_deg = value;
}
public double Gradians
{
get => p_deg * 1.11111111111; // Reciprocal of 9/10 as a constant (10/9)
set => p_deg = value * 0.9;
}
public double Radians
{
get => p_deg * Mathf.DegToRad;
set => p_deg = value * Mathf.RadToDeg;
}
public Angle Bounded => new(p_deg % 360);
private double p_deg;
public Angle(double value, Type valueType = Type.Degrees)
{
p_deg = valueType switch
{
Type.Degrees => value,
Type.Gradians => value * 0.9,
Type.Radians => value * Mathf.RadToDeg,
_ => throw new ArgumentException("Unknown type.", nameof(valueType)),
};
}
public static Angle Absolute(Angle val) => new(Mathf.Absolute(val.p_deg));
public static Angle Average(params Angle[] vals) => new(Mathf.Average(ToDoubles(Type.Degrees, vals)));
public static Angle Ceiling(Angle val) => new(Mathf.Ceiling(val.p_deg));
public static Angle Clamp(Angle val, Angle min, Angle max) => new(Mathf.Clamp(val.p_deg, min.p_deg, max.p_deg));
public static Angle Floor(Angle val) => new(Mathf.Ceiling(val.p_deg));
public static Angle Lerp(Angle a, Angle b, double t, bool clamp = true) =>
new(Mathf.Lerp(a.p_deg, b.p_deg, t, clamp));
public static Angle Max(params Angle[] vals) => new(Mathf.Max(ToDoubles(Type.Degrees, vals)));
public static Angle Median(params Angle[] vals) => new(Mathf.Median(ToDoubles(Type.Degrees, vals)));
public static Angle Min(params Angle[] vals) => new(Mathf.Min(ToDoubles(Type.Degrees, vals)));
public static double[] ToDoubles(Type outputType, params Angle[] vals)
{
double[] res = new double[vals.Length];
for (int i = 0; i < vals.Length; i++)
{
res[i] = outputType switch
{
Type.Degrees => vals[i].Degrees,
Type.Gradians => vals[i].Gradians,
Type.Radians => vals[i].Radians,
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
};
}
return res;
}
public int CompareTo(Angle other) => p_deg.CompareTo(other.p_deg);
public override bool Equals([NotNullWhen(true)] object? obj)
{
if (obj == null || obj.GetType() != typeof(Angle)) return false;
return Equals((Angle)obj);
}
public bool Equals(Angle other) => p_deg == other.p_deg;
public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(Type outputType) => ToString((string?)null, outputType);
public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch
{
Type.Degrees => p_deg.ToString(provider),
Type.Gradians => Gradians.ToString(provider),
Type.Radians => Radians.ToString(provider),
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
};
public string ToString(IFormatProvider provider, Type outputType = Type.Degrees) => outputType switch
{
Type.Degrees => p_deg.ToString(provider),
Type.Gradians => Gradians.ToString(provider),
Type.Radians => Radians.ToString(provider),
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
};
public object Clone() => new Angle(p_deg);
public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg);
public static Angle operator -(Angle a) => new(-a.p_deg);
public static Angle operator -(Angle a, Angle b) => new(a.p_deg - b.p_deg);
public static Angle operator *(Angle a, Angle b) => new(a.p_deg * b.p_deg);
public static Angle operator *(Angle a, double b) => new(a.p_deg * b);
public static Angle operator /(Angle a, Angle b) => new(a.p_deg / b.p_deg);
public static Angle operator /(Angle a, double b) => new(a.p_deg / b);
public static bool operator ==(Angle a, Angle b) => a.Equals(b);
public static bool operator !=(Angle a, Angle b) => !a.Equals(b);
public static bool operator >(Angle a, Angle b) => a.CompareTo(b) > 0;
public static bool operator <(Angle a, Angle b) => a.CompareTo(b) < 0;
public static bool operator >=(Angle a, Angle b) => a == b || a > b;
public static bool operator <=(Angle a, Angle b) => a == b || a < b;
public enum Type
{
Degrees,
Gradians,
Radians,
}
}
}