diff --git a/.gitignore b/.gitignore index 313fdd3..8ccf92a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ # Useless Visual Studio stuff +.vs/ /Nerd_STF/.vs/ +/Nerd_STF/Nerd_STF.csproj.user *.sln # Build Stuff @@ -14,6 +16,7 @@ # Nuget /Nerd_STF/LICENSE *.nupkg +*.snupkg # Personal /Nerd_STF/TODO.md diff --git a/Changelog.md b/Changelog.md index 2611457..3668d65 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,106 +1,1112 @@ -# Nerd_STF v2.3.1 +# Nerd_STF v2.3.2 -***Everything has been tested and most things work!*** +A bunch of stuff has changed, hasn't it? -**WARNING:** -All of the matrix classes have had all of their constructors' row and column variables swapped. You'll have to switch all your variables around. -Sorry for the inconvenience :(. +This update was originally intended to be a support update. But among other problems, I don't want to maintain 3 slightly different versions of Nerd_STF at the same time. So I'm going to put the support update on hold for now. I won't delete my progress on it (I got about a quarter of the way done with support for .NET Standard 2.0. It's a big undertaking), I won't promise any completion date either. -The `v2.3.1.x` updates go through every single field and method in Nerd_STF to make sure it works correctly. -You see, up until now I haven't actually tested literally anything at all. Partly because I didn't have the tools to and partly because I was lazy. But now, it's guarenteed to work in most cases (unless I like don't pick up some bug, you know). +Instead, this update ended up being a quality-of-life update. I already finished this part of the update before I decided to cancel the support update. This update now has lots of support for the new .NET 7 features. I'm now using a bunch of static abstract interfaces. I also added range indexing to almost all of the types available. The color byte types now have `int` fields instead of `byte` fields because `int`s are much more common. The values are automatically clamped between 0 and 255 just in case. Basically all types are records now because records are really nice. Lastly, some stuff has been marked as deprecated and to be removed in a future release because they already, exist, are kind of useless, and/or are misleading. Most of the deprecated stuff will be removed in either `2.4.0` or `2.5.0`. -Hi everyone! Everything has been checked now and most stuff works! Not everything, like the triangle and quadrilateral area stuff, but for the most part, it's all cool and good. +***Also, just want to note that despite the `Vert` struct not being marked as deprecated, it will still be removed in `2.5.0`. I didn't mark it because that would have created a bunch of warnings in my library. And I don't like warnings.*** -I've just now remembered how bad the Polygon struct was. It's getting remade. The v2.4.0 update will be mostly geometry focused, so that'll be the best time to figure out how to fix this stuff. The new Polygon struct will be much better, trust me. +One final note, I've changed the description of the library and I've changed a bunch of the assembly and compilation settings. -But all the matrix structs work like charm now! I'm honestly suprised they worked as well as they did before (especially the dynamic matrix). They can now be relied on. - -Next up is the documentation update. Stay tuned! -(This may be another update with beta parts, but I'm not sure yet. We'll see). +Anyway, that's it for this update. The longest delay was just getting this project to other versions of .NET. Stay tuned for v2.4.0, the *Equations and Numbers* update! ``` * Nerd_STF * Exceptions - * DifferingVertCountException - = Marked as deprecated (uses deprecated struct `Polygon`) + * InvalidSizeException + = Swapped a `this` method call for a `base` method call in `InvalidSizeException()` + * MathException + = Made `MathException()` have a default message + * Nerd_STFException + + Nerd_STFException(Exception) + = Made `Nerd_STFException()` have a default message + = Made `Nerd_STFException()` invoke the base constructor + * NoInverseException + = Changed base parent from `Exception` to `Nerd_STFException` + * UndefinedException + = Gave a better default message in `UndefinedException()` * Extensions - * Container2DExtension - + GetSize(T[,]) - + SwapDimensions(T[,], Int2?) - * Flatten(T[,]) - = Replaced a `size` parameter from an `Int2` to an `Int2?` + * ConversionExtension + * ToFill(T[,]) + = Made the type parameter `size` nullable (if null, will be replaced with automatic size) + = Marked `ToDictionary(IEnumerable>)` as obsolete, as the `Dictionary` type already has a constructor for it. + * Graphics + + Abstract + + IColor + + IColorByte + + IColorFloat + + IColorPresets + * CMYKA + + Made `CMYKA` a record + + : IAverage + + : IClamp + + : IColorFloat + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + float this[Index] + + float[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + - : IColorFloat + - Ceiling(CMYKA) + - Floor(CMYKA) + - Max(CMYKA[]) + - Min(CMYKA[]) + - Round(CMYKA) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(CMYKA, CMYKA) + - operator !=(CMYKA, CMYKA) + = Made `GetHashCode()` invoke the base method + * CMYKAByte + + Made `CMYKAByte` a record + + : IAverage + + : IClamp + + : IColorByte + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + p_c + + p_m + + p_y + + p_k + + p_a + + int this[Index] + + int[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + + ToArrayInt() + + ToFillInt() + + ToListInt() + - : IColorByte + - Max(CMYKAByte[]) + - Min(CMYKAByte[]) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(CMYKAByte, CMYKAByte) + - operator !=(CMYKAByte, CMYKAByte) + = Changed the return type of `Black` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Blue` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Clear` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Cyan` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Gray` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Green` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Magenta` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Orange` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Purple` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Red` from `CMYKA` to `CMYKAByte` + = Changed the return type of `White` from `CMYKA` to `CMYKAByte` + = Changed the return type of `Yellow` from `CMYKA` to `CMYKAByte` + = Made `C` a property that relates to `p_c` + = Made `M` a property that relates to `p_m` + = Made `Y` a property that relates to `p_y` + = Made `K` a property that relates to `p_k` + = Made `A` a property that relates to `p_a` + = Made `this[int]` return an `int` instead of a `byte` + = Made `SplitArray(CMYKAByte[])` use the private members of the type. + = Made `ToArray()` use the private members of the type. + = Made `ToList()` use the private members of the type. + = Made `GetEnumerator()` use the private members of the type. + = Made `GetHashCode()` invoke the base method + * HSVA + + Made `HSVA` a record + + : IAverage + + : IClamp + + : IColorFloat + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + float this[Index] + + float[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + - : IColorFloat + - Ceiling(HSVA) + - Floor(HSVA) + - Max(HSVA[]) + - Min(HSVA[]) + - Round(HSVA) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(HSVA, HSVA) + - operator !=(HSVA, HSVA) + = Made `GetHashCode()` invoke the base method + = Optimized some clamping in `this[int]` + * HSVAByte + + Made `HSVAByte` a record + + : IAverage + + : IClamp + + : IColorByte + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + p_h + + p_s + + p_v + + p_a + + int this[Index] + + int[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + + ToArrayInt() + + ToFillInt() + + ToListInt() + - : IColorByte + - Max(HSVAByte[]) + - Min(HSVAByte[]) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(HSVAByte, HSVAByte) + - operator !=(HSVAByte, HSVAByte) + = Changed the return type of `Black` from `HSVA` to `HSVAByte` + = Changed the return type of `Blue` from `HSVA` to `HSVAByte` + = Changed the return type of `Clear` from `HSVA` to `HSVAByte` + = Changed the return type of `Cyan` from `HSVA` to `HSVAByte` + = Changed the return type of `Gray` from `HSVA` to `HSVAByte` + = Changed the return type of `Green` from `HSVA` to `HSVAByte` + = Changed the return type of `Magenta` from `HSVA` to `HSVAByte` + = Changed the return type of `Orange` from `HSVA` to `HSVAByte` + = Changed the return type of `Purple` from `HSVA` to `HSVAByte` + = Changed the return type of `Red` from `HSVA` to `HSVAByte` + = Changed the return type of `White` from `HSVA` to `HSVAByte` + = Changed the return type of `Yellow` from `HSVA` to `HSVAByte` + = Changed the type of the parameter `t` from a `byte` to a `float` in `Lerp(HSVAByte, HSVAByte, byte, bool)` + = Made `H` a property that relates to `p_h` + = Made `S` a property that relates to `p_s` + = Made `V` a property that relates to `p_v` + = Made `A` a property that relates to `p_a` + = Made `this[int]` return an `int` instead of a `byte` + = Made `SplitArray(HSVAByte[])` use the private members of the type. + = Made `ToArray()` use the private members of the type. + = Made `ToList()` use the private members of the type. + = Made `GetEnumerator()` use the private members of the type. + = Made `GetHashCode()` invoke the base method + * Image + + : IEnumerable + - : IEnumerable + = Added a nullabilty modifier in `Equals(Image)` + = Changed a modifier in `Pixels` from `init` to `private set` + = Changed a modifier in `Size` from `init` to `private set` + = Fixed some random bug in `ModifySaturation(float, bool)` where if `set` is set to `true`, the saturation is completely zeroed out. + = Replaced a `this` assignment in `Scale(Float2)` with individual component assignments + = Turned `Image` into a `class` (from a `struct`) + * RGBA + + Made `RGBA` a record + + : IAverage + + : IClamp + + : IColorFloat + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + float this[Index] + + float[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + - : IColorFloat + - Ceiling(RGBA) + - Floor(RGBA) + - Max(RGBA[]) + - Min(RGBA[]) + - Round(RGBA) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(RGBA, RGBA) + - operator !=(RGBA, RGBA) + = Made `GetHashCode()` invoke the base method + * RGBAByte + + Made `RGBAByte` a record + + : IAverage + + : IClamp + + : IColorByte + + : IColorPresets + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : ISplittable + + p_r + + p_g + + p_b + + p_a + + int this[Index] + + int[] this[Range] + + Equals(IColor?) + + PrintMembers(StringBuilder) + + ToArrayInt() + + ToFillInt() + + ToListInt() + - : IColorByte + - Max(RGBAByte[]) + - Min(RGBAByte[]) + - override Equals(object?) + - Equals(IColorFloat?) + - Equals(IColorByte?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(RGBAByte, RGBAByte) + - operator !=(RGBAByte, RGBAByte) + = Changed the type of the parameter `t` from a `byte` to a `float` in `Lerp(RGBAByte, RGBAByte, byte, bool)` + = Made `R` a property that relates to `p_r` + = Made `G` a property that relates to `p_g` + = Made `B` a property that relates to `p_b` + = Made `A` a property that relates to `p_a` + = Made `this[int]` return an `int` instead of a `byte` + = Made `SplitArray(RGBAByte[])` use the private members of the type. + = Made `ToArray()` use the private members of the type. + = Made `ToList()` use the private members of the type. + = Made `GetEnumerator()` use the private members of the type. + = Made `GetHashCode()` invoke the base method + = Fixed a bug in `ToFill()` where it would return `HSVAByte` values instead + = Moved `IColor` to `Nerd_STF.Graphics.Abstract` + + : IEquatable + - : ICloneable + - : IEquatable + - : IEquatable + = Moved `IColorByte` to `Nerd_STF.Graphics.Abstract` + + ToArrayInt() + + ToFillInt() + + ToListInt() + = Moved `IColorFloat` to `Nerd_STF.Graphics.Abstract` * Mathematics + + Abstract + + IAbsolute + + IAverage + + ICeiling + + ICeiling + + IClamp + + IClampMagnitude + + IClampMagnitude + + ICross + + ICross + + IDivide + + IDot + + IDot + + IFloor + + IFloor + + IIndexAll + + IIndexGet + + IIndexRangeAll + + IIndexRangeGet + + IIndexRangeSet + + IIndexSet + + ILerp + + ILerp + + IMagnitude + + IMax + + IMatrixPresets + + IMedian + + IMin + + IPresets1D + + IPresets2D + + IPresets3D + + IPresets4D + + IProduct + + IRound + + IRound + + IShape2D + + IShape3D + + ISplittable + + IStaticMatrix + + ISubtract + + ISum + + IVector2 * Algebra - * IMatrix - - ToDictionary() * Matrix - + Cofactor() - + IdentityIsh(Int2) - + MinorOf(Int2) - - ToDictionary() - = Fixed `Determinant()` - = Fixed `Minors()` - = Fixed `Inverse()` - = Made `Identity(Int2)` only work with square matricies (since that's only when an identity exists) - = Marked the struct as `readonly` - = Simplified `Transpose()` - = Swapped row variables with column variables in all constructors (and methods that require those constructors). - = Swapped code for `Adjugate()` with `Cofactor()` + + this[Index, Index] + + this[Range, Range] + - ToString(string?) + - ToString(IFormatProvider) + = Added a better exception description in `Identity(Int2)` + = Added a nullability attribute to the return type of `Inverse()` + = Added a nullability attribute to the return type of `operator -(Matrix)` + = Added a nullability check in `Equals(Matrix)` + = Turned `Matrix` into a `class` (from a `struct`) + = Changed the parameter `other` in `Equals(Matrix)` to a nullable equivalent and added a nullability check + = Made `Inverse()` return `null` if there is no inverse instead of throwing an exception. + = Made `operator /(Matrix, Matrix)` throw an exception if no inverse exists for matrix `b` + = Marked `Equals(Matrix)` as virtual * Matrix2x2 - + Cofactor() - + operator *(Matrix2x2, Float2) - + operator /(Matrix2x2, Float2) - - ToDictionary() - = Swapped code for `Adjugate()` with `Cofactor()` - = Swapped row variables with column variables in all constructors (and methods that require those constructors). - = Fixed `this[int, int]` to compensate for the swapped variables. - = Fixed `operator -(Matrix2x2, Matrix2x2)` to not have an addition in one of the variables (fun). - = Fixed `Inverse()` - = Fixed `explicit operator Matrix2x2(Matrix)` + + Made `Matrix2x2` into a record + + : IStaticMatrix + + this[Index, Index] + + this[Range, Range] + - : IMatrix + - override Equals(object?) + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(Matrix2x2, Matrix2x2) + - operator !=(Matrix2x2, Matrix2x2) + = Added a nullability attribute to the return type of `Inverse()` + = Turned `Matrix2x2` into a `class` (from a `struct`) + = Marked `Equals(Matrix2x2)` as virtual + = Made `GetHashCode()` invoke the base method + = Made `Inverse()` return `null` if there is no inverse instead of throwing an exception. + = Made `operator /(Matrix2x2, Matrix2x2)` throw an exception if no inverse exists for matrix `b` + = Changed the parameter `other` in `Equals(Matrix2x2)` to a nullable equivalent and added a nullability check * Matrix3x3 - + Cofactor() - + operator *(Matrix3x3, Float3) - + operator /(Matrix3x3, Float3) - - ToDictionary() - = Swapped code for `Adjugate()` with `Cofactor()` - = Swapped row variables with column variables in all constructors (and methods that require those constructors). - = Fixed `this[int, int]` to compensate for the swapped variables. - = Fixed `Determinant()` - = Fixed `Inverse()` - = Fixed `explicit operator Matrix3x3(Matrix)` + + Made `Matrix3x3` into a record + + : IStaticMatrix + + this[Index, Index] + + this[Range, Range] + - : IMatrix + - override Equals(object?) + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(Matrix3x3, Matrix3x3) + - operator !=(Matrix3x3, Matrix3x3) + = Turned `Matrix3x3` into a `class` (from a `struct`) + = Added a nullability attribute to the return type of `Inverse()` + = Added a nullability attribute to the return type of `operator -(Matrix3x3)` + = Marked `Equals(Matrix3x3)` as virtual + = Made `GetHashCode()` invoke the base method + = Changed the parameter `other` in `Equals(Matrix3x3)` to a nullable equivalent and added a nullability check + = Made `Cofactor()` use a preset rather than parameterless constructor + = Made `operator /(Matrix3x3, Matrix3x3)` throw an exception if no inverse exists for matrix `b` * Matrix4x4 - + Cofactor() - + override string ToString() - + operator *(Matrix4x4, Float4) - + operator /(Matrix4x4, Float4) - - ToDictionary() - = Swapped code for `Adjugate()` with `Cofactor()` - = Swapped row variables with column variables in all constructors (and methods that require those constructors). - = Fixed `this[int, int]` to compensate for the swapped variables. - = Fixed `Determinant()` - = Fixed a typo in `Absolute(Matrix4x4)`, `Ceiling(Matrix4x4)`, `Floor(Matrix4x4)`, and `Round(Matrix4x4)` - = Fixed a typo in `Row1`, `Row2`, `Row3`, and `Row4`. Oops. - = Fixed some missing elements in `SplitArray(Matrix4x4[])` - = Fixed `explicit operator Matrix4x4(Matrix)` + + Made `Matrix4x4` into a record + + : IStaticMatrix + + this[Index, Index] + + this[Range, Range] + - : IMatrix + - override Equals(object?) + - ToString(string?) + - ToString(IFormatProvider) + - Clone() + - operator ==(Matrix4x4, Matrix4x4) + - operator !=(Matrix4x4, Matrix4x4) + = Added a nullability attribute to the return type of `Inverse()` + = Added a nullability attribute to the return type of `operator -(Matrix4x4)` + = Turned `Matrix4x4` into a `class` (from a `struct`) + = Marked `Equals(Matrix4x4)` as virtual + = Made `GetHashCode()` invoke the base method + = Changed the parameter `other` in `Equals(Matrix4x4)` to a nullable equivalent and added a nullability check + = Made `Cofactor()` use a preset rather than parameterless constructor + = Made `operator /(Matrix4x4, Matrix4x4)` throw an exception if no inverse exists for matrix `b` + * Vector2d + + Made `Vector2d` into a record + + : IAbsolute + + : IAverage + + : IClampMagnitude + + : ICross + + : IDot + + : IFromTuple + + : ILerp + + : IMax + + : IMagnitude + + : IMedian + + : IMin + + : IPresets2D + + : ISplittable + + : ISubtract + + : ISum + + float Magnitude + + operator Vector2d((Angle angle, float mag)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?, Angle.Type) + - ToString(IFormatProvider, Angle.Type) + - operator ==(Vector2d, Vector2d) + - operator !=(Vector2d, Vector2d) + = Made the tuple variable names lowercase in `SplitArray(Vector2d[])` + = Made `GetHashCode()` invoke the base method + = Made `ToString(Angle.Type)` resemble a record string + * Vector3d + + Made `Vector3d` into a record + + : IAbsolute + + : IAverage + + : IClampMagnitude + + : ICross + + : IDot + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMax + + : IMagnitude + + : IMedian + + : IMin + + : IPresets3D + + : ISplittable + + : ISubtract + + : ISum + + float Magnitude + + this[Index] + + this[Range] + + operator Vector3d((Angle yaw, Angle pitch, float mag)) + - ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?, Angle.Type) + - ToString(IFormatProvider, Angle.Type) + - operator ==(Vector3d, Vector3d) + - operator !=(Vector3d, Vector3d) + = Renamed the tuple variable names in `SplitArray(Vector3d[])` + = Made `GetHashCode()` invoke the base method + = Made `ToString(Angle.Type)` resemble a record string + = Moved `IMatrix` to `Nerd_STF.Mathematics.Abstract` + + : IAbsolute + + : ICeiling + + : IClamp + + : IDivide + + : IFloor + + : ILerp + + : IProduct + + : IRound + - : ICloneable + - : IEnumerable + = Added a nullability attribute to the return type of `Inverse()` * Geometry * Box2D - = Simplified some code in `Perimeter` + + Made `Box2D` into a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : ILerp + + : IMedian + + : IRound + + : IShape2D + + : ISplittable + + Round(Box2D) + + PrintMembers(StringBuilder) + - : ICloneable + - Max(Box2D[]) + - Min(Box2D[]) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Box2D, Box2D) + - operator !=(Box2D, Box2D) + = Turned `Box2D` into `class` (from a `struct`) + = Marked `Equals(Box2D)` as virtual + = Made `GetHashCode()` invoke the base method + = Changed the parameter `other` in `Equals(Box2D)` to a nullable equivalent and added a nullability check * Box3D - + SurfaceArea - = Renamed `Area` to `Volume` - = Simplified some code in `Perimeter` + + Made `Box3D` into a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : ILerp + + : IMedian + + : IRound + + : IShape3D + + : ISplittable + + Round(Box3D) + + PrintMembers(StringBuilder) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Box3D, Box3D) + - operator !=(Box3D, Box3D) + = Fixed an ambiguity in `Ceiling(Box3D)` + = Fixed an ambiguity in `Floor(Box3D)` + = Turned `Box3D` into `class` (from a `struct`) + = Marked `Equals(Box3D)` as virtual + = Made `GetHashCode()` invoke the base method + = Changed the parameter `other` in `Equals(Box3D)` to a nullable equivalent and added a nullability check + * Line + + Made `Line` into a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMedian + + : IPresets3D + + : IRound + + : ISplittable + + Round(Line) + + PrintMembers(StringBuilder) + + operator Line((Vert start, Vert end)) + - : ICloneable + - Clone() + - Max(Line[]) + - Min(Line[]) + - override Equals(object?) + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Line, Line) + - operator !=(Line, Line) + = Turned `Line` into `class` (from a `struct`) + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Line)` as deprecated, as it's a bit confusing + = Marked `operator >(Line, Line)` as deprecated, as it's a bit confusing + = Marked `operator <(Line, Line)` as deprecated, as it's a bit confusing + = Marked `operator >=(Line, Line)` as deprecated, as it's a bit confusing + = Marked `operator <=(Line, Line)` as deprecated, as it's a bit confusing + = Changed the parameter `other` in `Equals(Line)` to a nullable equivalent and added a nullability check + = Changed the parameter `other` in `CompareTo(Line)` to a nullable equivalent and added a nullability check * Polygon - = Marked as deprecated (will be redone in v2.4.0) - = Simplified collection initialization in `Triangulate()` + * Triangulate + = Replaced all `Exception`s thrown with `Nerd_STFException`s + - Max(Polygon[]) + - Min(Polygon[]) + - ToString(string?) + - ToString(IFormatProvider) + = Changed the deprecation removal notice from version 2.4.0 to 2.5.0 * Quadrilateral - - explicit operator Triangle(Polygon) - = Marked `Area` as deprecated (uses deprecated `Triangle.Area` field) + + Made `Quadrilateral` a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IRound + + : IShape2D + + Round(Quadrilateral) + + PrintMembers(StringBuilder) + + operator Quadrilateral((Vert a, Vert b, Vert c, Vert d)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Quadrilateral, Quadrilateral) + - operator !=(Quadrilateral, Quadrilateral) + = Turned `Quadrilateral` into a `class` (from a `struct`) + = Made `GetHashCode()` invoke the base method + = Marked `Equals(Quadrilateral)` as virtual + = Changed the parameter `other` in `Equals(Quadrilateral)` to a nullable equivalent and added a nullability check * Sphere - = Fixed `ClosestTo(Vert)` + + Made `Sphere` a record + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : IFromTuple + + : ILerp + + : IMax + + : IMedian + + : IMin + + : IRound + + : ISplittable + + Round(Sphere) + + PrintMembers(StringBuilder) + + operator Sphere((Vert center, float radius)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Sphere, Sphere) + - operator !=(Sphere, Sphere) + = Made `GetHashCode()` invoke the base method + = Marked `Equals(float)` as deprecated. It will be removed in 2.5.0 + = Marked `CompareTo(float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator ==(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator !=(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator >(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 + = Marked `operator <(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 + = Marked `operator >(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator <(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator >=(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 + = Marked `operator <=(Sphere, Sphere)` as deprecated. It will be removed in 2.5.0 + = Marked `operator >=(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `operator <=(Sphere, float)` as deprecated. It will be removed in 2.5.0 + = Marked `Equals(Sphere)` as virtual + = Changed the parameter `other` in `Equals(Sphere)` to a nullable equivalent and added a nullability check + = Changed the parameter `other` in `CompareTo(Sphere)` to a nullable equivalent and added a nullability check + = Turned `Sphere` into a `class` (from a `struct`) * Triangle - - explicit operator Triangle(Polygon) - = Marked `Area` as deprecated (will be fixed in v2.4.0) + + Made `Triangle` a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IRound + + : IShape2D + + Round(Triangle) + + PrintMembers(StringBuilder) + + operator Triangle((Vert a, Vert b, Vert c)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Triangle, Triangle) + - operator !=(Triangle, Triangle) + = Turned `Triangle` into a `class` (from a `struct`) + = Made `GetHashCode()` invoke the base method + = Marked `Equals(Triangle)` as virtual + = Changed the parameter `other` in `Equals(Triangle)` to a nullable equivalent and added a nullability check * Vert - = Marked as deprecated (will be removed in v2.4.0). - = Optimized `Normalized` to not clone more than required. + + Round(Vert) + - ToString(string?) + - ToString(IFormatProvider) + = Moved `ISubdividable` to `Nerd_STF.Mathematics.Abstract` and renamed it to `ISubdivide` + = Moved `ITriangulatable` to `Nerd_STF.Mathematics.Abstract` and renamed it to `ITriangulate` + * NumberSystems + * Complex + + Marked `Complex` as a record + + Added parameters `float`, `float` + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IClampMagnitude + + : IDivide + + : IDot + + : IFloor + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMax + + : IMedian + + : IMin + + : IPresets2D + + : IProduct + + : IRound + + : ISplittable + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Complex((float, float)) + - : ICloneable + - Complex(float, float) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Complex, Complex) + - operator !=(Complex, Complex) + = Added an assignment for `u` + = Added an assignment for `i` + = Marked `operator >(Complex, Complex)` as deprecated, as it's a bit confusing + = Marked `operator <(Complex, Complex)` as deprecated, as it's a bit confusing + = Marked `operator >=(Complex, Complex)` as deprecated, as it's a bit confusing + = Marked `operator <=(Complex, Complex)` as deprecated, as it's a bit confusing + * Quaternion + + Marked `Quaternion` as a record + + Added parameters `float`, `float`, `float`, `float` + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IClampMagnitude + + : IDivide + + : IDot + + : IFloor + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMax + + : IMedian + + : IMin + + : IPresets4D + + : IProduct + + : IRound + + : ISplittable + + : ISum + + HighW + + LowW + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Quaternion((float, float, float, float)) + - : ICloneable + - Quaternion(float, float, float, float) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Quaternion, Quaternion) + - operator !=(Quaternion, Quaternion) + = Added an assignment for `u` + = Added an assignment for `i` + = Added an assignment for `j` + = Added an assignment for `k` + = Fixed a mistake in `operator -(Quaternion)` that would just return the clone of the current instance rather than the proper negative. + = Made `GetHashCode()` invoke the base method + = Marked `operator >(Quaternion, Quaternion)` as deprecated, as it's a bit confusing + = Marked `operator <(Quaternion, Quaternion)` as deprecated, as it's a bit confusing + = Marked `operator >=(Quaternion, Quaternion)` as deprecated, as it's a bit confusing + = Marked `operator <=(Quaternion, Quaternion)` as deprecated, as it's a bit confusing + = Marked `Near` as deprecated, as it's replaced with `LowW`. + = Marked `Far` as deprecated, as it's replaced with `HighW`. + * Samples + * Constants + = Fixed a typo and renamed `TwelthRoot2` to `TwelfthRoot2` + = Made `EulerMascheroniConstant` reference `EulerConstant`, since they are the same + = Made `LiebSquareIceConstant` more simplified + = Renamed `UniversalHyperbolicConstant` to `UniversalParabolicConstant` (oops) + = Renamed `RegularPaperfoldingSequence` to `RegularPaperfoldingConstant` + = Simplified `SecondHermiteConstant` + * Angle + + : IAbsolute + + : IAverage + + : IClamp + + : ILerp + + : IMax + + : IMedian + + : IMin + + : IPresets2D + + operator Angle((float, Type)) + - ToString(string?, Type) + - ToString(IFormatProvider, Type) + = Improved the `SplitArray(Type, Angle[])` to use another function for conversion. + * Float2 + + Marked `Float2` as a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IClampMagnitude + + : ICross + + : IDivide + + : IDot + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMax + + : IMedian + + : IMin + + : IPresets2D + + : IProduct + + : IRound + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Float2((float, float)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Float2, Float2) + - operator !=(Float2, Float2) + = Made `Ceiling(Float2)` return an `Int2` instead of a `Float2` + = Made `Floor(Float2)` return an `Int2` instead of a `Float2` + = Made `Round(Float2)` return an `Int2` instead of a `Float2` + = Made `Max(Float2[])` compare magnitudes directly + = Made `Min(Float2[])` compare magnitudes directly + = Marked `CompareTo(Float2)` as deprecated, as it's a bit confusing + = Marked `operator >(Float2, Float2)` as deprecated, as it's a bit confusing + = Marked `operator <(Float2, Float2)` as deprecated, as it's a bit confusing + = Marked `operator >=(Float2, Float2)` as deprecated, as it's a bit confusing + = Marked `operator <=(Float2, Float2)` as deprecated, as it's a bit confusing + * Float3 + + Marked `Float3` as a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IClampMagnitude + + : ICross + + : IDivide + + : IDot + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMathOperators + + : IMax + + : IMedian + + : IMin + + : IPresets3D + + : IProduct + + : IRound + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Float3((float, float, float)) + - : ICloneable + - Float3(float, float, float) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Float3, Float3) + - operator !=(Float3, Float3) + = Made `Ceiling(Float3)` return an `Int3` instead of a `Float3` + = Made `Floor(Float3)` return an `Int3` instead of a `Float3` + = Made `Round(Float3)` return an `Int3` instead of a `Float3` + = Made `Max(Float3[])` compare magnitudes directly + = Made `Min(Float3[])` compare magnitudes directly + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Float3)` as deprecated, as it's a bit confusing + = Marked `operator >(Float3, Float3)` as deprecated, as it's a bit confusing + = Marked `operator <(Float3, Float3)` as deprecated, as it's a bit confusing + = Marked `operator >=(Float3, Float3)` as deprecated, as it's a bit confusing + = Marked `operator <=(Float3, Float3)` as deprecated, as it's a bit confusing + * Float4 + + Marked `Float4` as a record + + : IAbsolute + + : IAverage + + : ICeiling + + : IClamp + + : IClampMagnitude + + : IDivide + + : IDot + + : IFloor + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMathOperators + + : IMax + + : IMedian + + : IMin + + : IPresets4D + + : IProduct + + : IRound + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Float4((float, float, float, float)) + - : ICloneable + - Float4(float, float, float, float) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Float4, Float4) + - operator !=(Float4, Float4) + = Made `Ceiling(Float4)` return an `Int4` instead of a `Float4` + = Made `Floor(Float4)` return an `Int4` instead of a `Float4` + = Made `Round(Float4)` return an `Int4` instead of a `Float4` + = Made `Max(Float4[])` compare magnitudes directly + = Made `Min(Float4[])` compare magnitudes directly + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Float4)` as deprecated, as it's a bit confusing + = Marked `operator >(Float4, Float4)` as deprecated, as it's a bit confusing + = Marked `operator <(Float4, Float4)` as deprecated, as it's a bit confusing + = Marked `operator >=(Float4, Float4)` as deprecated, as it's a bit confusing + = Marked `operator <=(Float4, Float4)` as deprecated, as it's a bit confusing + * Int2 + + Marked `Int2` as a record + + : IAbsolute + + : IAverage + + : IClamp + + : IClampMagnitude + + : ICross + + : IDivide + + : IDot + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMathOperators + + : IMax + + : IMedian + + : IMin + + : IPresets2D + + : IProduct + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Int2((int, int)) + - : ICloneable + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Int2, Int2) + - operator !=(Int2, Int2) + = Made `Max(Int2[])` compare magnitudes directly + = Made `Min(Int2[])` compare magnitudes directly + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Int2)` as deprecated, as it's a bit confusing + = Marked `operator >(Int2, Int2)` as deprecated, as it's a bit confusing + = Marked `operator <(Int2, Int2)` as deprecated, as it's a bit confusing + = Marked `operator >=(Int2, Int2)` as deprecated, as it's a bit confusing + = Marked `operator <=(Int2, Int2)` as deprecated, as it's a bit confusing + * Int3 + + Marked `Int3` as a record + + : IAbsolute + + : IAverage + + : IClamp + + : IClampMagnitude, + + : ICross + + : IDivide + + : IDot + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMathOperators + + : IMax + + : IMedian + + : IMin + + : IProduct + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Int3((int, int, int)) + - : ICloneable() + - Int3(int, int, int) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Int3, Int3) + - operator !=(Int3, Int3) + = Made `Max(Int3[])` compare magnitudes directly + = Made `Min(Int3[])` compare magnitudes directly + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Int3)` as deprecated, as it's a bit confusing + = Marked `operator >(Int3, Int3)` as deprecated, as it's a bit confusing + = Marked `operator <(Int3, Int3)` as deprecated, as it's a bit confusing + = Marked `operator >=(Int3, Int3)` as deprecated, as it's a bit confusing + = Marked `operator <=(Int3, Int3)` as deprecated, as it's a bit confusing + * Int4 + + Marked `Int4` as a record + + : IAbsolute + + : IAverage + + : IClamp + + : IClampMagnitude + + : IDivide + + : IDot + + : IFromTuple + + : IIndexAll + + : IIndexRangeAll + + : ILerp + + : IMathOperators + + : IMax + + : IMedian + + : IMin + + : IProduct + + : ISplittable + + : ISubtract + + : ISum + + this[Index] + + this[Range] + + PrintMembers(StringBuilder) + + operator Int4((int, int, int, int)) + - : ICloneable + - Int4(int, int, int, int) + - Clone() + - override Equals(object?) + - override ToString() + - ToString(string?) + - ToString(IFormatProvider) + - operator ==(Int4, Int4) + - operator !=(Int4, Int4) + = Marked `Deep` as deprecated + = Made `Max(Int4[])` compare magnitudes directly + = Made `Min(Int4[])` compare magnitudes directly + = Made `GetHashCode()` invoke the base method + = Marked `CompareTo(Int4)` as deprecated, as it's a bit confusing + = Marked `operator >(Int4, Int4)` as deprecated, as it's a bit confusing + = Marked `operator <(Int4, Int4)` as deprecated, as it's a bit confusing + = Marked `operator >=(Int4, Int4)` as deprecated, as it's a bit confusing + = Marked `operator <=(Int4, Int4)` as deprecated, as it's a bit confusing + * Mathf + = Forced `Max(T[])` to not return a nullable object + = Forced `Min(T[])` to not return a nullable object + = Renamed a parameter `value` in `Mathf.Lerp(int, int, float, bool)` to `t` + = Replaced a `ContainsKey(float)` call with a `TryGetValue(float, out float)` call in `MakeEquation(Dictionary)` + = Removed a useless call to `Absolute(int)` in `PowerMod(int, int, int)` + = Simplified a list initialization in `Factors(int)` + * Miscellaneous + + AssemblyConfig + * GlobalUsings + + global using Nerd_STF.Graphics.Abstract + + global using Nerd_STF.Mathematics.Abstract + + global using System.Text + + global using System.Runtime.Serialization + + Nerd_STF + = Marked `Foreach(object)` as deprecated. Why would you even use this? + = Marked `Foreach(T)` as deprecated. Why would you even use this? + = Moved `IClosest` to `Nerd_STF.Mathematics.Abstract` and renamed it to `IClosestTo` + = Moved `IContainer` to `Nerd_STF.Mathematics.Abstract` and renamed it to `IContains` ``` diff --git a/Nerd_STF/Exceptions/DifferingVertCountException.cs b/Nerd_STF/Exceptions/DifferingVertCountException.cs index 8dce0b3..7321b9e 100644 --- a/Nerd_STF/Exceptions/DifferingVertCountException.cs +++ b/Nerd_STF/Exceptions/DifferingVertCountException.cs @@ -1,6 +1,4 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] [Obsolete("The Polygon struct is a garbage fire, and will be fixed in v2.4.0", false)] diff --git a/Nerd_STF/Exceptions/DisconnectedLinesException.cs b/Nerd_STF/Exceptions/DisconnectedLinesException.cs index 3c27050..b4d857c 100644 --- a/Nerd_STF/Exceptions/DisconnectedLinesException.cs +++ b/Nerd_STF/Exceptions/DisconnectedLinesException.cs @@ -1,6 +1,4 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] public class DisconnectedLinesException : Nerd_STFException diff --git a/Nerd_STF/Exceptions/InvalidSizeException.cs b/Nerd_STF/Exceptions/InvalidSizeException.cs index 6d16e83..9591da9 100644 --- a/Nerd_STF/Exceptions/InvalidSizeException.cs +++ b/Nerd_STF/Exceptions/InvalidSizeException.cs @@ -1,11 +1,9 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] public class InvalidSizeException : Nerd_STFException { - public InvalidSizeException() : this("Argument size is invalid.") { } + public InvalidSizeException() : base("Argument size is invalid.") { } public InvalidSizeException(string message) : base(message) { } public InvalidSizeException(string message, Exception inner) : base(message, inner) { } protected InvalidSizeException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/Nerd_STF/Exceptions/MathException.cs b/Nerd_STF/Exceptions/MathException.cs index eee2d3f..8b094f6 100644 --- a/Nerd_STF/Exceptions/MathException.cs +++ b/Nerd_STF/Exceptions/MathException.cs @@ -1,11 +1,9 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] public class MathException : Nerd_STFException { - public MathException() : base() { } + public MathException() : base("A calculation error occured.") { } public MathException(string message) : base(message) { } public MathException(string message, Exception inner) : base(message, inner) { } protected MathException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/Nerd_STF/Exceptions/Nerd_STFException.cs b/Nerd_STF/Exceptions/Nerd_STFException.cs index 5714792..2e9808f 100644 --- a/Nerd_STF/Exceptions/Nerd_STFException.cs +++ b/Nerd_STF/Exceptions/Nerd_STFException.cs @@ -1,11 +1,11 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] public class Nerd_STFException : Exception { - public Nerd_STFException() { } + public Nerd_STFException() : base("An unknown error occured within Nerd_STF.") { } + public Nerd_STFException(Exception inner) + : base("An unknown error occured within Nerd_STF.", inner) { } public Nerd_STFException(string message) : base(message) { } public Nerd_STFException(string message, Exception inner) : base(message, inner) { } protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/Nerd_STF/Exceptions/NoInverseException.cs b/Nerd_STF/Exceptions/NoInverseException.cs index a7eca4e..e90346b 100644 --- a/Nerd_STF/Exceptions/NoInverseException.cs +++ b/Nerd_STF/Exceptions/NoInverseException.cs @@ -1,9 +1,7 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] -public class NoInverseException : Exception +public class NoInverseException : Nerd_STFException { public Matrix? Matrix; diff --git a/Nerd_STF/Exceptions/UndefinedException.cs b/Nerd_STF/Exceptions/UndefinedException.cs index e166788..a9636a2 100644 --- a/Nerd_STF/Exceptions/UndefinedException.cs +++ b/Nerd_STF/Exceptions/UndefinedException.cs @@ -1,11 +1,9 @@ -using System.Runtime.Serialization; - -namespace Nerd_STF.Exceptions; +namespace Nerd_STF.Exceptions; [Serializable] public class UndefinedException : MathException { - public UndefinedException() : this("The equation calculated resulted in an undefined number.") { } + public UndefinedException() : this("A calculation has produced an undefined number.") { } public UndefinedException(string message) : base(message) { } public UndefinedException(string message, Exception inner) : base(message, inner) { } protected UndefinedException(SerializationInfo info, StreamingContext context) : base(info, context) { } diff --git a/Nerd_STF/Extensions/ConversionExtension.cs b/Nerd_STF/Extensions/ConversionExtension.cs index 3aa2ae0..6f82334 100644 --- a/Nerd_STF/Extensions/ConversionExtension.cs +++ b/Nerd_STF/Extensions/ConversionExtension.cs @@ -2,6 +2,8 @@ public static class ConversionExtension { + [Obsolete("This extension turns out to already exist as a constructor in the " + + "System.Collections.Generic.Dictionary type. This will be removed in v2.4.0")] public static Dictionary ToDictionary (this IEnumerable> pairs) where TKey : notnull @@ -12,6 +14,6 @@ public static class ConversionExtension } 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 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/Foreach.cs b/Nerd_STF/Foreach.cs index 624aa57..8004551 100644 --- a/Nerd_STF/Foreach.cs +++ b/Nerd_STF/Foreach.cs @@ -1,4 +1,6 @@ namespace Nerd_STF; +[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")] public delegate void Foreach(object item); +[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")] public delegate void Foreach(T item); diff --git a/Nerd_STF/Graphics/Abstract/IColor.cs b/Nerd_STF/Graphics/Abstract/IColor.cs new file mode 100644 index 0000000..cbacc99 --- /dev/null +++ b/Nerd_STF/Graphics/Abstract/IColor.cs @@ -0,0 +1,29 @@ +using System.Numerics; + +namespace Nerd_STF.Graphics.Abstract; + +public interface IColor : IEquatable +{ + public CMYKA ToCMYKA(); + public HSVA ToHSVA(); + public RGBA ToRGBA(); + + public CMYKAByte ToCMYKAByte(); + public HSVAByte ToHSVAByte(); + public RGBAByte ToRGBAByte(); +} +public interface IColor : IColor where T : IColor +{ + public static abstract bool operator ==(T a, CMYKA b); + public static abstract bool operator !=(T a, CMYKA b); + public static abstract bool operator ==(T a, CMYKAByte b); + public static abstract bool operator !=(T a, CMYKAByte b); + public static abstract bool operator ==(T a, HSVA b); + public static abstract bool operator !=(T a, HSVA b); + public static abstract bool operator ==(T a, HSVAByte b); + public static abstract bool operator !=(T a, HSVAByte b); + public static abstract bool operator ==(T a, RGBA b); + public static abstract bool operator !=(T a, RGBA b); + public static abstract bool operator ==(T a, RGBAByte b); + public static abstract bool operator !=(T a, RGBAByte b); +} diff --git a/Nerd_STF/Graphics/Abstract/IColorByte.cs b/Nerd_STF/Graphics/Abstract/IColorByte.cs new file mode 100644 index 0000000..c7a2ef0 --- /dev/null +++ b/Nerd_STF/Graphics/Abstract/IColorByte.cs @@ -0,0 +1,9 @@ +namespace Nerd_STF.Graphics.Abstract; + +public interface IColorByte : IColor, IGroup +{ + public int[] ToArrayInt(); + public Fill ToFillInt(); + public List ToListInt(); +} +public interface IColorByte : IColor, IColorByte where T : struct, IColorByte { } diff --git a/Nerd_STF/Graphics/Abstract/IColorFloat.cs b/Nerd_STF/Graphics/Abstract/IColorFloat.cs new file mode 100644 index 0000000..aa10363 --- /dev/null +++ b/Nerd_STF/Graphics/Abstract/IColorFloat.cs @@ -0,0 +1,4 @@ +namespace Nerd_STF.Graphics.Abstract; + +public interface IColorFloat : IColor, IGroup { } +public interface IColorFloat : IColor, IColorFloat where T : struct, IColorFloat { } diff --git a/Nerd_STF/Graphics/Abstract/IColorPresets.cs b/Nerd_STF/Graphics/Abstract/IColorPresets.cs new file mode 100644 index 0000000..b38a964 --- /dev/null +++ b/Nerd_STF/Graphics/Abstract/IColorPresets.cs @@ -0,0 +1,17 @@ +namespace Nerd_STF.Graphics.Abstract; + +public interface IColorPresets where T : IColorPresets +{ + public static abstract T Black { get; } + public static abstract T Blue { get; } + public static abstract T Clear { get; } + public static abstract T Cyan { get; } + public static abstract T Gray { get; } + public static abstract T Green { get; } + public static abstract T Magenta { get; } + public static abstract T Orange { get; } + public static abstract T Purple { get; } + public static abstract T Red { get; } + public static abstract T White { get; } + public static abstract T Yellow { get; } +} diff --git a/Nerd_STF/Graphics/CMYKA.cs b/Nerd_STF/Graphics/CMYKA.cs index 7b4a3f8..c3957e4 100644 --- a/Nerd_STF/Graphics/CMYKA.cs +++ b/Nerd_STF/Graphics/CMYKA.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Graphics; -public struct CMYKA : IColorFloat, IEquatable +public record struct CMYKA : IAverage, IClamp, IColorFloat, IColorPresets, + IEquatable, IIndexAll, IIndexRangeAll, ILerp, IMedian, + ISplittable { public static CMYKA Black => new(0, 0, 0, 1); public static CMYKA Blue => new(1, 1, 0, 0); @@ -103,6 +105,28 @@ public struct CMYKA : IColorFloat, IEquatable } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 5 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 5 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static CMYKA Average(params CMYKA[] vals) { @@ -111,16 +135,12 @@ public struct CMYKA : IColorFloat, IEquatable return val / vals.Length; } - public static CMYKA Ceiling(CMYKA val) => new(Mathf.Ceiling(val.C), Mathf.Ceiling(val.M), - Mathf.Ceiling(val.Y), Mathf.Ceiling(val.K), Mathf.Ceiling(val.A)); public static CMYKA Clamp(CMYKA val, CMYKA min, CMYKA max) => new(Mathf.Clamp(val.C, min.C, max.C), Mathf.Clamp(val.M, min.M, max.M), Mathf.Clamp(val.Y, min.Y, max.Y), Mathf.Clamp(val.K, min.K, max.K), Mathf.Clamp(val.A, min.A, max.A)); - public static CMYKA Floor(CMYKA val) => new(Mathf.Floor(val.C), Mathf.Floor(val.M), - Mathf.Floor(val.Y), Mathf.Floor(val.K), Mathf.Floor(val.A)); public static CMYKA Lerp(CMYKA a, CMYKA b, float t, bool clamp = true) => new(Mathf.Lerp(a.C, b.C, t, clamp), Mathf.Lerp(a.M, b.M, t, clamp), Mathf.Lerp(a.Y, b.Y, t, clamp), Mathf.Lerp(a.K, b.K, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp)); @@ -136,18 +156,6 @@ public struct CMYKA : IColorFloat, IEquatable CMYKA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; return Average(valA, valB); } - public static CMYKA Max(params CMYKA[] vals) - { - (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) = SplitArray(vals); - return new(Mathf.Max(Cs), Mathf.Max(Ms), Mathf.Max(Ys), Mathf.Max(Ks), Mathf.Max(As)); - } - public static CMYKA Min(params CMYKA[] vals) - { - (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) = SplitArray(vals); - return new(Mathf.Min(Cs), Mathf.Min(Ms), Mathf.Min(Ys), Mathf.Min(Ks), Mathf.Min(As)); - } - public static CMYKA Round(CMYKA val) => new(Mathf.Round(val.C), Mathf.Round(val.M), - Mathf.Round(val.Y), Mathf.Round(val.K), Mathf.Round(val.A)); public static (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) SplitArray(params CMYKA[] vals) { @@ -165,33 +173,10 @@ public struct CMYKA : IColorFloat, IEquatable return (Cs, Ms, Ys, Ks, As); } - public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKA()); - public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKA()); + public bool Equals(IColor? 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; - public override bool Equals([NotNullWhen(true)] object? obj) - { - 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((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); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode() ^ K.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider) - + " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider) - + " A: " + A.ToString(provider); - public string ToString(string? provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider) - + " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider) - + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() { @@ -224,7 +209,20 @@ public struct CMYKA : IColorFloat, IEquatable yield return A; } - public object Clone() => new CMYKA(C, M, Y, K, A); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("C = "); + builder.Append(C); + builder.Append(", M = "); + builder.Append(M); + builder.Append(", Y = "); + builder.Append(Y); + builder.Append(", K = "); + builder.Append(K); + builder.Append(", A = "); + builder.Append(A); + return true; + } public static CMYKA operator +(CMYKA a, CMYKA b) => new(a.C + b.C, a.M + b.M, a.Y + b.Y, a.K + b.K, a.A + b.A); public static CMYKA operator -(CMYKA c) => new(1 - c.C, 1 - c.M, 1 - c.Y, 1 - c.K, c.A != 1 ? 1 - c.A : 1); @@ -233,25 +231,23 @@ public struct CMYKA : IColorFloat, IEquatable public static CMYKA operator *(CMYKA a, float b) => new(a.C * b, a.M * b, a.Y * b, a.K * b, a.A * b); public static CMYKA operator /(CMYKA a, CMYKA b) => new(a.C / b.C, a.M / b.M, a.Y / b.Y, a.K / b.K, a.A / b.A); public static CMYKA operator /(CMYKA a, float b) => new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / b); - public static bool operator ==(CMYKA a, RGBA b) => a.Equals(b); - public static bool operator !=(CMYKA a, RGBA b) => !a.Equals(b); - public static bool operator ==(CMYKA a, CMYKA b) => a.Equals(b); - public static bool operator !=(CMYKA a, CMYKA b) => !a.Equals(b); public static bool operator ==(CMYKA a, HSVA b) => a.Equals(b); - public static bool operator !=(CMYKA a, HSVA b) => !a.Equals(b); - public static bool operator ==(CMYKA a, RGBAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(CMYKA a, RGBAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(CMYKA a, CMYKAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(CMYKA a, HSVAByte b) => !a.Equals((IColorByte?)b); + public static bool operator !=(CMYKA a, HSVA b) => a.Equals(b); + public static bool operator ==(CMYKA a, RGBA b) => a.Equals(b); + public static bool operator !=(CMYKA a, RGBA b) => a.Equals(b); + public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals(b); + public static bool operator !=(CMYKA a, CMYKAByte b) => a.Equals(b); + public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals(b); + public static bool operator !=(CMYKA a, HSVAByte b) => a.Equals(b); + public static bool operator ==(CMYKA a, RGBAByte b) => a.Equals(b); + public static bool operator !=(CMYKA a, RGBAByte b) => a.Equals(b); public static explicit operator CMYKA(Float3 val) => new(val.x, val.y, val.z, 0); public static implicit operator CMYKA(Float4 val) => new(val.x, val.y, val.z, val.w); - public static implicit operator CMYKA(RGBA val) => val.ToCMYKA(); public static implicit operator CMYKA(HSVA val) => val.ToCMYKA(); - public static implicit operator CMYKA(RGBAByte val) => val.ToCMYKA(); + public static implicit operator CMYKA(RGBA val) => val.ToCMYKA(); public static implicit operator CMYKA(CMYKAByte val) => val.ToCMYKA(); public static implicit operator CMYKA(HSVAByte val) => val.ToCMYKA(); + public static implicit operator CMYKA(RGBAByte val) => val.ToCMYKA(); public static implicit operator CMYKA(Fill val) => new(val); } diff --git a/Nerd_STF/Graphics/CMYKAByte.cs b/Nerd_STF/Graphics/CMYKAByte.cs index ee85963..a3dcf13 100644 --- a/Nerd_STF/Graphics/CMYKAByte.cs +++ b/Nerd_STF/Graphics/CMYKAByte.cs @@ -1,21 +1,50 @@ namespace Nerd_STF.Graphics; -public struct CMYKAByte : IColorByte, IEquatable +public record struct CMYKAByte : IAverage, IClamp, IColorByte, + IColorPresets, IEquatable, IIndexAll, IIndexRangeAll, + ILerp, IMedian, + ISplittable { - public static CMYKA Black => new(0, 0, 0, 255); - public static CMYKA Blue => new(255, 255, 0, 0); - public static CMYKA Clear => new(0, 0, 0, 0, 0); - public static CMYKA Cyan => new(255, 0, 0, 0); - public static CMYKA Gray => new(0, 0, 0, 127); - public static CMYKA Green => new(255, 0, 255, 0); - public static CMYKA Magenta => new(0, 255, 0, 0); - public static CMYKA Orange => new(0, 127, 255, 0); - public static CMYKA Purple => new(127, 255, 0, 0); - public static CMYKA Red => new(0, 255, 255, 0); - public static CMYKA White => new(0, 0, 0, 0); - public static CMYKA Yellow => new(0, 0, 255, 0); + public static CMYKAByte Black => new(0, 0, 0, 255); + public static CMYKAByte Blue => new(255, 255, 0, 0); + public static CMYKAByte Clear => new(0, 0, 0, 0, 0); + public static CMYKAByte Cyan => new(255, 0, 0, 0); + public static CMYKAByte Gray => new(0, 0, 0, 127); + public static CMYKAByte Green => new(255, 0, 255, 0); + public static CMYKAByte Magenta => new(0, 255, 0, 0); + public static CMYKAByte Orange => new(0, 127, 255, 0); + public static CMYKAByte Purple => new(127, 255, 0, 0); + public static CMYKAByte Red => new(0, 255, 255, 0); + public static CMYKAByte White => new(0, 0, 0, 0); + public static CMYKAByte Yellow => new(0, 0, 255, 0); - public byte C, M, Y, K, A; + public int C + { + get => p_c; + set => p_c = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int M + { + get => p_m; + set => p_m = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int Y + { + get => p_y; + set => p_y = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int K + { + get => p_k; + set => p_k = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int A + { + get => p_a; + set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + + private byte p_c, p_m, p_y, p_k, p_a; public bool HasCyan => C > 0; public bool HasMagenta => M > 0; @@ -30,16 +59,16 @@ public struct CMYKAByte : IColorByte, IEquatable public CMYKAByte(int c, int m, int y, int k) : this(c, m, y, k, 255) { } public CMYKAByte(int c, int m, int y, int k, int a) { - C = (byte)Mathf.Clamp(c, 0, 255); - M = (byte)Mathf.Clamp(m, 0, 255); - Y = (byte)Mathf.Clamp(y, 0, 255); - K = (byte)Mathf.Clamp(k, 0, 255); - A = (byte)Mathf.Clamp(a, 0, 255); + p_c = (byte)Mathf.Clamp(c, 0, 255); + p_m = (byte)Mathf.Clamp(m, 0, 255); + p_y = (byte)Mathf.Clamp(y, 0, 255); + p_k = (byte)Mathf.Clamp(k, 0, 255); + p_a = (byte)Mathf.Clamp(a, 0, 255); } public CMYKAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4)) { } public CMYKAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4)) { } - public byte this[int index] + public int this[int index] { get => index switch { @@ -78,6 +107,28 @@ public struct CMYKAByte : IColorByte, IEquatable } } } + public int this[Index index] + { + get => this[index.IsFromEnd ? 5 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 5 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static CMYKAByte Average(params CMYKAByte[] vals) { @@ -101,16 +152,6 @@ public struct CMYKAByte : IColorByte, IEquatable CMYKAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; return Average(valA, valB); } - public static CMYKAByte Max(params CMYKAByte[] vals) - { - (int[] Cs, int[] Ms, int[] Ys, int[] Ks, int[] As) = SplitArrayInt(vals); - return new(Mathf.Max(Cs), Mathf.Max(Ms), Mathf.Max(Ys), Mathf.Max(Ks), Mathf.Max(As)); - } - public static CMYKAByte Min(params CMYKAByte[] vals) - { - (int[] Cs, int[] Ms, int[] Ys, int[] Ks, int[] As) = SplitArrayInt(vals); - return new(Mathf.Min(Cs), Mathf.Min(Ms), Mathf.Min(Ys), Mathf.Min(Ks), Mathf.Min(As)); - } public static (byte[] Cs, byte[] Ms, byte[] Ys, byte[] Ks, byte[] As) SplitArray(params CMYKAByte[] vals) { @@ -119,11 +160,11 @@ public struct CMYKAByte : IColorByte, IEquatable As = new byte[vals.Length]; for (int i = 0; i < vals.Length; i++) { - Cs[i] = vals[i].C; - Ms[i] = vals[i].M; - Ys[i] = vals[i].Y; - Ks[i] = vals[i].K; - As[i] = vals[i].A; + Cs[i] = vals[i].p_c; + Ms[i] = vals[i].p_m; + Ys[i] = vals[i].p_y; + Ks[i] = vals[i].p_k; + As[i] = vals[i].p_a; } return (Cs, Ms, Ys, Ks, As); } @@ -143,34 +184,10 @@ public struct CMYKAByte : IColorByte, IEquatable return (Cs, Ms, Ys, Ks, As); } - 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; - public override bool Equals([NotNullWhen(true)] object? obj) - { - 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((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((IColorFloat)obj); - else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode() - ^ K.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider) - + " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider) - + " K: " + K.ToString(provider) + " A: " + A.ToString(provider); - public string ToString(string? provider) => "C: " + C.ToString(provider) - + " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider) - + " K: " + K.ToString(provider) + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte()); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() => ToCMYKA().ToRGBA(); public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f); @@ -180,25 +197,45 @@ public struct CMYKAByte : IColorByte, IEquatable public CMYKAByte ToCMYKAByte() => this; public HSVAByte ToHSVAByte() => ToCMYKA().ToHSVAByte(); - public byte[] ToArray() => new[] { C, M, Y, K, A }; + public byte[] ToArray() => new[] { p_c, p_m, p_y, p_k, p_a }; + public int[] ToArrayInt() => new[] { C, M, Y, K, A }; public Fill ToFill() + { + CMYKAByte @this = this; + return i => (byte)@this[i]; + } + public Fill ToFillInt() { CMYKAByte @this = this; return i => @this[i]; } - public List ToList() => new() { C, M, Y, K, A }; + public List ToList() => new() { p_c, p_m, p_y, p_k, p_a }; + public List ToListInt() => new() { C, M, Y, K, A }; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() { - yield return C; - yield return M; - yield return Y; - yield return K; - yield return A; + yield return p_c; + yield return p_m; + yield return p_y; + yield return p_k; + yield return p_a; } - public object Clone() => new CMYKAByte(C, M, Y, K, A); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("C = "); + builder.Append(C); + builder.Append(", M = "); + builder.Append(M); + builder.Append(", Y = "); + builder.Append(Y); + builder.Append(", K = "); + builder.Append(K); + builder.Append(", A = "); + builder.Append(A); + return true; + } public static CMYKAByte operator +(CMYKAByte a, CMYKAByte b) => new(a.C + b.C, a.M + b.M, a.Y + b.Y, a.K + b.K, a.A + b.A); @@ -216,26 +253,24 @@ 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((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); - public static bool operator !=(CMYKAByte a, CMYKAByte b) => !a.Equals(b); + public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals(b); + public static bool operator !=(CMYKAByte a, CMYKA b) => a.Equals(b); + public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals(b); + public static bool operator !=(CMYKAByte a, HSVA b) => a.Equals(b); + public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals(b); + public static bool operator !=(CMYKAByte a, RGBA b) => a.Equals(b); public static bool operator ==(CMYKAByte a, HSVAByte b) => a.Equals(b); - public static bool operator !=(CMYKAByte a, HSVAByte b) => !a.Equals(b); + public static bool operator !=(CMYKAByte a, HSVAByte b) => a.Equals(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 explicit operator CMYKAByte(Int3 val) => new(val.x, val.y, val.z, 0); public static implicit operator CMYKAByte(Int4 val) => new(val.x, val.y, val.z, val.w); - public static implicit operator CMYKAByte(RGBA val) => val.ToCMYKAByte(); public static implicit operator CMYKAByte(HSVA val) => val.ToCMYKAByte(); - public static implicit operator CMYKAByte(RGBAByte val) => val.ToCMYKAByte(); + public static implicit operator CMYKAByte(RGBA val) => val.ToCMYKAByte(); public static implicit operator CMYKAByte(CMYKA val) => val.ToCMYKAByte(); public static implicit operator CMYKAByte(HSVAByte val) => val.ToCMYKAByte(); + public static implicit operator CMYKAByte(RGBAByte val) => val.ToCMYKAByte(); public static implicit operator CMYKAByte(Fill val) => new(val); public static implicit operator CMYKAByte(Fill val) => new(val); } diff --git a/Nerd_STF/Graphics/HSVA.cs b/Nerd_STF/Graphics/HSVA.cs index 222a28a..8597e23 100644 --- a/Nerd_STF/Graphics/HSVA.cs +++ b/Nerd_STF/Graphics/HSVA.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Graphics; -public struct HSVA : IColorFloat, IEquatable +public record struct HSVA : IAverage, IClamp, IColorFloat, IColorPresets, IEquatable, + IIndexAll, IIndexRangeAll, ILerp, IMedian, + ISplittable { public static HSVA Black => new(Angle.Zero, 0, 0); public static HSVA Blue => new(new Angle(240), 1, 1); @@ -74,25 +76,47 @@ public struct HSVA : IColorFloat, IEquatable switch (index) { case 0: - H = new(Mathf.Clamp(value, 0, 1), Angle.Type.Normalized); + H = new(value, Angle.Type.Normalized); break; case 1: - S = Mathf.Clamp(value, 0, 1); + S = value; break; case 2: - V = Mathf.Clamp(value, 0, 1); + V = value; break; case 3: - A = Mathf.Clamp(value, 0, 1); + A = value; break; default: throw new IndexOutOfRangeException(nameof(index)); } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static HSVA Average(params HSVA[] vals) { @@ -100,15 +124,11 @@ public struct HSVA : IColorFloat, IEquatable for (int i = 0; i < vals.Length; i++) val += vals[i]; return val / vals.Length; } - public static HSVA Ceiling(HSVA val, Angle.Type type = Angle.Type.Degrees) => new(Angle.Ceiling(val.H, type), - Mathf.Ceiling(val.S), Mathf.Ceiling(val.V), Mathf.Ceiling(val.A)); public static HSVA Clamp(HSVA val, HSVA min, HSVA max) => new(Angle.Clamp(val.H, min.H, max.H), Mathf.Clamp(val.S, min.S, max.S), Mathf.Clamp(val.V, min.V, max.V), Mathf.Clamp(val.A, min.A, max.A)); - public static HSVA Floor(HSVA val, Angle.Type type = Angle.Type.Degrees) => new(Angle.Floor(val.H, type), - Mathf.Floor(val.S), Mathf.Floor(val.V), Mathf.Floor(val.A)); public static HSVA Lerp(HSVA a, HSVA b, float t, bool clamp = true) => new(Angle.Lerp(a.H, b.H, t, clamp), Mathf.Lerp(a.S, b.S, t, clamp), Mathf.Lerp(a.V, b.V, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp)); @@ -118,18 +138,6 @@ public struct HSVA : IColorFloat, IEquatable HSVA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; return Average(valA, valB); } - public static HSVA Max(params HSVA[] vals) - { - (Angle[] Hs, float[] Ss, float[] Vs, float[] As) = SplitArray(vals); - return new(Angle.Max(Hs), Mathf.Max(Ss), Mathf.Max(Vs), Mathf.Max(As)); - } - public static HSVA Min(params HSVA[] vals) - { - (Angle[] Hs, float[] Ss, float[] Vs, float[] As) = SplitArray(vals); - return new(Angle.Min(Hs), Mathf.Min(Ss), Mathf.Min(Vs), Mathf.Min(As)); - } - public static HSVA Round(HSVA val, Angle.Type type = Angle.Type.Degrees) => new(Angle.Round(val.H, type), - Mathf.Round(val.S), Mathf.Round(val.V), Mathf.Round(val.A)); public static (Angle[] Hs, float[] Ss, float[] Vs, float[] As) SplitArray(params HSVA[] vals) { @@ -159,31 +167,10 @@ public struct HSVA : IColorFloat, IEquatable return (Hs, Ss, Vs, As); } - public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVA()); - public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVA()); + public bool Equals(IColor? 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; - public override bool Equals([NotNullWhen(true)] object? obj) - { - 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((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); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider) - + " V: " + V.ToString(provider) + " A: " + A.ToString(provider); - public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider) - + " V: " + V.ToString(provider) + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() { @@ -222,32 +209,41 @@ public struct HSVA : IColorFloat, IEquatable yield return A; } - public object Clone() => new HSVA(H, S, V, A); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("H = "); + builder.Append(H); + builder.Append(", S = "); + builder.Append(S); + builder.Append(", V = "); + builder.Append(V); + builder.Append(", A = "); + builder.Append(A); + return true; + } public static HSVA operator +(HSVA a, HSVA b) => new(a.H + b.H, a.S + b.S, a.V + b.V, a.A + b.A); public static HSVA operator -(HSVA c) => new(1 - c.H.Normalized, 1 - c.S, 1 - c.V, c.A != 1 ? 1 - c.A : 1); public static HSVA operator -(HSVA a, HSVA b) => new(a.H - b.H, a.S - b.S, a.V - b.V, a.A - b.A); public static HSVA operator *(HSVA a, float b) => new(a.H * b, a.S * b, a.V * b, a.A * b); public static HSVA operator /(HSVA a, float b) => new(a.H / b, a.S / b, a.V / b, a.A / b); - public static bool operator ==(HSVA a, RGBA b) => a.Equals(b); - public static bool operator !=(HSVA a, RGBA b) => !a.Equals(b); public static bool operator ==(HSVA a, CMYKA b) => a.Equals(b); - public static bool operator !=(HSVA a, CMYKA b) => !a.Equals(b); - public static bool operator ==(HSVA a, HSVA b) => a.Equals(b); - public static bool operator !=(HSVA a, HSVA b) => !a.Equals(b); - public static bool operator ==(HSVA a, RGBAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(HSVA a, RGBAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(HSVA a, CMYKAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(HSVA a, HSVAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(HSVA a, HSVAByte b) => !a.Equals((IColorByte?)b); + public static bool operator !=(HSVA a, CMYKA b) => a.Equals(b); + public static bool operator ==(HSVA a, RGBA b) => a.Equals(b); + public static bool operator !=(HSVA a, RGBA b) => a.Equals(b); + public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals(b); + public static bool operator !=(HSVA a, CMYKAByte b) => a.Equals(b); + public static bool operator ==(HSVA a, HSVAByte b) => a.Equals(b); + public static bool operator !=(HSVA a, HSVAByte b) => a.Equals(b); + public static bool operator ==(HSVA a, RGBAByte b) => a.Equals(b); + public static bool operator !=(HSVA a, RGBAByte b) => a.Equals(b); public static explicit operator HSVA(Float3 val) => new(val.x, val.y, val.z); public static explicit operator HSVA(Float4 val) => new(val.x, val.y, val.z, val.w); public static implicit operator HSVA(CMYKA val) => val.ToHSVA(); public static implicit operator HSVA(RGBA val) => val.ToHSVA(); - public static implicit operator HSVA(RGBAByte val) => val.ToHSVA(); public static implicit operator HSVA(CMYKAByte val) => val.ToHSVA(); public static implicit operator HSVA(HSVAByte val) => val.ToHSVA(); + public static implicit operator HSVA(RGBAByte val) => val.ToHSVA(); public static implicit operator HSVA(Fill val) => new(val); } diff --git a/Nerd_STF/Graphics/HSVAByte.cs b/Nerd_STF/Graphics/HSVAByte.cs index f7e5a08..3927c0e 100644 --- a/Nerd_STF/Graphics/HSVAByte.cs +++ b/Nerd_STF/Graphics/HSVAByte.cs @@ -1,21 +1,44 @@ namespace Nerd_STF.Graphics; -public struct HSVAByte : IColorByte, IEquatable +public record struct HSVAByte : IAverage, IClamp, IColorByte, IColorPresets, + IEquatable, IIndexAll, IIndexRangeAll, ILerp, IMedian, + ISplittable { - public static HSVA Black => new(Angle.Zero, 0, 0); - public static HSVA Blue => new(new Angle(240), 255, 255); - public static HSVA Clear => new(Angle.Zero, 0, 0, 0); - public static HSVA Cyan => new(new Angle(180), 255, 255); - public static HSVA Gray => new(Angle.Zero, 0, 127); - public static HSVA Green => new(new Angle(120), 255, 255); - public static HSVA Magenta => new(new Angle(300), 255, 255); - public static HSVA Orange => new(new Angle(30), 255, 255); - public static HSVA Purple => new(new Angle(270), 255, 255); - public static HSVA Red => new(Angle.Zero, 255, 255); - public static HSVA White => new(Angle.Zero, 0, 255); - public static HSVA Yellow => new(new Angle(60), 255, 255); + public static HSVAByte Black => new(Angle.Zero, 0, 0); + public static HSVAByte Blue => new(new Angle(240), 255, 255); + public static HSVAByte Clear => new(Angle.Zero, 0, 0, 0); + public static HSVAByte Cyan => new(new Angle(180), 255, 255); + public static HSVAByte Gray => new(Angle.Zero, 0, 127); + public static HSVAByte Green => new(new Angle(120), 255, 255); + public static HSVAByte Magenta => new(new Angle(300), 255, 255); + public static HSVAByte Orange => new(new Angle(30), 255, 255); + public static HSVAByte Purple => new(new Angle(270), 255, 255); + public static HSVAByte Red => new(Angle.Zero, 255, 255); + public static HSVAByte White => new(Angle.Zero, 0, 255); + public static HSVAByte Yellow => new(new Angle(60), 255, 255); - public byte H, S, V, A; + public int H + { + get => p_h; + set => p_h = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int S + { + get => p_s; + set => p_s = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int V + { + get => p_v; + set => p_v = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int A + { + get => p_a; + set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + + private byte p_h, p_s, p_v, p_a; public bool HasColor => S != 0 && V != 0; public bool IsOpaque => A == 255; @@ -27,17 +50,17 @@ public struct HSVAByte : IColorByte, IEquatable public HSVAByte(int h, int s, int v) : this(h, s, v, 255) { } public HSVAByte(int h, int s, int v, int a) { - H = (byte)Mathf.Clamp(h, 0, 255); - S = (byte)Mathf.Clamp(s, 0, 255); - V = (byte)Mathf.Clamp(v, 0, 255); - A = (byte)Mathf.Clamp(a, 0, 255); + p_h = (byte)Mathf.Clamp(h, 0, 255); + p_s = (byte)Mathf.Clamp(s, 0, 255); + p_v = (byte)Mathf.Clamp(v, 0, 255); + p_a = (byte)Mathf.Clamp(a, 0, 255); } public HSVAByte(Angle h, int s, int v) : this(h, s, v, 255) { } public HSVAByte(Angle h, int s, int v, int a) : this(Mathf.RoundInt(h.Normalized * 255), s, v, a) { } public HSVAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } public HSVAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public byte this[int index] + public int this[int index] { get => index switch { @@ -71,6 +94,28 @@ public struct HSVAByte : IColorByte, IEquatable } } } + public int this[Index index] + { + get => this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static HSVAByte Average(params HSVAByte[] vals) { @@ -83,7 +128,7 @@ public struct HSVAByte : IColorByte, IEquatable Mathf.Clamp(val.S, min.S, max.S), Mathf.Clamp(val.V, min.V, max.V), Mathf.Clamp(val.A, min.A, max.A)); - public static HSVAByte Lerp(HSVAByte a, HSVAByte b, byte t, bool clamp = true) => + public static HSVAByte Lerp(HSVAByte a, HSVAByte b, float t, bool clamp = true) => new(Mathf.Lerp(a.H, b.H, t, clamp), Mathf.Lerp(a.S, b.S, t, clamp), Mathf.Lerp(a.V, b.V, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp)); public static HSVAByte Median(params HSVAByte[] vals) @@ -92,16 +137,6 @@ public struct HSVAByte : IColorByte, IEquatable HSVAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; return Average(valA, valB); } - public static HSVAByte Max(params HSVAByte[] vals) - { - (int[] Hs, int[] Ss, int[] Vs, int[] As) = SplitArrayInt(vals); - return new(Mathf.Max(Hs), Mathf.Max(Ss), Mathf.Max(Vs), Mathf.Max(As)); - } - public static HSVAByte Min(params HSVAByte[] vals) - { - (int[] Hs, int[] Ss, int[] Vs, int[] As) = SplitArrayInt(vals); - return new(Mathf.Min(Hs), Mathf.Min(Ss), Mathf.Min(Vs), Mathf.Min(As)); - } public static (byte[] Hs, byte[] Ss, byte[] Vs, byte[] As) SplitArray(params HSVAByte[] vals) { @@ -109,10 +144,10 @@ public struct HSVAByte : IColorByte, IEquatable Vs = new byte[vals.Length], As = new byte[vals.Length]; for (int i = 0; i < vals.Length; i++) { - Hs[i] = vals[i].H; - Ss[i] = vals[i].S; - Vs[i] = vals[i].V; - As[i] = vals[i].A; + Hs[i] = vals[i].p_h; + Ss[i] = vals[i].p_s; + Vs[i] = vals[i].p_v; + As[i] = vals[i].p_a; } return (Hs, Ss, Vs, As); } @@ -130,31 +165,10 @@ public struct HSVAByte : IColorByte, IEquatable return (Hs, Ss, Vs, As); } - public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVAByte()); - public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVAByte()); + public bool Equals(IColor? 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; - public override bool Equals([NotNullWhen(true)] object? obj) - { - 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((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((IColorFloat)obj); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider) - + " V: " + V.ToString(provider) + " A: " + A.ToString(provider); - public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider) - + " V: " + V.ToString(provider) + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() => ToHSVA().ToRGBA(); public CMYKA ToCMYKA() => ToHSVA().ToCMYKA(); @@ -164,24 +178,42 @@ public struct HSVAByte : IColorByte, IEquatable public CMYKAByte ToCMYKAByte() => ToHSVA().ToCMYKAByte(); public HSVAByte ToHSVAByte() => this; - public byte[] ToArray() => new[] { H, S, V, A }; + public byte[] ToArray() => new[] { p_h, p_s, p_v, p_a }; + public int[] ToArrayInt() => new[] { H, S, V, A }; public Fill ToFill() + { + HSVAByte @this = this; + return i => (byte)@this[i]; + } + public Fill ToFillInt() { HSVAByte @this = this; return i => @this[i]; } - public List ToList() => new() { H, S, V, A }; + public List ToList() => new() { p_h, p_s, p_v, p_a }; + public List ToListInt() => new() { H, S, V, A }; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() { - yield return H; - yield return S; - yield return V; - yield return A; + yield return p_h; + yield return p_s; + yield return p_v; + yield return p_a; } - public object Clone() => new HSVAByte(H, S, V, A); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("H = "); + builder.Append(H); + builder.Append(", S = "); + builder.Append(S); + builder.Append(", V = "); + builder.Append(V); + builder.Append(", A = "); + builder.Append(A); + return true; + } 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 c) => new(255 - c.H, 255 - c.S, 255 - c.V, c.A != 255 ? 255 - c.A : 255); @@ -192,18 +224,16 @@ 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((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, CMYKA b) => a.Equals(b); + public static bool operator !=(HSVAByte a, CMYKA b) => a.Equals(b); + public static bool operator ==(HSVAByte a, HSVA b) => a.Equals(b); + public static bool operator !=(HSVAByte a, HSVA b) => a.Equals(b); + public static bool operator ==(HSVAByte a, RGBA b) => a.Equals(b); + public static bool operator !=(HSVAByte a, RGBA b) => a.Equals(b); public static bool operator ==(HSVAByte a, CMYKAByte b) => a.Equals(b); - public static bool operator !=(HSVAByte a, CMYKAByte b) => !a.Equals(b); - public static bool operator ==(HSVAByte a, HSVAByte b) => a.Equals(b); - public static bool operator !=(HSVAByte a, HSVAByte b) => !a.Equals(b); + public static bool operator !=(HSVAByte a, CMYKAByte b) => a.Equals(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 implicit operator HSVAByte(Int3 val) => new(val.x, val.y, val.z); public static implicit operator HSVAByte(Int4 val) => new(val.x, val.y, val.z, val.w); diff --git a/Nerd_STF/Graphics/IColor.cs b/Nerd_STF/Graphics/IColor.cs deleted file mode 100644 index 3b7f701..0000000 --- a/Nerd_STF/Graphics/IColor.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Nerd_STF.Graphics; - -public interface IColor : ICloneable, IEquatable, IEquatable -{ - public RGBA ToRGBA(); - public CMYKA ToCMYKA(); - public HSVA ToHSVA(); - - public RGBAByte ToRGBAByte(); - public CMYKAByte ToCMYKAByte(); - public HSVAByte ToHSVAByte(); -} diff --git a/Nerd_STF/Graphics/IColorByte.cs b/Nerd_STF/Graphics/IColorByte.cs deleted file mode 100644 index 903293d..0000000 --- a/Nerd_STF/Graphics/IColorByte.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Nerd_STF.Graphics; - -public interface IColorByte : IColor, IGroup { } diff --git a/Nerd_STF/Graphics/IColorFloat.cs b/Nerd_STF/Graphics/IColorFloat.cs deleted file mode 100644 index 2978b35..0000000 --- a/Nerd_STF/Graphics/IColorFloat.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Nerd_STF.Graphics; - -public interface IColorFloat : IColor, IGroup { } diff --git a/Nerd_STF/Graphics/Image.cs b/Nerd_STF/Graphics/Image.cs index 44200e2..e72308f 100644 --- a/Nerd_STF/Graphics/Image.cs +++ b/Nerd_STF/Graphics/Image.cs @@ -1,9 +1,9 @@ namespace Nerd_STF.Graphics; -public struct Image : ICloneable, IEnumerable, IEquatable +public class Image : ICloneable, IEnumerable, IEquatable { - public IColor[,] Pixels { get; init; } - public Int2 Size { get; init; } + public IColor[,] Pixels { get; private set; } + public Int2 Size { get; private set; } public Image(int width, int height) { @@ -58,7 +58,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable public object Clone() => new Image(Size, Pixels); - public bool Equals(Image other) => Pixels == other.Pixels; + public bool Equals(Image? other) => other is not null && Pixels == other.Pixels; public override bool Equals([NotNullWhen(true)] object? obj) { if (obj == null) return base.Equals(obj); @@ -110,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 ? 1 : col.S) * value; Pixels[x, y] = col; } } @@ -133,7 +133,8 @@ public struct Image : ICloneable, IEnumerable, IEquatable RGBA col = Pixels[Mathf.Floor(f.x * Size.x), Mathf.Floor(f.y * Size.y)].ToRGBA(); img[x, y] = col; } - this = img; + Pixels = img.Pixels; + Size = img.Size; } public IColor[] ToArray() diff --git a/Nerd_STF/Graphics/Material.cs b/Nerd_STF/Graphics/Material.cs index 71526f4..a4e3c0c 100644 --- a/Nerd_STF/Graphics/Material.cs +++ b/Nerd_STF/Graphics/Material.cs @@ -1,4 +1,6 @@ -namespace Nerd_STF.Graphics; +using Nerd_STF.Graphics.Abstract; + +namespace Nerd_STF.Graphics; public struct Material : ICloneable, IEquatable { diff --git a/Nerd_STF/Graphics/RGBA.cs b/Nerd_STF/Graphics/RGBA.cs index f3be995..58fdff1 100644 --- a/Nerd_STF/Graphics/RGBA.cs +++ b/Nerd_STF/Graphics/RGBA.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Graphics; -public struct RGBA : IColorFloat, IEquatable +public record struct RGBA : IAverage, IClamp, IColorFloat, IEquatable, IIndexAll, + IIndexRangeAll, ILerp, IMedian, + ISplittable { public static RGBA Black => new(0, 0, 0); public static RGBA Blue => new(0, 0, 1); @@ -91,6 +93,28 @@ public struct RGBA : IColorFloat, IEquatable } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static RGBA Average(params RGBA[] vals) { @@ -98,15 +122,11 @@ public struct RGBA : IColorFloat, IEquatable for (int i = 0; i < vals.Length; i++) val += vals[i]; return val / vals.Length; } - public static RGBA Ceiling(RGBA val) => - new(Mathf.Ceiling(val.R), Mathf.Ceiling(val.G), Mathf.Ceiling(val.B), Mathf.Ceiling(val.A)); public static RGBA Clamp(RGBA val, RGBA min, RGBA max) => new(Mathf.Clamp(val.R, min.R, max.R), Mathf.Clamp(val.G, min.G, max.G), Mathf.Clamp(val.B, min.B, max.B), Mathf.Clamp(val.A, min.A, max.A)); - public static RGBA Floor(RGBA val) => - new(Mathf.Floor(val.R), Mathf.Floor(val.G), Mathf.Floor(val.B), Mathf.Floor(val.A)); public static RGBA Lerp(RGBA a, RGBA b, float t, bool clamp = true) => new(Mathf.Lerp(a.R, b.R, t, clamp), Mathf.Lerp(a.G, b.G, t, clamp), Mathf.Lerp(a.B, b.B, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp)); @@ -122,18 +142,6 @@ public struct RGBA : IColorFloat, IEquatable RGBA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; return Average(valA, valB); } - public static RGBA Max(params RGBA[] vals) - { - (float[] Rs, float[] Gs, float[] Bs, float[] As) = SplitArray(vals); - return new(Mathf.Max(Rs), Mathf.Max(Gs), Mathf.Max(Bs), Mathf.Max(As)); - } - public static RGBA Min(params RGBA[] vals) - { - (float[] Rs, float[] Gs, float[] Bs, float[] As) = SplitArray(vals); - return new(Mathf.Min(Rs), Mathf.Min(Gs), Mathf.Min(Bs), Mathf.Min(As)); - } - public static RGBA Round(RGBA val) => - new(Mathf.Round(val.R), Mathf.Round(val.G), Mathf.Round(val.B), Mathf.Round(val.A)); public static (float[] Rs, float[] Gs, float[] Bs, float[] As) SplitArray(params RGBA[] vals) { @@ -149,30 +157,9 @@ public struct RGBA : IColorFloat, IEquatable return (Rs, Gs, Bs, As); } - public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBA()); - public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBA()); + public bool Equals(IColor? 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) - { - 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((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); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) + - " B: " + B.ToString(provider) + " A: " + A.ToString(provider); - public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) + - " B: " + B.ToString(provider) + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() => this; public CMYKA ToCMYKA() @@ -223,10 +210,21 @@ public struct RGBA : IColorFloat, IEquatable yield return A; } - public object Clone() => new RGBA(R, G, B, A); - public Vector3d ToVector() => ((Float3)this).ToVector(); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("R = "); + builder.Append(R); + builder.Append(", G = "); + builder.Append(G); + builder.Append(", B = "); + builder.Append(B); + builder.Append(", A = "); + builder.Append(A); + return true; + } + public static RGBA operator +(RGBA a, RGBA b) => new(a.R + b.R, a.G + b.G, a.B + b.B, a.A + b.A); public static RGBA operator -(RGBA c) => new(1 - c.R, 1 - c.G, 1 - c.B, c.A != 1 ? 1 - c.A : 1); public static RGBA operator -(RGBA a, RGBA b) => new(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A); @@ -234,25 +232,23 @@ public struct RGBA : IColorFloat, IEquatable public static RGBA operator *(RGBA a, float b) => new(a.R * b, a.G * b, a.B * b, a.A * b); public static RGBA operator /(RGBA a, RGBA b) => new(a.R / b.R, a.G / b.G, a.B / b.B, a.A / b.A); public static RGBA operator /(RGBA a, float b) => new(a.R / b, a.G / b, a.B / b, a.A / b); - public static bool operator ==(RGBA a, RGBA b) => a.Equals(b); - public static bool operator !=(RGBA a, RGBA b) => !a.Equals(b); public static bool operator ==(RGBA a, CMYKA b) => a.Equals(b); - public static bool operator !=(RGBA a, CMYKA b) => !a.Equals(b); + public static bool operator !=(RGBA a, CMYKA b) => a.Equals(b); public static bool operator ==(RGBA a, HSVA b) => a.Equals(b); - public static bool operator !=(RGBA a, HSVA b) => !a.Equals(b); - public static bool operator ==(RGBA a, RGBAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(RGBA a, RGBAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(RGBA a, CMYKAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(RGBA a, CMYKAByte b) => !a.Equals((IColorByte?)b); - public static bool operator ==(RGBA a, HSVAByte b) => a.Equals((IColorByte?)b); - public static bool operator !=(RGBA a, HSVAByte b) => !a.Equals((IColorByte?)b); + public static bool operator !=(RGBA a, HSVA b) => a.Equals(b); + public static bool operator ==(RGBA a, CMYKAByte b) => a.Equals(b); + public static bool operator !=(RGBA a, CMYKAByte b) => a.Equals(b); + public static bool operator ==(RGBA a, HSVAByte b) => a.Equals(b); + public static bool operator !=(RGBA a, HSVAByte b) => a.Equals(b); + public static bool operator ==(RGBA a, RGBAByte b) => a.Equals(b); + public static bool operator !=(RGBA a, RGBAByte b) => a.Equals(b); public static implicit operator RGBA(Float3 val) => new(val.x, val.y, val.z); public static implicit operator RGBA(Float4 val) => new(val.x, val.y, val.z, val.w); public static implicit operator RGBA(CMYKA val) => val.ToRGBA(); public static implicit operator RGBA(HSVA val) => val.ToRGBA(); - public static implicit operator RGBA(RGBAByte val) => val.ToRGBA(); public static implicit operator RGBA(CMYKAByte val) => val.ToRGBA(); public static implicit operator RGBA(HSVAByte val) => val.ToRGBA(); + public static implicit operator RGBA(RGBAByte val) => val.ToRGBA(); public static implicit operator RGBA(Fill val) => new(val); } diff --git a/Nerd_STF/Graphics/RGBAByte.cs b/Nerd_STF/Graphics/RGBAByte.cs index a8eb8b0..53e1a46 100644 --- a/Nerd_STF/Graphics/RGBAByte.cs +++ b/Nerd_STF/Graphics/RGBAByte.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Graphics; -public struct RGBAByte : IColorByte, IEquatable +public record struct RGBAByte : IAverage, IClamp, IColorByte, IColorPresets, + IEquatable, IIndexAll, IIndexRangeAll, ILerp, IMedian, + ISplittable { public static RGBAByte Black => new(0, 0, 0); public static RGBAByte Blue => new(0, 0, 255); @@ -15,7 +17,28 @@ public struct RGBAByte : IColorByte, IEquatable public static RGBAByte White => new(255, 255, 255); public static RGBAByte Yellow => new(255, 255, 0); - public byte R, G, B, A; + public int R + { + get => p_r; + set => p_r = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int G + { + get => p_g; + set => p_g = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int B + { + get => p_b; + set => p_b = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + public int A + { + get => p_a; + set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue); + } + + private byte p_r, p_g, p_b, p_a; public bool HasBlue => B > 0; public bool HasGreen => G > 0; @@ -37,7 +60,7 @@ public struct RGBAByte : IColorByte, IEquatable public RGBAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } public RGBAByte(Fill fill) : this(fill(0), fill(1), fill(2), fill(3)) { } - public byte this[int index] + public int this[int index] { get => index switch { @@ -71,6 +94,28 @@ public struct RGBAByte : IColorByte, IEquatable } } } + public int this[Index index] + { + get => this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static RGBAByte Average(params RGBAByte[] vals) { @@ -83,7 +128,7 @@ public struct RGBAByte : IColorByte, IEquatable Mathf.Clamp(val.G, min.G, max.G), Mathf.Clamp(val.B, min.B, max.B), Mathf.Clamp(val.A, min.A, max.A)); - public static RGBAByte Lerp(RGBAByte a, RGBAByte b, byte t, bool clamp = true) => + public static RGBAByte Lerp(RGBAByte a, RGBAByte b, float t, bool clamp = true) => new(Mathf.Lerp(a.R, b.R, t, clamp), Mathf.Lerp(a.G, b.G, t, clamp), Mathf.Lerp(a.B, b.B, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp)); public static RGBAByte LerpSquared(RGBAByte a, RGBAByte b, byte t, bool clamp = true) => @@ -111,10 +156,10 @@ public struct RGBAByte : IColorByte, IEquatable Bs = new byte[vals.Length], As = new byte[vals.Length]; for (int i = 0; i < vals.Length; i++) { - Rs[i] = vals[i].R; - Gs[i] = vals[i].G; - Bs[i] = vals[i].B; - As[i] = vals[i].A; + Rs[i] = vals[i].p_r; + Gs[i] = vals[i].p_g; + Bs[i] = vals[i].p_b; + As[i] = vals[i].p_a; } return (Rs, Gs, Bs, As); } @@ -132,30 +177,9 @@ public struct RGBAByte : IColorByte, IEquatable return (Rs, Gs, Bs, As); } - public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBAByte()); - public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBAByte()); + public bool Equals(IColor? 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) - { - 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((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); - else if (t == typeof(IColorByte)) return Equals((IColorByte)obj); - - return base.Equals(obj); - } - public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode(); - public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) + - " B: " + B.ToString(provider) + " A: " + A.ToString(provider); - public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) + - " B: " + B.ToString(provider) + " A: " + A.ToString(provider); - public override string ToString() => ToString((string?)null); + public override int GetHashCode() => base.GetHashCode(); public RGBA ToRGBA() => new(R / 255f, G / 255f, B / 255f, A / 255f); public CMYKA ToCMYKA() => ToRGBA().ToCMYKA(); @@ -165,27 +189,45 @@ public struct RGBAByte : IColorByte, IEquatable public CMYKAByte ToCMYKAByte() => ToRGBA().ToCMYKAByte(); public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte(); - public byte[] ToArray() => new[] { R, G, B, A }; + public byte[] ToArray() => new[] { p_r, p_g, p_b, p_a }; + public int[] ToArrayInt() => new[] { R, G, B, A }; public Fill ToFill() { - HSVAByte @this = this; + RGBAByte @this = this; + return i => (byte)@this[i]; + } + public Fill ToFillInt() + { + RGBAByte @this = this; return i => @this[i]; } - public List ToList() => new() { R, G, B, A }; + public List ToList() => new() { p_r, p_g, p_b, p_a }; + public List ToListInt() => new() { R, G, B, A }; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() { - yield return R; - yield return G; - yield return B; - yield return A; + yield return p_r; + yield return p_g; + yield return p_b; + yield return p_a; } - public object Clone() => new RGBAByte(R, G, B, A); - public Vector3d ToVector() => ((RGBA)this).ToVector(); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("R = "); + builder.Append(R); + builder.Append(", G = "); + builder.Append(G); + builder.Append(", B = "); + builder.Append(B); + builder.Append(", A = "); + builder.Append(A); + return true; + } + 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 c) => new(255 - c.R, 255 - c.G, 255 - c.B, c.A != 255 ? 255 - c.A : 255); 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); @@ -195,18 +237,16 @@ 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((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, CMYKA b) => a.Equals(b); + public static bool operator !=(RGBAByte a, CMYKA b) => a.Equals(b); + public static bool operator ==(RGBAByte a, HSVA b) => a.Equals(b); + public static bool operator !=(RGBAByte a, HSVA b) => a.Equals(b); + public static bool operator ==(RGBAByte a, RGBA b) => a.Equals(b); + public static bool operator !=(RGBAByte a, RGBA b) => a.Equals(b); public static bool operator ==(RGBAByte a, CMYKAByte b) => a.Equals(b); - public static bool operator !=(RGBAByte a, CMYKAByte b) => !a.Equals(b); + public static bool operator !=(RGBAByte a, CMYKAByte b) => a.Equals(b); public static bool operator ==(RGBAByte a, HSVAByte b) => a.Equals(b); - public static bool operator !=(RGBAByte a, HSVAByte b) => !a.Equals(b); + public static bool operator !=(RGBAByte a, HSVAByte b) => a.Equals(b); public static implicit operator RGBAByte(Int3 val) => new(val.x, val.y, val.z); public static implicit operator RGBAByte(Int4 val) => new(val.x, val.y, val.z, val.w); diff --git a/Nerd_STF/IClosest.cs b/Nerd_STF/IClosest.cs deleted file mode 100644 index 4ba047c..0000000 --- a/Nerd_STF/IClosest.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nerd_STF; - -public interface IClosest where T : IEquatable -{ - public T ClosestTo(T item); -} diff --git a/Nerd_STF/IContainer.cs b/Nerd_STF/IContainer.cs deleted file mode 100644 index 43dc911..0000000 --- a/Nerd_STF/IContainer.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Nerd_STF; - -public interface IContainer where T : IEquatable -{ - public bool Contains(T item); -} diff --git a/Nerd_STF/IEncapsulator.cs b/Nerd_STF/IEncapsulator.cs index 62f7de5..f02b25d 100644 --- a/Nerd_STF/IEncapsulator.cs +++ b/Nerd_STF/IEncapsulator.cs @@ -1,6 +1,6 @@ namespace Nerd_STF; -public interface IEncapsulator : IContainer where T : IEquatable where TE : IEquatable +public interface IEncapsulator : IContains where T : IEquatable where TE : IEquatable { public T Encapsulate(TE val); } diff --git a/Nerd_STF/Mathematics/Abstract/IAbsolute.cs b/Nerd_STF/Mathematics/Abstract/IAbsolute.cs new file mode 100644 index 0000000..47135bc --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IAbsolute.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IAbsolute where T : IAbsolute +{ + public static abstract T Absolute(T val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IAverage.cs b/Nerd_STF/Mathematics/Abstract/IAverage.cs new file mode 100644 index 0000000..e0ea024 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IAverage.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IAverage where T : IAverage +{ + public static abstract T Average(params T[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/ICeiling.cs b/Nerd_STF/Mathematics/Abstract/ICeiling.cs new file mode 100644 index 0000000..e7c5448 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ICeiling.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface ICeiling : ICeiling where TSelf : ICeiling { } +public interface ICeiling where TSelf : ICeiling +{ + public static abstract TRound Ceiling(TSelf val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IClamp.cs b/Nerd_STF/Mathematics/Abstract/IClamp.cs new file mode 100644 index 0000000..131f181 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IClamp.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IClamp where T : IClamp +{ + public static abstract T Clamp(T val, T min, T max); +} diff --git a/Nerd_STF/Mathematics/Abstract/IClampMagnitude.cs b/Nerd_STF/Mathematics/Abstract/IClampMagnitude.cs new file mode 100644 index 0000000..721c840 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IClampMagnitude.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IClampMagnitude + where TSelf : IClampMagnitude + where TNumber : INumber +{ + public static abstract TSelf ClampMagnitude(TSelf val, TNumber minMag, TNumber maxMag); +} +public interface IClampMagnitude where TSelf : IClampMagnitude +{ + public static abstract TSelf ClampMagnitude(TSelf val, TNumber minMag, TNumber maxMag) + where TNumber : INumber; +} diff --git a/Nerd_STF/Mathematics/Abstract/IClosestTo.cs b/Nerd_STF/Mathematics/Abstract/IClosestTo.cs new file mode 100644 index 0000000..7946d69 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IClosestTo.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IClosestTo where T : IEquatable +{ + public T ClosestTo(T item); +} diff --git a/Nerd_STF/Mathematics/Abstract/IContains.cs b/Nerd_STF/Mathematics/Abstract/IContains.cs new file mode 100644 index 0000000..c12be14 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IContains.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IContains where T : IEquatable +{ + public bool Contains(T item); +} diff --git a/Nerd_STF/Mathematics/Abstract/ICross.cs b/Nerd_STF/Mathematics/Abstract/ICross.cs new file mode 100644 index 0000000..bd21bea --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ICross.cs @@ -0,0 +1,8 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface ICross : ICross + where TSelf : ICross { } +public interface ICross where TSelf : ICross +{ + public static abstract TOut Cross(TSelf a, TSelf b, bool normalized = false); +} diff --git a/Nerd_STF/Mathematics/Abstract/IDivide.cs b/Nerd_STF/Mathematics/Abstract/IDivide.cs new file mode 100644 index 0000000..f6450bb --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IDivide.cs @@ -0,0 +1,8 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IDivide : IDivisionOperators where T : IDivide +{ + public static abstract T Divide(T num, params T[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IDot.cs b/Nerd_STF/Mathematics/Abstract/IDot.cs new file mode 100644 index 0000000..128f14e --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IDot.cs @@ -0,0 +1,18 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IDot + where TSelf : IDot + where TNumber : INumber +{ + public static abstract TNumber Dot(TSelf a, TSelf b); + public static abstract TNumber Dot(TSelf[] vals); +} +public interface IDot where TSelf : IDot +{ + public static abstract TNumber Dot(TSelf a, TSelf b) + where TNumber : INumber; + public static abstract TNumber Dot(TSelf[] vals) + where TNumber : INumber; +} diff --git a/Nerd_STF/Mathematics/Abstract/IFloor.cs b/Nerd_STF/Mathematics/Abstract/IFloor.cs new file mode 100644 index 0000000..f3bd949 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IFloor.cs @@ -0,0 +1,9 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IFloor : IFloor + where TSelf : IFloor { } +public interface IFloor + where TSelf : IFloor +{ + public static abstract TRound Floor(TSelf val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IFromTuple.cs b/Nerd_STF/Mathematics/Abstract/IFromTuple.cs new file mode 100644 index 0000000..16f05cf --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IFromTuple.cs @@ -0,0 +1,9 @@ +using System.Runtime.CompilerServices; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IFromTuple where TSelf : IFromTuple + where TTuple : ITuple +{ + public static abstract implicit operator TSelf(TTuple val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IIndexAll.cs b/Nerd_STF/Mathematics/Abstract/IIndexAll.cs new file mode 100644 index 0000000..fe58f74 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexAll.cs @@ -0,0 +1,3 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexAll : IIndexGet, IIndexSet { } diff --git a/Nerd_STF/Mathematics/Abstract/IIndexGet.cs b/Nerd_STF/Mathematics/Abstract/IIndexGet.cs new file mode 100644 index 0000000..ec6b4ed --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexGet.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexGet +{ + public TSub this[int index] { get; } + public TSub this[Index index] { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IIndexRangeAll.cs b/Nerd_STF/Mathematics/Abstract/IIndexRangeAll.cs new file mode 100644 index 0000000..51f9c0b --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexRangeAll.cs @@ -0,0 +1,3 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexRangeAll : IIndexRangeGet, IIndexRangeSet { } diff --git a/Nerd_STF/Mathematics/Abstract/IIndexRangeGet.cs b/Nerd_STF/Mathematics/Abstract/IIndexRangeGet.cs new file mode 100644 index 0000000..eb49a24 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexRangeGet.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexRangeGet +{ + public TSub[] this[Range range] { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IIndexRangeSet.cs b/Nerd_STF/Mathematics/Abstract/IIndexRangeSet.cs new file mode 100644 index 0000000..4ffffdb --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexRangeSet.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexRangeSet +{ + public TSub[] this[Range range] { set; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IIndexSet.cs b/Nerd_STF/Mathematics/Abstract/IIndexSet.cs new file mode 100644 index 0000000..28e8866 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IIndexSet.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IIndexSet +{ + public TSub this[int index] { set; } + public TSub this[Index index] { set; } +} diff --git a/Nerd_STF/Mathematics/Abstract/ILerp.cs b/Nerd_STF/Mathematics/Abstract/ILerp.cs new file mode 100644 index 0000000..ba017f3 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ILerp.cs @@ -0,0 +1,15 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface ILerp + where TSelf : ILerp + where TNumber : INumber +{ + public static abstract TSelf Lerp(TSelf a, TSelf b, TNumber t, bool clamp = true); +} +public interface ILerp where TSelf : ILerp +{ + public static abstract TSelf Lerp(TSelf a, TSelf b, TNumber t, bool clamp = true) + where TNumber : INumber; +} diff --git a/Nerd_STF/Mathematics/Abstract/IMagnitude.cs b/Nerd_STF/Mathematics/Abstract/IMagnitude.cs new file mode 100644 index 0000000..ef3fc92 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMagnitude.cs @@ -0,0 +1,8 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMagnitude where TNumber : INumber +{ + public TNumber Magnitude { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IMathOperators.cs b/Nerd_STF/Mathematics/Abstract/IMathOperators.cs new file mode 100644 index 0000000..d24228c --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMathOperators.cs @@ -0,0 +1,8 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMathOperators : IAdditionOperators, + ISubtractionOperators, IMultiplyOperators, + IDivisionOperators + where TSelf : IMathOperators { } diff --git a/Nerd_STF/Mathematics/Algebra/IMatrix.cs b/Nerd_STF/Mathematics/Abstract/IMatrix.cs similarity index 51% rename from Nerd_STF/Mathematics/Algebra/IMatrix.cs rename to Nerd_STF/Mathematics/Abstract/IMatrix.cs index 9e9339d..deb1b0a 100644 --- a/Nerd_STF/Mathematics/Algebra/IMatrix.cs +++ b/Nerd_STF/Mathematics/Abstract/IMatrix.cs @@ -1,11 +1,13 @@ -namespace Nerd_STF.Mathematics.Algebra; +namespace Nerd_STF.Mathematics.Abstract; -public interface IMatrix : ICloneable, IEnumerable, IEquatable, IGroup2D +public interface IMatrix : IAbsolute, ICeiling, IClamp, IDivide, + IEquatable, IFloor, IGroup2D, ILerp, IProduct, IRound, + ISubtract, ISum where T : IMatrix { public T Adjugate(); public float Determinant(); - public T Inverse(); + public T? Inverse(); public T Transpose(); } diff --git a/Nerd_STF/Mathematics/Abstract/IMatrixPresets.cs b/Nerd_STF/Mathematics/Abstract/IMatrixPresets.cs new file mode 100644 index 0000000..756a9bf --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMatrixPresets.cs @@ -0,0 +1,9 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMatrixPresets where T : IMatrix, IMatrixPresets +{ + public static abstract T Identity { get; } + public static abstract T One { get; } + public static abstract T SignGrid { get; } + public static abstract T Zero { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IMax.cs b/Nerd_STF/Mathematics/Abstract/IMax.cs new file mode 100644 index 0000000..aef3217 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMax.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMax where T : IMax, IComparable +{ + public static virtual T Max(params T[] vals) => Mathf.Max(vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IMedian.cs b/Nerd_STF/Mathematics/Abstract/IMedian.cs new file mode 100644 index 0000000..007b44e --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMedian.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMedian where T : IMedian +{ + public static virtual T Median(params T[] vals) => Mathf.Median(vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IMin.cs b/Nerd_STF/Mathematics/Abstract/IMin.cs new file mode 100644 index 0000000..bf1a3e6 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IMin.cs @@ -0,0 +1,6 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IMin where T : IMin, IComparable +{ + public static virtual T Min(params T[] vals) => Mathf.Min(vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IPresets1D.cs b/Nerd_STF/Mathematics/Abstract/IPresets1D.cs new file mode 100644 index 0000000..8caa6f3 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IPresets1D.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IPresets1D where T : IPresets1D +{ + public static abstract T One { get; } + public static abstract T Zero { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IPresets2D.cs b/Nerd_STF/Mathematics/Abstract/IPresets2D.cs new file mode 100644 index 0000000..b9f4b00 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IPresets2D.cs @@ -0,0 +1,9 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IPresets2D : IPresets1D where T : IPresets2D +{ + public static abstract T Down { get; } + public static abstract T Left { get; } + public static abstract T Right { get; } + public static abstract T Up { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IPresets3D.cs b/Nerd_STF/Mathematics/Abstract/IPresets3D.cs new file mode 100644 index 0000000..68772cc --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IPresets3D.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IPresets3D : IPresets2D where T : IPresets3D +{ + public static abstract T Back { get; } + public static abstract T Forward { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IPresets4D.cs b/Nerd_STF/Mathematics/Abstract/IPresets4D.cs new file mode 100644 index 0000000..188bfd7 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IPresets4D.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IPresets4D : IPresets2D, IPresets3D where T : IPresets4D +{ + public static abstract T HighW { get; } + public static abstract T LowW { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IProduct.cs b/Nerd_STF/Mathematics/Abstract/IProduct.cs new file mode 100644 index 0000000..49651ef --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IProduct.cs @@ -0,0 +1,9 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IProduct : IMultiplyOperators + where T : IProduct +{ + public static abstract T Product(params T[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IRound.cs b/Nerd_STF/Mathematics/Abstract/IRound.cs new file mode 100644 index 0000000..b4cd663 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IRound.cs @@ -0,0 +1,9 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IRound : IRound + where TSelf : IRound { } +public interface IRound + where TSelf : IRound +{ + public static abstract TRound Round(TSelf val); +} diff --git a/Nerd_STF/Mathematics/Abstract/IShape2D.cs b/Nerd_STF/Mathematics/Abstract/IShape2D.cs new file mode 100644 index 0000000..83bc19c --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IShape2D.cs @@ -0,0 +1,9 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IShape2D where TNumber : INumber +{ + public TNumber Area { get; } + public TNumber Perimeter { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/IShape3D.cs b/Nerd_STF/Mathematics/Abstract/IShape3D.cs new file mode 100644 index 0000000..babb384 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IShape3D.cs @@ -0,0 +1,9 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface IShape3D where TNumber : INumber +{ + public TNumber SurfaceArea { get; } + public TNumber Volume { get; } +} diff --git a/Nerd_STF/Mathematics/Abstract/ISplittable.cs b/Nerd_STF/Mathematics/Abstract/ISplittable.cs new file mode 100644 index 0000000..f20e6b0 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ISplittable.cs @@ -0,0 +1,8 @@ +using System.Runtime.CompilerServices; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface ISplittable where TTuple : ITuple +{ + public static abstract TTuple SplitArray(params TSelf[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/IStaticMatrix.cs b/Nerd_STF/Mathematics/Abstract/IStaticMatrix.cs new file mode 100644 index 0000000..e8287b9 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/IStaticMatrix.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface IStaticMatrix : IAverage, IMatrix, IMedian, + IMatrixPresets where T : IStaticMatrix +{ + +} diff --git a/Nerd_STF/Mathematics/Abstract/ISubdivide.cs b/Nerd_STF/Mathematics/Abstract/ISubdivide.cs new file mode 100644 index 0000000..9738818 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ISubdivide.cs @@ -0,0 +1,7 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface ISubdivide +{ + public T Subdivide(); + public T Subdivide(int iterations); +} diff --git a/Nerd_STF/Mathematics/Abstract/ISubtract.cs b/Nerd_STF/Mathematics/Abstract/ISubtract.cs new file mode 100644 index 0000000..29daabe --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ISubtract.cs @@ -0,0 +1,8 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface ISubtract : ISubtractionOperators where T : ISubtract +{ + public static abstract T Subtract(T num, params T[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/ISum.cs b/Nerd_STF/Mathematics/Abstract/ISum.cs new file mode 100644 index 0000000..1cc9d72 --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ISum.cs @@ -0,0 +1,9 @@ +using System.Numerics; + +namespace Nerd_STF.Mathematics.Abstract; + +public interface ISum : IAdditionOperators + where T : ISum +{ + public static abstract T Sum(params T[] vals); +} diff --git a/Nerd_STF/Mathematics/Abstract/ITriangulate.cs b/Nerd_STF/Mathematics/Abstract/ITriangulate.cs new file mode 100644 index 0000000..01620cd --- /dev/null +++ b/Nerd_STF/Mathematics/Abstract/ITriangulate.cs @@ -0,0 +1,19 @@ +namespace Nerd_STF.Mathematics.Abstract; + +public interface ITriangulate +{ + public static Triangle[] TriangulateAll(params ITriangulate[] triangulatables) + { + List res = new(); + foreach (ITriangulate triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); + return res.ToArray(); + } + public static Triangle[] TriangulateAll(params T[] triangulatables) where T : ITriangulate + { + List res = new(); + foreach (ITriangulate triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate()); + return res.ToArray(); + } + + public Triangle[] Triangulate(); +} diff --git a/Nerd_STF/Mathematics/Algebra/Matrix.cs b/Nerd_STF/Mathematics/Algebra/Matrix.cs index 0f7e827..e3fcacd 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix.cs @@ -1,10 +1,13 @@ -namespace Nerd_STF.Mathematics.Algebra; +using System.Buffers; -public readonly struct Matrix : IMatrix +namespace Nerd_STF.Mathematics.Algebra; + +public class Matrix : IMatrix { public static Matrix Identity(Int2 size) { - if (size.x != size.y) throw new InvalidSizeException("Can only create an identity matrix of a square matrix."); + if (size.x != size.y) throw new InvalidSizeException("Can only create an identity matrix of a square matrix." + + " You may want to use " + nameof(IdentityIsh) + " instead."); Matrix m = Zero(size); for (int i = 0; i < size.x; i++) m[i, i] = 1; return m; @@ -105,6 +108,51 @@ public readonly struct Matrix : IMatrix get => this[index.x, index.y]; set => this[index.x, index.y] = value; } + public float this[Index r, Index c] + { + get + { + int row = r.IsFromEnd ? Size.x - r.Value : r.Value, + col = c.IsFromEnd ? Size.y - c.Value : c.Value; + return array[row, col]; + } + set + { + int row = r.IsFromEnd ? Size.x - r.Value : r.Value, + col = c.IsFromEnd ? Size.y - c.Value : c.Value; + array[row, col] = value; + } + } + public Matrix this[Range rs, Range cs] + { + get + { + int rowStart = rs.Start.IsFromEnd ? Size.x - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? Size.x - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? Size.y - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? Size.y - cs.End.Value : cs.End.Value; + + Matrix newMatrix = new((rowEnd - rowStart - 1, colEnd - colStart - 1)); + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + newMatrix[r, c] = array[r, c]; + return newMatrix; + } + set + { + int rowStart = rs.Start.IsFromEnd ? Size.x - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? Size.x - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? Size.y - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? Size.y - cs.End.Value : cs.End.Value; + + if (value.Size != (rowEnd - rowStart - 1, colEnd - colStart - 1)) + throw new InvalidSizeException("Matrix has invalid size."); + + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + array[r, c] = value[r, c]; + } + } public static Matrix Absolute(Matrix val) => new(val.Size, (r, c) => Mathf.Absolute(val[r, c])); public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c])); @@ -192,10 +240,11 @@ public readonly struct Matrix : IMatrix return det; } - public Matrix Inverse() + public Matrix? Inverse() { float d = Determinant(); - if (d == 0) throw new NoInverseException(); + if (d == 0) return null; + return Adjugate() / d; } public Matrix[,] Minors() @@ -233,25 +282,18 @@ public readonly struct Matrix : IMatrix return base.Equals(obj); } - public bool Equals(Matrix other) => array == other.array; + public bool Equals(Matrix? other) + { + if (other is null) return false; + return array.Equals(other.array); + } public override int GetHashCode() => array.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) + public override string ToString() { string res = ""; for (int r = 0; r < Size.x; r++) { - for (int c = 0; c < Size.y; c++) res += array[r, c].ToString(provider) + " "; - res += "\n"; - } - return res; - } - public string ToString(IFormatProvider provider) - { - string res = ""; - for (int r = 0; r < Size.y; r++) - { - for (int c = 0; c < Size.x; c++) res += array[r, c].ToString(provider) + " "; + for (int c = 0; c < Size.y; c++) res += array[r, c] + " "; res += "\n"; } return res; @@ -276,7 +318,7 @@ public readonly struct Matrix : IMatrix public List ToList() => ToArray().ToList(); public static Matrix operator +(Matrix a, Matrix b) => new(a.Size, (r, c) => a[r, c] + b[r, c]); - public static Matrix operator -(Matrix m) => m.Inverse(); + public static Matrix? operator -(Matrix m) => m.Inverse(); public static Matrix operator -(Matrix a, Matrix b) => new(a.Size, (r, c) => a[r, c] - b[r, c]); public static Matrix operator *(Matrix a, float b) => new(a.Size, (r, c) => a[r, c] * b); public static Matrix operator *(Matrix a, Matrix b) @@ -292,7 +334,12 @@ public readonly struct Matrix : IMatrix public static Vector2d operator *(Matrix a, Vector2d b) => (Vector2d)(a * (Matrix)b); public static Vector3d operator *(Matrix a, Vector3d b) => (Vector3d)(a * (Matrix)b); public static Matrix operator /(Matrix a, float b) => new(a.Size, (r, c) => a[r, c] / b); - public static Matrix operator /(Matrix a, Matrix b) => a * b.Inverse(); + public static Matrix operator /(Matrix a, Matrix b) + { + Matrix? bInv = b.Inverse(); + if (bInv is null) throw new NoInverseException(b); + return a * bInv; + } public static Complex operator /(Matrix a, Complex b) => (Complex)(a / (Matrix)b); public static Quaternion operator /(Matrix a, Quaternion b) => (Quaternion)(a / (Matrix)b); public static Float2 operator /(Matrix a, Float2 b) => (Float2)(a / (Matrix)b); diff --git a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs index 9301818..a969cd5 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Algebra; -public struct Matrix2x2 : IMatrix +public record class Matrix2x2 : IStaticMatrix { public static Matrix2x2 Identity => new(new[,] { @@ -116,6 +116,48 @@ public struct Matrix2x2 : IMatrix get => this[index.x, index.y]; set => this[index.x, index.y] = value; } + public float this[Index r, Index c] + { + get + { + int row = r.IsFromEnd ? 2 - r.Value : r.Value, + col = c.IsFromEnd ? 2 - c.Value : c.Value; + return this[row, col]; + } + set + { + int row = r.IsFromEnd ? 2 - r.Value : r.Value, + col = c.IsFromEnd ? 2 - c.Value : c.Value; + this[row, col] = value; + } + } + public float[,] this[Range rs, Range cs] + { + get + { + int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value; + + float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1]; + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + vals[r, c] = this[r, c]; + return vals; + } + set + { + int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value; + + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + this[r, c] = value[r, c]; + } + } public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2)); @@ -187,10 +229,10 @@ public struct Matrix2x2 : IMatrix return swapped ^ SignGrid; } public float Determinant() => r1c1 * r2c2 - r1c2 * r2c1; - public Matrix2x2 Inverse() + public Matrix2x2? Inverse() { float d = Determinant(); - if (d == 0) throw new NoInverseException(); + if (d == 0) return null; return Transpose().Adjugate() / d; } public Matrix2x2 Transpose() => new(new[,] @@ -199,22 +241,13 @@ public struct Matrix2x2 : IMatrix { r1c2, r2c2 } }); - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Matrix2x2? other) { - if (obj == null || obj.GetType() != typeof(Matrix2x2)) return base.Equals(obj); - return Equals((Matrix2x2)obj); + if (other is null) return false; + return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r2c1 == other.r2c1 && r2c2 == other.r2c2; } - public bool Equals(Matrix2x2 other) => r1c1 == other.r1c1 && r1c2 == other.r1c2 - && r2c1 == other.r2c1 && r2c2 == other.r2c2; - public override int GetHashCode() => r1c1.GetHashCode() ^ r1c2.GetHashCode() - ^ r2c1.GetHashCode() ^ r2c2.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => r1c1.ToString(provider) + " " + r1c2.ToString(provider) + "\n" - + r2c1.ToString(provider) + " " + r2c2.ToString(provider); - public string ToString(IFormatProvider provider) => r1c1.ToString(provider) + " " + r1c2.ToString(provider) + "\n" - + r2c1.ToString(provider) + " " + r2c2.ToString(provider); - - public object Clone() => new Matrix2x2(ToArray2D()); + public override int GetHashCode() => base.GetHashCode(); + public override string ToString() => r1c1 + " " + r1c2 + "\n" + r2c1 + " " + r2c2; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -252,12 +285,15 @@ public struct Matrix2x2 : IMatrix }); public static Float2 operator *(Matrix2x2 a, Float2 b) => (Matrix)a * b; public static Matrix2x2 operator /(Matrix2x2 a, float b) => new(a.r1c1 / b, a.r1c2 / b, a.r2c1 / b, a.r2c2 / b); - public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b) => a * b.Inverse(); + public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b) + { + Matrix2x2? bInv = b.Inverse(); + if (bInv is null) throw new NoInverseException(b); + return a * bInv; + } public static Float2 operator /(Matrix2x2 a, Float2 b) => (Matrix)a / b; public static Matrix2x2 operator ^(Matrix2x2 a, Matrix2x2 b) => // Single number multiplication. new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2); - public static bool operator ==(Matrix2x2 a, Matrix2x2 b) => a.Equals(b); - public static bool operator !=(Matrix2x2 a, Matrix2x2 b) => !a.Equals(b); public static explicit operator Matrix2x2(Matrix m) { diff --git a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs index be67ed8..17a111a 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Algebra; -public struct Matrix3x3 : IMatrix +public record class Matrix3x3 : IStaticMatrix { public static Matrix3x3 Identity => new(new[,] { @@ -180,6 +180,48 @@ public struct Matrix3x3 : IMatrix get => this[index.x, index.y]; set => this[index.x, index.y] = value; } + public float this[Index r, Index c] + { + get + { + int row = r.IsFromEnd ? 3 - r.Value : r.Value, + col = c.IsFromEnd ? 3 - c.Value : c.Value; + return this[row, col]; + } + set + { + int row = r.IsFromEnd ? 3 - r.Value : r.Value, + col = c.IsFromEnd ? 3 - c.Value : c.Value; + this[row, col] = value; + } + } + public float[,] this[Range rs, Range cs] + { + get + { + int rowStart = rs.Start.IsFromEnd ? 3 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 3 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 3 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 3 - cs.End.Value : cs.End.Value; + + float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1]; + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + vals[r, c] = this[r, c]; + return vals; + } + set + { + int rowStart = rs.Start.IsFromEnd ? 3 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 3 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 3 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 3 - cs.End.Value : cs.End.Value; + + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + this[r, c] = value[r, c]; + } + } public static Matrix3x3 Absolute(Matrix3x3 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), @@ -264,7 +306,7 @@ public struct Matrix3x3 : IMatrix public Matrix3x3 Adjugate() => Cofactor().Transpose(); public Matrix3x3 Cofactor() { - Matrix3x3 dets = new(); + Matrix3x3 dets = Zero; Matrix2x2[,] minors = Minors(); for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) dets[r, c] = minors[r, c].Determinant(); return dets ^ SignGrid; @@ -275,10 +317,10 @@ public struct Matrix3x3 : IMatrix return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) + (r1c3 * minors[0, 2].Determinant()); } - public Matrix3x3 Inverse() + public Matrix3x3? Inverse() { float d = Determinant(); - if (d == 0) throw new NoInverseException(); + if (d == 0) return null; return Adjugate() / d; } public Matrix2x2[,] Minors() => new Matrix2x2[,] @@ -294,30 +336,18 @@ public struct Matrix3x3 : IMatrix { r1c3, r2c3, r3c3 } }); - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Matrix3x3? other) { - if (obj == null || obj.GetType() != typeof(Matrix3x3)) return base.Equals(obj); - return Equals((Matrix3x3)obj); + if (other is null) return false; + return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && + r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && + r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3; } - public bool Equals(Matrix3x3 other) => - r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && - r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && - r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3; - public override int GetHashCode() => - r1c1.GetHashCode() ^ r1c2.GetHashCode() ^ r1c3.GetHashCode() ^ - r2c1.GetHashCode() ^ r2c2.GetHashCode() ^ r2c3.GetHashCode() ^ - r3c1.GetHashCode() ^ r3c2.GetHashCode() ^ r3c3.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + "\n" + - r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + r2c3.ToString(provider) + "\n" + - r3c1.ToString(provider) + " " + r3c2.ToString(provider) + " " + r3c3.ToString(provider); - public string ToString(IFormatProvider provider) => - r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + "\n" + - r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + r2c3.ToString(provider) + "\n" + - r3c1.ToString(provider) + " " + r3c2.ToString(provider) + " " + r3c3.ToString(provider); - - public object Clone() => new Matrix3x3(ToArray2D()); + public override int GetHashCode() => base.GetHashCode(); + public override string ToString() => + r1c1 + " " + r1c2 + " " + r1c3 + "\n" + + r2c1 + " " + r2c2 + " " + r2c3 + "\n" + + r3c1 + " " + r3c2 + " " + r3c3; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -352,7 +382,7 @@ public struct Matrix3x3 : IMatrix new(a.r1c1 + b.r1c1, a.r1c2 + b.r1c2, a.r1c3 + b.r1c3, a.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3, a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3); - public static Matrix3x3 operator -(Matrix3x3 m) => m.Inverse(); + public static Matrix3x3? operator -(Matrix3x3 m) => m.Inverse(); public static Matrix3x3 operator -(Matrix3x3 a, Matrix3x3 b) => new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3, a.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3, @@ -372,14 +402,17 @@ public struct Matrix3x3 : IMatrix new(a.r1c1 / b, a.r1c2 / b, a.r1c3 / b, a.r2c1 / b, a.r2c2 / b, a.r2c3 / b, a.r3c1 / b, a.r3c2 / b, a.r3c3 / b); - public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b) => a * b.Inverse(); + public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b) + { + Matrix3x3? bInv = b.Inverse(); + if (bInv is null) throw new NoInverseException(b); + return a * bInv; + } public static Float3 operator /(Matrix3x3 a, Float3 b) => (Matrix)a / b; public static Matrix3x3 operator ^(Matrix3x3 a, Matrix3x3 b) => // Single number multiplication new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2, a.r2c3 * b.r2c3, a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3); - public static bool operator ==(Matrix3x3 a, Matrix3x3 b) => a.Equals(b); - public static bool operator !=(Matrix3x3 a, Matrix3x3 b) => !a.Equals(b); public static explicit operator Matrix3x3(Matrix m) { diff --git a/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs b/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs index f5d71f5..0f2a96b 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix4x4.cs @@ -1,6 +1,6 @@ namespace Nerd_STF.Mathematics.Algebra; -public struct Matrix4x4 : IMatrix +public record class Matrix4x4 : IStaticMatrix { public static Matrix4x4 Identity => new(new[,] { @@ -251,6 +251,48 @@ public struct Matrix4x4 : IMatrix get => this[index.x, index.y]; set => this[index.x, index.y] = value; } + public float this[Index r, Index c] + { + get + { + int row = r.IsFromEnd ? 4 - r.Value : r.Value, + col = c.IsFromEnd ? 4 - c.Value : c.Value; + return this[row, col]; + } + set + { + int row = r.IsFromEnd ? 4 - r.Value : r.Value, + col = c.IsFromEnd ? 4 - c.Value : c.Value; + this[row, col] = value; + } + } + public float[,] this[Range rs, Range cs] + { + get + { + int rowStart = rs.Start.IsFromEnd ? 4 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 4 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 4 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 4 - cs.End.Value : cs.End.Value; + + float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1]; + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + vals[r, c] = this[r, c]; + return vals; + } + set + { + int rowStart = rs.Start.IsFromEnd ? 4 - rs.Start.Value : rs.Start.Value, + rowEnd = rs.End.IsFromEnd ? 4 - rs.End.Value : rs.End.Value, + colStart = cs.Start.IsFromEnd ? 4 - cs.Start.Value : cs.Start.Value, + colEnd = cs.End.IsFromEnd ? 4 - cs.End.Value : cs.End.Value; + + for (int r = rowStart; r < rowEnd; r++) + for (int c = colStart; c < colEnd; c++) + this[r, c] = value[r, c]; + } + } public static Matrix4x4 Absolute(Matrix4x4 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r1c4), @@ -357,7 +399,7 @@ public struct Matrix4x4 : IMatrix public Matrix4x4 Adjugate() => Cofactor().Transpose(); public Matrix4x4 Cofactor() { - Matrix4x4 dets = new(); + Matrix4x4 dets = Zero; Matrix3x3[,] minors = Minors(); for (int r = 0; r < 4; r++) for (int c = 0; c < 4; c++) dets[r, c] = minors[r, c].Determinant(); return dets ^ SignGrid; @@ -368,10 +410,10 @@ public struct Matrix4x4 : IMatrix return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) + (r1c3 * minors[0, 2].Determinant()) - (r1c4 * minors[0, 3].Determinant()); } - public Matrix4x4 Inverse() + public Matrix4x4? Inverse() { float d = Determinant(); - if (d == 0) throw new NoInverseException(); + if (d == 0) return null; return Adjugate() / d; } public Matrix3x3[,] Minors() => new Matrix3x3[,] @@ -409,38 +451,20 @@ public struct Matrix4x4 : IMatrix { r1c4, r2c4, r3c4, r4c4 } }); - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Matrix4x4? other) { - if (obj == null || obj.GetType() != typeof(Matrix4x4)) return base.Equals(obj); - return Equals((Matrix4x4)obj); + if (other is null) return false; + return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && r1c4 == other.r1c4 && + r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && r2c4 == other.r2c4 && + r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3 && r3c4 == other.r3c4 && + r4c1 == other.r4c1 && r4c2 == other.r4c2 && r4c3 == other.r4c3 && r4c4 == other.r4c4; } - public bool Equals(Matrix4x4 other) => - r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && r1c4 == other.r1c4 && - r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && r2c4 == other.r2c4 && - r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3 && r3c4 == other.r3c4 && - r4c1 == other.r4c1 && r4c2 == other.r4c2 && r4c3 == other.r4c3 && r4c4 == other.r4c4; - public override int GetHashCode() => - r1c1.GetHashCode() ^ r1c2.GetHashCode() ^ r1c3.GetHashCode() ^ r1c4.GetHashCode() ^ - r2c1.GetHashCode() ^ r2c2.GetHashCode() ^ r2c3.GetHashCode() ^ r2c4.GetHashCode() ^ - r3c1.GetHashCode() ^ r3c2.GetHashCode() ^ r3c3.GetHashCode() ^ r3c4.GetHashCode() ^ - r4c1.GetHashCode() ^ r4c2.GetHashCode() ^ r4c3.GetHashCode() ^ r4c4.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + " " + - r1c4.ToString(provider) + "\n" + r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + - r2c3.ToString(provider) + " " + r2c4.ToString(provider) + "\n" + r3c1.ToString(provider) + " " + - r3c2.ToString(provider) + " " + r3c3.ToString(provider) + " " + r3c4.ToString(provider) + "\n" + - r4c1.ToString(provider) + " " + r4c2.ToString(provider) + " " + r4c3.ToString(provider) + " " + - r4c4.ToString(provider); - public string ToString(IFormatProvider provider) => - r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + " " + - r1c4.ToString(provider) + "\n" + r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + - r2c3.ToString(provider) + " " + r2c4.ToString(provider) + "\n" + r3c1.ToString(provider) + " " + - r3c2.ToString(provider) + " " + r3c3.ToString(provider) + " " + r3c4.ToString(provider) + "\n" + - r4c1.ToString(provider) + " " + r4c2.ToString(provider) + " " + r4c3.ToString(provider) + " " + - r4c4.ToString(provider); - - public object Clone() => new Matrix4x4(ToArray2D()); + public override int GetHashCode() => base.GetHashCode(); + public override string ToString() => + r1c1 + " " + r1c2 + " " + r1c3 + " " + r1c4 + "\n" + + r2c1 + " " + r2c2 + " " + r2c3 + " " + r2c4 + "\n" + + r3c1 + " " + r3c2 + " " + r3c3 + " " + r3c4 + "\n" + + r4c1 + " " + r4c2 + " " + r4c3 + " " + r4c4; IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -496,7 +520,7 @@ public struct Matrix4x4 : IMatrix a.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3, a.r2c4 + b.r2c4, a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3, a.r3c4 + b.r3c4, a.r4c1 + b.r4c1, a.r4c2 + b.r4c2, a.r4c3 + b.r4c3, a.r4c4 + b.r4c4); - public static Matrix4x4 operator -(Matrix4x4 m) => m.Inverse(); + public static Matrix4x4? operator -(Matrix4x4 m) => m.Inverse(); public static Matrix4x4 operator -(Matrix4x4 a, Matrix4x4 b) => new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3, a.r1c4 - b.r1c4, a.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3, a.r2c4 - b.r2c4, @@ -524,15 +548,18 @@ public struct Matrix4x4 : IMatrix a.r2c1 / b, a.r2c2 / b, a.r2c3 / b, a.r2c4 / b, a.r3c1 / b, a.r3c2 / b, a.r3c3 / b, a.r3c4 / b, a.r4c1 / b, a.r4c2 / b, a.r4c3 / b, a.r4c4 / b); - public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b) => a * b.Inverse(); + public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b) + { + Matrix4x4? bInv = b.Inverse(); + if (bInv is null) throw new NoInverseException(b); + return a * bInv; + } public static Float4 operator /(Matrix4x4 a, Float4 b) => (Matrix)a / b; public static Matrix4x4 operator ^(Matrix4x4 a, Matrix4x4 b) => // Single number multiplication new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3, a.r1c4 * b.r1c4, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2, a.r2c3 * b.r2c3, a.r2c4 * b.r2c4, a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3, a.r3c4 * b.r3c4, a.r4c1 * b.r4c1, a.r4c2 * b.r4c2, a.r4c3 * b.r4c3, a.r4c4 * b.r4c4); - public static bool operator ==(Matrix4x4 a, Matrix4x4 b) => a.Equals(b); - public static bool operator !=(Matrix4x4 a, Matrix4x4 b) => !a.Equals(b); public static explicit operator Matrix4x4(Matrix m) { diff --git a/Nerd_STF/Mathematics/Algebra/Vector2d.cs b/Nerd_STF/Mathematics/Algebra/Vector2d.cs index 0e5bed9..3e3488b 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector2d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector2d.cs @@ -1,6 +1,11 @@ namespace Nerd_STF.Mathematics.Algebra; -public struct Vector2d : ICloneable, IComparable, IEquatable +public record struct Vector2d : IAbsolute, IAverage, + IClampMagnitude, IComparable, ICross, + IDot, IEquatable, IFromTuple, + ILerp, IMax, IMagnitude, IMedian, IMin, + IPresets2D, ISplittable, ISubtract, + ISum { public static Vector2d Down => new(Angle.Down); public static Vector2d Left => new(Angle.Left); @@ -10,6 +15,12 @@ public struct Vector2d : ICloneable, IComparable, IEquatable public static Vector2d One => new(Angle.Zero); public static Vector2d Zero => new(Angle.Zero, 0); + public float Magnitude + { + get => magnitude; + set => magnitude = value; + } + public Vector2d Inverse => new(-theta, magnitude); public Vector2d Normalized => new(theta, 1); @@ -86,7 +97,7 @@ public struct Vector2d : ICloneable, IComparable, IEquatable return val; } - public static (Angle[] Rots, float[] Mags) SplitArray(params Vector2d[] vals) + public static (Angle[] rots, float[] mags) SplitArray(params Vector2d[] vals) { Angle[] rots = new Angle[vals.Length]; float[] mags = new float[vals.Length]; @@ -99,21 +110,11 @@ public struct Vector2d : ICloneable, IComparable, IEquatable } public int CompareTo(Vector2d other) => magnitude.CompareTo(other.magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Vector2d)) return base.Equals(obj); - return Equals((Vector2d)obj); - } 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) => 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) => - "Mag: " + magnitude.ToString(provider) + " Rot: " + theta.ToString(provider, outputType); - - public object Clone() => new Vector2d(theta, magnitude); + public override int GetHashCode() => base.GetHashCode(); + public override string ToString() => ToString(Angle.Type.Degrees); + public string ToString(Angle.Type outputType) => + nameof(Vector2d) + " { Mag = " + magnitude + ", Rot = " + theta.ToString(outputType) + " }"; public Float2 ToXYZ() => new Float2(Mathf.Cos(theta), Mathf.Sin(theta)) * magnitude; @@ -124,8 +125,6 @@ public struct Vector2d : ICloneable, IComparable, IEquatable public static Vector2d operator *(Vector2d a, Matrix b) => (Vector2d)((Matrix)a * b); public static Vector2d operator /(Vector2d a, float b) => new(a.theta, a.magnitude / b); public static Vector2d operator /(Vector2d a, Matrix b) => (Vector2d)((Matrix)a / b); - public static bool operator ==(Vector2d a, Vector2d b) => a.Equals(b); - public static bool operator !=(Vector2d a, Vector2d b) => !a.Equals(b); public static bool operator >(Vector2d a, Vector2d b) => a.CompareTo(b) > 0; public static bool operator <(Vector2d a, Vector2d b) => a.CompareTo(b) < 0; public static bool operator >=(Vector2d a, Vector2d b) => a == b || a > b; @@ -139,4 +138,5 @@ public struct Vector2d : ICloneable, IComparable, IEquatable public static explicit operator Vector2d(Matrix m) => ((Float2)m).ToVector(); public static explicit operator Vector2d(Vert val) => (Vector2d)val.ToVector(); public static explicit operator Vector2d(Vector3d val) => new(val.yaw, val.magnitude); + public static implicit operator Vector2d((Angle angle, float mag) val) => new(val.angle, val.mag); } diff --git a/Nerd_STF/Mathematics/Algebra/Vector3d.cs b/Nerd_STF/Mathematics/Algebra/Vector3d.cs index c363d79..1798ac6 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector3d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector3d.cs @@ -1,6 +1,10 @@ namespace Nerd_STF.Mathematics.Algebra; -public struct Vector3d : ICloneable, IComparable, IEquatable +public record struct Vector3d : IAbsolute, IAverage, IClampMagnitude, + IComparable, ICross, IDot, IEquatable, + IFromTuple, IIndexAll, IIndexRangeAll, + ILerp, IMagnitude, IMax, IMedian, IMin, + IPresets3D, ISubtract, ISum { public static Vector3d Back => new(Angle.Zero, Angle.Up); public static Vector3d Down => new(Angle.Down, Angle.Zero); @@ -12,6 +16,12 @@ public struct Vector3d : ICloneable, IComparable, IEquatable public static Vector3d One => new(Angle.Zero); public static Vector3d Zero => new(Angle.Zero, 0); + public float Magnitude + { + get => magnitude; + set => magnitude = value; + } + public Vector3d Inverse => new(-yaw, -pitch, magnitude); public Vector3d Normalized => new(yaw, pitch, 1); @@ -56,6 +66,28 @@ public struct Vector3d : ICloneable, IComparable, IEquatable } } } + public Angle this[Index index] + { + get => this[index.IsFromEnd ? 2 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value; + } + public Angle[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Vector3d Absolute(Vector3d val) => new(Angle.Absolute(val.yaw), Angle.Absolute(val.pitch), Mathf.Absolute(val.magnitude)); @@ -123,38 +155,27 @@ public struct Vector3d : ICloneable, IComparable, IEquatable return val; } - public static (Angle[] Thetas, Angle[] Phis, float[] Mags) SplitArray(params Vector3d[] vals) + public static (Angle[] yaws, Angle[] pitches, float[] mags) SplitArray(params Vector3d[] vals) { - Angle[] yaws = new Angle[vals.Length], pitchs = new Angle[vals.Length]; + Angle[] yaws = new Angle[vals.Length], pitches = new Angle[vals.Length]; float[] mags = new float[vals.Length]; for (int i = 0; i < vals.Length; i++) { yaws[i] = vals[i].yaw; - pitchs[i] = vals[i].pitch; + pitches[i] = vals[i].pitch; mags[i] = vals[i].magnitude; } - return (yaws, pitchs, mags); + return (yaws, pitches, mags); } public int CompareTo(Vector3d other) => magnitude.CompareTo(other.magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Vector3d)) return base.Equals(obj); - return Equals((Vector3d)obj); - } 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) + " 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 override int GetHashCode() => base.GetHashCode(); + public override string ToString() => ToString(Angle.Type.Degrees); + public string ToString(Angle.Type outputType) => + nameof(Vector3d) + " { Mag = " + magnitude + ", Yaw = " + yaw.ToString(outputType) + + ", Pitch = " + pitch.ToString(outputType) + " }"; public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw), Mathf.Cos(yaw), @@ -169,8 +190,6 @@ public struct Vector3d : ICloneable, IComparable, IEquatable public static Vector3d operator *(Vector3d a, Matrix b) => (Vector3d)((Matrix)a * b); public static Vector3d operator /(Vector3d a, float b) => new(a.yaw, a.pitch, a.magnitude / b); public static Vector3d operator /(Vector3d a, Matrix b) => (Vector3d)((Matrix)a / b); - public static bool operator ==(Vector3d a, Vector3d b) => a.Equals(b); - public static bool operator !=(Vector3d a, Vector3d b) => !a.Equals(b); public static bool operator >(Vector3d a, Vector3d b) => a.CompareTo(b) > 0; public static bool operator <(Vector3d a, Vector3d b) => a.CompareTo(b) < 0; public static bool operator >=(Vector3d a, Vector3d b) => a == b || a > b; @@ -184,4 +203,6 @@ public struct Vector3d : ICloneable, IComparable, IEquatable public static explicit operator Vector3d(Matrix m) => ((Float3)m).ToVector(); public static explicit operator Vector3d(Vert val) => val.ToVector(); public static implicit operator Vector3d(Vector2d v) => new(v.theta, Angle.Zero, v.magnitude); + public static implicit operator Vector3d((Angle yaw, Angle pitch, float mag) val) => + new(val.yaw, val.pitch, val.mag); } diff --git a/Nerd_STF/Mathematics/Angle.cs b/Nerd_STF/Mathematics/Angle.cs index 17cfe18..712f12c 100644 --- a/Nerd_STF/Mathematics/Angle.cs +++ b/Nerd_STF/Mathematics/Angle.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Mathematics; -public struct Angle : ICloneable, IComparable, IEquatable +public struct Angle : IAbsolute, IAverage, IClamp, ICloneable, + IComparable, IEquatable, ILerp, IMax, IMedian, + IMin, IPresets2D { public static Angle Down => new(270); public static Angle Left => new(180); @@ -84,17 +86,7 @@ public struct Angle : ICloneable, IComparable, IEquatable public static float[] SplitArray(Type outputType, params Angle[] vals) { float[] res = new float[vals.Length]; - for (int i = 0; i < vals.Length; i++) - { - res[i] = outputType switch - { - Type.Degrees => vals[i].Degrees, - Type.Gradians => vals[i].Gradians, - Type.Normalized => vals[i].Normalized, - Type.Radians => vals[i].Radians, - _ => throw new ArgumentException("Unknown type.", nameof(outputType)), - }; - } + for (int i = 0; i < vals.Length; i++) res[i] = vals[i].ValueFromType(outputType); return res; } @@ -106,22 +98,13 @@ public struct Angle : ICloneable, IComparable, IEquatable } public bool Equals(Angle other) => p_deg == other.p_deg; public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(Type outputType) => ToString((string?)null, outputType); - public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch + public override string ToString() => ToString(Type.Degrees); + public string ToString(Type outputType) => outputType switch { - Type.Degrees => p_deg.ToString(provider) + "°", - Type.Gradians => Gradians.ToString(provider) + "grad", - Type.Normalized => Normalized.ToString(provider) + "%", - Type.Radians => Radians.ToString(provider) + "rad", - _ => throw new ArgumentException("Unknown type.", nameof(outputType)), - }; - public string ToString(IFormatProvider provider, Type outputType = Type.Degrees) => outputType switch - { - Type.Degrees => p_deg.ToString(provider) + "°", - Type.Gradians => Gradians.ToString(provider) + "grad", - Type.Normalized => Normalized.ToString(provider) + "%", - Type.Radians => Radians.ToString(provider) + "rad", + Type.Degrees => p_deg + "°", + Type.Gradians => Gradians + "grad", + Type.Normalized => Normalized + "%", + Type.Radians => Radians + "rad", _ => throw new ArgumentException("Unknown type.", nameof(outputType)), }; @@ -133,7 +116,7 @@ public struct Angle : ICloneable, IComparable, IEquatable Type.Gradians => Gradians, Type.Normalized => Normalized, Type.Radians => Radians, - _ => throw new ArgumentException("Unknown type.", nameof(type)), + _ => throw new ArgumentException("Unknown type.", nameof(type)) }; public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg); @@ -148,6 +131,8 @@ public struct Angle : ICloneable, IComparable, IEquatable public static bool operator >=(Angle a, Angle b) => a == b || a > b; public static bool operator <=(Angle a, Angle b) => a == b || a < b; + public static implicit operator Angle((float val, Type type) obj) => new(obj.val, obj.type); + public enum Type { Degrees, diff --git a/Nerd_STF/Mathematics/Float2.cs b/Nerd_STF/Mathematics/Float2.cs index 4e31c6e..1de768d 100644 --- a/Nerd_STF/Mathematics/Float2.cs +++ b/Nerd_STF/Mathematics/Float2.cs @@ -1,6 +1,12 @@ namespace Nerd_STF.Mathematics; -public struct Float2 : ICloneable, IComparable, IEquatable, IGroup +public record struct Float2 : IAbsolute, IAverage, ICeiling, + IClamp, IClampMagnitude, IComparable, + ICross, IDivide, IDot, IEquatable, + IFloor, IFromTuple, IGroup, + ILerp, IMathOperators, IMax, IMedian, IMin, + IIndexAll, IIndexRangeAll, IPresets2D, IProduct, IRound, + ISplittable, ISubtract, ISum { public static Float2 Down => new(0, -1); public static Float2 Left => new(-1, 0); @@ -16,14 +22,13 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro public float x, y; public Float2(float all) : this(all, all) { } + public Float2(Fill fill) : this(fill(0), fill(1)) { } + public Float2(Fill fill) : this(fill(0), fill(1)) { } 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 @@ -48,11 +53,33 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 2 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } 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) => + public static Int2 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), @@ -83,7 +110,7 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro } return x + y; } - public static Float2 Floor(Float2 val) => + public static Int2 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)); @@ -97,14 +124,14 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro { if (vals.Length < 1) return Zero; Float2 val = vals[0]; - foreach (Float2 f in vals) val = f > val ? f : val; + foreach (Float2 f in vals) val = f.Magnitude > val.Magnitude ? f : val; return val; } public static Float2 Min(params Float2[] vals) { if (vals.Length < 1) return Zero; Float2 val = vals[0]; - foreach (Float2 f in vals) val = f < val ? f : val; + foreach (Float2 f in vals) val = f.Magnitude < val.Magnitude ? f : val; return val; } public static Float2 Product(params Float2[] vals) @@ -114,8 +141,8 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro foreach (Float2 f in vals) val *= f; return val; } - public static Float2 Round(Float2 val) => - new(Mathf.Round(val.x), Mathf.Round(val.y)); + public static Int2 Round(Float2 val) => + new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y)); public static Float2 Subtract(Float2 num, params Float2[] vals) => num - Sum(vals); public static Float2 Sum(params Float2[] vals) { @@ -135,21 +162,11 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro return (Xs, Ys); } + [Obsolete("This method is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] 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 base.Equals(obj); - 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); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -168,6 +185,15 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro public Vector2d ToVector() => new(Mathf.ArcTan(y / x), Magnitude); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + return true; + } + 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); @@ -178,11 +204,17 @@ 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 bool operator ==(Float2 a, Float2 b) => a.Equals(b); - public static bool operator !=(Float2 a, Float2 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Float2 a, Float2 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Float2 a, Float2 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Float2 a, Float2 b) => a == b || a < b; public static implicit operator Float2(Complex val) => new(val.u, val.i); @@ -197,4 +229,5 @@ public struct Float2 : ICloneable, IComparable, IEquatable, IGro 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); + public static implicit operator Float2((float x, float y) val) => new(val.x, val.y); } diff --git a/Nerd_STF/Mathematics/Float3.cs b/Nerd_STF/Mathematics/Float3.cs index 1e7b41b..7674707 100644 --- a/Nerd_STF/Mathematics/Float3.cs +++ b/Nerd_STF/Mathematics/Float3.cs @@ -1,6 +1,14 @@ -namespace Nerd_STF.Mathematics; +using System; -public struct Float3 : ICloneable, IComparable, IEquatable, IGroup +namespace Nerd_STF.Mathematics; + +public record struct Float3 : IAbsolute, IAverage, + ICeiling, IClamp, IClampMagnitude, IComparable, + ICross, IDivide, IDot, IEquatable, + IFloor, IFromTuple, IGroup, + IIndexAll, IIndexRangeAll, ILerp, IMathOperators, IMax, + IMedian, IMin, IPresets3D, IProduct, IRound, + ISplittable, ISubtract, ISum { public static Float3 Back => new(0, 0, -1); public static Float3 Down => new(0, -1, 0); @@ -61,11 +69,33 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 3 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } 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) => + public static Int3 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), @@ -103,7 +133,7 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro } return x + y + z; } - public static Float3 Floor(Float3 val) => + public static Int3 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)); @@ -117,14 +147,14 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro { if (vals.Length < 1) return Zero; Float3 val = vals[0]; - foreach (Float3 d in vals) val = d > val ? d : val; + foreach (Float3 d in vals) val = d.Magnitude > val.Magnitude ? 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; + foreach (Float3 d in vals) val = d.Magnitude < val.Magnitude ? d : val; return val; } public static Float3 Product(params Float3[] vals) @@ -134,8 +164,8 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro foreach (Float3 d in vals) val *= d; return val; } - public static Float3 Round(Float3 val) => - new(Mathf.Round(val.x), Mathf.Round(val.y), Mathf.Round(val.z)); + public static Int3 Round(Float3 val) => + new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y), Mathf.RoundInt(val.z)); public static Float3 Subtract(Float3 num, params Float3[] vals) => num - Sum(vals); public static Float3 Sum(params Float3[] vals) { @@ -156,21 +186,11 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro return (Xs, Ys, Zs); } + [Obsolete("This method is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] 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 base.Equals(obj); - 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); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -197,6 +217,17 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro return new(yaw, pitch, mag); } + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + builder.Append(", z = "); + builder.Append(z); + return true; + } + 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); @@ -207,11 +238,17 @@ 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 bool operator ==(Float3 a, Float3 b) => a.Equals(b); - public static bool operator !=(Float3 a, Float3 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Float3 a, Float3 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Float3 a, Float3 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Float3 a, Float3 b) => a == b || a < b; public static implicit operator Float3(Complex val) => new(val.u, val.i, 0); @@ -230,4 +267,6 @@ public struct Float3 : ICloneable, IComparable, IEquatable, IGro public static explicit operator Float3(HSVAByte val) => (Float3)val.ToHSVA(); public static implicit operator Float3(Fill fill) => new(fill); public static implicit operator Float3(Fill fill) => new(fill); + public static implicit operator Float3((float x, float y, float z) val) => + new(val.x, val.y, val.z); } diff --git a/Nerd_STF/Mathematics/Float4.cs b/Nerd_STF/Mathematics/Float4.cs index 34a678d..b8af96c 100644 --- a/Nerd_STF/Mathematics/Float4.cs +++ b/Nerd_STF/Mathematics/Float4.cs @@ -1,6 +1,13 @@ namespace Nerd_STF.Mathematics; -public struct Float4 : ICloneable, IComparable, IEquatable, IGroup +public record struct Float4 : IAbsolute, + IAverage, ICeiling, IClamp, IClampMagnitude, + IComparable, IDivide, IDot, IEquatable, + IFloor, IFromTuple, + IGroup, IIndexAll, IIndexRangeAll, ILerp, IMathOperators, + IMax, IMedian, IMin, IPresets4D, IProduct, IRound, + ISplittable, ISubtract, + ISum { public static Float4 Back => new(0, 0, -1, 0); public static Float4 Down => new(0, -1, 0, 0); @@ -84,11 +91,33 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } 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) => + public static Int4 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), @@ -121,7 +150,7 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro } return x + y + z; } - public static Float4 Floor(Float4 val) => + public static Int4 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), @@ -136,18 +165,19 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro { if (vals.Length < 1) return Zero; Float4 val = vals[0]; - foreach (Float4 d in vals) val = d > val ? d : val; + foreach (Float4 d in vals) val = d.Magnitude > val.Magnitude ? 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; + foreach (Float4 d in vals) val = d.Magnitude < val.Magnitude ? d : val; return val; } - public static Float4 Round(Float4 val) => - new(Mathf.Round(val.x), Mathf.Round(val.y), Mathf.Round(val.z), Mathf.Round(val.w)); + public static Int4 Round(Float4 val) => + new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y), Mathf.RoundInt(val.z), + Mathf.RoundInt(val.w)); public static Float4 Product(params Float4[] vals) { if (vals.Length < 1) return Zero; @@ -177,23 +207,11 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro return (Xs, Ys, Zs, Ws); } + [Obsolete("This method is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] 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 base.Equals(obj); - 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); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -212,6 +230,19 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro } public List ToList() => new() { x, y, z, w }; + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + builder.Append(", z = "); + builder.Append(z); + builder.Append(", w = "); + builder.Append(w); + return true; + } + 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); @@ -221,11 +252,17 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro 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, Matrix b) => (Float4)((Matrix)a / b); - public static bool operator ==(Float4 a, Float4 b) => a.Equals(b); - public static bool operator !=(Float4 a, Float4 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Float4 a, Float4 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Float4 a, Float4 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Float4 a, Float4 b) => a == b || a < b; public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0); @@ -246,4 +283,6 @@ public struct Float4 : ICloneable, IComparable, IEquatable, IGro public static implicit operator Float4(HSVAByte val) => (Float4)val.ToHSVA(); public static implicit operator Float4(Fill fill) => new(fill); public static implicit operator Float4(Fill fill) => new(fill); + public static implicit operator Float4((float x, float y, float z, float w) vals) => + new(vals.x, vals.y, vals.z, vals.w); } diff --git a/Nerd_STF/Mathematics/Geometry/Box2D.cs b/Nerd_STF/Mathematics/Geometry/Box2D.cs index 177438a..68d18ac 100644 --- a/Nerd_STF/Mathematics/Geometry/Box2D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box2D.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Mathematics.Geometry; -public struct Box2D : ICloneable, IContainer, IEquatable +public record class Box2D : IAbsolute, IAverage, ICeiling, IClamp, IContains, + IEquatable, IFloor, ILerp, IMedian, IRound, IShape2D, + ISplittable { public static Box2D Unit => new(Vert.Zero, Float2.One); @@ -10,7 +12,7 @@ public struct Box2D : ICloneable, IContainer, IEquatable set { Vert diff = center - value; - size = (Float2)diff.position * 2; + size = (Float2)diff.position * 2f; } } public Vert MinVert @@ -19,7 +21,7 @@ public struct Box2D : ICloneable, IContainer, IEquatable set { Vert diff = center + value; - size = (Float2)diff.position * 2; + size = (Float2)diff.position * 2f; } } @@ -60,16 +62,8 @@ public struct Box2D : ICloneable, IContainer, IEquatable (Vert[] verts, Float2[] sizes) = SplitArray(vals); return new(Vert.Median(verts), Float2.Median(sizes)); } - public static Box2D Max(params Box2D[] vals) - { - (Vert[] verts, Float2[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Float2.Max(sizes)); - } - public static Box2D Min(params Box2D[] vals) - { - (Vert[] verts, Float2[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Float2.Min(sizes)); - } + public static Box2D Round(Box2D val) => new(Vert.Round(val.center), Float2.Round(val.size)); + public static (Vert[] centers, Float2[] sizes) SplitArray(params Box2D[] vals) { Vert[] centers = new Vert[vals.Length]; @@ -84,18 +78,12 @@ public struct Box2D : ICloneable, IContainer, IEquatable return (centers, sizes); } - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Box2D? other) { - if (obj == null || obj.GetType() != typeof(Box2D)) return base.Equals(obj); - return Equals((Box2D)obj); + if (other is null) return false; + return center == other.center && size == other.size; } - public bool Equals(Box2D other) => center == other.center && size == other.size; - public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - public string ToString(IFormatProvider provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + public override int GetHashCode() => base.GetHashCode(); public bool Contains(Vert vert) { @@ -103,7 +91,14 @@ public struct Box2D : ICloneable, IContainer, IEquatable return diff.x <= size.x && diff.y <= size.y; } - public object Clone() => new Box2D(center, size); + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("Min = "); + builder.Append(MinVert); + builder.Append(", Max = "); + builder.Append(MaxVert); + return true; + } public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size); public static Box2D operator +(Box2D a, Float2 b) => new(a.center, a.size + b); @@ -114,8 +109,6 @@ public struct Box2D : ICloneable, IContainer, IEquatable 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, (Float2)box.size); diff --git a/Nerd_STF/Mathematics/Geometry/Box3D.cs b/Nerd_STF/Mathematics/Geometry/Box3D.cs index 73efa89..aa4cedb 100644 --- a/Nerd_STF/Mathematics/Geometry/Box3D.cs +++ b/Nerd_STF/Mathematics/Geometry/Box3D.cs @@ -1,6 +1,8 @@ namespace Nerd_STF.Mathematics.Geometry; -public struct Box3D : ICloneable, IContainer, IEquatable +public record class Box3D : IAbsolute, IAverage, ICeiling, IClamp, + IContains, IEquatable, IFloor, ILerp, IMedian, + IRound, IShape3D, ISplittable { public static Box3D Unit => new(Vert.Zero, Float3.One); @@ -51,10 +53,12 @@ public struct Box3D : ICloneable, IContainer, IEquatable (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), Float3.Ceiling(val.size)); + public static Box3D Ceiling(Box3D val) => + new(Vert.Ceiling(val.center), (Float3)Float3.Ceiling(val.size)); public static Box3D Clamp(Box3D val, Box3D min, Box3D max) => 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 Floor(Box3D val) => + new(Vert.Floor(val.center), (Float3)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), Float3.Lerp(a.size, b.size, t, clamp)); public static Box3D Median(params Box3D[] vals) @@ -62,16 +66,8 @@ public struct Box3D : ICloneable, IContainer, IEquatable (Vert[] verts, Float3[] sizes) = SplitArray(vals); return new(Vert.Median(verts), Float3.Median(sizes)); } - public static Box3D Max(params Box3D[] vals) - { - (Vert[] verts, Float3[] sizes) = SplitArray(vals); - return new(Vert.Max(verts), Float3.Max(sizes)); - } - public static Box3D Min(params Box3D[] vals) - { - (Vert[] verts, Float3[] sizes) = SplitArray(vals); - return new(Vert.Min(verts), Float3.Min(sizes)); - } + public static Box3D Round(Box3D val) => new(Vert.Ceiling(val.center), (Float3)Float3.Ceiling(val.size)); + public static (Vert[] centers, Float3[] sizes) SplitArray(params Box3D[] vals) { Vert[] centers = new Vert[vals.Length]; @@ -86,25 +82,27 @@ public struct Box3D : ICloneable, IContainer, IEquatable return (centers, sizes); } - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Box3D? other) { - if (obj == null || obj.GetType() != typeof(Box3D)) return base.Equals(obj); - return Equals((Box3D)obj); + if (other is null) return false; + return center == other.center && size == other.size; } - public bool Equals(Box3D other) => center == other.center && size == other.size; - public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); - public string ToString(IFormatProvider provider) => - "Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider); + public override int GetHashCode() => base.GetHashCode(); public bool Contains(Vert 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); + + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("Min = "); + builder.Append(MinVert); + builder.Append(", Max = "); + builder.Append(MaxVert); + return true; + } public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size); public static Box3D operator +(Box3D a, Float3 b) => new(a.center, a.size + b); @@ -115,8 +113,6 @@ public struct Box3D : ICloneable, IContainer, IEquatable 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(Box2D box) => new(box); diff --git a/Nerd_STF/Mathematics/Geometry/ISubdividable.cs b/Nerd_STF/Mathematics/Geometry/ISubdividable.cs deleted file mode 100644 index 7807595..0000000 --- a/Nerd_STF/Mathematics/Geometry/ISubdividable.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Nerd_STF.Mathematics.Geometry; - -public interface ISubdividable -{ - public T Subdivide(); - public T Subdivide(int iterations); -} diff --git a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs b/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs deleted file mode 100644 index 363bf0a..0000000 --- a/Nerd_STF/Mathematics/Geometry/ITriangulatable.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace Nerd_STF.Mathematics.Geometry; - -public interface ITriangulatable -{ - public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables) - { - List res = new(); - 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/Geometry/Line.cs b/Nerd_STF/Mathematics/Geometry/Line.cs index b76242e..9fb1fe2 100644 --- a/Nerd_STF/Mathematics/Geometry/Line.cs +++ b/Nerd_STF/Mathematics/Geometry/Line.cs @@ -1,7 +1,11 @@ -namespace Nerd_STF.Mathematics.Geometry; +using Nerd_STF.Mathematics.Abstract; -public struct Line : ICloneable, IClosest, IComparable, IContainer, IEquatable, - IGroup, ISubdividable +namespace Nerd_STF.Mathematics.Geometry; + +public record class Line : IAbsolute, IAverage, ICeiling, IClamp, IClosestTo, + IComparable, IContains, IEquatable, IFloor, IFromTuple, + IGroup, IIndexAll, IIndexRangeAll, ILerp, IMedian, IPresets3D, + IRound, ISplittable, ISubdivide { public static Line Back => new(Vert.Zero, Vert.Back); public static Line Down => new(Vert.Zero, Vert.Down); @@ -56,6 +60,28 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer this[index.IsFromEnd ? 2 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value; + } + public Vert[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b)); public static Line Average(params Line[] vals) @@ -74,16 +100,7 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer new(Vert.Round(val.a), Vert.Round(val.b)); public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines) { @@ -96,22 +113,20 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer a == other.a && b == other.b; - public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "A: " + a.ToString(provider) + " B: " + b.ToString(provider); - public string ToString(IFormatProvider provider) => - "A: " + a.ToString(provider) + " B: " + b.ToString(provider); + public override int GetHashCode() => base.GetHashCode(); - public object Clone() => new Line(a, b); - - public int CompareTo(Line line) => Length.CompareTo(line.Length); + [Obsolete("This method is a bit ambiguous. You should instead compare " + + nameof(Length) + "s directly.")] + public int CompareTo(Line? line) + { + if (line is null) return -1; + return Length.CompareTo(line.Length); + } public bool Contains(Vert vert) { @@ -173,6 +188,15 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer ToFloatList() => new() { a.position.x, a.position.y, a.position.z, b.position.x, b.position.y, b.position.z }; + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("A = "); + builder.Append(a); + builder.Append(", B = "); + builder.Append(b); + return true; + } + public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b); public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b); public static Line operator -(Line l) => new(-l.a, -l.b); @@ -184,11 +208,17 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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, 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); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Length) + "s directly.")] public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Length) + "s directly.")] public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Length) + "s directly.")] public static bool operator >=(Line a, Line b) => a > b || a == b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Length) + "s directly.")] public static bool operator <=(Line a, Line b) => a < b || a == b; public static implicit operator Line(Fill fill) => new(fill); @@ -196,4 +226,5 @@ public struct Line : ICloneable, IClosest, IComparable, IContainer 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((Vert start, Vert end) val) => new(val.start, val.end); } diff --git a/Nerd_STF/Mathematics/Geometry/Polygon.cs b/Nerd_STF/Mathematics/Geometry/Polygon.cs index fb7084d..9a5d00d 100644 --- a/Nerd_STF/Mathematics/Geometry/Polygon.cs +++ b/Nerd_STF/Mathematics/Geometry/Polygon.cs @@ -1,7 +1,7 @@ namespace Nerd_STF.Mathematics.Geometry; -[Obsolete("This struct is a garbage fire. This will be completely redesigned in v2.4.0")] -public struct Polygon : ICloneable, IEquatable, IGroup, ISubdividable, ITriangulatable +[Obsolete("This struct is a garbage fire. This will be completely redesigned in v2.5.0")] +public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivide, ITriangulate { public Line[] Lines { @@ -83,8 +83,8 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid while (true) { Line? v = fill(i); - if (!v.HasValue) break; - lines.Add(v.Value); + if (v is null) break; + lines.Add(v); } this = new(lines.ToArray()); } @@ -190,24 +190,6 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid Line[][] lines = new Line[2][] { a.Lines, b.Lines }; Line[] res = new Line[a.Lines.Length]; for (int i = 0; i < res.Length; i++) res[i] = Line.Lerp(lines[0][i], lines[1][i], t, clamp); - return new(res); - } - public static Polygon Max(params Polygon[] vals) - { - if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); - if (vals.Length < 1) return default; - - Line[][] lines = new Line[vals.Length][]; - for (int i = 0; i < vals.Length; i++) lines[i] = vals[i].Lines; - - Line[] res = new Line[vals[0].Lines.Length]; - for (int i = 0; i < res.Length; i++) - { - Line[] row = new Line[vals.Length]; - for (int j = 0; j < vals[0].Lines.Length; j++) row[j] = vals[j].Lines[i]; - res[i] = Line.Max(row); - } - return new(res); } public static Polygon Median(params Polygon[] vals) @@ -226,24 +208,6 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid res[i] = Line.Median(row); } - return new(res); - } - public static Polygon Min(params Polygon[] vals) - { - if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals); - if (vals.Length < 1) return default; - - Line[][] lines = new Line[vals.Length][]; - for (int i = 0; i < vals.Length; i++) lines[i] = vals[i].Lines; - - Line[] res = new Line[vals[0].Lines.Length]; - for (int i = 0; i < res.Length; i++) - { - Line[] row = new Line[vals.Length]; - for (int j = 0; j < vals[0].Lines.Length; j++) row[j] = vals[j].Lines[i]; - res[i] = Line.Min(row); - } - return new(res); } @@ -266,19 +230,12 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid return Lines == other.Lines; } public override int GetHashCode() => Lines.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) - { - string s = ""; - for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " "; - return s; - } - public string ToString(IFormatProvider provider) - { - string s = ""; - for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " "; - return s; - } + public override string ToString() + { + string s = ""; + for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i] + " "; + return s; + } public object Clone() => new Polygon(Lines); @@ -375,7 +332,8 @@ public struct Polygon : ICloneable, IEquatable, IGroup, ISubdivid } } - if (closest == null) throw new("Unknown error triangulating the polygon."); + if (closest == null) + throw new Nerd_STFException("Unknown error triangulating the polygon."); if (closest.Value.posB > closest.Value.posA) closest = (closest.Value.posB, closest.Value.posA, closest.Value.line); diff --git a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs index 94929ce..e5e62fa 100644 --- a/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs +++ b/Nerd_STF/Mathematics/Geometry/Quadrilateral.cs @@ -1,6 +1,9 @@ namespace Nerd_STF.Mathematics.Geometry; -public struct Quadrilateral : ICloneable, IEquatable, IGroup, ITriangulatable +public record class Quadrilateral : IAbsolute, IAverage, ICeiling, + IClamp, IEquatable, IFloor, + IFromTuple, IGroup, IIndexAll, IIndexRangeAll, + ILerp, IRound, IShape2D, ITriangulate { public Vert A { @@ -179,6 +182,28 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public Vert[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Quadrilateral Absolute(Quadrilateral val) => new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D)); @@ -212,6 +237,8 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup + new(Vert.Round(val.A), Vert.Round(val.B), Vert.Round(val.C), Vert.Round(val.D)); public static (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) SplitVertArray(params Quadrilateral[] quads) { @@ -265,20 +292,12 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup ToFloatListAll(params Quadrilateral[] quads) => new(ToFloatArrayAll(quads)); - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Quadrilateral? other) { - if (obj == null || obj.GetType() != typeof(Quadrilateral)) return base.Equals(obj); - return Equals((Quadrilateral)obj); + if (other is null) return false; + return A == other.A && B == other.B && C == other.C && D == other.D; } - public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D; - public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider) - + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); - public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: " - + B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider); - - public object Clone() => new Quadrilateral(A, B, C, D); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -309,6 +328,19 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup new Line(A, C).Length > new Line(B, D).Length ? new Triangle[] { new(A, B, C), new(C, D, A) } : new Triangle[] { new(B, C, D), new(D, A, B) }; + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("A = "); + builder.Append(A); + builder.Append(", B = "); + builder.Append(B); + builder.Append(", C = "); + builder.Append(C); + builder.Append(", D = "); + builder.Append(D); + return true; + } + 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); @@ -324,8 +356,6 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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); @@ -333,4 +363,6 @@ public struct Quadrilateral : ICloneable, IEquatable, IGroup 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((Vert a, Vert b, Vert c, Vert d) val) => + new(val.a, val.b, val.c, val.d); } diff --git a/Nerd_STF/Mathematics/Geometry/Sphere.cs b/Nerd_STF/Mathematics/Geometry/Sphere.cs index bc81c5c..ebc6baa 100644 --- a/Nerd_STF/Mathematics/Geometry/Sphere.cs +++ b/Nerd_STF/Mathematics/Geometry/Sphere.cs @@ -1,7 +1,9 @@ namespace Nerd_STF.Mathematics.Geometry; -public struct Sphere : ICloneable, IClosest, IComparable, IComparable, IContainer, - IEquatable, IEquatable +public record class Sphere : IAverage, ICeiling, IClamp, IClosestTo, + IComparable, IComparable, IContains, IEquatable, IEquatable, IFloor, + IFromTuple, ILerp, IMax, IMedian, + IMin, IRound, ISplittable { public static Sphere Unit => new(Vert.Zero, 1); @@ -54,6 +56,7 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara (Vert[] centers, float[] radii) = SplitArray(vals); return new(Vert.Min(centers), Mathf.Min(radii)); } + public static Sphere Round(Sphere val) => new(Vert.Round(val.center), Mathf.Round(val.radius)); public static (Vert[] centers, float[] radii) SplitArray(params Sphere[] spheres) { @@ -67,32 +70,38 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara return (centers, radii); } - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null) return base.Equals(obj); - Type type = obj.GetType(); - if (type == typeof(Sphere)) return Equals((Sphere)obj); - if (type == typeof(float)) return Equals((float)obj); - return base.Equals(obj); - } + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] 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); - public string ToString(string? provider) => "Center: " + center.ToString(provider) - + " Radius: " + radius.ToString(provider); - public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider) - + " Radius: " + radius.ToString(provider); + public virtual bool Equals(Sphere? other) + { + if (other is null) return false; + return center == other.center && radius == other.radius; + } + public override int GetHashCode() => base.GetHashCode(); - public object Clone() => new Sphere(center, radius); - - public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume); + public int CompareTo(Sphere? other) + { + if (other is null) return -1; + return Volume.CompareTo(other.Volume); + } + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public int CompareTo(float volume) => Volume.CompareTo(volume); public bool Contains(Vert vert) => (center - vert).Magnitude <= radius; public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + center; + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("Center = "); + builder.Append(builder); + builder.Append(", Radius = "); + builder.Append(radius); + return true; + } + 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, float b) => new(a.center, a.radius + b); @@ -103,16 +112,37 @@ public struct Sphere : ICloneable, IClosest, IComparable, ICompara 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, 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); + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator ==(Sphere a, float b) => a.Equals(b); + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator !=(Sphere a, float b) => !a.Equals(b); + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator >(Sphere a, float b) => a.CompareTo(b) > 0; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator <(Sphere a, float b) => a.CompareTo(b) < 0; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator >=(Sphere a, Sphere b) => a > b || a == b; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator <=(Sphere a, Sphere b) => a < b || a == b; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator >=(Sphere a, float b) => a > b || a == b; + [Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " + + "This method will be removed in Nerd_STF 2.5.0.")] public static bool operator <=(Sphere a, float b) => a < b || a == b; + + public static implicit operator Sphere((Vert center, float radius) val) => + new(val.center, val.radius); } diff --git a/Nerd_STF/Mathematics/Geometry/Triangle.cs b/Nerd_STF/Mathematics/Geometry/Triangle.cs index dab25e9..415c75e 100644 --- a/Nerd_STF/Mathematics/Geometry/Triangle.cs +++ b/Nerd_STF/Mathematics/Geometry/Triangle.cs @@ -1,6 +1,10 @@ -namespace Nerd_STF.Mathematics.Geometry; +using System.Net.Security; -public struct Triangle : ICloneable, IEquatable, IGroup +namespace Nerd_STF.Mathematics.Geometry; + +public record class Triangle : IAbsolute, IAverage, ICeiling, IClamp, + IEquatable, IFloor, IFromTuple, IGroup, + IIndexAll, IIndexRangeAll, ILerp, IRound, IShape2D { public Vert A { @@ -142,6 +146,28 @@ public struct Triangle : ICloneable, IEquatable, IGroup } } } + public Vert this[Index index] + { + get => this[index.IsFromEnd ? 3 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value; + } + public Vert[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Triangle Absolute(Triangle val) => new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C)); @@ -173,6 +199,8 @@ public struct Triangle : ICloneable, IEquatable, IGroup (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs)); } + public static Triangle Round(Triangle val) => + new(Vert.Round(val.A), Vert.Round(val.B), Vert.Round(val.C)); public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris) { @@ -217,20 +245,12 @@ public struct Triangle : ICloneable, IEquatable, IGroup } public static List ToFloatListAll(params Triangle[] tris) => new(ToFloatArrayAll(tris)); - public override bool Equals([NotNullWhen(true)] object? obj) + public virtual bool Equals(Triangle? other) { - if (obj == null || obj.GetType() != typeof(Triangle)) return base.Equals(obj); - return Equals((Triangle)obj); + if (other is null) return false; + return A == other.A && B == other.B && C == other.C; } - public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C; - public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); - public string ToString(IFormatProvider provider) => - "A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider); - - public object Clone() => new Triangle(A, B, C); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -254,6 +274,18 @@ public struct Triangle : ICloneable, IEquatable, IGroup public List ToFloatList() => 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 }; + + protected virtual bool PrintMembers(StringBuilder builder) + { + builder.Append("A = "); + builder.Append(A); + builder.Append(", B = "); + builder.Append(B); + builder.Append(", C = "); + builder.Append(C); + return true; + } + public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C); public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b); public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C); @@ -265,8 +297,6 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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, 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); @@ -274,4 +304,6 @@ public struct Triangle : ICloneable, IEquatable, IGroup 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((Vert a, Vert b, Vert c) val) => + new(val.a, val.b, val.c); } diff --git a/Nerd_STF/Mathematics/Geometry/Vert.cs b/Nerd_STF/Mathematics/Geometry/Vert.cs index 6c48269..9b7fc1c 100644 --- a/Nerd_STF/Mathematics/Geometry/Vert.cs +++ b/Nerd_STF/Mathematics/Geometry/Vert.cs @@ -50,6 +50,8 @@ public struct Vert : ICloneable, IEquatable, IGroup Float3.Max(ToFloat3Array(vals)); public static Vert Min(params Vert[] vals) => Float3.Min(ToFloat3Array(vals)); + public static Vert Round(Vert val) => + Float3.Round(val); public static Float3[] ToFloat3Array(params Vert[] vals) { @@ -66,9 +68,7 @@ public struct Vert : ICloneable, IEquatable, IGroup } public bool Equals(Vert other) => position == other.position; public override int GetHashCode() => position.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => position.ToString(provider); - public string ToString(IFormatProvider provider) => position.ToString(provider); + public override string ToString() => position.ToString(); public object Clone() => new Vert(position); diff --git a/Nerd_STF/Mathematics/Int2.cs b/Nerd_STF/Mathematics/Int2.cs index aefd30e..55482ae 100644 --- a/Nerd_STF/Mathematics/Int2.cs +++ b/Nerd_STF/Mathematics/Int2.cs @@ -1,6 +1,10 @@ namespace Nerd_STF.Mathematics; -public struct Int2 : ICloneable, IComparable, IEquatable, IGroup +public record struct Int2 : IAbsolute, IAverage, IClamp, IClampMagnitude, + IComparable, ICross, IDivide, IDot, IEquatable, + IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, + IMathOperators, IMax, IMedian, IMin, IPresets2D, IProduct, + ISplittable, ISubtract, ISum { public static Int2 Down => new(0, -1); public static Int2 Left => new(-1, 0); @@ -47,6 +51,28 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup this[index.IsFromEnd ? 2 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Int2 Absolute(Int2 val) => new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); @@ -92,14 +118,14 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup val ? d : val; + foreach (Int2 d in vals) val = d.Magnitude > val.Magnitude ? d : val; return val; } public static Int2 Min(params Int2[] vals) { if (vals.Length < 1) return Zero; Int2 val = vals[0]; - foreach (Int2 d in vals) val = d < val ? d : val; + foreach (Int2 d in vals) val = d.Magnitude < val.Magnitude ? d : val; return val; } public static Int2 Product(params Int2[] vals) @@ -128,21 +154,11 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int2)) return base.Equals(obj); - return Equals((Int2)obj); - } public bool Equals(Int2 other) => x == other.x && y == other.y; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider); - - public object Clone() => new Int2(x, y); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -161,6 +177,15 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup ((Float2)this).ToVector(); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + return true; + } + public static Int2 operator +(Int2 a, Int2 b) => new(a.x + b.x, a.y + b.y); public static Int2 operator -(Int2 i) => new(-i.x, -i.y); public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y); @@ -173,11 +198,17 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup new(a.x & b.x, a.y & b.y); public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y); public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y); - public static bool operator ==(Int2 a, Int2 b) => a.Equals(b); - public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Int2 a, Int2 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Int2 a, Int2 b) => a == b || a < b; public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i); @@ -191,4 +222,5 @@ public struct Int2 : ICloneable, IComparable, IEquatable, IGroup new(val.x, val.y); public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y); public static implicit operator Int2(Fill fill) => new(fill); + public static implicit operator Int2((int x, int y) val) => new(val.x, val.y); } diff --git a/Nerd_STF/Mathematics/Int3.cs b/Nerd_STF/Mathematics/Int3.cs index 7b47634..2b3c881 100644 --- a/Nerd_STF/Mathematics/Int3.cs +++ b/Nerd_STF/Mathematics/Int3.cs @@ -1,6 +1,12 @@ -namespace Nerd_STF.Mathematics; +using System.Data; -public struct Int3 : ICloneable, IComparable, IEquatable, IGroup +namespace Nerd_STF.Mathematics; + +public record struct Int3 : IAbsolute, IAverage, IClamp, IClampMagnitude, + IComparable, ICross, IDivide, IDot, IEquatable, + IFromTuple, IGroup, IIndexAll, IIndexRangeAll, ILerp, + IMathOperators, IMax, IMedian, IMin, IPresets3D, IProduct, + ISplittable, ISubtract, ISum { public static Int3 Back => new(0, 0, -1); public static Int3 Down => new(0, -1, 0); @@ -60,6 +66,28 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup this[index.IsFromEnd ? 3 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Int3 Absolute(Int3 val) => new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); @@ -112,14 +140,14 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup val ? d : val; + foreach (Int3 d in vals) val = d.Magnitude > val.Magnitude ? d : val; return val; } public static Int3 Min(params Int3[] vals) { if (vals.Length < 1) return Zero; Int3 val = vals[0]; - foreach (Int3 d in vals) val = d < val ? d : val; + foreach (Int3 d in vals) val = d.Magnitude < val.Magnitude ? d : val; return val; } public static Int3 Product(params Int3[] vals) @@ -148,20 +176,13 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int3)) return base.Equals(obj); - return Equals((Int3)obj); - } public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider); - public object Clone() => new Int3(x, y, z); + public override int GetHashCode() => base.GetHashCode(); + IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() { @@ -180,6 +201,17 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup ((Float3)this).ToVector(); + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + builder.Append(", z = "); + builder.Append(z); + return true; + } + public static Int3 operator +(Int3 a, Int3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); public static Int3 operator -(Int3 i) => new(-i.x, -i.y, -i.z); public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); @@ -192,11 +224,17 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup new(a.x & b.x, a.y & b.y, a.z & b.z); public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z); public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z); - public static bool operator ==(Int3 a, Int3 b) => a.Equals(b); - public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Int3 a, Int3 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Int3 a, Int3 b) => a == b || a < b; public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0); @@ -215,4 +253,6 @@ public struct Int3 : ICloneable, IComparable, IEquatable, IGroup new(val.R, val.G, val.B); public static explicit operator Int3(HSVAByte val) => new(val.H, val.S, val.V); public static implicit operator Int3(Fill fill) => new(fill); + public static implicit operator Int3((int x, int y, int z) vals) => + new(vals.x, vals.y, vals.z); } diff --git a/Nerd_STF/Mathematics/Int4.cs b/Nerd_STF/Mathematics/Int4.cs index 192d98a..9598d29 100644 --- a/Nerd_STF/Mathematics/Int4.cs +++ b/Nerd_STF/Mathematics/Int4.cs @@ -1,8 +1,14 @@ namespace Nerd_STF.Mathematics; -public struct Int4 : ICloneable, IComparable, IEquatable, IGroup +public record struct Int4 : IAbsolute, IAverage, IClamp, IClampMagnitude, + IComparable, IDivide, IDot, IEquatable, + IFromTuple, IGroup, IIndexAll, IIndexRangeAll, + ILerp, IMathOperators, IMax, IMedian, IMin, IPresets4D, + IProduct, ISplittable, ISubtract, ISum { public static Int4 Back => new(0, 0, -1, 0); + [Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " + + "This field will be removed in v2.4.0.", false)] public static Int4 Deep => new(0, 0, 0, -1); public static Int4 Down => new(0, -1, 0, 0); [Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " + @@ -81,6 +87,28 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public int[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Int4 Absolute(Int4 val) => new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); @@ -129,14 +157,14 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup val ? d : val; + foreach (Int4 d in vals) val = d.Magnitude > val.Magnitude ? d : val; return val; } public static Int4 Min(params Int4[] vals) { if (vals.Length < 1) return Zero; Int4 val = vals[0]; - foreach (Int4 d in vals) val = d < val ? d : val; + foreach (Int4 d in vals) val = d.Magnitude < val.Magnitude ? d : val; return val; } public static Int4 Product(params Int4[] vals) @@ -168,23 +196,11 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Int4)) return base.Equals(obj); - return Equals((Int4)obj); - } public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w; - public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - public string ToString(IFormatProvider provider) => - "X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider) - + " W: " + w.ToString(provider); - - public object Clone() => new Int4(x, y, z, w); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -203,6 +219,19 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup ToList() => new() { x, y, z, w }; + private bool PrintMembers(StringBuilder builder) + { + builder.Append("x = "); + builder.Append(x); + builder.Append(", y = "); + builder.Append(y); + builder.Append(", z = "); + builder.Append(z); + builder.Append(", w = "); + builder.Append(w); + return true; + } + public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); public static Int4 operator -(Int4 d) => new(-d.x, -d.y, -d.z, -d.w); public static Int4 operator -(Int4 a, Int4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); @@ -215,11 +244,17 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w); public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w); public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w); - public static bool operator ==(Int4 a, Int4 b) => a.Equals(b); - public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Int4 a, Int4 b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Int4 a, Int4 b) => a == b || a < b; public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0); @@ -240,4 +275,6 @@ public struct Int4 : ICloneable, IComparable, IEquatable, IGroup new(val.C, val.M, val.Y, val.K); public static implicit operator Int4(HSVAByte val) => new(val.H, val.S, val.V, val.A); public static implicit operator Int4(Fill fill) => new(fill); + public static implicit operator Int4((int x, int y, int z, int w) vals) => + new(vals.x, vals.y, vals.z, vals.w); } diff --git a/Nerd_STF/Mathematics/Mathf.cs b/Nerd_STF/Mathematics/Mathf.cs index bebb2ad..788638c 100644 --- a/Nerd_STF/Mathematics/Mathf.cs +++ b/Nerd_STF/Mathematics/Mathf.cs @@ -105,8 +105,7 @@ public static class Mathf public static int[] Factors(int val) { - List factors = new(); - factors.Add(1); + List factors = new() { 1 }; for (int i = 2; i < val; i++) if (val % i == 0) factors.Add(i); factors.Add(val); return factors.ToArray(); @@ -144,14 +143,14 @@ public static class Mathf if (clamp) v = Clamp(v, Min(a, b), Max(a, b)); return v; } - public static int Lerp(int a, int b, float value, bool clamp = true) => (int)Lerp((float)a, b, value, clamp); + public static int Lerp(int a, int b, float t, bool clamp = true) => (int)Lerp((float)a, b, t, clamp); public static Equation MakeEquation(Dictionary vals) => delegate (float x) { if (vals.Count < 1) throw new UndefinedException(); if (vals.Count == 1) return vals.Values.First(); - if (vals.ContainsKey(x)) return vals[x]; + if (vals.TryGetValue(x, out float value)) return value; float? min, max; if (x < (min = vals.Keys.Min())) @@ -212,9 +211,9 @@ public static class Mathf foreach (int i in vals) val = i > val ? i : val; return val; } - public static T? Max(params T[] vals) where T : IComparable + public static T Max(params T[] vals) where T : IComparable { - if (vals.Length < 1) return default; + if (vals.Length < 1) return default!; T val = vals[0]; foreach (T t in vals) val = t.CompareTo(val) > 0 ? t : val; return val; @@ -254,9 +253,9 @@ public static class Mathf foreach (int i in vals) val = i < val ? i : val; return val; } - public static T? Min(params T[] vals) where T : IComparable + public static T Min(params T[] vals) where T : IComparable { - if (vals.Length < 1) return default; + if (vals.Length < 1) return default!; T val = vals[0]; foreach (T t in vals) val = t.CompareTo(val) < 0 ? t : val; return val; @@ -327,8 +326,7 @@ public static class Mathf if (pow == 1) return num; if (pow < 1) return 0; int val = 1; - int abs = Absolute(pow); - for (int i = 0; i < abs; i++) val = val * num % mod; + for (int i = 0; i < pow; i++) val = val * num % mod; return val; } diff --git a/Nerd_STF/Mathematics/NumberSystems/Complex.cs b/Nerd_STF/Mathematics/NumberSystems/Complex.cs index 0ffe053..85db4ae 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Complex.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Complex.cs @@ -1,6 +1,10 @@ namespace Nerd_STF.Mathematics.NumberSystems; -public struct Complex : ICloneable, IComparable, IEquatable, IGroup +public record struct Complex(float u, float i) : IAbsolute, IAverage, ICeiling, + IClampMagnitude, IComparable, IDivide, IDot, + IEquatable, IFloor, IGroup, IIndexAll, IIndexRangeAll, + ILerp, IMax, IMedian, IMin, IPresets2D, IProduct, + IRound, ISplittable, ISum { public static Complex Down => new(0, -1); public static Complex Left => new(-1, 0); @@ -15,14 +19,10 @@ public struct Complex : ICloneable, IComparable, IEquatable, I public float Magnitude => Mathf.Sqrt(u * u + i * i); public Complex Normalized => this * Mathf.InverseSqrt(u * u + i * i); - public float u, i; + public float u = u; + public float i = i; public Complex(float all) : this(all, all) { } - public Complex(float u, float i) - { - this.u = u; - this.i = i; - } public Complex(Fill fill) : this(fill(0), fill(1)) { } public Complex(Fill fill) : this(fill(0), fill(1)) { } @@ -50,6 +50,28 @@ public struct Complex : ICloneable, IComparable, IEquatable, I } } } + public float this[Index index] + { + get => this[index.IsFromEnd ? 2 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Complex Absolute(Complex val) => Float2.Absolute(val); public static Complex Average(params Complex[] vals) @@ -129,20 +151,8 @@ public struct Complex : ICloneable, IComparable, IEquatable, I public Angle GetAngle() => Mathf.ArcTan(i / u); public int CompareTo(Complex other) => Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Complex)) return base.Equals(obj); - return Equals((Complex)obj); - } public bool Equals(Complex other) => u == other.u && i == other.i; - public override int GetHashCode() => u.GetHashCode() ^ i.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => - u.ToString(provider) + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"; - public string ToString(IFormatProvider provider) => - u.ToString(provider) + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"; - - public object Clone() => new Complex(u, i); + public override int GetHashCode() => base.GetHashCode(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public IEnumerator GetEnumerator() @@ -161,6 +171,15 @@ public struct Complex : ICloneable, IComparable, IEquatable, I public Vector2d ToVector() => ((Float2)this).ToVector(); + private bool PrintMembers(StringBuilder builder) + { + builder.Append(u); + builder.Append(i >= 0 ? " + " : " - "); + builder.Append(Mathf.Absolute(i)); + builder.Append('i'); + return true; + } + public static Complex operator +(Complex a, Complex b) => new(a.u + b.u, a.i + b.i); public static Complex operator -(Complex c) => new(-c.u, -c.i); public static Complex operator -(Complex a, Complex b) => new(a.u - b.u, a.i - b.i); @@ -171,11 +190,17 @@ public struct Complex : ICloneable, IComparable, IEquatable, I 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); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Complex a, Complex b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Complex a, Complex b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Complex a, Complex b) => a == b || a < b; public static explicit operator Complex(Quaternion val) => new(val.u, val.i); @@ -190,4 +215,5 @@ public struct Complex : ICloneable, IComparable, IEquatable, I public static explicit operator Complex(Vert val) => new(val.position.x, val.position.y); public static implicit operator Complex(Fill fill) => new(fill); public static implicit operator Complex(Fill fill) => new(fill); + public static implicit operator Complex((float u, float i) val) => new(val.u, val.i); } diff --git a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs index 987a583..ea74f48 100644 --- a/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs +++ b/Nerd_STF/Mathematics/NumberSystems/Quaternion.cs @@ -1,12 +1,23 @@ namespace Nerd_STF.Mathematics.NumberSystems; -public struct Quaternion : ICloneable, IComparable, IEquatable, IGroup +public record struct Quaternion(float u, float i, float j, float k) : IAbsolute, IAverage, + ICeiling, IClamp, IClampMagnitude, IComparable, + IDivide, IDot, IEquatable, IFloor, IGroup, + IIndexAll, IIndexRangeAll, ILerp, IMax, IMedian, + IMin, IPresets4D, IProduct, IRound, + ISplittable, ISum { public static Quaternion Back => new(0, 0, -1, 0); public static Quaternion Down => new(0, -1, 0, 0); + [Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " + + "This field will be removed in v2.4.0.", false)] public static Quaternion Far => new(0, 0, 0, 1); public static Quaternion Forward => new(0, 0, 1, 0); + public static Quaternion HighW => new(0, 0, 0, 1); public static Quaternion Left => new(-1, 0, 0, 0); + public static Quaternion LowW => new(0, 0, 0, -1); + [Obsolete("Field has been replaced by " + nameof(LowW) + ", because it has a better name. " + + "This field will be removed in v2.4.0.", false)] public static Quaternion Near => new(0, 0, 0, -1); public static Quaternion Right => new(1, 0, 0, 0); public static Quaternion Up => new(0, 1, 0, 0); @@ -30,19 +41,15 @@ public struct Quaternion : ICloneable, IComparable, IEquatable fill) : this(fill(0), fill(1), fill(2)) { } public Quaternion(Fill fill) : this(fill(0), fill(1), fill(2)) { } @@ -80,6 +87,28 @@ public struct Quaternion : ICloneable, IComparable, IEquatable this[index.IsFromEnd ? 4 - index.Value : index.Value]; + set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value; + } + public float[] this[Range range] + { + get + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + List res = new(); + for (int i = start; i < end; i++) res.Add(this[i]); + return res.ToArray(); + } + set + { + int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value; + int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value; + for (int i = start; i < end; i++) this[i] = value[i]; + } + } public static Quaternion Absolute(Quaternion val) => Float4.Absolute(val); public static Quaternion Average(params Quaternion[] vals) @@ -187,24 +216,8 @@ public struct Quaternion : ICloneable, IComparable, IEquatable Magnitude.CompareTo(other.Magnitude); - public override bool Equals([NotNullWhen(true)] object? obj) - { - if (obj == null || obj.GetType() != typeof(Quaternion)) return base.Equals(obj); - return Equals((Quaternion)obj); - } public bool Equals(Quaternion other) => u == other.u && i == other.i && j == other.j && k == other.k; - public override int GetHashCode() => u.GetHashCode() ^ i.GetHashCode() ^ j.GetHashCode() ^ k.GetHashCode(); - public override string ToString() => ToString((string?)null); - public string ToString(string? provider) => u.ToString(provider) - + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i" - + (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j" - + (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k"; - public string ToString(IFormatProvider provider) => u.ToString(provider) - + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i" - + (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j" - + (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k"; - - public object Clone() => new Quaternion(u, i, j, k); + public override int GetHashCode() => base.GetHashCode(); public Angle GetAngle() => Mathf.ArcCos(u) * 2; public Float3 GetAxis() => IJK.Normalized; @@ -275,8 +288,23 @@ public struct Quaternion : ICloneable, IComparable, IEquatable ToList() => new() { u, i, j, k }; + private bool PrintMembers(StringBuilder builder) + { + builder.Append(u); + builder.Append(i >= 0 ? " + " : " - "); + builder.Append(Mathf.Absolute(i)); + builder.Append('i'); + builder.Append(j >= 0 ? " + " : " - "); + builder.Append(Mathf.Absolute(j)); + builder.Append('j'); + builder.Append(k >= 0 ? " + " : " - "); + builder.Append('k'); + builder.Append(Mathf.Absolute(k)); + return true; + } + public static Quaternion operator +(Quaternion a, Quaternion b) => new(a.u + b.u, a.i + b.i, a.j + b.j, a.k + b.k); - public static Quaternion operator -(Quaternion q) => new(q.u, q.i, q.j, q.k); + public static Quaternion operator -(Quaternion q) => new(-q.u, -q.i, -q.j, -q.k); public static Quaternion operator -(Quaternion a, Quaternion b) => new(a.u - b.u, a.i - b.i, a.j - b.j, a.k - b.k); public static Quaternion operator *(Quaternion x, Quaternion y) { @@ -295,11 +323,17 @@ public struct Quaternion : ICloneable, IComparable, IEquatable (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); + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0; + [Obsolete("This operator is a bit ambiguous. You should instead compare " + + nameof(Magnitude) + "s directly.")] public static bool operator <(Quaternion a, Quaternion b) => a.CompareTo(b) < 0; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator >=(Quaternion a, Quaternion b) => a == b || a > b; + [Obsolete("This operator is a bit ambiguous (and misleading at times). " + + "You should instead compare " + nameof(Magnitude) + "s directly.")] public static bool operator <=(Quaternion a, Quaternion b) => a == b || a < b; public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0); @@ -314,4 +348,6 @@ public struct Quaternion : ICloneable, IComparable, IEquatable new(val); public static implicit operator Quaternion(Fill fill) => new(fill); public static implicit operator Quaternion(Fill fill) => new(fill); + public static implicit operator Quaternion((float u, float i, float j, float k) val) => + new(val.u, val.i, val.j, val.k); } diff --git a/Nerd_STF/Mathematics/Samples/Constants.cs b/Nerd_STF/Mathematics/Samples/Constants.cs index 6b916c7..418a349 100644 --- a/Nerd_STF/Mathematics/Samples/Constants.cs +++ b/Nerd_STF/Mathematics/Samples/Constants.cs @@ -33,7 +33,7 @@ public static class Constants public const float Sqrt3 = 1.7320508076f; public const float Sqrt5 = 2.2360679775f; public const float Sqrt10 = 3.16227766017f; - public const float TwelthRoot2 = 1.05946309436f; + public const float TwelfthRoot2 = 1.05946309436f; public const float Cos0Deg = 1; public const float Cos30Deg = Sqrt3 / 2; @@ -85,7 +85,7 @@ public static class Constants public const float ConnectiveConstant = 1.847759065f; public const float DeVicciTesseractConstant = 1.0074347568f; public const float EmbreeTrefethenConstant = 0.70258f; - public const float EulerMascheroniConstant = 0.5772156649f; + public const float EulerMascheroniConstant = EulerConstant; public const float ErdosBorweinConstant = 1.6066951524f; public const float ErdosTenenbaumFordConstant = 0.8607133205f; public const float FeigenbaumConstant1 = 4.6692016091f; @@ -108,7 +108,7 @@ public static class Constants public const float LandauConstant = (0.5f + 0.54326f) / 2; public const float LandauThirdConstant = (0.5f + 0.7853f) / 2; public const float LandauRamanujanConstant = 0.7642236535f; - public const float LiebSquareIceConstant = 8 / (3 * Sqrt3); + public const float LiebSquareIceConstant = 8 * Sqrt3 / 9; public const float LemniscateConstant = 2.6220575542f; public const float LevyConstant1 = Pi * Pi / (12 * Ln2); public const float LevyConstant2 = 3.2758229187f; @@ -141,8 +141,8 @@ public static class Constants public const float FirstNielsenRamanujanConstant = Pi * Pi / 12; public const float SecondDuBoisRaymondConstant = (E * E - 7) / 2; public const float SecondFavardConstant = 1.2337005501f; - public const float SecondHermiteConstant = 2 / Sqrt3; - public const float UniversalHyperbolicConstant = 2.2955871493f; + public const float SecondHermiteConstant = 2 * Sqrt3 / 9; + public const float UniversalParabolicConstant = 2.2955871493f; public const float DottieNumber = 0.7390851332f; public const float FractalDimensionOfTheApollonianPackingOfCircles = 1.305688f; @@ -152,5 +152,5 @@ public static class Constants public const float PlasticNumber = 1.3247179572f; public const float LaplaceLimit = 0.6627434193f; public const float LogarithmicCapacityOfTheUnitDisk = 0.5901702995f; - public const float RegularPaperfoldingSequence = 0.8507361882f; + public const float RegularPaperfoldingConstant = 0.8507361882f; } diff --git a/Nerd_STF/Miscellaneous/AssemblyInfo.cs b/Nerd_STF/Miscellaneous/AssemblyInfo.cs new file mode 100644 index 0000000..a3721d3 --- /dev/null +++ b/Nerd_STF/Miscellaneous/AssemblyInfo.cs @@ -0,0 +1,4 @@ +using System.Reflection; + +// Includes assembly configuration that isn't automatically handled by the compiler. +// So far, there is none. There may be some in the future. We will see. diff --git a/Nerd_STF/Miscellaneous/GlobalUsings.cs b/Nerd_STF/Miscellaneous/GlobalUsings.cs index ed144bb..f5408f2 100644 --- a/Nerd_STF/Miscellaneous/GlobalUsings.cs +++ b/Nerd_STF/Miscellaneous/GlobalUsings.cs @@ -1,18 +1,22 @@ -global using System; +global using Nerd_STF; +global using Nerd_STF.Graphics; +global using Nerd_STF.Graphics.Abstract; +global using Nerd_STF.Exceptions; +global using Nerd_STF.Extensions; +global using Nerd_STF.Mathematics; +global using Nerd_STF.Mathematics.Abstract; +global using Nerd_STF.Mathematics.Algebra; +global using Nerd_STF.Mathematics.Geometry; +global using Nerd_STF.Mathematics.NumberSystems; +global using Nerd_STF.Mathematics.Samples; +global using System; global using System.Collections; global using System.Collections.Generic; global using System.Diagnostics.CodeAnalysis; global using System.IO; global using System.Linq; global using System.Net.Http; +global using System.Runtime.Serialization; +global using System.Text; global using System.Threading; global using System.Threading.Tasks; -global using Nerd_STF; -global using Nerd_STF.Graphics; -global using Nerd_STF.Exceptions; -global using Nerd_STF.Extensions; -global using Nerd_STF.Mathematics; -global using Nerd_STF.Mathematics.Algebra; -global using Nerd_STF.Mathematics.Geometry; -global using Nerd_STF.Mathematics.NumberSystems; -global using Nerd_STF.Mathematics.Samples; diff --git a/Nerd_STF/Nerd_STF.cs b/Nerd_STF/Nerd_STF.cs new file mode 100644 index 0000000..559b45b --- /dev/null +++ b/Nerd_STF/Nerd_STF.cs @@ -0,0 +1,21 @@ +namespace Nerd_STF; + +public static class Nerd_STF +{ + public static readonly string[] Contributors = + { + MainDeveloper + }; + public static readonly Dictionary PersonalLinks = new() + { + { "email", "mailto:kyle@thatonenerd.net" }, + { "website", "https://thatonenerd.net/" } + }; + public static readonly Dictionary LibraryLinks = new() + { + { "github", "https://github.com/That-One-Nerd/Nerd_STF" }, + { "nuget", "https://www.nuget.org/packages/Nerd_STF/" } + }; + public const string MainDeveloper = "That_One_Nerd"; + public const string Version = "2.3.2"; +} diff --git a/Nerd_STF/Nerd_STF.csproj b/Nerd_STF/Nerd_STF.csproj index 867da58..fcbba69 100644 --- a/Nerd_STF/Nerd_STF.csproj +++ b/Nerd_STF/Nerd_STF.csproj @@ -1,59 +1,57 @@ - + - net6.0 - enable + net7.0 + disable 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. + Nerd_STF is a general-purpose .NET library. Copyright (c) 2022 That_One_Nerd README.md https://github.com/That-One-Nerd/Nerd_STF - 2.3.1 + 2.3.2 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 + 2.3.2 Nerd_STF Nerd_STF MIT Logo Square.png - -# Nerd_STF v2.3.1 + A bunch of stuff has changed, hasn't it? -***Everything has been tested and most things work!*** +This update was originally intended to be a support update. But among other problems, I don't want to maintain 3 slightly different versions of Nerd_STF at the same time. So I'm going to put the support update on hold for now. I won't delete my progress on it (I got about a quarter of the way done with support for .NET Standard 2.0. It's a big undertaking), I won't promise any completion date either. -**WARNING:** -All of the matrix classes have had all of their constructors' row and column variables swapped. You'll have to switch all your variables around. -Sorry for the inconvenience :(. +Instead, this update ended up being a quality-of-life update. I already finished this part of the update before I decided to cancel the support update. This update now has lots of support for the new .NET 7 features. I'm now using a bunch of static abstract interfaces. I also added range indexing to almost all of the types available. The color byte types now have int fields instead of byte fields because ints are much more common. The values are automatically clamped between 0 and 255 just in case. Basically all types are records now because records are really nice. Lastly, some stuff has been marked as deprecated and to be removed in a future release because they already, exist, are kind of useless, and/or are misleading. Most of the deprecated stuff will be removed in either 2.4.0 or 2.5.0. -The `v2.3.1.x` updates go through every single field and method in Nerd_STF to make sure it works correctly. -You see, up until now I haven't actually tested literally anything at all. Partly because I didn't have the tools to and partly because I was lazy. But now, it's guarenteed to work in most cases (unless I like don't pick up some bug, you know). +Also, just want to note that despite the Vert`struct not being marked as deprecated, it will still be removed in 2.5.0. I didn't mark it because that would have created a bunch of warnings in my library. And I don't like warnings. -Hi everyone! Everything has been checked now and most stuff works! Not everything, like the triangle and quadrilateral area stuff, but for the most part, it's all cool and good. +One final note, I've changed the description of the library and I've changed a bunch of the assembly and compilation settings. -I've just now remembered how bad the Polygon struct was. It's getting remade. The v2.4.0 update will be mostly geometry focused, so that'll be the best time to figure out how to fix this stuff. The new Polygon struct will be much better, trust me. - -But all the matrix structs work like charm now! I'm honestly suprised they worked as well as they did before (especially the dynamic matrix). They can now be relied on. - -Next up is the documentation update. Stay tuned! -(This may be another update with beta parts, but I'm not sure yet. We'll see). - -*P.S. (NuGet only message): I didn't know I had the room to put the whole changelog here. I'll do that from now on.* - +Anyway, that's it for this update. The longest delay was just getting this project to other versions of .NET. Stay tuned for v2.4.0, the Equations and Numbers update! https://github.com/That-One-Nerd/Nerd_STF False False False + Nerd_STF + True + snupkg + False + C:\Users\kyley\Desktop\Misc Items\Private Keys\SNA\Nerd_STF.snk + False - True + False + 9999 + False True + 9999 + True diff --git a/README.md b/README.md index 5ecbcbf..c2a0763 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,46 @@ # Nerd_STF +## Table of Contents +- [What is it?](#what-is-it) +- [What about Nerd_STF Versions `2021`?](#what-about-nerd_stf-versions-2021) +- [How do I install it?](#how-do-i-install-it) +- [I've found a bug!](#ive-found-a-bug) +- [I'd like to contribute.](#id-like-to-contribute) + ## What is it? -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. Feel free to do with it what you would like. +Nerd_STF is a multi-purpose .NET 7.0 library that contains many objects I feel would help the default C# library package. Feel free to do with it what you'd like. -Nerd_STF has recently been remade, completely rebuilding many of its topics. - -## What does it include? -Nerd_STF will include math structures as well as other computer science topics. Right now, it is mainly focused on mathematics, but will branch out in the future. It currently contains things like lists of 3 floats or ints, or `Vert`, `Line`, and `Triangle` classes, that are rich in implementation. +Nerd_STF includes some math as well as many other computer science topics. It contains types like groups of floats/ints, geometry types like `Vert`, `Line`, and `Triangle`, and color types like `RGBA`, `CMYKA`, `HSVA`, and their byte equivalents, all of which can convert seamlessly between each other. ## What about Nerd_STF Versions `2021`? Nerd_STF `2021` used an different version scheme, based on the year, as you might have guessed (it is not the year `2` right now), and while I will be keeping the `2021` versions up, I wouldn't recommend using them, and the code is old code, written by a more naive me. Hell, I wrote an entire `List` class there before I knew of the `System.Collections.Generic.List` class that did literally everything for me already. Oh well. So, keep that in mind when you check out those versions of the library. ## How do I install it? -There is a nuget package for this ([here](https://www.nuget.org/packages/Nerd_STF/)), so you could install it that way. +The NuGet package for this library is [here](https://www.nuget.org/packages/Nerd_STF/), so you could always install it that way using the .NET CLI: +1. Open your terminal in your project directory. +2. Enter this command: `dotnet add package Nerd_STF` +3. There is no step 3. -Alternatively, you can install it with a project reference in Visual Studio, and I'll walk you through doing that here. +You can also include the NuGet package via a package reference in your project file: +1. Open your project file. +2. Add this to the XML data: `` +3. There is no step 3. -Step 1: Find the `.dll` for this library, found in `/Nerd_STF/Nerd_STF/bin/Release/net6.0/ref/Nerd_STF.dll`. You can either move it, or simply remember where it is. -Step 2: Search for "Add Project Reference" in the Visual Studio 2019 or 2022 search bar. -Step 3: Click the "Browse" tab on the left, then click the "Browse" button on the bottom-right. -Step 4: Select the `.dll` we found earlier. -Step 5: Click OK. +Alternatively, you can install it via a project reference in Visual Studio 2019 and 2022. Here's how: +1. Download the latest library release from the [GitHub repository](https://github.com/That-One-Nerd/Nerd_STF/releases), extract the files, and save them somewhere you can find later. The files must all be in the same direcrtory/folder together. +2. Open Visual Studio 2019 or 2022. +3. Right-click your .NET project in the Solution Explorer. +4. Hover over "Add >" list and then click "Project Reference..." +5. Click "Browse," and locate the `.dll` file you previously extracted (the full name is "Nerd_STF.dll"). +6. Click "Add," then "OK," and the library is now imported! -This is what happens the first time you import it. Any other times, simply go to the "Add Project Reference" Window, then the "Browse" tab, and the `.dll` will already be in the list in the middle. Find it, and click the box on its left. Then click OK. +## I've found a bug! ---- +I'm not suprised, there are definitely a bunch of undiscovered bugs in Nerd_STF simply because I'm just one person. If you've found one, please do me a favor and create an issue about it in the [GitHub repository](https://github.com/That-One-Nerd/Nerd_STF). They likely aren't difficult fixes, they are just hard to spot even with some level of testing. -I hope you enjoy using Nerd_STF! +## I'd like to contribute. + +I would love some contributions! I probably won't accept drastic pull requests or merges with the library, but small changes are quite welcome! I'm just one person and I can only do so much work by myself. If you want to contribute, please only edit the current version branch (eg. if we are on version `2.3.1`, edit the `v2.3` branch). Please do not edit the main branch. I will merge the changes with main myself. + +Try to follow a similar style to the current library, but otherwise I'm open to changes. Thank you to those who contribute!