From 6233ba65f9333547e2d2529dc09c2e44ea4c6259 Mon Sep 17 00:00:00 2001 From: That-One-Nerd Date: Mon, 2 May 2022 13:19:51 -0400 Subject: [PATCH] Version 2.1.2 --- Changelog.md | 16 +- .../Exceptions/DifferingVertCountException.cs | 1 + .../Exceptions/DisconnectedLinesException.cs | 3 +- Nerd_STF/Mathematics/Angle.cs | 26 +-- Nerd_STF/Mathematics/Calculus.cs | 24 +- Nerd_STF/Mathematics/Double2.cs | 181 --------------- Nerd_STF/Mathematics/Double3.cs | 202 ---------------- Nerd_STF/Mathematics/Double4.cs | 218 ------------------ Nerd_STF/Mathematics/Equation.cs | 2 +- Nerd_STF/Mathematics/Float2.cs | 181 +++++++++++++++ Nerd_STF/Mathematics/Float3.cs | 202 ++++++++++++++++ Nerd_STF/Mathematics/Float4.cs | 218 ++++++++++++++++++ Nerd_STF/Mathematics/Geometry/Box2D.cs | 66 +++--- Nerd_STF/Mathematics/Geometry/Box3D.cs | 62 ++--- Nerd_STF/Mathematics/Geometry/Line.cs | 34 +-- Nerd_STF/Mathematics/Geometry/Polygon.cs | 36 +-- .../Mathematics/Geometry/Quadrilateral.cs | 36 +-- Nerd_STF/Mathematics/Geometry/Sphere.cs | 66 +++--- Nerd_STF/Mathematics/Geometry/Triangle.cs | 37 +-- Nerd_STF/Mathematics/Geometry/Vert.cs | 74 +++--- Nerd_STF/Mathematics/Int2.cs | 14 +- Nerd_STF/Mathematics/Int3.cs | 14 +- Nerd_STF/Mathematics/Int4.cs | 14 +- Nerd_STF/Mathematics/Mathf.cs | 164 ++++++------- Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll | Bin 47616 -> 47104 bytes 25 files changed, 948 insertions(+), 943 deletions(-) delete mode 100644 Nerd_STF/Mathematics/Double2.cs delete mode 100644 Nerd_STF/Mathematics/Double3.cs delete mode 100644 Nerd_STF/Mathematics/Double4.cs create mode 100644 Nerd_STF/Mathematics/Float2.cs create mode 100644 Nerd_STF/Mathematics/Float3.cs create mode 100644 Nerd_STF/Mathematics/Float4.cs diff --git a/Changelog.md b/Changelog.md index d23e884..d2554b7 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,12 +1,14 @@ -# Nerd_STF v2.1.1 +# Nerd_STF v2.1.2 -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. +This update just replaces instances of `double` with `float` instead. + +I know, this isn't the update you wanted. More stuff coming soon. ``` * Nerd_STF - = Removed unused or unrequired usings in all files. - = Replaced all namespace declarations with file-scoped declarations. - * Miscellaneous - * GlobalUsings - + global using System.Diagnostics.CodeAnalysis + = Replace all instances of `double` with `float` + * Mathematics + = Renamed `Double2` to `Float2` + = Renamed `Double3` to `Float3` + = Renamed `Double4` to `Float4` ``` diff --git a/Nerd_STF/Exceptions/DifferingVertCountException.cs b/Nerd_STF/Exceptions/DifferingVertCountException.cs index dc37933..361d82b 100644 --- a/Nerd_STF/Exceptions/DifferingVertCountException.cs +++ b/Nerd_STF/Exceptions/DifferingVertCountException.cs @@ -24,5 +24,6 @@ public class DifferingVertCountException : Nerd_STFException 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 539dd4a..3c27050 100644 --- a/Nerd_STF/Exceptions/DisconnectedLinesException.cs +++ b/Nerd_STF/Exceptions/DisconnectedLinesException.cs @@ -18,11 +18,12 @@ public class DisconnectedLinesException : Nerd_STFException { ParamName = paramName; Lines = lines; - } + } public DisconnectedLinesException(string paramName, Line[] lines, Exception inner) : this(inner) { ParamName = paramName; Lines = lines; } + protected DisconnectedLinesException(SerializationInfo info, StreamingContext context) : base(info, context) { } } diff --git a/Nerd_STF/Mathematics/Angle.cs b/Nerd_STF/Mathematics/Angle.cs index 67bfa9a..5fa167e 100644 --- a/Nerd_STF/Mathematics/Angle.cs +++ b/Nerd_STF/Mathematics/Angle.cs @@ -8,17 +8,17 @@ public struct Angle : ICloneable, IComparable, IEquatable public static Angle Quarter => new(90); public static Angle Zero => new(0); - public double Degrees + public float Degrees { get => p_deg; set => p_deg = value; } - public double Gradians + public float Gradians { - get => p_deg * 1.11111111111; // Reciprocal of 9/10 as a constant (10/9) - set => p_deg = value * 0.9; + get => p_deg * 1.11111111111f; // Reciprocal of 9/10 as a constant (10/9) + set => p_deg = value * 0.9f; } - public double Radians + public float Radians { get => p_deg * Mathf.DegToRad; set => p_deg = value * Mathf.RadToDeg; @@ -26,14 +26,14 @@ public struct Angle : ICloneable, IComparable, IEquatable public Angle Bounded => new(p_deg % 360); - private double p_deg; + private float p_deg; - public Angle(double value, Type valueType = Type.Degrees) + public Angle(float value, Type valueType = Type.Degrees) { p_deg = valueType switch { Type.Degrees => value, - Type.Gradians => value * 0.9, + Type.Gradians => value * 0.9f, Type.Radians => value * Mathf.RadToDeg, _ => throw new ArgumentException("Unknown type.", nameof(valueType)), }; @@ -44,15 +44,15 @@ public struct Angle : ICloneable, IComparable, IEquatable 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) => + public static Angle Lerp(Angle a, Angle b, float 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) + public static float[] ToDoubles(Type outputType, params Angle[] vals) { - double[] res = new double[vals.Length]; + float[] res = new float[vals.Length]; for (int i = 0; i < vals.Length; i++) { res[i] = outputType switch @@ -97,9 +97,9 @@ public struct Angle : ICloneable, IComparable, IEquatable 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, float 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 Angle operator /(Angle a, float 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; diff --git a/Nerd_STF/Mathematics/Calculus.cs b/Nerd_STF/Mathematics/Calculus.cs index 227a6c9..a117c75 100644 --- a/Nerd_STF/Mathematics/Calculus.cs +++ b/Nerd_STF/Mathematics/Calculus.cs @@ -2,32 +2,32 @@ public static class Calculus { - public const double DefaultStep = 0.001; + public const float DefaultStep = 0.001f; - public static Equation GetDerivative(Equation equ, double min, double max, double step = DefaultStep) + public static Equation GetDerivative(Equation equ, float min, float max, float step = DefaultStep) { - Dictionary vals = new(); - for (double x = min; x <= max; x += step) + Dictionary vals = new(); + for (float x = min; x <= max; x += step) { - double val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step; + float val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step; vals.Add(x, change); } return Mathf.MakeEquation(vals); } - public static double GetDerivativeAtPoint(Equation equ, double x, double step = DefaultStep) => + public static float GetDerivativeAtPoint(Equation equ, float x, float step = DefaultStep) => (equ(x + DefaultStep) - equ(x)) / step; - public static double GetIntegral(Equation equ, double lowerBound, double upperBound, double step = DefaultStep) + public static float GetIntegral(Equation equ, float lowerBound, float upperBound, float step = DefaultStep) { - double val = 0; - for (double x = lowerBound; x <= upperBound; x += step) val += equ(x) * step; + float val = 0; + for (float 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) + public static float GradientDescent(Equation equ, float initial, float rate, float stepCount = 1000, + float step = DefaultStep) { - double val = initial; + float 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 deleted file mode 100644 index 050aeb5..0000000 --- a/Nerd_STF/Mathematics/Double2.cs +++ /dev/null @@ -1,181 +0,0 @@ -namespace Nerd_STF.Mathematics; - -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) - { - 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 deleted file mode 100644 index d49a0bb..0000000 --- a/Nerd_STF/Mathematics/Double3.cs +++ /dev/null @@ -1,202 +0,0 @@ -namespace Nerd_STF.Mathematics; - -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) - { - 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 deleted file mode 100644 index ca38c11..0000000 --- a/Nerd_STF/Mathematics/Double4.cs +++ /dev/null @@ -1,218 +0,0 @@ -namespace Nerd_STF.Mathematics; - -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) - { - 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 e6012ac..7557964 100644 --- a/Nerd_STF/Mathematics/Equation.cs +++ b/Nerd_STF/Mathematics/Equation.cs @@ -1,3 +1,3 @@ namespace Nerd_STF.Mathematics; -public delegate double Equation(double x); +public delegate float Equation(float x); diff --git a/Nerd_STF/Mathematics/Float2.cs b/Nerd_STF/Mathematics/Float2.cs new file mode 100644 index 0000000..1171fbd --- /dev/null +++ b/Nerd_STF/Mathematics/Float2.cs @@ -0,0 +1,181 @@ +namespace Nerd_STF.Mathematics; + +public struct Float2 : ICloneable, IComparable, IEquatable, IGroup +{ + public static Float2 Down => new(0, -1); + public static Float2 Left => new(-1, 0); + public static Float2 Right => new(1, 0); + public static Float2 Up => new(0, 1); + + public static Float2 One => new(1, 1); + public static Float2 Zero => new(0, 0); + + public float Magnitude => Mathf.Sqrt(x * x + y * y); + public Float2 Normalized => this / Magnitude; + + public float x, y; + + public Float2(float all) : this(all, all) { } + public Float2(float x, float y) + { + this.x = x; + this.y = y; + } + public Float2(Fill fill) : this(fill(0), fill(1)) { } + public Float2(Fill fill) : this(fill(0), fill(1)) { } + + public float 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 Float2 Absolute(Float2 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); + public static Float2 Average(params Float2[] vals) => Sum(vals) / vals.Length; + public static Float2 Ceiling(Float2 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y)); + public static Float2 Clamp(Float2 val, Float2 min, Float2 max) => + new(Mathf.Clamp(val.x, min.x, max.x), + Mathf.Clamp(val.y, min.y, max.y)); + public static Float2 ClampMagnitude(Float2 val, float minMag, float maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + float 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 Float3 Cross(Float2 a, Float2 b, bool normalized = false) => + Float3.Cross(a, b, normalized); + public static Float2 Divide(Float2 num, params Float2[] vals) + { + foreach (Float2 d in vals) num /= d; + return num; + } + public static float Dot(Float2 a, Float2 b) => a.x * b.x + a.y * b.y; + public static float Dot(params Float2[] vals) + { + if (vals.Length < 1) return 0; + float x = 1, y = 1; + foreach (Float2 d in vals) + { + x *= d.x; + y *= d.y; + } + return x + y; + } + public static Float2 Floor(Float2 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y)); + public static Float2 Lerp(Float2 a, Float2 b, float t, bool clamp = true) => + new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp)); + public static Float2 Median(params Float2[] vals) + { + float index = Mathf.Average(0, vals.Length - 1); + Float2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Float2 Max(params Float2[] vals) + { + if (vals.Length < 1) return Zero; + Float2 val = vals[0]; + foreach (Float2 d in vals) val = d > val ? d : val; + return val; + } + public static Float2 Min(params Float2[] vals) + { + if (vals.Length < 1) return Zero; + Float2 val = vals[0]; + foreach (Float2 d in vals) val = d < val ? d : val; + return val; + } + public static Float2 Multiply(params Float2[] vals) + { + if (vals.Length < 1) return Zero; + Float2 val = One; + foreach (Float2 d in vals) val *= d; + return val; + } + public static Float2 Subtract(Float2 num, params Float2[] vals) + { + foreach (Float2 d in vals) num -= d; + return num; + } + public static Float2 Sum(params Float2[] vals) + { + Float2 val = Zero; + foreach (Float2 d in vals) val += d; + return val; + } + + public int CompareTo(Float2 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Float2)) return false; + return Equals((Float2)obj); + } + public bool Equals(Float2 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 Float2(x, y); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + } + + public float[] ToArray() => new[] { x, y }; + public List ToList() => new() { x, y }; + + public static Float2 operator +(Float2 a, Float2 b) => new(a.x + b.x, a.y + b.y); + public static Float2 operator -(Float2 d) => new(-d.x, -d.y); + public static Float2 operator -(Float2 a, Float2 b) => new(a.x - b.x, a.y - b.y); + public static Float2 operator *(Float2 a, Float2 b) => new(a.x * b.x, a.y * b.y); + public static Float2 operator *(Float2 a, float b) => new(a.x * b, a.y * b); + public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y); + public static Float2 operator /(Float2 a, float b) => new(a.x / b, a.y / b); + public static bool operator ==(Float2 a, Float2 b) => a.Equals(b); + public static bool operator !=(Float2 a, Float2 b) => !a.Equals(b); + public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0; + public static bool operator <(Float2 a, Float2 b) => a.CompareTo(b) < 0; + public static bool operator >=(Float2 a, Float2 b) => a == b || a > b; + public static bool operator <=(Float2 a, Float2 b) => a == b || a < b; + + public static explicit operator Float2(Float3 val) => new(val.x, val.y); + public static explicit operator Float2(Float4 val) => new(val.x, val.y); + public static implicit operator Float2(Int2 val) => new(val.x, val.y); + public static explicit operator Float2(Int3 val) => new(val.x, val.y); + public static explicit operator Float2(Int4 val) => new(val.x, val.y); + public static explicit operator Float2(Vert val) => new(val.position.x, val.position.y); + public static implicit operator Float2(Fill fill) => new(fill); + public static implicit operator Float2(Fill fill) => new(fill); +} diff --git a/Nerd_STF/Mathematics/Float3.cs b/Nerd_STF/Mathematics/Float3.cs new file mode 100644 index 0000000..9e77b21 --- /dev/null +++ b/Nerd_STF/Mathematics/Float3.cs @@ -0,0 +1,202 @@ +namespace Nerd_STF.Mathematics; + +public struct Float3 : ICloneable, IComparable, IEquatable, IGroup +{ + public static Float3 Back => new(0, 0, -1); + public static Float3 Down => new(0, -1, 0); + public static Float3 Forward => new(0, 0, 1); + public static Float3 Left => new(-1, 0, 0); + public static Float3 Right => new(1, 0, 0); + public static Float3 Up => new(0, 1, 0); + + public static Float3 One => new(1, 1, 1); + public static Float3 Zero => new(0, 0, 0); + + public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z); + public Float3 Normalized => this / Magnitude; + + public Float2 XY => new(x, y); + public Float2 XZ => new(x, z); + public Float2 YZ => new(y, z); + + public float x, y, z; + + public Float3(float all) : this(all, all, all) { } + public Float3(float x, float y) : this(x, y, 0) { } + public Float3(float x, float y, float z) + { + this.x = x; + this.y = y; + this.z = z; + } + public Float3(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public Float3(Fill fill) : this(fill(0), fill(1), fill(2)) { } + + public float 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 Float3 Absolute(Float3 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); + public static Float3 Average(params Float3[] vals) => Sum(vals) / vals.Length; + public static Float3 Ceiling(Float3 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z)); + public static Float3 Clamp(Float3 val, Float3 min, Float3 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 Float3 ClampMagnitude(Float3 val, float minMag, float maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + float 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 Float3 Cross(Float3 a, Float3 b, bool normalized = false) + { + Float3 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 Float3 Divide(Float3 num, params Float3[] vals) + { + foreach (Float3 d in vals) num /= d; + return num; + } + public static float Dot(Float3 a, Float3 b) => a.x * b.x + a.y * b.y + a.z * b.z; + public static float Dot(params Float3[] vals) + { + if (vals.Length < 1) return 0; + float x = 1, y = 1, z = 1; + foreach (Float3 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + } + return x + y + z; + } + public static Float3 Floor(Float3 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z)); + public static Float3 Lerp(Float3 a, Float3 b, float 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 Float3 Median(params Float3[] vals) + { + float index = Mathf.Average(0, vals.Length - 1); + Float3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Float3 Max(params Float3[] vals) + { + if (vals.Length < 1) return Zero; + Float3 val = vals[0]; + foreach (Float3 d in vals) val = d > val ? d : val; + return val; + } + public static Float3 Min(params Float3[] vals) + { + if (vals.Length < 1) return Zero; + Float3 val = vals[0]; + foreach (Float3 d in vals) val = d < val ? d : val; + return val; + } + public static Float3 Multiply(params Float3[] vals) + { + if (vals.Length < 1) return Zero; + Float3 val = One; + foreach (Float3 d in vals) val *= d; + return val; + } + public static Float3 Subtract(Float3 num, params Float3[] vals) + { + foreach (Float3 d in vals) num -= d; + return num; + } + public static Float3 Sum(params Float3[] vals) + { + Float3 val = Zero; + foreach (Float3 d in vals) val += d; + return val; + } + + public int CompareTo(Float3 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Float3)) return false; + return Equals((Float3)obj); + } + public bool Equals(Float3 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 Float3(x, y, z); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + } + + public float[] ToArray() => new[] { x, y, z }; + public List ToList() => new() { x, y, z }; + + public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); + public static Float3 operator -(Float3 d) => new(-d.x, -d.y, -d.z); + public static Float3 operator -(Float3 a, Float3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); + public static Float3 operator *(Float3 a, Float3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z); + public static Float3 operator *(Float3 a, float b) => new(a.x * b, a.y * b, a.z * b); + public static Float3 operator /(Float3 a, Float3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z); + public static Float3 operator /(Float3 a, float b) => new(a.x / b, a.y / b, a.z / b); + public static bool operator ==(Float3 a, Float3 b) => a.Equals(b); + public static bool operator !=(Float3 a, Float3 b) => !a.Equals(b); + public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0; + public static bool operator <(Float3 a, Float3 b) => a.CompareTo(b) < 0; + public static bool operator >=(Float3 a, Float3 b) => a == b || a > b; + public static bool operator <=(Float3 a, Float3 b) => a == b || a < b; + + public static implicit operator Float3(Float2 val) => new(val.x, val.y, 0); + public static explicit operator Float3(Float4 val) => new(val.x, val.y, val.z); + public static implicit operator Float3(Int2 val) => new(val.x, val.y, 0); + public static implicit operator Float3(Int3 val) => new(val.x, val.y, val.z); + public static explicit operator Float3(Int4 val) => new(val.x, val.y, val.z); + public static implicit operator Float3(Vert val) => new(val.position.x, val.position.y, val.position.z); + public static implicit operator Float3(Fill fill) => new(fill); + public static implicit operator Float3(Fill fill) => new(fill); +} diff --git a/Nerd_STF/Mathematics/Float4.cs b/Nerd_STF/Mathematics/Float4.cs new file mode 100644 index 0000000..928ff25 --- /dev/null +++ b/Nerd_STF/Mathematics/Float4.cs @@ -0,0 +1,218 @@ +namespace Nerd_STF.Mathematics; + +public struct Float4 : ICloneable, IComparable, IEquatable, IGroup +{ + public static Float4 Back => new(0, 0, -1, 0); + public static Float4 Deep => new(0, 0, 0, -1); + public static Float4 Down => new(0, -1, 0, 0); + public static Float4 Far => new(0, 0, 0, 1); + public static Float4 Forward => new(0, 0, 1, 0); + public static Float4 Left => new(-1, 0, 0, 0); + public static Float4 Right => new(1, 0, 0, 0); + public static Float4 Up => new(0, 1, 0, 0); + + public static Float4 One => new(1, 1, 1, 1); + public static Float4 Zero => new(0, 0, 0, 0); + + public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); + public Float4 Normalized => this / Magnitude; + + public Float2 XY => new(x, y); + public Float2 XZ => new(x, z); + public Float2 XW => new(x, w); + public Float2 YW => new(y, w); + public Float2 YZ => new(y, z); + public Float2 ZW => new(z, w); + + public Float3 XYW => new(x, y, w); + public Float3 XYZ => new(x, y, z); + public Float3 YZW => new(y, z, w); + public Float3 XZW => new(x, z, w); + + public float x, y, z, w; + + public Float4(float all) : this(all, all, all, all) { } + public Float4(float x, float y) : this(x, y, 0, 0) { } + public Float4(float x, float y, float z) : this(x, y, z, 0) { } + public Float4(float x, float y, float z, float w) + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + public Float4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + public Float4(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } + + public float 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 Float4 Absolute(Float4 val) => + new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); + public static Float4 Average(params Float4[] vals) => Sum(vals) / vals.Length; + public static Float4 Ceiling(Float4 val) => + new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w)); + public static Float4 Clamp(Float4 val, Float4 min, Float4 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 Float4 ClampMagnitude(Float4 val, float minMag, float maxMag) + { + if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag), + nameof(maxMag) + " must be greater than or equal to " + nameof(minMag)); + float 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 Float4 Divide(Float4 num, params Float4[] vals) + { + foreach (Float4 d in vals) num /= d; + return num; + } + public static float Dot(Float4 a, Float4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; + public static float Dot(params Float4[] vals) + { + if (vals.Length < 1) return 0; + float x = 1, y = 1, z = 1, w = 1; + foreach (Float4 d in vals) + { + x *= d.x; + y *= d.y; + z *= d.z; + w *= d.w; + } + return x + y + z; + } + public static Float4 Floor(Float4 val) => + new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w)); + public static Float4 Lerp(Float4 a, Float4 b, float 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 Float4 Median(params Float4[] vals) + { + float index = Mathf.Average(0, vals.Length - 1); + Float4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; + return Average(valA, valB); + } + public static Float4 Max(params Float4[] vals) + { + if (vals.Length < 1) return Zero; + Float4 val = vals[0]; + foreach (Float4 d in vals) val = d > val ? d : val; + return val; + } + public static Float4 Min(params Float4[] vals) + { + if (vals.Length < 1) return Zero; + Float4 val = vals[0]; + foreach (Float4 d in vals) val = d < val ? d : val; + return val; + } + public static Float4 Multiply(params Float4[] vals) + { + if (vals.Length < 1) return Zero; + Float4 val = One; + foreach (Float4 d in vals) val *= d; + return val; + } + public static Float4 Subtract(Float4 num, params Float4[] vals) + { + foreach (Float4 d in vals) num -= d; + return num; + } + public static Float4 Sum(params Float4[] vals) + { + Float4 val = Zero; + foreach (Float4 d in vals) val += d; + return val; + } + + public int CompareTo(Float4 other) => Magnitude.CompareTo(other.Magnitude); + public override bool Equals([NotNullWhen(true)] object? obj) + { + if (obj == null || obj.GetType() != typeof(Float4)) return false; + return Equals((Float4)obj); + } + public bool Equals(Float4 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 Float4(x, y, z, w); + + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); + public IEnumerator GetEnumerator() + { + yield return x; + yield return y; + yield return z; + yield return w; + } + + public float[] ToArray() => new[] { x, y, z, w }; + public List ToList() => new() { x, y, z, w }; + + public static Float4 operator +(Float4 a, Float4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); + public static Float4 operator -(Float4 d) => new(-d.x, -d.y, -d.z, -d.w); + public static Float4 operator -(Float4 a, Float4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); + public static Float4 operator *(Float4 a, Float4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); + public static Float4 operator *(Float4 a, float b) => new(a.x * b, a.y * b, a.z * b, a.w * b); + public static Float4 operator /(Float4 a, Float4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); + public static Float4 operator /(Float4 a, float b) => new(a.x / b, a.y / b, a.z / b, a.w / b); + public static bool operator ==(Float4 a, Float4 b) => a.Equals(b); + public static bool operator !=(Float4 a, Float4 b) => !a.Equals(b); + public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0; + public static bool operator <(Float4 a, Float4 b) => a.CompareTo(b) < 0; + public static bool operator >=(Float4 a, Float4 b) => a == b || a > b; + public static bool operator <=(Float4 a, Float4 b) => a == b || a < b; + + public static implicit operator Float4(Float2 val) => new(val.x, val.y, 0, 0); + public static implicit operator Float4(Float3 val) => new(val.x, val.y, val.z, 0); + public static implicit operator Float4(Int2 val) => new(val.x, val.y, 0, 0); + public static implicit operator Float4(Int3 val) => new(val.x, val.y, val.z, 0); + public static implicit operator Float4(Int4 val) => new(val.x, val.y, val.z, val.w); + public static implicit operator Float4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0); + public static implicit operator Float4(Fill fill) => new(fill); + public static implicit operator Float4(Fill fill) => new(fill); +} diff --git a/Nerd_STF/Mathematics/Geometry/Box2D.cs b/Nerd_STF/Mathematics/Geometry/Box2D.cs index 570e77c..0ba2df7 100644 --- a/Nerd_STF/Mathematics/Geometry/Box2D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box2D.cs @@ -2,7 +2,7 @@ public struct Box2D : ICloneable, IContainer, IEquatable { - public static Box2D Unit => new(Vert.Zero, Double2.One); + public static Box2D Unit => new(Vert.Zero, Float2.One); public Vert MaxVert { @@ -10,7 +10,7 @@ public struct Box2D : ICloneable, IContainer, IEquatable set { Vert diff = center - value; - size = (Double2)diff.position * 2; + size = (Float2)diff.position * 2; } } public Vert MinVert @@ -19,25 +19,25 @@ public struct Box2D : ICloneable, IContainer, IEquatable set { Vert diff = center + value; - size = (Double2)diff.position * 2; + size = (Float2)diff.position * 2; } } - public double Area => size.x * size.y; - public double Perimeter => size.x * 2 + size.y * 2; + public float Area => size.x * size.y; + public float Perimeter => size.x * 2 + size.y * 2; public Vert center; - public Double2 size; + public Float2 size; - public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Double2)(min - max)) { } - public Box2D(Vert center, Double2 size) + public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Float2)(min - max)) { } + public Box2D(Vert center, Float2 size) { this.center = center; this.size = size; } - public Box2D(Fill fill) : this(fill, new Double2(fill(3), fill(4))) { } + public Box2D(Fill fill) : this(fill, new Float2(fill(3), fill(4))) { } - public double this[int index] + public float this[int index] { get => size[index]; set => size[index] = value; @@ -46,34 +46,34 @@ public struct Box2D : ICloneable, IContainer, IEquatable 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)); + (Vert[] centers, Float2[] sizes) = SplitArray(vals); + return new(Vert.Average(centers), Float2.Average(sizes)); } - public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Double2.Ceiling(val.size)); + public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Float2.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)); + new(Vert.Clamp(val.center, min.center, max.center), Float2.Clamp(val.size, min.size, max.size)); + public static Box2D Floor(Box2D val) => new(Vert.Floor(val.center), Float2.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)); + new(Vert.Lerp(a.center, b.center, t, clamp), Float2.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)); + (Vert[] verts, Float2[] sizes) = SplitArray(vals); + return new(Vert.Median(verts), Float2.Median(sizes)); } public static Box2D Max(params Box2D[] vals) { - (Vert[] verts, Double2[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Double2.Max(sizes)); + (Vert[] verts, Float2[] sizes) = SplitArray(vals); + return new(Vert.Max(verts), Float2.Max(sizes)); } public static Box2D Min(params Box2D[] vals) { - (Vert[] verts, Double2[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Double2.Min(sizes)); + (Vert[] verts, Float2[] sizes) = SplitArray(vals); + return new(Vert.Min(verts), Float2.Min(sizes)); } - public static (Vert[] centers, Double2[] sizes) SplitArray(params Box2D[] vals) + public static (Vert[] centers, Float2[] sizes) SplitArray(params Box2D[] vals) { Vert[] centers = new Vert[vals.Length]; - Double2[] sizes = new Double2[vals.Length]; + Float2[] sizes = new Float2[vals.Length]; for (int i = 0; i < vals.Length; i++) { @@ -99,24 +99,24 @@ public struct Box2D : ICloneable, IContainer, IEquatable public bool Contains(Vert vert) { - Double2 diff = Double2.Absolute((Double2)(center - vert)); + Float2 diff = Float2.Absolute((Float2)(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 a, Float2 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 Box2D operator -(Box2D a, Float2 b) => new(a.center, a.size - b); + public static Box2D operator *(Box2D a, float b) => new(a.center * b, a.size * b); + public static Box2D operator *(Box2D a, Float2 b) => new(a.center, a.size * b); + public static Box2D operator /(Box2D a, float b) => new(a.center / b, a.size / b); + public static Box2D operator /(Box2D a, Float2 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 static implicit operator Box2D(Fill fill) => new(fill); + public static explicit operator Box2D(Box3D box) => new(box.center, (Float2)box.size); } diff --git a/Nerd_STF/Mathematics/Geometry/Box3D.cs b/Nerd_STF/Mathematics/Geometry/Box3D.cs index 47a64c2..62feb64 100644 --- a/Nerd_STF/Mathematics/Geometry/Box3D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box3D.cs @@ -2,7 +2,7 @@ public struct Box3D : ICloneable, IContainer, IEquatable { - public static Box3D Unit => new(Vert.Zero, Double3.One); + public static Box3D Unit => new(Vert.Zero, Float3.One); public Vert MaxVert { @@ -23,22 +23,22 @@ public struct Box3D : ICloneable, IContainer, IEquatable } } - public double Area => size.x * size.y * size.z; - public double Perimeter => size.x * 2 + size.y * 2 + size.z * 2; + public float Area => size.x * size.y * size.z; + public float Perimeter => size.x * 2 + size.y * 2 + size.z * 2; public Vert center; - public Double3 size; + public Float3 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) + public Box3D(Box2D box) : this(box.center, (Float3)box.size) { } + public Box3D(Vert min, Vert max) : this(Vert.Average(min, max), (Float3)(min - max)) { } + public Box3D(Vert center, Float3 size) { this.center = center; this.size = size; } - public Box3D(Fill fill) : this(fill, new Double3(fill(3), fill(4), fill(5))) { } + public Box3D(Fill fill) : this(fill, new Float3(fill(3), fill(4), fill(5))) { } - public double this[int index] + public float this[int index] { get => size[index]; set => size[index] = value; @@ -47,34 +47,34 @@ public struct Box3D : ICloneable, IContainer, IEquatable 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)); + (Vert[] centers, Float3[] sizes) = SplitArray(vals); + return new(Vert.Average(centers), Float3.Average(sizes)); } - public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Double3.Ceiling(val.size)); + public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Float3.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)); + new(Vert.Clamp(val.center, min.center, max.center), Float3.Clamp(val.size, min.size, max.size)); + public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Float3.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)); + new(Vert.Lerp(a.center, b.center, t, clamp), Float3.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)); + (Vert[] verts, Float3[] sizes) = SplitArray(vals); + return new(Vert.Median(verts), Float3.Median(sizes)); } public static Box3D Max(params Box3D[] vals) { - (Vert[] verts, Double3[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Double3.Max(sizes)); + (Vert[] verts, Float3[] sizes) = SplitArray(vals); + return new(Vert.Max(verts), Float3.Max(sizes)); } public static Box3D Min(params Box3D[] vals) { - (Vert[] verts, Double3[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Double3.Min(sizes)); + (Vert[] verts, Float3[] sizes) = SplitArray(vals); + return new(Vert.Min(verts), Float3.Min(sizes)); } - public static (Vert[] centers, Double3[] sizes) SplitArray(params Box3D[] vals) + public static (Vert[] centers, Float3[] sizes) SplitArray(params Box3D[] vals) { Vert[] centers = new Vert[vals.Length]; - Double3[] sizes = new Double3[vals.Length]; + Float3[] sizes = new Float3[vals.Length]; for (int i = 0; i < vals.Length; i++) { @@ -100,23 +100,23 @@ public struct Box3D : ICloneable, IContainer, IEquatable public bool Contains(Vert vert) { - Double3 diff = Double3.Absolute(center - vert); + Float3 diff = Float3.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 a, Float3 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 Box3D operator -(Box3D a, Float3 b) => new(a.center, a.size - b); + public static Box3D operator *(Box3D a, float b) => new(a.center * b, a.size * b); + public static Box3D operator *(Box3D a, Float3 b) => new(a.center, a.size * b); + public static Box3D operator /(Box3D a, float b) => new(a.center / b, a.size / b); + public static Box3D operator /(Box3D a, Float3 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(Fill fill) => new(fill); public static implicit operator Box3D(Box2D box) => new(box); } diff --git a/Nerd_STF/Mathematics/Geometry/Line.cs b/Nerd_STF/Mathematics/Geometry/Line.cs index 51779b2..5e07311 100644 --- a/Nerd_STF/Mathematics/Geometry/Line.cs +++ b/Nerd_STF/Mathematics/Geometry/Line.cs @@ -13,7 +13,7 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer new(Vert.Zero, Vert.One); public static Line Zero => new(Vert.Zero, Vert.Zero); - public double Length => (b - a).Magnitude; + public float Length => (b - a).Magnitude; public Vert a, b; @@ -22,13 +22,13 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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)), 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 Line(Fill fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { } public Vert this[int index] @@ -66,7 +66,7 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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) => + public static Line Lerp(Line a, Line b, float 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) { @@ -114,16 +114,16 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer ClosestTo(vert, Calculus.DefaultStep); - public Vert ClosestTo(Vert vert, double step) + public Vert ClosestTo(Vert vert, float step) { Vert closestA = a, closestB = b; - for (double t = 0; t <= 1; t += step) + for (float t = 0; t <= 1; t += step) { Vert valA = Vert.Lerp(a, b, t); Vert valB = Vert.Lerp(b, a, t); @@ -143,7 +143,7 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer, IComparable, IContainer new Vert[] { a, b }; public List ToList() => new() { a, b }; - public double[] ToDoubleArray() => new double[] { a.position.x, a.position.y, a.position.z, + public float[] ToDoubleArray() => new float[] { 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, + 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); @@ -174,10 +174,10 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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, float 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, float 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; @@ -186,8 +186,8 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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); + 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 de88add..14b45f7 100644 --- a/Nerd_STF/Mathematics/Geometry/Polygon.cs +++ b/Nerd_STF/Mathematics/Geometry/Polygon.cs @@ -26,20 +26,20 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid [Obsolete("This method uses the Polygon.Triangulate() function, which has issues. It will be fixed in a " + "future update.")] - public double Area + public float Area { get { - double val = 0; + float val = 0; foreach (Triangle t in Triangulate()) val += t.Area; return val; } } - public double Perimeter + public float Perimeter { get { - double val = 0; + float val = 0; foreach (Line l in Lines) val += l.Length; return val; } @@ -62,7 +62,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid } this = new(verts.ToArray()); } - public Polygon(Fill fill) + public Polygon(Fill fill) { List verts = new(); int i = 0; @@ -92,7 +92,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid 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)); @@ -104,7 +104,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid for (int i = 0; i < length; i++) lines.Add(fill(i)); this = new(lines.ToArray()); } - public Polygon(params Double3[] verts) + public Polygon(params Float3[] verts) { p_verts = new Vert[verts.Length]; for (int i = 0; i < verts.Length; i++) p_verts[i] = verts[i]; @@ -132,7 +132,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid List parts = new(); for (int i = 0; i < vertCount; i++) { - double val = Mathf.Tau * i / vertCount; + float val = Mathf.Tau * i / vertCount; parts.Add(new(Mathf.Cos(val), Mathf.Sin(val))); } return new(parts.ToArray()); @@ -182,7 +182,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid 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, float t, bool clamp = true) { if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b); Line[][] lines = new Line[2][] { a.Lines, b.Lines }; @@ -245,10 +245,10 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid return new(res); } - public static double[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray(); - public static List ToDoubleListAll(params Polygon[] polys) + public static float[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray(); + public static List ToDoubleListAll(params Polygon[] polys) { - List vals = new(); + List vals = new(); foreach (Polygon poly in polys) vals.AddRange(poly.ToDoubleArray()); return vals; } @@ -286,9 +286,9 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid public Vert[] ToArray() => Verts; public List ToList() => new(Verts); - public double[] ToDoubleArray() + public float[] ToDoubleArray() { - double[] vals = new double[Verts.Length * 3]; + float[] vals = new float[Verts.Length * 3]; for (int i = 0; i < Verts.Length; i++) { int pos = i * 3; @@ -298,7 +298,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid } return vals; } - public List ToDoubleList() => new(ToDoubleArray()); + public List ToDoubleList() => new(ToDoubleArray()); public Polygon Subdivide() { @@ -323,7 +323,7 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid { for (int factor = 0; factor < segments; factor++) { - double unit = factor / (double)(segments * 2), unit2 = unit + 0.5, lastUnit = unit * 2; + float unit = factor / (float)(segments * 2), unit2 = unit + 0.5f, lastUnit = unit * 2; Vert p1, p2; if (i == Verts.Length - 1) { @@ -500,10 +500,10 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid 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(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(Float3[] 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 c2d297e..f00c9e6 100644 --- a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs +++ b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs @@ -94,16 +94,16 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup AB.Length + BC.Length + CD.Length + DA.Length; + public float Perimeter => AB.Length + BC.Length + CD.Length + DA.Length; public Quadrilateral(Vert a, Vert b, Vert c, Vert d) { @@ -130,16 +130,16 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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)) { } - public Quadrilateral(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6), + 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)) { } @@ -193,7 +193,7 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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) => + public static Quadrilateral Lerp(Quadrilateral a, Quadrilateral b, float 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) @@ -241,9 +241,9 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup, IGroup 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) { @@ -291,11 +291,11 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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, + public float[] ToDoubleArray() => new float[] { 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 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 }; @@ -313,19 +313,19 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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, float 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, float 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 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 23df755..3dc5c25 100644 --- a/Nerd_STF/Mathematics/Geometry/Sphere.cs +++ b/Nerd_STF/Mathematics/Geometry/Sphere.cs @@ -1,64 +1,64 @@ 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 float radius; - public double SurfaceArea => 4 * Mathf.Pi * radius * radius; - public double Volume => 4 / 3 * (Mathf.Pi * radius * radius * radius); + public float SurfaceArea => 4 * Mathf.Pi * radius * radius; + public float 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 Sphere(Vert center, float 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(float cX, float cY, float radius) : this(new Vert(cX, cY), radius) { } + public Sphere(float cX, float cY, float cZ, float radius) : this(new Vert(cX, cY, cZ), radius) { } + public Sphere(Fill fill, float radius) : this(new Vert(fill), radius) { } + public Sphere(Fill fill) : this(new Vert(fill), fill(3)) { } + public Sphere(Fill fill, float 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 Sphere(Fill fill, float 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); + (Vert[] centers, float[] 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) => + public static Sphere Lerp(Sphere a, Sphere b, float 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); + (Vert[] centers, float[] radii) = SplitArray(vals); return new(Vert.Max(centers), Mathf.Max(radii)); } public static Sphere Median(params Sphere[] vals) { - (Vert[] centers, double[] radii) = SplitArray(vals); + (Vert[] centers, float[] radii) = SplitArray(vals); return new(Vert.Median(centers), Mathf.Median(radii)); } public static Sphere Min(params Sphere[] vals) { - (Vert[] centers, double[] radii) = SplitArray(vals); + (Vert[] centers, float[] radii) = SplitArray(vals); return new(Vert.Min(centers), Mathf.Min(radii)); } - public static (Vert[] centers, double[] radii) SplitArray(params Sphere[] spheres) + public static (Vert[] centers, float[] radii) SplitArray(params Sphere[] spheres) { Vert[] centers = new Vert[spheres.Length]; - double[] radii = new double[spheres.Length]; + float[] radii = new float[spheres.Length]; for (int i = 0; i < spheres.Length; i++) { centers[i] = spheres[i].center; @@ -72,10 +72,10 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara 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); + if (type == typeof(float)) return Equals((float)obj); return false; } - public bool Equals(double other) => Volume == other; + public bool Equals(float 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); @@ -87,7 +87,7 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara 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 int CompareTo(float volume) => Volume.CompareTo(volume); public bool Contains(Vert vert) => (center - vert).Magnitude <= radius; @@ -95,24 +95,24 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara 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, float 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, float 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, float 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 Sphere operator /(Sphere a, float 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, float b) => a.Equals(b); + public static bool operator !=(Sphere a, float 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, float b) => a.CompareTo(b) > 0; + public static bool operator <(Sphere a, float 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; + public static bool operator >=(Sphere a, float b) => a > b || a == b; + public static bool operator <=(Sphere a, float b) => a < b || a == b; } diff --git a/Nerd_STF/Mathematics/Geometry/Triangle.cs b/Nerd_STF/Mathematics/Geometry/Triangle.cs index 03c3a44..64033b3 100644 --- a/Nerd_STF/Mathematics/Geometry/Triangle.cs +++ b/Nerd_STF/Mathematics/Geometry/Triangle.cs @@ -72,9 +72,10 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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 float Area => (float)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.5f; + public float Perimeter => AB.Length + BC.Length + CA.Length; public Triangle(Vert a, Vert b, Vert c) { @@ -97,15 +98,15 @@ public struct Triangle : ICloneable, IEquatable, IGroup p_bc = bc; p_ca = ca; } - public Triangle(double x1, double y1, double x2, double y2, double x3, double y3) + public Triangle(float x1, float y1, float x2, float y2, float x3, float 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(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, + float 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), + 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)) { } @@ -153,7 +154,7 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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) => + public static Triangle Lerp(Triangle a, Triangle b, float 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) { @@ -194,9 +195,9 @@ public struct Triangle : ICloneable, IEquatable, IGroup return (ab, bc, ca); } - public static double[] ToDoubleArrayAll(params Triangle[] tris) + public static float[] ToDoubleArrayAll(params Triangle[] tris) { - double[] vals = new double[tris.Length * 9]; + float[] vals = new float[tris.Length * 9]; for (int i = 0; i < tris.Length; i++) { int pos = i * 9; @@ -212,7 +213,7 @@ public struct Triangle : ICloneable, IEquatable, IGroup } return vals; } - public static List ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris)); + public static List ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris)); public override bool Equals([NotNullWhen(true)] object? obj) { @@ -240,10 +241,10 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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, + public float[] ToDoubleArray() => new float[] { 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 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); @@ -253,18 +254,18 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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, float 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, float 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 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 97d5545..9b76ceb 100644 --- a/Nerd_STF/Mathematics/Geometry/Vert.cs +++ b/Nerd_STF/Mathematics/Geometry/Vert.cs @@ -1,6 +1,6 @@ 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); @@ -12,51 +12,51 @@ public struct Vert : ICloneable, IEquatable, IGroup public static Vert One => new(1, 1, 1); public static Vert Zero => new(0, 0, 0); - public double Magnitude => position.Magnitude; + public float Magnitude => position.Magnitude; public Vert Normalized => new(this / Magnitude); - public Double3 position; + public Float3 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 Vert(Float2 pos) : this(pos.x, pos.y, 0) { } + public Vert(Float3 pos) => position = pos; + public Vert(float x, float y) : this(new Float2(x, y)) { } + public Vert(float x, float y, float z) : this(new Float3(x, y, z)) { } + public Vert(Fill fill) : this(new Float3(fill)) { } + public Vert(Fill fill) : this(new Float3(fill)) { } - public double this[int index] + public float 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 Absolute(Vert val) => new(Float3.Absolute(val.position)); + public static Vert Average(params Vert[] vals) => Float3.Average(ToDouble3Array(vals)); + public static Vert Ceiling(Vert val) => new(Float3.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)); + new(Float3.Clamp(val.position, min.position, max.position)); + public static Vert ClampMagnitude(Vert val, float minMag, float maxMag) => + new(Float3.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)); + new(Float3.Cross(a.position, b.position, normalized)); + public static float Dot(Vert a, Vert b) => Float3.Dot(a.position, b.position); + public static float Dot(params Vert[] vals) => Float3.Dot(ToDouble3Array(vals)); + public static Vert Floor(Vert val) => new(Float3.Floor(val.position)); + public static Vert Lerp(Vert a, Vert b, float t, bool clamp = true) => + new(Float3.Lerp(a.position, b.position, t, clamp)); public static Vert Median(params Vert[] vals) => - Double3.Median(ToDouble3Array(vals)); + Float3.Median(ToDouble3Array(vals)); public static Vert Max(params Vert[] vals) => - Double3.Max(ToDouble3Array(vals)); + Float3.Max(ToDouble3Array(vals)); public static Vert Min(params Vert[] vals) => - Double3.Min(ToDouble3Array(vals)); - public static Double3[] ToDouble3Array(params Vert[] vals) + Float3.Min(ToDouble3Array(vals)); + public static Float3[] ToDouble3Array(params Vert[] vals) { - Double3[] doubles = new Double3[vals.Length]; + Float3[] doubles = new Float3[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 static List ToDouble3List(params Vert[] vals) => ToDouble3Array(vals).ToList(); public override bool Equals([NotNullWhen(true)] object? obj) { @@ -72,27 +72,27 @@ public struct Vert : ICloneable, IEquatable, IGroup public object Clone() => new Vert(position); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); - public IEnumerator GetEnumerator() => position.GetEnumerator(); + public IEnumerator GetEnumerator() => position.GetEnumerator(); - public double[] ToArray() => position.ToArray(); - public List ToList() => position.ToList(); + public float[] 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, float 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 Vert operator /(Vert a, float 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(Float2 val) => new(val); + public static implicit operator Vert(Float3 val) => new(val); + public static explicit operator Vert(Float4 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); public static implicit operator Vert(Fill fill) => new(fill); } diff --git a/Nerd_STF/Mathematics/Int2.cs b/Nerd_STF/Mathematics/Int2.cs index f65ebc2..3509f81 100644 --- a/Nerd_STF/Mathematics/Int2.cs +++ b/Nerd_STF/Mathematics/Int2.cs @@ -10,8 +10,8 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup 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 float Magnitude => Mathf.Sqrt(x * x + y * y); + public Int2 Normalized => (Int2)((Float2)this / Magnitude); public int x, y; @@ -58,7 +58,7 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup= minMag && mag <= maxMag) return val; val = val.Normalized; if (mag < minMag) val *= minMag; @@ -84,7 +84,7 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup + public static Int2 Lerp(Int2 a, Int2 b, float 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) { @@ -168,9 +168,9 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup=(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(Float2 val) => new((int)val.x, (int)val.y); + public static explicit operator Int2(Float3 val) => new((int)val.x, (int)val.y); + public static explicit operator Int2(Float4 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); diff --git a/Nerd_STF/Mathematics/Int3.cs b/Nerd_STF/Mathematics/Int3.cs index 1641aa7..f2811ce 100644 --- a/Nerd_STF/Mathematics/Int3.cs +++ b/Nerd_STF/Mathematics/Int3.cs @@ -12,8 +12,8 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup 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 float Magnitude => Mathf.Sqrt(x * x + y * y + z * z); + public Int3 Normalized => (Int3)((Float3)this / Magnitude); public Int2 XY => new(x, y); public Int2 XZ => new(x, z); @@ -72,7 +72,7 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup= minMag && mag <= maxMag) return val; val = val.Normalized; if (mag < minMag) val *= minMag; @@ -104,7 +104,7 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup + public static Int3 Lerp(Int3 a, Int3 b, float 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) { @@ -186,9 +186,9 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup=(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 explicit operator Int3(Float2 val) => new((int)val.x, (int)val.y, 0); + public static explicit operator Int3(Float3 val) => new((int)val.x, (int)val.y, (int)val.z); + public static explicit operator Int3(Float4 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, diff --git a/Nerd_STF/Mathematics/Int4.cs b/Nerd_STF/Mathematics/Int4.cs index b694e9c..dda3fee 100644 --- a/Nerd_STF/Mathematics/Int4.cs +++ b/Nerd_STF/Mathematics/Int4.cs @@ -14,8 +14,8 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup 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 float Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w); + public Int4 Normalized => (Int4)((Float4)this / Magnitude); public Int2 XY => new(x, y); public Int2 XZ => new(x, z); @@ -90,7 +90,7 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup= minMag && mag <= maxMag) return val; val = val.Normalized; if (mag < minMag) val *= minMag; @@ -116,7 +116,7 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup + public static Int4 Lerp(Int4 a, Int4 b, float 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) @@ -205,9 +205,9 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup=(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 explicit operator Int4(Float2 val) => new((int)val.x, (int)val.y, 0, 0); + public static explicit operator Int4(Float3 val) => new((int)val.x, (int)val.y, (int)val.z, 0); + public static explicit operator Int4(Float4 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, diff --git a/Nerd_STF/Mathematics/Mathf.cs b/Nerd_STF/Mathematics/Mathf.cs index 29bbff2..816b81f 100644 --- a/Nerd_STF/Mathematics/Mathf.cs +++ b/Nerd_STF/Mathematics/Mathf.cs @@ -2,42 +2,42 @@ 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 const float RadToDeg = 0.0174532925199f; // Pi / 180 + public const float E = 2.71828182846f; + public const float GoldenRatio = 1.61803398875f; // (1 + Sqrt(5)) / 2 + public const float HalfPi = 1.57079632679f; // Pi / 2 + public const float Pi = 3.14159265359f; + public const float DegToRad = 57.2957795131f; // 180 / Pi + public const float Tau = 6.28318530718f; // 2 * Pi - public static double Absolute(double val) => val < 0 ? -val : val; + public static float Absolute(float 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 float ArcCos(float value) => -ArcSin(value) + HalfPi; - public static double ArcCot(double value) => ArcCos(value / Sqrt(1 + value * value)); + public static float ArcCot(float value) => ArcCos(value / Sqrt(1 + value * value)); - public static double ArcCsc(double value) => ArcSin(1 / value); + public static float ArcCsc(float value) => ArcSin(1 / value); - public static double ArcSec(double value) => ArcCos(1 / value); + public static float ArcSec(float 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 float ArcSin(float value) => (float)Math.Asin(value); - public static double ArcTan(double value) => ArcSin(value / Sqrt(1 + value * value)); + public static float ArcTan(float value) => ArcSin(value / Sqrt(1 + value * value)); - public static double Average(Equation equ, double min, double max, double step = Calculus.DefaultStep) + public static float Average(Equation equ, float min, float max, float step = Calculus.DefaultStep) { - List vals = new(); - for (double x = min; x <= max; x += step) vals.Add(equ(x)); + List vals = new(); + for (float 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 float Average(params float[] 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 int Ceiling(float val) => (int)(val + (1 - (val % 1))); - public static double Clamp(double val, double min, double max) + public static float Clamp(float val, float min, float max) { if (max < min) throw new ArgumentOutOfRangeException(nameof(max), nameof(max) + " must be greater than or equal to " + nameof(min)); @@ -54,15 +54,15 @@ public static class Mathf return val; } - public static double Cos(double radians) => Sin(radians + HalfPi); + public static float Cos(float radians) => Sin(radians + HalfPi); - public static double Cot(double radians) => Cos(radians) / Sin(radians); + public static float Cot(float radians) => Cos(radians) / Sin(radians); - public static double Csc(double radians) => 1 / Sin(radians); + public static float Csc(float radians) => 1 / Sin(radians); - public static double Divide(double val, params double[] dividends) + public static float Divide(float val, params float[] dividends) { - foreach (double d in dividends) val /= d; + foreach (float d in dividends) val /= d; return val; } public static int Divide(int val, params int[] dividends) @@ -79,53 +79,53 @@ public static class Mathf return val; } - public static int Floor(double val) => (int)(val - (val % 1)); + public static int Floor(float val) => (int)(val - (val % 1)); - public static Dictionary GetValues(Equation equ, double min, double max, - double step = Calculus.DefaultStep) + public static Dictionary GetValues(Equation equ, float min, float max, + float step = Calculus.DefaultStep) { - Dictionary vals = new(); - for (double x = min; x <= max; x += step) vals.Add(x, equ(x)); + Dictionary vals = new(); + for (float 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) + public static float Lerp(float a, float b, float t, bool clamp = true) { - double v = a + t * (b - a); + float 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 int Lerp(int a, int b, float value, bool clamp = true) => Floor(Lerp(a, b, value, clamp)); - public static Equation MakeEquation(Dictionary vals) => (x) => + public static Equation MakeEquation(Dictionary vals) => (x) => { - double min = -1, max = -1; - foreach (KeyValuePair val in vals) + float 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); + float per = x % (max - min); return Lerp(min, max, per); }; - public static double Max(Equation equ, double min, double max, double step = Calculus.DefaultStep) + public static float Max(Equation equ, float min, float max, float step = Calculus.DefaultStep) { - double Y = equ(min); - for (double x = min; x <= max; x += step) + float Y = equ(min); + for (float x = min; x <= max; x += step) { - double val = equ(x); + float val = equ(x); Y = val > Y ? val : Y; } return Y; } - public static double Max(params double[] vals) + public static float Max(params float[] vals) { if (vals.Length < 1) return 0; - double val = vals[0]; - foreach (double d in vals) val = d > val ? d : val; + float val = vals[0]; + foreach (float d in vals) val = d > val ? d : val; return val; } public static int Max(params int[] vals) @@ -136,29 +136,29 @@ public static class Mathf return val; } - public static double Median(params double[] vals) + public static float Median(params float[] vals) { - double index = Average(0, vals.Length - 1); - double valA = vals[Floor(index)], valB = vals[Ceiling(index)]; + float index = Average(0, vals.Length - 1); + float 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) + public static float Min(Equation equ, float min, float max, float step = Calculus.DefaultStep) { - double Y = equ(min); - for (double x = min; x <= max; x += step) + float Y = equ(min); + for (float x = min; x <= max; x += step) { - double val = equ(x); + float val = equ(x); Y = val < Y ? val : Y; } return Y; } - public static double Min(params double[] vals) + public static float Min(params float[] vals) { if (vals.Length < 1) return 0; - double val = vals[0]; - foreach (double d in vals) val = d < val ? d : val; + float val = vals[0]; + foreach (float d in vals) val = d < val ? d : val; return val; } public static int Min(params int[] vals) @@ -169,11 +169,11 @@ public static class Mathf return val; } - public static double Multiply(params double[] vals) + public static float Multiply(params float[] vals) { if (vals.Length < 1) return 0; - double val = 1; - foreach (double d in vals) val *= d; + float val = 1; + foreach (float d in vals) val *= d; return val; } public static int Multiply(params int[] vals) @@ -184,7 +184,7 @@ public static class Mathf return val; } - public static double Power(double num, double pow) => Math.Pow(num, pow); + public static float Power(float num, float pow) => (float)Math.Pow(num, pow); public static int Power(int num, int pow) { if (pow < 0) return 0; @@ -193,28 +193,28 @@ public static class Mathf return val; } - public static double Root(double value, double index) => Math.Exp(index * Math.Log(value)); + public static float Root(float value, float index) => (float)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 float Round(float num) => num % 1 >= 0.5 ? Ceiling(num) : Floor(num); + public static float Round(float num, float nearest) => nearest * Round(num / nearest); + public static int RoundInt(float num) => (int)Round(num); - public static double Sec(double radians) => 1 / Cos(radians); + public static float Sec(float radians) => 1 / Cos(radians); - public static double Sin(double radians) + public static float Sin(float 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; + const float a = 0.000013028f, + b = 0.999677f, + c = 0.00174164f, + d = -0.170587f, + e = 0.0046494f, + f = 0.00508955f, + g = 0.00140205f, + h = -0.000577413f, + i = 0.0000613134f, + j = -0.00000216852f; + float 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) @@ -222,11 +222,11 @@ public static class Mathf + (j * x * x * x * x * x * x * x * x * x); } - public static double Sqrt(double value) => Root(value, 2); + public static float Sqrt(float value) => Root(value, 2); - public static double Subtract(double num, params double[] vals) + public static float Subtract(float num, params float[] vals) { - foreach (double d in vals) num -= d; + foreach (float d in vals) num -= d; return num; } public static int Subtract(int num, params int[] vals) @@ -235,10 +235,10 @@ public static class Mathf return num; } - public static double Sum(params double[] vals) + public static float Sum(params float[] vals) { - double val = 0; - foreach (double d in vals) val += d; + float val = 0; + foreach (float d in vals) val += d; return val; } public static int Sum(params int[] vals) @@ -248,5 +248,5 @@ public static class Mathf return val; } - public static double Tan(double radians) => Sin(radians) / Cos(radians); + public static float Tan(float radians) => Sin(radians) / Cos(radians); } 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 acbe61278fedfb72cb0aac013731c474fecd53a3..0d80df7cc156eb829bb3dac304dbd441f0162a3d 100644 GIT binary patch literal 47104 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

%Qu8=g||10kbNz*~! zm9)zDEARItwSiVkDviA0y-J~1yjLr<-}`-q-t}Ii(4V|(75c=xPEv71E4Wrt4_~0* zI!RLlDuqmy3L`3YX-7A<+peoe&AC?b*`v|jAC1OBxpz8G5BKJMZ?&V3RpN0gbMm-d z@6>_DZKr}86nfIQ(Ip9E7u+IgYvA~Tjgk`Pu!379Eeww+ zxItG1wU5k?1FnG?GDT?xKC2jUtI80NoBF(f(Ip~;d@BZCiotf^n7?+ z!6TA}Bj=+I(I~Dj*y4~qiXW4{cS6~Mt=KRQ#RYjE*!Uf@dYY4SG(}uGq?g-IDfzUX(Q6zp~&ZNz*}lC9U$UEOg4Y$=Q1FJN;>fK9`z4h|?k+f>&;tc;N-BYt zY+r#TDGi@b(kA%)lAaHLUJ#Hp963V{(Hs)D!VcMUNJRSH3H7oHrH|&2s3e+0T(aj7 zmCDSRj6!or2Z!uA#3g$U$rH^Xd7?SQC7MI}S$SIRf2p986O-nUepY8mZLxmVkqQm9 zj*`@hoZS=}Y8@@ zRU)YkG(b{mWVAI%p-OA8LRHofNyU*F)=-6NtYMN$BlD~iBo#-RtP@>AZ(U-Yq|l|- za7pR#66<71H$<0Mr%0+ZmRMzyMuAS1)Z|}cjgV9UDwkAcUSW(>XsIA1t&)bL?#mQfX)TvD1~IR2$vQdmmh~Nn zmRnCm-&g4A=!XhzhHr(;`5=6GI>LBMUnza32Nl8@;ZsZcK&Ee%n-lbyaivRq|7Eo# zy8p7qAvy7{OzT2g5wLj$BEa?U0yi=jGeRoT0i`Dt=QRr;neUe)Jb-te{bhhuOl6J+? zzK1030X-tAIFj={DycMbiEoRflOxM~k2z%btUOWA$`kdhtuiO|tUOWA+9rL}vm~MS ztn{h$sr9&<6TUURClq=N&-mT<3DC2_osy`ZJ?Rkjv-Q58Nvbk8_ zZ{XRk=2e)g(E)X!eJ}Y=aL^O zl+!hsh50ZCQnx&EM}o$!SuZ4D&-VM&?bG=Egm?m&}2CMoGZ*WX!ES?pZ@5t7pI z9Vw|bcA>wELw29<>Jat$EB)Q1kNSL(BK-!Z?ZLbJd5W74wWG%rx-hoG-&1a9#db+rF3!W9Zr8V5 zd={M|iAST%N%WfkI48DurPf2H)@93B?P6P;xyNFSYLBw;k-9fz(D zbZS7QiGhiV@7%y7h0=k^3M~puQK&Ugt%`;c z+Q2!IPPc9doGYoyYzv$xX(xO$C2bAd5tt<@6TBf%D`|J&fk2(4vRGSSo}{F|Es&Cw z2AwZyk8fLGzNDvoPX*Er*(1E(AsXS&1sbG}MtGwn8sRS4BV462vq?tjj}d->L-t5@ ziC+8O<5PFNo}$Hfr}J+KX8dc9|u|_wIa&p3cVj#s?f)Q<&t*Az6^Xv z(jL%CNyU+Z;3|cV41Q0c-oYysIx)Cfp^?Eg3XKb1rO+9{s}(vc_l#UY z^$!(Fz_(WV#>1DVI{4N}-}&(6X(fEuO5Ymz@-$4J8N5#V%Je#grop#f`p$(fPZz;= zz4W!hm#5C~-5`BM@a2i-mmf$U%`cKLqnsa9X-RN{n-jj}!Ho)C9lTSa!TyI7D)T?A zP;dVu3bh6QL!rlvM-_U~*y0k;FONy0`DLp^bd_*t@Nr31=KaC{l(ZARCnRkR{6}!R zq)hNmJOQ+?QPv4O$qqgxsVsJXaF?W{|Nh`FC8a^Xl5}P4+2GTX(y{k~&q~_kGeXZv zdde3FJ@1e`+w69TW}D8T7o?A7n-?X~Y~zwW+o)7#?vYVwwt2}Rd$w`Oo^A3(vrV38 zwsFaxZSq93jZ1H8G>5oEb4a(4NLh7*;O$UnNoBF8Lq|zU`kxMUm6Qf`lhhjfbEwE6dvtVnh(?De99PI6 zK1SxGv2v^=8Y?c@V@0Jhvsgx1*d4a;PN}a8MIZG7k5gwpWNqCT?wpiEj5QR#@!z8sL%83e~B=4%-^I?Z~p}fwFNT@J!WJTdeX?b z#OKClNpx;p;1Hb~Q{hFDs?4VFVo5vUTOw&|U{Ux&Nts|Oe2Jvpf!6S)lFDLD;Z{jW ze^Yp=q%>%mq$^`rhL=l9$2Nt(BWaKC;qXdHPx&4Xf7c;<^sjP=M*ptx_oR=;`<0St zyt`zNca_S_)iMf=_cadL=SG+8b7P+9+?XdiH@ak>8}mfxMwe(V_;pyNz2U2!{n6Pl z6~0E&3&^=vp}pa2CAGzV9bT`{-tY|y9SHwWQY)g|q|n~*%?cd|-y&&O?EUa2Nqa!I zN-Bf;(6N!b6zUhbTT*FcSmei&dicsB_eh!=P$^`pR2WgI zOFO!;-F96)YR_KJtk>uV0L7yq=b1vy(=epG)8k^&NFGwF>w@TvcR)?JHR)uig>d>1SU$;8sT(?ReeNN*gN%RiPJkdKa zU83=~Et03z{z;L&&UW;Kcw6LUNo}!hkyjPk71<}L6**s5Xjf#vq+PKWB5z9C1A0qR zab#cQ9fjVCyep|R^2f+~l8PgLjl8drDEz&o(uh^~2T8?|!ooi))V1&fhp4xD#h(=F zRj5*-_)zinFZ{DYLks_+&?$uSC?6NM%ge&*0p>~DJE7m5#`M)%~$L$5-W3WcWl z`WNa7l?F_OY70FI)fW~h)LiIu$liNU@p(m9p~805zcA8nyQq>=6CE7-tv1Vp?*fn% ziM8a(cWdEWdfxXgK4~w>R~}s>iH?INI>{&$v$G_MDT!lB(kP}Rj_Hye^9UJ*Vjd}p zVoKtek~pR$j_Hyevx|&EF^`f&F(vut6pkqi98(g< zbjglcB%@Hwqa{&HNgPuW$CSh|U80y?(cOt+@4+Rz7sT7`L6Yz7!uKsnya!3V2bb)a z$H*vD>SHBQsU>ktNgPuW$8^b#SuCSa%pQ^`rX-FjiDOFQm@e5dd&(#jvzH`_DT!lB z;+T>+CVg{D#mH;&-ra56$I(R@d+qoi;QK!`VcVp-ScozhVkDQ= zPA|cS!F7C=p3+MZ-xNFW!EOzoNdKyyhRC{;9>>SMH4*1p*fx3b4HiMF#ld!dFK7Ym z%T{~8|2lgp+9BU2RQE@??sobFZf!N?BW|U4jIZXb<0HPwL+LHi!a|P|N9`dKxXnq` z9^&?mx49*4?yM`G z{d_Ve(6{kVVq+?(&u|CeUn ze60^ZlYIN5tmZt_s~ehc)%3$%z1!zC^_)nN4>hjUS3_~Un!_s^MeVKLC#p@YsynY?DP0q`_W;+_PElLN zJ_>doyF99`meAfxJ!;hEy7LNjI@(sp_q)*^zwP3qD@Hndaz-ICw_D5xztoX7Y?zQ3U!oqgyS zx_AR>h;jJ(JQLppPDfcye-mDly&m>@#U##S$3L8Y^V#RWuUB8f^*UUy?#*{;?7p2> z-ML?3w~X2*s_o^OK~4GJY#;7e*y-wMI&@B5gykKWL)mw6FS6Bc^MjA_O65#p&o=f< zWuHy{@fl1Lzv8{ydbne4AI&Q{=i!dj9=_joIPd>-`oS%KaI1FXqp*nQTlJ`Y8#`Zq zL!=PF6!!h4VX$>E0&0j$IlUva{YcNx03NXxW85pQgBFMfp_X`rNBuX?3qKgAiL)cz5nPCD&HS8V$V=kO^5IPzqud++_f zXRdIMNt3Aaj&8e z?%`_6KXWFz8@jKb0v zO9_?~zQKD1mN8hyW0{C$3YHXp?O+9#8CcH4G7-xZEGf|m>7B%EEOW3-#4-g-3crA` z0?YYW8pM&XkA!`s$cV16yNU%^mS8y_%OzMY$Fdwt3d>6ThSCZwS7W&x%W^C!EbFk$ z6GiY9;ddR1;46Z!2)-huAC2^*5%*|uBbGKS=VSR1mOJoU9xJfijpcGI%dwA!0rRP5A43M`@-%E zyPvoc%gtEs75!oNhut4`3G5QsC9q3jm%=WE?GyB#ohZ~RxYV>Z4 zIx#c)UD*BzrOd?pic-Aoot(ZHwx)GM`gg?&j$@&Yt2Iju5Z6G5i1pAD@oOG2l=>Oi zr-)miWnwpUBytAv8xXg_JC(gDXi%&XcR{Za_i4IVD}Dp}I$Vth#Sg@z&<)~o=tg`G zeo)*det|fT^R_=@?V-_LdTUgMe%dw2Q>NVp9mhJIHKo0blzP~@cuD&$RMUS0jT&U1 zWRTr#l3w7Ul(inR@AZyAi%J#sQREa<7mIzAz5*H)Kjic+oPL3y(kBE+rv^!X z7$WT-Ax##N`eLL-9VmWThu>&DF@mSyTiFAmYqSJotp~KLsDKuu#Y*rC9+j{Mi_4)W zi?z@Sd?!zdI9)sitrBO)O2pZ$wPFtJ`K(!yiw(wzelS)cE<~IP%p0q<(Y&uJq@RoL z3a9j1POlZMqP0_!)3dCt>}_Q)eBzEy%Q*e}tT#g+jBR53e%5W`SaEOc3DzB)@*L-R zgH!gyzBhJ&(?8^NL!KVq}^FqSxiw%vXt zX^$?X`&rGSIE6LAx|DSz>;9uCT92+2Egq+6@nbfNJ{^`GLtAY;meedJ-Ojq7)$GAB zS?gGrvTpA|(afF{ZQF4aZCmfnVrGZBz8v9r-l`wltovEb{+!NQ$GVhtdw-5rLeXXo zplGuOZWiC~P&b4l4CSqcvCX=l)jWaIS?gGrvTi?tqn*e#9nLj9d9!%3!~Rn#|NarA ziE_4C&5<03HNm=+btCKkk=$;hC|dbx6m8>J%DTm9)l|-<)l^O~ zb+h=aLt;8do4P$OKIEkWqXl-7V8GqZLIrP#d7k-S!c1fux?=8#=4I+eg)+$XPw2`!n%QV zAFKEdM`JB#oyEF=bsOtGR~aoUvrdL)OkOrm{+|kmUT9- zqLdz2@o{0TV_kX`wg2|3sQouy%ii^*=JljKSQD&utV>xpUe8DTdfICHjg)ig2G%y3 z)wi>nw~(D+UCO$h)!fMGtV>z9v-{{XIuqqc$KZ=6?Fiw(>me`_E=o0p9E_Z zUhPiCtK7MGbz3jGiY#8GUd*pfkH&AibjPckI9`SI#4DIycr|()Uc>apE7CsVPP|gQ zTlB-v@Aen>;T7Re@JjHf*jvVI!B1Hl{^ih{EYj{C(z+n&`T*&W(03_4OzLG_Zmfnq zJ#Y=QV}!JbwT)A{dnjc++v7~y>TzQ|w2%KrXm8&w(CGovs7cx}LR!Sy#_8QXl(L>} zH^Oa5d0nSC@3DTy>c+ea>9+?+r?Y;}8Z{}UV}!JbwT;uednjc++iv{(kfO%FkK;eC z>}wC(59?Ht4_TjKeTvmC$@IX3@OF%l7O}Q*N_P*XtY_QZte>&EF`q&D?E%v1te>++O-kt)AuVEUocrRvDzgW5%~?g&qZH@{s-&v2K9$NvLT7KHu+-4y;D+J5ik9img& zs#zOYuVEdj8+dwK!+HhlF{}qi7!k3Mvj^8J@JXHYgg1b&S?grq8DKTr&+}2G*Fv}G|b=)u@JY7uSjr(CctNNyoju3PipM zs*7I>`rX&(#A(py#W?70+#}J&3n-~BUPKvnu?MBYT_BW87r((>C|&FoXF^{_>2&v?E&aL+Jn%0wTGei zY5xJeU)uuxiMAE`fc7}_r`i+H2elp0hqNc54{JYzKBD~sx=s5f%JVoBZK6L7?WsSD zlwMG@iT)hy-ca1x*LOqv>Mue|@Ow;}D21ZG>3gA*^;eK`1{D2Ge+_mORL8vWTj*5% z4d@L00MgHf>f%!UchDC7ZRlnCyU@$^_o1!&AD~P151`BR524HTkDyoRA4AvZpCH0j zP#wR5`x)$=P+dH!{|)w2P+j~?{}TFhUDMF(bVJj`3sBtaGd!^UP+bJ@`#G8jLUj?s z@8xJB4An)%2*56c(mlx#>=;xR9gGOiyMso&>tA3&|8gxNWTq=@nsB#?lFc!UouXB{>C^7y4N@v`m#|5eZ?37 zebpEVea)zV?lVS1e`lPAIB!95r_>w=Ej3Sv4mKx1hnkb1Cz)qJPd2NdBh0DLk>;7u z(dKmMY3A9`)6H|C6U>>=DP|3{+N_11WhS9B%(>9>%oKE%IUibQ)>dWm%sv<2SY;&OQV;B$%nq2GbGk5~zBAF&GFKH^Gv`--dK?JKT< zx35?SZ(ng8ynV&>@b(iM;O!^c;O&Rcq?JK`1aCia8@&C+o$&S-cf;FX+ygJJRN?I} zegbcacnIDS@d&&n;!$`@#AEQ5;1`UCVn*K%Z>iV`Z>e|+-cs>%cuU1Dc#lEZOYuyq z3{L|p@jPh`X3(ryin;y=;uf(P*TawCF8`C_mzc+2#*F)}_>=fl6lh_svv#!BQ|qq{ z)ylLn+61jyJ6o&O&etx`7HXGhW(z&z)3CUI^qb!JT)6yOu6>FpdS6W&jVHsnR=`=X zC(e|;&<~D7FX)XvKs}%@j{ouax%htQ0sV3OOK|i{aqQ{OFYe@>1)X)+Sr=lh!CxrW zu|MXd55gLsPQ}^Si}$2>aX#iHD*q&n>lmX0C8~Q2}nG(cIM1P zD%+H$z}%+oO!6MLkEg+Rn4>OQVUXbHM7&nSp&ty=5*RI$5k}eH`QcZa&~QJ z8#nrb=9--28k0(=vFXU#T&l4F#<`FIgli3{1$`r2_ z4HSz9iX{UNQKeyn4v~1`ATg~b-JGm$ZbHciQT*DPrfhSXS_hm+ad~PoiveTOjWs#s zX@D#mBo+@6OAZxt=-@-_XxLzNM}zHHgDKWvv1qVZJXkDgmt%;XV+iFKA{Gr1i-(9M zLkvuRXs*jEzahW^(Esb ziE7^BtTXM^bbIZr&YIz%v&O3SEGMI=oo-t*oCJG4eTJx=Ar{clo;g!A&8)#vOHxZfVpIDQdBn1 zb!vk6TqEADqNa9UQjBh>8`rR)aeh*aO3qC+IQF=TbYnx3CIC6G*``^iF>9w+XHqo{ zb7?>_SKuh+k`<{;EjAk2Fc)g)fH4{KO#Q@~`lO&4$F>s4U7bRb)32s9H{=MZO4AzC zmavk4n}4&HH-6crX=T}n>Jutb2?Mr<)-kNx9xI%l zOU+KDQ#r*ul8!BPLLL@0UnDU7EkMl{VCc}OufjAXYNd5%CY7_(7D_8iStiuv=FQ;| zIkqN^E3{MtW*1Rkvxrt>(hy9c)s2`;X;Ot&BvF=zxnCL6CC)J>&zUuu23l7)R$;8b zsL#%|J38;DGTAUUH&3MP743C$N+6?XoP9oL7*$g{ALDLuLv2M(Iz5}H)-~iDSy7X# zN7uxBn3*re)YRgVAytzWDa@0!J_B=pCPkw=148@YRGyqm_81J}w7{f&8qa2#>UlK{ zlQMKQ#Hp2-KGh^NusTD{P-L2{(J;xH zdYl|wizYw}XIvn=298&~)5th8)MJu@-~?D*)9{tj6S~C~6Owh9v&Do|1D`Fi!XXut z8`F#DHu8pavY|0cTTN}i#nnWb5Gg?!v*;G{lYE6pj`q`cNfo*pod)f#5C#V&m%$-W z^Cssw=Vsc^$htZl7DU3C#Wvhaj?s&1lRUt263o^%HZ5d(jSCwDkCaTZx{*#DbYTjsT}i2W=pT^N8q=8Orcn9$sLV)aY-4H@b0V2+ zLWkvfrYZ*;S4B0s$9Lh2UNX)a^2|HxR_F2ric<6TlxM>6GoC|_S&o) z2gRD((3s^Uy4cDJenEmOA(_QF^_SRlaWaD=vmjNQ%sMAP99vu+1Nm@bpeA9{P{6#y z_P7SLXI-)i7ipNkQt)ENP_9j~a#Y$exCe0r+iIGLNsD6gr9zfwglTj|k(IBPXs*lR z%s*u2%-p;b$Css7Du^1?;XLA#%$x9T>E66O|mpO+oi!2io)78a&4;V zX&J>K!FkP8QZXSzH+L3R7}zGrBfHqY3Dmm508VH2ZuEU7Evb<;)mLDNEcA zhR#$nC5dCp$GS2($2O+W`ISb_xca7asy4;;=tYiAjWrchyBIf;&I{NcmjJj}=M`U9 zV}2Lhf~XT+H(+(BQaG;@)Y6>dUN_?9;Gk1WDw;DmSO2{mSD^>vwcX#lwL1-#D5DC) zuMy)qvzX4QxvveWw&_1sZh8%jN>ls(V*%WX{{s=eP36BKtl9u-*3;ArqLI1DjVT;a zn#K9-A*gfPR!u#fPVC{56N$#0n9>NLSU82!0pLl*wK=_JQ9j+VDWIsj0D_lP=$1J- z9Sx?d1W69?Y64zpPQIhe0IB-&Jkfs>=D&vh!vib)l*k%lu3KYpdu1p8}`4xi%ak_lI(JZKwGPMhfJ z#-61Yqv_Bvlw}FuMuU8L{=R`n-L!7pL*~=lmUWo*sxaf4W*KpOaU+aqlrZdx>slC! zgmKZgNjvcZE!wZ3Q>^8CT673IqeCc!?um<7%gv6b-1d}vI>mZu zL1(g6wv*Gq9!_%7S=VVr(X_<{m$90Vy-thLsz!_E zoFI#UXr7>*x(Fq$ap59lLC%&I>z)xaFOBZ@4>##c%I zH-~s)K-2M|Y#N z4(OA31Gli^g38@N_;9Q`#i+}X1064JXt8F?qTonFm81PaNDD^?bc(iIrbRDCcM78! zqC;SygK6B$qC*N$jvy-J73j7=S`|fy_=Q18|NO$VjiBxqdJ$zt2JFb<4z72ja&lM; zWevlPm|~24*G=0HmI~nr$!2* zk+8d9Y&un?9OEQfPAy4pYLJeaG%VT*?V)QHK8m14%cJE~x$>fDIaLlw|18@KVsAz? zK`FWqMZ_BUP{<&e*gVLanMBd@AjULmk3FN}CItNO zR8Oqjdcx#-VvT%UPng&o^~7eTy^&MT1lJQGbUPW@ITqK#-V98wgca8!5#?GWqFjqa zlxvZ2YLSq&V2f)pmTED!AZ}7ExEf=D2spMVI+m&dq<>Tmtf(3~8Srx9VcLa9X4B5< z6n-oh9vgCg&dw3I@b+e4F8o;gNQ|`$Kh`e%SiA6Jox+cmg=dQkUrB|pq|gC6ymY|ET=5vZ%XFCX){X*2sq0%buk250(85Y+MhFun}U!`5YO8Xd9+V!in>sRU2uafG=wVF(|noJ$bvTHOsI+zsqII)z0eQBH()ESga%$)5gU&|G#74=FmH=R{}Glr{@d0B%`$dYl!VMP->)6rDw7 z0n$Gz3mac83uZNnqDN;@At;Mo2(oCpqa?c!FsKl-WFcl@&jOb;7Zt_kp_O1znbN+v zm*=Kn(C?gSsD`eYkQPP^U&hdR)j}4kS2~)e!l!X9L4^m>KPo&MK|R*4A*nIbTzXOq z7grpT_ebrD|0o151aP8(&4o;3w{#iir4m!Y_&Na=H9hZz8iEX5(%F_>ejuY)M9YE_id$jznoyeP1 z5elEcP>4412yTitQ6o0t3XB>NNdKr2*`R)}72))SB!sS~Gg%WiViQdUWFio?24|<% zAj57ASaxf`z!$eio2YDVP4FHyH6ig8PNTO_sVEW~eELN~nht$a^dfteqf*fEMEgZB zF(JSFA0Xy~go6>coPHJzM&dzf)6kZkj6>&eU5!2DilRAc5Fq`d24N$pAH}`uXQn+o zsaLs6uCsJer*!{QJZeG&ahov5O_-y0Xhs*=?Lz|z7AkLd8EOXGvVuxCLSxA;MWsNwwCJLu=pt(V zMHJDXm2H}~5!7+8^D`J~z6j@UJ;-%l1hqK93R3lXQ>s20cJ*P|)rWyO8LnUu=S#cX zP#*yw*I?Y2Kay0Ui=r1%0WZSzLL~#zKRS491aFeOsMuuK#fD`U8wMS9l>387uw4TJF0%s}Zu zyT&#IP)RovRoD&<%Q30Fkyh@kd6Q3Dl9+E?2hBn__F+4ToUxYO(UzC&Z0UTqw3CgJJiRe>_cJYeiPjr0(R#xmDklqq zS2KhO!US1k$r?*mC0P($K@d(RoJ>|VS=D5n_q4|>WL3@aIc0O5}E$uB(?$2*JoaeWLQdB6iNe*Qj_Zu$s;PpKE+ zNolesn-q8-tBA`7pz+?ded2=#3>p;w$|fyWX`NO$r{oAtPBA&*n0C2HT8#XttN$`~-Vkd`>c% zjxTI%PS?ffCDTm^nT*%j&uG*=HQ{j~p0JnTO$JiDZ}vA&e**B@_5=ug{~<~PPY1^dnd+8hl&!1c7d zgKNK8>G*@++J*OPeZy9R53v>Azw`}T4LQVCczcx?jBkTFWC?NKchDiW8FJ#+Z*$1f z4fy(P4plb19f}Ua35P73y#G!2FAq^jyvIw7(8Tbs-`IKNd5GBi~a!p)ZjpsaZ z+-k@BapHB2$!x=MIrOm1{5bAfE{-ourqgy8U5LlG@ws@I=Q>iEy14!DAsbIM#A|UE z6!Vcjld|-oniB8J!&}tF()sj`%4$7?$Jvbwom;?okBsgc*MMh|c>GjH z*(y7Jb2gtQOn#6pI@|M7f&Fwc>!G(BWQ7Rejv&oecq_2zXlL=_Q7WD`nf$IrOx5sb4PZAIH1X=gD;j>;ONDzZjJB5Nc@BHLH@Ne``3I7{05lp%SF zqn%JZE(R4TAC5vbX=1+GL7HhAqDjZ;SS5C|@;iun_rbw!;0NIS;tS`cYUjo0)u3x+ zvv|T-5+8?dMP2CYy8{(R{?R>G^>6#zd3u%X@;s~7GfF-oX5v(kNT(;DbK*@HwKy*% z`TYpA#g{!1i7I^7 zVj4cZF$LB*d`@E`cpP*LZ2H?`{^1KdKAq3pclhFc;OxbXTuybsStYR65Vc0&X*WKt zk;bPt#^JkY=HPQ0^w)#8s)n})sag1IL=O2HLH6H0<~2C@_)G!P@vI%`c;CxGk(xNq z0My(5H$=>)HV^}}RoJ!y@#^s}iLLR#2Aci_{>ZkB}pL$ zl`A6_gLC+H8!B5I+{|T-b1CUtYbY9dhQS_ycPLYw21JkJ6Dw4c9GFUO@1YK!Bzy4` zo1@iY-3$wFm20;xwFVyhI_cx!n*$r~z=O3Ak(*)BUgmLH6D%ra5^LJS9BfTFsAPw( zQxkI3;?pyDZzu9&%ELFsgk^h?w*hsZh&8nx{Z%`yFcW>E0ckU3OA36m5iUaIu}Q$2 zMRYo5O(;YDn0~eGDQ-W37XWhGY1lS{t@GOqLg@x#!F-7QgpikdQI7L9pnP~kk1XX^ zn+Ksh)kcFoX~$w$DEo;y&!@r=0c6r48=z;rEBdy}n-_ai3Q8%Oh$VQ@MCc zHq($zG{x%@&CQv7e10;XZEcRHn&XwzX2hE^^~usu$luQiT{A(5D$NwRrFUKKp6zAP zCmzs72yr`7{B~;hx3DkA7RM$;G4FM|+>}7&=bv&-f+6Oupse)2uy@eTEw;TW#5A@w zakUKMIB6HxL=d~p$k$6r{z|i42usOifhQ|m+O#lL59Xr9VW2LBO2EcXxe((^^U1|| z*u8GG6Sz&hu$7;<5c5j2xojQM>^h(gD9=4gCYa^;Uz$y(GssAFqPp>U-A<=8{FLLo zZ2U+5*SEl>uYdl)QzsoVZsUD(_O-9=|LOnw3je2qom${8Sl8%>)+SweL~Xecwci&4 zE5kqa&(K@r6Wp5jTklZI11?zY3TY3h3JbdcoCor>>2rNs<|OY zIf85KrLgbJ8KM|At&x2v&74w+eH=Wx2Y7rsGoLc!M@Ml_J^bE)uRGuqZIr;C%6~Mr z;n-$jTY$BFfJcZ{*oR{y-@C{}`Di;7+fT5)h;1ykq1Y%Lv3ad5!rs0-yyv5IT42vB z`b*F&Mp&dhyw3$AqGyQG|HkRdz0X)kx8Cr3MW~4MUe=+kzwlDZ>#R3&%2>AV^HBO8 z55=ssj)vV9CjHz)dLiq}oH8jwDI&(evzu3k022Stk@6f&CXg>Bs zlX5QL^l^T&S98j_obpByrTobIlLDG>p7ZLSv zvDksw6JVP{L*^UAI{g&fyLiL~9RD;(fP73pbjZ&X*KA*a=~l-VMBHN0E4WUdiQ~e; zhcldIuG5!@BGHx4@MdhCz5+KOJ=ph*xh1#+NAwUEBj*$0Ey0;0Dk|AGRwG{wvxuTx z&eT<0#&ic$50sEf{X_qj;3?uTQKC`K3G6#e9Kp1PsYJ|U`VmuHbZB(GwHBSPpZI`% zIsNX~5^<#Hr&E+AOvA)9omyg+xI0GU{ye68O`9&@oC7>`+;DLb(}jMbk>XLNjE`uP z@EH_yCg(gs%wpP!C`&LeRx$005><$uh88atV*+P{uS7d^HHnU3nkY(`BA{o`Dg#U% zb+5tvTLBtk8aTr^ly#=4a;OphnW9>ZVBcr#n<|cGdVzh@#26+3a@L6POz*Jo6fv3U zNcK$^Q<-M4Z-$u0^axX}n8}1C0#Rm)Gni-*oQal8m;=Q1p(1^N_>mRBoH@q|Lr)4t zp#lFP(2F=FVV1ytI~IpN9q6Zfy`~Y?XSE4m9J6&=N8U*|9z#tq| z6C?c_t7?CCkdzahbSlr^Vx%>!w*A>bQcgtrthW34yf^4{_A7DrS#3Riq`g?P2HB%I z{+!^Ei2N;U1k|-h!yai+`teXrTogJMdS`enG{`BVSjVt7vmRqqz+2AR#@Y?)#(X$D z=zzznM-_8^Z-CDJGPm~V@FZz3K^fdOKPFU#^7jdo`k-EMONh#UONfrWC3FhwOxDv` z&xC#$O0Z3(x+QcrYcp$BuPMiH5bZth$2zBp0$qwy7wF1PL_Yd4__#Ha9@8#2*Xr~N zi+qo1E6kg9`#M5&o_UK-R~Gtt%yUlQPTgk%=*aMobY39Yx6bo3Js^D-#C*NVZxclDT((~FCAq3$2)EYXb#pw+4oSGD^EODpagcG#oT~xMi_=hl>^ZD~{_a zeIEDP;DQni1zQ7LH-XriQ5zSYKLNgbe*T@q(n*Be!m znxh+y8c7%UZZl>`s*l`joa&NwTHxo#97$awD)s6_8#?9e?NM{CRebH%ab{4)Y`3-; zj}!=_uDBCDVVvolomQKtjkyZ#H0HTv9qxbGNJtvw-)qcwh{ogAGGpo=LGcTz%xX);n^g>{yxlmH0|9xYr zr1IGN#(9!5@SQJdGkh0F+8OR?UMOiSa<(}{vtx{Tu|xLkxJ3Hi35_?GNgvIQ<&tQ2 zxI{BxvZ+$Fxk5&v`OxmrE811T(x< z^A<^`1ym|FRq7H^saGf3(CN6|9yRA$#b?h=_k1)rAD3ruw_ed7F$%tYo#+#lcoxf? zpeKyYP910#KV{yk(9^~p3hgxRbcyHm4^c1_>3b(M#Pf{w(VYIZB%0GM z*>hT@YV%nch352c9J1%MOZJ>D5Y6cV(VTXP=JW_pf!6q+HJ^84(wrXQ*(s?bHo~(@ zq2oNeCAA~xiwYg*c}dca*f`HCl6He$l~nB?=h-W14(N4Bt9;`;Z%XO_?UOVhGR5kX2JJk+dB?ucWPk?|X_QO)~HG_$Bo+AM}JIbwnTcL=@WLiArh>-r$Kz zdLi(} znfFvlOT(+ZvnBO1Z}grisUzCqovY9t-h`wV0{437OKSADdKXA4kF|OmBxT@hl(ZSX zl%$>E8@*>s8jGB1hiEoFzz8#ygjbyMum17 zH@n2M_&btl7O!`RuCV1r-<34WoK&JVqD_(}nX`*-k+d{iS9GhSUS?C#9g;et zi;8}r&_zXeOL`&DUUZM7M*pOuA4@8aO)C0{qzrubN!kqGPbKXPHx=D4X)JO+;1JE? z)kP0FWY6NCOW!-8>xv$dKAOc_B+)E($)3e3RhtjXC^U<=I%Lmcm+V{3-C6XUq}`yMlB)f87VVNW2eez#D&L(&FG}hFy(FnD^5ddc6ne1e4+?E7 zdR5YZ$dg5TB$Y*eU9?xBT}7`+8W4G<=ygd0efx^ukhD3V(rKOO(@s=usyVwvRO;1< zHgr0!w@1ynR`J<0+${^u@b_fN>=|D0(F`xp-JNJlC!*P3$hor<-KURM&hUOG+R=#~ zSBcjU8I#wLH=P!=*N}Y*eN^;Eg?1Y6yTmKX2a;$-`OqO+QT|@^v7}k1Y5iH!)B5KB1ka9k@oqGgsY>4m^?mLaLpZ(2o?%44QwNy@fmP)l;F~)S!D{fSfdnLWQ~?IAabE~ltL@4qa~F^uC$JkG$3+~b*xJmtv6f8DYVf#UQ#A} zvvq=`o1-^dV1>p&Mp7^HaqAR?p0;L4I@7n&nklI@c&{}}(yGvN z)~S+S2<)-WQ0Q%IuB0FMKeXy3mB(%~>J{2-H7azcm6Fux-)x<&(4E#fk~03=jI=_V ztrmsuw9b{ZIkwqy-xs}BY>wS&<)kkY6u!JdUf)7V-;WC4Vo8R1v$a$q;X6;#8IgOf z3nWcO>s}~nA$s~ENw16$;&HwM&|Un3uX_ofrxFE_0~e zdMp}M=-1I63f&3cN}2P1_zHBW5i~BBzNtZla7F0tlRnTO-<57o(9^~@UE=4$t0d8L zo2wn7Yrsg~8cDOvV}0L}v>m={ByA0p`@SuyH8|3@R?-WBZ}_g4)aXCfcax;@*s;Ew zC1v3Ij->Y3EZ=&E?A80b4!x$m6KeErls;O$H%X$^+a-JTR;k+TkWr2dH~YRPiPrL4 z9HKS3)u+-$zVA!l8vjV&ZIX5&=j{qz~yGK&H|1#gb3SH#;v7{Zb zt9|!L+6}s2(tyZX-vg4$BH#5rDCxw=_kBNi$R1e*qLEb~8d(p?oHViuL?dg9^wG$Y zgwb=SPo>_zhuxg;-RpZqp{I>UUE*=}m?Ro!k2^%;>_OjlNwdstzF$b%4&RfKwg#T^ zJte6%_@Hlxq!$7^eZP{_=-=l1jimC}Hs5oSGVnbwsXg`w-%f|@akk4L8fPE+ek*-6 z&UQWs%NdqD!{tpxy=>L#EJ4c@#>5KOeKT>F| z{*jwgJm4$!e=L1hdyet{+4WfiePb0mEud1dsZy7SO1(PKhEB)z_NY16D!z8h>kAt0 z+3C)>w@;-tp1(RJBj0%c-xaFz8;0|28@^Nhra}q7N1>+;uR=SGB9}1c&+%K52Klpo zpF=d}m-+*eW|@k0sLp0{^@%NHG8uKNRXw180k9n1<&E7H!jq<}KB?9;P3q}aj;BkBk#BO=}j=G=Bd3*2~e}Vd%zw1PQQ0T(goBsatxIpYZN$nzmC*-cL zU3?auFNtTP%t>Sf20Br$wbuBT;&U|aJv3&ce~3axV5p>y*eCu{g^a)mg+hTcN$rR- zS|KBFv_hf4v63)T1IJ6kOvR^v+_F^ry9G{^GzU~JX_c>AV7#ObP^Bcy@W4cc1_vf7 zG&(R@p_2kr6q*t^*`appoY3$5-;mTAnh_|_4dFNaRnoU9JUdVzy2?~bA6;c6Va9od zO7jCMWdl>)>z%+%f4%8^L4xer+%;H-DwF=!6n5EF{z^Mw&2%P2;&*IZ1(JY?r z(6wTl`P0B0NmH$d0%uB^Wj+=-OVW1u=1STccsejoQfu&`K%Jx)0=okBlFDO`1sWwa z`X39VBxOKnOWN(*6F5iGlfJhDX@~3?-sBL?@IMEdrH^KKMiR|%m+Tp?QnlG4qtFaL z*CBhRxmU@&|$%LNjqYF zgO^F#4Z2*?fXI=-D-{|Oyh@>};5QYT6I`WGGI+H@O~KU)wFcKHbbjz#4&hUedenD~ zq+xmwg(kuGZRx9quRsm(T`PS}@D=DP_^y+_Z^2if|X*+z6NZJ~B zDY#8iYw%aW$0fZGcnhBza;_GlJhn6Vl%z)g&fqU4Wk63$S{?f+xI|>Jri6AoXQw-XUj<*3vT8wyPcy`|8M(A$!B#Lfu)QPOVEdy)o3>O$`;lnH&H(9+O{3atoz zq|nu&j}^Kh^k+$Bkxik$NIEfcTj;M2wOf5L#|jkm6zEzpE_j#Bd9Cnb(AuNZJnHQb}6_>%!+rY7Jf$zEIK&fm^~CNh*(B z6J92%(SJ>Nxugteg{0N7d&2FKGO_L9%Ovggy%@e+(v!Zu;VT@nXaAKB(d>UOe3kUk zeE+5-n(r>z^IfHCbCrxj^Zjav>}#V-_O-DGSX! z=X`WEyefQ+q+Q7QZG}D$Uni*}_Hp=ng+348sE{vmlcaV;`Hn)Lhc_tXi)@s%BNmNx zNZJj$Mbd!CA(8JZ)IV~oLL(x#DRe^Qc7-NJ?og-(pDA}=YnMf4M}8n_pf3@*OVVip zm5NQ3xuo^gOF6a<@}5q9=@d6ne_M zSD~kkpD47`xX&fbzn6`lN}{K>_d7)MFBf@0(k%1*$b*u$!}oJZTLbNpha^ohzm3n+ zyLY2Y!|NlDO6rK-5qUzPpG1BksWq63JSpjgz(bLzBsKcakNiqfdF=eiGm4xyUgTv-?a28Dh2D$ok+dWB zN#r$2yFqVA8W1sy-%==8yiZbDq-*ipk_JS26~CiUzv4eiDvJy)epk|f$mrtt6gsK+ zPY%&&^@{fuI=NV-V)23EJEizTg-$R2SfP2ve^%)1;=d}CE&kM@+rX-H(k{$C98HHjVDv4rB@}-LF3`rbQ632AOj(M1jLNR+u zqL`96rX-FjiDSBC$1IUiC}wX-6jKt%l*BP5aZHyerdJ&9M6u7{l06FIoz5W1_jYmA zCyCD>iO=AY9rFkog-YE=5|vsK$CSh|C2>rb?3jIJ6pGnT62+9nF(q+KNgUH9J7#|w zg<=knL@_0COi3J5633+9+@Xor!}R+&eE9mbCML&R)y0YU(zL-|`wP;VsEv?!B)&fF z>V3$giBs__nMjL^F^~Mk#ky#PZHSee{GK#U(}NkS$ER=;_Kd;=*zXRZSrD; z2~sWgw+m-M3*cO~+UNcE*~g+C3T;Ale~{~Lr`K?6t0{lsR(i+yV$KHc@y#AeUluJc z_Be6g=Ju)Kv;2+Q{O_D%t2$=v-u$|~ri)uJHVknmj}W(QX>9D^wjGaNc6-Y87JBm^ z?RR@5s4?x7{l`ET9u>B#=RK6?h??^6vhBKmxvG7%e-9RV(-5Eir%y57{@t_q%X`!I z{-b^R#a=eWiT`7LtHo{KRlOop4{G?WG&DX7S7i5Ey#KuZx@&Ub zdO`7Nbp6*><9}t(9>G_i!WsX4SKhBvhOa-b_wUUw&RdroBu2G{P*_n7kj+( ziv891T3#dr8u)BBr3aDN^De{5(SA8|q z7q8~@Rd=u zsa197H7uoT!uGzwHMLXJma%)m&SRHHwbc^ZN2$F=ZLT}7K+V8mb93{WW+^_IlXs6*Zj4j(;%y>Z{Lx z->ANr>vgbEeI!4nvB!2nb?147-7;#MsJ4$+1~ujXXZv7%VW+FJ>A*R45tYws4rJfO zqsUgf&G+x+tCTB+z1r9-m3=k&=T|UIJi}+V^v;M1Bh9W-J;$wZ{CLHDG2my`|6k9mX{_U`T%KoFv9!vk7;|hx#el+n0uFLk1 zZFkm#jkiK;cfK;d`2X1$+rMqs^A%PtzkO%&FwY&;{yo08qKh}6hOoVAipFEfPN%cz zPM*RU51ulLBhP@k&))xg)(W>DFWv9DU_ZZA?|J6%)uG3J*9f&`{x94A%$lPKb+w6o z&2^^pT6EyMj{Vmb_b$3H-VT)VuUtv)#;9{gAlaHw^&eeH%J!S5|H{$$<*jOa?UiI9 zuN$@&o=dn-Bk7%>f9-n*YAdPNi$Z$mSE+WMgX!1lwg0(yde@`#>>MTtZU!SoMr| zU`=-C(Z9;JaIfMMF>EOj5-YJCimkVZz>bJM*al!5f~^!=3V(}WCAOon9gl4Ywo+^< z{8fUL*iOVY9@`LXrPxyV4c;rUO~iIGwyD^rV@u($9jwGQ8{1jfred3pEhV}ky_=Yi zZ2`8a*rsDk;V&Sp#CA5eX3-ONPuM+07Jt=XCANjwmSQ^_+lAOJ!Pbr~h3#_u4W*UX z)?m8?TRXNCwrjC9iW2xr@OK?b;46Wz1ilia_eOee#O*C^#`axoXJh*wwp;PHJXT`6 z6Wb-&+OefX9BFa<@uN8E9!K5dNb4`kux-G0H(Id_+XifRi-E8Q!X5~F5dH$dAlQRo z4~9J$_F&jUU=M*k1olwzO>7&m-7SW}9tL|D>{8gJuuEYNhdmtjaM(UUpV^5*z2Xq4 z9}&qO2`v`Kv5sS%!g>np>8uIX6zjRHOQ7Av#Za%f9!h^Xg6zT28R9r-v3N$@j^9~) z3hX5!p)JIxF2-r}X^VO>KY9i1P=r$E<8wtRKK6D_UjkdxdLjJ^v6AChsN*Wl5+lSl z(9z<0=&|BvErwFR2YZaz2puavf{sJZ5dH?lW_V|^Hw6uetHs^WYj6jyi*MskvxLN2 z@d$LCcnZ2+JO|w*eh=L&UPqjV`Pl8O{WLnuAdSi}RJ#Uw#%i0PQ&>-DO=*8aN)v3n zqSie4QzCn{PhfwflU-tveY#0{u7^^-?IHVaFWJv|$v(uQQbm0fIR(|l5+9|ngoeaT zocHz7?An8pZ(qR$OWHG5PMq1K^;*ag}iPj%8c%fb@0^+1-DdyT_=wYG( z+7~TWiof8|0(+GB9`pq9Q)q>F4Ehc6Hgtx#C{`-YV679E!#;;KC)UPBVV&3=s}ScQ zP6gJDRoVnT*9@dztk-dR9jDicW#ZOuNlwqPE@SU9_AZ0>nQkjM{adUXpu1xoZ2ypT zi|8Ysi#@{nD5pHjd0yp|J+PmP?d9|jINi`FzXxOCV!bch{n@TyyMpZrtaY4H$99r+ z1?xsm-^g|c>lTe_`Us~#!YPlkzRc;ba{8;B@~U>D_)E9FY#Tb2#L%fEhEC}ow&O_0 zcm3Ggms9$(w?EqxSnJqZ=h$>?lI>-jzRa;HeFfVaIenvJQ+fy6k8t`UY(L8SDyO{a z*pzcG+xRvKmDb?W8kFu~yDz8rXS;&!32fJ~UFX=8KgsqoPG9EOl)l`!0BajwkNRGaY`NA zN!DdZxmaJp_C}L>xr6OT*xrWUYp_atlv7^ils%lXms1Q6Tu3)>8 zy%RX4j#H9sFJpVT=UZs=6`Zn>Q##mwgzZP!e%V8#dMwV*I)OFGdNFi&Yz5mJ*zREaVYVM- z`xUnLvhDG49M%b}N!Ast9juSC?q&7(IX~+-)(Nah))lNBtdFwpW%UI3DAozAN!Ast z9juSC?q&4^IX~+J)+Fl+)=fd`(+;*DW!=jvLev+Y5Fg7rfi=mxg0+M7QP#bzB7B>8 zCFTj!QT@Ucxj)+zSd*;FIei7&9juiR%3064oOKiH9@aM_pNfaOo5hr;vY1BE@?z?j zE#0Vu_1!6bOZVGE&n|mJ(@XqAUjwDpHmwDs}Z#I!D( z;&kk`BRE1I(mkwZUru4IWL?g>iFHq3iq@|mmu(mF8f z7^kz=vo2@dHjJW~r4()62#Pju1i_*HSsf%-cktu9c^AL^+zr_|R`v`uvs zt!)8CYiqbo^zF9oY(AFNJcpyPnoS&swUV`-bvf($CT@Wyin*tWVs2STDO(oZCQ{uh z7t^uJmym8^-Nw3S$v$y>_dQDv71O$#OF911ed5gS{gzTnC8yN0E@$1el;bbu*1L$} zo0rg0mCH!$S(meJTDDIt?7nFk)pr}G>{&*~RxYPw%UA41{&}qHS+}sh%qrT+8)u!z z+Qzz`bqnjutno`JXF2OU);8AltS_^Q%QzZqIqN*u^{iW1UuG36IVbBp);8AltS_^Q z%lV9~^H|$h*RyV66<2T^)^gT)tZl4YSYKupS8`6)a@IE1^{iW1`>o=(y_$46>n7H1 zSML*7b>DXNq2fE;_i&22dY`zxySbWD`mN@EVXbFfzM9&9+iGh6P1mvadQ$TS(tfO! zto5wRSvTFlJ$?fnwe4ogxqLnAcWFJ}#%gXPyOMP|>o!(%6Q{E-XWho?$CEK3?!@1f zA}b_xyrK@^)pJ+8R_lX1_2XcT$E)2Myvl9BtJ@}Vn8@K(>IMAjv^W0Z;^BC86UVEt z{&)p50Ix;|;x)`5ydoWpKhZk`uSkcAyTmYY4_*=8i&ug_#@SlUP54umUjMDo?^>jN zJfsal(scpSV?sZm^f0N9b*1q`*mDB+L3>0<)5U`>8NeSgV3S=t)3YVKaUhO{*O5RHsxHq*?vH$l6=hiEbEi3c1h+0cEj5vLKr z^xFfZb67uT?P^j=j|gd;wS&|9cqnBZ+iv{7B1Mh=BaXjKIoEEsAJC~JAG1Eo`XsAe zlJSwx;C()7;GNK)vz8h(Dy9cX?RFa<@xlA$d5-jjk!MbTw5v(lBSIQy?cnr29!goq zw%=#R?}C&ip+ljY!*OWmvy=B2oyvA9>$$Agu~zB>kzUVwIcq=G{UeNz3`Nd?T(4pe zop=A3YP9YLiF2fHB;w2okajgmdqha%tR0-*$3rRW*mir0%5S&i-4Qzb_~K)baxgm| zIRRcf&%x|>BNWrl^VPP6zgDVat%^WtZ$Ntp540!VFU2zrJay9XG#~&yjMuha$g5%H zq9b}^h10NlMPbLW(rMxdsE$>y8+0-v>0%0E;9Dg)TF0}95@;2Uz|#-p)$t^-FLWAK zK3&ve-P7>QXCUm$u=e4}37%@`c+xivdIeTKU0jK$T{>3GQP6LSqoAwAG0>~A%IadZ zI03o_Pm=J-Byke-8az+Z@f@%Mk#B_R;%PAfx zeFe{2bnyqQ`}7Hw4D>B=F3PhHs^h6!4%$a+h4$4JLHlV-p#AYQLKg$H3!nqFi=czF zi=jicWjJ;iR2TEK70`rsDRjQJ5?ZHS0j<}rf+n?9&;{CRXoL1GXruORXiB>ddbV~w z^c+0l&_!Ci33{&f9YoGTb^N8+4bbmt8=<#o9nj6%Ezs|4--q6+-3Gl)y90W=_5(Z{!n`mdaw2n^hesm&>w4$K!2h=3cXKz9Qspj zJM@0-N$3{smnhG}P_&7@1KMAI1}OueXcPTe*n^8ZJ{*d1rSFE; z=r1DW6sRty>o38c0mXRJUxCilUxm)r_aglasE)sA`#Q8ue-nDKz7Kkd{tk4R{w{R6 z{wL@P{R3#b{t@(2{m;;=^}iy*YN(FCg8M1#$Dq1+T>m@lC!o66u73{wg|2BBT{`}x zj(8r5XMKhTwjZjCfKdcH2-QUheXoqXc@IaX569aRj_qLou6-zOdIo zF`JD3u&;sQ$)_<8_O(!5TxSf1y%wsA>y0B}-vHIcjm9wOI%7EW7GosRH$yRxj8V`R zjH95tjANj`HI9SsHco*4&KL`Q(KreEdt)5*C8GlRvM~Yrx-kiH-hkpssW}BY-24V~ zlvxcu%A5v0&O8Nrf;j_vk~tGP&O8-5!8{#0$vgx44f9NBwK*3$-Aq7h%{u65W)eEv zY=E9+rl9l8bD;HR6Lf)@(IS}LgRx4UtqsPSXX%5n+FcIqiuNCjHSaFyVPdLhFz)Vt z11%8?y@RpZEiD?1_3<-ke=*A%20hIh4xMd{gwC->LC>;|!oA;ocn64jcn63D@D31- z@D31X!#hwk!#hy4z&lW6;T-Uz4cE{AupxDwvM;+yae5o_QbBCdgVh`1KsA^0oNqo6myJ5;QPcPQ>NheJ16W1-)J zcc|D5?=W#YyuWIe8@$8C zWAF|aPry4|`~u$L;wgBKK-q`mJ*lyHH=qjdCoRAVniI>hrmqtl#cjABz8_Ed9~ZyG zdi^`Btoy|K;uBG%g|+TlZ>_&JOgl;&t4-9ZwOZ{Atxh{zJ6BtzU8tFD^gf;YSLJat z&40xk-wT&N?b_e*ULJjJsPNOSO~yOJ0)IC;^Uyn+I2E{EV5D z%ui@;ZAxYn`Aqi2`nhwD9&v!gV~}`a-Q2mAsa#7sv7{oM$mK?joO__GM~xIyX0*<) zPc2NO_^|RYa;KsCZ^J996GKppUO1Dm@+Aw zX>B2+BGa5tq?(gif*~6iY^mr6UherK8IZka%pFn3YJkCTm+; zQ1UX0UzcdfwWg_cz?CU3Pa?a7Ak&J1BU5v}Oe`)FOUlI30|h;5)B(PDHZG=Ut!0#LyPg5#buSGqblw6 zO50(R4V9vHf|#1j*3X?$J5kJ7lFKKXN~cW2?HrZlv{UWf>Gs~)oi^J+XOCUoX--B_ zce-uOb`tFU>9a-MY_X6!eC}M)GB<&(j-)=p`Nn0FwlSkMyC6}QWNw)|pR$tFVVhqk z#%1efB7*ovX^L}Hm zqP~9awC3t$E|+LXPEXdQk_(ZVO*Ul~CJ*4C=9rqvHYL)jrO4M@Ff%Q4$EWg(Qn}=~ z=6W$B32AL}n$zjbqA8hg%-BVln8_|mWKmL@!AarH<)oOD%ui0_8Y?nL zr4v^t8k$r2RuI;Mrj`PZTZrYPAt|ad4NgrEpKHX&RV3;flVU=1{gmc~nRAk2e6k_c z?ATK((wXKYtpRdwvrP+6CTFMDW>bmg2AY%173igWvLcnO!$ISk8=!U$7&TaGnx-b2 zl7bc;+p0wF+7yzUaW%cQIZsGcnw3doEffpw9i>cbMm@0Fh%^b8&Y8GNT9A-I~s)>JqtpWip*?K(U;HQ`M+}+@&WeusSEP z0*{`Xg$vArR6{G;{D46!lexNVs-?5DGPxju-mFHiB(sGR^L1oGI@y$L&eJf=6?LY@}1UQ}ZFTZo!1#MGf#KLg8@ zsFT*I*;L+6TO_Rj88n=c-Lak!i6;!z2?;xHz~LEr6KLxJPyk^jDM9$ha~zVUdF10$7`9{zB;q-C~RC zWIfhwQJre$t0i{mQc;shFKNi|fpoE)Y{vc7R9X-zL7B4{7Uv}SCXpPSm+#UU z7;1DGw2wjQC(7dY2uI?uTJdUOjS;mTqg?k&fJ#dS%Z;J66p>N3sExS%KN z=`xU0T?;UQFp@CH@)fv><_kV*xXR3;X2CNho2<>yrGxHGVRb4gRS)9>GAWbBGB=&d z&%H7`nYE3XEzFh4WD5o?uQN09uyI$^Vqbbi9bJG0UDa@XfK`>uw%}0^D(Tz=Ov@6W zfa%s8W+RY_I5CkGQ*gb4AxwK$nY&n!&UC3DUN5Pgfg zV<2}YCTbEkO$DqwY)@%Md)6ms;3f_0R|;ON7|Oj#PR>d@29F?)U|TJ7v1n0DzE#N4 ziZF}rD01>86RmYQT=_@Oottk=aeP^NrGltIJ#O?8=_NU2s!r8qGr7!yeCK3dO>(q2 z+oi!0io)78a&4;Vq^#nQ;Job0xwAGWuol?YNLeDK>k3^XXGMkUtyx^F|Ivf(E5bi~ zw7U$JDzggHFN1lVT|(E?{FjDQ+w`9+H@yf(rKx@Yxd3j(|A`1+r}AGBR&4+^>m>Dt zXk5M~lR}TuD$Z9AL4(`25>0eDv8PKOulw_2dImzVa0#Uj;6=o>IX$tsknY$NP|P?N zf|pbnmU+1xjiS2*Ne=L?8ZR`b;@(l%Hv?D#otsI4>mc1!irPf0NS@n@skR6g9)`)0w6pzfx*}{iVIbmpHm*!d)p( z+Gdo~Cc3+^SLr2aIy4MrSxQg9#HFu){=icw9Wrj?eRKA;ukHV-FyoqL8FBpLMi|j3 zVb~MbwJ;P3Q@q_`39XC3u9wzDvx#;|JMmmCI<%-;tnDf-I+~r)(G)`W#6_%agX0-v zd&YRW#rkO>Xi^J#kt^2Lfivsyw%wtHOnL_l+{-zt+&-$@!Act|9jvmkiep+F)3O6u zPL3KoM~#EEHr4`rY0+1P6Cs|9=)4x0MrPU`{JLY!1!vBz`+`9PV>uy~1>R(T?K778S_R}L^ zyj5BW!&h$I^<>?lzw4+fcTx^1=f|>UIU=Ilp+c0eD%XVJE%E61D7M!sLOGkX=m^6b zYt_AB!%JrL0^J)jy(lT{G1$sYFY51sa8jDEg)&?XXC<~OY&F~!9B5pe1ll9bj3;}#$C z7FJwPxw{A-`m3*S?P-bMni7cK3dM_#`hqX}FFx-e4 zro9jQSljim@CRV+7)7=b!k$xn!i-IhO%8>SVuZ-BgvtAmPk3x2M8zJ1c@rH&t%fXI z`L3EYEYv52y6c)1qKb@(j-iT-DT$7uiU8@KWt$;HHlpQ}qWe%B?2!)z3XzG!LwuM? z6de=797j!YW>gY|z=}b&M76jtoEcpbDzbY9#pj3|kdNn@+JV94cJV6hU6sA7v3Ipx zW(+kSmAzXG6_l1mZBR~aQ0_&yqP^&t@@P37Q(h7+r+NbEAJr2(x1KP$p4cNF*ApfV zM?Ga&vz+UR5W1a=>>P`0VIKyjR>F>JQ6A-5lt;N1$dR>Rd&2=5DH?TGh~Cv+NqxL~E!QH^Nl)CeZm2z%t?8o{({gu_hxAg4w(TqA_g?PMxD#p1Hthk?25HFnu+?6RZf zs9rU8*=wA#*T}NhQrT;1h@tG<9kq7W+LCB36&^_csPMEy;dL_Lsoz*FF zEf*OFa(>Rv5xB_qVPGzDtzG0=yU4Y6k!$TntaXZ9>l7JN!9=fH9-5UQs8xba;ML5q zXNh6g1Xq|6%o*K6hOjVk&83Tuvw)hERWHKz)WToD4hSta*~#F+>J~y=9LJqI$AbpK z%>i94u-;(d#18*0$KndiiO!)8pHmW@Lv046f7Bvu1a*9>2N#!zb-Fxa%|t$KojC}r zQ&=<-G!Ib#ZdrKAoEM!(WtmqJokwK>(myH- z8(%C7RyvBJN9R!?D2rVPvSs2V^ zcdkBEL)R>q7G@0J>duUq zN9~ILCvt8#{G?5Yd#A#1R1#Pvn{*+NWwsgrm6n$;iIXJ zjZ1@T)=&#^4!$6J2t)&svr}u3VYddX zAkSbJ_~q`=7Al)t6MT+MO(_2Yr!iWnR1}E~j4$4&sq0&!=i9qHm4f;cEg8YWg#7Y< zfS5Z8oe{U3aTW?i;z4QC)Ru#cL+5etjWgs+qIqf%ApN5TVI!m;%A;z#X-`iYRqmGW zE?qPz-TxGinh-(UCd_ja=BeE{DzzIKcDuo{M-dDfMR{cu**1?N+r;wk=19|k;#3|` zY;h;&aeIx~wiq{>(ZzQA&_sfT%G*PRn!&cLkTQ(WSaL{FDNrsgy0|2|n3{hvMKow< zo2G4qbaZxM1w+jj>p= z;C$*e4oAf%!!9-~yVx+O*UndZ&9=GMY?FJ=Sj%Zz z@EE7Qwg+AqHC2W^Roq_9LP6I=0^L90MFvd|)C?6v=c8TR14HoB%0THsyT&#IP)Rov zRoD&<%Q30Fk%ns!?|GVn`PLJA+y7K6RS10_wv)&iYkMx*w#&|zE@VqP*(k{~2ut@+ycWi5sX=&&HV6jM7_uOEg+o|Q zSWZ?YS(Ri}kp;mW1Yr$f4Oz8h)si*G1FNl#%y}ef?;xt4g=CB+FDbmplP2$C4+O7y z2Z>(TEK3vitLWbJaj06o`>EMP%hXJ>d<Oji#KUo@sQ2-(g&nqPl+!`Ce!gnnbvfD zyfK+>LC9ph-hLBDJyQ$bPsCgBrTAc%COl=OBTGjL5kgbCWy43cP~+)Iey=K%T{1J9 z9^9DEx8#l=KD;57Z)}}kT9;`WPW2mx&nyh1(loWZ84#c(S=9z9^Ya+oN<5-r|in;0-_5k;>M`?KdcL@ls*Z@z$1lymgH+IzbcVUtR~i<5zg6`v5h; z2MPrqvYqhdQEK_!wDf_R5+C2gC)vgFbLfMYwR#9|d1n?mkBRX)8r?Ug8Sh)-EvkCT zR@L>Zv-vb(@|)eFyS+3O+3#THJoJ%-oDcy#6y!&Am`PpjEMC0big%<;ep8VWaYrKb zaXEc_POr%6l{gBM7#BQxxQI_0i=K8CW8C|Gsic|ikK@kxz3 zTpN=7p#?hP^ZtnO#nY&v{$u~IYyo^%0rl#MHL!E_?9W|eMcFT%@=eBe8m@k$dD>8l zfIS*IOU%G`ZD!%yJJVrJ!S{5gf~PCjIG+@p z(($3E{UWt+o)P#BIQGBMVm>S(Mrc>!*b2mJ!oMVr#=C_`p9(vR-?K9pacdEee(z8Y zn!r|p?@Yx}k`!W4xw2vjIFH|ML}iPETe+-pE@d2_M5k!vIU4o|d_tY#G$VQ(-&mrW z|0^sbCR8orPjcE{!aQ7_!hv%$1h7P1>?|Cc#nFXh%22wIywQ0=$V;Or z&-t2BK75)>mhy}7OVJu>{G*=*;s_jDh2t9dC>j|ps3VoK0d>nG&;Ds~d<&rt-$ICs zGW2g5{>8tvCGh<~F5@&OF7-W?(H*x$c8h*lS