diff --git a/Changelog.md b/Changelog.md index c0c8185..d23e884 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,82 +1,12 @@ -# Nerd_STF v2.1.0 +# Nerd_STF v2.1.1 + +This update doesn't add any new features, simply a code simplification, using some of the .net 6 tools, such as global usings and file-scoped namespace declarations. ``` * Nerd_STF - + Exceptions - + Nerd_STFException - + DifferingVertCountException - + DisconnectedLinesException - + Miscellaneous - + `GlobalUsings.cs` - + IClosest - + IContainer - * Logger - * DefaultLogHandler(LogMessage) - = Replaced a `throw new Exception` with a `throw new ArgumentException` - * Mathematics - + Angle - + Calculus - + delegate double Equation(double) - * Double2 - = Made `CompareTo(Double2)` better - * Double3 - = Made `CompareTo(Double3)` better - * Double4 - = Made `CompareTo(Double4)` better - * Int2 - + operator &(Int2, Int2) - + operator |(Int2, Int2) - + operator ^(Int2, Int2) - = Made `CompareTo(Int2)` better - * Int3 - + operator &(Int3, Int3) - + operator |(Int3, Int3) - + operator ^(Int3, Int3) - = Made `CompareTo(Int3)` better - * Int4 - + operator &(Int4, Int4) - + operator |(Int4, Int4) - + operator ^(Int4, Int4) - = Made `CompareTo(Int4)` better - * Mathf - + Average(Equation, double, double, double) - + GetValues(Equation) - + MakeEquation(Dictionary) - + Max(Equation, double, double, double) - + Min(Equation, double, double, double) - = Swapped the names of "RadToDeg" and "DegToRad" - * Geometry - + Box2D - + Box3D - + Polygon - + Quadrilateral - + Sphere - + ISubdividable - * ITriangulatable - + Triangle[] TriangulateAll(params ITriangulatable[]) - * Line - + : IComparable - + : IContainer - + : IClosest - + : ISubdividable - + ClosestTo(Vert) - + ClosestTo(Vert, double) - + CompareTo(Line) - + Contains(Vert) - + Subdivide() - + operator -(Line) - + operator >(Line) - + operator <(Line) - + operator >=(Line) - + operator <=(Line) - = Renamed all instances of "start" to "a" - = Renamed all instances of "end" to "b" - * Triangle - + operator -(Triangle) - + ToDoubleArrayAll(params Triangle[]) - = Replaced the variable assignings in the Triangle to not re-assign the lines. - = Now uses custom exception in line constructor - = Renamed "L1" to "AB" - = Renamed "L2" to "BC" - = Renamed "L3" to "CA" + = Removed unused or unrequired usings in all files. + = Replaced all namespace declarations with file-scoped declarations. + * Miscellaneous + * GlobalUsings + + global using System.Diagnostics.CodeAnalysis ``` diff --git a/Nerd_STF/Exceptions/DifferingVertCountException.cs b/Nerd_STF/Exceptions/DifferingVertCountException.cs index 0d5c81c..dc37933 100644 --- a/Nerd_STF/Exceptions/DifferingVertCountException.cs +++ b/Nerd_STF/Exceptions/DifferingVertCountException.cs @@ -1,30 +1,28 @@ using System.Runtime.Serialization; -namespace Nerd_STF.Exceptions +namespace Nerd_STF.Exceptions; + +[Serializable] +public class DifferingVertCountException : Nerd_STFException { + public string? ParamName; + public Polygon[]? Polygons; - [Serializable] - public class DifferingVertCountException : Nerd_STFException + public DifferingVertCountException() : base("Not all polygons have the same vert count.") { } + public DifferingVertCountException(Exception inner) : base("Not all polygons have the same vert count.", inner) { } + public DifferingVertCountException(string paramName) : this() => ParamName = paramName; + public DifferingVertCountException(string paramName, Exception inner) : this(inner) => ParamName = paramName; + public DifferingVertCountException(params Polygon[] polys) : this() => Polygons = polys; + public DifferingVertCountException(Polygon[] polys, Exception inner) : this(inner) => Polygons = polys; + public DifferingVertCountException(string paramName, Polygon[] polys) : this() { - public string? ParamName; - public Polygon[]? Polygons; - - public DifferingVertCountException() : base("Not all polygons have the same vert count.") { } - public DifferingVertCountException(Exception inner) : base("Not all polygons have the same vert count.", inner) { } - public DifferingVertCountException(string paramName) : this() => ParamName = paramName; - public DifferingVertCountException(string paramName, Exception inner) : this(inner) => ParamName = paramName; - public DifferingVertCountException(params Polygon[] polys) : this() => Polygons = polys; - public DifferingVertCountException(Polygon[] polys, Exception inner) : this(inner) => Polygons = polys; - public DifferingVertCountException(string paramName, Polygon[] polys) : this() - { - ParamName = paramName; - Polygons = polys; - } - public DifferingVertCountException(string paramName, Polygon[] polys, Exception inner) : this(inner) - { - ParamName = paramName; - Polygons = polys; - } - protected DifferingVertCountException(SerializationInfo info, StreamingContext context) : base(info, context) { } + ParamName = paramName; + Polygons = polys; } + public DifferingVertCountException(string paramName, Polygon[] polys, Exception inner) : this(inner) + { + ParamName = paramName; + Polygons = polys; + } + protected DifferingVertCountException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/Nerd_STF/Exceptions/DisconnectedLinesException.cs b/Nerd_STF/Exceptions/DisconnectedLinesException.cs index 5f72248..539dd4a 100644 --- a/Nerd_STF/Exceptions/DisconnectedLinesException.cs +++ b/Nerd_STF/Exceptions/DisconnectedLinesException.cs @@ -1,35 +1,28 @@ -using Nerd_STF.Mathematics.Geometry; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.Serialization; -namespace Nerd_STF.Exceptions +namespace Nerd_STF.Exceptions; + +[Serializable] +public class DisconnectedLinesException : Nerd_STFException { - [Serializable] - public class DisconnectedLinesException : Nerd_STFException - { - public string? ParamName; - public Line[]? Lines; + public string? ParamName; + public Line[]? Lines; - public DisconnectedLinesException() : base("Lines are not connected.") { } - public DisconnectedLinesException(Exception inner) : base("Lines are not connected.", inner) { } - public DisconnectedLinesException(string paramName) : this() => ParamName = paramName; - public DisconnectedLinesException(string paramName, Exception inner) : this(inner) => ParamName = paramName; - public DisconnectedLinesException(params Line[] lines) : this() => Lines = lines; - public DisconnectedLinesException(Line[] lines, Exception inner) : this(inner) => Lines = lines; - public DisconnectedLinesException(string paramName, Line[] lines) : this() + public DisconnectedLinesException() : base("Lines are not connected.") { } + public DisconnectedLinesException(Exception inner) : base("Lines are not connected.", inner) { } + public DisconnectedLinesException(string paramName) : this() => ParamName = paramName; + public DisconnectedLinesException(string paramName, Exception inner) : this(inner) => ParamName = paramName; + public DisconnectedLinesException(params Line[] lines) : this() => Lines = lines; + public DisconnectedLinesException(Line[] lines, Exception inner) : this(inner) => Lines = lines; + public DisconnectedLinesException(string paramName, Line[] lines) : this() { ParamName = paramName; Lines = lines; } - public DisconnectedLinesException(string paramName, Line[] lines, Exception inner) : this(inner) + public DisconnectedLinesException(string paramName, Line[] lines, Exception inner) : this(inner) { ParamName = paramName; Lines = lines; } - protected DisconnectedLinesException(SerializationInfo info, StreamingContext context) : base(info, context) { } - } + protected DisconnectedLinesException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/Nerd_STF/Exceptions/Nerd_STFException.cs b/Nerd_STF/Exceptions/Nerd_STFException.cs index b36a9d9..5714792 100644 --- a/Nerd_STF/Exceptions/Nerd_STFException.cs +++ b/Nerd_STF/Exceptions/Nerd_STFException.cs @@ -1,18 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.Serialization; -using System.Text; -using System.Threading.Tasks; +using System.Runtime.Serialization; -namespace Nerd_STF.Exceptions +namespace Nerd_STF.Exceptions; + +[Serializable] +public class Nerd_STFException : Exception { - [Serializable] - public class Nerd_STFException : Exception - { - public Nerd_STFException() { } - public Nerd_STFException(string message) : base(message) { } - public Nerd_STFException(string message, Exception inner) : base(message, inner) { } - protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { } - } + public Nerd_STFException() { } + public Nerd_STFException(string message) : base(message) { } + public Nerd_STFException(string message, Exception inner) : base(message, inner) { } + protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/Nerd_STF/Fill.cs b/Nerd_STF/Fill.cs index 5f6ecf3..062c232 100644 --- a/Nerd_STF/Fill.cs +++ b/Nerd_STF/Fill.cs @@ -1,4 +1,3 @@ -namespace Nerd_STF -{ - public delegate T Fill(int index); -} +namespace Nerd_STF; + +public delegate T Fill(int index); diff --git a/Nerd_STF/IClosest.cs b/Nerd_STF/IClosest.cs index 4c61357..4ba047c 100644 --- a/Nerd_STF/IClosest.cs +++ b/Nerd_STF/IClosest.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF; -namespace Nerd_STF +public interface IClosest where T : IEquatable { - public interface IClosest where T : IEquatable - { - public T ClosestTo(T item); - } + public T ClosestTo(T item); } diff --git a/Nerd_STF/IContainer.cs b/Nerd_STF/IContainer.cs index 5f47e28..43dc911 100644 --- a/Nerd_STF/IContainer.cs +++ b/Nerd_STF/IContainer.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF; -namespace Nerd_STF +public interface IContainer where T : IEquatable { - public interface IContainer where T : IEquatable - { - public bool Contains(T item); - } + public bool Contains(T item); } diff --git a/Nerd_STF/IEncapsulator.cs b/Nerd_STF/IEncapsulator.cs index 853eaf7..62f7de5 100644 --- a/Nerd_STF/IEncapsulator.cs +++ b/Nerd_STF/IEncapsulator.cs @@ -1,13 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF; -namespace Nerd_STF +public interface IEncapsulator : IContainer where T : IEquatable where TE : IEquatable { - public interface IEncapsulator : IContainer where T : IEquatable where TE : IEquatable - { - public T Encapsulate(TE val); - } + public T Encapsulate(TE val); } diff --git a/Nerd_STF/IGroup.cs b/Nerd_STF/IGroup.cs index 06459c9..9b7bc54 100644 --- a/Nerd_STF/IGroup.cs +++ b/Nerd_STF/IGroup.cs @@ -1,8 +1,7 @@ -namespace Nerd_STF +namespace Nerd_STF; + +public interface IGroup : IEnumerable { - public interface IGroup : IEnumerable - { - public T[] ToArray(); - public List ToList(); - } + public T[] ToArray(); + public List ToList(); } diff --git a/Nerd_STF/LogMessage.cs b/Nerd_STF/LogMessage.cs index c33b94f..47f336a 100644 --- a/Nerd_STF/LogMessage.cs +++ b/Nerd_STF/LogMessage.cs @@ -1,25 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF; -namespace Nerd_STF +public struct LogMessage { - public struct LogMessage + public string Message; + public LogSeverity Severity; + public DateTime Timestamp; + + public LogMessage() : this("", LogSeverity.Information, null) { } + public LogMessage(string msg, LogSeverity severity, DateTime? time = null) { - public string Message; - public LogSeverity Severity; - public DateTime Timestamp; - - public LogMessage() : this("", LogSeverity.Information, null) { } - public LogMessage(string msg, LogSeverity severity, DateTime? time = null) - { - Message = msg; - Severity = severity; - Timestamp = time ?? DateTime.Now; - } - - public override string ToString() => Timestamp + " " + Severity.ToString().ToUpper() + ": " + Message; + Message = msg; + Severity = severity; + Timestamp = time ?? DateTime.Now; } + + public override string ToString() => Timestamp + " " + Severity.ToString().ToUpper() + ": " + Message; } diff --git a/Nerd_STF/LogSeverity.cs b/Nerd_STF/LogSeverity.cs index 51c598e..a67cbf6 100644 --- a/Nerd_STF/LogSeverity.cs +++ b/Nerd_STF/LogSeverity.cs @@ -1,11 +1,10 @@ -namespace Nerd_STF +namespace Nerd_STF; + +public enum LogSeverity { - public enum LogSeverity - { - Debug = 1, - Information = 2, - Warning = 4, - Error = 8, - Fatal = 16, - } + Debug = 1, + Information = 2, + Warning = 4, + Error = 8, + Fatal = 16, } diff --git a/Nerd_STF/Logger.cs b/Nerd_STF/Logger.cs index b1e666c..a71d8b7 100644 --- a/Nerd_STF/Logger.cs +++ b/Nerd_STF/Logger.cs @@ -1,72 +1,71 @@ using System.Text; -namespace Nerd_STF +namespace Nerd_STF; + +public class Logger { - public class Logger + public event Action OnMessageRecieved = DefaultLogHandler; + + public LogMessage[] Cache => msgs.ToArray(); + public int CacheSize = 64; + public List IncludeSeverities = new() { - public event Action OnMessageRecieved = DefaultLogHandler; + LogSeverity.Warning, + LogSeverity.Error, + LogSeverity.Fatal, + }; + public Stream? LogStream; + public int WriteSize; - public LogMessage[] Cache => msgs.ToArray(); - public int CacheSize = 64; - public List IncludeSeverities = new() + private readonly List msgs; + private readonly List writeCache; + + public Logger(Stream? logStream = null, int cacheSize = 64, int writeSize = 1) + { + CacheSize = cacheSize; + LogStream = logStream; + WriteSize = writeSize; + + msgs = new(CacheSize); + writeCache = new(); + } + + public void Send(LogMessage msg) + { + if (!IncludeSeverities.Contains(msg.Severity)) return; + + msgs.Insert(0, msg); + writeCache.Add(msg.ToString()); + while (msgs.Count > CacheSize) msgs.RemoveAt(CacheSize); + OnMessageRecieved(msg); + + if (writeCache.Count >= WriteSize && LogStream != null) { - LogSeverity.Warning, - LogSeverity.Error, - LogSeverity.Fatal, - }; - public Stream? LogStream; - public int WriteSize; - - private readonly List msgs; - private readonly List writeCache; - - public Logger(Stream? logStream = null, int cacheSize = 64, int writeSize = 1) - { - CacheSize = cacheSize; - LogStream = logStream; - WriteSize = writeSize; - - msgs = new(CacheSize); - writeCache = new(); - } - - public void Send(LogMessage msg) - { - if (!IncludeSeverities.Contains(msg.Severity)) return; - - msgs.Insert(0, msg); - writeCache.Add(msg.ToString()); - while (msgs.Count > CacheSize) msgs.RemoveAt(CacheSize); - OnMessageRecieved(msg); - - if (writeCache.Count >= WriteSize && LogStream != null) - { - string s = ""; - foreach (string cache in writeCache) s += cache + "\n" + (cache.Contains('\n') ? "\n" : ""); - LogStream.Write(Encoding.Default.GetBytes(s)); - LogStream.Flush(); - writeCache.Clear(); - } - } - - public static void DefaultLogHandler(LogMessage msg) - { - ConsoleColor color = msg.Severity switch - { - LogSeverity.Debug => ConsoleColor.DarkGray, - LogSeverity.Information => ConsoleColor.White, - LogSeverity.Warning => ConsoleColor.DarkYellow, - LogSeverity.Error => ConsoleColor.Red, - LogSeverity.Fatal => ConsoleColor.DarkRed, - _ => throw new ArgumentException("Unknown log severity " + msg.Severity, nameof(msg)), - }; - - ConsoleColor originalCol = Console.ForegroundColor; - - Console.ForegroundColor = color; - Console.WriteLine(msg.ToString()); - - Console.ForegroundColor = originalCol; + string s = ""; + foreach (string cache in writeCache) s += cache + "\n" + (cache.Contains('\n') ? "\n" : ""); + LogStream.Write(Encoding.Default.GetBytes(s)); + LogStream.Flush(); + writeCache.Clear(); } } + + public static void DefaultLogHandler(LogMessage msg) + { + ConsoleColor color = msg.Severity switch + { + LogSeverity.Debug => ConsoleColor.DarkGray, + LogSeverity.Information => ConsoleColor.White, + LogSeverity.Warning => ConsoleColor.DarkYellow, + LogSeverity.Error => ConsoleColor.Red, + LogSeverity.Fatal => ConsoleColor.DarkRed, + _ => throw new ArgumentException("Unknown log severity " + msg.Severity, nameof(msg)), + }; + + ConsoleColor originalCol = Console.ForegroundColor; + + Console.ForegroundColor = color; + Console.WriteLine(msg.ToString()); + + Console.ForegroundColor = originalCol; + } } diff --git a/Nerd_STF/Mathematics/Angle.cs b/Nerd_STF/Mathematics/Angle.cs index 5b8990f..67bfa9a 100644 --- a/Nerd_STF/Mathematics/Angle.cs +++ b/Nerd_STF/Mathematics/Angle.cs @@ -1,124 +1,116 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Angle : ICloneable, IComparable, IEquatable { - public struct Angle : ICloneable, IComparable, IEquatable - { - 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 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 + public double Degrees { get => p_deg; set => p_deg = value; } - public double Gradians + 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 + public double Radians { get => p_deg * Mathf.DegToRad; set => p_deg = value * Mathf.RadToDeg; } - public Angle Bounded => new(p_deg % 360); + public Angle Bounded => new(p_deg % 360); - private double p_deg; + private double p_deg; - public Angle(double value, Type valueType = Type.Degrees) + public Angle(double value, Type valueType = Type.Degrees) + { + p_deg = valueType switch { - 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 => value, - Type.Gradians => value * 0.9, - Type.Radians => value * Mathf.RadToDeg, - _ => throw new ArgumentException("Unknown type.", nameof(valueType)), + 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 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 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 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 object Clone() => new Angle(p_deg); - 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 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 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, - } + public enum Type + { + Degrees, + Gradians, + Radians, } } diff --git a/Nerd_STF/Mathematics/Calculus.cs b/Nerd_STF/Mathematics/Calculus.cs index a2bdf63..227a6c9 100644 --- a/Nerd_STF/Mathematics/Calculus.cs +++ b/Nerd_STF/Mathematics/Calculus.cs @@ -1,41 +1,34 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public static class Calculus { - public static class Calculus + public const double DefaultStep = 0.001; + + public static Equation GetDerivative(Equation equ, double min, double max, double step = DefaultStep) { - public const double DefaultStep = 0.001; - - public static Equation GetDerivative(Equation equ, double min, double max, double step = DefaultStep) + Dictionary vals = new(); + for (double x = min; x <= max; x += step) { - Dictionary vals = new(); - for (double x = min; x <= max; x += step) - { - double val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step; - vals.Add(x, change); - } - return Mathf.MakeEquation(vals); + double val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step; + vals.Add(x, change); } - public static double GetDerivativeAtPoint(Equation equ, double x, double step = DefaultStep) => - (equ(x + DefaultStep) - equ(x)) / step; + return Mathf.MakeEquation(vals); + } + public static double GetDerivativeAtPoint(Equation equ, double x, double step = DefaultStep) => + (equ(x + DefaultStep) - equ(x)) / step; - public static double GetIntegral(Equation equ, double lowerBound, double upperBound, double step = DefaultStep) + public static double GetIntegral(Equation equ, double lowerBound, double upperBound, double step = DefaultStep) { double val = 0; for (double x = lowerBound; x <= upperBound; x += step) val += equ(x) * step; return val; } - public static double GradientDescent(Equation equ, double initial, double rate, double stepCount = 1000, - double step = DefaultStep) - { - double val = initial; - for (int i = 0; i < stepCount; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate; - return val; - } + public static double GradientDescent(Equation equ, double initial, double rate, double stepCount = 1000, + double step = DefaultStep) + { + double val = initial; + for (int i = 0; i < stepCount; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate; + return val; } } diff --git a/Nerd_STF/Mathematics/Double2.cs b/Nerd_STF/Mathematics/Double2.cs index 1504fbf..050aeb5 100644 --- a/Nerd_STF/Mathematics/Double2.cs +++ b/Nerd_STF/Mathematics/Double2.cs @@ -1,186 +1,181 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Double2 : ICloneable, IComparable, IEquatable, IGroup { - public struct Double2 : ICloneable, IComparable, IEquatable, IGroup + public static Double2 Down => new(0, -1); + public static Double2 Left => new(-1, 0); + public static Double2 Right => new(1, 0); + public static Double2 Up => new(0, 1); + + public static Double2 One => new(1, 1); + public static Double2 Zero => new(0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y); + public Double2 Normalized => this / Magnitude; + + public double x, y; + + public Double2(double all) : this(all, all) { } + public Double2(double x, double y) { - public static Double2 Down => new(0, -1); - public static Double2 Left => new(-1, 0); - public static Double2 Right => new(1, 0); - public static Double2 Up => new(0, 1); - - public static Double2 One => new(1, 1); - public static Double2 Zero => new(0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y); - public Double2 Normalized => this / Magnitude; - - public double x, y; - - public Double2(double all) : this(all, all) { } - public Double2(double x, double y) - { - this.x = x; - this.y = y; - } - public Double2(Fill fill) : this(fill(0), fill(1)) { } - public Double2(Fill fill) : this(fill(0), fill(1)) { } - - public double this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Double2 Absolute(Double2 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); - public static Double2 Average(params Double2[] vals) => Sum(vals) / vals.Length; - public static Double2 Ceiling(Double2 val) => - new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y)); - public static Double2 Clamp(Double2 val, Double2 min, Double2 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y)); - public static Double2 ClampMagnitude(Double2 val, double minMag, double maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Double3 Cross(Double2 a, Double2 b, bool normalized = false) => - Double3.Cross(a, b, normalized); - public static Double2 Divide(Double2 num, params Double2[] vals) - { - foreach (Double2 d in vals) num /= d; - return num; - } - public static double Dot(Double2 a, Double2 b) => a.x * b.x + a.y * b.y; - public static double Dot(params Double2[] vals) - { - if (vals.Length < 1) return 0; - double x = 1, y = 1; - foreach (Double2 d in vals) - { - x *= d.x; - y *= d.y; - } - return x + y; - } - public static Double2 Floor(Double2 val) => - new(Mathf.Floor(val.x), Mathf.Floor(val.y)); - public static Double2 Lerp(Double2 a, Double2 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp)); - public static Double2 Median(params Double2[] vals) - { - double index = Mathf.Average(0, vals.Length - 1); - Double2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Double2 Max(params Double2[] vals) - { - if (vals.Length < 1) return Zero; - Double2 val = vals[0]; - foreach (Double2 d in vals) val = d > val ? d : val; - return val; - } - public static Double2 Min(params Double2[] vals) - { - if (vals.Length < 1) return Zero; - Double2 val = vals[0]; - foreach (Double2 d in vals) val = d < val ? d : val; - return val; - } - public static Double2 Multiply(params Double2[] vals) - { - if (vals.Length < 1) return Zero; - Double2 val = One; - foreach (Double2 d in vals) val *= d; - return val; - } - public static Double2 Subtract(Double2 num, params Double2[] vals) - { - foreach (Double2 d in vals) num -= d; - return num; - } - public static Double2 Sum(params Double2[] vals) - { - Double2 val = Zero; - foreach (Double2 d in vals) val += d; - return val; - } - - public int CompareTo(Double2 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Double2)) return false; - return Equals((Double2)obj); - } - public bool Equals(Double2 other) => x == other.x && y == other.y; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - - public object Clone() => new Double2(x, y); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - } - - public double[] ToArray() => new[] { x, y }; - public List ToList() => new() { x, y }; - - public static Double2 operator +(Double2 a, Double2 b) => new(a.x + b.x, a.y + b.y); - public static Double2 operator -(Double2 d) => new(-d.x, -d.y); - public static Double2 operator -(Double2 a, Double2 b) => new(a.x - b.x, a.y - b.y); - public static Double2 operator *(Double2 a, Double2 b) => new(a.x * b.x, a.y * b.y); - public static Double2 operator *(Double2 a, double b) => new(a.x * b, a.y * b); - public static Double2 operator /(Double2 a, Double2 b) => new(a.x / b.x, a.y / b.y); - public static Double2 operator /(Double2 a, double b) => new(a.x / b, a.y / b); - public static bool operator ==(Double2 a, Double2 b) => a.Equals(b); - public static bool operator !=(Double2 a, Double2 b) => !a.Equals(b); - public static bool operator >(Double2 a, Double2 b) => a.CompareTo(b) > 0; - public static bool operator <(Double2 a, Double2 b) => a.CompareTo(b) < 0; - public static bool operator >=(Double2 a, Double2 b) => a == b || a > b; - public static bool operator <=(Double2 a, Double2 b) => a == b || a < b; - - public static explicit operator Double2(Double3 val) => new(val.x, val.y); - public static explicit operator Double2(Double4 val) => new(val.x, val.y); - public static implicit operator Double2(Int2 val) => new(val.x, val.y); - public static explicit operator Double2(Int3 val) => new(val.x, val.y); - public static explicit operator Double2(Int4 val) => new(val.x, val.y); - public static explicit operator Double2(Vert val) => new(val.position.x, val.position.y); - public static implicit operator Double2(Fill fill) => new(fill); - public static implicit operator Double2(Fill fill) => new(fill); + this.x = x; + this.y = y; } + public Double2(Fill fill) : this(fill(0), fill(1)) { } + public Double2(Fill fill) : this(fill(0), fill(1)) { } + + public double this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Double2 Absolute(Double2 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); + public static Double2 Average(params Double2[] vals) => Sum(vals) / vals.Length; + public static Double2 Ceiling(Double2 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y)); + public static Double2 Clamp(Double2 val, Double2 min, Double2 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y)); + public static Double2 ClampMagnitude(Double2 val, double minMag, double maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Double3 Cross(Double2 a, Double2 b, bool normalized = false) => + Double3.Cross(a, b, normalized); + public static Double2 Divide(Double2 num, params Double2[] vals) + { + foreach (Double2 d in vals) num /= d; + return num; + } + public static double Dot(Double2 a, Double2 b) => a.x * b.x + a.y * b.y; + public static double Dot(params Double2[] vals) + { + if (vals.Length < 1) return 0; + double x = 1, y = 1; + foreach (Double2 d in vals) + { + x *= d.x; + y *= d.y; + } + return x + y; + } + public static Double2 Floor(Double2 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y)); + public static Double2 Lerp(Double2 a, Double2 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp)); + public static Double2 Median(params Double2[] vals) + { + double index = Mathf.Average(0, vals.Length - 1); + Double2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Double2 Max(params Double2[] vals) + { + if (vals.Length < 1) return Zero; + Double2 val = vals[0]; + foreach (Double2 d in vals) val = d > val ? d : val; + return val; + } + public static Double2 Min(params Double2[] vals) + { + if (vals.Length < 1) return Zero; + Double2 val = vals[0]; + foreach (Double2 d in vals) val = d < val ? d : val; + return val; + } + public static Double2 Multiply(params Double2[] vals) + { + if (vals.Length < 1) return Zero; + Double2 val = One; + foreach (Double2 d in vals) val *= d; + return val; + } + public static Double2 Subtract(Double2 num, params Double2[] vals) + { + foreach (Double2 d in vals) num -= d; + return num; + } + public static Double2 Sum(params Double2[] vals) + { + Double2 val = Zero; + foreach (Double2 d in vals) val += d; + return val; + } + + public int CompareTo(Double2 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Double2)) return false; + return Equals((Double2)obj); + } + public bool Equals(Double2 other) => x == other.x && y == other.y; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); + + public object Clone() => new Double2(x, y); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + } + + public double[] ToArray() => new[] { x, y }; + public List ToList() => new() { x, y }; + + public static Double2 operator +(Double2 a, Double2 b) => new(a.x + b.x, a.y + b.y); + public static Double2 operator -(Double2 d) => new(-d.x, -d.y); + public static Double2 operator -(Double2 a, Double2 b) => new(a.x - b.x, a.y - b.y); + public static Double2 operator *(Double2 a, Double2 b) => new(a.x * b.x, a.y * b.y); + public static Double2 operator *(Double2 a, double b) => new(a.x * b, a.y * b); + public static Double2 operator /(Double2 a, Double2 b) => new(a.x / b.x, a.y / b.y); + public static Double2 operator /(Double2 a, double b) => new(a.x / b, a.y / b); + public static bool operator ==(Double2 a, Double2 b) => a.Equals(b); + public static bool operator !=(Double2 a, Double2 b) => !a.Equals(b); + public static bool operator >(Double2 a, Double2 b) => a.CompareTo(b) > 0; + public static bool operator <(Double2 a, Double2 b) => a.CompareTo(b) < 0; + public static bool operator >=(Double2 a, Double2 b) => a == b || a > b; + public static bool operator <=(Double2 a, Double2 b) => a == b || a < b; + + public static explicit operator Double2(Double3 val) => new(val.x, val.y); + public static explicit operator Double2(Double4 val) => new(val.x, val.y); + public static implicit operator Double2(Int2 val) => new(val.x, val.y); + public static explicit operator Double2(Int3 val) => new(val.x, val.y); + public static explicit operator Double2(Int4 val) => new(val.x, val.y); + public static explicit operator Double2(Vert val) => new(val.position.x, val.position.y); + public static implicit operator Double2(Fill fill) => new(fill); + public static implicit operator Double2(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Double3.cs b/Nerd_STF/Mathematics/Double3.cs index b675239..d49a0bb 100644 --- a/Nerd_STF/Mathematics/Double3.cs +++ b/Nerd_STF/Mathematics/Double3.cs @@ -1,207 +1,202 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Double3 : ICloneable, IComparable, IEquatable, IGroup { - public struct Double3 : ICloneable, IComparable, IEquatable, IGroup + public static Double3 Back => new(0, 0, -1); + public static Double3 Down => new(0, -1, 0); + public static Double3 Forward => new(0, 0, 1); + public static Double3 Left => new(-1, 0, 0); + public static Double3 Right => new(1, 0, 0); + public static Double3 Up => new(0, 1, 0); + + public static Double3 One => new(1, 1, 1); + public static Double3 Zero => new(0, 0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z); + public Double3 Normalized => this / Magnitude; + + public Double2 XY => new(x, y); + public Double2 XZ => new(x, z); + public Double2 YZ => new(y, z); + + public double x, y, z; + + public Double3(double all) : this(all, all, all) { } + public Double3(double x, double y) : this(x, y, 0) { } + public Double3(double x, double y, double z) { - public static Double3 Back => new(0, 0, -1); - public static Double3 Down => new(0, -1, 0); - public static Double3 Forward => new(0, 0, 1); - public static Double3 Left => new(-1, 0, 0); - public static Double3 Right => new(1, 0, 0); - public static Double3 Up => new(0, 1, 0); - - public static Double3 One => new(1, 1, 1); - public static Double3 Zero => new(0, 0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z); - public Double3 Normalized => this / Magnitude; - - public Double2 XY => new(x, y); - public Double2 XZ => new(x, z); - public Double2 YZ => new(y, z); - - public double x, y, z; - - public Double3(double all) : this(all, all, all) { } - public Double3(double x, double y) : this(x, y, 0) { } - public Double3(double x, double y, double z) - { - this.x = x; - this.y = y; - this.z = z; - } - public Double3(Fill fill) : this(fill(0), fill(1), fill(2)) { } - public Double3(Fill fill) : this(fill(0), fill(1), fill(2)) { } - - public double this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - 2 => z, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - case 2: - z = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Double3 Absolute(Double3 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); - public static Double3 Average(params Double3[] vals) => Sum(vals) / vals.Length; - public static Double3 Ceiling(Double3 val) => - new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z)); - public static Double3 Clamp(Double3 val, Double3 min, Double3 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y), - Mathf.Clamp(val.z, min.z, max.z)); - public static Double3 ClampMagnitude(Double3 val, double minMag, double maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Double3 Cross(Double3 a, Double3 b, bool normalized = false) - { - Double3 val = new(a.y * b.z - b.y * a.z, - b.x * a.z - a.x * b.z, - a.x * b.y - b.x * a.y); - return normalized ? val.Normalized : val; - } - public static Double3 Divide(Double3 num, params Double3[] vals) - { - foreach (Double3 d in vals) num /= d; - return num; - } - public static double Dot(Double3 a, Double3 b) => a.x * b.x + a.y * b.y + a.z * b.z; - public static double Dot(params Double3[] vals) - { - if (vals.Length < 1) return 0; - double x = 1, y = 1, z = 1; - foreach (Double3 d in vals) - { - x *= d.x; - y *= d.y; - z *= d.z; - } - return x + y + z; - } - public static Double3 Floor(Double3 val) => - new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z)); - public static Double3 Lerp(Double3 a, Double3 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp)); - public static Double3 Median(params Double3[] vals) - { - double index = Mathf.Average(0, vals.Length - 1); - Double3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Double3 Max(params Double3[] vals) - { - if (vals.Length < 1) return Zero; - Double3 val = vals[0]; - foreach (Double3 d in vals) val = d > val ? d : val; - return val; - } - public static Double3 Min(params Double3[] vals) - { - if (vals.Length < 1) return Zero; - Double3 val = vals[0]; - foreach (Double3 d in vals) val = d < val ? d : val; - return val; - } - public static Double3 Multiply(params Double3[] vals) - { - if (vals.Length < 1) return Zero; - Double3 val = One; - foreach (Double3 d in vals) val *= d; - return val; - } - public static Double3 Subtract(Double3 num, params Double3[] vals) - { - foreach (Double3 d in vals) num -= d; - return num; - } - public static Double3 Sum(params Double3[] vals) - { - Double3 val = Zero; - foreach (Double3 d in vals) val += d; - return val; - } - - public int CompareTo(Double3 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Double3)) return false; - return Equals((Double3)obj); - } - public bool Equals(Double3 other) => x == other.x && y == other.y && z == other.z; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - - public object Clone() => new Double3(x, y, z); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - yield return z; - } - - public double[] ToArray() => new[] { x, y, z }; - public List ToList() => new() { x, y, z }; - - public static Double3 operator +(Double3 a, Double3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); - public static Double3 operator -(Double3 d) => new(-d.x, -d.y, -d.z); - public static Double3 operator -(Double3 a, Double3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); - public static Double3 operator *(Double3 a, Double3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z); - public static Double3 operator *(Double3 a, double b) => new(a.x * b, a.y * b, a.z * b); - public static Double3 operator /(Double3 a, Double3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z); - public static Double3 operator /(Double3 a, double b) => new(a.x / b, a.y / b, a.z / b); - public static bool operator ==(Double3 a, Double3 b) => a.Equals(b); - public static bool operator !=(Double3 a, Double3 b) => !a.Equals(b); - public static bool operator >(Double3 a, Double3 b) => a.CompareTo(b) > 0; - public static bool operator <(Double3 a, Double3 b) => a.CompareTo(b) < 0; - public static bool operator >=(Double3 a, Double3 b) => a == b || a > b; - public static bool operator <=(Double3 a, Double3 b) => a == b || a < b; - - public static implicit operator Double3(Double2 val) => new(val.x, val.y, 0); - public static explicit operator Double3(Double4 val) => new(val.x, val.y, val.z); - public static implicit operator Double3(Int2 val) => new(val.x, val.y, 0); - public static implicit operator Double3(Int3 val) => new(val.x, val.y, val.z); - public static explicit operator Double3(Int4 val) => new(val.x, val.y, val.z); - public static implicit operator Double3(Vert val) => new(val.position.x, val.position.y, val.position.z); - public static implicit operator Double3(Fill fill) => new(fill); - public static implicit operator Double3(Fill fill) => new(fill); + this.x = x; + this.y = y; + this.z = z; } + public Double3(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Double3(Fill fill) : this(fill(0), fill(1), fill(2)) { } + + public double this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + 2 => z, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + case 2: + z = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Double3 Absolute(Double3 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); + public static Double3 Average(params Double3[] vals) => Sum(vals) / vals.Length; + public static Double3 Ceiling(Double3 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z)); + public static Double3 Clamp(Double3 val, Double3 min, Double3 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y), + Mathf.Clamp(val.z, min.z, max.z)); + public static Double3 ClampMagnitude(Double3 val, double minMag, double maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Double3 Cross(Double3 a, Double3 b, bool normalized = false) + { + Double3 val = new(a.y * b.z - b.y * a.z, + b.x * a.z - a.x * b.z, + a.x * b.y - b.x * a.y); + return normalized ? val.Normalized : val; + } + public static Double3 Divide(Double3 num, params Double3[] vals) + { + foreach (Double3 d in vals) num /= d; + return num; + } + public static double Dot(Double3 a, Double3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + public static double Dot(params Double3[] vals) + { + if (vals.Length < 1) return 0; + double x = 1, y = 1, z = 1; + foreach (Double3 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + } + return x + y + z; + } + public static Double3 Floor(Double3 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z)); + public static Double3 Lerp(Double3 a, Double3 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp)); + public static Double3 Median(params Double3[] vals) + { + double index = Mathf.Average(0, vals.Length - 1); + Double3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Double3 Max(params Double3[] vals) + { + if (vals.Length < 1) return Zero; + Double3 val = vals[0]; + foreach (Double3 d in vals) val = d > val ? d : val; + return val; + } + public static Double3 Min(params Double3[] vals) + { + if (vals.Length < 1) return Zero; + Double3 val = vals[0]; + foreach (Double3 d in vals) val = d < val ? d : val; + return val; + } + public static Double3 Multiply(params Double3[] vals) + { + if (vals.Length < 1) return Zero; + Double3 val = One; + foreach (Double3 d in vals) val *= d; + return val; + } + public static Double3 Subtract(Double3 num, params Double3[] vals) + { + foreach (Double3 d in vals) num -= d; + return num; + } + public static Double3 Sum(params Double3[] vals) + { + Double3 val = Zero; + foreach (Double3 d in vals) val += d; + return val; + } + + public int CompareTo(Double3 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Double3)) return false; + return Equals((Double3)obj); + } + public bool Equals(Double3 other) => x == other.x && y == other.y && z == other.z; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); + + public object Clone() => new Double3(x, y, z); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + } + + public double[] ToArray() => new[] { x, y, z }; + public List ToList() => new() { x, y, z }; + + public static Double3 operator +(Double3 a, Double3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); + public static Double3 operator -(Double3 d) => new(-d.x, -d.y, -d.z); + public static Double3 operator -(Double3 a, Double3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); + public static Double3 operator *(Double3 a, Double3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z); + public static Double3 operator *(Double3 a, double b) => new(a.x * b, a.y * b, a.z * b); + public static Double3 operator /(Double3 a, Double3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z); + public static Double3 operator /(Double3 a, double b) => new(a.x / b, a.y / b, a.z / b); + public static bool operator ==(Double3 a, Double3 b) => a.Equals(b); + public static bool operator !=(Double3 a, Double3 b) => !a.Equals(b); + public static bool operator >(Double3 a, Double3 b) => a.CompareTo(b) > 0; + public static bool operator <(Double3 a, Double3 b) => a.CompareTo(b) < 0; + public static bool operator >=(Double3 a, Double3 b) => a == b || a > b; + public static bool operator <=(Double3 a, Double3 b) => a == b || a < b; + + public static implicit operator Double3(Double2 val) => new(val.x, val.y, 0); + public static explicit operator Double3(Double4 val) => new(val.x, val.y, val.z); + public static implicit operator Double3(Int2 val) => new(val.x, val.y, 0); + public static implicit operator Double3(Int3 val) => new(val.x, val.y, val.z); + public static explicit operator Double3(Int4 val) => new(val.x, val.y, val.z); + public static implicit operator Double3(Vert val) => new(val.position.x, val.position.y, val.position.z); + public static implicit operator Double3(Fill fill) => new(fill); + public static implicit operator Double3(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Double4.cs b/Nerd_STF/Mathematics/Double4.cs index 7018175..ca38c11 100644 --- a/Nerd_STF/Mathematics/Double4.cs +++ b/Nerd_STF/Mathematics/Double4.cs @@ -1,223 +1,218 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Double4 : ICloneable, IComparable, IEquatable, IGroup { - public struct Double4 : ICloneable, IComparable, IEquatable, IGroup + public static Double4 Back => new(0, 0, -1, 0); + public static Double4 Deep => new(0, 0, 0, -1); + public static Double4 Down => new(0, -1, 0, 0); + public static Double4 Far => new(0, 0, 0, 1); + public static Double4 Forward => new(0, 0, 1, 0); + public static Double4 Left => new(-1, 0, 0, 0); + public static Double4 Right => new(1, 0, 0, 0); + public static Double4 Up => new(0, 1, 0, 0); + + public static Double4 One => new(1, 1, 1, 1); + public static Double4 Zero => new(0, 0, 0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); + public Double4 Normalized => this / Magnitude; + + public Double2 XY => new(x, y); + public Double2 XZ => new(x, z); + public Double2 XW => new(x, w); + public Double2 YW => new(y, w); + public Double2 YZ => new(y, z); + public Double2 ZW => new(z, w); + + public Double3 XYW => new(x, y, w); + public Double3 XYZ => new(x, y, z); + public Double3 YZW => new(y, z, w); + public Double3 XZW => new(x, z, w); + + public double x, y, z, w; + + public Double4(double all) : this(all, all, all, all) { } + public Double4(double x, double y) : this(x, y, 0, 0) { } + public Double4(double x, double y, double z) : this(x, y, z, 0) { } + public Double4(double x, double y, double z, double w) { - public static Double4 Back => new(0, 0, -1, 0); - public static Double4 Deep => new(0, 0, 0, -1); - public static Double4 Down => new(0, -1, 0, 0); - public static Double4 Far => new(0, 0, 0, 1); - public static Double4 Forward => new(0, 0, 1, 0); - public static Double4 Left => new(-1, 0, 0, 0); - public static Double4 Right => new(1, 0, 0, 0); - public static Double4 Up => new(0, 1, 0, 0); - - public static Double4 One => new(1, 1, 1, 1); - public static Double4 Zero => new(0, 0, 0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); - public Double4 Normalized => this / Magnitude; - - public Double2 XY => new(x, y); - public Double2 XZ => new(x, z); - public Double2 XW => new(x, w); - public Double2 YW => new(y, w); - public Double2 YZ => new(y, z); - public Double2 ZW => new(z, w); - - public Double3 XYW => new(x, y, w); - public Double3 XYZ => new(x, y, z); - public Double3 YZW => new(y, z, w); - public Double3 XZW => new(x, z, w); - - public double x, y, z, w; - - public Double4(double all) : this(all, all, all, all) { } - public Double4(double x, double y) : this(x, y, 0, 0) { } - public Double4(double x, double y, double z) : this(x, y, z, 0) { } - public Double4(double x, double y, double z, double w) - { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - public Double4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public Double4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - - public double this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - 2 => z, - 3 => w, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - case 2: - z = value; - break; - - case 3: - w = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Double4 Absolute(Double4 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); - public static Double4 Average(params Double4[] vals) => Sum(vals) / vals.Length; - public static Double4 Ceiling(Double4 val) => - new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w)); - public static Double4 Clamp(Double4 val, Double4 min, Double4 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y), - Mathf.Clamp(val.z, min.z, max.z), - Mathf.Clamp(val.w, min.w, max.w)); - public static Double4 ClampMagnitude(Double4 val, double minMag, double maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Double4 Divide(Double4 num, params Double4[] vals) - { - foreach (Double4 d in vals) num /= d; - return num; - } - public static double Dot(Double4 a, Double4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; - public static double Dot(params Double4[] vals) - { - if (vals.Length < 1) return 0; - double x = 1, y = 1, z = 1, w = 1; - foreach (Double4 d in vals) - { - x *= d.x; - y *= d.y; - z *= d.z; - w *= d.w; - } - return x + y + z; - } - public static Double4 Floor(Double4 val) => - new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w)); - public static Double4 Lerp(Double4 a, Double4 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp), - Mathf.Lerp(a.w, b.w, t, clamp)); - public static Double4 Median(params Double4[] vals) - { - double index = Mathf.Average(0, vals.Length - 1); - Double4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Double4 Max(params Double4[] vals) - { - if (vals.Length < 1) return Zero; - Double4 val = vals[0]; - foreach (Double4 d in vals) val = d > val ? d : val; - return val; - } - public static Double4 Min(params Double4[] vals) - { - if (vals.Length < 1) return Zero; - Double4 val = vals[0]; - foreach (Double4 d in vals) val = d < val ? d : val; - return val; - } - public static Double4 Multiply(params Double4[] vals) - { - if (vals.Length < 1) return Zero; - Double4 val = One; - foreach (Double4 d in vals) val *= d; - return val; - } - public static Double4 Subtract(Double4 num, params Double4[] vals) - { - foreach (Double4 d in vals) num -= d; - return num; - } - public static Double4 Sum(params Double4[] vals) - { - Double4 val = Zero; - foreach (Double4 d in vals) val += d; - return val; - } - - public int CompareTo(Double4 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Double4)) return false; - return Equals((Double4)obj); - } - public bool Equals(Double4 other) => x == other.x && y == other.y && z == other.z && w == other.w; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - - public object Clone() => new Double4(x, y, z, w); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - yield return z; - yield return w; - } - - public double[] ToArray() => new[] { x, y, z, w }; - public List ToList() => new() { x, y, z, w }; - - public static Double4 operator +(Double4 a, Double4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - public static Double4 operator -(Double4 d) => new(-d.x, -d.y, -d.z, -d.w); - public static Double4 operator -(Double4 a, Double4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); - public static Double4 operator *(Double4 a, Double4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); - public static Double4 operator *(Double4 a, double b) => new(a.x * b, a.y * b, a.z * b, a.w * b); - public static Double4 operator /(Double4 a, Double4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); - public static Double4 operator /(Double4 a, double b) => new(a.x / b, a.y / b, a.z / b, a.w / b); - public static bool operator ==(Double4 a, Double4 b) => a.Equals(b); - public static bool operator !=(Double4 a, Double4 b) => !a.Equals(b); - public static bool operator >(Double4 a, Double4 b) => a.CompareTo(b) > 0; - public static bool operator <(Double4 a, Double4 b) => a.CompareTo(b) < 0; - public static bool operator >=(Double4 a, Double4 b) => a == b || a > b; - public static bool operator <=(Double4 a, Double4 b) => a == b || a < b; - - public static implicit operator Double4(Double2 val) => new(val.x, val.y, 0, 0); - public static implicit operator Double4(Double3 val) => new(val.x, val.y, val.z, 0); - public static implicit operator Double4(Int2 val) => new(val.x, val.y, 0, 0); - public static implicit operator Double4(Int3 val) => new(val.x, val.y, val.z, 0); - public static implicit operator Double4(Int4 val) => new(val.x, val.y, val.z, val.w); - public static implicit operator Double4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0); - public static implicit operator Double4(Fill fill) => new(fill); - public static implicit operator Double4(Fill fill) => new(fill); + this.x = x; + this.y = y; + this.z = z; + this.w = w; } + public Double4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Double4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + + public double this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + 2 => z, + 3 => w, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + case 2: + z = value; + break; + + case 3: + w = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Double4 Absolute(Double4 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); + public static Double4 Average(params Double4[] vals) => Sum(vals) / vals.Length; + public static Double4 Ceiling(Double4 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w)); + public static Double4 Clamp(Double4 val, Double4 min, Double4 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y), + Mathf.Clamp(val.z, min.z, max.z), + Mathf.Clamp(val.w, min.w, max.w)); + public static Double4 ClampMagnitude(Double4 val, double minMag, double maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Double4 Divide(Double4 num, params Double4[] vals) + { + foreach (Double4 d in vals) num /= d; + return num; + } + public static double Dot(Double4 a, Double4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + public static double Dot(params Double4[] vals) + { + if (vals.Length < 1) return 0; + double x = 1, y = 1, z = 1, w = 1; + foreach (Double4 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + w *= d.w; + } + return x + y + z; + } + public static Double4 Floor(Double4 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w)); + public static Double4 Lerp(Double4 a, Double4 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp), + Mathf.Lerp(a.w, b.w, t, clamp)); + public static Double4 Median(params Double4[] vals) + { + double index = Mathf.Average(0, vals.Length - 1); + Double4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Double4 Max(params Double4[] vals) + { + if (vals.Length < 1) return Zero; + Double4 val = vals[0]; + foreach (Double4 d in vals) val = d > val ? d : val; + return val; + } + public static Double4 Min(params Double4[] vals) + { + if (vals.Length < 1) return Zero; + Double4 val = vals[0]; + foreach (Double4 d in vals) val = d < val ? d : val; + return val; + } + public static Double4 Multiply(params Double4[] vals) + { + if (vals.Length < 1) return Zero; + Double4 val = One; + foreach (Double4 d in vals) val *= d; + return val; + } + public static Double4 Subtract(Double4 num, params Double4[] vals) + { + foreach (Double4 d in vals) num -= d; + return num; + } + public static Double4 Sum(params Double4[] vals) + { + Double4 val = Zero; + foreach (Double4 d in vals) val += d; + return val; + } + + public int CompareTo(Double4 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Double4)) return false; + return Equals((Double4)obj); + } + public bool Equals(Double4 other) => x == other.x && y == other.y && z == other.z && w == other.w; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) + + " W: " + w.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) + + " W: " + w.ToString(provider); + + public object Clone() => new Double4(x, y, z, w); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + yield return w; + } + + public double[] ToArray() => new[] { x, y, z, w }; + public List ToList() => new() { x, y, z, w }; + + public static Double4 operator +(Double4 a, Double4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + public static Double4 operator -(Double4 d) => new(-d.x, -d.y, -d.z, -d.w); + public static Double4 operator -(Double4 a, Double4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + public static Double4 operator *(Double4 a, Double4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + public static Double4 operator *(Double4 a, double b) => new(a.x * b, a.y * b, a.z * b, a.w * b); + public static Double4 operator /(Double4 a, Double4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + public static Double4 operator /(Double4 a, double b) => new(a.x / b, a.y / b, a.z / b, a.w / b); + public static bool operator ==(Double4 a, Double4 b) => a.Equals(b); + public static bool operator !=(Double4 a, Double4 b) => !a.Equals(b); + public static bool operator >(Double4 a, Double4 b) => a.CompareTo(b) > 0; + public static bool operator <(Double4 a, Double4 b) => a.CompareTo(b) < 0; + public static bool operator >=(Double4 a, Double4 b) => a == b || a > b; + public static bool operator <=(Double4 a, Double4 b) => a == b || a < b; + + public static implicit operator Double4(Double2 val) => new(val.x, val.y, 0, 0); + public static implicit operator Double4(Double3 val) => new(val.x, val.y, val.z, 0); + public static implicit operator Double4(Int2 val) => new(val.x, val.y, 0, 0); + public static implicit operator Double4(Int3 val) => new(val.x, val.y, val.z, 0); + public static implicit operator Double4(Int4 val) => new(val.x, val.y, val.z, val.w); + public static implicit operator Double4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0); + public static implicit operator Double4(Fill fill) => new(fill); + public static implicit operator Double4(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Equation.cs b/Nerd_STF/Mathematics/Equation.cs index 4e53596..e6012ac 100644 --- a/Nerd_STF/Mathematics/Equation.cs +++ b/Nerd_STF/Mathematics/Equation.cs @@ -1,10 +1,3 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics -{ - public delegate double Equation(double x); -} +public delegate double Equation(double x); diff --git a/Nerd_STF/Mathematics/Geometry/Box2D.cs b/Nerd_STF/Mathematics/Geometry/Box2D.cs index 3191dc0..570e77c 100644 --- a/Nerd_STF/Mathematics/Geometry/Box2D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box2D.cs @@ -1,130 +1,122 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Box2D : ICloneable, IContainer, IEquatable { - public struct Box2D : ICloneable, IContainer, IEquatable + public static Box2D Unit => new(Vert.Zero, Double2.One); + + public Vert MaxVert { - public static Box2D Unit => new(Vert.Zero, Double2.One); - - public Vert MaxVert + get => center + (size / 2); + set { - get => center + (size / 2); - set - { - Vert diff = center - value; - size = (Double2)diff.position * 2; - } + Vert diff = center - value; + size = (Double2)diff.position * 2; } - public Vert MinVert - { - get => center - (size / 2); - set - { - Vert diff = center + value; - size = (Double2)diff.position * 2; - } - } - - public double Area => size.x * size.y; - public double Perimeter => size.x * 2 + size.y * 2; - - public Vert center; - public Double2 size; - - public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Double2)(min - max)) { } - public Box2D(Vert center, Double2 size) - { - this.center = center; - this.size = size; - } - public Box2D(Fill fill) : this(fill, new Double2(fill(3), fill(4))) { } - - public double this[int index] - { - get => size[index]; - set => size[index] = value; - } - - public static Box2D Absolute(Box2D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert)); - public static Box2D Average(params Box2D[] vals) - { - (Vert[] centers, Double2[] sizes) = SplitArray(vals); - return new(Vert.Average(centers), Double2.Average(sizes)); - } - public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Double2.Ceiling(val.size)); - public static Box2D Clamp(Box2D val, Box2D min, Box2D max) => - new(Vert.Clamp(val.center, min.center, max.center), Double2.Clamp(val.size, min.size, max.size)); - public static Box2D Floor(Box2D val) => new(Vert.Floor(val.center), Double2.Floor(val.size)); - public static Box2D Lerp(Box2D a, Box2D b, float t, bool clamp = true) => - new(Vert.Lerp(a.center, b.center, t, clamp), Double2.Lerp(a.size, b.size, t, clamp)); - public static Box2D Median(params Box2D[] vals) - { - (Vert[] verts, Double2[] sizes) = SplitArray(vals); - return new(Vert.Median(verts), Double2.Median(sizes)); - } - public static Box2D Max(params Box2D[] vals) - { - (Vert[] verts, Double2[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Double2.Max(sizes)); - } - public static Box2D Min(params Box2D[] vals) - { - (Vert[] verts, Double2[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Double2.Min(sizes)); - } - public static (Vert[] centers, Double2[] sizes) SplitArray(params Box2D[] vals) - { - Vert[] centers = new Vert[vals.Length]; - Double2[] sizes = new Double2[vals.Length]; - - for (int i = 0; i < vals.Length; i++) - { - centers[i] = vals[i].center; - sizes[i] = vals[i].size; - } - - return (centers, sizes); - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Box2D)) return false; - return Equals((Box2D)obj); - } - public bool Equals(Box2D other) => center == other.center && size == other.size; - public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - public string ToString(IFormatProvider provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - - public bool Contains(Vert vert) - { - Double2 diff = Double2.Absolute((Double2)(center - vert)); - return diff.x <= size.x && diff.y <= size.y; - } - - public object Clone() => new Box2D(center, size); - - public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size); - public static Box2D operator +(Box2D a, Double2 b) => new(a.center, a.size + b); - public static Box2D operator -(Box2D b) => new(-b.MaxVert, -b.MinVert); - public static Box2D operator -(Box2D a, Vert b) => new(a.center - b, a.size); - public static Box2D operator -(Box2D a, Double2 b) => new(a.center, a.size - b); - public static Box2D operator *(Box2D a, double b) => new(a.center * b, a.size * b); - public static Box2D operator *(Box2D a, Double2 b) => new(a.center, a.size * b); - public static Box2D operator /(Box2D a, double b) => new(a.center / b, a.size / b); - public static Box2D operator /(Box2D a, Double2 b) => new(a.center, a.size / b); - public static bool operator ==(Box2D a, Box2D b) => a.Equals(b); - public static bool operator !=(Box2D a, Box2D b) => !a.Equals(b); - - public static implicit operator Box2D(Fill fill) => new(fill); - public static explicit operator Box2D(Box3D box) => new(box.center, (Double2)box.size); } + public Vert MinVert + { + get => center - (size / 2); + set + { + Vert diff = center + value; + size = (Double2)diff.position * 2; + } + } + + public double Area => size.x * size.y; + public double Perimeter => size.x * 2 + size.y * 2; + + public Vert center; + public Double2 size; + + public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Double2)(min - max)) { } + public Box2D(Vert center, Double2 size) + { + this.center = center; + this.size = size; + } + public Box2D(Fill fill) : this(fill, new Double2(fill(3), fill(4))) { } + + public double this[int index] + { + get => size[index]; + set => size[index] = value; + } + + public static Box2D Absolute(Box2D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert)); + public static Box2D Average(params Box2D[] vals) + { + (Vert[] centers, Double2[] sizes) = SplitArray(vals); + return new(Vert.Average(centers), Double2.Average(sizes)); + } + public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Double2.Ceiling(val.size)); + public static Box2D Clamp(Box2D val, Box2D min, Box2D max) => + new(Vert.Clamp(val.center, min.center, max.center), Double2.Clamp(val.size, min.size, max.size)); + public static Box2D Floor(Box2D val) => new(Vert.Floor(val.center), Double2.Floor(val.size)); + public static Box2D Lerp(Box2D a, Box2D b, float t, bool clamp = true) => + new(Vert.Lerp(a.center, b.center, t, clamp), Double2.Lerp(a.size, b.size, t, clamp)); + public static Box2D Median(params Box2D[] vals) + { + (Vert[] verts, Double2[] sizes) = SplitArray(vals); + return new(Vert.Median(verts), Double2.Median(sizes)); + } + public static Box2D Max(params Box2D[] vals) + { + (Vert[] verts, Double2[] sizes) = SplitArray(vals); + return new(Vert.Max(verts), Double2.Max(sizes)); + } + public static Box2D Min(params Box2D[] vals) + { + (Vert[] verts, Double2[] sizes) = SplitArray(vals); + return new(Vert.Min(verts), Double2.Min(sizes)); + } + public static (Vert[] centers, Double2[] sizes) SplitArray(params Box2D[] vals) + { + Vert[] centers = new Vert[vals.Length]; + Double2[] sizes = new Double2[vals.Length]; + + for (int i = 0; i < vals.Length; i++) + { + centers[i] = vals[i].center; + sizes[i] = vals[i].size; + } + + return (centers, sizes); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Box2D)) return false; + return Equals((Box2D)obj); + } + public bool Equals(Box2D other) => center == other.center && size == other.size; + public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + public string ToString(IFormatProvider provider) => + "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + + public bool Contains(Vert vert) + { + Double2 diff = Double2.Absolute((Double2)(center - vert)); + return diff.x <= size.x && diff.y <= size.y; + } + + public object Clone() => new Box2D(center, size); + + public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size); + public static Box2D operator +(Box2D a, Double2 b) => new(a.center, a.size + b); + public static Box2D operator -(Box2D b) => new(-b.MaxVert, -b.MinVert); + public static Box2D operator -(Box2D a, Vert b) => new(a.center - b, a.size); + public static Box2D operator -(Box2D a, Double2 b) => new(a.center, a.size - b); + public static Box2D operator *(Box2D a, double b) => new(a.center * b, a.size * b); + public static Box2D operator *(Box2D a, Double2 b) => new(a.center, a.size * b); + public static Box2D operator /(Box2D a, double b) => new(a.center / b, a.size / b); + public static Box2D operator /(Box2D a, Double2 b) => new(a.center, a.size / b); + public static bool operator ==(Box2D a, Box2D b) => a.Equals(b); + public static bool operator !=(Box2D a, Box2D b) => !a.Equals(b); + + public static implicit operator Box2D(Fill fill) => new(fill); + public static explicit operator Box2D(Box3D box) => new(box.center, (Double2)box.size); } diff --git a/Nerd_STF/Mathematics/Geometry/Box3D.cs b/Nerd_STF/Mathematics/Geometry/Box3D.cs index a3cc1df..47a64c2 100644 --- a/Nerd_STF/Mathematics/Geometry/Box3D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box3D.cs @@ -1,131 +1,122 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Box3D : ICloneable, IContainer, IEquatable { - public struct Box3D : ICloneable, IContainer, IEquatable + public static Box3D Unit => new(Vert.Zero, Double3.One); + + public Vert MaxVert { - public static Box3D Unit => new(Vert.Zero, Double3.One); - - public Vert MaxVert + get => center + (Vert)(size / 2); + set { - get => center + (Vert)(size / 2); - set - { - Vert diff = center - value; - size = diff.position * 2; - } + Vert diff = center - value; + size = diff.position * 2; } - public Vert MinVert - { - get => center - (Vert)(size / 2); - set - { - Vert diff = center + value; - size = diff.position * 2; - } - } - - public double Area => size.x * size.y * size.z; - public double Perimeter => size.x * 2 + size.y * 2 + size.z * 2; - - public Vert center; - public Double3 size; - - public Box3D(Box2D box) : this(box.center, (Double3)box.size) { } - public Box3D(Vert min, Vert max) : this(Vert.Average(min, max), (Double3)(min - max)) { } - public Box3D(Vert center, Double3 size) - { - this.center = center; - this.size = size; - } - public Box3D(Fill fill) : this(fill, new Double3(fill(3), fill(4), fill(5))) { } - - public double this[int index] - { - get => size[index]; - set => size[index] = value; - } - - public static Box3D Absolute(Box3D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert)); - public static Box3D Average(params Box3D[] vals) - { - (Vert[] centers, Double3[] sizes) = SplitArray(vals); - return new(Vert.Average(centers), Double3.Average(sizes)); - } - public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Double3.Ceiling(val.size)); - public static Box3D Clamp(Box3D val, Box3D min, Box3D max) => - new(Vert.Clamp(val.center, min.center, max.center), Double3.Clamp(val.size, min.size, max.size)); - public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Double3.Floor(val.size)); - public static Box3D Lerp(Box3D a, Box3D b, float t, bool clamp = true) => - new(Vert.Lerp(a.center, b.center, t, clamp), Double3.Lerp(a.size, b.size, t, clamp)); - public static Box3D Median(params Box3D[] vals) - { - (Vert[] verts, Double3[] sizes) = SplitArray(vals); - return new(Vert.Median(verts), Double3.Median(sizes)); - } - public static Box3D Max(params Box3D[] vals) - { - (Vert[] verts, Double3[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Double3.Max(sizes)); - } - public static Box3D Min(params Box3D[] vals) - { - (Vert[] verts, Double3[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Double3.Min(sizes)); - } - public static (Vert[] centers, Double3[] sizes) SplitArray(params Box3D[] vals) - { - Vert[] centers = new Vert[vals.Length]; - Double3[] sizes = new Double3[vals.Length]; - - for (int i = 0; i < vals.Length; i++) - { - centers[i] = vals[i].center; - sizes[i] = vals[i].size; - } - - return (centers, sizes); - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Box3D)) return false; - return Equals((Box3D)obj); - } - public bool Equals(Box3D other) => center == other.center && size == other.size; - public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - public string ToString(IFormatProvider provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - - public bool Contains(Vert vert) - { - Double3 diff = Double3.Absolute(center - vert); - return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z; - } - - public object Clone() => new Box3D(center, size); - - public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size); - public static Box3D operator +(Box3D a, Double3 b) => new(a.center, a.size + b); - public static Box3D operator -(Box3D b) => new(-b.MaxVert, -b.MinVert); - public static Box3D operator -(Box3D a, Vert b) => new(a.center - b, a.size); - public static Box3D operator -(Box3D a, Double3 b) => new(a.center, a.size - b); - public static Box3D operator *(Box3D a, double b) => new(a.center * b, a.size * b); - public static Box3D operator *(Box3D a, Double3 b) => new(a.center, a.size * b); - public static Box3D operator /(Box3D a, double b) => new(a.center / b, a.size / b); - public static Box3D operator /(Box3D a, Double3 b) => new(a.center, a.size / b); - public static bool operator ==(Box3D a, Box3D b) => a.Equals(b); - public static bool operator !=(Box3D a, Box3D b) => !a.Equals(b); - - public static implicit operator Box3D(Fill fill) => new(fill); - public static implicit operator Box3D(Box2D box) => new(box); } + public Vert MinVert + { + get => center - (Vert)(size / 2); + set + { + Vert diff = center + value; + size = diff.position * 2; + } + } + + public double Area => size.x * size.y * size.z; + public double Perimeter => size.x * 2 + size.y * 2 + size.z * 2; + + public Vert center; + public Double3 size; + + public Box3D(Box2D box) : this(box.center, (Double3)box.size) { } + public Box3D(Vert min, Vert max) : this(Vert.Average(min, max), (Double3)(min - max)) { } + public Box3D(Vert center, Double3 size) + { + this.center = center; + this.size = size; + } + public Box3D(Fill fill) : this(fill, new Double3(fill(3), fill(4), fill(5))) { } + + public double this[int index] + { + get => size[index]; + set => size[index] = value; + } + + public static Box3D Absolute(Box3D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert)); + public static Box3D Average(params Box3D[] vals) + { + (Vert[] centers, Double3[] sizes) = SplitArray(vals); + return new(Vert.Average(centers), Double3.Average(sizes)); + } + public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Double3.Ceiling(val.size)); + public static Box3D Clamp(Box3D val, Box3D min, Box3D max) => + new(Vert.Clamp(val.center, min.center, max.center), Double3.Clamp(val.size, min.size, max.size)); + public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Double3.Floor(val.size)); + public static Box3D Lerp(Box3D a, Box3D b, float t, bool clamp = true) => + new(Vert.Lerp(a.center, b.center, t, clamp), Double3.Lerp(a.size, b.size, t, clamp)); + public static Box3D Median(params Box3D[] vals) + { + (Vert[] verts, Double3[] sizes) = SplitArray(vals); + return new(Vert.Median(verts), Double3.Median(sizes)); + } + public static Box3D Max(params Box3D[] vals) + { + (Vert[] verts, Double3[] sizes) = SplitArray(vals); + return new(Vert.Max(verts), Double3.Max(sizes)); + } + public static Box3D Min(params Box3D[] vals) + { + (Vert[] verts, Double3[] sizes) = SplitArray(vals); + return new(Vert.Min(verts), Double3.Min(sizes)); + } + public static (Vert[] centers, Double3[] sizes) SplitArray(params Box3D[] vals) + { + Vert[] centers = new Vert[vals.Length]; + Double3[] sizes = new Double3[vals.Length]; + + for (int i = 0; i < vals.Length; i++) + { + centers[i] = vals[i].center; + sizes[i] = vals[i].size; + } + + return (centers, sizes); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Box3D)) return false; + return Equals((Box3D)obj); + } + public bool Equals(Box3D other) => center == other.center && size == other.size; + public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + public string ToString(IFormatProvider provider) => + "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + + public bool Contains(Vert vert) + { + Double3 diff = Double3.Absolute(center - vert); + return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z; + } + public object Clone() => new Box3D(center, size); + + public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size); + public static Box3D operator +(Box3D a, Double3 b) => new(a.center, a.size + b); + public static Box3D operator -(Box3D b) => new(-b.MaxVert, -b.MinVert); + public static Box3D operator -(Box3D a, Vert b) => new(a.center - b, a.size); + public static Box3D operator -(Box3D a, Double3 b) => new(a.center, a.size - b); + public static Box3D operator *(Box3D a, double b) => new(a.center * b, a.size * b); + public static Box3D operator *(Box3D a, Double3 b) => new(a.center, a.size * b); + public static Box3D operator /(Box3D a, double b) => new(a.center / b, a.size / b); + public static Box3D operator /(Box3D a, Double3 b) => new(a.center, a.size / b); + public static bool operator ==(Box3D a, Box3D b) => a.Equals(b); + public static bool operator !=(Box3D a, Box3D b) => !a.Equals(b); + + public static implicit operator Box3D(Fill fill) => new(fill); + public static implicit operator Box3D(Box2D box) => new(box); } diff --git a/Nerd_STF/Mathematics/Geometry/ISubdividable.cs b/Nerd_STF/Mathematics/Geometry/ISubdividable.cs index ff93cba..7807595 100644 --- a/Nerd_STF/Mathematics/Geometry/ISubdividable.cs +++ b/Nerd_STF/Mathematics/Geometry/ISubdividable.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public interface ISubdividable { - public interface ISubdividable - { - public T Subdivide(); - public T Subdivide(int iterations); - } + public T Subdivide(); + public T Subdivide(int iterations); } diff --git a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs b/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs index c142c4e..8097f74 100644 --- a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs +++ b/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs @@ -1,20 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public interface ITriangulatable { - public interface ITriangulatable + public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables) { - public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables) - { - List res = new(); - foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); - return res.ToArray(); - } - - public Triangle[] Triangulate(); + List res = new(); + foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); + return res.ToArray(); } + + public Triangle[] Triangulate(); } diff --git a/Nerd_STF/Mathematics/Geometry/Line.cs b/Nerd_STF/Mathematics/Geometry/Line.cs index 318455d..51779b2 100644 --- a/Nerd_STF/Mathematics/Geometry/Line.cs +++ b/Nerd_STF/Mathematics/Geometry/Line.cs @@ -1,202 +1,193 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Line : ICloneable, IClosest, IComparable, IContainer, IEquatable, + IGroup, ISubdividable { - public struct Line : ICloneable, IClosest, IComparable, IContainer, IEquatable, - IGroup, ISubdividable + public static Line Back => new(Vert.Zero, Vert.Back); + public static Line Down => new(Vert.Zero, Vert.Down); + public static Line Forward => new(Vert.Zero, Vert.Forward); + public static Line Left => new(Vert.Zero, Vert.Left); + public static Line Right => new(Vert.Zero, Vert.Right); + public static Line Up => new(Vert.Zero, Vert.Up); + + public static Line One => new(Vert.Zero, Vert.One); + public static Line Zero => new(Vert.Zero, Vert.Zero); + + public double Length => (b - a).Magnitude; + + public Vert a, b; + + public Line(Vert a, Vert b) { - public static Line Back => new(Vert.Zero, Vert.Back); - public static Line Down => new(Vert.Zero, Vert.Down); - public static Line Forward => new(Vert.Zero, Vert.Forward); - public static Line Left => new(Vert.Zero, Vert.Left); - public static Line Right => new(Vert.Zero, Vert.Right); - public static Line Up => new(Vert.Zero, Vert.Up); - - public static Line One => new(Vert.Zero, Vert.One); - public static Line Zero => new(Vert.Zero, Vert.Zero); - - public double Length => (b - a).Magnitude; - - public Vert a, b; - - public Line(Vert a, Vert b) - { - this.a = a; - this.b = b; - } - public Line(double x1, double y1, double x2, double y2) : this(new(x1, y1), new(x2, y2)) { } - public Line(double x1, double y1, double z1, double x2, double y2, double z2) - : this(new(x1, y1, z1), new(x2, y2, z2)) { } - public Line(Fill fill) : this(fill(0), fill(1)) { } - public Line(Fill fill) : this(new(fill(0)), new(fill(1))) { } - public Line(Fill fill) : this(new(fill(0)), new(fill(1))) { } - public Line(Fill fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { } - public Line(Fill fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { } - - public Vert this[int index] - { - get => index switch - { - 0 => a, - 1 => b, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - a = value; - break; - - case 1: - b = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b)); - public static Line Average(params Line[] vals) - { - (Vert[] starts, Vert[] ends) = SplitArray(vals); - return new(Vert.Average(starts), Vert.Average(ends)); - } - public static Line Ceiling(Line val) => new(Vert.Ceiling(val.a), Vert.Ceiling(val.b)); - public static Line Clamp(Line val, Line min, Line max) => - new(Vert.Clamp(val.a, min.a, max.a), Vert.Clamp(val.b, min.b, max.b)); - public static Line Floor(Line val) => new(Vert.Floor(val.a), Vert.Floor(val.b)); - public static Line Lerp(Line a, Line b, double t, bool clamp = true) => - new(Vert.Lerp(a.a, b.a, t, clamp), Vert.Lerp(a.b, b.b, t, clamp)); - public static Line Median(params Line[] vals) - { - (Vert[] starts, Vert[] ends) = SplitArray(vals); - return new(Vert.Median(starts), Vert.Median(ends)); - } - public static Line Max(params Line[] vals) - { - (Vert[] starts, Vert[] ends) = SplitArray(vals); - return new(Vert.Max(starts), Vert.Max(ends)); - } - public static Line Min(params Line[] vals) - { - (Vert[] starts, Vert[] ends) = SplitArray(vals); - return new(Vert.Min(starts), Vert.Min(ends)); - } - - public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines) - { - Vert[] starts = new Vert[lines.Length], ends = new Vert[lines.Length]; - for (int i = 0; i < lines.Length; i++) - { - starts[i] = lines[i].a; - ends[i] = lines[i].b; - } - return (starts, ends); - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Line)) return false; - return Equals((Line)obj); - } - public bool Equals(Line other) => a == other.a && b == other.b; - public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "A: " + a.ToString(provider) + " B: " + b.ToString(provider); - public string ToString(IFormatProvider provider) => - "A: " + a.ToString(provider) + " B: " + b.ToString(provider); - - public object Clone() => new Line(a, b); - - public int CompareTo(Line line) => Length.CompareTo(line.Length); - - public bool Contains(Vert vert) - { - Double3 diffA = a - vert, diffB = a - b; - double lerpVal = diffA.Magnitude / diffB.Magnitude; - return Vert.Lerp(a, b, lerpVal) == vert; - } - - public Vert ClosestTo(Vert vert) => ClosestTo(vert, Calculus.DefaultStep); - public Vert ClosestTo(Vert vert, double step) - { - Vert closestA = a, closestB = b; - for (double t = 0; t <= 1; t += step) - { - Vert valA = Vert.Lerp(a, b, t); - Vert valB = Vert.Lerp(b, a, t); - closestA = (valA - vert).Magnitude < (closestA - vert).Magnitude ? valA : closestA; - closestB = (valB - vert).Magnitude < (closestB - vert).Magnitude ? valB : closestB; - } - - return (closestA - vert).Magnitude >= (closestB - vert).Magnitude ? closestA : closestB; - } - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return a; - yield return b; - } - - public Line[] Subdivide() - { - Vert middle = Vert.Lerp(a, b, 0.5); - return new Line[] { new(a, middle), new(middle, b) }; - } - public Line[] Subdivide(int iterations) - { - if (iterations < 1) return Array.Empty(); - List lines = new(Subdivide()); - for (int i = 1; i < iterations; i++) - { - List add = new(); - for (int j = 0; j < lines.Count; j++) add.AddRange(lines[j].Subdivide()); - lines = add; - } - return lines.ToArray(); - } - - public Vert[] ToArray() => new Vert[] { a, b }; - public List ToList() => new() { a, b }; - - public double[] ToDoubleArray() => new double[] { a.position.x, a.position.y, a.position.z, - b.position.x, b.position.y, b.position.z }; - public List ToDoubleList() => new() { a.position.x, a.position.y, a.position.z, - b.position.x, b.position.y, b.position.z }; - - public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b); - public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b); - public static Line operator -(Line l) => new(-l.a, -l.b); - public static Line operator -(Line a, Line b) => new(a.a - b.a, a.b - b.b); - public static Line operator -(Line a, Vert b) => new(a.a - b, a.b - b); - public static Line operator *(Line a, Line b) => new(a.a * b.a, a.b * b.b); - public static Line operator *(Line a, Vert b) => new(a.a * b, a.b * b); - public static Line operator *(Line a, double b) => new(a.a * b, a.b * b); - public static Line operator /(Line a, Line b) => new(a.a / b.a, a.b / b.b); - public static Line operator /(Line a, Vert b) => new(a.a / b, a.b / b); - public static Line operator /(Line a, double b) => new(a.a / b, a.b / b); - public static bool operator ==(Line a, Line b) => a.Equals(b); - public static bool operator !=(Line a, Line b) => !a.Equals(b); - public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0; - public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0; - public static bool operator >=(Line a, Line b) => a > b || a == b; - public static bool operator <=(Line a, Line b) => a < b || a == b; - - public static implicit operator Line(Fill fill) => new(fill); - public static implicit operator Line(Fill fill) => new(fill); - public static implicit operator Line(Fill fill) => new(fill); - public static implicit operator Line(Fill fill) => new(fill); - public static implicit operator Line(Fill fill) => new(fill); + this.a = a; + this.b = b; } + public Line(double x1, double y1, double x2, double y2) : this(new(x1, y1), new(x2, y2)) { } + public Line(double x1, double y1, double z1, double x2, double y2, double z2) + : this(new(x1, y1, z1), new(x2, y2, z2)) { } + public Line(Fill fill) : this(fill(0), fill(1)) { } + public Line(Fill fill) : this(new(fill(0)), new(fill(1))) { } + public Line(Fill fill) : this(new(fill(0)), new(fill(1))) { } + public Line(Fill fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { } + public Line(Fill fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { } + + public Vert this[int index] + { + get => index switch + { + 0 => a, + 1 => b, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + a = value; + break; + + case 1: + b = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b)); + public static Line Average(params Line[] vals) + { + (Vert[] starts, Vert[] ends) = SplitArray(vals); + return new(Vert.Average(starts), Vert.Average(ends)); + } + public static Line Ceiling(Line val) => new(Vert.Ceiling(val.a), Vert.Ceiling(val.b)); + public static Line Clamp(Line val, Line min, Line max) => + new(Vert.Clamp(val.a, min.a, max.a), Vert.Clamp(val.b, min.b, max.b)); + public static Line Floor(Line val) => new(Vert.Floor(val.a), Vert.Floor(val.b)); + public static Line Lerp(Line a, Line b, double t, bool clamp = true) => + new(Vert.Lerp(a.a, b.a, t, clamp), Vert.Lerp(a.b, b.b, t, clamp)); + public static Line Median(params Line[] vals) + { + (Vert[] starts, Vert[] ends) = SplitArray(vals); + return new(Vert.Median(starts), Vert.Median(ends)); + } + public static Line Max(params Line[] vals) + { + (Vert[] starts, Vert[] ends) = SplitArray(vals); + return new(Vert.Max(starts), Vert.Max(ends)); + } + public static Line Min(params Line[] vals) + { + (Vert[] starts, Vert[] ends) = SplitArray(vals); + return new(Vert.Min(starts), Vert.Min(ends)); + } + + public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines) + { + Vert[] starts = new Vert[lines.Length], ends = new Vert[lines.Length]; + for (int i = 0; i < lines.Length; i++) + { + starts[i] = lines[i].a; + ends[i] = lines[i].b; + } + return (starts, ends); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Line)) return false; + return Equals((Line)obj); + } + public bool Equals(Line other) => a == other.a && b == other.b; + public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "A: " + a.ToString(provider) + " B: " + b.ToString(provider); + public string ToString(IFormatProvider provider) => + "A: " + a.ToString(provider) + " B: " + b.ToString(provider); + + public object Clone() => new Line(a, b); + + public int CompareTo(Line line) => Length.CompareTo(line.Length); + + public bool Contains(Vert vert) + { + Double3 diffA = a - vert, diffB = a - b; + double lerpVal = diffA.Magnitude / diffB.Magnitude; + return Vert.Lerp(a, b, lerpVal) == vert; + } + + public Vert ClosestTo(Vert vert) => ClosestTo(vert, Calculus.DefaultStep); + public Vert ClosestTo(Vert vert, double step) + { + Vert closestA = a, closestB = b; + for (double t = 0; t <= 1; t += step) + { + Vert valA = Vert.Lerp(a, b, t); + Vert valB = Vert.Lerp(b, a, t); + closestA = (valA - vert).Magnitude < (closestA - vert).Magnitude ? valA : closestA; + closestB = (valB - vert).Magnitude < (closestB - vert).Magnitude ? valB : closestB; + } + + return (closestA - vert).Magnitude >= (closestB - vert).Magnitude ? closestA : closestB; + } + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return a; + yield return b; + } + + public Line[] Subdivide() + { + Vert middle = Vert.Lerp(a, b, 0.5); + return new Line[] { new(a, middle), new(middle, b) }; + } + public Line[] Subdivide(int iterations) + { + if (iterations < 1) return Array.Empty(); + List lines = new(Subdivide()); + for (int i = 1; i < iterations; i++) + { + List add = new(); + for (int j = 0; j < lines.Count; j++) add.AddRange(lines[j].Subdivide()); + lines = add; + } + return lines.ToArray(); + } + + public Vert[] ToArray() => new Vert[] { a, b }; + public List ToList() => new() { a, b }; + + public double[] ToDoubleArray() => new double[] { a.position.x, a.position.y, a.position.z, + b.position.x, b.position.y, b.position.z }; + public List ToDoubleList() => new() { a.position.x, a.position.y, a.position.z, + b.position.x, b.position.y, b.position.z }; + + public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b); + public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b); + public static Line operator -(Line l) => new(-l.a, -l.b); + public static Line operator -(Line a, Line b) => new(a.a - b.a, a.b - b.b); + public static Line operator -(Line a, Vert b) => new(a.a - b, a.b - b); + public static Line operator *(Line a, Line b) => new(a.a * b.a, a.b * b.b); + public static Line operator *(Line a, Vert b) => new(a.a * b, a.b * b); + public static Line operator *(Line a, double b) => new(a.a * b, a.b * b); + public static Line operator /(Line a, Line b) => new(a.a / b.a, a.b / b.b); + public static Line operator /(Line a, Vert b) => new(a.a / b, a.b / b); + public static Line operator /(Line a, double b) => new(a.a / b, a.b / b); + public static bool operator ==(Line a, Line b) => a.Equals(b); + public static bool operator !=(Line a, Line b) => !a.Equals(b); + public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0; + public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0; + public static bool operator >=(Line a, Line b) => a > b || a == b; + public static bool operator <=(Line a, Line b) => a < b || a == b; + + public static implicit operator Line(Fill fill) => new(fill); + public static implicit operator Line(Fill fill) => new(fill); + public static implicit operator Line(Fill fill) => new(fill); + public static implicit operator Line(Fill fill) => new(fill); + public static implicit operator Line(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Geometry/Polygon.cs b/Nerd_STF/Mathematics/Geometry/Polygon.cs index 8fe2a34..de88add 100644 --- a/Nerd_STF/Mathematics/Geometry/Polygon.cs +++ b/Nerd_STF/Mathematics/Geometry/Polygon.cs @@ -1,16 +1,8 @@ -using Nerd_STF.Exceptions; -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Polygon : ICloneable, IEquatable, IGroup, ISubdividable, ITriangulatable { - public struct Polygon : ICloneable, IEquatable, IGroup, ISubdividable, ITriangulatable - { - public Line[] Lines + public Line[] Lines { get => p_lines; set @@ -19,7 +11,7 @@ namespace Nerd_STF.Mathematics.Geometry p_verts = GenerateVerts(value); } } - public Vert[] Verts + public Vert[] Verts { get => p_verts; set @@ -29,21 +21,21 @@ namespace Nerd_STF.Mathematics.Geometry } } - private Line[] p_lines; - private Vert[] p_verts; + private Line[] p_lines; + private Vert[] p_verts; - [Obsolete("This method uses the Polygon.Triangulate() function, which has issues. It will be fixed in a " + - "future update.")] - public double Area + [Obsolete("This method uses the Polygon.Triangulate() function, which has issues. It will be fixed in a " + + "future update.")] + public double Area + { + get { - get - { - double val = 0; - foreach (Triangle t in Triangulate()) val += t.Area; - return val; - } + double val = 0; + foreach (Triangle t in Triangulate()) val += t.Area; + return val; } - public double Perimeter + } + public double Perimeter { get { @@ -53,12 +45,12 @@ namespace Nerd_STF.Mathematics.Geometry } } - public Polygon() - { - p_lines = Array.Empty(); - p_verts = Array.Empty(); - } - public Polygon(Fill fill) + public Polygon() + { + p_lines = Array.Empty(); + p_verts = Array.Empty(); + } + public Polygon(Fill fill) { List verts = new(); int i = 0; @@ -70,7 +62,7 @@ namespace Nerd_STF.Mathematics.Geometry } this = new(verts.ToArray()); } - public Polygon(Fill fill) + public Polygon(Fill fill) { List verts = new(); int i = 0; @@ -82,7 +74,7 @@ namespace Nerd_STF.Mathematics.Geometry } this = new(verts.ToArray()); } - public Polygon(Fill fill) + public Polygon(Fill fill) { List lines = new(); int i = 0; @@ -94,65 +86,65 @@ namespace Nerd_STF.Mathematics.Geometry } this = new(lines.ToArray()); } - public Polygon(Fill fill, int length) + public Polygon(Fill fill, int length) { List verts = new(); for (int i = 0; i < length; i++) verts.Add(fill(i)); this = new(verts.ToArray()); } - public Polygon(Fill fill, int length) + public Polygon(Fill fill, int length) { List verts = new(); for (int i = 0; i < length; i++) verts.Add(fill(i)); this = new(verts.ToArray()); } - public Polygon(Fill fill, int length) + public Polygon(Fill fill, int length) { List lines = new(); for (int i = 0; i < length; i++) lines.Add(fill(i)); this = new(lines.ToArray()); } - public Polygon(params Double3[] verts) + public Polygon(params Double3[] verts) { p_verts = new Vert[verts.Length]; for (int i = 0; i < verts.Length; i++) p_verts[i] = verts[i]; p_lines = GenerateLines(p_verts); } - public Polygon(params Vert[] verts) + public Polygon(params Vert[] verts) { p_verts = verts; p_lines = GenerateLines(verts); } - public Polygon(params Line[] lines) + public Polygon(params Line[] lines) { p_lines = lines; p_verts = GenerateVerts(lines); } - public Vert this[int index] + public Vert this[int index] { get => Verts[index]; set => Verts[index] = value; } - public static Polygon CreateCircle(int vertCount) + public static Polygon CreateCircle(int vertCount) + { + List parts = new(); + for (int i = 0; i < vertCount; i++) { - List parts = new(); - for (int i = 0; i < vertCount; i++) - { - double val = Mathf.Tau * i / vertCount; - parts.Add(new(Mathf.Cos(val), Mathf.Sin(val))); - } - return new(parts.ToArray()); + double val = Mathf.Tau * i / vertCount; + parts.Add(new(Mathf.Cos(val), Mathf.Sin(val))); } + return new(parts.ToArray()); + } - public static Polygon Absolute(Polygon val) + public static Polygon Absolute(Polygon val) { Vert[] v = val.Verts; for (int i = 0; i < v.Length; i++) v[i] = Vert.Absolute(v[i]); return new(v); } - public static Polygon Average(params Polygon[] vals) + public static Polygon Average(params Polygon[] vals) { if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); if (vals.Length < 1) return default; @@ -170,13 +162,13 @@ namespace Nerd_STF.Mathematics.Geometry return new(res); } - public static Polygon Ceiling(Polygon val) + public static Polygon Ceiling(Polygon val) { Vert[] v = val.Verts; for (int i = 0; i < v.Length; i++) v[i] = Vert.Ceiling(v[i]); return new(v); } - public static Polygon Clamp(Polygon val, Polygon min, Polygon max) + public static Polygon Clamp(Polygon val, Polygon min, Polygon max) { if (!CheckVerts(val, min, max)) throw new DifferingVertCountException(val, min, max); Line[][] lines = new Line[3][] { val.Lines, min.Lines, max.Lines }; @@ -184,13 +176,13 @@ namespace Nerd_STF.Mathematics.Geometry for (int i = 0; i < res.Length; i++) res[i] = Line.Clamp(lines[0][i], lines[1][i], lines[2][i]); return new(res); } - public static Polygon Floor(Polygon val) + public static Polygon Floor(Polygon val) { Vert[] v = val.Verts; for (int i = 0; i < v.Length; i++) v[i] = Vert.Floor(v[i]); return new(v); } - public static Polygon Lerp(Polygon a, Polygon b, double t, bool clamp = true) + public static Polygon Lerp(Polygon a, Polygon b, double t, bool clamp = true) { if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); Line[][] lines = new Line[2][] { a.Lines, b.Lines }; @@ -198,7 +190,7 @@ namespace Nerd_STF.Mathematics.Geometry for (int i = 0; i < res.Length; i++) res[i] = Line.Lerp(lines[0][i], lines[1][i], t, clamp); return new(res); } - public static Polygon Max(params Polygon[] vals) + public static Polygon Max(params Polygon[] vals) { if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); if (vals.Length < 1) return default; @@ -216,7 +208,7 @@ namespace Nerd_STF.Mathematics.Geometry return new(res); } - public static Polygon Median(params Polygon[] vals) + public static Polygon Median(params Polygon[] vals) { if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); if (vals.Length < 1) return default; @@ -234,7 +226,7 @@ namespace Nerd_STF.Mathematics.Geometry return new(res); } - public static Polygon Min(params Polygon[] vals) + public static Polygon Min(params Polygon[] vals) { if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); if (vals.Length < 1) return default; @@ -253,48 +245,48 @@ namespace Nerd_STF.Mathematics.Geometry return new(res); } - public static double[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray(); - public static List ToDoubleListAll(params Polygon[] polys) + public static double[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray(); + public static List ToDoubleListAll(params Polygon[] polys) { List vals = new(); foreach (Polygon poly in polys) vals.AddRange(poly.ToDoubleArray()); return vals; } - public override bool Equals([NotNullWhen(true)] object? obj) + public override bool Equals([NotNullWhen(true)] object? obj) { if (obj == null || obj.GetType() != typeof(Polygon)) return false; return Equals((Polygon)obj); } - public bool Equals(Polygon other) + public bool Equals(Polygon other) { if (!CheckVerts(this, other)) return false; return Lines == other.Lines; } - public override int GetHashCode() => Lines.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) + public override int GetHashCode() => Lines.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) { string s = ""; for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " "; return s; } - public string ToString(IFormatProvider provider) + public string ToString(IFormatProvider provider) { string s = ""; for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " "; return s; } - public object Clone() => new Polygon(Lines); + public object Clone() => new Polygon(Lines); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() { foreach (Vert v in Verts) yield return v; } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() { foreach (Vert v in Verts) yield return v; } - public Vert[] ToArray() => Verts; - public List ToList() => new(Verts); + public Vert[] ToArray() => Verts; + public List ToList() => new(Verts); - public double[] ToDoubleArray() + public double[] ToDoubleArray() { double[] vals = new double[Verts.Length * 3]; for (int i = 0; i < Verts.Length; i++) @@ -306,57 +298,57 @@ namespace Nerd_STF.Mathematics.Geometry } return vals; } - public List ToDoubleList() => new(ToDoubleArray()); + public List ToDoubleList() => new(ToDoubleArray()); - public Polygon Subdivide() - { - Polygon poly = new(); - List lines = new(); - for (int i = 0; i < Lines.Length; i++) lines.AddRange(Lines[i].Subdivide()); - return poly; - } - public Polygon Subdivide(int iterations) - { - if (iterations < 1) return new(); - Polygon poly = this; - for (int i = 0; i < iterations; i++) poly = poly.Subdivide(); - return poly; - } + public Polygon Subdivide() + { + Polygon poly = new(); + List lines = new(); + for (int i = 0; i < Lines.Length; i++) lines.AddRange(Lines[i].Subdivide()); + return poly; + } + public Polygon Subdivide(int iterations) + { + if (iterations < 1) return new(); + Polygon poly = this; + for (int i = 0; i < iterations; i++) poly = poly.Subdivide(); + return poly; + } - public Polygon SubdivideCatmullClark(int segments) + public Polygon SubdivideCatmullClark(int segments) + { + // Thanks Saalty for making this accidentally. + List newVerts = new(); + for (int i = 0; i < Verts.Length; i++) { - // Thanks Saalty for making this accidentally. - List newVerts = new(); - for (int i = 0; i < Verts.Length; i++) + for (int factor = 0; factor < segments; factor++) { - for (int factor = 0; factor < segments; factor++) + double unit = factor / (double)(segments * 2), unit2 = unit + 0.5, lastUnit = unit * 2; + Vert p1, p2; + if (i == Verts.Length - 1) { - double unit = factor / (double)(segments * 2), unit2 = unit + 0.5, lastUnit = unit * 2; - Vert p1, p2; - if (i == Verts.Length - 1) - { - p1 = Verts[^1] + (Verts[0] - Verts[^1]) * unit2; - p2 = Verts[0] + (Verts[1] - Verts[0]) * unit; - } - else if (i == Verts.Length - 2) - { - p1 = Verts[^2] + (Verts[^1] - Verts[^2]) * unit2; - p2 = Verts[^1] + (Verts[0] - Verts[^1]) * unit; - } - else - { - p1 = Verts[i] + (Verts[i + 1] - Verts[i]) * unit2; - p2 = Verts[i + 1] + (Verts[i + 2] - Verts[i + 1]) * unit; - } - newVerts.Add(p1 + (p2 - p1) * lastUnit); + p1 = Verts[^1] + (Verts[0] - Verts[^1]) * unit2; + p2 = Verts[0] + (Verts[1] - Verts[0]) * unit; } + else if (i == Verts.Length - 2) + { + p1 = Verts[^2] + (Verts[^1] - Verts[^2]) * unit2; + p2 = Verts[^1] + (Verts[0] - Verts[^1]) * unit; + } + else + { + p1 = Verts[i] + (Verts[i + 1] - Verts[i]) * unit2; + p2 = Verts[i + 1] + (Verts[i + 2] - Verts[i + 1]) * unit; + } + newVerts.Add(p1 + (p2 - p1) * lastUnit); } - return new(newVerts.ToArray()); } + return new(newVerts.ToArray()); + } - [Obsolete("This method doesn't work very well, and will give very weird results in certain cases. " + - "This will be fixed in a future update.")] - public Triangle[] Triangulate() + [Obsolete("This method doesn't work very well, and will give very weird results in certain cases. " + + "This will be fixed in a future update.")] + public Triangle[] Triangulate() { // This may cause issues. FIXME // Tbh, not even sure if this works. This was a bit confusing. @@ -397,7 +389,7 @@ namespace Nerd_STF.Mathematics.Geometry return tris.ToArray(); } - private static bool CheckVerts(params Polygon[] polys) + private static bool CheckVerts(params Polygon[] polys) { int len = -1; foreach (Polygon poly in polys) @@ -411,14 +403,14 @@ namespace Nerd_STF.Mathematics.Geometry } return true; } - private static Line[] GenerateLines(Vert[] verts) + private static Line[] GenerateLines(Vert[] verts) { Line[] lines = new Line[verts.Length]; for (int i = 0; i < lines.Length; i++) lines[i] = new(verts[i], verts[i == lines.Length - 1 ? 0 : i + 1]); return lines; } - private static Vert[] GenerateVerts(Line[] lines) + private static Vert[] GenerateVerts(Line[] lines) { Vert[] verts = new Vert[lines.Length]; for (int i = 0; i < verts.Length; i++) @@ -430,90 +422,89 @@ namespace Nerd_STF.Mathematics.Geometry return verts; } - public static Polygon operator +(Polygon a, Polygon b) - { - if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); - Line[][] lines = new Line[2][] { a.Lines, b.Lines }; - Line[] res = new Line[a.Lines.Length]; - for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] + lines[1][i]; - return new(res); - } - public static Polygon operator +(Polygon a, Vert b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] += b; - return new(lines); - } - public static Polygon operator -(Polygon p) - { - Line[] lines = p.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] = -lines[i]; - return new(lines); - } - public static Polygon operator -(Polygon a, Polygon b) - { - if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); - Line[][] lines = new Line[2][] { a.Lines, b.Lines }; - Line[] res = new Line[a.Lines.Length]; - for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] - lines[1][i]; - return new(res); - } - public static Polygon operator -(Polygon a, Vert b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] -= b; - return new(lines); - } - public static Polygon operator *(Polygon a, Polygon b) - { - if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); - Line[][] lines = new Line[2][] { a.Lines, b.Lines }; - Line[] res = new Line[a.Lines.Length]; - for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] * lines[1][i]; - return new(res); - } - public static Polygon operator *(Polygon a, Vert b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] *= b; - return new(lines); - } - public static Polygon operator *(Polygon a, float b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] *= b; - return new(lines); - } - public static Polygon operator /(Polygon a, Polygon b) - { - if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); - Line[][] lines = new Line[2][] { a.Lines, b.Lines }; - Line[] res = new Line[a.Lines.Length]; - for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] / lines[1][i]; - return new(res); - } - public static Polygon operator /(Polygon a, Vert b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] /= b; - return new(lines); - } - public static Polygon operator /(Polygon a, float b) - { - Line[] lines = a.Lines; - for (int i = 0; i < lines.Length; i++) lines[i] /= b; - return new(lines); - } - public static bool operator ==(Polygon a, Polygon b) => a.Equals(b); - public static bool operator !=(Polygon a, Polygon b) => !a.Equals(b); - - public static implicit operator Polygon(Fill fill) => new(fill); - public static implicit operator Polygon(Fill fill) => new(fill); - public static implicit operator Polygon(Fill fill) => new(fill); - public static implicit operator Polygon(Vert[] verts) => new(verts); - public static implicit operator Polygon(Double3[] verts) => new(verts); - public static implicit operator Polygon(Line[] lines) => new(lines); - public static implicit operator Polygon(Triangle tri) => new(tri.AB, tri.BC, tri.CA); - public static implicit operator Polygon(Quadrilateral quad) => new(quad.AB, quad.BC, quad.CD, quad.DA); + public static Polygon operator +(Polygon a, Polygon b) + { + if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); + Line[][] lines = new Line[2][] { a.Lines, b.Lines }; + Line[] res = new Line[a.Lines.Length]; + for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] + lines[1][i]; + return new(res); } + public static Polygon operator +(Polygon a, Vert b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] += b; + return new(lines); + } + public static Polygon operator -(Polygon p) + { + Line[] lines = p.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] = -lines[i]; + return new(lines); + } + public static Polygon operator -(Polygon a, Polygon b) + { + if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); + Line[][] lines = new Line[2][] { a.Lines, b.Lines }; + Line[] res = new Line[a.Lines.Length]; + for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] - lines[1][i]; + return new(res); + } + public static Polygon operator -(Polygon a, Vert b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] -= b; + return new(lines); + } + public static Polygon operator *(Polygon a, Polygon b) + { + if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); + Line[][] lines = new Line[2][] { a.Lines, b.Lines }; + Line[] res = new Line[a.Lines.Length]; + for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] * lines[1][i]; + return new(res); + } + public static Polygon operator *(Polygon a, Vert b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] *= b; + return new(lines); + } + public static Polygon operator *(Polygon a, float b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] *= b; + return new(lines); + } + public static Polygon operator /(Polygon a, Polygon b) + { + if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); + Line[][] lines = new Line[2][] { a.Lines, b.Lines }; + Line[] res = new Line[a.Lines.Length]; + for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] / lines[1][i]; + return new(res); + } + public static Polygon operator /(Polygon a, Vert b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] /= b; + return new(lines); + } + public static Polygon operator /(Polygon a, float b) + { + Line[] lines = a.Lines; + for (int i = 0; i < lines.Length; i++) lines[i] /= b; + return new(lines); + } + public static bool operator ==(Polygon a, Polygon b) => a.Equals(b); + public static bool operator !=(Polygon a, Polygon b) => !a.Equals(b); + + public static implicit operator Polygon(Fill fill) => new(fill); + public static implicit operator Polygon(Fill fill) => new(fill); + public static implicit operator Polygon(Fill fill) => new(fill); + public static implicit operator Polygon(Vert[] verts) => new(verts); + public static implicit operator Polygon(Double3[] verts) => new(verts); + public static implicit operator Polygon(Line[] lines) => new(lines); + public static implicit operator Polygon(Triangle tri) => new(tri.AB, tri.BC, tri.CA); + public static implicit operator Polygon(Quadrilateral quad) => new(quad.AB, quad.BC, quad.CD, quad.DA); } diff --git a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs index 6b5e70d..c2d297e 100644 --- a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs +++ b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs @@ -1,17 +1,8 @@ -using Nerd_STF.Exceptions; -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Quadrilateral : ICloneable, IEquatable, IGroup, ITriangulatable { - public struct Quadrilateral : ICloneable, IEquatable, IGroup, ITriangulatable - { - public Vert A + public Vert A { get => p_a; set @@ -21,7 +12,7 @@ namespace Nerd_STF.Mathematics.Geometry p_da.b = value; } } - public Vert B + public Vert B { get => p_b; set @@ -31,7 +22,7 @@ namespace Nerd_STF.Mathematics.Geometry p_bc.a = value; } } - public Vert C + public Vert C { get => p_c; set @@ -41,7 +32,7 @@ namespace Nerd_STF.Mathematics.Geometry p_cd.a = value; } } - public Vert D + public Vert D { get => p_d; set @@ -51,7 +42,7 @@ namespace Nerd_STF.Mathematics.Geometry p_da.a = value; } } - public Line AB + public Line AB { get => p_ab; set @@ -63,7 +54,7 @@ namespace Nerd_STF.Mathematics.Geometry p_da.b = value.a; } } - public Line BC + public Line BC { get => p_bc; set @@ -75,7 +66,7 @@ namespace Nerd_STF.Mathematics.Geometry p_ab.b = value.a; } } - public Line CD + public Line CD { get => p_cd; set @@ -87,7 +78,7 @@ namespace Nerd_STF.Mathematics.Geometry p_bc.b = value.a; } } - public Line DA + public Line DA { get => p_da; set @@ -100,21 +91,21 @@ namespace Nerd_STF.Mathematics.Geometry } } - private Vert p_a, p_b, p_c, p_d; - private Line p_ab, p_bc, p_cd, p_da; + private Vert p_a, p_b, p_c, p_d; + private Line p_ab, p_bc, p_cd, p_da; - public double Area + public double Area + { + get { - get - { - double val = 0; - foreach (Triangle t in Triangulate()) val += t.Area; - return val; - } + double val = 0; + foreach (Triangle t in Triangulate()) val += t.Area; + return val; } - public double Perimeter => AB.Length + BC.Length + CD.Length + DA.Length; + } + public double Perimeter => AB.Length + BC.Length + CD.Length + DA.Length; - public Quadrilateral(Vert a, Vert b, Vert c, Vert d) + public Quadrilateral(Vert a, Vert b, Vert c, Vert d) { p_a = a; p_b = b; @@ -125,7 +116,7 @@ namespace Nerd_STF.Mathematics.Geometry p_cd = new(c, d); p_da = new(d, a); } - public Quadrilateral(Line ab, Line bc, Line cd, Line da) + public Quadrilateral(Line ab, Line bc, Line cd, Line da) { if (ab.a != da.b || ab.b != bc.a || bc.b != cd.a || cd.b != da.a) throw new DisconnectedLinesException(ab, bc, cd, da); @@ -139,21 +130,21 @@ namespace Nerd_STF.Mathematics.Geometry p_cd = cd; p_da = da; } - public Quadrilateral(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) - : this(new Vert(x1, y1), new(x2, y2), new(x3, y3), new(x4, y4)) { } - public Quadrilateral(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, - double z3, double x4, double y4, double z4) - : this(new Vert(x1, y1, z1), new(x2, y2, z2), new(x3, y3, z3), new(x4, y4, z4)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), - fill(7), fill(8), fill(9), fill(10), fill(11)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), - fill(7), fill(8), fill(9), fill(10), fill(11)) { } + public Quadrilateral(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) + : this(new Vert(x1, y1), new(x2, y2), new(x3, y3), new(x4, y4)) { } + public Quadrilateral(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, + double z3, double x4, double y4, double z4) + : this(new Vert(x1, y1, z1), new(x2, y2, z2), new(x3, y3, z3), new(x4, y4, z4)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), + fill(7), fill(8), fill(9), fill(10), fill(11)) { } + public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), + fill(7), fill(8), fill(9), fill(10), fill(11)) { } - public Vert this[int index] + public Vert this[int index] { get => index switch { @@ -188,40 +179,40 @@ namespace Nerd_STF.Mathematics.Geometry } } - public static Quadrilateral Absolute(Quadrilateral val) => - new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D)); - public static Quadrilateral Average(params Quadrilateral[] vals) - { - (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); - return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs), Vert.Average(Ds)); - } - public static Quadrilateral Ceiling(Quadrilateral val) => - new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C), Vert.Ceiling(val.D)); - public static Quadrilateral Clamp(Quadrilateral val, Quadrilateral min, Quadrilateral max) => - new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C), - Vert.Clamp(val.D, min.D, max.D)); - public static Quadrilateral Floor(Quadrilateral val) => - new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C), Vert.Floor(val.D)); - public static Quadrilateral Lerp(Quadrilateral a, Quadrilateral b, double t, bool clamp = true) => - new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp), - Vert.Lerp(a.D, b.D, t, clamp)); - public static Quadrilateral Max(params Quadrilateral[] vals) - { - (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); - return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs), Vert.Max(Ds)); - } - public static Quadrilateral Median(params Quadrilateral[] vals) - { - (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); - return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs), Vert.Median(Ds)); - } - public static Quadrilateral Min(params Quadrilateral[] vals) - { - (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); - return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs), Vert.Min(Ds)); - } + public static Quadrilateral Absolute(Quadrilateral val) => + new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D)); + public static Quadrilateral Average(params Quadrilateral[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); + return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs), Vert.Average(Ds)); + } + public static Quadrilateral Ceiling(Quadrilateral val) => + new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C), Vert.Ceiling(val.D)); + public static Quadrilateral Clamp(Quadrilateral val, Quadrilateral min, Quadrilateral max) => + new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C), + Vert.Clamp(val.D, min.D, max.D)); + public static Quadrilateral Floor(Quadrilateral val) => + new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C), Vert.Floor(val.D)); + public static Quadrilateral Lerp(Quadrilateral a, Quadrilateral b, double t, bool clamp = true) => + new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp), + Vert.Lerp(a.D, b.D, t, clamp)); + public static Quadrilateral Max(params Quadrilateral[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); + return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs), Vert.Max(Ds)); + } + public static Quadrilateral Median(params Quadrilateral[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); + return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs), Vert.Median(Ds)); + } + public static Quadrilateral Min(params Quadrilateral[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); + return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs), Vert.Min(Ds)); + } - public static (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) SplitVertArray(params Quadrilateral[] quads) + public static (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) SplitVertArray(params Quadrilateral[] quads) { Vert[] a = new Vert[quads.Length], b = new Vert[quads.Length], c = new Vert[quads.Length], d = new Vert[quads.Length]; @@ -235,7 +226,7 @@ namespace Nerd_STF.Mathematics.Geometry return (a, b, c, d); } - public static (Line[] ABs, Line[] BCs, Line[] CDs, Line[] DAs) SplitLineArray(params Quadrilateral[] quads) + public static (Line[] ABs, Line[] BCs, Line[] CDs, Line[] DAs) SplitLineArray(params Quadrilateral[] quads) { Line[] ab = new Line[quads.Length], bc = new Line[quads.Length], cd = new Line[quads.Length], da = new Line[quads.Length]; @@ -250,7 +241,7 @@ namespace Nerd_STF.Mathematics.Geometry return (ab, bc, cd, da); } - public static double[] ToDoubleArrayAll(params Quadrilateral[] quads) + public static double[] ToDoubleArrayAll(params Quadrilateral[] quads) { double[] vals = new double[quads.Length * 12]; for (int i = 0; i < quads.Length; i++) @@ -271,72 +262,71 @@ namespace Nerd_STF.Mathematics.Geometry } return vals; } - public static List ToDoubleListAll(params Quadrilateral[] quads) => new(ToDoubleArrayAll(quads)); + public static List ToDoubleListAll(params Quadrilateral[] quads) => new(ToDoubleArrayAll(quads)); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Quadrilateral)) return false; - return Equals((Quadrilateral)obj); - } - public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D; - public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider) - + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); - public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: " - + B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Quadrilateral)) return false; + return Equals((Quadrilateral)obj); + } + public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D; + public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); + public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: " + + B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); - public object Clone() => new Quadrilateral(A, B, C, D); + public object Clone() => new Quadrilateral(A, B, C, D); - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return A; - yield return B; - yield return C; - yield return D; - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return A; + yield return B; + yield return C; + yield return D; + } - public Vert[] ToArray() => new Vert[] { A, B, C, D }; - public List ToList() => new() { A, B, C, D }; + public Vert[] ToArray() => new Vert[] { A, B, C, D }; + public List ToList() => new() { A, B, C, D }; - public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z, - B.position.x, B.position.y, B.position.z, - C.position.x, C.position.y, C.position.z, - D.position.x, D.position.y, D.position.z }; - public List ToDoubleList() => new() { A.position.x, A.position.y, A.position.z, + public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z, B.position.x, B.position.y, B.position.z, C.position.x, C.position.y, C.position.z, D.position.x, D.position.y, D.position.z }; + public List ToDoubleList() => new() { A.position.x, A.position.y, A.position.z, + B.position.x, B.position.y, B.position.z, + C.position.x, C.position.y, C.position.z, + D.position.x, D.position.y, D.position.z }; - public Triangle[] Triangulate() => new Line(A, C).Length > new Line(B, D).Length ? - new Triangle[] { new(A, B, C), new(C, D, A) } : new Triangle[] { new(B, C, D), new(D, A, B) }; + public Triangle[] Triangulate() => new Line(A, C).Length > new Line(B, D).Length ? + new Triangle[] { new(A, B, C), new(C, D, A) } : new Triangle[] { new(B, C, D), new(D, A, B) }; - public static Quadrilateral operator +(Quadrilateral a, Quadrilateral b) => new(a.A + b.A, a.B + b.B, - a.C + b.C, a.D + b.D); - public static Quadrilateral operator +(Quadrilateral a, Vert b) => new(a.A + b, a.B + b, a.C + b, a.D + b); - public static Quadrilateral operator -(Quadrilateral q) => new(-q.A, -q.B, -q.C, -q.D); - public static Quadrilateral operator -(Quadrilateral a, Quadrilateral b) => new(a.A - b.A, a.B - b.B, - a.C - b.C, a.D - b.D); - public static Quadrilateral operator -(Quadrilateral a, Vert b) => new(a.A - b, a.B - b, a.C - b, a.D - b); - public static Quadrilateral operator *(Quadrilateral a, Quadrilateral b) => new(a.A * b.A, a.B * b.B, - a.C * b.C, a.D * b.D); - public static Quadrilateral operator *(Quadrilateral a, Vert b) => new(a.A * b, a.B * b, a.C * b, a.D * b); - public static Quadrilateral operator *(Quadrilateral a, double b) => new(a.A * b, a.B * b, a.C * b, a.D * b); - public static Quadrilateral operator /(Quadrilateral a, Quadrilateral b) => new(a.A / b.A, a.B / b.B, - a.C / b.C, a.D / b.D); - public static Quadrilateral operator /(Quadrilateral a, Vert b) => new(a.A / b, a.B / b, a.C / b, a.D / b); - public static Quadrilateral operator /(Quadrilateral a, double b) => new(a.A / b, a.B / b, a.C / b, a.D / b); - public static bool operator ==(Quadrilateral a, Quadrilateral b) => a.Equals(b); - public static bool operator !=(Quadrilateral a, Quadrilateral b) => !a.Equals(b); + public static Quadrilateral operator +(Quadrilateral a, Quadrilateral b) => new(a.A + b.A, a.B + b.B, + a.C + b.C, a.D + b.D); + public static Quadrilateral operator +(Quadrilateral a, Vert b) => new(a.A + b, a.B + b, a.C + b, a.D + b); + public static Quadrilateral operator -(Quadrilateral q) => new(-q.A, -q.B, -q.C, -q.D); + public static Quadrilateral operator -(Quadrilateral a, Quadrilateral b) => new(a.A - b.A, a.B - b.B, + a.C - b.C, a.D - b.D); + public static Quadrilateral operator -(Quadrilateral a, Vert b) => new(a.A - b, a.B - b, a.C - b, a.D - b); + public static Quadrilateral operator *(Quadrilateral a, Quadrilateral b) => new(a.A * b.A, a.B * b.B, + a.C * b.C, a.D * b.D); + public static Quadrilateral operator *(Quadrilateral a, Vert b) => new(a.A * b, a.B * b, a.C * b, a.D * b); + public static Quadrilateral operator *(Quadrilateral a, double b) => new(a.A * b, a.B * b, a.C * b, a.D * b); + public static Quadrilateral operator /(Quadrilateral a, Quadrilateral b) => new(a.A / b.A, a.B / b.B, + a.C / b.C, a.D / b.D); + public static Quadrilateral operator /(Quadrilateral a, Vert b) => new(a.A / b, a.B / b, a.C / b, a.D / b); + public static Quadrilateral operator /(Quadrilateral a, double b) => new(a.A / b, a.B / b, a.C / b, a.D / b); + public static bool operator ==(Quadrilateral a, Quadrilateral b) => a.Equals(b); + public static bool operator !=(Quadrilateral a, Quadrilateral b) => !a.Equals(b); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static implicit operator Quadrilateral(Fill fill) => new(fill); - public static explicit operator Quadrilateral(Polygon poly) => new(poly.Lines[0], poly.Lines[1], - poly.Lines[2], poly.Lines[3]); - } + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static implicit operator Quadrilateral(Fill fill) => new(fill); + public static explicit operator Quadrilateral(Polygon poly) => new(poly.Lines[0], poly.Lines[1], + poly.Lines[2], poly.Lines[3]); } diff --git a/Nerd_STF/Mathematics/Geometry/Sphere.cs b/Nerd_STF/Mathematics/Geometry/Sphere.cs index ba85ee3..23df755 100644 --- a/Nerd_STF/Mathematics/Geometry/Sphere.cs +++ b/Nerd_STF/Mathematics/Geometry/Sphere.cs @@ -1,126 +1,118 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Sphere : ICloneable, IClosest, IComparable, IComparable, IContainer, + IEquatable, IEquatable { - public struct Sphere : ICloneable, IClosest, IComparable, IComparable, IContainer, - IEquatable, IEquatable + public static Sphere Unit => new(Vert.Zero, 1); + + public Vert center; + public double radius; + + public double SurfaceArea => 4 * Mathf.Pi * radius * radius; + public double Volume => 4 / 3 * (Mathf.Pi * radius * radius * radius); + + public static Sphere FromDiameter(Vert a, Vert b) => new(Vert.Average(a, b), (a - b).Magnitude / 2); + public static Sphere FromRadius(Vert center, Vert radius) => new(center, (center - radius).Magnitude); + + public Sphere(Vert center, double radius) { - public static Sphere Unit => new(Vert.Zero, 1); - - public Vert center; - public double radius; - - public double SurfaceArea => 4 * Mathf.Pi * radius * radius; - public double Volume => 4 / 3 * (Mathf.Pi * radius * radius * radius); - - public static Sphere FromDiameter(Vert a, Vert b) => new(Vert.Average(a, b), (a - b).Magnitude / 2); - public static Sphere FromRadius(Vert center, Vert radius) => new(center, (center - radius).Magnitude); - - public Sphere(Vert center, double radius) - { - this.center = center; - this.radius = radius; - } - public Sphere(double cX, double cY, double radius) : this(new Vert(cX, cY), radius) { } - public Sphere(double cX, double cY, double cZ, double radius) : this(new Vert(cX, cY, cZ), radius) { } - public Sphere(Fill fill, double radius) : this(new Vert(fill), radius) { } - public Sphere(Fill fill) : this(new Vert(fill), fill(3)) { } - public Sphere(Fill fill, double radius) : this(new Vert(fill), radius) { } - public Sphere(Fill fill) : this(new Vert(fill), fill(3)) { } - public Sphere(Fill fill, double radius) : this(fill(0), radius) { } - public Sphere(Fill fillA, Fill fillB) : this(fillA(0), fillB(0)) { } - - public static Sphere Average(params Sphere[] vals) - { - (Vert[] centers, double[] radii) = SplitArray(vals); - return new(Vert.Average(centers), Mathf.Average(radii)); - } - public static Sphere Ceiling(Sphere val) => new(Vert.Ceiling(val.center), Mathf.Ceiling(val.radius)); - public static Sphere Clamp(Sphere val, Sphere min, Sphere max) => - new(Vert.Clamp(val.center, min.center, max.center), Mathf.Clamp(val.radius, min.radius, max.radius)); - public static Sphere Floor(Sphere val) => new(Vert.Floor(val.center), Mathf.Floor(val.radius)); - public static Sphere Lerp(Sphere a, Sphere b, double t, bool clamp = true) => - new(Vert.Lerp(a.center, b.center, t, clamp), Mathf.Lerp(a.radius, b.radius, t, clamp)); - public static Sphere Max(params Sphere[] vals) - { - (Vert[] centers, double[] radii) = SplitArray(vals); - return new(Vert.Max(centers), Mathf.Max(radii)); - } - public static Sphere Median(params Sphere[] vals) - { - (Vert[] centers, double[] radii) = SplitArray(vals); - return new(Vert.Median(centers), Mathf.Median(radii)); - } - public static Sphere Min(params Sphere[] vals) - { - (Vert[] centers, double[] radii) = SplitArray(vals); - return new(Vert.Min(centers), Mathf.Min(radii)); - } - - public static (Vert[] centers, double[] radii) SplitArray(params Sphere[] spheres) - { - Vert[] centers = new Vert[spheres.Length]; - double[] radii = new double[spheres.Length]; - for (int i = 0; i < spheres.Length; i++) - { - centers[i] = spheres[i].center; - radii[i] = spheres[i].radius; - } - return (centers, radii); - } - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null) return false; - Type type = obj.GetType(); - if (type == typeof(Sphere)) return Equals((Sphere)obj); - if (type == typeof(double)) return Equals((double)obj); - return false; - } - public bool Equals(double other) => Volume == other; - public bool Equals(Sphere other) => center == other.center && radius == other.radius; - public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => "Center: " + center.ToString(provider) - + " Radius: " + radius.ToString(provider); - public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider) - + " Radius: " + radius.ToString(provider); - - public object Clone() => new Sphere(center, radius); - - public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume); - public int CompareTo(double volume) => Volume.CompareTo(volume); - - public bool Contains(Vert vert) => (center - vert).Magnitude <= radius; - - public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + vert; - - public static Sphere operator +(Sphere a, Sphere b) => new(a.center + b.center, a.radius + b.radius); - public static Sphere operator +(Sphere a, Vert b) => new(a.center + b, a.radius); - public static Sphere operator +(Sphere a, double b) => new(a.center, a.radius + b); - public static Sphere operator -(Sphere a, Sphere b) => new(a.center + b.center, a.radius + b.radius); - public static Sphere operator -(Sphere a, Vert b) => new(a.center + b, a.radius); - public static Sphere operator -(Sphere a, double b) => new(a.center, a.radius + b); - public static Sphere operator *(Sphere a, Sphere b) => new(a.center * b.center, a.radius * b.radius); - public static Sphere operator *(Sphere a, double b) => new(a.center * b, a.radius * b); - public static Sphere operator /(Sphere a, Sphere b) => new(a.center * b.center, a.radius * b.radius); - public static Sphere operator /(Sphere a, double b) => new(a.center * b, a.radius * b); - public static bool operator ==(Sphere a, Sphere b) => a.Equals(b); - public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b); - public static bool operator ==(Sphere a, double b) => a.Equals(b); - public static bool operator !=(Sphere a, double b) => !a.Equals(b); - public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0; - public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0; - public static bool operator >(Sphere a, double b) => a.CompareTo(b) > 0; - public static bool operator <(Sphere a, double b) => a.CompareTo(b) < 0; - public static bool operator >=(Sphere a, Sphere b) => a > b || a == b; - public static bool operator <=(Sphere a, Sphere b) => a < b || a == b; - public static bool operator >=(Sphere a, double b) => a > b || a == b; - public static bool operator <=(Sphere a, double b) => a < b || a == b; + this.center = center; + this.radius = radius; } + public Sphere(double cX, double cY, double radius) : this(new Vert(cX, cY), radius) { } + public Sphere(double cX, double cY, double cZ, double radius) : this(new Vert(cX, cY, cZ), radius) { } + public Sphere(Fill fill, double radius) : this(new Vert(fill), radius) { } + public Sphere(Fill fill) : this(new Vert(fill), fill(3)) { } + public Sphere(Fill fill, double radius) : this(new Vert(fill), radius) { } + public Sphere(Fill fill) : this(new Vert(fill), fill(3)) { } + public Sphere(Fill fill, double radius) : this(fill(0), radius) { } + public Sphere(Fill fillA, Fill fillB) : this(fillA(0), fillB(0)) { } + + public static Sphere Average(params Sphere[] vals) + { + (Vert[] centers, double[] radii) = SplitArray(vals); + return new(Vert.Average(centers), Mathf.Average(radii)); + } + public static Sphere Ceiling(Sphere val) => new(Vert.Ceiling(val.center), Mathf.Ceiling(val.radius)); + public static Sphere Clamp(Sphere val, Sphere min, Sphere max) => + new(Vert.Clamp(val.center, min.center, max.center), Mathf.Clamp(val.radius, min.radius, max.radius)); + public static Sphere Floor(Sphere val) => new(Vert.Floor(val.center), Mathf.Floor(val.radius)); + public static Sphere Lerp(Sphere a, Sphere b, double t, bool clamp = true) => + new(Vert.Lerp(a.center, b.center, t, clamp), Mathf.Lerp(a.radius, b.radius, t, clamp)); + public static Sphere Max(params Sphere[] vals) + { + (Vert[] centers, double[] radii) = SplitArray(vals); + return new(Vert.Max(centers), Mathf.Max(radii)); + } + public static Sphere Median(params Sphere[] vals) + { + (Vert[] centers, double[] radii) = SplitArray(vals); + return new(Vert.Median(centers), Mathf.Median(radii)); + } + public static Sphere Min(params Sphere[] vals) + { + (Vert[] centers, double[] radii) = SplitArray(vals); + return new(Vert.Min(centers), Mathf.Min(radii)); + } + + public static (Vert[] centers, double[] radii) SplitArray(params Sphere[] spheres) + { + Vert[] centers = new Vert[spheres.Length]; + double[] radii = new double[spheres.Length]; + for (int i = 0; i < spheres.Length; i++) + { + centers[i] = spheres[i].center; + radii[i] = spheres[i].radius; + } + return (centers, radii); + } + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null) return false; + Type type = obj.GetType(); + if (type == typeof(Sphere)) return Equals((Sphere)obj); + if (type == typeof(double)) return Equals((double)obj); + return false; + } + public bool Equals(double other) => Volume == other; + public bool Equals(Sphere other) => center == other.center && radius == other.radius; + public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => "Center: " + center.ToString(provider) + + " Radius: " + radius.ToString(provider); + public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider) + + " Radius: " + radius.ToString(provider); + + public object Clone() => new Sphere(center, radius); + + public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume); + public int CompareTo(double volume) => Volume.CompareTo(volume); + + public bool Contains(Vert vert) => (center - vert).Magnitude <= radius; + + public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + vert; + + public static Sphere operator +(Sphere a, Sphere b) => new(a.center + b.center, a.radius + b.radius); + public static Sphere operator +(Sphere a, Vert b) => new(a.center + b, a.radius); + public static Sphere operator +(Sphere a, double b) => new(a.center, a.radius + b); + public static Sphere operator -(Sphere a, Sphere b) => new(a.center + b.center, a.radius + b.radius); + public static Sphere operator -(Sphere a, Vert b) => new(a.center + b, a.radius); + public static Sphere operator -(Sphere a, double b) => new(a.center, a.radius + b); + public static Sphere operator *(Sphere a, Sphere b) => new(a.center * b.center, a.radius * b.radius); + public static Sphere operator *(Sphere a, double b) => new(a.center * b, a.radius * b); + public static Sphere operator /(Sphere a, Sphere b) => new(a.center * b.center, a.radius * b.radius); + public static Sphere operator /(Sphere a, double b) => new(a.center * b, a.radius * b); + public static bool operator ==(Sphere a, Sphere b) => a.Equals(b); + public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b); + public static bool operator ==(Sphere a, double b) => a.Equals(b); + public static bool operator !=(Sphere a, double b) => !a.Equals(b); + public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0; + public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0; + public static bool operator >(Sphere a, double b) => a.CompareTo(b) > 0; + public static bool operator <(Sphere a, double b) => a.CompareTo(b) < 0; + public static bool operator >=(Sphere a, Sphere b) => a > b || a == b; + public static bool operator <=(Sphere a, Sphere b) => a < b || a == b; + public static bool operator >=(Sphere a, double b) => a > b || a == b; + public static bool operator <=(Sphere a, double b) => a < b || a == b; } diff --git a/Nerd_STF/Mathematics/Geometry/Triangle.cs b/Nerd_STF/Mathematics/Geometry/Triangle.cs index b1fcc62..03c3a44 100644 --- a/Nerd_STF/Mathematics/Geometry/Triangle.cs +++ b/Nerd_STF/Mathematics/Geometry/Triangle.cs @@ -1,12 +1,8 @@ -using Nerd_STF.Exceptions; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Triangle : ICloneable, IEquatable, IGroup { - public struct Triangle : ICloneable, IEquatable, IGroup - { - public Vert A + public Vert A { get => p_a; set @@ -16,7 +12,7 @@ namespace Nerd_STF.Mathematics.Geometry p_ca.b = value; } } - public Vert B + public Vert B { get => p_b; set @@ -26,7 +22,7 @@ namespace Nerd_STF.Mathematics.Geometry p_bc.a = value; } } - public Vert C + public Vert C { get => p_c; set @@ -36,7 +32,7 @@ namespace Nerd_STF.Mathematics.Geometry p_ca.a = value; } } - public Line AB + public Line AB { get => p_ab; set @@ -48,7 +44,7 @@ namespace Nerd_STF.Mathematics.Geometry p_ca.b = value.a; } } - public Line BC + public Line BC { get => p_bc; set @@ -60,7 +56,7 @@ namespace Nerd_STF.Mathematics.Geometry p_ab.b = value.a; } } - public Line CA + public Line CA { get => p_ca; set @@ -73,208 +69,202 @@ namespace Nerd_STF.Mathematics.Geometry } } - private Vert p_a, p_b, p_c; - private Line p_ab, p_bc, p_ca; + private Vert p_a, p_b, p_c; + private Line p_ab, p_bc, p_ca; - public double Area => Mathf.Absolute((A.position.x * B.position.y) + (B.position.x * C.position.y) + (C.position.x * A.position.y) - - ((B.position.x * A.position.y) + (C.position.x * B.position.y) + (A.position.x * C.position.y))) * 0.5; - public double Perimeter => AB.Length + BC.Length + CA.Length; + public double Area => Mathf.Absolute((A.position.x * B.position.y) + (B.position.x * C.position.y) + (C.position.x * A.position.y) - + ((B.position.x * A.position.y) + (C.position.x * B.position.y) + (A.position.x * C.position.y))) * 0.5; + public double Perimeter => AB.Length + BC.Length + CA.Length; - public Triangle(Vert a, Vert b, Vert c) + public Triangle(Vert a, Vert b, Vert c) + { + p_a = a; + p_b = b; + p_c = c; + p_ab = new(a, b); + p_bc = new(b, c); + p_ca = new(c, a); + } + public Triangle(Line ab, Line bc, Line ca) + { + if (ab.a != ca.b || ab.b != bc.a || bc.b != ca.a) + throw new DisconnectedLinesException(ab, bc, ca); + + p_a = ab.a; + p_b = bc.a; + p_c = ca.a; + p_ab = ab; + p_bc = bc; + p_ca = ca; + } + public Triangle(double x1, double y1, double x2, double y2, double x3, double y3) + : this(new Vert(x1, y1), new Vert(x2, y2), new Vert(x3, y3)) { } + public Triangle(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, + double z3) : this(new Vert(x1, y1, z1), new Vert(x2, y2, z2), new Vert(x3, y3, z3)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), + fill(7), fill(8)) { } + public Triangle(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), + fill(7), fill(8)) { } + + public Vert this[int index] + { + get => index switch { - p_a = a; - p_b = b; - p_c = c; - p_ab = new(a, b); - p_bc = new(b, c); - p_ca = new(c, a); - } - public Triangle(Line ab, Line bc, Line ca) + 0 => A, + 1 => B, + 2 => C, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set { - if (ab.a != ca.b || ab.b != bc.a || bc.b != ca.a) - throw new DisconnectedLinesException(ab, bc, ca); - - p_a = ab.a; - p_b = bc.a; - p_c = ca.a; - p_ab = ab; - p_bc = bc; - p_ca = ca; - } - public Triangle(double x1, double y1, double x2, double y2, double x3, double y3) - : this(new Vert(x1, y1), new Vert(x2, y2), new Vert(x3, y3)) { } - public Triangle(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, - double z3) : this(new Vert(x1, y1, z1), new Vert(x2, y2, z2), new Vert(x3, y3, z3)) { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2)) { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), - fill(7), fill(8)) - { } - public Triangle(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), - fill(7), fill(8)) - { } - - public Vert this[int index] - { - get => index switch + switch (index) { - 0 => A, - 1 => B, - 2 => C, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - A = value; - break; + case 0: + A = value; + break; - case 1: - B = value; - break; + case 1: + B = value; + break; - case 2: - C = value; - break; + case 2: + C = value; + break; - default: throw new IndexOutOfRangeException(nameof(index)); - } + default: throw new IndexOutOfRangeException(nameof(index)); } } + } - public static Triangle Absolute(Triangle val) => - new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C)); - public static Triangle Average(params Triangle[] vals) + public static Triangle Absolute(Triangle val) => + new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C)); + public static Triangle Average(params Triangle[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); + return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs)); + } + public static Triangle Ceiling(Triangle val) => + new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C)); + public static Triangle Clamp(Triangle val, Triangle min, Triangle max) => + new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C)); + public static Triangle Floor(Triangle val) => + new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C)); + public static Triangle Lerp(Triangle a, Triangle b, double t, bool clamp = true) => + new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp)); + public static Triangle Max(params Triangle[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); + return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs)); + } + public static Triangle Median(params Triangle[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); + return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs)); + } + public static Triangle Min(params Triangle[] vals) + { + (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); + return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs)); + } + + public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris) + { + Vert[] a = new Vert[tris.Length], b = new Vert[tris.Length], c = new Vert[tris.Length]; + for (int i = 0; i < tris.Length; i++) { - (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); - return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs)); + a[i] = tris[i].A; + b[i] = tris[i].B; + c[i] = tris[i].C; } - public static Triangle Ceiling(Triangle val) => - new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C)); - public static Triangle Clamp(Triangle val, Triangle min, Triangle max) => - new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C)); - public static Triangle Floor(Triangle val) => - new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C)); - public static Triangle Lerp(Triangle a, Triangle b, double t, bool clamp = true) => - new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp)); - public static Triangle Max(params Triangle[] vals) + return (a, b, c); + } + public static (Line[] ABs, Line[] BCs, Line[] CAs) SplitLineArray(params Triangle[] tris) + { + Line[] ab = new Line[tris.Length], bc = new Line[tris.Length], ca = new Line[tris.Length]; + for (int i = 0; i < tris.Length; i++) { - (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); - return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs)); + ab[i] = tris[i].AB; + bc[i] = tris[i].BC; + ca[i] = tris[i].CA; } - public static Triangle Median(params Triangle[] vals) + return (ab, bc, ca); + } + + public static double[] ToDoubleArrayAll(params Triangle[] tris) + { + double[] vals = new double[tris.Length * 9]; + for (int i = 0; i < tris.Length; i++) { - (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); - return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs)); - } - public static Triangle Min(params Triangle[] vals) - { - (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); - return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs)); + int pos = i * 9; + vals[pos + 0] = tris[i].A.position.x; + vals[pos + 1] = tris[i].A.position.y; + vals[pos + 2] = tris[i].A.position.z; + vals[pos + 3] = tris[i].B.position.x; + vals[pos + 4] = tris[i].B.position.y; + vals[pos + 5] = tris[i].B.position.z; + vals[pos + 6] = tris[i].C.position.x; + vals[pos + 7] = tris[i].C.position.y; + vals[pos + 8] = tris[i].C.position.z; } + return vals; + } + public static List ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris)); - public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris) - { - Vert[] a = new Vert[tris.Length], b = new Vert[tris.Length], c = new Vert[tris.Length]; - for (int i = 0; i < tris.Length; i++) - { - a[i] = tris[i].A; - b[i] = tris[i].B; - c[i] = tris[i].C; - } + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Triangle)) return false; + return Equals((Triangle)obj); + } + public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C; + public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); + public string ToString(IFormatProvider provider) => + "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); - return (a, b, c); - } - public static (Line[] ABs, Line[] BCs, Line[] CAs) SplitLineArray(params Triangle[] tris) - { - Line[] ab = new Line[tris.Length], bc = new Line[tris.Length], ca = new Line[tris.Length]; - for (int i = 0; i < tris.Length; i++) - { - ab[i] = tris[i].AB; - bc[i] = tris[i].BC; - ca[i] = tris[i].CA; - } + public object Clone() => new Triangle(A, B, C); - return (ab, bc, ca); - } + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return A; + yield return B; + yield return C; + } - public static double[] ToDoubleArrayAll(params Triangle[] tris) - { - double[] vals = new double[tris.Length * 9]; - for (int i = 0; i < tris.Length; i++) - { - int pos = i * 9; - vals[pos + 0] = tris[i].A.position.x; - vals[pos + 1] = tris[i].A.position.y; - vals[pos + 2] = tris[i].A.position.z; - vals[pos + 3] = tris[i].B.position.x; - vals[pos + 4] = tris[i].B.position.y; - vals[pos + 5] = tris[i].B.position.z; - vals[pos + 6] = tris[i].C.position.x; - vals[pos + 7] = tris[i].C.position.y; - vals[pos + 8] = tris[i].C.position.z; - } - return vals; - } - public static List ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris)); + public Vert[] ToArray() => new Vert[] { A, B, C }; + public List ToList() => new() { A, B, C }; - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Triangle)) return false; - return Equals((Triangle)obj); - } - public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C; - public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); - public string ToString(IFormatProvider provider) => - "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); - - public object Clone() => new Triangle(A, B, C); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return A; - yield return B; - yield return C; - } - - public Vert[] ToArray() => new Vert[] { A, B, C }; - public List ToList() => new() { A, B, C }; - - public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z, - B.position.x, B.position.y, B.position.z, - C.position.x, C.position.y, C.position.z }; - public List ToDoubleList() => new() { A.position.x, A.position.y, A.position.z, + public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z, B.position.x, B.position.y, B.position.z, C.position.x, C.position.y, C.position.z }; + public List ToDoubleList() => new() { A.position.x, A.position.y, A.position.z, + B.position.x, B.position.y, B.position.z, + C.position.x, C.position.y, C.position.z }; + public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C); + public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b); + public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C); + public static Triangle operator -(Triangle a, Triangle b) => new(a.A - b.A, a.B - b.B, a.C - b.C); + public static Triangle operator -(Triangle a, Vert b) => new(a.A - b, a.B - b, a.C - b); + public static Triangle operator *(Triangle a, Triangle b) => new(a.A * b.A, a.B * b.B, a.C * b.C); + public static Triangle operator *(Triangle a, Vert b) => new(a.A * b, a.B * b, a.C * b); + public static Triangle operator *(Triangle a, double b) => new(a.A * b, a.B * b, a.C * b); + public static Triangle operator /(Triangle a, Triangle b) => new(a.A / b.A, a.B / b.B, a.C / b.C); + public static Triangle operator /(Triangle a, Vert b) => new(a.A / b, a.B / b, a.C / b); + public static Triangle operator /(Triangle a, double b) => new(a.A / b, a.B / b, a.C / b); + public static bool operator ==(Triangle a, Triangle b) => a.Equals(b); + public static bool operator !=(Triangle a, Triangle b) => !a.Equals(b); - public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C); - public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b); - public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C); - public static Triangle operator -(Triangle a, Triangle b) => new(a.A - b.A, a.B - b.B, a.C - b.C); - public static Triangle operator -(Triangle a, Vert b) => new(a.A - b, a.B - b, a.C - b); - public static Triangle operator *(Triangle a, Triangle b) => new(a.A * b.A, a.B * b.B, a.C * b.C); - public static Triangle operator *(Triangle a, Vert b) => new(a.A * b, a.B * b, a.C * b); - public static Triangle operator *(Triangle a, double b) => new(a.A * b, a.B * b, a.C * b); - public static Triangle operator /(Triangle a, Triangle b) => new(a.A / b.A, a.B / b.B, a.C / b.C); - public static Triangle operator /(Triangle a, Vert b) => new(a.A / b, a.B / b, a.C / b); - public static Triangle operator /(Triangle a, double b) => new(a.A / b, a.B / b, a.C / b); - public static bool operator ==(Triangle a, Triangle b) => a.Equals(b); - public static bool operator !=(Triangle a, Triangle b) => !a.Equals(b); - - public static implicit operator Triangle(Fill fill) => new(fill); - public static implicit operator Triangle(Fill fill) => new(fill); - public static implicit operator Triangle(Fill fill) => new(fill); - public static implicit operator Triangle(Fill fill) => new(fill); - public static implicit operator Triangle(Fill fill) => new(fill); - public static implicit operator Triangle(Fill fill) => new(fill); - public static explicit operator Triangle(Polygon poly) => new(poly.Lines[0], poly.Lines[1], poly.Lines[2]); - } + public static implicit operator Triangle(Fill fill) => new(fill); + public static implicit operator Triangle(Fill fill) => new(fill); + public static implicit operator Triangle(Fill fill) => new(fill); + public static implicit operator Triangle(Fill fill) => new(fill); + public static implicit operator Triangle(Fill fill) => new(fill); + public static implicit operator Triangle(Fill fill) => new(fill); + public static explicit operator Triangle(Polygon poly) => new(poly.Lines[0], poly.Lines[1], poly.Lines[2]); } diff --git a/Nerd_STF/Mathematics/Geometry/Vert.cs b/Nerd_STF/Mathematics/Geometry/Vert.cs index 8705c41..97d5545 100644 --- a/Nerd_STF/Mathematics/Geometry/Vert.cs +++ b/Nerd_STF/Mathematics/Geometry/Vert.cs @@ -1,102 +1,98 @@ -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics.Geometry; -namespace Nerd_STF.Mathematics.Geometry +public struct Vert : ICloneable, IEquatable, IGroup { - public struct Vert : ICloneable, IEquatable, IGroup + public static Vert Back => new(0, 0, -1); + public static Vert Down => new(0, -1, 0); + public static Vert Forward => new(0, 0, 1); + public static Vert Left => new(-1, 0, 0); + public static Vert Right => new(1, 0, 0); + public static Vert Up => new(0, 1, 0); + + public static Vert One => new(1, 1, 1); + public static Vert Zero => new(0, 0, 0); + + public double Magnitude => position.Magnitude; + public Vert Normalized => new(this / Magnitude); + + public Double3 position; + + public Vert(Double2 pos) : this(pos.x, pos.y, 0) { } + public Vert(Double3 pos) => position = pos; + public Vert(double x, double y) : this(new Double2(x, y)) { } + public Vert(double x, double y, double z) : this(new Double3(x, y, z)) { } + public Vert(Fill fill) : this(new Double3(fill)) { } + public Vert(Fill fill) : this(new Double3(fill)) { } + + public double this[int index] { - public static Vert Back => new(0, 0, -1); - public static Vert Down => new(0, -1, 0); - public static Vert Forward => new(0, 0, 1); - public static Vert Left => new(-1, 0, 0); - public static Vert Right => new(1, 0, 0); - public static Vert Up => new(0, 1, 0); - - public static Vert One => new(1, 1, 1); - public static Vert Zero => new(0, 0, 0); - - public double Magnitude => position.Magnitude; - public Vert Normalized => new(this / Magnitude); - - public Double3 position; - - public Vert(Double2 pos) : this(pos.x, pos.y, 0) { } - public Vert(Double3 pos) => position = pos; - public Vert(double x, double y) : this(new Double2(x, y)) { } - public Vert(double x, double y, double z) : this(new Double3(x, y, z)) { } - public Vert(Fill fill) : this(new Double3(fill)) { } - public Vert(Fill fill) : this(new Double3(fill)) { } - - public double this[int index] - { - get => position[index]; - set => position[index] = value; - } - - public static Vert Absolute(Vert val) => new(Double3.Absolute(val.position)); - public static Vert Average(params Vert[] vals) => Double3.Average(ToDouble3Array(vals)); - public static Vert Ceiling(Vert val) => new(Double3.Ceiling(val.position)); - public static Vert Clamp(Vert val, Vert min, Vert max) => - new(Double3.Clamp(val.position, min.position, max.position)); - public static Vert ClampMagnitude(Vert val, double minMag, double maxMag) => - new(Double3.ClampMagnitude(val.position, minMag, maxMag)); - public static Vert Cross(Vert a, Vert b, bool normalized = false) => - new(Double3.Cross(a.position, b.position, normalized)); - public static double Dot(Vert a, Vert b) => Double3.Dot(a.position, b.position); - public static double Dot(params Vert[] vals) => Double3.Dot(ToDouble3Array(vals)); - public static Vert Floor(Vert val) => new(Double3.Floor(val.position)); - public static Vert Lerp(Vert a, Vert b, double t, bool clamp = true) => - new(Double3.Lerp(a.position, b.position, t, clamp)); - public static Vert Median(params Vert[] vals) => - Double3.Median(ToDouble3Array(vals)); - public static Vert Max(params Vert[] vals) => - Double3.Max(ToDouble3Array(vals)); - public static Vert Min(params Vert[] vals) => - Double3.Min(ToDouble3Array(vals)); - public static Double3[] ToDouble3Array(params Vert[] vals) - { - Double3[] doubles = new Double3[vals.Length]; - for (int i = 0; i < vals.Length; i++) doubles[i] = vals[i].position; - return doubles; - } - public static List ToDouble3List(params Vert[] vals) => ToDouble3Array(vals).ToList(); - - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Vert)) return false; - return Equals((Vert)obj); - } - public bool Equals(Vert other) => position == other.position; - public override int GetHashCode() => position.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => position.ToString(provider); - public string ToString(IFormatProvider provider) => position.ToString(provider); - - public object Clone() => new Vert(position); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() => position.GetEnumerator(); - - public double[] ToArray() => position.ToArray(); - public List ToList() => position.ToList(); - - public static Vert operator +(Vert a, Vert b) => new(a.position + b.position); - public static Vert operator -(Vert d) => new(-d.position); - public static Vert operator -(Vert a, Vert b) => new(a.position - b.position); - public static Vert operator *(Vert a, Vert b) => new(a.position * b.position); - public static Vert operator *(Vert a, double b) => new(a.position * b); - public static Vert operator /(Vert a, Vert b) => new(a.position / b.position); - public static Vert operator /(Vert a, double b) => new(a.position / b); - public static bool operator ==(Vert a, Vert b) => a.Equals(b); - public static bool operator !=(Vert a, Vert b) => !a.Equals(b); - - public static implicit operator Vert(Double2 val) => new(val); - public static implicit operator Vert(Double3 val) => new(val); - public static explicit operator Vert(Double4 val) => new(val.XYZ); - public static implicit operator Vert(Int2 val) => new(val); - public static implicit operator Vert(Int3 val) => new(val); - public static explicit operator Vert(Int4 val) => new(val.XYZ); - public static implicit operator Vert(Fill fill) => new(fill); - public static implicit operator Vert(Fill fill) => new(fill); + get => position[index]; + set => position[index] = value; } + + public static Vert Absolute(Vert val) => new(Double3.Absolute(val.position)); + public static Vert Average(params Vert[] vals) => Double3.Average(ToDouble3Array(vals)); + public static Vert Ceiling(Vert val) => new(Double3.Ceiling(val.position)); + public static Vert Clamp(Vert val, Vert min, Vert max) => + new(Double3.Clamp(val.position, min.position, max.position)); + public static Vert ClampMagnitude(Vert val, double minMag, double maxMag) => + new(Double3.ClampMagnitude(val.position, minMag, maxMag)); + public static Vert Cross(Vert a, Vert b, bool normalized = false) => + new(Double3.Cross(a.position, b.position, normalized)); + public static double Dot(Vert a, Vert b) => Double3.Dot(a.position, b.position); + public static double Dot(params Vert[] vals) => Double3.Dot(ToDouble3Array(vals)); + public static Vert Floor(Vert val) => new(Double3.Floor(val.position)); + public static Vert Lerp(Vert a, Vert b, double t, bool clamp = true) => + new(Double3.Lerp(a.position, b.position, t, clamp)); + public static Vert Median(params Vert[] vals) => + Double3.Median(ToDouble3Array(vals)); + public static Vert Max(params Vert[] vals) => + Double3.Max(ToDouble3Array(vals)); + public static Vert Min(params Vert[] vals) => + Double3.Min(ToDouble3Array(vals)); + public static Double3[] ToDouble3Array(params Vert[] vals) + { + Double3[] doubles = new Double3[vals.Length]; + for (int i = 0; i < vals.Length; i++) doubles[i] = vals[i].position; + return doubles; + } + public static List ToDouble3List(params Vert[] vals) => ToDouble3Array(vals).ToList(); + + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Vert)) return false; + return Equals((Vert)obj); + } + public bool Equals(Vert other) => position == other.position; + public override int GetHashCode() => position.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => position.ToString(provider); + public string ToString(IFormatProvider provider) => position.ToString(provider); + + public object Clone() => new Vert(position); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() => position.GetEnumerator(); + + public double[] ToArray() => position.ToArray(); + public List ToList() => position.ToList(); + + public static Vert operator +(Vert a, Vert b) => new(a.position + b.position); + public static Vert operator -(Vert d) => new(-d.position); + public static Vert operator -(Vert a, Vert b) => new(a.position - b.position); + public static Vert operator *(Vert a, Vert b) => new(a.position * b.position); + public static Vert operator *(Vert a, double b) => new(a.position * b); + public static Vert operator /(Vert a, Vert b) => new(a.position / b.position); + public static Vert operator /(Vert a, double b) => new(a.position / b); + public static bool operator ==(Vert a, Vert b) => a.Equals(b); + public static bool operator !=(Vert a, Vert b) => !a.Equals(b); + + public static implicit operator Vert(Double2 val) => new(val); + public static implicit operator Vert(Double3 val) => new(val); + public static explicit operator Vert(Double4 val) => new(val.XYZ); + public static implicit operator Vert(Int2 val) => new(val); + public static implicit operator Vert(Int3 val) => new(val); + public static explicit operator Vert(Int4 val) => new(val.XYZ); + public static implicit operator Vert(Fill fill) => new(fill); + public static implicit operator Vert(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Int2.cs b/Nerd_STF/Mathematics/Int2.cs index 7d8f476..f65ebc2 100644 --- a/Nerd_STF/Mathematics/Int2.cs +++ b/Nerd_STF/Mathematics/Int2.cs @@ -1,183 +1,178 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Int2 : ICloneable, IComparable, IEquatable, IGroup { - public struct Int2 : ICloneable, IComparable, IEquatable, IGroup + public static Int2 Down => new(0, -1); + public static Int2 Left => new(-1, 0); + public static Int2 Right => new(1, 0); + public static Int2 Up => new(0, 1); + + public static Int2 One => new(1, 1); + public static Int2 Zero => new(0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y); + public Int2 Normalized => (Int2)((Double2)this / Magnitude); + + public int x, y; + + public Int2(int all) : this(all, all) { } + public Int2(int x, int y) { - public static Int2 Down => new(0, -1); - public static Int2 Left => new(-1, 0); - public static Int2 Right => new(1, 0); - public static Int2 Up => new(0, 1); - - public static Int2 One => new(1, 1); - public static Int2 Zero => new(0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y); - public Int2 Normalized => (Int2)((Double2)this / Magnitude); - - public int x, y; - - public Int2(int all) : this(all, all) { } - public Int2(int x, int y) - { - this.x = x; - this.y = y; - } - public Int2(Fill fill) : this(fill(0), fill(1)) { } - - public int this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Int2 Absolute(Int2 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); - public static Int2 Average(params Int2[] vals) => Sum(vals) / vals.Length; - public static Int2 Clamp(Int2 val, Int2 min, Int2 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y)); - public static Int2 ClampMagnitude(Int2 val, int minMag, int maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Int3 Cross(Int2 a, Int2 b, bool normalized = false) => - Int3.Cross(a, b, normalized); - public static Int2 Divide(Int2 num, params Int2[] vals) - { - foreach (Int2 d in vals) num /= d; - return num; - } - public static int Dot(Int2 a, Int2 b) => a.x * b.x + a.y * b.y; - public static int Dot(params Int2[] vals) - { - if (vals.Length < 1) return 0; - int x = 1, y = 1; - foreach (Int2 d in vals) - { - x *= d.x; - y *= d.y; - } - return x + y; - } - public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp)); - public static Int2 Median(params Int2[] vals) - { - int index = Mathf.Average(0, vals.Length - 1); - Int2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Int2 Max(params Int2[] vals) - { - if (vals.Length < 1) return Zero; - Int2 val = vals[0]; - foreach (Int2 d in vals) val = d > val ? d : val; - return val; - } - public static Int2 Min(params Int2[] vals) - { - if (vals.Length < 1) return Zero; - Int2 val = vals[0]; - foreach (Int2 d in vals) val = d < val ? d : val; - return val; - } - public static Int2 Multiply(params Int2[] vals) - { - if (vals.Length < 1) return Zero; - Int2 val = One; - foreach (Int2 d in vals) val *= d; - return val; - } - public static Int2 Subtract(Int2 num, params Int2[] vals) - { - foreach (Int2 d in vals) num -= d; - return num; - } - public static Int2 Sum(params Int2[] vals) - { - Int2 val = Zero; - foreach (Int2 d in vals) val += d; - return val; - } - - public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int2)) return false; - return Equals((Int2)obj); - } - public bool Equals(Int2 other) => x == other.x && y == other.y; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - - public object Clone() => new Int2(x, y); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - } - - public int[] ToArray() => new[] { x, y }; - public List ToList() => new() { x, y }; - - public static Int2 operator +(Int2 a, Int2 b) => new(a.x + b.x, a.y + b.y); - public static Int2 operator -(Int2 i) => new(-i.x, -i.y); - public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y); - public static Int2 operator *(Int2 a, Int2 b) => new(a.x * b.x, a.y * b.y); - public static Int2 operator *(Int2 a, int b) => new(a.x * b, a.y * b); - public static Int2 operator /(Int2 a, Int2 b) => new(a.x / b.x, a.y / b.y); - public static Int2 operator /(Int2 a, int b) => new(a.x / b, a.y / b); - public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y); - public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y); - public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y); - public static bool operator ==(Int2 a, Int2 b) => a.Equals(b); - public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b); - public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0; - public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0; - public static bool operator >=(Int2 a, Int2 b) => a == b || a > b; - public static bool operator <=(Int2 a, Int2 b) => a == b || a < b; - - public static explicit operator Int2(Double2 val) => new((int)val.x, (int)val.y); - public static explicit operator Int2(Double3 val) => new((int)val.x, (int)val.y); - public static explicit operator Int2(Double4 val) => new((int)val.x, (int)val.y); - public static explicit operator Int2(Int3 val) => new(val.x, val.y); - public static explicit operator Int2(Int4 val) => new(val.x, val.y); - public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y); - public static implicit operator Int2(Fill fill) => new(fill); + this.x = x; + this.y = y; } + public Int2(Fill fill) : this(fill(0), fill(1)) { } + + public int this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Int2 Absolute(Int2 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); + public static Int2 Average(params Int2[] vals) => Sum(vals) / vals.Length; + public static Int2 Clamp(Int2 val, Int2 min, Int2 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y)); + public static Int2 ClampMagnitude(Int2 val, int minMag, int maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Int3 Cross(Int2 a, Int2 b, bool normalized = false) => + Int3.Cross(a, b, normalized); + public static Int2 Divide(Int2 num, params Int2[] vals) + { + foreach (Int2 d in vals) num /= d; + return num; + } + public static int Dot(Int2 a, Int2 b) => a.x * b.x + a.y * b.y; + public static int Dot(params Int2[] vals) + { + if (vals.Length < 1) return 0; + int x = 1, y = 1; + foreach (Int2 d in vals) + { + x *= d.x; + y *= d.y; + } + return x + y; + } + public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp)); + public static Int2 Median(params Int2[] vals) + { + int index = Mathf.Average(0, vals.Length - 1); + Int2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Int2 Max(params Int2[] vals) + { + if (vals.Length < 1) return Zero; + Int2 val = vals[0]; + foreach (Int2 d in vals) val = d > val ? d : val; + return val; + } + public static Int2 Min(params Int2[] vals) + { + if (vals.Length < 1) return Zero; + Int2 val = vals[0]; + foreach (Int2 d in vals) val = d < val ? d : val; + return val; + } + public static Int2 Multiply(params Int2[] vals) + { + if (vals.Length < 1) return Zero; + Int2 val = One; + foreach (Int2 d in vals) val *= d; + return val; + } + public static Int2 Subtract(Int2 num, params Int2[] vals) + { + foreach (Int2 d in vals) num -= d; + return num; + } + public static Int2 Sum(params Int2[] vals) + { + Int2 val = Zero; + foreach (Int2 d in vals) val += d; + return val; + } + + public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Int2)) return false; + return Equals((Int2)obj); + } + public bool Equals(Int2 other) => x == other.x && y == other.y; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); + + public object Clone() => new Int2(x, y); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + } + + public int[] ToArray() => new[] { x, y }; + public List ToList() => new() { x, y }; + + public static Int2 operator +(Int2 a, Int2 b) => new(a.x + b.x, a.y + b.y); + public static Int2 operator -(Int2 i) => new(-i.x, -i.y); + public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y); + public static Int2 operator *(Int2 a, Int2 b) => new(a.x * b.x, a.y * b.y); + public static Int2 operator *(Int2 a, int b) => new(a.x * b, a.y * b); + public static Int2 operator /(Int2 a, Int2 b) => new(a.x / b.x, a.y / b.y); + public static Int2 operator /(Int2 a, int b) => new(a.x / b, a.y / b); + public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y); + public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y); + public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y); + public static bool operator ==(Int2 a, Int2 b) => a.Equals(b); + public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b); + public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0; + public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0; + public static bool operator >=(Int2 a, Int2 b) => a == b || a > b; + public static bool operator <=(Int2 a, Int2 b) => a == b || a < b; + + public static explicit operator Int2(Double2 val) => new((int)val.x, (int)val.y); + public static explicit operator Int2(Double3 val) => new((int)val.x, (int)val.y); + public static explicit operator Int2(Double4 val) => new((int)val.x, (int)val.y); + public static explicit operator Int2(Int3 val) => new(val.x, val.y); + public static explicit operator Int2(Int4 val) => new(val.x, val.y); + public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y); + public static implicit operator Int2(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Int3.cs b/Nerd_STF/Mathematics/Int3.cs index 1cd49ba..1641aa7 100644 --- a/Nerd_STF/Mathematics/Int3.cs +++ b/Nerd_STF/Mathematics/Int3.cs @@ -1,205 +1,197 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Int3 : ICloneable, IComparable, IEquatable, IGroup { - public struct Int3 : ICloneable, IComparable, IEquatable, IGroup + public static Int3 Back => new(0, 0, -1); + public static Int3 Down => new(0, -1, 0); + public static Int3 Forward => new(0, 0, 1); + public static Int3 Left => new(-1, 0, 0); + public static Int3 Right => new(1, 0, 0); + public static Int3 Up => new(0, 1, 0); + + public static Int3 One => new(1, 1, 1); + public static Int3 Zero => new(0, 0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z); + public Int3 Normalized => (Int3)((Double3)this / Magnitude); + + public Int2 XY => new(x, y); + public Int2 XZ => new(x, z); + public Int2 YZ => new(y, z); + + public int x, y, z; + + public Int3(int all) : this(all, all, all) { } + public Int3(int x, int y) : this(x, y, 0) { } + public Int3(int x, int y, int z) { - public static Int3 Back => new(0, 0, -1); - public static Int3 Down => new(0, -1, 0); - public static Int3 Forward => new(0, 0, 1); - public static Int3 Left => new(-1, 0, 0); - public static Int3 Right => new(1, 0, 0); - public static Int3 Up => new(0, 1, 0); - - public static Int3 One => new(1, 1, 1); - public static Int3 Zero => new(0, 0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z); - public Int3 Normalized => (Int3)((Double3)this / Magnitude); - - public Int2 XY => new(x, y); - public Int2 XZ => new(x, z); - public Int2 YZ => new(y, z); - - public int x, y, z; - - public Int3(int all) : this(all, all, all) { } - public Int3(int x, int y) : this(x, y, 0) { } - public Int3(int x, int y, int z) - { - this.x = x; - this.y = y; - this.z = z; - } - public Int3(Fill fill) : this(fill(0), fill(1), fill(2)) { } - - public int this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - 2 => z, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - case 2: - z = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Int3 Absolute(Int3 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); - public static Int3 Average(params Int3[] vals) => Sum(vals) / vals.Length; - public static Int3 Clamp(Int3 val, Int3 min, Int3 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y), - Mathf.Clamp(val.z, min.z, max.z)); - public static Int3 ClampMagnitude(Int3 val, int minMag, int maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Int3 Cross(Int3 a, Int3 b, bool normalized = false) - { - Int3 val = new(a.y * b.z - b.y * a.z, - b.x * a.z - a.x * b.z, - a.x * b.y - b.x * a.y); - return normalized ? val.Normalized : val; - } - public static Int3 Divide(Int3 num, params Int3[] vals) - { - foreach (Int3 d in vals) num /= d; - return num; - } - public static int Dot(Int3 a, Int3 b) => a.x * b.x + a.y * b.y + a.z * b.z; - public static int Dot(params Int3[] vals) - { - if (vals.Length < 1) return 0; - int x = 1, y = 1, z = 1; - foreach (Int3 d in vals) - { - x *= d.x; - y *= d.y; - z *= d.z; - } - return x + y + z; - } - public static Int3 Lerp(Int3 a, Int3 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp)); - public static Int3 Median(params Int3[] vals) - { - int index = Mathf.Average(0, vals.Length - 1); - Int3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Int3 Max(params Int3[] vals) - { - if (vals.Length < 1) return Zero; - Int3 val = vals[0]; - foreach (Int3 d in vals) val = d > val ? d : val; - return val; - } - public static Int3 Min(params Int3[] vals) - { - if (vals.Length < 1) return Zero; - Int3 val = vals[0]; - foreach (Int3 d in vals) val = d < val ? d : val; - return val; - } - public static Int3 Multiply(params Int3[] vals) - { - if (vals.Length < 1) return Zero; - Int3 val = One; - foreach (Int3 d in vals) val *= d; - return val; - } - public static Int3 Subtract(Int3 num, params Int3[] vals) - { - foreach (Int3 d in vals) num -= d; - return num; - } - public static Int3 Sum(params Int3[] vals) - { - Int3 val = Zero; - foreach (Int3 d in vals) val += d; - return val; - } - - public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int3)) return false; - return Equals((Int3)obj); - } - public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - - public object Clone() => new Int3(x, y, z); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - yield return z; - } - - public int[] ToArray() => new[] { x, y, z }; - public List ToList() => new() { x, y, z }; - - public static Int3 operator +(Int3 a, Int3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); - public static Int3 operator -(Int3 i) => new(-i.x, -i.y, -i.z); - public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); - public static Int3 operator *(Int3 a, Int3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z); - public static Int3 operator *(Int3 a, int b) => new(a.x * b, a.y * b, a.z * b); - public static Int3 operator /(Int3 a, Int3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z); - public static Int3 operator /(Int3 a, int b) => new(a.x / b, a.y / b, a.z / b); - public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z); - public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z); - public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z); - public static bool operator ==(Int3 a, Int3 b) => a.Equals(b); - public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b); - public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0; - public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0; - public static bool operator >=(Int3 a, Int3 b) => a == b || a > b; - public static bool operator <=(Int3 a, Int3 b) => a == b || a < b; - - public static explicit operator Int3(Double2 val) => new((int)val.x, (int)val.y, 0); - public static explicit operator Int3(Double3 val) => new((int)val.x, (int)val.y, (int)val.z); - public static explicit operator Int3(Double4 val) => new((int)val.x, (int)val.y, (int)val.z); - public static implicit operator Int3(Int2 val) => new(val.x, val.y, 0); - public static explicit operator Int3(Int4 val) => new(val.x, val.y, val.z); - public static explicit operator Int3(Vert val) => new((int)val.position.x, (int)val.position.y, - (int)val.position.z); - public static implicit operator Int3(Fill fill) => new(fill); + this.x = x; + this.y = y; + this.z = z; } + public Int3(Fill fill) : this(fill(0), fill(1), fill(2)) { } + + public int this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + 2 => z, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + case 2: + z = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Int3 Absolute(Int3 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); + public static Int3 Average(params Int3[] vals) => Sum(vals) / vals.Length; + public static Int3 Clamp(Int3 val, Int3 min, Int3 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y), + Mathf.Clamp(val.z, min.z, max.z)); + public static Int3 ClampMagnitude(Int3 val, int minMag, int maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Int3 Cross(Int3 a, Int3 b, bool normalized = false) + { + Int3 val = new(a.y * b.z - b.y * a.z, + b.x * a.z - a.x * b.z, + a.x * b.y - b.x * a.y); + return normalized ? val.Normalized : val; + } + public static Int3 Divide(Int3 num, params Int3[] vals) + { + foreach (Int3 d in vals) num /= d; + return num; + } + public static int Dot(Int3 a, Int3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + public static int Dot(params Int3[] vals) + { + if (vals.Length < 1) return 0; + int x = 1, y = 1, z = 1; + foreach (Int3 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + } + return x + y + z; + } + public static Int3 Lerp(Int3 a, Int3 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp)); + public static Int3 Median(params Int3[] vals) + { + int index = Mathf.Average(0, vals.Length - 1); + Int3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Int3 Max(params Int3[] vals) + { + if (vals.Length < 1) return Zero; + Int3 val = vals[0]; + foreach (Int3 d in vals) val = d > val ? d : val; + return val; + } + public static Int3 Min(params Int3[] vals) + { + if (vals.Length < 1) return Zero; + Int3 val = vals[0]; + foreach (Int3 d in vals) val = d < val ? d : val; + return val; + } + public static Int3 Multiply(params Int3[] vals) + { + if (vals.Length < 1) return Zero; + Int3 val = One; + foreach (Int3 d in vals) val *= d; + return val; + } + public static Int3 Subtract(Int3 num, params Int3[] vals) + { + foreach (Int3 d in vals) num -= d; + return num; + } + public static Int3 Sum(params Int3[] vals) + { + Int3 val = Zero; + foreach (Int3 d in vals) val += d; + return val; + } + public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Int3)) return false; + return Equals((Int3)obj); + } + public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); + public object Clone() => new Int3(x, y, z); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + } + + public int[] ToArray() => new[] { x, y, z }; + public List ToList() => new() { x, y, z }; + + public static Int3 operator +(Int3 a, Int3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); + public static Int3 operator -(Int3 i) => new(-i.x, -i.y, -i.z); + public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); + public static Int3 operator *(Int3 a, Int3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z); + public static Int3 operator *(Int3 a, int b) => new(a.x * b, a.y * b, a.z * b); + public static Int3 operator /(Int3 a, Int3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z); + public static Int3 operator /(Int3 a, int b) => new(a.x / b, a.y / b, a.z / b); + public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z); + public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z); + public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z); + public static bool operator ==(Int3 a, Int3 b) => a.Equals(b); + public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b); + public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0; + public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0; + public static bool operator >=(Int3 a, Int3 b) => a == b || a > b; + public static bool operator <=(Int3 a, Int3 b) => a == b || a < b; + + public static explicit operator Int3(Double2 val) => new((int)val.x, (int)val.y, 0); + public static explicit operator Int3(Double3 val) => new((int)val.x, (int)val.y, (int)val.z); + public static explicit operator Int3(Double4 val) => new((int)val.x, (int)val.y, (int)val.z); + public static implicit operator Int3(Int2 val) => new(val.x, val.y, 0); + public static explicit operator Int3(Int4 val) => new(val.x, val.y, val.z); + public static explicit operator Int3(Vert val) => new((int)val.position.x, (int)val.position.y, + (int)val.position.z); + public static implicit operator Int3(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Int4.cs b/Nerd_STF/Mathematics/Int4.cs index a2a4ad2..b694e9c 100644 --- a/Nerd_STF/Mathematics/Int4.cs +++ b/Nerd_STF/Mathematics/Int4.cs @@ -1,221 +1,216 @@ -using Nerd_STF.Mathematics.Geometry; -using System.Collections; -using System.Diagnostics.CodeAnalysis; +namespace Nerd_STF.Mathematics; -namespace Nerd_STF.Mathematics +public struct Int4 : ICloneable, IComparable, IEquatable, IGroup { - public struct Int4 : ICloneable, IComparable, IEquatable, IGroup + public static Int4 Back => new(0, 0, -1, 0); + public static Int4 Deep => new(0, 0, 0, -1); + public static Int4 Down => new(0, -1, 0, 0); + public static Int4 Far => new(0, 0, 0, 1); + public static Int4 Forward => new(0, 0, 1, 0); + public static Int4 Left => new(-1, 0, 0, 0); + public static Int4 Right => new(1, 0, 0, 0); + public static Int4 Up => new(0, 1, 0, 0); + + public static Int4 One => new(1, 1, 1, 1); + public static Int4 Zero => new(0, 0, 0, 0); + + public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); + public Int4 Normalized => (Int4)((Double4)this / Magnitude); + + public Int2 XY => new(x, y); + public Int2 XZ => new(x, z); + public Int2 XW => new(x, w); + public Int2 YW => new(y, w); + public Int2 YZ => new(y, z); + public Int2 ZW => new(z, w); + + public Int3 XYW => new(x, y, w); + public Int3 XYZ => new(x, y, z); + public Int3 YZW => new(y, z, w); + public Int3 XZW => new(x, z, w); + + public int x, y, z, w; + + public Int4(int all) : this(all, all, all, all) { } + public Int4(int x, int y) : this(x, y, 0, 0) { } + public Int4(int x, int y, int z) : this(x, y, z, 0) { } + public Int4(int x, int y, int z, int w) { - public static Int4 Back => new(0, 0, -1, 0); - public static Int4 Deep => new(0, 0, 0, -1); - public static Int4 Down => new(0, -1, 0, 0); - public static Int4 Far => new(0, 0, 0, 1); - public static Int4 Forward => new(0, 0, 1, 0); - public static Int4 Left => new(-1, 0, 0, 0); - public static Int4 Right => new(1, 0, 0, 0); - public static Int4 Up => new(0, 1, 0, 0); - - public static Int4 One => new(1, 1, 1, 1); - public static Int4 Zero => new(0, 0, 0, 0); - - public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); - public Int4 Normalized => (Int4)((Double4)this / Magnitude); - - public Int2 XY => new(x, y); - public Int2 XZ => new(x, z); - public Int2 XW => new(x, w); - public Int2 YW => new(y, w); - public Int2 YZ => new(y, z); - public Int2 ZW => new(z, w); - - public Int3 XYW => new(x, y, w); - public Int3 XYZ => new(x, y, z); - public Int3 YZW => new(y, z, w); - public Int3 XZW => new(x, z, w); - - public int x, y, z, w; - - public Int4(int all) : this(all, all, all, all) { } - public Int4(int x, int y) : this(x, y, 0, 0) { } - public Int4(int x, int y, int z) : this(x, y, z, 0) { } - public Int4(int x, int y, int z, int w) - { - this.x = x; - this.y = y; - this.z = z; - this.w = w; - } - public Int4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - - public int this[int index] - { - get => index switch - { - 0 => x, - 1 => y, - 2 => z, - 3 => w, - _ => throw new IndexOutOfRangeException(nameof(index)), - }; - set - { - switch (index) - { - case 0: - x = value; - break; - - case 1: - y = value; - break; - - case 2: - z = value; - break; - - case 3: - w = value; - break; - - default: throw new IndexOutOfRangeException(nameof(index)); - } - } - } - - public static Int4 Absolute(Int4 val) => - new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); - public static Int4 Average(params Int4[] vals) => Sum(vals) / vals.Length; - public static Int4 Clamp(Int4 val, Int4 min, Int4 max) => - new(Mathf.Clamp(val.x, min.x, max.x), - Mathf.Clamp(val.y, min.y, max.y), - Mathf.Clamp(val.z, min.z, max.z), - Mathf.Clamp(val.w, min.w, max.w)); - public static Int4 ClampMagnitude(Int4 val, int minMag, int maxMag) - { - if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), - nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); - double mag = val.Magnitude; - if (mag >= minMag && mag <= maxMag) return val; - val = val.Normalized; - if (mag < minMag) val *= minMag; - else if (mag > maxMag) val *= maxMag; - return val; - } - public static Int4 Divide(Int4 num, params Int4[] vals) - { - foreach (Int4 d in vals) num /= d; - return num; - } - public static int Dot(Int4 a, Int4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; - public static int Dot(params Int4[] vals) - { - if (vals.Length < 1) return 0; - int x = 1, y = 1, z = 1, w = 1; - foreach (Int4 d in vals) - { - x *= d.x; - y *= d.y; - z *= d.z; - w *= d.w; - } - return x + y + z; - } - public static Int4 Lerp(Int4 a, Int4 b, double t, bool clamp = true) => - new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp), - Mathf.Lerp(a.w, b.w, t, clamp)); - public static Int4 Median(params Int4[] vals) - { - int index = Mathf.Average(0, vals.Length - 1); - Int4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; - return Average(valA, valB); - } - public static Int4 Max(params Int4[] vals) - { - if (vals.Length < 1) return Zero; - Int4 val = vals[0]; - foreach (Int4 d in vals) val = d > val ? d : val; - return val; - } - public static Int4 Min(params Int4[] vals) - { - if (vals.Length < 1) return Zero; - Int4 val = vals[0]; - foreach (Int4 d in vals) val = d < val ? d : val; - return val; - } - public static Int4 Multiply(params Int4[] vals) - { - if (vals.Length < 1) return Zero; - Int4 val = One; - foreach (Int4 d in vals) val *= d; - return val; - } - public static Int4 Subtract(Int4 num, params Int4[] vals) - { - foreach (Int4 d in vals) num -= d; - return num; - } - public static Int4 Sum(params Int4[] vals) - { - Int4 val = Zero; - foreach (Int4 d in vals) val += d; - return val; - } - - public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int4)) return false; - return Equals((Int4)obj); - } - public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - - public object Clone() => new Int4(x, y, z, w); - - IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() - { - yield return x; - yield return y; - yield return z; - yield return w; - } - - public int[] ToArray() => new[] { x, y, z, w }; - public List ToList() => new() { x, y, z, w }; - - public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); - public static Int4 operator -(Int4 d) => new(-d.x, -d.y, -d.z, -d.w); - public static Int4 operator -(Int4 a, Int4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); - public static Int4 operator *(Int4 a, Int4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); - public static Int4 operator *(Int4 a, int b) => new(a.x * b, a.y * b, a.z * b, a.w * b); - public static Int4 operator /(Int4 a, Int4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); - public static Int4 operator /(Int4 a, int b) => new(a.x / b, a.y / b, a.z / b, a.w / b); - public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); - public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); - public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); - public static bool operator ==(Int4 a, Int4 b) => a.Equals(b); - public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b); - public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0; - public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0; - public static bool operator >=(Int4 a, Int4 b) => a == b || a > b; - public static bool operator <=(Int4 a, Int4 b) => a == b || a < b; - - public static explicit operator Int4(Double2 val) => new((int)val.x, (int)val.y, 0, 0); - public static explicit operator Int4(Double3 val) => new((int)val.x, (int)val.y, (int)val.z, 0); - public static explicit operator Int4(Double4 val) => new((int)val.x, (int)val.y, (int)val.z, (int)val.w); - public static implicit operator Int4(Int2 val) => new(val.x, val.y, 0, 0); - public static implicit operator Int4(Int3 val) => new(val.x, val.y, val.z, 0); - public static explicit operator Int4(Vert val) => new((int)val.position.x, (int)val.position.y, - (int)val.position.z, 0); - public static implicit operator Int4(Fill fill) => new(fill); + this.x = x; + this.y = y; + this.z = z; + this.w = w; } + public Int4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + + public int this[int index] + { + get => index switch + { + 0 => x, + 1 => y, + 2 => z, + 3 => w, + _ => throw new IndexOutOfRangeException(nameof(index)), + }; + set + { + switch (index) + { + case 0: + x = value; + break; + + case 1: + y = value; + break; + + case 2: + z = value; + break; + + case 3: + w = value; + break; + + default: throw new IndexOutOfRangeException(nameof(index)); + } + } + } + + public static Int4 Absolute(Int4 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); + public static Int4 Average(params Int4[] vals) => Sum(vals) / vals.Length; + public static Int4 Clamp(Int4 val, Int4 min, Int4 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y), + Mathf.Clamp(val.z, min.z, max.z), + Mathf.Clamp(val.w, min.w, max.w)); + public static Int4 ClampMagnitude(Int4 val, int minMag, int maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + double mag = val.Magnitude; + if (mag >= minMag && mag <= maxMag) return val; + val = val.Normalized; + if (mag < minMag) val *= minMag; + else if (mag > maxMag) val *= maxMag; + return val; + } + public static Int4 Divide(Int4 num, params Int4[] vals) + { + foreach (Int4 d in vals) num /= d; + return num; + } + public static int Dot(Int4 a, Int4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + public static int Dot(params Int4[] vals) + { + if (vals.Length < 1) return 0; + int x = 1, y = 1, z = 1, w = 1; + foreach (Int4 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + w *= d.w; + } + return x + y + z; + } + public static Int4 Lerp(Int4 a, Int4 b, double t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp), + Mathf.Lerp(a.w, b.w, t, clamp)); + public static Int4 Median(params Int4[] vals) + { + int index = Mathf.Average(0, vals.Length - 1); + Int4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Int4 Max(params Int4[] vals) + { + if (vals.Length < 1) return Zero; + Int4 val = vals[0]; + foreach (Int4 d in vals) val = d > val ? d : val; + return val; + } + public static Int4 Min(params Int4[] vals) + { + if (vals.Length < 1) return Zero; + Int4 val = vals[0]; + foreach (Int4 d in vals) val = d < val ? d : val; + return val; + } + public static Int4 Multiply(params Int4[] vals) + { + if (vals.Length < 1) return Zero; + Int4 val = One; + foreach (Int4 d in vals) val *= d; + return val; + } + public static Int4 Subtract(Int4 num, params Int4[] vals) + { + foreach (Int4 d in vals) num -= d; + return num; + } + public static Int4 Sum(params Int4[] vals) + { + Int4 val = Zero; + foreach (Int4 d in vals) val += d; + return val; + } + + public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Int4)) return false; + return Equals((Int4)obj); + } + public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w; + public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(string? provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) + + " W: " + w.ToString(provider); + public string ToString(IFormatProvider provider) => + "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) + + " W: " + w.ToString(provider); + + public object Clone() => new Int4(x, y, z, w); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + yield return w; + } + + public int[] ToArray() => new[] { x, y, z, w }; + public List ToList() => new() { x, y, z, w }; + + public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + public static Int4 operator -(Int4 d) => new(-d.x, -d.y, -d.z, -d.w); + public static Int4 operator -(Int4 a, Int4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + public static Int4 operator *(Int4 a, Int4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + public static Int4 operator *(Int4 a, int b) => new(a.x * b, a.y * b, a.z * b, a.w * b); + public static Int4 operator /(Int4 a, Int4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + public static Int4 operator /(Int4 a, int b) => new(a.x / b, a.y / b, a.z / b, a.w / b); + public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); + public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); + public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); + public static bool operator ==(Int4 a, Int4 b) => a.Equals(b); + public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b); + public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0; + public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0; + public static bool operator >=(Int4 a, Int4 b) => a == b || a > b; + public static bool operator <=(Int4 a, Int4 b) => a == b || a < b; + + public static explicit operator Int4(Double2 val) => new((int)val.x, (int)val.y, 0, 0); + public static explicit operator Int4(Double3 val) => new((int)val.x, (int)val.y, (int)val.z, 0); + public static explicit operator Int4(Double4 val) => new((int)val.x, (int)val.y, (int)val.z, (int)val.w); + public static implicit operator Int4(Int2 val) => new(val.x, val.y, 0, 0); + public static implicit operator Int4(Int3 val) => new(val.x, val.y, val.z, 0); + public static explicit operator Int4(Vert val) => new((int)val.position.x, (int)val.position.y, + (int)val.position.z, 0); + public static implicit operator Int4(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Mathf.cs b/Nerd_STF/Mathematics/Mathf.cs index 10118ad..29bbff2 100644 --- a/Nerd_STF/Mathematics/Mathf.cs +++ b/Nerd_STF/Mathematics/Mathf.cs @@ -1,253 +1,252 @@ -namespace Nerd_STF.Mathematics +namespace Nerd_STF.Mathematics; + +public static class Mathf { - public static class Mathf + public const double RadToDeg = 0.0174532925199; // Pi / 180 + public const double E = 2.71828182846; + public const double GoldenRatio = 1.61803398875; // (1 + Sqrt(5)) / 2 + public const double HalfPi = 1.57079632679; // Pi / 2 + public const double Pi = 3.14159265359; + public const double DegToRad = 57.2957795131; // 180 / Pi + public const double Tau = 6.28318530718; // 2 * Pi + + public static double Absolute(double val) => val < 0 ? -val : val; + public static int Absolute(int val) => val < 0 ? -val : val; + + public static double ArcCos(double value) => -ArcSin(value) + HalfPi; + + public static double ArcCot(double value) => ArcCos(value / Sqrt(1 + value * value)); + + public static double ArcCsc(double value) => ArcSin(1 / value); + + public static double ArcSec(double value) => ArcCos(1 / value); + + // Maybe one day I'll have a polynomial for this, but the RMSE for an order 10 polynomial is only 0.00876. + public static double ArcSin(double value) => Math.Asin(value); + + public static double ArcTan(double value) => ArcSin(value / Sqrt(1 + value * value)); + + public static double Average(Equation equ, double min, double max, double step = Calculus.DefaultStep) { - public const double RadToDeg = 0.0174532925199; // Pi / 180 - public const double E = 2.71828182846; - public const double GoldenRatio = 1.61803398875; // (1 + Sqrt(5)) / 2 - public const double HalfPi = 1.57079632679; // Pi / 2 - public const double Pi = 3.14159265359; - public const double DegToRad = 57.2957795131; // 180 / Pi - public const double Tau = 6.28318530718; // 2 * Pi - - public static double Absolute(double val) => val < 0 ? -val : val; - public static int Absolute(int val) => val < 0 ? -val : val; - - public static double ArcCos(double value) => -ArcSin(value) + HalfPi; - - public static double ArcCot(double value) => ArcCos(value / Sqrt(1 + value * value)); - - public static double ArcCsc(double value) => ArcSin(1 / value); - - public static double ArcSec(double value) => ArcCos(1 / value); - - // Maybe one day I'll have a polynomial for this, but the RMSE for an order 10 polynomial is only 0.00876. - public static double ArcSin(double value) => Math.Asin(value); - - public static double ArcTan(double value) => ArcSin(value / Sqrt(1 + value * value)); - - public static double Average(Equation equ, double min, double max, double step = Calculus.DefaultStep) - { - List vals = new(); - for (double x = min; x <= max; x += step) vals.Add(equ(x)); - return Average(vals.ToArray()); - } - public static double Average(params double[] vals) => Sum(vals) / vals.Length; - public static int Average(params int[] vals) => Sum(vals) / vals.Length; - - public static int Ceiling(double val) => (int)(val + (1 - (val % 1))); - - public static double Clamp(double val, double min, double max) - { - if (max < min) throw new ArgumentOutOfRangeException(nameof(max), - nameof(max) + " must be greater than or equal to " + nameof(min)); - val = val < min ? min : val; - val = val > max ? max : val; - return val; - } - public static int Clamp(int val, int min, int max) - { - if (max < min) throw new ArgumentOutOfRangeException(nameof(max), - nameof(max) + " must be greater than or equal to " + nameof(min)); - val = val < min ? min : val; - val = val > max ? max : val; - return val; - } - - public static double Cos(double radians) => Sin(radians + HalfPi); - - public static double Cot(double radians) => Cos(radians) / Sin(radians); - - public static double Csc(double radians) => 1 / Sin(radians); - - public static double Divide(double val, params double[] dividends) - { - foreach (double d in dividends) val /= d; - return val; - } - public static int Divide(int val, params int[] dividends) - { - foreach (int i in dividends) val /= i; - return val; - } - - public static int Factorial(int amount) - { - if (amount < 0) return 0; - int val = 1; - for (int i = 2; i <= amount; i++) val *= i; - return val; - } - - public static int Floor(double val) => (int)(val - (val % 1)); - - public static Dictionary GetValues(Equation equ, double min, double max, - double step = Calculus.DefaultStep) - { - Dictionary vals = new(); - for (double x = min; x <= max; x += step) vals.Add(x, equ(x)); - return vals; - } - - public static double Lerp(double a, double b, double t, bool clamp = true) - { - double v = a + t * (b - a); - if (clamp) v = Clamp(v, a, b); - return v; - } - public static int Lerp(int a, int b, double value, bool clamp = true) => Floor(Lerp(a, b, value, clamp)); - - public static Equation MakeEquation(Dictionary vals) => (x) => - { - double min = -1, max = -1; - foreach (KeyValuePair val in vals) - { - if (val.Key <= x) min = val.Key; - if (val.Key >= x) max = val.Key; - - if (min != -1 && max != -1) break; - } - double per = x % (max - min); - return Lerp(min, max, per); - }; - - public static double Max(Equation equ, double min, double max, double step = Calculus.DefaultStep) - { - double Y = equ(min); - for (double x = min; x <= max; x += step) - { - double val = equ(x); - Y = val > Y ? val : Y; - } - return Y; - } - public static double Max(params double[] vals) - { - if (vals.Length < 1) return 0; - double val = vals[0]; - foreach (double d in vals) val = d > val ? d : val; - return val; - } - public static int Max(params int[] vals) - { - if (vals.Length < 1) return 0; - int val = vals[0]; - foreach (int i in vals) val = i > val ? i : val; - return val; - } - - public static double Median(params double[] vals) - { - double index = Average(0, vals.Length - 1); - double valA = vals[Floor(index)], valB = vals[Ceiling(index)]; - return Average(valA, valB); - } - public static int Median(params int[] vals) => vals[Floor(Average(0, vals.Length - 1))]; - - public static double Min(Equation equ, double min, double max, double step = Calculus.DefaultStep) - { - double Y = equ(min); - for (double x = min; x <= max; x += step) - { - double val = equ(x); - Y = val < Y ? val : Y; - } - return Y; - } - public static double Min(params double[] vals) - { - if (vals.Length < 1) return 0; - double val = vals[0]; - foreach (double d in vals) val = d < val ? d : val; - return val; - } - public static int Min(params int[] vals) - { - if (vals.Length < 1) return 0; - int val = vals[0]; - foreach (int i in vals) val = i < val ? i : val; - return val; - } - - public static double Multiply(params double[] vals) - { - if (vals.Length < 1) return 0; - double val = 1; - foreach (double d in vals) val *= d; - return val; - } - public static int Multiply(params int[] vals) - { - if (vals.Length < 1) return 0; - int val = 1; - foreach (int i in vals) val *= i; - return val; - } - - public static double Power(double num, double pow) => Math.Pow(num, pow); - public static int Power(int num, int pow) - { - if (pow < 0) return 0; - int val = 1; - for (int i = 0; i < Absolute(pow); i++) val *= num; - return val; - } - - public static double Root(double value, double index) => Math.Exp(index * Math.Log(value)); - - public static double Round(double num) => num % 1 >= 0.5 ? Ceiling(num) : Floor(num); - public static double Round(double num, double nearest) => nearest * Round(num / nearest); - public static int RoundInt(double num) => (int)Round(num); - - public static double Sec(double radians) => 1 / Cos(radians); - - public static double Sin(double radians) - { - // Really close polynomial to sin(x) (when modded by 2pi). RMSE of 0.000003833 - const double a = 0.000013028, - b = 0.999677, - c = 0.00174164, - d = -0.170587, - e = 0.0046494, - f = 0.00508955, - g = 0.00140205, - h = -0.000577413, - i = 0.0000613134, - j = -0.00000216852; - double x = radians % Tau; - - return - a + (b * x) + (c * x * x) + (d * x * x * x) + (e * x * x * x * x) + (f * x * x * x * x * x) - + (g * x * x * x * x * x * x) + (h * x * x * x * x * x * x * x) + (i * x * x * x * x * x * x * x * x) - + (j * x * x * x * x * x * x * x * x * x); - } - - public static double Sqrt(double value) => Root(value, 2); - - public static double Subtract(double num, params double[] vals) - { - foreach (double d in vals) num -= d; - return num; - } - public static int Subtract(int num, params int[] vals) - { - foreach (int i in vals) num -= i; - return num; - } - - public static double Sum(params double[] vals) - { - double val = 0; - foreach (double d in vals) val += d; - return val; - } - public static int Sum(params int[] vals) - { - int val = 0; - foreach (int i in vals) val += i; - return val; - } - - public static double Tan(double radians) => Sin(radians) / Cos(radians); + List vals = new(); + for (double x = min; x <= max; x += step) vals.Add(equ(x)); + return Average(vals.ToArray()); } + public static double Average(params double[] vals) => Sum(vals) / vals.Length; + public static int Average(params int[] vals) => Sum(vals) / vals.Length; + + public static int Ceiling(double val) => (int)(val + (1 - (val % 1))); + + public static double Clamp(double val, double min, double max) + { + if (max < min) throw new ArgumentOutOfRangeException(nameof(max), + nameof(max) + " must be greater than or equal to " + nameof(min)); + val = val < min ? min : val; + val = val > max ? max : val; + return val; + } + public static int Clamp(int val, int min, int max) + { + if (max < min) throw new ArgumentOutOfRangeException(nameof(max), + nameof(max) + " must be greater than or equal to " + nameof(min)); + val = val < min ? min : val; + val = val > max ? max : val; + return val; + } + + public static double Cos(double radians) => Sin(radians + HalfPi); + + public static double Cot(double radians) => Cos(radians) / Sin(radians); + + public static double Csc(double radians) => 1 / Sin(radians); + + public static double Divide(double val, params double[] dividends) + { + foreach (double d in dividends) val /= d; + return val; + } + public static int Divide(int val, params int[] dividends) + { + foreach (int i in dividends) val /= i; + return val; + } + + public static int Factorial(int amount) + { + if (amount < 0) return 0; + int val = 1; + for (int i = 2; i <= amount; i++) val *= i; + return val; + } + + public static int Floor(double val) => (int)(val - (val % 1)); + + public static Dictionary GetValues(Equation equ, double min, double max, + double step = Calculus.DefaultStep) + { + Dictionary vals = new(); + for (double x = min; x <= max; x += step) vals.Add(x, equ(x)); + return vals; + } + + public static double Lerp(double a, double b, double t, bool clamp = true) + { + double v = a + t * (b - a); + if (clamp) v = Clamp(v, a, b); + return v; + } + public static int Lerp(int a, int b, double value, bool clamp = true) => Floor(Lerp(a, b, value, clamp)); + + public static Equation MakeEquation(Dictionary vals) => (x) => + { + double min = -1, max = -1; + foreach (KeyValuePair val in vals) + { + if (val.Key <= x) min = val.Key; + if (val.Key >= x) max = val.Key; + + if (min != -1 && max != -1) break; + } + double per = x % (max - min); + return Lerp(min, max, per); + }; + + public static double Max(Equation equ, double min, double max, double step = Calculus.DefaultStep) + { + double Y = equ(min); + for (double x = min; x <= max; x += step) + { + double val = equ(x); + Y = val > Y ? val : Y; + } + return Y; + } + public static double Max(params double[] vals) + { + if (vals.Length < 1) return 0; + double val = vals[0]; + foreach (double d in vals) val = d > val ? d : val; + return val; + } + public static int Max(params int[] vals) + { + if (vals.Length < 1) return 0; + int val = vals[0]; + foreach (int i in vals) val = i > val ? i : val; + return val; + } + + public static double Median(params double[] vals) + { + double index = Average(0, vals.Length - 1); + double valA = vals[Floor(index)], valB = vals[Ceiling(index)]; + return Average(valA, valB); + } + public static int Median(params int[] vals) => vals[Floor(Average(0, vals.Length - 1))]; + + public static double Min(Equation equ, double min, double max, double step = Calculus.DefaultStep) + { + double Y = equ(min); + for (double x = min; x <= max; x += step) + { + double val = equ(x); + Y = val < Y ? val : Y; + } + return Y; + } + public static double Min(params double[] vals) + { + if (vals.Length < 1) return 0; + double val = vals[0]; + foreach (double d in vals) val = d < val ? d : val; + return val; + } + public static int Min(params int[] vals) + { + if (vals.Length < 1) return 0; + int val = vals[0]; + foreach (int i in vals) val = i < val ? i : val; + return val; + } + + public static double Multiply(params double[] vals) + { + if (vals.Length < 1) return 0; + double val = 1; + foreach (double d in vals) val *= d; + return val; + } + public static int Multiply(params int[] vals) + { + if (vals.Length < 1) return 0; + int val = 1; + foreach (int i in vals) val *= i; + return val; + } + + public static double Power(double num, double pow) => Math.Pow(num, pow); + public static int Power(int num, int pow) + { + if (pow < 0) return 0; + int val = 1; + for (int i = 0; i < Absolute(pow); i++) val *= num; + return val; + } + + public static double Root(double value, double index) => Math.Exp(index * Math.Log(value)); + + public static double Round(double num) => num % 1 >= 0.5 ? Ceiling(num) : Floor(num); + public static double Round(double num, double nearest) => nearest * Round(num / nearest); + public static int RoundInt(double num) => (int)Round(num); + + public static double Sec(double radians) => 1 / Cos(radians); + + public static double Sin(double radians) + { + // Really close polynomial to sin(x) (when modded by 2pi). RMSE of 0.000003833 + const double a = 0.000013028, + b = 0.999677, + c = 0.00174164, + d = -0.170587, + e = 0.0046494, + f = 0.00508955, + g = 0.00140205, + h = -0.000577413, + i = 0.0000613134, + j = -0.00000216852; + double x = radians % Tau; + + return + a + (b * x) + (c * x * x) + (d * x * x * x) + (e * x * x * x * x) + (f * x * x * x * x * x) + + (g * x * x * x * x * x * x) + (h * x * x * x * x * x * x * x) + (i * x * x * x * x * x * x * x * x) + + (j * x * x * x * x * x * x * x * x * x); + } + + public static double Sqrt(double value) => Root(value, 2); + + public static double Subtract(double num, params double[] vals) + { + foreach (double d in vals) num -= d; + return num; + } + public static int Subtract(int num, params int[] vals) + { + foreach (int i in vals) num -= i; + return num; + } + + public static double Sum(params double[] vals) + { + double val = 0; + foreach (double d in vals) val += d; + return val; + } + public static int Sum(params int[] vals) + { + int val = 0; + foreach (int i in vals) val += i; + return val; + } + + public static double Tan(double radians) => Sin(radians) / Cos(radians); } diff --git a/Nerd_STF/Miscellaneous/GlobalUsings.cs b/Nerd_STF/Miscellaneous/GlobalUsings.cs index d25b3b7..520cd0b 100644 --- a/Nerd_STF/Miscellaneous/GlobalUsings.cs +++ b/Nerd_STF/Miscellaneous/GlobalUsings.cs @@ -1,6 +1,7 @@ global using System; global using System.Collections; global using System.Collections.Generic; +global using System.Diagnostics.CodeAnalysis; global using System.IO; global using System.Linq; global using System.Net.Http; diff --git a/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll b/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll index be99c01..acbe612 100644 Binary files a/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll and b/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll differ