Merge pull request #14 from That-One-Nerd/main

Released v2.3.1.52
This commit is contained in:
That_One_Nerd 2022-10-31 11:56:15 -04:00 committed by GitHub
commit 9a1821cb10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 334 additions and 305 deletions

14
.gitignore vendored
View File

@ -1,13 +1,11 @@
# Visual Studio stuff
*.csproj
*.editorconfig
*.sln
# Useless Visual Studio stuff
/Nerd_STF/.vs/
# Build Stuff
/Nerd_STF/obj
/Nerd_STF/bin/Debug
/Nerd_STF/bin/Release/net6.0/Nerd_STF.deps.json
/Nerd_STF/bin/Release/net6.0/Nerd_STF.dll
/Nerd_STF/bin/Release/net6.0/Nerd_STF.pdb
/Nerd_STF/bin
*.dll
*.pdb
# Testing project
/Testing

View File

@ -1,4 +1,4 @@
# Nerd_STF v2.3.1.39
# Nerd_STF v2.3.1.52
***Read this to know what works and what doesn't!***
@ -25,11 +25,23 @@ The following types have been checked for the most part and can be safe to use:
- `Nerd_STF.Exceptions.InvalidSizeException`
- `Nerd_STF.Exceptions.Nerd_STFException`
- `Nerd_STF.Exceptions.NoInverseException`
- `Nerd_STF.Extensions.Container2DExtension`
- `Nerd_STF.Extensions.ConversionExtension`
- `Nerd_STF.Extensions.EquationExtension`
- `Nerd_STF.Extensions.ToFillExtension`
- `Nerd_STF.Graphics.CMYKA`
- `Nerd_STF.Graphics.CMYKAByte`
- `Nerd_STF.Graphics.ColorChannel`
- `Nerd_STF.Graphics.HSVA`
- `Nerd_STF.Graphics.HSVAByte`
- `Nerd_STF.Graphics.IColor`
- `Nerd_STF.Graphics.IColorByte`
- `Nerd_STF.Graphics.IlluminationFlags`
- `Nerd_STF.Graphics.IlluminationModel`
- `Nerd_STF.Graphics.Image`
- `Nerd_STF.Graphics.Material`
- `Nerd_STF.Graphics.RGBA`
- `Nerd_STF.Graphics.RGBAByte`
- `Nerd_STF.Graphics.TextureConfig`
- `Nerd_STF.Mathematics.Angle`
- `Nerd_STF.Mathematics.Calculus`
@ -41,32 +53,13 @@ The following types have been checked for the most part and can be safe to use:
- `Nerd_STF.Mathematics.Int3`
- `Nerd_STF.Mathematics.Int4`
- `Nerd_STF.Mathematics.Mathf`
- `Nerd_STF.Mathematics.Geometry.ISubdividable`
- `Nerd_STF.Mathematics.NumberSystems.Complex`
- `Nerd_STF.Mathematics.NumberSystems.Quaternion`
- With the exception of the following methods:
- `Quaternion.FromAngles(Angle, Angle, Angle?)`
- `Quaternion.FromAngles(Float3, Angle.Type)`
- `Quaternion.FromVector(Vector3d)`
- `GetAngle()`
- `GetAxis()`
- `ToAngles()`
- `ToVector()`
- `Nerd_STF.Mathematics.Samples.Constants`
- `Nerd_STF.Mathematics.Samples.Equations`
The following types haven't been checked yet, and should still be taken with a grain of salt:
- `Nerd_STF.Extensions.Container2DExtension`
- `Nerd_STF.Extensions.ConversionExtension`
- `Nerd_STF.Extensions.EquationExtension`
- `Nerd_STF.Graphics.CMYKA`
- `Nerd_STF.Graphics.CMYKAByte`
- `Nerd_STF.Graphics.HSVA`
- `Nerd_STF.Graphics.HSVAByte`
- `Nerd_STF.Graphics.IColor`
- `Nerd_STF.Graphics.IColorByte`
- `Nerd_STF.Graphics.Image`
- `Nerd_STF.Graphics.RGBA`
- `Nerd_STF.Graphics.RGBAByte`
- `Nerd_STF.Mathematics.Algebra.IMatrix`
- `Nerd_STF.Mathematics.Algebra.Matrix`
- `Nerd_STF.Mathematics.Algebra.Matrix2x2`
@ -76,7 +69,6 @@ The following types haven't been checked yet, and should still be taken with a g
- `Nerd_STF.Mathematics.Algebra.Vector3d`
- `Nerd_STF.Mathematics.Geometry.Box2D`
- `Nerd_STF.Mathematics.Geometry.Box3D`
- `Nerd_STF.Mathematics.Geometry.ISubdividable`
- `Nerd_STF.Mathematics.Geometry.ITriangulatable`
- `Nerd_STF.Mathematics.Geometry.Line`
- `Nerd_STF.Mathematics.Geometry.Polygon`
@ -85,134 +77,74 @@ The following types haven't been checked yet, and should still be taken with a g
- `Nerd_STF.Mathematics.Geometry.Triangle`
- `Nerd_STF.Mathematics.Geometry.Vert`
I've checked a total of 39 types, with 29 left to go. It sounds like I'm over halfway, but really I've saved all of the annoying ones that are likely wrong to be checked next. My 39 done includes a bunch of really simple types that never needed checking in the first place too. But there are some done, like any type in the Mathematics directory.
16 left to go.
Honestly, most of the time taken for this update was spent on Quaternions. Turns out my multiply function was subtley wrong. Who knew!
Just a relief to be done with it. The other stuff wasn't too much of a problem. Matrixes are probably going to be a huge pain if they don't work first try, though. That'll be in the next update, probably.
I should also note that I just realized after way to long that the `.csproj` file isn't included in the Github. It's included in this new release, and sometime in the future I'll go back and add a correctly working `.csproj` file to all the other releases as well (with the exception of the legacy Nerd_STF 2021 versions likely. We'll see). I'll now not include the `/bin` build files. They'll be in the release and you can build it yourself if you need to now. Anyway, have fun.
```
* Nerd_STF
* Exceptions
+ MathException
+ UndefinedException
* Extensions
+ EquationExtension
* Container2DExtension
= Fixed `Flatten<T>(T[,], Int2)`
= `GetColumn<T>(T[,], int, int)` and `GetRow<T>(T[,], int, int)` have been fixed (They had swapped roles)
* ConversionExtension
+ ToFill<T>(T[])
+ ToFill<T>(T[,], Int2)
+ ToFill2D<T>(T[,])
* EquationExtension
= Fixed `Scale(Equation, float, ScaleType)` by swapping all instances of `x` and `value` (oops)
= Moved `ScaleType` out of parent class `EquationExtension` and into namespace `Nerd_STF`
* Geometry
* ITriangulatable
+ TriangulateAll<T>(T[]) where T : ITriangulatable
* Graphics
+ Renamed `IColor` to `IColorFloat`
= Made IColor an object both `IColorFloat` and `IColorByte` inherit from.
* CMYKA
= Made `ToRGBA()` include the alpha value of the color.
* CMYKAByte
= In `ToHSVA()` and `ToHSVAByte()`, swapped some conversions from `RGBA` to `CMYKA`
* HSVA
= Made `ToRGBA()` include the alpha value of the color.
* Image
- Removed some useless constructors
= Fixed some broken constructors
* Mathematics
* NumberSystems
* Complex
+ Inverse
+ GetAngle()
= Fixed `ToString()` and all overloads from adding a redundant negative sign sometimes in the imaginary component.
= Replaced the `/` operator with a multiplication by its inverse.
* Quaternion
+ Inverse
= Fixed `ToString()` and all overloads from adding a redundant negative sign sometimes in the i, j, and k components.
= Replaced the `/` operator with a multiplication by its inverse.
* Algebra
* Vector2d
- static Product(params Vector2d[])
- static Divide(Vector2d, params Vector2d[])
- operator *(Vector2d, Angle)
- operator *(Vector2d, Vector2d)
- operator /(Vector2d, Angle)
- operator /(Vector2d, Vector2d)
= Made `ToXYZ()` actually work
= Removed a default parameter value in `ToString(Angle.Type)` to prevent confusion.
* Vector3d
- static Product(params Vector3d[])
- static Divide(Vector3d, params Vector3d[])
- operator *(Vector3d, Angle)
- operator *(Vector3d, Vector3d)
- operator /(Vector3d, Angle)
- operator /(Vector3d, Vector3d)
* Calculus
+ GetDynamicIntegral(Equation, Equation, Equation, float)
= Made `GetDerivative(Equation, float)` calculate specific values on the fly, and removed the min/max.
* Graphics
* HSVA
- static LerpSquared(HSVA, HSVA, float, Angle.Type, bool = true)
- operator *(HSVA, HSVA)
- operator /(HSVA, HSVA)
* HSVAByte
- static LerpSquared(HSVAByte, HSVAByte, float, Angle.Type, bool = true)
+ string ToString()
+ string ToString(Angle.Type)
+ string ToString(IFormatProvider, Angle.Type)
= Fixed `ToXYZ()`
* NumberSystems
* Complex
+ operator ~(Complex)
* Quaternion
+ Rotate(Float3)
+ Rotate(Vector3d)
+ operator ~(Quaternion)
- ToVector()
= Gave `IJK` proper get and set accessors.
= Renamed some terms in `ToString()`
= Fixed the `Quaternion.FromAngles(*)` methods to do the proper thing.
= Fixed `Quaternion.Rotate(Quaternion)`
= Fixed `Quaternion.Rotate(Float3)`
= Fixed `operator *(Quaternion, Quaternion)`
= Optimized `GetAxis()`
= Simplified `ToXYZ()`
= Swapped the order of `Rotate(Quaternion)`
= Made `GetAxis()` not accidentally create an infinite vector.
* Angle
+ Reflected
+ static Max(bool, params Angle[])
+ static Min(bool, params Angle[])
- operator *(Angle, Angle)
- operator /(Angle, Angle)
= Made `Angle(float, Type)` use a lambda expression
= Made `Bounded` use the `AbsoluteMod()` function instead of the default `%` expression
= Replaced an accidental `Mathf.Floor()` call with a `Mathf.Round()` call in `Floor()`
= Made `operator -(Angle)` actually give you the reverse angle (not the reflected angle)
+ Complimentary
+ Supplementary
* Float2
= Made `Median(params Float2)` not use an unneccesary average
= Made `ToVector()` not create an angle out of `ArcTan(float)`, as it already is one
= Optimized `Divide(Float2, params Float2[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float2, params Float2[])` to subtract a sum instead of individually subtracting
+ operator *(Float2, Quaternion)
* Float3
= Made `Median(params Float3)` not use an unneccesary average
= Made `ToVector()` not create an angle out of the arc trig functions, as they already are angles
= Optimized `Divide(Float3, params Float3[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float3, params Float3[])` to subtract a sum instead of individually subtracting
* Float4
= Marked `Far` and `Near` as obsolete/deprecated, as they have been replaced by `HighW` and `LowW`
= Made `Median(params Float4)` not use an unneccesary average
= Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting
* Int2
= Made `Median(params Float4)` not use an unneccesary average
= Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting
* Int3
= Made `Median(params Float4)` not use an unneccesary average
= Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting
* Int4
+ LowW
= Marked `Far` as obsolete/deprecated, as it has been replaced by `HighW`
= Made `Median(params Float4)` not use an unneccesary average
= Optimized `Divide(Float4, params Float4[])` to divide a product instead of individually dividing
= Optimized `Subtract(Float4, params Float4[])` to subtract a sum instead of individually subtracting
* Mathf
+ AbsoluteMod(float)
+ Binomial(int, int, float)
+ Factors(int)
+ PowerMod(int, int, int)
= Fixed `Ceiling(float)` from rounding up when it shouldn't
= Made `Median(params float[])` actually calculate the right midpoint
= Removed two unneeded `Average(float, float)` calls in `Median(params float[])`
= Replaced the `Floor(float)` and `Ceiling(float)` calls in `Median(params float[])` with a better alternative
= Replaced the mod in `Sin(float)` with an `AbsoluteMod(float, float)` call
= Made `MadeEquation(Dictionary<float, float>)` actually work.
= Added caching to Power(float, int) for the absolute max
= Fixed an if statement and added another one to prevent extra computation in `Power(float, int)`
= Added caching to Power(int, int) for the absolute max
= Fixed an if statement and added another one to prevent extra computation in `Power(int, int)`
= Made the `Lerp(int, int, float, bool)` function not call itself infinitely many times.
= Replaced a multiplication with a division in `Root(float, float)`
= Made the `Average(int[])` function give you the int average instead of the float average (unlike `Average(float[])`)
= Replaced the float return statement with an Angle in `ArcCos(float)`
= Replaced the float return statement with an Angle in `ArcCot(float)`
= Replaced the float return statement with an Angle in `ArcCsc(float)`
= Replaced the float return statement with an Angle in `ArcSec(float)`
= Replaced the float return statement with an Angle in `ArcSin(float)`
= Replaced the float return statement with an Angle in `ArcTan(float)`
= Replaced the float return statement with an Angle in `ArcTan2(float, float)`
= Optimized `ArcCos(float)` to use presets
= Optimized `Divide(float, params float[])` to use other functions.
= Optimized `Divide(int, params int[])` to use other functions.
= Optimized `Subtract(float, params float[])` to subtract a sum instead of individually subtracting
= Optimized `Subtract(int, params int[])` to subtract a sum instead of individually subtracting
= Made `Clamp(int, int, int)` not remake code and use `Clamp(float, float, float)`
= Made `Lerp(int, int, float, bool)` cast to an int instead of flooring
= Made `Lerp(float, float, float, bool)` not break when clamping and A is greater than B
= Made `Median<T>(params T[])` not use an unneccesary average
= Made `Power(int, int)` not care about absolutes
= Made `Variance(params float[])` correctly calculate variance.
* Quaternion
= Made `GetAngle()` not create an angle out of `ArcCos(float)`, as it already is one
= Made `ToAngles()` not create angles out of arc trig functions, as they are already angles
* Samples
* Constants
= Swapped `DegToRad` and `RadToDeg`
* Equations
= Moved `static Scale(Equation, float, ScaleType)` to `EquationExtension`
= Moved `ScaleType` to `EquationExtension`
+ operator *(Float3, Quaternion)
= Fixed `ToVector()`
```

4
Nerd_STF/.editorconfig Normal file
View File

@ -0,0 +1,4 @@
[*.cs]
# CA1050: Declare types in namespaces
dotnet_diagnostic.CA1050.severity = warning

View File

@ -5,20 +5,20 @@ public static class Container2DExtension
public static T[] Flatten<T>(this T[,] array, Int2 size)
{
T[] res = new T[size.x * size.y];
for (int x = 0; x < size.x; x++) for (int y = 0; y < size.y; y++) res[x + y * size.y] = array[x, y];
for (int x = 0; x < size.x; x++) for (int y = 0; y < size.y; y++) res[x + y * size.x] = array[y, x];
return res;
}
public static T[] GetColumn<T>(this T[,] array, int column, int length)
{
T[] res = new T[length];
for (int i = 0; i < length; i++) res[i] = array[column, i];
for (int i = 0; i < length; i++) res[i] = array[i, column];
return res;
}
public static T[] GetRow<T>(this T[,] array, int row, int length)
{
T[] res = new T[length];
for (int i = 0; i < length; i++) res[i] = array[i, row];
for (int i = 0; i < length; i++) res[i] = array[row, i];
return res;
}
}

View File

@ -10,4 +10,8 @@ public static class ConversionExtension
foreach (KeyValuePair<TKey, TValue> pair in pairs) res.Add(pair.Key, pair.Value);
return res;
}
public static Fill<T> ToFill<T>(this T[] arr) => i => arr[i];
public static Fill<T> ToFill<T>(this T[,] arr, Int2 size) => arr.Flatten(size).ToFill();
public static Fill2D<T> ToFill2D<T>(this T[,] arr) => (x, y) => arr[x, y];
}

View File

@ -4,16 +4,9 @@ public static class EquationExtension
{
public static Equation Scale(this Equation equ, float value, ScaleType type = ScaleType.Both) => type switch
{
ScaleType.X => x => equ(value / x),
ScaleType.Y => x => x * equ(value),
ScaleType.Both => x => x * equ(value / x),
ScaleType.X => x => equ(x / value),
ScaleType.Y => x => value * equ(x),
ScaleType.Both => x => value * equ(x / value),
_ => throw new ArgumentException("Unknown scale type " + type)
};
public enum ScaleType
{
X = 1,
Y = 2,
Both = X | Y
}
}

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Graphics;
public struct CMYKA : IColor, IEquatable<CMYKA>
public struct CMYKA : IColorFloat, IEquatable<CMYKA>
{
public static CMYKA Black => new(0, 0, 0, 1);
public static CMYKA Blue => new(1, 1, 0, 0);
@ -165,7 +165,7 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
return (Cs, Ms, Ys, Ks, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKA());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKA());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKA());
public bool Equals(CMYKA col) => A == 0 && col.A == 0 || K == 1 && col.K == 1 || C == col.C && M == col.M
&& Y == col.Y && K == col.K && A == col.A;
@ -174,9 +174,9 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(CMYKA)) return Equals((CMYKA)obj);
else if (t == typeof(RGBA)) return Equals((IColor)obj);
else if (t == typeof(HSVA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
@ -196,7 +196,7 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
public RGBA ToRGBA()
{
float kInv = 1 - K, r = 1 - C, g = 1 - M, b = 1 - Y;
return new(r * kInv, g * kInv, b * kInv);
return new(r * kInv, g * kInv, b * kInv, A);
}
public CMYKA ToCMYKA() => this;
public HSVA ToHSVA() => ToRGBA().ToHSVA();

View File

@ -143,7 +143,7 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
return (Cs, Ms, Ys, Ks, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKAByte());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKAByte());
public bool Equals(CMYKAByte col) => A == 0 && col.A == 0 || K == 1 && col.K == 255 || C == col.C && M == col.M
&& Y == col.Y && K == col.K && A == col.A;
@ -152,11 +152,11 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(CMYKAByte)) return Equals((CMYKAByte)obj);
else if (t == typeof(RGBA)) return Equals((IColor)obj);
else if (t == typeof(HSVA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
@ -174,11 +174,11 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
public RGBA ToRGBA() => ToCMYKA().ToRGBA();
public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f);
public HSVA ToHSVA() => ToRGBA().ToHSVA();
public HSVA ToHSVA() => ToCMYKA().ToHSVA();
public RGBAByte ToRGBAByte() => ToCMYKA().ToRGBAByte();
public CMYKAByte ToCMYKAByte() => this;
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
public HSVAByte ToHSVAByte() => ToCMYKA().ToHSVAByte();
public byte[] ToArray() => new[] { C, M, Y, K, A };
public Fill<byte> ToFill()
@ -216,12 +216,12 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
public static CMYKAByte operator /(CMYKAByte a, int b) =>
new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / b);
public static CMYKAByte operator /(CMYKAByte a, float b) => (a.ToCMYKA() / b).ToCMYKAByte();
public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColor?)b);
public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColor?)b);
public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColor?)b);
public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColor?)b);
public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColor?)b);
public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColor?)b);
public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(CMYKAByte a, RGBAByte b) => a.Equals(b);
public static bool operator !=(CMYKAByte a, RGBAByte b) => !a.Equals(b);
public static bool operator ==(CMYKAByte a, CMYKAByte b) => a.Equals(b);

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Graphics;
public struct HSVA : IColor, IEquatable<HSVA>
public struct HSVA : IColorFloat, IEquatable<HSVA>
{
public static HSVA Black => new(Angle.Zero, 0, 0);
public static HSVA Blue => new(new Angle(240), 1, 1);
@ -159,7 +159,7 @@ public struct HSVA : IColor, IEquatable<HSVA>
return (Hs, Ss, Vs, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToHSVA());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVA());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVA());
public bool Equals(HSVA col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0
|| H == col.H && S == col.S && V == col.V && A == col.A;
@ -168,9 +168,9 @@ public struct HSVA : IColor, IEquatable<HSVA>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(HSVA)) return Equals((HSVA)obj);
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
else if (t == typeof(RGBA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
@ -195,7 +195,7 @@ public struct HSVA : IColor, IEquatable<HSVA>
else if (d < 240) vals = (0, x, c);
else if (d < 300) vals = (x, 0, c);
else if (d < 360) vals = (c, 0, x);
return new(vals.r + m, vals.g + m, vals.b + m);
return new(vals.r + m, vals.g + m, vals.b + m, A);
}
public CMYKA ToCMYKA() => ToRGBA().ToCMYKA();
public HSVA ToHSVA() => this;

View File

@ -130,7 +130,7 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
return (Hs, Ss, Vs, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToHSVAByte());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVAByte());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVAByte());
public bool Equals(HSVAByte col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0
|| H == col.H && S == col.S && V == col.V && A == col.A;
@ -139,12 +139,12 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(HSVAByte)) return Equals((HSVAByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
else if (t == typeof(RGBA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVA)) return Equals((IColor)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
@ -192,12 +192,12 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
public static HSVAByte operator /(HSVAByte a, HSVAByte b) => new(a.H / b.H, a.S / b.S, a.V / b.V, a.A / b.A);
public static HSVAByte operator /(HSVAByte a, int b) => new(a.H / b, a.S / b, a.V / b, a.A / b);
public static HSVAByte operator /(HSVAByte a, float b) => (a.ToHSVA() * b).ToHSVAByte();
public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColor?)b);
public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColor?)b);
public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColor?)b);
public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColor?)b);
public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColor?)b);
public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColor?)b);
public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(HSVAByte a, RGBAByte b) => a.Equals(b);
public static bool operator !=(HSVAByte a, RGBAByte b) => !a.Equals(b);
public static bool operator ==(HSVAByte a, CMYKAByte b) => a.Equals(b);

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Graphics;
public interface IColor : ICloneable, IEquatable<IColor?>, IEquatable<IColorByte?>, IGroup<float>
public interface IColor : ICloneable, IEquatable<IColorFloat?>, IEquatable<IColorByte?>
{
public RGBA ToRGBA();
public CMYKA ToCMYKA();

View File

@ -1,12 +1,3 @@
namespace Nerd_STF.Graphics;
public interface IColorByte : ICloneable, IEquatable<IColor?>, IEquatable<IColorByte?>, IGroup<byte>
{
public RGBA ToRGBA();
public CMYKA ToCMYKA();
public HSVA ToHSVA();
public RGBAByte ToRGBAByte();
public CMYKAByte ToCMYKAByte();
public HSVAByte ToHSVAByte();
}
public interface IColorByte : IColor, IGroup<byte> { }

View File

@ -0,0 +1,3 @@
namespace Nerd_STF.Graphics;
public interface IColorFloat : IColor, IGroup<float> { }

View File

@ -15,12 +15,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
{
Pixels = new IColor[width, height];
Size = new(width, height);
for (int y = 0; y < width; y++) for (int x = 0; x < height; x++) Pixels[x, y] = cols[y * width + x];
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y * width + x];
}
public Image(int width, int height, IColor[,] cols)
{
Pixels = cols;
Pixels = new IColor[width, height];
Size = new(width, height);
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y, x];
}
public Image(int width, int height, Fill<IColor> fill)
{
@ -32,28 +33,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
{
Pixels = new IColor[width, height];
Size = new(width, height);
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(x, y);
}
public Image(int width, int height, Fill<IColorByte> fill)
{
Pixels = new IColor[width, height];
Size = new(width, height);
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++)
Pixels[x, y] = (IColor)fill(y * width + x);
}
public Image(int width, int height, Fill2D<IColorByte> fill)
{
Pixels = new IColor[width, height];
Size = new(width, height);
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = (IColor)fill(x, y);
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(y, x);
}
public Image(Int2 size) : this(size.x, size.y) { }
public Image(Int2 size, IColor[] cols) : this(size.x, size.y, cols) { }
public Image(Int2 size, IColor[,] cols) : this(size.x, size.y, cols) { }
public Image(Int2 size, Fill<IColor> fill) : this(size.x, size.y, fill) { }
public Image(Int2 size, Fill2D<IColor> fill) : this(size.x, size.y, fill) { }
public Image(Int2 size, Fill<IColorByte> fill) : this(size.x, size.y, fill) { }
public Image(Int2 size, Fill2D<IColorByte> fill) : this(size.x, size.y, fill) { }
public IColor this[int indexX, int indexY]
{
@ -124,7 +110,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
for (int y = 0; y < Size.y; y++) for (int x = 0; x < Size.x; x++)
{
HSVA col = Pixels[x, y].ToHSVA();
col.S = (set ? 0 : col.S) + value;
col.S = (set ? 0 : col.S) * value;
Pixels[x, y] = col;
}
}
@ -144,7 +130,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
for (int y = 0; y < newSize.y; y++) for (int x = 0; x < newSize.x; x++)
{
Float2 f = new((float)x / newSize.x, (float)y / newSize.y);
RGBA col = Pixels[Mathf.RoundInt(f.x * Size.x), Mathf.RoundInt(f.y * Size.y)].ToRGBA();
RGBA col = Pixels[Mathf.Floor(f.x * Size.x), Mathf.Floor(f.y * Size.y)].ToRGBA();
img[x, y] = col;
}
this = img;

View File

@ -5,17 +5,17 @@ public struct Material : ICloneable, IEquatable<Material>
public float Alpha;
public float Anisotropy;
public float AnisotropyRoughness;
public IColor AmbientColor;
public IColorFloat AmbientColor;
public float ClearcoatRoughness;
public float ClearcoatThickness;
public IColor DiffuseColor;
public IColor Emissive;
public IColorFloat DiffuseColor;
public IColorFloat Emissive;
public IlluminationModel IllumModel;
public float Metallic;
public float OpticalDensity;
public float Roughness;
public float Sheen;
public IColor SpecularColor;
public IColorFloat SpecularColor;
public float SpecularExponent;
public (Image Image, TextureConfig Config) AlphaTexture;
@ -67,17 +67,17 @@ public struct Material : ICloneable, IEquatable<Material>
Alpha = (float)fill(0);
Anisotropy = (float)fill(1);
AnisotropyRoughness = (float)fill(2);
AmbientColor = (IColor)fill(3);
AmbientColor = (IColorFloat)fill(3);
ClearcoatRoughness = (float)fill(4);
ClearcoatThickness = (float)fill(5);
DiffuseColor = (IColor)fill(6);
Emissive = (IColor)fill(7);
DiffuseColor = (IColorFloat)fill(6);
Emissive = (IColorFloat)fill(7);
IllumModel = (IlluminationModel)fill(8);
Metallic = (float)fill(9);
OpticalDensity = (float)fill(10);
Roughness = (float)fill(11);
Sheen = (float)fill(12);
SpecularColor = (IColor)fill(13);
SpecularColor = (IColorFloat)fill(13);
SpecularExponent = (float)fill(14);
AlphaTexture = ((Image, TextureConfig))fill(15);
@ -93,7 +93,7 @@ public struct Material : ICloneable, IEquatable<Material>
SpecularHighlightTexture = ((Image, TextureConfig))fill(25);
StencilTexture = ((Image, TextureConfig))fill(26);
}
public Material(IlluminationModel illum, Fill<float> floats, Fill<IColor> colors, Fill<(Image, TextureConfig)> images)
public Material(IlluminationModel illum, Fill<float> floats, Fill<IColorFloat> colors, Fill<(Image, TextureConfig)> images)
{
Alpha = floats(0);
Anisotropy = floats(1);

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Graphics;
public struct RGBA : IColor, IEquatable<RGBA>
public struct RGBA : IColorFloat, IEquatable<RGBA>
{
public static RGBA Black => new(0, 0, 0);
public static RGBA Blue => new(0, 0, 1);
@ -149,7 +149,7 @@ public struct RGBA : IColor, IEquatable<RGBA>
return (Rs, Gs, Bs, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToRGBA());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBA());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBA());
public bool Equals(RGBA col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj)
@ -157,9 +157,9 @@ public struct RGBA : IColor, IEquatable<RGBA>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(RGBA)) return Equals((RGBA)obj);
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
else if (t == typeof(HSVA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);

View File

@ -132,7 +132,7 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
return (Rs, Gs, Bs, As);
}
public bool Equals(IColor? col) => col != null && Equals(col.ToRGBAByte());
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBAByte());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBAByte());
public bool Equals(RGBAByte col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj)
@ -140,9 +140,9 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(RGBAByte)) return Equals((RGBAByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
else if (t == typeof(HSVA)) return Equals((IColor)obj);
else if (t == typeof(IColor)) return Equals((IColor)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
@ -195,12 +195,12 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
public static RGBAByte operator /(RGBAByte a, RGBAByte b) => new(a.R / b.R, a.G / b.G, a.B / b.B, a.A / b.A);
public static RGBAByte operator /(RGBAByte a, int b) => new(a.R / b, a.G / b, a.B / b, a.A / b);
public static RGBAByte operator /(RGBAByte a, float b) => (a.ToRGBA() / b).ToRGBAByte();
public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColor?)b);
public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColor?)b);
public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColor?)b);
public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColor?)b);
public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColor?)b);
public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColor?)b);
public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColorFloat?)b);
public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColorFloat?)b);
public static bool operator ==(RGBAByte a, RGBAByte b) => a.Equals(b);
public static bool operator !=(RGBAByte a, RGBAByte b) => !a.Equals(b);
public static bool operator ==(RGBAByte a, CMYKAByte b) => a.Equals(b);

View File

@ -107,7 +107,7 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
public bool Equals(Vector2d other) => theta == other.theta && magnitude == other.magnitude;
public override int GetHashCode() => theta.GetHashCode() ^ magnitude.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(Angle.Type outputType = Angle.Type.Degrees) => ToString((string?)null, outputType);
public string ToString(Angle.Type outputType) => ToString((string?)null, outputType);
public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) =>
"Mag: " + magnitude.ToString(provider) + " Rot: " + theta.ToString(provider, outputType);
public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) =>

View File

@ -145,15 +145,20 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
public bool Equals(Vector3d other) => yaw == other.yaw && pitch == other.pitch
&& magnitude == other.magnitude;
public override int GetHashCode() => yaw.GetHashCode() ^ pitch.GetHashCode() ^ magnitude.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(Angle.Type outputType) => ToString((string?)null, outputType);
public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) =>
"Mag: " + magnitude.ToString(provider) + " Theta: " + yaw.ToString(provider, outputType) +
" Phi: " + pitch.ToString(provider, outputType);
"Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) +
" Pitch: " + pitch.ToString(provider, outputType);
public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) =>
"Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) +
" Pitch: " + pitch.ToString(provider, outputType);
public object Clone() => new Vector3d(yaw, pitch, magnitude);
public Float3 ToXYZ() => new(Mathf.Sin(pitch) * Mathf.Cos(yaw) * magnitude,
Mathf.Sin(pitch) * Mathf.Sin(yaw) * magnitude,
Mathf.Cos(pitch) * magnitude);
public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw),
Mathf.Cos(yaw),
Mathf.Cos(pitch) * Mathf.Sin(yaw)) * magnitude;
public static Vector3d operator +(Vector3d a, Vector3d b) => new(a.yaw + b.yaw, a.pitch + b.pitch,
a.magnitude + b.magnitude);

View File

@ -35,6 +35,8 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
}
public Angle Bounded => new(Mathf.AbsoluteMod(p_deg, 360));
public Angle Complimentary => Quarter - this;
public Angle Supplementary => Half - this;
public Angle Reflected => new Angle(-p_deg).Bounded;
private float p_deg;

View File

@ -174,6 +174,7 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
public static Float2 operator *(Float2 a, Float2 b) => new(a.x * b.x, a.y * b.y);
public static Float2 operator *(Float2 a, float b) => new(a.x * b, a.y * b);
public static Float2 operator *(Float2 a, Matrix b) => (Float2)((Matrix)a * b);
public static Quaternion operator *(Float2 a, Quaternion b) => (Quaternion)a * b;
public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y);
public static Float2 operator /(Float2 a, float b) => new(a.x / b, a.y / b);
public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b);

View File

@ -191,7 +191,10 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
public Vector3d ToVector()
{
float mag = Magnitude;
return new(Mathf.ArcTan(y / x), Mathf.ArcCos(z / mag), mag);
Float3 normalized = Normalized;
Angle yaw = Mathf.ArcCos(normalized.y);
Angle pitch = Mathf.ArcSin(normalized.x / Mathf.Sin(yaw));
return new(yaw, pitch, mag);
}
public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
@ -200,6 +203,7 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
public static Float3 operator *(Float3 a, Float3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
public static Float3 operator *(Float3 a, float b) => new(a.x * b, a.y * b, a.z * b);
public static Float3 operator *(Float3 a, Matrix b) => (Float3)((Matrix)a * b);
public static Quaternion operator *(Float3 a, Quaternion b) => (Quaternion)a * b;
public static Float3 operator /(Float3 a, Float3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
public static Float3 operator /(Float3 a, float b) => new(a.x / b, a.y / b, a.z / b);
public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b);

View File

@ -8,6 +8,12 @@ public interface ITriangulatable
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
return res.ToArray();
}
public static Triangle[] TriangulateAll<T>(params T[] triangulatables) where T : ITriangulatable
{
List<Triangle> res = new();
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
return res.ToArray();
}
public Triangle[] Triangulate();
}

View File

@ -170,6 +170,7 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
public static Complex operator /(Complex a, Complex b) => a * b.Inverse;
public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b);
public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b);
public static Complex operator ~(Complex v) => v.Conjugate;
public static bool operator ==(Complex a, Complex b) => a.Equals(b);
public static bool operator !=(Complex a, Complex b) => !a.Equals(b);
public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0;

View File

@ -14,12 +14,21 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
public static Quaternion One => new(1, 1, 1, 1);
public static Quaternion Zero => new(0, 0, 0, 0);
public Quaternion Conjugate => new(u, -i, -j, -k);
public Quaternion Conjugate => new(u, -IJK);
public Quaternion Inverse => Conjugate / (u * u + i * i + j * j + k * k);
public float Magnitude => Mathf.Sqrt(u * u + i * i + j * j + k * k);
public Quaternion Normalized => this * Mathf.InverseSqrt(u * u + i * i + j * j + k * k);
public Float3 IJK => new(i, j, k);
public Float3 IJK
{
get => new(i, j, k);
set
{
i = value.x;
j = value.y;
k = value.z;
}
}
public float u, i, j, k;
@ -136,27 +145,31 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
return Float4.Sum(floats.ToArray());
}
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public static Quaternion FromAngles(Angle yaw, Angle pitch, Angle? roll = null)
{
roll ??= Angle.Zero;
float cosYaw = Mathf.Cos(yaw), cosPitch = Mathf.Cos(pitch), cosRoll = Mathf.Cos(roll.Value),
sinYaw = Mathf.Sin(yaw), sinPitch = Mathf.Sin(pitch), sinRoll = Mathf.Sin(roll.Value);
float cosYaw, cosPitch, cosRoll, sinYaw, sinPitch, sinRoll,
cosYawCosPitch, sinYawSinPitch, cosYawSinPitch, sinYawCosPitch;
float cosYawCosPitch = cosYaw * cosPitch,
cosYawSinPitch = cosYaw * sinPitch,
sinYawCosPitch = sinYaw * cosPitch,
sinYawSinPitch = sinYaw * sinPitch;
cosYaw = Mathf.Cos(yaw * 0.5f);
cosPitch = Mathf.Cos(pitch * 0.5f);
cosRoll = Mathf.Cos(roll.Value * 0.5f);
sinYaw = Mathf.Sin(yaw * 0.5f);
sinPitch = Mathf.Sin(pitch * 0.5f);
sinRoll = Mathf.Sin(roll.Value * 0.5f);
cosYawCosPitch = cosYaw * cosPitch;
sinYawSinPitch = sinYaw * sinPitch;
cosYawSinPitch = cosYaw * sinPitch;
sinYawCosPitch = sinYaw * cosPitch;
return new(cosYawCosPitch * cosRoll + sinYawSinPitch * sinRoll,
cosYawCosPitch * sinRoll + sinYawSinPitch * cosRoll,
cosYawCosPitch * sinRoll - sinYawSinPitch * cosRoll,
cosYawSinPitch * cosRoll + sinYawCosPitch * sinRoll,
sinYawCosPitch * cosRoll + cosYawSinPitch * sinRoll);
sinYawCosPitch * cosRoll - cosYawSinPitch * sinRoll);
}
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public static Quaternion FromAngles(Float3 vals, Angle.Type valType) =>
FromAngles(new(vals.x, valType), new(vals.y, valType), new(vals.z, valType));
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public static Quaternion FromVector(Vector3d vec) => FromAngles(vec.yaw, vec.pitch);
public static (float[] Us, float[] Is, float[] Js, float[] Ks) SplitArray(params Quaternion[] vals)
@ -193,18 +206,8 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
public object Clone() => new Quaternion(u, i, j, k);
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public Angle GetAngle() => Mathf.ArcCos(u) * 2;
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public Float3 GetAxis()
{
Float3 axis = IJK;
float mag = Magnitude;
if (mag < 0) return Float3.Zero;
return axis / mag;
}
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public Float3 GetAxis() => IJK.Normalized;
public (Angle yaw, Angle pitch, Angle roll) ToAngles()
{
Quaternion doubled = this;
@ -213,42 +216,47 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
doubled.j *= j;
doubled.k *= k;
Matrix3x3 rotMatrix = new(new[,]
Matrix3x3 rot = new(new[,]
{
{ doubled.u + doubled.i - doubled.j - doubled.k, 0, 0 },
{ 2 * (i * j + u * k), 0, 0 },
{ 2 * (i * k + u * j), 2 * (j * k + u * i), doubled.u - doubled.i - doubled.j + doubled.k }
{ u * u + i * i - j * j - k * k, 2 * i * j + 2 * k * u, 2 * i * k - 2 * j * u },
{ 2 * i * j - 2 * k * u, u * u - i * i + j * j - k * k, 2 * j * k + 2 * i * u },
{ 2 * k * i + 2 * j * u, 2 * k * j - 2 * i * u, u * u - i * i - j * j + k * k }
});
Angle yaw, pitch, roll;
float r3c1Abs = Mathf.Absolute(rotMatrix.r3c1);
if (r3c1Abs >= 1)
float absr3c1 = Mathf.Absolute(rot.r3c1);
if (absr3c1 >= 1)
{
rotMatrix.r1c2 = 2 * (i * j - u * k);
rotMatrix.r1c3 = 2 * (i * k + u * j);
yaw = Mathf.ArcTan2(-rotMatrix.r1c2, -rotMatrix.r3c1 * rotMatrix.r1c3);
pitch = new(-Constants.HalfPi * rotMatrix.r3c1 / r3c1Abs, Angle.Type.Radians);
yaw = Mathf.ArcTan2(-rot.r1c2, -rot.r3c1 * rot.r1c3);
pitch = new(-Constants.HalfPi * rot.r3c1 / absr3c1, Angle.Type.Radians);
roll = Angle.Zero;
}
else
{
yaw = Mathf.ArcTan2(rotMatrix.r2c1, rotMatrix.r1c1);
pitch = Mathf.ArcSin(-rotMatrix.r3c1);
roll = Mathf.ArcTan2(rotMatrix.r3c2, rotMatrix.r3c3);
yaw = Mathf.ArcTan2(rot.r2c1, rot.r1c1);
pitch = Mathf.ArcSin(-rot.r3c1);
roll = Mathf.ArcTan2(rot.r3c2, rot.r3c3);
}
return (yaw, pitch, roll);
}
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
public Vector3d ToVector()
public Float3 ToAnglesFloat3(Angle.Type type = Angle.Type.Degrees)
{
(Angle yaw, Angle pitch, _) = ToAngles();
return new(yaw, pitch);
(Angle yaw, Angle pitch, Angle roll) = ToAngles();
return new(yaw.ValueFromType(type), pitch.ValueFromType(type), roll.ValueFromType(type));
}
public Quaternion Rotate(Quaternion other) => other * this * other.Conjugate;
public Quaternion Rotate(Quaternion other) => this * other * Conjugate;
public Float3 Rotate(Float3 other)
{
const float tolerance = 0.001f;
Quaternion res = this * other * Conjugate;
if (Mathf.Absolute(res.u) > tolerance)
throw new MathException("A rotated vector should never have non-zero scalar part.");
return res.IJK;
}
public Vector3d Rotate(Vector3d other) => Rotate(other.ToXYZ()).ToVector();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator()
@ -275,7 +283,7 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
float a = x.u, b = x.i, c = x.j, d = x.k, e = y.u, f = y.i, g = y.j, h = y.k,
u = a * e - b * f - c * g - d * h,
i = a * f + b * e + c * h - d * g,
j = a * g + c * e + b * h - d * f,
j = a * g - b * h + c * e + d * f,
k = a * h + b * g + d * e - c * f;
return new(u, i, j, k);
}
@ -286,6 +294,7 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
public static Quaternion operator /(Quaternion a, float b) => new(a.u / b, a.i / b, a.j / b, a.k / b);
public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b);
public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b);
public static Quaternion operator ~(Quaternion v) => v.Conjugate;
public static bool operator ==(Quaternion a, Quaternion b) => a.Equals(b);
public static bool operator !=(Quaternion a, Quaternion b) => !a.Equals(b);
public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0;

46
Nerd_STF/Nerd_STF.csproj Normal file
View File

@ -0,0 +1,46 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<RootNamespace>Nerd_STF</RootNamespace>
<AssemblyName>Nerd_STF</AssemblyName>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>That_One_Nerd</Authors>
<Description>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.</Description>
<Copyright>Copyright (c) 2022 That_One_Nerd</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/That-One-Nerd/Nerd_STF</RepositoryUrl>
<AssemblyVersion>2.3.1.52</AssemblyVersion>
<PackageTags>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</PackageTags>
<Version>2.3.1.52-alpha</Version>
<Product>Nerd_STF</Product>
<PackageId>Nerd_STF</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo Square0001.png</PackageIcon>
<PackageReleaseNotes>The `v2.3.1.x` updates go through every single field and method in Nerd_STF to make sure it works correctly.</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>
<GenerateDocumentationFile>False</GenerateDocumentationFile>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\..\..\Nerd_STF\Icons\Logo Square0001.png">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup>
</Project>

36
Nerd_STF/Nerd_STF.sln Normal file
View File

@ -0,0 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerd_STF", "Nerd_STF.csproj", "{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Testing", "..\Testing\Testing.csproj", "{53E8335D-AE54-4E34-A692-136786788DD6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FBAFC98C-AC9E-4E76-A6E7-8F4DB1B23BED}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1F2C87DB-56F2-48B7-8FF6-A12D8E3614DB}.Release|Any CPU.Build.0 = Release|Any CPU
{53E8335D-AE54-4E34-A692-136786788DD6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{53E8335D-AE54-4E34-A692-136786788DD6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{53E8335D-AE54-4E34-A692-136786788DD6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{53E8335D-AE54-4E34-A692-136786788DD6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {81A13C28-98B5-49F8-9141-C4A62EE8729F}
EndGlobalSection
EndGlobal

8
Nerd_STF/ScaleType.cs Normal file
View File

@ -0,0 +1,8 @@
namespace Nerd_STF;
public enum ScaleType
{
X = 1,
Y = 2,
Both = X | Y
}