diff --git a/.gitignore b/.gitignore index b47618a..56f823e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,11 @@ -# Visual Studio stuff -*.csproj -*.editorconfig -*.sln +# Useless Visual Studio stuff /Nerd_STF/.vs/ + +# Build Stuff /Nerd_STF/obj -/Nerd_STF/bin/Debug -/Nerd_STF/bin/Release/net6.0/Nerd_STF.deps.json -/Nerd_STF/bin/Release/net6.0/Nerd_STF.dll -/Nerd_STF/bin/Release/net6.0/Nerd_STF.pdb +/Nerd_STF/bin +*.dll +*.pdb # Testing project /Testing diff --git a/Changelog.md b/Changelog.md index 59234c9..f0ca60f 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,4 +1,4 @@ -# Nerd_STF v2.3.1.39 +# Nerd_STF v2.3.1.52 ***Read this to know what works and what doesn't!*** @@ -25,11 +25,23 @@ The following types have been checked for the most part and can be safe to use: - `Nerd_STF.Exceptions.InvalidSizeException` - `Nerd_STF.Exceptions.Nerd_STFException` - `Nerd_STF.Exceptions.NoInverseException` +- `Nerd_STF.Extensions.Container2DExtension` +- `Nerd_STF.Extensions.ConversionExtension` +- `Nerd_STF.Extensions.EquationExtension` - `Nerd_STF.Extensions.ToFillExtension` +- `Nerd_STF.Graphics.CMYKA` +- `Nerd_STF.Graphics.CMYKAByte` - `Nerd_STF.Graphics.ColorChannel` +- `Nerd_STF.Graphics.HSVA` +- `Nerd_STF.Graphics.HSVAByte` +- `Nerd_STF.Graphics.IColor` +- `Nerd_STF.Graphics.IColorByte` - `Nerd_STF.Graphics.IlluminationFlags` - `Nerd_STF.Graphics.IlluminationModel` +- `Nerd_STF.Graphics.Image` - `Nerd_STF.Graphics.Material` +- `Nerd_STF.Graphics.RGBA` +- `Nerd_STF.Graphics.RGBAByte` - `Nerd_STF.Graphics.TextureConfig` - `Nerd_STF.Mathematics.Angle` - `Nerd_STF.Mathematics.Calculus` @@ -41,32 +53,13 @@ The following types have been checked for the most part and can be safe to use: - `Nerd_STF.Mathematics.Int3` - `Nerd_STF.Mathematics.Int4` - `Nerd_STF.Mathematics.Mathf` +- `Nerd_STF.Mathematics.Geometry.ISubdividable` - `Nerd_STF.Mathematics.NumberSystems.Complex` - `Nerd_STF.Mathematics.NumberSystems.Quaternion` - - With the exception of the following methods: - - `Quaternion.FromAngles(Angle, Angle, Angle?)` - - `Quaternion.FromAngles(Float3, Angle.Type)` - - `Quaternion.FromVector(Vector3d)` - - `GetAngle()` - - `GetAxis()` - - `ToAngles()` - - `ToVector()` - `Nerd_STF.Mathematics.Samples.Constants` - `Nerd_STF.Mathematics.Samples.Equations` The following types haven't been checked yet, and should still be taken with a grain of salt: -- `Nerd_STF.Extensions.Container2DExtension` -- `Nerd_STF.Extensions.ConversionExtension` -- `Nerd_STF.Extensions.EquationExtension` -- `Nerd_STF.Graphics.CMYKA` -- `Nerd_STF.Graphics.CMYKAByte` -- `Nerd_STF.Graphics.HSVA` -- `Nerd_STF.Graphics.HSVAByte` -- `Nerd_STF.Graphics.IColor` -- `Nerd_STF.Graphics.IColorByte` -- `Nerd_STF.Graphics.Image` -- `Nerd_STF.Graphics.RGBA` -- `Nerd_STF.Graphics.RGBAByte` - `Nerd_STF.Mathematics.Algebra.IMatrix` - `Nerd_STF.Mathematics.Algebra.Matrix` - `Nerd_STF.Mathematics.Algebra.Matrix2x2` @@ -76,7 +69,6 @@ The following types haven't been checked yet, and should still be taken with a g - `Nerd_STF.Mathematics.Algebra.Vector3d` - `Nerd_STF.Mathematics.Geometry.Box2D` - `Nerd_STF.Mathematics.Geometry.Box3D` -- `Nerd_STF.Mathematics.Geometry.ISubdividable` - `Nerd_STF.Mathematics.Geometry.ITriangulatable` - `Nerd_STF.Mathematics.Geometry.Line` - `Nerd_STF.Mathematics.Geometry.Polygon` @@ -85,134 +77,74 @@ The following types haven't been checked yet, and should still be taken with a g - `Nerd_STF.Mathematics.Geometry.Triangle` - `Nerd_STF.Mathematics.Geometry.Vert` -I've checked a total of 39 types, with 29 left to go. It sounds like I'm over halfway, but really I've saved all of the annoying ones that are likely wrong to be checked next. My 39 done includes a bunch of really simple types that never needed checking in the first place too. But there are some done, like any type in the Mathematics directory. +16 left to go. + +Honestly, most of the time taken for this update was spent on Quaternions. Turns out my multiply function was subtley wrong. Who knew! +Just a relief to be done with it. The other stuff wasn't too much of a problem. Matrixes are probably going to be a huge pain if they don't work first try, though. That'll be in the next update, probably. + +I should also note that I just realized after way to long that the `.csproj` file isn't included in the Github. It's included in this new release, and sometime in the future I'll go back and add a correctly working `.csproj` file to all the other releases as well (with the exception of the legacy Nerd_STF 2021 versions likely. We'll see). I'll now not include the `/bin` build files. They'll be in the release and you can build it yourself if you need to now. Anyway, have fun. ``` * Nerd_STF - * Exceptions - + MathException - + UndefinedException * Extensions - + EquationExtension + * Container2DExtension + = Fixed `Flatten(T[,], Int2)` + = `GetColumn(T[,], int, int)` and `GetRow(T[,], int, int)` have been fixed (They had swapped roles) + * ConversionExtension + + ToFill(T[]) + + ToFill(T[,], Int2) + + ToFill2D(T[,]) + * EquationExtension + = Fixed `Scale(Equation, float, ScaleType)` by swapping all instances of `x` and `value` (oops) + = Moved `ScaleType` out of parent class `EquationExtension` and into namespace `Nerd_STF` + * Geometry + * ITriangulatable + + TriangulateAll(T[]) where T : ITriangulatable + * Graphics + + Renamed `IColor` to `IColorFloat` + = Made IColor an object both `IColorFloat` and `IColorByte` inherit from. + * CMYKA + = Made `ToRGBA()` include the alpha value of the color. + * CMYKAByte + = In `ToHSVA()` and `ToHSVAByte()`, swapped some conversions from `RGBA` to `CMYKA` + * HSVA + = Made `ToRGBA()` include the alpha value of the color. + * Image + - Removed some useless constructors + = Fixed some broken constructors * Mathematics - * NumberSystems - * Complex - + Inverse - + GetAngle() - = Fixed `ToString()` and all overloads from adding a redundant negative sign sometimes in the imaginary component. - = Replaced the `/` operator with a multiplication by its inverse. - * Quaternion - + Inverse - = Fixed `ToString()` and all overloads from adding a redundant negative sign sometimes in the i, j, and k components. - = Replaced the `/` operator with a multiplication by its inverse. * Algebra * Vector2d - - static Product(params Vector2d[]) - - static Divide(Vector2d, params Vector2d[]) - - operator *(Vector2d, Angle) - - operator *(Vector2d, Vector2d) - - operator /(Vector2d, Angle) - - operator /(Vector2d, Vector2d) - = Made `ToXYZ()` actually work - * Vector3d - - static Product(params Vector3d[]) - - static Divide(Vector3d, params Vector3d[]) - - operator *(Vector3d, Angle) - - operator *(Vector3d, Vector3d) - - operator /(Vector3d, Angle) - - operator /(Vector3d, Vector3d) - * Calculus - + GetDynamicIntegral(Equation, Equation, Equation, float) - = Made `GetDerivative(Equation, float)` calculate specific values on the fly, and removed the min/max. - * Graphics - * HSVA - - static LerpSquared(HSVA, HSVA, float, Angle.Type, bool = true) - - operator *(HSVA, HSVA) - - operator /(HSVA, HSVA) - * HSVAByte - - static LerpSquared(HSVAByte, HSVAByte, float, Angle.Type, bool = true) + = Removed a default parameter value in `ToString(Angle.Type)` to prevent confusion. + * Vector3d + + string ToString() + + string ToString(Angle.Type) + + string ToString(IFormatProvider, Angle.Type) + = Fixed `ToXYZ()` + * NumberSystems + * Complex + + operator ~(Complex) + * Quaternion + + Rotate(Float3) + + Rotate(Vector3d) + + operator ~(Quaternion) + - ToVector() + = Gave `IJK` proper get and set accessors. + = Renamed some terms in `ToString()` + = Fixed the `Quaternion.FromAngles(*)` methods to do the proper thing. + = Fixed `Quaternion.Rotate(Quaternion)` + = Fixed `Quaternion.Rotate(Float3)` + = Fixed `operator *(Quaternion, Quaternion)` + = Optimized `GetAxis()` + = Simplified `ToXYZ()` + = Swapped the order of `Rotate(Quaternion)` + = Made `GetAxis()` not accidentally create an infinite vector. * Angle - + Reflected - + static Max(bool, params Angle[]) - + static Min(bool, params Angle[]) - - operator *(Angle, Angle) - - operator /(Angle, Angle) - = Made `Angle(float, Type)` use a lambda expression - = Made `Bounded` use the `AbsoluteMod()` function instead of the default `%` expression - = Replaced an accidental `Mathf.Floor()` call with a `Mathf.Round()` call in `Floor()` - = Made `operator -(Angle)` actually give you the reverse angle (not the reflected angle) + + Complimentary + + Supplementary * Float2 - = Made `Median(params Float2)` not use an unneccesary average - = Made `ToVector()` not create an angle out of `ArcTan(float)`, as it already is one - = Optimized `Divide(Float2, params Float2[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float2, params Float2[])` to subtract a sum instead of individually subtracting + + operator *(Float2, Quaternion) * Float3 - = Made `Median(params Float3)` not use an unneccesary average - = Made `ToVector()` not create an angle out of the arc trig functions, as they already are angles - = Optimized `Divide(Float3, params Float3[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float3, params Float3[])` to subtract a sum instead of individually subtracting - * Float4 - = Marked `Far` and `Near` as obsolete/deprecated, as they have been replaced by `HighW` and `LowW` - = Made `Median(params Float4)` not use an unneccesary average - = Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting - * Int2 - = Made `Median(params Float4)` not use an unneccesary average - = Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting - * Int3 - = Made `Median(params Float4)` not use an unneccesary average - = Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting - * Int4 - + LowW - = Marked `Far` as obsolete/deprecated, as it has been replaced by `HighW` - = Made `Median(params Float4)` not use an unneccesary average - = Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing - = Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting - * Mathf - + AbsoluteMod(float) - + Binomial(int, int, float) - + Factors(int) - + PowerMod(int, int, int) - = Fixed `Ceiling(float)` from rounding up when it shouldn't - = Made `Median(params float[])` actually calculate the right midpoint - = Removed two unneeded `Average(float, float)` calls in `Median(params float[])` - = Replaced the `Floor(float)` and `Ceiling(float)` calls in `Median(params float[])` with a better alternative - = Replaced the mod in `Sin(float)` with an `AbsoluteMod(float, float)` call - = Made `MadeEquation(Dictionary)` actually work. - = Added caching to Power(float, int) for the absolute max - = Fixed an if statement and added another one to prevent extra computation in `Power(float, int)` - = Added caching to Power(int, int) for the absolute max - = Fixed an if statement and added another one to prevent extra computation in `Power(int, int)` - = Made the `Lerp(int, int, float, bool)` function not call itself infinitely many times. - = Replaced a multiplication with a division in `Root(float, float)` - = Made the `Average(int[])` function give you the int average instead of the float average (unlike `Average(float[])`) - = Replaced the float return statement with an Angle in `ArcCos(float)` - = Replaced the float return statement with an Angle in `ArcCot(float)` - = Replaced the float return statement with an Angle in `ArcCsc(float)` - = Replaced the float return statement with an Angle in `ArcSec(float)` - = Replaced the float return statement with an Angle in `ArcSin(float)` - = Replaced the float return statement with an Angle in `ArcTan(float)` - = Replaced the float return statement with an Angle in `ArcTan2(float, float)` - = Optimized `ArcCos(float)` to use presets - = Optimized `Divide(float, params float[])` to use other functions. - = Optimized `Divide(int, params int[])` to use other functions. - = Optimized `Subtract(float, params float[])` to subtract a sum instead of individually subtracting - = Optimized `Subtract(int, params int[])` to subtract a sum instead of individually subtracting - = Made `Clamp(int, int, int)` not remake code and use `Clamp(float, float, float)` - = Made `Lerp(int, int, float, bool)` cast to an int instead of flooring - = Made `Lerp(float, float, float, bool)` not break when clamping and A is greater than B - = Made `Median(params T[])` not use an unneccesary average - = Made `Power(int, int)` not care about absolutes - = Made `Variance(params float[])` correctly calculate variance. - * Quaternion - = Made `GetAngle()` not create an angle out of `ArcCos(float)`, as it already is one - = Made `ToAngles()` not create angles out of arc trig functions, as they are already angles - * Samples - * Constants - = Swapped `DegToRad` and `RadToDeg` - * Equations - = Moved `static Scale(Equation, float, ScaleType)` to `EquationExtension` - = Moved `ScaleType` to `EquationExtension` + + operator *(Float3, Quaternion) + = Fixed `ToVector()` ``` diff --git a/Nerd_STF/.editorconfig b/Nerd_STF/.editorconfig new file mode 100644 index 0000000..1c2dc1c --- /dev/null +++ b/Nerd_STF/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] + +# CA1050: Declare types in namespaces +dotnet_diagnostic.CA1050.severity = warning diff --git a/Nerd_STF/Extensions/Container2DExtension.cs b/Nerd_STF/Extensions/Container2DExtension.cs index 6a90731..a2cbc7a 100644 --- a/Nerd_STF/Extensions/Container2DExtension.cs +++ b/Nerd_STF/Extensions/Container2DExtension.cs @@ -5,20 +5,20 @@ public static class Container2DExtension public static T[] Flatten(this T[,] array, Int2 size) { T[] res = new T[size.x * size.y]; - for (int x = 0; x < size.x; x++) for (int y = 0; y < size.y; y++) res[x + y * size.y] = array[x, y]; + for (int x = 0; x < size.x; x++) for (int y = 0; y < size.y; y++) res[x + y * size.x] = array[y, x]; return res; } public static T[] GetColumn(this T[,] array, int column, int length) { T[] res = new T[length]; - for (int i = 0; i < length; i++) res[i] = array[column, i]; + for (int i = 0; i < length; i++) res[i] = array[i, column]; return res; } public static T[] GetRow(this T[,] array, int row, int length) { T[] res = new T[length]; - for (int i = 0; i < length; i++) res[i] = array[i, row]; + for (int i = 0; i < length; i++) res[i] = array[row, i]; return res; } } diff --git a/Nerd_STF/Extensions/ConversionExtension.cs b/Nerd_STF/Extensions/ConversionExtension.cs index 83c9c3c..3aa2ae0 100644 --- a/Nerd_STF/Extensions/ConversionExtension.cs +++ b/Nerd_STF/Extensions/ConversionExtension.cs @@ -10,4 +10,8 @@ public static class ConversionExtension foreach (KeyValuePair pair in pairs) res.Add(pair.Key, pair.Value); return res; } + + public static Fill ToFill(this T[] arr) => i => arr[i]; + public static Fill ToFill(this T[,] arr, Int2 size) => arr.Flatten(size).ToFill(); + public static Fill2D ToFill2D(this T[,] arr) => (x, y) => arr[x, y]; } diff --git a/Nerd_STF/Extensions/EquationExtension.cs b/Nerd_STF/Extensions/EquationExtension.cs index f39faf6..b3b82d8 100644 --- a/Nerd_STF/Extensions/EquationExtension.cs +++ b/Nerd_STF/Extensions/EquationExtension.cs @@ -4,16 +4,9 @@ public static class EquationExtension { public static Equation Scale(this Equation equ, float value, ScaleType type = ScaleType.Both) => type switch { - ScaleType.X => x => equ(value / x), - ScaleType.Y => x => x * equ(value), - ScaleType.Both => x => x * equ(value / x), + ScaleType.X => x => equ(x / value), + ScaleType.Y => x => value * equ(x), + ScaleType.Both => x => value * equ(x / value), _ => throw new ArgumentException("Unknown scale type " + type) }; - - public enum ScaleType - { - X = 1, - Y = 2, - Both = X | Y - } } diff --git a/Nerd_STF/Graphics/CMYKA.cs b/Nerd_STF/Graphics/CMYKA.cs index 65809f0..7b4a3f8 100644 --- a/Nerd_STF/Graphics/CMYKA.cs +++ b/Nerd_STF/Graphics/CMYKA.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Graphics; -public struct CMYKA : IColor, IEquatable +public struct CMYKA : IColorFloat, IEquatable { public static CMYKA Black => new(0, 0, 0, 1); public static CMYKA Blue => new(1, 1, 0, 0); @@ -165,7 +165,7 @@ public struct CMYKA : IColor, IEquatable return (Cs, Ms, Ys, Ks, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKA()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKA()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKA()); public bool Equals(CMYKA col) => A == 0 && col.A == 0 || K == 1 && col.K == 1 || C == col.C && M == col.M && Y == col.Y && K == col.K && A == col.A; @@ -174,9 +174,9 @@ public struct CMYKA : IColor, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(CMYKA)) return Equals((CMYKA)obj); - else if (t == typeof(RGBA)) return Equals((IColor)obj); - else if (t == typeof(HSVA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(RGBA)) return Equals((IColorFloat)obj); + else if (t == typeof(HSVA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj); else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj); else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); @@ -196,7 +196,7 @@ public struct CMYKA : IColor, IEquatable public RGBA ToRGBA() { float kInv = 1 - K, r = 1 - C, g = 1 - M, b = 1 - Y; - return new(r * kInv, g * kInv, b * kInv); + return new(r * kInv, g * kInv, b * kInv, A); } public CMYKA ToCMYKA() => this; public HSVA ToHSVA() => ToRGBA().ToHSVA(); diff --git a/Nerd_STF/Graphics/CMYKAByte.cs b/Nerd_STF/Graphics/CMYKAByte.cs index 92ce249..ee85963 100644 --- a/Nerd_STF/Graphics/CMYKAByte.cs +++ b/Nerd_STF/Graphics/CMYKAByte.cs @@ -143,7 +143,7 @@ public struct CMYKAByte : IColorByte, IEquatable return (Cs, Ms, Ys, Ks, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKAByte()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKAByte()); public bool Equals(CMYKAByte col) => A == 0 && col.A == 0 || K == 1 && col.K == 255 || C == col.C && M == col.M && Y == col.Y && K == col.K && A == col.A; @@ -152,11 +152,11 @@ public struct CMYKAByte : IColorByte, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(CMYKAByte)) return Equals((CMYKAByte)obj); - else if (t == typeof(RGBA)) return Equals((IColor)obj); - else if (t == typeof(HSVA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(RGBA)) return Equals((IColorFloat)obj); + else if (t == typeof(HSVA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj); - else if (t == typeof(CMYKA)) return Equals((IColor)obj); + else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj); else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); @@ -174,11 +174,11 @@ public struct CMYKAByte : IColorByte, IEquatable public RGBA ToRGBA() => ToCMYKA().ToRGBA(); public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f); - public HSVA ToHSVA() => ToRGBA().ToHSVA(); + public HSVA ToHSVA() => ToCMYKA().ToHSVA(); public RGBAByte ToRGBAByte() => ToCMYKA().ToRGBAByte(); public CMYKAByte ToCMYKAByte() => this; - public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte(); + public HSVAByte ToHSVAByte() => ToCMYKA().ToHSVAByte(); public byte[] ToArray() => new[] { C, M, Y, K, A }; public Fill ToFill() @@ -216,12 +216,12 @@ public struct CMYKAByte : IColorByte, IEquatable public static CMYKAByte operator /(CMYKAByte a, int b) => new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / b); public static CMYKAByte operator /(CMYKAByte a, float b) => (a.ToCMYKA() / b).ToCMYKAByte(); - public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColor?)b); - public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColor?)b); - public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColor?)b); - public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColor?)b); - public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColor?)b); - public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColor?)b); + public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator ==(CMYKAByte a, RGBAByte b) => a.Equals(b); public static bool operator !=(CMYKAByte a, RGBAByte b) => !a.Equals(b); public static bool operator ==(CMYKAByte a, CMYKAByte b) => a.Equals(b); diff --git a/Nerd_STF/Graphics/HSVA.cs b/Nerd_STF/Graphics/HSVA.cs index 455b833..222a28a 100644 --- a/Nerd_STF/Graphics/HSVA.cs +++ b/Nerd_STF/Graphics/HSVA.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Graphics; -public struct HSVA : IColor, IEquatable +public struct HSVA : IColorFloat, IEquatable { public static HSVA Black => new(Angle.Zero, 0, 0); public static HSVA Blue => new(new Angle(240), 1, 1); @@ -159,7 +159,7 @@ public struct HSVA : IColor, IEquatable return (Hs, Ss, Vs, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToHSVA()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVA()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVA()); public bool Equals(HSVA col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0 || H == col.H && S == col.S && V == col.V && A == col.A; @@ -168,9 +168,9 @@ public struct HSVA : IColor, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(HSVA)) return Equals((HSVA)obj); - else if (t == typeof(CMYKA)) return Equals((IColor)obj); - else if (t == typeof(RGBA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj); + else if (t == typeof(RGBA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj); else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj); else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); @@ -195,7 +195,7 @@ public struct HSVA : IColor, IEquatable else if (d < 240) vals = (0, x, c); else if (d < 300) vals = (x, 0, c); else if (d < 360) vals = (c, 0, x); - return new(vals.r + m, vals.g + m, vals.b + m); + return new(vals.r + m, vals.g + m, vals.b + m, A); } public CMYKA ToCMYKA() => ToRGBA().ToCMYKA(); public HSVA ToHSVA() => this; diff --git a/Nerd_STF/Graphics/HSVAByte.cs b/Nerd_STF/Graphics/HSVAByte.cs index 8d2bb80..f7e5a08 100644 --- a/Nerd_STF/Graphics/HSVAByte.cs +++ b/Nerd_STF/Graphics/HSVAByte.cs @@ -130,7 +130,7 @@ public struct HSVAByte : IColorByte, IEquatable return (Hs, Ss, Vs, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToHSVAByte()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVAByte()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVAByte()); public bool Equals(HSVAByte col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0 || H == col.H && S == col.S && V == col.V && A == col.A; @@ -139,12 +139,12 @@ public struct HSVAByte : IColorByte, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(HSVAByte)) return Equals((HSVAByte)obj); - else if (t == typeof(CMYKA)) return Equals((IColor)obj); - else if (t == typeof(RGBA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj); + else if (t == typeof(RGBA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj); else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj); - else if (t == typeof(HSVA)) return Equals((IColor)obj); + else if (t == typeof(HSVA)) return Equals((IColorFloat)obj); else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); return base.Equals(obj); @@ -192,12 +192,12 @@ public struct HSVAByte : IColorByte, IEquatable public static HSVAByte operator /(HSVAByte a, HSVAByte b) => new(a.H / b.H, a.S / b.S, a.V / b.V, a.A / b.A); public static HSVAByte operator /(HSVAByte a, int b) => new(a.H / b, a.S / b, a.V / b, a.A / b); public static HSVAByte operator /(HSVAByte a, float b) => (a.ToHSVA() * b).ToHSVAByte(); - public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColor?)b); - public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColor?)b); - public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColor?)b); - public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColor?)b); - public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColor?)b); - public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColor?)b); + public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator ==(HSVAByte a, RGBAByte b) => a.Equals(b); public static bool operator !=(HSVAByte a, RGBAByte b) => !a.Equals(b); public static bool operator ==(HSVAByte a, CMYKAByte b) => a.Equals(b); diff --git a/Nerd_STF/Graphics/IColor.cs b/Nerd_STF/Graphics/IColor.cs index 1bdeeb4..3b7f701 100644 --- a/Nerd_STF/Graphics/IColor.cs +++ b/Nerd_STF/Graphics/IColor.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Graphics; -public interface IColor : ICloneable, IEquatable, IEquatable, IGroup +public interface IColor : ICloneable, IEquatable, IEquatable { public RGBA ToRGBA(); public CMYKA ToCMYKA(); diff --git a/Nerd_STF/Graphics/IColorByte.cs b/Nerd_STF/Graphics/IColorByte.cs index 1f3ab76..903293d 100644 --- a/Nerd_STF/Graphics/IColorByte.cs +++ b/Nerd_STF/Graphics/IColorByte.cs @@ -1,12 +1,3 @@ namespace Nerd_STF.Graphics; -public interface IColorByte : ICloneable, IEquatable, IEquatable, IGroup -{ - public RGBA ToRGBA(); - public CMYKA ToCMYKA(); - public HSVA ToHSVA(); - - public RGBAByte ToRGBAByte(); - public CMYKAByte ToCMYKAByte(); - public HSVAByte ToHSVAByte(); -} +public interface IColorByte : IColor, IGroup { } diff --git a/Nerd_STF/Graphics/IColorFloat.cs b/Nerd_STF/Graphics/IColorFloat.cs new file mode 100644 index 0000000..2978b35 --- /dev/null +++ b/Nerd_STF/Graphics/IColorFloat.cs @@ -0,0 +1,3 @@ +namespace Nerd_STF.Graphics; + +public interface IColorFloat : IColor, IGroup { } diff --git a/Nerd_STF/Graphics/Image.cs b/Nerd_STF/Graphics/Image.cs index f6a35b1..44200e2 100644 --- a/Nerd_STF/Graphics/Image.cs +++ b/Nerd_STF/Graphics/Image.cs @@ -15,12 +15,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable { Pixels = new IColor[width, height]; Size = new(width, height); - for (int y = 0; y < width; y++) for (int x = 0; x < height; x++) Pixels[x, y] = cols[y * width + x]; + for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y * width + x]; } public Image(int width, int height, IColor[,] cols) { - Pixels = cols; + Pixels = new IColor[width, height]; Size = new(width, height); + for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y, x]; } public Image(int width, int height, Fill fill) { @@ -32,28 +33,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable { Pixels = new IColor[width, height]; Size = new(width, height); - for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(x, y); - } - public Image(int width, int height, Fill fill) - { - Pixels = new IColor[width, height]; - Size = new(width, height); - for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) - Pixels[x, y] = (IColor)fill(y * width + x); - } - public Image(int width, int height, Fill2D fill) - { - Pixels = new IColor[width, height]; - Size = new(width, height); - for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = (IColor)fill(x, y); + for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(y, x); } public Image(Int2 size) : this(size.x, size.y) { } public Image(Int2 size, IColor[] cols) : this(size.x, size.y, cols) { } public Image(Int2 size, IColor[,] cols) : this(size.x, size.y, cols) { } public Image(Int2 size, Fill fill) : this(size.x, size.y, fill) { } public Image(Int2 size, Fill2D fill) : this(size.x, size.y, fill) { } - public Image(Int2 size, Fill fill) : this(size.x, size.y, fill) { } - public Image(Int2 size, Fill2D fill) : this(size.x, size.y, fill) { } public IColor this[int indexX, int indexY] { @@ -124,7 +110,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable for (int y = 0; y < Size.y; y++) for (int x = 0; x < Size.x; x++) { HSVA col = Pixels[x, y].ToHSVA(); - col.S = (set ? 0 : col.S) + value; + col.S = (set ? 0 : col.S) * value; Pixels[x, y] = col; } } @@ -144,7 +130,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable for (int y = 0; y < newSize.y; y++) for (int x = 0; x < newSize.x; x++) { Float2 f = new((float)x / newSize.x, (float)y / newSize.y); - RGBA col = Pixels[Mathf.RoundInt(f.x * Size.x), Mathf.RoundInt(f.y * Size.y)].ToRGBA(); + RGBA col = Pixels[Mathf.Floor(f.x * Size.x), Mathf.Floor(f.y * Size.y)].ToRGBA(); img[x, y] = col; } this = img; diff --git a/Nerd_STF/Graphics/Material.cs b/Nerd_STF/Graphics/Material.cs index d92a20c..71526f4 100644 --- a/Nerd_STF/Graphics/Material.cs +++ b/Nerd_STF/Graphics/Material.cs @@ -5,17 +5,17 @@ public struct Material : ICloneable, IEquatable public float Alpha; public float Anisotropy; public float AnisotropyRoughness; - public IColor AmbientColor; + public IColorFloat AmbientColor; public float ClearcoatRoughness; public float ClearcoatThickness; - public IColor DiffuseColor; - public IColor Emissive; + public IColorFloat DiffuseColor; + public IColorFloat Emissive; public IlluminationModel IllumModel; public float Metallic; public float OpticalDensity; public float Roughness; public float Sheen; - public IColor SpecularColor; + public IColorFloat SpecularColor; public float SpecularExponent; public (Image Image, TextureConfig Config) AlphaTexture; @@ -67,17 +67,17 @@ public struct Material : ICloneable, IEquatable Alpha = (float)fill(0); Anisotropy = (float)fill(1); AnisotropyRoughness = (float)fill(2); - AmbientColor = (IColor)fill(3); + AmbientColor = (IColorFloat)fill(3); ClearcoatRoughness = (float)fill(4); ClearcoatThickness = (float)fill(5); - DiffuseColor = (IColor)fill(6); - Emissive = (IColor)fill(7); + DiffuseColor = (IColorFloat)fill(6); + Emissive = (IColorFloat)fill(7); IllumModel = (IlluminationModel)fill(8); Metallic = (float)fill(9); OpticalDensity = (float)fill(10); Roughness = (float)fill(11); Sheen = (float)fill(12); - SpecularColor = (IColor)fill(13); + SpecularColor = (IColorFloat)fill(13); SpecularExponent = (float)fill(14); AlphaTexture = ((Image, TextureConfig))fill(15); @@ -93,7 +93,7 @@ public struct Material : ICloneable, IEquatable SpecularHighlightTexture = ((Image, TextureConfig))fill(25); StencilTexture = ((Image, TextureConfig))fill(26); } - public Material(IlluminationModel illum, Fill floats, Fill colors, Fill<(Image, TextureConfig)> images) + public Material(IlluminationModel illum, Fill floats, Fill colors, Fill<(Image, TextureConfig)> images) { Alpha = floats(0); Anisotropy = floats(1); diff --git a/Nerd_STF/Graphics/RGBA.cs b/Nerd_STF/Graphics/RGBA.cs index 5f8211d..f3be995 100644 --- a/Nerd_STF/Graphics/RGBA.cs +++ b/Nerd_STF/Graphics/RGBA.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Graphics; -public struct RGBA : IColor, IEquatable +public struct RGBA : IColorFloat, IEquatable { public static RGBA Black => new(0, 0, 0); public static RGBA Blue => new(0, 0, 1); @@ -149,7 +149,7 @@ public struct RGBA : IColor, IEquatable return (Rs, Gs, Bs, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToRGBA()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBA()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBA()); public bool Equals(RGBA col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A; public override bool Equals([NotNullWhen(true)] object? obj) @@ -157,9 +157,9 @@ public struct RGBA : IColor, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(RGBA)) return Equals((RGBA)obj); - else if (t == typeof(CMYKA)) return Equals((IColor)obj); - else if (t == typeof(HSVA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj); + else if (t == typeof(HSVA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj); else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj); else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); diff --git a/Nerd_STF/Graphics/RGBAByte.cs b/Nerd_STF/Graphics/RGBAByte.cs index 26a07ae..a8eb8b0 100644 --- a/Nerd_STF/Graphics/RGBAByte.cs +++ b/Nerd_STF/Graphics/RGBAByte.cs @@ -132,7 +132,7 @@ public struct RGBAByte : IColorByte, IEquatable return (Rs, Gs, Bs, As); } - public bool Equals(IColor? col) => col != null && Equals(col.ToRGBAByte()); + public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBAByte()); public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBAByte()); public bool Equals(RGBAByte col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A; public override bool Equals([NotNullWhen(true)] object? obj) @@ -140,9 +140,9 @@ public struct RGBAByte : IColorByte, IEquatable if (obj == null) return base.Equals(obj); Type t = obj.GetType(); if (t == typeof(RGBAByte)) return Equals((RGBAByte)obj); - else if (t == typeof(CMYKA)) return Equals((IColor)obj); - else if (t == typeof(HSVA)) return Equals((IColor)obj); - else if (t == typeof(IColor)) return Equals((IColor)obj); + else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj); + else if (t == typeof(HSVA)) return Equals((IColorFloat)obj); + else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj); else if (t == typeof(RGBA)) return Equals((IColorByte)obj); else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj); else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); @@ -195,12 +195,12 @@ public struct RGBAByte : IColorByte, IEquatable public static RGBAByte operator /(RGBAByte a, RGBAByte b) => new(a.R / b.R, a.G / b.G, a.B / b.B, a.A / b.A); public static RGBAByte operator /(RGBAByte a, int b) => new(a.R / b, a.G / b, a.B / b, a.A / b); public static RGBAByte operator /(RGBAByte a, float b) => (a.ToRGBA() / b).ToRGBAByte(); - public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColor?)b); - public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColor?)b); - public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColor?)b); - public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColor?)b); - public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColor?)b); - public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColor?)b); + public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); + public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColorFloat?)b); + public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator ==(RGBAByte a, RGBAByte b) => a.Equals(b); public static bool operator !=(RGBAByte a, RGBAByte b) => !a.Equals(b); public static bool operator ==(RGBAByte a, CMYKAByte b) => a.Equals(b); diff --git a/Nerd_STF/Mathematics/Algebra/Vector2d.cs b/Nerd_STF/Mathematics/Algebra/Vector2d.cs index 36b1831..0e5bed9 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector2d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector2d.cs @@ -107,7 +107,7 @@ public struct Vector2d : ICloneable, IComparable, IEquatable public bool Equals(Vector2d other) => theta == other.theta && magnitude == other.magnitude; public override int GetHashCode() => theta.GetHashCode() ^ magnitude.GetHashCode(); public override string ToString() => ToString((string?)null); - public string ToString(Angle.Type outputType = Angle.Type.Degrees) => ToString((string?)null, outputType); + public string ToString(Angle.Type outputType) => ToString((string?)null, outputType); public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) => "Mag: " + magnitude.ToString(provider) + " Rot: " + theta.ToString(provider, outputType); public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) => diff --git a/Nerd_STF/Mathematics/Algebra/Vector3d.cs b/Nerd_STF/Mathematics/Algebra/Vector3d.cs index 8b47cee..c363d79 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector3d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector3d.cs @@ -145,15 +145,20 @@ public struct Vector3d : ICloneable, IComparable, IEquatable public bool Equals(Vector3d other) => yaw == other.yaw && pitch == other.pitch && magnitude == other.magnitude; public override int GetHashCode() => yaw.GetHashCode() ^ pitch.GetHashCode() ^ magnitude.GetHashCode(); + public override string ToString() => ToString((string?)null); + public string ToString(Angle.Type outputType) => ToString((string?)null, outputType); public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) => - "Mag: " + magnitude.ToString(provider) + " Theta: " + yaw.ToString(provider, outputType) + - " Phi: " + pitch.ToString(provider, outputType); + "Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) + + " Pitch: " + pitch.ToString(provider, outputType); + public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) => + "Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) + + " Pitch: " + pitch.ToString(provider, outputType); public object Clone() => new Vector3d(yaw, pitch, magnitude); - public Float3 ToXYZ() => new(Mathf.Sin(pitch) * Mathf.Cos(yaw) * magnitude, - Mathf.Sin(pitch) * Mathf.Sin(yaw) * magnitude, - Mathf.Cos(pitch) * magnitude); + public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw), + Mathf.Cos(yaw), + Mathf.Cos(pitch) * Mathf.Sin(yaw)) * magnitude; public static Vector3d operator +(Vector3d a, Vector3d b) => new(a.yaw + b.yaw, a.pitch + b.pitch, a.magnitude + b.magnitude); diff --git a/Nerd_STF/Mathematics/Angle.cs b/Nerd_STF/Mathematics/Angle.cs index c80ed87..17cfe18 100644 --- a/Nerd_STF/Mathematics/Angle.cs +++ b/Nerd_STF/Mathematics/Angle.cs @@ -35,6 +35,8 @@ public struct Angle : ICloneable, IComparable, IEquatable } public Angle Bounded => new(Mathf.AbsoluteMod(p_deg, 360)); + public Angle Complimentary => Quarter - this; + public Angle Supplementary => Half - this; public Angle Reflected => new Angle(-p_deg).Bounded; private float p_deg; diff --git a/Nerd_STF/Mathematics/Float2.cs b/Nerd_STF/Mathematics/Float2.cs index 3f9f29e..4e31c6e 100644 --- a/Nerd_STF/Mathematics/Float2.cs +++ b/Nerd_STF/Mathematics/Float2.cs @@ -174,6 +174,7 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro 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, Matrix b) => (Float2)((Matrix)a * b); + public static Quaternion operator *(Float2 a, Quaternion b) => (Quaternion)a * 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 Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b); diff --git a/Nerd_STF/Mathematics/Float3.cs b/Nerd_STF/Mathematics/Float3.cs index 9d28ee4..1e7b41b 100644 --- a/Nerd_STF/Mathematics/Float3.cs +++ b/Nerd_STF/Mathematics/Float3.cs @@ -191,7 +191,10 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro public Vector3d ToVector() { float mag = Magnitude; - return new(Mathf.ArcTan(y / x), Mathf.ArcCos(z / mag), mag); + Float3 normalized = Normalized; + Angle yaw = Mathf.ArcCos(normalized.y); + Angle pitch = Mathf.ArcSin(normalized.x / Mathf.Sin(yaw)); + return new(yaw, pitch, mag); } public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); @@ -200,6 +203,7 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro 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, Matrix b) => (Float3)((Matrix)a * b); + public static Quaternion operator *(Float3 a, Quaternion b) => (Quaternion)a * 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 Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b); diff --git a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs b/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs index 8097f74..363bf0a 100644 --- a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs +++ b/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs @@ -8,6 +8,12 @@ public interface ITriangulatable foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); return res.ToArray(); } + public static Triangle[] TriangulateAll(params T[] triangulatables) where T : ITriangulatable + { + List res = new(); + foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); + return res.ToArray(); + } public Triangle[] Triangulate(); } diff --git a/Nerd_STF/Mathematics/NumberSystems/Complex.cs b/Nerd_STF/Mathematics/NumberSystems/Complex.cs index fa4db6a..0ffe053 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Complex.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Complex.cs @@ -170,6 +170,7 @@ public struct Complex : ICloneable, IComparable, IEquatable, I public static Complex operator /(Complex a, Complex b) => a * b.Inverse; public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b); public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b); + public static Complex operator ~(Complex v) => v.Conjugate; public static bool operator ==(Complex a, Complex b) => a.Equals(b); public static bool operator !=(Complex a, Complex b) => !a.Equals(b); public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0; diff --git a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs index d3eba84..987a583 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs @@ -14,12 +14,21 @@ public struct Quaternion : ICloneable, IComparable, IEquatable new(1, 1, 1, 1); public static Quaternion Zero => new(0, 0, 0, 0); - public Quaternion Conjugate => new(u, -i, -j, -k); + public Quaternion Conjugate => new(u, -IJK); public Quaternion Inverse => Conjugate / (u * u + i * i + j * j + k * k); public float Magnitude => Mathf.Sqrt(u * u + i * i + j * j + k * k); public Quaternion Normalized => this * Mathf.InverseSqrt(u * u + i * i + j * j + k * k); - public Float3 IJK => new(i, j, k); + public Float3 IJK + { + get => new(i, j, k); + set + { + i = value.x; + j = value.y; + k = value.z; + } + } public float u, i, j, k; @@ -136,27 +145,31 @@ public struct Quaternion : ICloneable, IComparable, IEquatable FromAngles(new(vals.x, valType), new(vals.y, valType), new(vals.z, valType)); - [Obsolete("This method does not produce the correct output. Please update to a newer release.")] public static Quaternion FromVector(Vector3d vec) => FromAngles(vec.yaw, vec.pitch); public static (float[] Us, float[] Is, float[] Js, float[] Ks) SplitArray(params Quaternion[] vals) @@ -193,18 +206,8 @@ public struct Quaternion : ICloneable, IComparable, IEquatable new Quaternion(u, i, j, k); - [Obsolete("This method does not produce the correct output. Please update to a newer release.")] public Angle GetAngle() => Mathf.ArcCos(u) * 2; - [Obsolete("This method does not produce the correct output. Please update to a newer release.")] - public Float3 GetAxis() - { - Float3 axis = IJK; - float mag = Magnitude; - - if (mag < 0) return Float3.Zero; - return axis / mag; - } - [Obsolete("This method does not produce the correct output. Please update to a newer release.")] + public Float3 GetAxis() => IJK.Normalized; public (Angle yaw, Angle pitch, Angle roll) ToAngles() { Quaternion doubled = this; @@ -213,42 +216,47 @@ public struct Quaternion : ICloneable, IComparable, IEquatable= 1) + float absr3c1 = Mathf.Absolute(rot.r3c1); + if (absr3c1 >= 1) { - rotMatrix.r1c2 = 2 * (i * j - u * k); - rotMatrix.r1c3 = 2 * (i * k + u * j); - - yaw = Mathf.ArcTan2(-rotMatrix.r1c2, -rotMatrix.r3c1 * rotMatrix.r1c3); - pitch = new(-Constants.HalfPi * rotMatrix.r3c1 / r3c1Abs, Angle.Type.Radians); + yaw = Mathf.ArcTan2(-rot.r1c2, -rot.r3c1 * rot.r1c3); + pitch = new(-Constants.HalfPi * rot.r3c1 / absr3c1, Angle.Type.Radians); roll = Angle.Zero; } else { - yaw = Mathf.ArcTan2(rotMatrix.r2c1, rotMatrix.r1c1); - pitch = Mathf.ArcSin(-rotMatrix.r3c1); - roll = Mathf.ArcTan2(rotMatrix.r3c2, rotMatrix.r3c3); + yaw = Mathf.ArcTan2(rot.r2c1, rot.r1c1); + pitch = Mathf.ArcSin(-rot.r3c1); + roll = Mathf.ArcTan2(rot.r3c2, rot.r3c3); } return (yaw, pitch, roll); } - [Obsolete("This method does not produce the correct output. Please update to a newer release.")] - public Vector3d ToVector() + public Float3 ToAnglesFloat3(Angle.Type type = Angle.Type.Degrees) { - (Angle yaw, Angle pitch, _) = ToAngles(); - return new(yaw, pitch); + (Angle yaw, Angle pitch, Angle roll) = ToAngles(); + return new(yaw.ValueFromType(type), pitch.ValueFromType(type), roll.ValueFromType(type)); } - public Quaternion Rotate(Quaternion other) => other * this * other.Conjugate; + public Quaternion Rotate(Quaternion other) => this * other * Conjugate; + public Float3 Rotate(Float3 other) + { + const float tolerance = 0.001f; + Quaternion res = this * other * Conjugate; + if (Mathf.Absolute(res.u) > tolerance) + throw new MathException("A rotated vector should never have non-zero scalar part."); + return res.IJK; + } + public Vector3d Rotate(Vector3d other) => Rotate(other.ToXYZ()).ToVector(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -275,7 +283,7 @@ public struct Quaternion : ICloneable, IComparable, IEquatable, IEquatable new(a.u / b, a.i / b, a.j / b, a.k / b); public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b); public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b); + public static Quaternion operator ~(Quaternion v) => v.Conjugate; public static bool operator ==(Quaternion a, Quaternion b) => a.Equals(b); public static bool operator !=(Quaternion a, Quaternion b) => !a.Equals(b); public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0; diff --git a/Nerd_STF/Nerd_STF.csproj b/Nerd_STF/Nerd_STF.csproj new file mode 100644 index 0000000..5cc9014 --- /dev/null +++ b/Nerd_STF/Nerd_STF.csproj @@ -0,0 +1,46 @@ + + + + net6.0 + enable + enable + Nerd_STF + Nerd_STF + True + That_One_Nerd + Nerd_STF is a C# library that runs on .Net 6.0, and contains added structures and classes I feel would help the default C# library package. + Copyright (c) 2022 That_One_Nerd + README.md + https://github.com/That-One-Nerd/Nerd_STF + 2.3.1.52 + c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers + 2.3.1.52-alpha + Nerd_STF + Nerd_STF + MIT + Logo Square0001.png + The `v2.3.1.x` updates go through every single field and method in Nerd_STF to make sure it works correctly. + https://github.com/That-One-Nerd/Nerd_STF + False + + + + True + + + + True + + + + + True + \ + + + True + \ + + + + diff --git a/Nerd_STF/Nerd_STF.sln b/Nerd_STF/Nerd_STF.sln new file mode 100644 index 0000000..c485096 --- /dev/null +++ b/Nerd_STF/Nerd_STF.sln @@ -0,0 +1,36 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerd_STF", "Nerd_STF.csproj", "{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testing", "..\Testing\Testing.csproj", "{53E8335D-AE54-4E34-A692-136786788DD6}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FBAFC98C-AC9E-4E76-A6E7-8F4DB1B23BED}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Release|Any CPU.Build.0 = Release|Any CPU + {53E8335D-AE54-4E34-A692-136786788DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {53E8335D-AE54-4E34-A692-136786788DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {53E8335D-AE54-4E34-A692-136786788DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {53E8335D-AE54-4E34-A692-136786788DD6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {81A13C28-98B5-49F8-9141-C4A62EE8729F} + EndGlobalSection +EndGlobal diff --git a/Nerd_STF/ScaleType.cs b/Nerd_STF/ScaleType.cs new file mode 100644 index 0000000..21f3dab --- /dev/null +++ b/Nerd_STF/ScaleType.cs @@ -0,0 +1,8 @@ +namespace Nerd_STF; + +public enum ScaleType +{ + X = 1, + Y = 2, + Both = X | Y +} 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 33252d8..0dfa500 100644 Binary files a/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll and b/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll differ