Version 2.3.0 has been released.
More to come in the rest of 2.3!
This commit is contained in:
parent
494d3b2581
commit
e06a49c634
6
.gitignore
vendored
6
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
# Visual Studio stuff
|
||||
*.sln
|
||||
*.csproj
|
||||
*.editorconfig
|
||||
*.sln
|
||||
/Nerd_STF/.vs/
|
||||
/Nerd_STF/obj
|
||||
/Nerd_STF/bin/Debug
|
||||
@ -8,6 +9,9 @@
|
||||
/Nerd_STF/bin/Release/net6.0/Nerd_STF.dll
|
||||
/Nerd_STF/bin/Release/net6.0/Nerd_STF.pdb
|
||||
|
||||
# Testing project
|
||||
/Testing
|
||||
|
||||
# Nuget
|
||||
/Nerd_STF/LICENSE
|
||||
*.nupkg
|
||||
|
||||
259
Changelog.md
259
Changelog.md
@ -1,124 +1,173 @@
|
||||
# Nerd_STF v2.2.0
|
||||
# Nerd_STF v2.3.0
|
||||
|
||||
This update adds many types of graphics-based objects, as well as some math functions and constants.
|
||||
This update adds lots of linear algebra tools, like matrixes and vectors, as well as new number systems, like complex numbers and quaternions.
|
||||
|
||||
```
|
||||
* Nerd_STF
|
||||
+ delegate Fill2D<T>(int, int)
|
||||
+ Extensions
|
||||
+ ConversionExtension
|
||||
+ Container2DExtension
|
||||
+ ToFillExtension
|
||||
+ Foreach
|
||||
+ IGroup2D
|
||||
+ Modifier
|
||||
+ Modifier2D
|
||||
* IGroup<T>
|
||||
+ ToFill()
|
||||
* Exceptions
|
||||
+ FileParsingException
|
||||
+ FileType
|
||||
+ Graphics
|
||||
+ ColorChannel
|
||||
+ CMYKA
|
||||
+ CMYKAByte
|
||||
+ HSVA
|
||||
+ HSVAByte
|
||||
+ IColor
|
||||
+ IColorByte
|
||||
+ IlluminationFlags
|
||||
+ IlluminationModel
|
||||
+ Image
|
||||
+ Material
|
||||
+ RGBA
|
||||
+ RGBAByte
|
||||
+ InvalidSizeException
|
||||
+ NoInverseException
|
||||
* Graphics
|
||||
* CMYKA
|
||||
+ ToFill()
|
||||
+ static Round(CMYKA)
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* CMYKAByte
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* HSVA
|
||||
+ ToFill()
|
||||
+ static Round(HSVA, Angle.Type)
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* HSVAByte
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Image
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Material
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
= Merged 2 if statements into 1 in `override bool Equals(object?)`
|
||||
* RGBA
|
||||
+ ToFill()
|
||||
+ ToVector()
|
||||
+ static Round(RGBA)
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* RGBAByte
|
||||
+ ToFill()
|
||||
+ ToVector()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Mathematics
|
||||
* Angle
|
||||
+ Normalized
|
||||
= Made fancier `ToString()` formatting
|
||||
* Type
|
||||
+ Normalized
|
||||
+ Constants
|
||||
* Float2
|
||||
+ static SplitArray(params Float2[])
|
||||
= Renamed `static Multiply(params Float2[])` to `Product`
|
||||
* Float3
|
||||
+ static SplitArray(params Float3[])
|
||||
+ explicit operator Float3(RGBA)
|
||||
+ explicit operator Float3(HSVA)
|
||||
+ explicit operator Float3(RGBAByte)
|
||||
+ explicit operator Float3(HSVAByte)
|
||||
= Renamed `static Multiply(params Float3[])` to `Product`
|
||||
* Float4
|
||||
+ static SplitArray(params Float4[])
|
||||
+ implicit operator Float4(RGBA)
|
||||
+ explicit operator Float4(CMYKA)
|
||||
+ implicit operator Float4(HSVA)
|
||||
+ implicit operator Float4(RGBAByte)
|
||||
+ explicit operator Float4(CMYKAByte)
|
||||
+ implicit operator Float4(HSVAByte)
|
||||
= Renamed `static Multiply(params Float4[])` to `Product`
|
||||
+ Algebra
|
||||
+ IMatrix
|
||||
+ Matrix2x2
|
||||
+ Matrix3x3
|
||||
+ Matrix4x4
|
||||
+ Vector2d
|
||||
+ Vector3d
|
||||
+ NumberSystems
|
||||
+ Complex
|
||||
+ Quaternion
|
||||
+ Samples
|
||||
+ Equations
|
||||
+ ScaleType
|
||||
= Moved `Constants` file to Samples folder.
|
||||
* Geometry
|
||||
* Box2D
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Box3D
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Line
|
||||
+ Midpoint
|
||||
= Renamed `ToDoubleArray()` to `ToFloatArray`
|
||||
= Renamed `ToDoubleList()` to `ToFloatList`
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Polygon
|
||||
+ Midpoint
|
||||
= Renamed `ToDoubleArray()` to `ToFloatArray`
|
||||
= Renamed `ToDoubleList()` to `ToFloatList`
|
||||
= Renamed `static ToDoubleArrayAll(params Triangle[])` to `ToFloatArrayAll`
|
||||
= Renamed `static ToDoubleListAll(params Triangle[])` to `ToFloatListAll`
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Quadrilateral
|
||||
+ Midpoint
|
||||
= Renamed `ToDoubleArray()` to `ToFloatArray`
|
||||
= Renamed `ToDoubleList()` to `ToFloatList`
|
||||
= Renamed `static ToDoubleArrayAll(params Triangle[])` to `ToFloatArrayAll`
|
||||
= Renamed `static ToDoubleListAll(params Triangle[])` to `ToFloatListAll`
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Sphere
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Triangle
|
||||
+ Midpoint
|
||||
= Renamed `ToDoubleArray()` to `ToFloatArray`
|
||||
= Renamed `ToDoubleList()` to `ToFloatList`
|
||||
= Renamed `static ToDoubleArrayAll(params Triangle[])` to `ToFloatArrayAll`
|
||||
= Renamed `static ToDoubleListAll(params Triangle[])` to `ToFloatListAll`
|
||||
+ ToFill()
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Vert
|
||||
= Renamed `static ToDouble3Array(params Vert[])` to `ToFloat3Array`
|
||||
= Renamed `static ToDouble3List(params Vert[])` to `ToFloat3List`
|
||||
+ ToFill()
|
||||
+ ToVector()
|
||||
= Made `Vert(Float2)` not recreate a float group, and instead use itself.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Angle
|
||||
+ static Down
|
||||
+ static Left
|
||||
+ static Right
|
||||
+ static Up
|
||||
+ static Round(Angle, Type)
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Float2
|
||||
+ ToFill()
|
||||
+ ToVector()
|
||||
+ static Round(Float2)
|
||||
+ implicit operator Float2(Complex)
|
||||
+ explicit operator Float2(Quaternion)
|
||||
+ explicit operator Float2(Matrix)
|
||||
+ operator *(Float2, Matrix)
|
||||
+ operator /(Float2, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Float3
|
||||
+ ToFill()
|
||||
+ ToVector()
|
||||
+ static Round(Float3)
|
||||
+ implicit operator Float3(Complex)
|
||||
+ explicit operator Float3(Quaternion)
|
||||
+ explicit operator Float3(Matrix)
|
||||
+ operator *(Float3, Matrix)
|
||||
+ operator /(Float3, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Float4
|
||||
+ ToFill()
|
||||
+ static Round(Float4)
|
||||
+ implicit operator Float4(Complex)
|
||||
+ implicit operator Float4(Quaternion)
|
||||
+ explicit operator Float4(Matrix)
|
||||
+ operator *(Float4, Matrix)
|
||||
+ operator /(Float4, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
= Renamed `Float4.Deep` to `Float4.Near`
|
||||
* Int2
|
||||
+ static SplitArray(params Int[])
|
||||
= Renamed `static Multiply(params Int2[])` to `Product`
|
||||
+ ToFill()
|
||||
+ explicit operator Int2(Complex)
|
||||
+ explicit operator Int2(Quaternion)
|
||||
+ explicit operator Int2(Matrix)
|
||||
+ operator *(Int2, Matrix)
|
||||
+ operator /(Int2, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Int3
|
||||
+ static SplitArray(params Int3[])
|
||||
+ explicit operator Int3(RGBA)
|
||||
+ explicit operator Int3(HSVA)
|
||||
+ explicit operator Int3(RGBAByte)
|
||||
+ explicit operator Int3(HSVAByte)
|
||||
= Renamed `static Multiply(params Int3[])` to `Product`
|
||||
+ ToFill()
|
||||
+ explicit operator Int3(Complex)
|
||||
+ explicit operator Int3(Quaternion)
|
||||
+ explicit operator Int3(Matrix)
|
||||
+ operator *(Int3, Matrix)
|
||||
+ operator /(Int3, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Int4
|
||||
+ static SplitArray(params Int4[])
|
||||
+ explicit operator Int4(RGBA)
|
||||
+ explicit operator Int4(CMYKA)
|
||||
+ explicit operator Int4(HSVA)
|
||||
+ implicit operator Int4(RGBAByte)
|
||||
+ explicit operator Int4(CMYKAByte)
|
||||
+ implicit operator Int4(HSVAByte)
|
||||
= Renamed `static Multiply(params Int4[])` to `Product`
|
||||
+ explicit operator Int4(Complex)
|
||||
+ explicit operator Int4(Quaternion)
|
||||
+ explicit operator Int4(Matrix)
|
||||
+ operator *(Int4, Matrix)
|
||||
+ operator /(Int4, Matrix)
|
||||
= Made `Normalized` multiply by the inverse square root instead of dividing by the square root.
|
||||
= Replaced a false statement with `base.Equals(object?)` in `override bool Equals(object?)`
|
||||
* Mathf
|
||||
+ static Combinations(int, int)
|
||||
+ static GreatestCommonFactor(params int[])
|
||||
+ static InverseSqrt(float)
|
||||
+ static LeastCommonMultiple(params int[])
|
||||
+ static Mode<T>(params T[]) where T : IEquatable<T>
|
||||
+ static Permutations(int, int)
|
||||
+ static Pow(float, int)
|
||||
+ static Product(Equation, float, float, float)
|
||||
+ static Sum(Equation, float, float, float)
|
||||
+ static UniqueItems<T>(params T[]) where T : IEquatable<T>
|
||||
+ static ZScore(float, params float[])
|
||||
+ static ZScore(float, float, float)
|
||||
- const RadToDeg
|
||||
- const E
|
||||
- const GoldenRatio
|
||||
- const HalfPi
|
||||
- const Pi
|
||||
- const DegToRad
|
||||
- const Tau
|
||||
= GreatestCommonFactor actually works now
|
||||
= Pow has been fixed
|
||||
= Mode actually works
|
||||
* static Average(params int[])
|
||||
= Replaced its `int` return type with `float`
|
||||
+ Cos(Angle)
|
||||
+ Cot(Angle)
|
||||
+ Csc(Angle)
|
||||
+ Dot(float[], float[])
|
||||
+ Dot(float[][])
|
||||
+ Max<T>(T[]) where T : IComparable<T>
|
||||
+ Median<T>(T[])
|
||||
+ Min<T>(T[]) where T : IComparable<T>
|
||||
+ Sec(Angle)
|
||||
+ Sin(Angle)
|
||||
+ Tan(Angle)
|
||||
* Miscellaneous
|
||||
* GlobalUsings.cs
|
||||
+ global using Nerd_STF.Graphics;
|
||||
+ global using Nerd_STF.Collections
|
||||
+ global using Nerd_STF.Extensions
|
||||
+ global using Nerd_STF.Mathematics.Algebra
|
||||
+ global using Nerd_STF.Mathematics.NumberSystems
|
||||
+ global using Nerd_STF.Mathematics.Samples
|
||||
```
|
||||
|
||||
12
Nerd_STF/Exceptions/InvalidSizeException.cs
Normal file
12
Nerd_STF/Exceptions/InvalidSizeException.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class InvalidSizeException : Nerd_STFException
|
||||
{
|
||||
public InvalidSizeException() : this("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) { }
|
||||
}
|
||||
18
Nerd_STF/Exceptions/NoInverseException.cs
Normal file
18
Nerd_STF/Exceptions/NoInverseException.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class NoInverseException : Exception
|
||||
{
|
||||
public Matrix? Matrix;
|
||||
|
||||
public NoInverseException() : base("This matrix does not have an inverse.") { }
|
||||
public NoInverseException(string message) : base(message) { }
|
||||
public NoInverseException(string message, Exception inner) : base(message, inner) { }
|
||||
public NoInverseException(Matrix? matrix) : this() => Matrix = matrix;
|
||||
public NoInverseException(Matrix? matrix, string message) : this(message) => Matrix = matrix;
|
||||
public NoInverseException(Matrix? matrix, string message, Exception inner) : this(message, inner) =>
|
||||
Matrix = matrix;
|
||||
protected NoInverseException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
}
|
||||
24
Nerd_STF/Extensions/Container2DExtension.cs
Normal file
24
Nerd_STF/Extensions/Container2DExtension.cs
Normal file
@ -0,0 +1,24 @@
|
||||
namespace Nerd_STF.Extensions;
|
||||
|
||||
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];
|
||||
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];
|
||||
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];
|
||||
return res;
|
||||
}
|
||||
}
|
||||
13
Nerd_STF/Extensions/ConversionExtension.cs
Normal file
13
Nerd_STF/Extensions/ConversionExtension.cs
Normal file
@ -0,0 +1,13 @@
|
||||
namespace Nerd_STF.Extensions;
|
||||
|
||||
public static class ConversionExtension
|
||||
{
|
||||
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>
|
||||
(this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
|
||||
where TKey : notnull
|
||||
{
|
||||
Dictionary<TKey, TValue> res = new();
|
||||
foreach (KeyValuePair<TKey, TValue> pair in pairs) res.Add(pair.Key, pair.Value);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
6
Nerd_STF/Extensions/ToFillExtension.cs
Normal file
6
Nerd_STF/Extensions/ToFillExtension.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Extensions;
|
||||
|
||||
public static class ToFillExtension
|
||||
{
|
||||
public static Fill<T> ToFill<T>(this IEnumerable<T> group) => i => group.ElementAt(i);
|
||||
}
|
||||
4
Nerd_STF/Foreach.cs
Normal file
4
Nerd_STF/Foreach.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public delegate void Foreach(object item);
|
||||
public delegate void Foreach<T>(T item);
|
||||
@ -146,6 +146,8 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
(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)
|
||||
{
|
||||
@ -169,7 +171,7 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
&& Y == col.Y && K == col.K && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
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);
|
||||
@ -180,7 +182,7 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
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)
|
||||
@ -205,6 +207,11 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
|
||||
|
||||
public float[] ToArray() => new[] { C, M, Y, K, A };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
CMYKA @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { C, M, Y, K, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
@ -149,7 +149,7 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
&& Y == col.Y && K == col.K && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
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);
|
||||
@ -160,7 +160,7 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode()
|
||||
^ K.GetHashCode() ^ A.GetHashCode();
|
||||
@ -181,6 +181,11 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
|
||||
|
||||
public byte[] ToArray() => new[] { C, M, Y, K, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
CMYKAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { C, M, Y, K, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
@ -100,15 +100,15 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
for (int i = 0; i < vals.Length; i++) val += vals[i];
|
||||
return val / vals.Length;
|
||||
}
|
||||
public static HSVA Ceiling(HSVA val, Angle.Type type) => new(Angle.Ceiling(val.H, type), Mathf.Ceiling(val.S),
|
||||
Mathf.Ceiling(val.V), Mathf.Ceiling(val.A));
|
||||
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) => new(Angle.Floor(val.H, type), Mathf.Floor(val.S),
|
||||
Mathf.Floor(val.V), Mathf.Floor(val.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));
|
||||
@ -136,6 +136,8 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
(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)
|
||||
{
|
||||
@ -171,7 +173,7 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
|| H == col.H && S == col.S && V == col.V && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
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);
|
||||
@ -182,7 +184,7 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
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)
|
||||
@ -212,6 +214,11 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
Mathf.RoundInt(V * 255), Mathf.RoundInt(A * 255));
|
||||
|
||||
public float[] ToArray() => new[] { H.Normalized, S, V, A };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
HSVA @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { H.Normalized, S, V, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
@ -138,7 +138,7 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
|| H == col.H && S == col.S && V == col.V && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
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);
|
||||
@ -149,7 +149,7 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
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)
|
||||
@ -167,6 +167,11 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
public HSVAByte ToHSVAByte() => this;
|
||||
|
||||
public byte[] ToArray() => new[] { H, S, V, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
HSVAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { H, S, V, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
|
||||
@ -75,9 +75,9 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
public bool Equals(Image other) => Pixels == other.Pixels;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
if (obj == null) return base.Equals(obj);
|
||||
if (obj.GetType() == typeof(Image)) return Equals((Image)obj);
|
||||
return false;
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => Pixels.GetHashCode();
|
||||
|
||||
|
||||
@ -171,9 +171,8 @@ public struct Material : ICloneable, IEquatable<Material>
|
||||
SpecularHighlightTexture.Equals(other.SpecularHighlightTexture) && StencilTexture.Equals(other.StencilTexture);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
if (obj.GetType() == typeof(Material)) return Equals((Material)obj);
|
||||
return false;
|
||||
if (obj == null || obj.GetType() != typeof(Material)) return base.Equals(obj);
|
||||
return Equals((Material)obj);
|
||||
}
|
||||
public override int GetHashCode() => Alpha.GetHashCode() ^ AmbientColor.GetHashCode() ^ Anisotropy.GetHashCode() ^
|
||||
AnisotropyRoughness.GetHashCode() ^ ClearcoatRoughness.GetHashCode() ^ ClearcoatThickness.GetHashCode() ^
|
||||
|
||||
@ -132,6 +132,8 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
(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)
|
||||
{
|
||||
@ -152,7 +154,7 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
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 false;
|
||||
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);
|
||||
@ -163,7 +165,7 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
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) +
|
||||
@ -205,6 +207,11 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
public HSVAByte ToHSVAByte() => ToHSVA().ToHSVAByte();
|
||||
|
||||
public float[] ToArray() => new[] { R, G, B, A };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
RGBA @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { R, G, B, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
@ -218,6 +225,8 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
|
||||
public object Clone() => new RGBA(R, G, B, A);
|
||||
|
||||
public Vector3d ToVector() => ((Float3)this).ToVector();
|
||||
|
||||
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);
|
||||
|
||||
@ -137,7 +137,7 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
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 false;
|
||||
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);
|
||||
@ -148,7 +148,7 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return false;
|
||||
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) +
|
||||
@ -166,6 +166,11 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
|
||||
|
||||
public byte[] ToArray() => new[] { R, G, B, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
HSVAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { R, G, B, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
@ -179,6 +184,8 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
|
||||
public object Clone() => new RGBAByte(R, G, B, A);
|
||||
|
||||
public Vector3d ToVector() => ((RGBA)this).ToVector();
|
||||
|
||||
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);
|
||||
|
||||
@ -3,5 +3,6 @@
|
||||
public interface IGroup<T> : IEnumerable<T>
|
||||
{
|
||||
public T[] ToArray();
|
||||
public Fill<T> ToFill();
|
||||
public List<T> ToList();
|
||||
}
|
||||
|
||||
7
Nerd_STF/IGroup2D.cs
Normal file
7
Nerd_STF/IGroup2D.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public interface IGroup2D<T> : IGroup<T>
|
||||
{
|
||||
public T[,] ToArray2D();
|
||||
public Fill2D<T> ToFill2D();
|
||||
}
|
||||
18
Nerd_STF/Mathematics/Algebra/IMatrix.cs
Normal file
18
Nerd_STF/Mathematics/Algebra/IMatrix.cs
Normal file
@ -0,0 +1,18 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public interface IMatrix<T> : ICloneable, IEnumerable, IEquatable<T>, IGroup2D<float>
|
||||
where T : IMatrix<T>
|
||||
{
|
||||
public T Adjugate();
|
||||
public float Determinant();
|
||||
public T Inverse();
|
||||
public T Transpose();
|
||||
|
||||
public Dictionary<Int2, float> ToDictionary();
|
||||
}
|
||||
|
||||
public interface IMatrix<This, TMinor> : IMatrix<This> where This : IMatrix<This, TMinor>
|
||||
where TMinor : IMatrix<TMinor>
|
||||
{
|
||||
public TMinor[,] Minors();
|
||||
}
|
||||
337
Nerd_STF/Mathematics/Algebra/Matrix.cs
Normal file
337
Nerd_STF/Mathematics/Algebra/Matrix.cs
Normal file
@ -0,0 +1,337 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
{
|
||||
public static Matrix Identity(Int2 size)
|
||||
{
|
||||
Matrix m = Zero(size);
|
||||
int max = Mathf.Min(size.x, size.y);
|
||||
for (int i = 0; i < max; i++) m[i, i] = 1;
|
||||
return m;
|
||||
}
|
||||
public static Matrix One(Int2 size) => new(size, 1);
|
||||
public static Matrix SignGrid(Int2 size) => new(size, Equations.SgnFill);
|
||||
public static Matrix Zero(Int2 size) => new(size);
|
||||
|
||||
public bool HasMinors => Size.x > 1 && Size.y > 1;
|
||||
public bool IsSquare => Size.x == Size.y;
|
||||
|
||||
public Int2 Size { get; private init; }
|
||||
|
||||
private readonly float[,] array;
|
||||
|
||||
public Matrix() : this(Int2.Zero) { }
|
||||
public Matrix(Int2 size, float all = 0)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
|
||||
if (all == 0) return;
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = all;
|
||||
}
|
||||
public Matrix(Int2 size, float[] vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
|
||||
if (vals.Length < size.x * size.y)
|
||||
throw new InvalidSizeException("Array must contain enough values to fill the matrix.");
|
||||
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals[c + r * size.y];
|
||||
}
|
||||
public Matrix(Int2 size, int[] vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
|
||||
if (vals.Length < size.x * size.y)
|
||||
throw new InvalidSizeException("Array must contain enough values to fill the matrix.");
|
||||
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals[c + r * size.y];
|
||||
}
|
||||
public Matrix(Int2 size, Fill<float> vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals(c + r * size.y);
|
||||
}
|
||||
public Matrix(Int2 size, Fill<int> vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals(c + r * size.y);
|
||||
}
|
||||
public Matrix(Int2 size, float[,] vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals[c, r];
|
||||
}
|
||||
public Matrix(Int2 size, int[,] vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals[c, r];
|
||||
}
|
||||
public Matrix(Int2 size, Fill2D<float> vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals(c, r);
|
||||
}
|
||||
public Matrix(Int2 size, Fill2D<int> vals)
|
||||
{
|
||||
Size = size;
|
||||
array = new float[size.x, size.y];
|
||||
for (int r = 0; r < size.y; r++) for (int c = 0; c < size.x; c++) array[c, r] = vals(c, r);
|
||||
}
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => array[r, c];
|
||||
set => array[r, c] = value;
|
||||
}
|
||||
public float this[Int2 index]
|
||||
{
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
|
||||
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]));
|
||||
public static Matrix Clamp(Matrix val, Matrix min, Matrix max) =>
|
||||
new(val.Size, (r, c) => Mathf.Clamp(val[r, c], min[r, c], max[r, c]));
|
||||
public static Matrix Divide(Matrix num, params Matrix[] vals)
|
||||
{
|
||||
foreach (Matrix m in vals) num /= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix Floor(Matrix val) => new(val.Size, (r, c) => Mathf.Floor(val[r, c]));
|
||||
public static Matrix Lerp(Matrix a, Matrix b, float t, bool clamp = true) =>
|
||||
new(a.Size, (r, c) => Mathf.Lerp(a[r, c], b[r, c], t, clamp));
|
||||
public static Matrix Product(params Matrix[] vals)
|
||||
{
|
||||
if (vals.Length < 1) throw new InvalidSizeException("Array must contain at least one matrix.");
|
||||
if (!CheckSize(vals)) throw new InvalidSizeException("All matricies must be the same size.");
|
||||
Matrix val = Identity(vals[0].Size);
|
||||
foreach (Matrix m in vals) val *= m;
|
||||
return val;
|
||||
}
|
||||
public static Matrix Round(Matrix val) => new(val.Size, (r, c) => Mathf.Round(val[r, c]));
|
||||
public static Matrix Subtract(Matrix num, params Matrix[] vals)
|
||||
{
|
||||
foreach (Matrix m in vals) num -= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix Sum(params Matrix[] vals)
|
||||
{
|
||||
if (!CheckSize(vals)) throw new InvalidSizeException("All matricies must be the same size.");
|
||||
Matrix val = Zero(vals[0].Size);
|
||||
foreach (Matrix m in vals) val += m;
|
||||
return val;
|
||||
}
|
||||
|
||||
public void Apply(Modifier2D modifier)
|
||||
{
|
||||
for (int r = 0; r < Size.y; r++) for (int c = 0; c < Size.x; c++)
|
||||
array[r, c] = modifier(new(r, c), array[r, c]);
|
||||
}
|
||||
|
||||
public float[] GetColumn(int column)
|
||||
{
|
||||
float[] vals = new float[Size.y];
|
||||
for (int i = 0; i < Size.y; i++) vals[i] = array[i, column];
|
||||
return vals;
|
||||
}
|
||||
public float[] GetRow(int row)
|
||||
{
|
||||
float[] vals = new float[Size.x];
|
||||
for (int i = 0; i < Size.x; i++) vals[i] = array[row, i];
|
||||
return vals;
|
||||
}
|
||||
|
||||
public void SetColumn(int column, float[] vals)
|
||||
{
|
||||
if (vals.Length < Size.y)
|
||||
throw new InvalidSizeException("Array must contain enough values to fill the column.");
|
||||
for (int i = 0; i < Size.y; i++) array[i, column] = vals[i];
|
||||
}
|
||||
public void SetRow(int row, float[] vals)
|
||||
{
|
||||
if (vals.Length < Size.x)
|
||||
throw new InvalidSizeException("Array must contain enough values to fill the row.");
|
||||
for (int i = 0; i < Size.x; i++) array[row, i] = vals[i];
|
||||
}
|
||||
|
||||
public Matrix Adjugate()
|
||||
{
|
||||
Matrix dets = new(Size);
|
||||
Matrix[,] minors = Minors();
|
||||
for (int r = 0; r < Size.y; r++) for (int c = 0; c < Size.x; c++) dets[c, r] = minors[c, r].Determinant();
|
||||
return dets ^ SignGrid(Size);
|
||||
}
|
||||
public float Determinant()
|
||||
{
|
||||
if (!IsSquare) throw new InvalidSizeException("Matrix must be square to calculate determinant.");
|
||||
if (Size.x <= 0 || Size.y <= 0) return 0;
|
||||
if (Size.x == 1 || Size.y == 1) return array[0, 0];
|
||||
|
||||
Matrix[] minors = Minors().GetRow(0, Size.x);
|
||||
float det = 0;
|
||||
for (int i = 0; i < minors.Length; i++) det += minors[i].Determinant() * (i % 2 == 0 ? 1 : -1);
|
||||
|
||||
return det;
|
||||
}
|
||||
public Matrix Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
}
|
||||
public Matrix[,] Minors()
|
||||
{
|
||||
// This will absolutely blow my mind if it works.
|
||||
// Remember that whole "don't have a way to test" thing?
|
||||
|
||||
if (!HasMinors) return new Matrix[0,0];
|
||||
|
||||
Int2 newSize = Size - Int2.One;
|
||||
Matrix[,] array = new Matrix[Size.x, Size.y];
|
||||
for (int r1 = 0; r1 < Size.y; r1++) for (int c1 = 0; c1 < Size.x; c1++)
|
||||
{
|
||||
Matrix m = new(newSize);
|
||||
for (int r2 = 0; r2 < newSize.y; r2++) for (int c2 = 0; c2 < newSize.x; c2++)
|
||||
{
|
||||
int toSkip = c2 + r2 * newSize.y;
|
||||
for (int r3 = 0; r3 < newSize.y; r3++) for (int c3 = 0; c3 < newSize.x; c3++)
|
||||
{
|
||||
if (r3 == r1 || c3 == c1) continue;
|
||||
if (toSkip > 0)
|
||||
{
|
||||
toSkip--;
|
||||
continue;
|
||||
}
|
||||
m[c2, r2] = this.array[c3, r3];
|
||||
break;
|
||||
}
|
||||
}
|
||||
array[c1, r1] = m;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
public Matrix Transpose()
|
||||
{
|
||||
Matrix m = new(new(Size.y, Size.x));
|
||||
for (int r = 0; r < Size.y; r++) m.SetColumn(r, GetRow(r));
|
||||
for (int c = 0; c < Size.x; c++) m.SetRow(c, GetColumn(c));
|
||||
return m;
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(Matrix)) return Equals((Matrix)obj);
|
||||
else if (t == typeof(Matrix2x2)) return Equals((Matrix)obj);
|
||||
else if (t == typeof(Matrix3x3)) return Equals((Matrix)obj);
|
||||
else if (t == typeof(Matrix4x4)) return Equals((Matrix)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public bool Equals(Matrix other) => array == other.array;
|
||||
public override int GetHashCode() => array.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider)
|
||||
{
|
||||
string res = "";
|
||||
for (int r = 0; r < Size.y; r++)
|
||||
{
|
||||
for (int c = 0; c < Size.x; c++) res += array[c, r].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[c, r].ToString(provider) + " ";
|
||||
res += "\n";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public object Clone() => new Matrix(Size, array);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
for (int r = 0; r < Size.y; r++) for (int c = 0; c < Size.x; c++) yield return array[c, r];
|
||||
}
|
||||
|
||||
public float[] ToArray() => array.Flatten(Size);
|
||||
public float[,] ToArray2D() => array;
|
||||
public Dictionary<Int2, float> ToDictionary()
|
||||
{
|
||||
Dictionary<Int2, float> dict = new();
|
||||
for (int r = 0; r < Size.y; r++) for (int c = 0; c < Size.x; c++) dict.Add(new(c, r), array[c, r]);
|
||||
return dict;
|
||||
}
|
||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||
public Fill2D<float> ToFill2D()
|
||||
{
|
||||
Matrix @this = this;
|
||||
return (x, y) => @this[x, y];
|
||||
}
|
||||
public List<float> 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 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) =>
|
||||
new(new(a.Size.y, b.Size.x), (r, c) => Mathf.Dot(a.GetRow(r), b.GetColumn(c)));
|
||||
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);
|
||||
public static Float3 operator *(Matrix a, Float3 b) => (Float3)(a * (Matrix)b);
|
||||
public static Float4 operator *(Matrix a, Float4 b) => (Float4)(a * (Matrix)b);
|
||||
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 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);
|
||||
public static Float3 operator /(Matrix a, Float3 b) => (Float3)(a / (Matrix)b);
|
||||
public static Float4 operator /(Matrix a, Float4 b) => (Float4)(a / (Matrix)b);
|
||||
public static Vector2d operator /(Matrix a, Vector2d b) => (Vector2d)(a / (Matrix)b);
|
||||
public static Vector3d operator /(Matrix a, Vector3d b) => (Vector3d)(a / (Matrix)b);
|
||||
// Single number multiplication
|
||||
public static Matrix operator ^(Matrix a, Matrix b) => new(a.Size, (r, c) => a[r, c] * b[r, c]);
|
||||
public static bool operator ==(Matrix a, Matrix b) => a.Equals(b);
|
||||
public static bool operator !=(Matrix a, Matrix b) => !a.Equals(b);
|
||||
|
||||
public static explicit operator Matrix(Complex c) => (Matrix)(Float2)c;
|
||||
public static explicit operator Matrix(Quaternion c) => (Matrix)(Float4)c;
|
||||
public static explicit operator Matrix(Float2 f) => new(new(2, 1), i => f[i]);
|
||||
public static explicit operator Matrix(Float3 f) => new(new(3, 1), i => f[i]);
|
||||
public static explicit operator Matrix(Float4 f) => new(new(4, 1), i => f[i]);
|
||||
public static implicit operator Matrix(Matrix2x2 m) => new(new(2, 2), m.ToFill2D());
|
||||
public static implicit operator Matrix(Matrix3x3 m) => new(new(3, 3), m.ToFill2D());
|
||||
public static implicit operator Matrix(Matrix4x4 m) => new(new(4, 4), m.ToFill2D());
|
||||
public static explicit operator Matrix(Vector2d v) => (Matrix)v.ToXYZ();
|
||||
public static explicit operator Matrix(Vector3d v) => (Matrix)v.ToXYZ();
|
||||
|
||||
private static bool CheckSize(params Matrix[] vals)
|
||||
{
|
||||
if (vals.Length <= 1) return true;
|
||||
Int2 size = vals[0].Size;
|
||||
for (int i = 1; i < vals.Length; i++) if (size != vals[i].Size) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
275
Nerd_STF/Mathematics/Algebra/Matrix2x2.cs
Normal file
275
Nerd_STF/Mathematics/Algebra/Matrix2x2.cs
Normal file
@ -0,0 +1,275 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
{
|
||||
public static Matrix2x2 Identity => new(new[,]
|
||||
{
|
||||
{ 1, 0 },
|
||||
{ 0, 1 }
|
||||
});
|
||||
public static Matrix2x2 One => new(1);
|
||||
public static Matrix2x2 SignGrid => new(new[,]
|
||||
{
|
||||
{ +1, -1 },
|
||||
{ -1, +1 }
|
||||
});
|
||||
public static Matrix2x2 Zero => new(0);
|
||||
|
||||
public Float2 Column1
|
||||
{
|
||||
get => new(r1c1, r2c1);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r2c1 = value.y;
|
||||
}
|
||||
}
|
||||
public Float2 Column2
|
||||
{
|
||||
get => new(r1c2, r2c2);
|
||||
set
|
||||
{
|
||||
r1c2 = value.x;
|
||||
r2c2 = value.y;
|
||||
}
|
||||
}
|
||||
public Float2 Row1
|
||||
{
|
||||
get => new(r1c1, r1c2);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r1c2 = value.y;
|
||||
}
|
||||
}
|
||||
public Float2 Row2
|
||||
{
|
||||
get => new(r2c1, r2c2);
|
||||
set
|
||||
{
|
||||
r2c1 = value.x;
|
||||
r2c2 = value.y;
|
||||
}
|
||||
}
|
||||
|
||||
public float r1c1, r2c1, r1c2, r2c2;
|
||||
|
||||
public Matrix2x2(float all) : this(all, all, all, all) { }
|
||||
public Matrix2x2(float r1c1, float r2c1, float r1c2, float r2c2)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
this.r1c2 = r1c2;
|
||||
this.r2c2 = r2c2;
|
||||
}
|
||||
public Matrix2x2(float[] nums) : this(nums[0], nums[1], nums[2], nums[3]) { }
|
||||
public Matrix2x2(int[] nums) : this(nums[0], nums[1], nums[2], nums[3]) { }
|
||||
public Matrix2x2(Fill<float> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public Matrix2x2(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public Matrix2x2(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
||||
public Matrix2x2(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[1, 0], nums[1, 1]) { }
|
||||
public Matrix2x2(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
||||
public Matrix2x2(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(1, 0), fill(1, 1)) { }
|
||||
public Matrix2x2(Float2 c1, Float2 c2) : this(c1.x, c1.y, c2.x, c2.y) { }
|
||||
public Matrix2x2(Fill<Float2> fill) : this(fill(0), fill(1)) { }
|
||||
public Matrix2x2(Fill<Int2> fill) : this((IEnumerable<int>)fill(0), fill(1)) { }
|
||||
public Matrix2x2(IEnumerable<float> c1, IEnumerable<float> c2) : this(c1.ToFill(), c2.ToFill()) { }
|
||||
public Matrix2x2(IEnumerable<int> c1, IEnumerable<int> c2) : this(c1.ToFill(), c2.ToFill()) { }
|
||||
public Matrix2x2(Fill<float> c1, Fill<float> c2) : this(c1(0), c1(1), c2(0), c2(1)) { }
|
||||
public Matrix2x2(Fill<int> c1, Fill<int> c2) : this(c1(0), c1(1), c2(0), c2(1)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
// It's definitely better than it was before. Trust me.
|
||||
switch ("r" + (r + 1) + "c" + (c + 1))
|
||||
{
|
||||
case "r1c1":
|
||||
r1c1 = value;
|
||||
break;
|
||||
|
||||
case "r2c1":
|
||||
r2c1 = value;
|
||||
break;
|
||||
|
||||
case "r1c2":
|
||||
r1c2 = value;
|
||||
break;
|
||||
|
||||
case "r2c2":
|
||||
r2c2 = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
string @params = "";
|
||||
if (r < 0 || r > 1) @params += r;
|
||||
if (c < 0 || c > 1) @params += string.IsNullOrEmpty(@params) ? c : " and " + c;
|
||||
throw new IndexOutOfRangeException(@params);
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Int2 index]
|
||||
{
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
|
||||
public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r2c1),
|
||||
Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c2));
|
||||
public static Matrix2x2 Average(params Matrix2x2[] vals) => Sum(vals) / vals.Length;
|
||||
public static Matrix2x2 Ceiling(Matrix2x2 val) => new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r2c1),
|
||||
Mathf.Ceiling(val.r1c2), Mathf.Ceiling(val.r2c2));
|
||||
public static Matrix2x2 Clamp(Matrix2x2 val, Matrix2x2 min, Matrix2x2 max) =>
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1),
|
||||
Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2), Mathf.Clamp(val.r2c2, min.r2c2, max.r2c2));
|
||||
public static Matrix2x2 Divide(Matrix2x2 num, params Matrix2x2[] vals)
|
||||
{
|
||||
foreach (Matrix2x2 m in vals) num /= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix2x2 Floor(Matrix2x2 val) => new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r2c1),
|
||||
Mathf.Floor(val.r1c2), Mathf.Floor(val.r2c2));
|
||||
public static Matrix2x2 Lerp(Matrix2x2 a, Matrix2x2 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r2c1, b.r2c1, t, clamp),
|
||||
Mathf.Lerp(a.r1c2, b.r1c2, t, clamp), Mathf.Lerp(a.r2c2, b.r2c2, t, clamp));
|
||||
public static Matrix2x2 Median(params Matrix2x2[] vals)
|
||||
{
|
||||
float index = Mathf.Average(0, vals.Length - 1);
|
||||
Matrix2x2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static Matrix2x2 Product(params Matrix2x2[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Matrix2x2 val = Identity;
|
||||
foreach (Matrix2x2 m in vals) val *= m;
|
||||
return val;
|
||||
}
|
||||
public static Matrix2x2 Round(Matrix2x2 val) => new(Mathf.Round(val.r1c1), Mathf.Round(val.r2c1),
|
||||
Mathf.Round(val.r1c2), Mathf.Round(val.r2c2));
|
||||
public static Matrix2x2 Subtract(Matrix2x2 num, params Matrix2x2[] vals)
|
||||
{
|
||||
foreach (Matrix2x2 m in vals) num -= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix2x2 Sum(params Matrix2x2[] vals)
|
||||
{
|
||||
Matrix2x2 val = Zero;
|
||||
foreach (Matrix2x2 m in vals) val += m;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (float[] r1c1s, float[] r2c1s, float[] r1c2s, float[] r2c2s) SplitArray(params Matrix2x2[] vals)
|
||||
{
|
||||
float[] r1c1s = new float[vals.Length], r2c1s = new float[vals.Length], r1c2s = new float[vals.Length],
|
||||
r2c2s = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
r1c1s[i] = vals[i].r1c1;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r1c2s[i] = vals[i].r1c2;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
}
|
||||
return (r1c1s, r2c1s, r1c2s, r2c2s);
|
||||
}
|
||||
|
||||
public Matrix2x2 Adjugate()
|
||||
{
|
||||
Matrix2x2 swapped = new(new[,]
|
||||
{
|
||||
{ r2c2, r1c2 },
|
||||
{ r2c1, r1c1 }
|
||||
});
|
||||
return swapped ^ SignGrid;
|
||||
}
|
||||
public float Determinant() => r1c1 * r2c2 - r1c2 * r2c1;
|
||||
public Matrix2x2 Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
}
|
||||
public Matrix2x2 Transpose() => new(new[,]
|
||||
{
|
||||
{ r1c1, r2c1 },
|
||||
{ r1c2, r2c2 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix2x2)) return base.Equals(obj);
|
||||
return Equals((Matrix2x2)obj);
|
||||
}
|
||||
public bool Equals(Matrix2x2 other) => r1c1 == other.r1c1 && r2c1 == other.r2c1
|
||||
&& r1c2 == other.r1c2&& r2c2 == other.r2c2;
|
||||
public override int GetHashCode() => r1c1.GetHashCode() ^ r2c1.GetHashCode()
|
||||
^ r1c2.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());
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return r1c1;
|
||||
yield return r2c1;
|
||||
yield return r1c2;
|
||||
yield return r2c2;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { r1c1, r2c1, r1c2, r2c2 };
|
||||
public float[,] ToArray2D() => new[,]
|
||||
{
|
||||
{ r1c1, r1c2 },
|
||||
{ r2c1, r2c2 }
|
||||
};
|
||||
public Dictionary<Int2, float> ToDictionary()
|
||||
{
|
||||
Dictionary<Int2, float> dict = new();
|
||||
float[] arr = ToArray();
|
||||
for (int i = 0; i < arr.Length; i++) dict.Add(new(i % 2, i / 2), arr[i]);
|
||||
return dict;
|
||||
}
|
||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||
public Fill2D<float> ToFill2D()
|
||||
{
|
||||
Matrix2x2 @this = this;
|
||||
return (x, y) => @this[x, y];
|
||||
}
|
||||
public List<float> ToList() => new() { r1c1, r2c1, r1c2, r2c2 };
|
||||
|
||||
public static Matrix2x2 operator +(Matrix2x2 a, Matrix2x2 b) => new(a.r1c1 + b.r1c1, a.r2c1 + b.r2c1,
|
||||
a.r1c2 + b.r1c2, a.r2c2 + b.r2c2);
|
||||
public static Matrix2x2? operator -(Matrix2x2 m) => m.Inverse();
|
||||
public static Matrix2x2 operator -(Matrix2x2 a, Matrix2x2 b) => new(a.r1c1 - b.r1c1, a.r2c1 - b.r2c1,
|
||||
a.r1c2 - b.r1c2, a.r2c2 + b.r2c2);
|
||||
public static Matrix2x2 operator *(Matrix2x2 a, float b) => new(a.r1c1 * b, a.r2c1 * b, a.r1c2 * b, a.r2c2 * b);
|
||||
public static Matrix2x2 operator *(Matrix2x2 a, Matrix2x2 b) => new(new[,]
|
||||
{
|
||||
{ Float2.Dot(a.Row1, b.Column1), Float2.Dot(a.Row1, b.Column2) },
|
||||
{ Float2.Dot(a.Row2, b.Column1), Float2.Dot(a.Row2, b.Column2) },
|
||||
});
|
||||
public static Matrix2x2 operator /(Matrix2x2 a, float b) => new(a.r1c1 / b, a.r2c1 / b, a.r1c2 / b, a.r2c2 / b);
|
||||
public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b) => a * b.Inverse();
|
||||
public static Matrix2x2 operator ^(Matrix2x2 a, Matrix2x2 b) => // Single number multiplication.
|
||||
new(a.r1c1 * b.r1c1, a.r2c1 * b.r2c1, a.r1c2 * b.r1c2, 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)
|
||||
{
|
||||
Matrix2x2 res = Zero, identity = Identity;
|
||||
for (int r = 0; r < 2; r++) for (int c = 0; c < 2; c++)
|
||||
res[c, r] = m.Size.x < c && m.Size.y < r ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static explicit operator Matrix2x2(Matrix3x3 m) => new(m.r1c1, m.r2c1, m.r1c2, m.r2c2);
|
||||
public static explicit operator Matrix2x2(Matrix4x4 m) => new(m.r1c1, m.r2c1, m.r1c2, m.r2c2);
|
||||
}
|
||||
411
Nerd_STF/Mathematics/Algebra/Matrix3x3.cs
Normal file
411
Nerd_STF/Mathematics/Algebra/Matrix3x3.cs
Normal file
@ -0,0 +1,411 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
{
|
||||
public static Matrix3x3 Identity => new(new[,]
|
||||
{
|
||||
{ 1, 0, 0 },
|
||||
{ 0, 1, 0 },
|
||||
{ 0, 0, 1 }
|
||||
});
|
||||
public static Matrix3x3 One => new(1);
|
||||
public static Matrix3x3 SignGrid => new(new[,]
|
||||
{
|
||||
{ +1, -1, +1 },
|
||||
{ -1, +1, -1 },
|
||||
{ +1, -1, +1 }
|
||||
});
|
||||
public static Matrix3x3 Zero => new(0);
|
||||
|
||||
public Float3 Column1
|
||||
{
|
||||
get => new(r1c1, r2c1, r3c1);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r2c1 = value.y;
|
||||
r3c1 = value.z;
|
||||
}
|
||||
}
|
||||
public Float3 Column2
|
||||
{
|
||||
get => new(r1c2, r2c2, r3c2);
|
||||
set
|
||||
{
|
||||
r1c2 = value.x;
|
||||
r2c2 = value.y;
|
||||
r3c2 = value.z;
|
||||
}
|
||||
}
|
||||
public Float3 Column3
|
||||
{
|
||||
get => new(r1c3, r2c3, r3c3);
|
||||
set
|
||||
{
|
||||
r1c3 = value.x;
|
||||
r2c3 = value.y;
|
||||
r3c3 = value.z;
|
||||
}
|
||||
}
|
||||
public Float3 Row1
|
||||
{
|
||||
get => new(r1c1, r1c2, r1c3);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r1c2 = value.y;
|
||||
r1c3 = value.z;
|
||||
}
|
||||
}
|
||||
public Float3 Row2
|
||||
{
|
||||
get => new(r2c1, r2c2, r2c3);
|
||||
set
|
||||
{
|
||||
r2c1 = value.x;
|
||||
r2c2 = value.y;
|
||||
r2c3 = value.z;
|
||||
}
|
||||
}
|
||||
public Float3 Row3
|
||||
{
|
||||
get => new(r3c1, r3c2, r3c3);
|
||||
set
|
||||
{
|
||||
r3c1 = value.x;
|
||||
r3c2 = value.y;
|
||||
r3c3 = value.z;
|
||||
}
|
||||
}
|
||||
|
||||
public float r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c3, r2c3, r3c3;
|
||||
|
||||
public Matrix3x3(float all) : this(all, all, all, all, all, all, all, all, all) { }
|
||||
public Matrix3x3(float r1c1, float r2c1, float r3c1, float r1c2,
|
||||
float r2c2, float r3c2, float r1c3, float r2c3, float r3c3)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
this.r3c1 = r3c1;
|
||||
this.r1c2 = r1c2;
|
||||
this.r2c2 = r2c2;
|
||||
this.r3c2 = r3c2;
|
||||
this.r1c3 = r1c3;
|
||||
this.r2c3 = r2c3;
|
||||
this.r3c3 = r3c3;
|
||||
}
|
||||
public Matrix3x3(float[] nums) : this(nums[0], nums[1], nums[2],
|
||||
nums[3], nums[4], nums[5], nums[6], nums[7], nums[8]) { }
|
||||
public Matrix3x3(int[] nums) : this(nums[0], nums[1], nums[2],
|
||||
nums[3], nums[4], nums[5], nums[6], nums[7], nums[8]) { }
|
||||
public Matrix3x3(Fill<float> fill) : this(fill(0), fill(1), fill(2),
|
||||
fill(3), fill(4), fill(5), fill(6), fill(7), fill(8)) { }
|
||||
public Matrix3x3(Fill<int> fill) : this(fill(0), fill(1), fill(2),
|
||||
fill(3), fill(4), fill(5), fill(6), fill(7), fill(8)) { }
|
||||
public Matrix3x3(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2],
|
||||
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
||||
public Matrix3x3(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2],
|
||||
nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { }
|
||||
public Matrix3x3(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
||||
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
||||
public Matrix3x3(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2),
|
||||
fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { }
|
||||
public Matrix3x3(Float3 c1, Float3 c2, Float3 c3) : this(c1.x, c1.y, c1.z, c2.x, c2.y, c2.z, c3.x, c3.y, c3.z) { }
|
||||
public Matrix3x3(Fill<Float3> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||
public Matrix3x3(Fill<Int3> fill) : this((IEnumerable<int>)fill(0), fill(1), fill(2)) { }
|
||||
public Matrix3x3(IEnumerable<float> c1, IEnumerable<float> c2, IEnumerable<float> c3)
|
||||
: this(c1.ToFill(), c2.ToFill(), c3.ToFill()) { }
|
||||
public Matrix3x3(IEnumerable<int> c1, IEnumerable<int> c2, IEnumerable<int> c3)
|
||||
: this(c1.ToFill(), c2.ToFill(), c3.ToFill()) { }
|
||||
public Matrix3x3(Fill<float> c1, Fill<float> c2, Fill<float> c3)
|
||||
: this(c1(0), c1(1), c1(2), c2(0), c2(1), c2(2), c3(0), c3(1), c3(2)) { }
|
||||
public Matrix3x3(Fill<int> c1, Fill<int> c2, Fill<int> c3)
|
||||
: this(c1(0), c1(1), c1(2), c2(0), c2(1), c2(2), c3(0), c3(1), c3(2)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
// It's definitely better than it was before. Trust me.
|
||||
switch ("r" + (r + 1) + "c" + (c + 1))
|
||||
{
|
||||
case "r1c1":
|
||||
r1c1 = value;
|
||||
break;
|
||||
|
||||
case "r2c1":
|
||||
r2c1 = value;
|
||||
break;
|
||||
|
||||
case "r3c1":
|
||||
r3c1 = value;
|
||||
break;
|
||||
|
||||
case "r1c2":
|
||||
r1c2 = value;
|
||||
break;
|
||||
|
||||
case "r2c2":
|
||||
r2c2 = value;
|
||||
break;
|
||||
|
||||
case "r3c2":
|
||||
r3c2 = value;
|
||||
break;
|
||||
|
||||
case "r1c3":
|
||||
r1c3 = value;
|
||||
break;
|
||||
|
||||
case "r2c3":
|
||||
r2c3 = value;
|
||||
break;
|
||||
|
||||
case "r3c3":
|
||||
r3c3 = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
string @params = "";
|
||||
if (r < 0 || r > 2) @params += r;
|
||||
if (c < 0 || c > 2) @params += string.IsNullOrEmpty(@params) ? c : " and " + c;
|
||||
throw new IndexOutOfRangeException(@params);
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Int2 index]
|
||||
{
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
|
||||
public static Matrix3x3 Absolute(Matrix3x3 val) =>
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r3c1),
|
||||
Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r3c2),
|
||||
Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r2c3), Mathf.Absolute(val.r3c3));
|
||||
public static Matrix3x3 Average(params Matrix3x3[] vals) => Sum(vals) / vals.Length;
|
||||
public static Matrix3x3 Ceiling(Matrix3x3 val) =>
|
||||
new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r2c1), Mathf.Ceiling(val.r3c1),
|
||||
Mathf.Ceiling(val.r1c2), Mathf.Ceiling(val.r2c2), Mathf.Ceiling(val.r3c2),
|
||||
Mathf.Ceiling(val.r1c3), Mathf.Ceiling(val.r2c3), Mathf.Ceiling(val.r3c3));
|
||||
public static Matrix3x3 Clamp(Matrix3x3 val, Matrix3x3 min, Matrix3x3 max) =>
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1),
|
||||
Mathf.Clamp(val.r3c1, min.r3c1, max.r3c1), Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2),
|
||||
Mathf.Clamp(val.r2c2, min.r2c2, max.r2c2), Mathf.Clamp(val.r3c2, min.r3c2, max.r3c2),
|
||||
Mathf.Clamp(val.r1c3, min.r1c3, max.r1c3), Mathf.Clamp(val.r2c3, min.r2c3, max.r2c3),
|
||||
Mathf.Clamp(val.r3c3, min.r3c3, max.r3c3));
|
||||
public static Matrix3x3 Divide(Matrix3x3 num, params Matrix3x3[] vals)
|
||||
{
|
||||
foreach (Matrix3x3 m in vals) num /= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix3x3 Floor(Matrix3x3 val) =>
|
||||
new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r2c1), Mathf.Floor(val.r3c1),
|
||||
Mathf.Floor(val.r1c2), Mathf.Floor(val.r2c2), Mathf.Floor(val.r3c2),
|
||||
Mathf.Floor(val.r1c3), Mathf.Floor(val.r2c3), Mathf.Floor(val.r3c3));
|
||||
public static Matrix3x3 Lerp(Matrix3x3 a, Matrix3x3 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r2c1, b.r2c1, t, clamp),
|
||||
Mathf.Lerp(a.r3c1, b.r3c1, t, clamp), Mathf.Lerp(a.r1c2, b.r1c2, t, clamp),
|
||||
Mathf.Lerp(a.r2c2, b.r2c2, t, clamp), Mathf.Lerp(a.r3c2, b.r3c2, t, clamp),
|
||||
Mathf.Lerp(a.r1c3, b.r1c3, t, clamp), Mathf.Lerp(a.r2c3, b.r2c3, t, clamp),
|
||||
Mathf.Lerp(a.r3c3, b.r3c3, t, clamp));
|
||||
public static Matrix3x3 Median(params Matrix3x3[] vals)
|
||||
{
|
||||
float index = Mathf.Average(0, vals.Length - 1);
|
||||
Matrix3x3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static Matrix3x3 Product(params Matrix3x3[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Matrix3x3 val = Identity;
|
||||
foreach (Matrix3x3 m in vals) val *= m;
|
||||
return val;
|
||||
}
|
||||
public static Matrix3x3 Round(Matrix3x3 val) =>
|
||||
new(Mathf.Round(val.r1c1), Mathf.Round(val.r2c1), Mathf.Round(val.r3c1),
|
||||
Mathf.Round(val.r1c2), Mathf.Round(val.r2c2), Mathf.Round(val.r3c2),
|
||||
Mathf.Round(val.r1c3), Mathf.Round(val.r2c3), Mathf.Round(val.r3c3));
|
||||
public static Matrix3x3 Subtract(Matrix3x3 num, params Matrix3x3[] vals)
|
||||
{
|
||||
foreach (Matrix3x3 m in vals) num -= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix3x3 Sum(params Matrix3x3[] vals)
|
||||
{
|
||||
Matrix3x3 val = Zero;
|
||||
foreach (Matrix3x3 m in vals) val += m;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (float[] r1c1s, float[] r2c1s, float[] r3c1s, float[] r1c2s, float[] r2c2s,
|
||||
float[] r3c2s, float[] r1c3s, float[] r2c3s, float[] r3c3s) SplitArray(params Matrix3x3[] vals)
|
||||
{
|
||||
float[] r1c1s = new float[vals.Length], r2c1s = new float[vals.Length], r3c1s = new float[vals.Length],
|
||||
r1c2s = new float[vals.Length], r2c2s = new float[vals.Length], r3c2s = new float[vals.Length],
|
||||
r1c3s = new float[vals.Length], r2c3s = new float[vals.Length], r3c3s = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
r1c1s[i] = vals[i].r1c1;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r3c1s[i] = vals[i].r3c1;
|
||||
r1c2s[i] = vals[i].r1c2;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
r3c2s[i] = vals[i].r3c2;
|
||||
r1c3s[i] = vals[i].r1c3;
|
||||
r2c3s[i] = vals[i].r2c3;
|
||||
r3c3s[i] = vals[i].r3c3;
|
||||
}
|
||||
return (r1c1s, r2c1s, r3c1s, r1c2s, r2c2s, r3c2s, r1c3s, r2c3s, r3c3s);
|
||||
}
|
||||
|
||||
public Matrix3x3 Adjugate()
|
||||
{
|
||||
Matrix3x3 dets = new();
|
||||
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;
|
||||
}
|
||||
public float Determinant()
|
||||
{
|
||||
Matrix2x2[,] minors = Minors();
|
||||
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[1, 0].Determinant())
|
||||
+ (r1c3 * minors[2, 0].Determinant());
|
||||
}
|
||||
public Matrix3x3 Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
}
|
||||
public Matrix2x2[,] Minors() => new Matrix2x2[,]
|
||||
{
|
||||
{ new(r2c2, r3c2, r2c3, r3c3), new(r2c1, r3c1, r2c3, r3c3), new(r2c1, r3c1, r2c2, r3c2) },
|
||||
{ new(r1c2, r3c2, r1c3, r3c3), new(r1c1, r3c1, r1c3, r3c3), new(r1c1, r3c1, r1c2, r3c2) },
|
||||
{ new(r1c2, r2c2, r1c3, r2c3), new(r1c1, r2c1, r1c3, r2c3), new(r1c1, r2c1, r1c2, r2c2) }
|
||||
};
|
||||
public Matrix3x3 Transpose() => new(new[,]
|
||||
{
|
||||
{ r1c1, r2c1, r3c1 },
|
||||
{ r1c2, r2c2, r3c2 },
|
||||
{ r1c3, r2c3, r3c3 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix3x3)) return base.Equals(obj);
|
||||
return Equals((Matrix3x3)obj);
|
||||
}
|
||||
public bool Equals(Matrix3x3 other) =>
|
||||
r1c1 == other.r1c1 && r2c1 == other.r2c1 && r3c1 == other.r3c1 &&
|
||||
r1c2 == other.r1c2 && r2c2 == other.r2c2 && r3c2 == other.r3c2 &&
|
||||
r1c3 == other.r1c3 && r2c3 == other.r2c3 && r3c3 == other.r3c3;
|
||||
public override int GetHashCode() =>
|
||||
r1c1.GetHashCode() ^ r2c1.GetHashCode() ^ r3c1.GetHashCode() ^
|
||||
r1c2.GetHashCode() ^ r2c2.GetHashCode() ^ r3c2.GetHashCode() ^
|
||||
r1c3.GetHashCode() ^ r2c3.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());
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return r1c1;
|
||||
yield return r2c1;
|
||||
yield return r3c1;
|
||||
yield return r1c2;
|
||||
yield return r2c2;
|
||||
yield return r3c2;
|
||||
yield return r1c3;
|
||||
yield return r2c3;
|
||||
yield return r3c3;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c3, r2c3, r3c3 };
|
||||
public float[,] ToArray2D() => new[,]
|
||||
{
|
||||
{ r1c1, r1c2, r1c3 },
|
||||
{ r2c1, r2c2, r2c3 },
|
||||
{ r3c1, r3c2, r3c3 }
|
||||
};
|
||||
public Dictionary<Int2, float> ToDictionary()
|
||||
{
|
||||
Dictionary<Int2, float> dict = new();
|
||||
float[] arr = ToArray();
|
||||
for (int i = 0; i < arr.Length; i++) dict.Add(new(i % 3, i / 3), arr[i]);
|
||||
return dict;
|
||||
}
|
||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||
public Fill2D<float> ToFill2D()
|
||||
{
|
||||
Matrix3x3 @this = this;
|
||||
return (x, y) => @this[x, y];
|
||||
}
|
||||
public List<float> ToList() => new() { r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c3, r2c3, r3c3 };
|
||||
|
||||
public static Matrix3x3 operator +(Matrix3x3 a, Matrix3x3 b) =>
|
||||
new(a.r1c1 + b.r1c1, a.r2c1 + b.r2c1, a.r3c1 + b.r3c1,
|
||||
a.r1c2 + b.r1c2, a.r2c2 + b.r2c2, a.r3c2 + b.r3c2,
|
||||
a.r1c3 + b.r1c3, a.r2c3 + b.r2c3, a.r3c3 + b.r3c3);
|
||||
public static Matrix3x3 operator -(Matrix3x3 m) => m.Inverse();
|
||||
public static Matrix3x3 operator -(Matrix3x3 a, Matrix3x3 b) =>
|
||||
new(a.r1c1 - b.r1c1, a.r2c1 - b.r2c1, a.r3c1 - b.r3c1,
|
||||
a.r1c2 - b.r1c2, a.r2c2 - b.r2c2, a.r3c2 - b.r3c2,
|
||||
a.r1c3 - b.r1c3, a.r2c3 - b.r2c3, a.r3c3 - b.r3c3);
|
||||
public static Matrix3x3 operator *(Matrix3x3 a, float b) =>
|
||||
new(a.r1c1 * b, a.r2c1 * b, a.r3c1 * b,
|
||||
a.r1c2 * b, a.r2c2 * b, a.r3c2 * b,
|
||||
a.r1c3 * b, a.r2c3 * b, a.r3c3 * b);
|
||||
public static Matrix3x3 operator *(Matrix3x3 a, Matrix3x3 b) => new(new[,]
|
||||
{
|
||||
{ Float3.Dot(a.Row1, b.Column1), Float3.Dot(a.Row1, b.Column2), Float3.Dot(a.Row1, b.Column3) },
|
||||
{ Float3.Dot(a.Row2, b.Column1), Float3.Dot(a.Row2, b.Column2), Float3.Dot(a.Row2, b.Column3) },
|
||||
{ Float3.Dot(a.Row3, b.Column1), Float3.Dot(a.Row3, b.Column2), Float3.Dot(a.Row3, b.Column3) },
|
||||
});
|
||||
public static Matrix3x3 operator /(Matrix3x3 a, float b) =>
|
||||
new(a.r1c1 / b, a.r2c1 / b, a.r3c1 / b,
|
||||
a.r1c2 / b, a.r2c2 / b, a.r3c2 / b,
|
||||
a.r1c3 / b, a.r2c3 / b, a.r3c3 / b);
|
||||
public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b) => a * b.Inverse();
|
||||
public static Matrix3x3 operator ^(Matrix3x3 a, Matrix3x3 b) => // Single number multiplication
|
||||
new(a.r1c1 * b.r1c1, a.r2c1 * b.r2c1, a.r3c1 * b.r3c1,
|
||||
a.r1c2 * b.r1c2, a.r2c2 * b.r2c2, a.r3c2 * b.r3c2,
|
||||
a.r1c3 * b.r1c3, a.r2c3 * b.r2c3, 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)
|
||||
{
|
||||
Matrix3x3 res = Zero, identity = Identity;
|
||||
for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++)
|
||||
res[c, r] = m.Size.x < c && m.Size.y < r ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static implicit operator Matrix3x3(Matrix2x2 m)
|
||||
{
|
||||
Matrix3x3 identity = Identity;
|
||||
return new(new[,]
|
||||
{
|
||||
{ m.r1c1, m.r1c2, identity.r1c3 },
|
||||
{ m.r2c1, m.r2c2, identity.r2c3 },
|
||||
{ identity.r3c1, identity.r3c2, identity.r3c3 }
|
||||
});
|
||||
}
|
||||
public static explicit operator Matrix3x3(Matrix4x4 m) => new(new[,]
|
||||
{
|
||||
{ m.r1c1, m.r1c2, m.r1c3 },
|
||||
{ m.r2c1, m.r2c2, m.r2c3 },
|
||||
{ m.r3c1, m.r3c2, m.r3c3 }
|
||||
});
|
||||
}
|
||||
566
Nerd_STF/Mathematics/Algebra/Matrix4x4.cs
Normal file
566
Nerd_STF/Mathematics/Algebra/Matrix4x4.cs
Normal file
@ -0,0 +1,566 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
{
|
||||
public static Matrix4x4 Identity => new(new[,]
|
||||
{
|
||||
{ 1, 0, 0, 0 },
|
||||
{ 0, 1, 0, 0 },
|
||||
{ 0, 0, 1, 0 },
|
||||
{ 0, 0, 0, 1 },
|
||||
});
|
||||
public static Matrix4x4 One => new(1);
|
||||
public static Matrix4x4 SignGrid => new(new[,]
|
||||
{
|
||||
{ +1, -1, +1, -1 },
|
||||
{ -1, +1, -1, +1 },
|
||||
{ +1, -1, +1, -1 },
|
||||
{ -1, +1, -1, +1 }
|
||||
});
|
||||
public static Matrix4x4 Zero => new(0);
|
||||
|
||||
public Float4 Column1
|
||||
{
|
||||
get => new(r1c1, r2c1, r3c1, r4c1);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r2c1 = value.y;
|
||||
r3c1 = value.z;
|
||||
r4c1 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Column2
|
||||
{
|
||||
get => new(r1c2, r2c2, r3c2, r4c2);
|
||||
set
|
||||
{
|
||||
r1c2 = value.x;
|
||||
r2c2 = value.y;
|
||||
r3c2 = value.z;
|
||||
r4c2 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Column3
|
||||
{
|
||||
get => new(r1c3, r2c3, r3c3, r4c3);
|
||||
set
|
||||
{
|
||||
r1c3 = value.x;
|
||||
r2c3 = value.y;
|
||||
r3c3 = value.z;
|
||||
r4c3 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Column4
|
||||
{
|
||||
get => new(r1c4, r2c4, r3c4, r4c4);
|
||||
set
|
||||
{
|
||||
r1c4 = value.x;
|
||||
r2c4 = value.y;
|
||||
r3c4 = value.z;
|
||||
r4c4 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Row1
|
||||
{
|
||||
get => new(r1c1, r1c2, r1c3, r1c3);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
r1c2 = value.y;
|
||||
r1c3 = value.z;
|
||||
r1c4 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Row2
|
||||
{
|
||||
get => new(r2c1, r2c2, r2c3, r2c3);
|
||||
set
|
||||
{
|
||||
r2c1 = value.x;
|
||||
r2c2 = value.y;
|
||||
r2c3 = value.z;
|
||||
r2c4 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Row3
|
||||
{
|
||||
get => new(r3c1, r3c2, r3c3, r3c3);
|
||||
set
|
||||
{
|
||||
r3c1 = value.x;
|
||||
r3c2 = value.y;
|
||||
r3c3 = value.z;
|
||||
r3c4 = value.w;
|
||||
}
|
||||
}
|
||||
public Float4 Row4
|
||||
{
|
||||
get => new(r4c1, r4c2, r4c3, r4c3);
|
||||
set
|
||||
{
|
||||
r4c1 = value.x;
|
||||
r4c2 = value.y;
|
||||
r4c3 = value.z;
|
||||
r4c4 = value.w;
|
||||
}
|
||||
}
|
||||
|
||||
public float r1c1, r2c1, r3c1, r4c1, r1c2, r2c2, r3c2, r4c2, r1c3, r2c3, r3c3, r4c3, r1c4, r2c4, r3c4, r4c4;
|
||||
|
||||
public Matrix4x4(float all) : this(all, all, all, all, all,
|
||||
all, all, all, all, all, all, all, all, all, all, all) { }
|
||||
public Matrix4x4(float r1c1, float r2c1, float r3c1, float r4c1, float r1c2, float r2c2, float r3c2,
|
||||
float r4c2, float r1c3, float r2c3, float r3c3, float r4c3, float r1c4, float r2c4, float r3c4, float r4c4)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
this.r3c1 = r3c1;
|
||||
this.r4c1 = r4c1;
|
||||
this.r1c2 = r1c2;
|
||||
this.r2c2 = r2c2;
|
||||
this.r3c2 = r3c2;
|
||||
this.r4c2 = r4c2;
|
||||
this.r1c3 = r1c3;
|
||||
this.r2c3 = r2c3;
|
||||
this.r3c3 = r3c3;
|
||||
this.r4c3 = r4c3;
|
||||
this.r1c4 = r1c4;
|
||||
this.r2c4 = r2c4;
|
||||
this.r3c4 = r3c4;
|
||||
this.r4c4 = r4c4;
|
||||
}
|
||||
public Matrix4x4(float[] nums) : this(nums[0], nums[1], nums[2], nums[3], nums[4], nums[5], nums[6],
|
||||
nums[7], nums[8], nums[9], nums[10], nums[11], nums[12], nums[13], nums[14], nums[15]) { }
|
||||
public Matrix4x4(int[] nums) : this(nums[0], nums[1], nums[2], nums[3], nums[4], nums[5], nums[6],
|
||||
nums[7], nums[8], nums[9], nums[10], nums[11], nums[12], nums[13], nums[14], nums[15]) { }
|
||||
public Matrix4x4(Fill<float> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||
fill(7), fill(8), fill(9), fill(10), fill(11), fill(12), fill(13), fill(14), fill(15)) { }
|
||||
public Matrix4x4(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||
fill(7), fill(8), fill(9), fill(10), fill(11), fill(12), fill(13), fill(14), fill(15)) { }
|
||||
public Matrix4x4(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], nums[0, 3], nums[1, 0],
|
||||
nums[1, 1], nums[1, 2], nums[1, 3], nums[2, 0], nums[2, 1], nums[2, 2], nums[2, 3], nums[3, 0],
|
||||
nums[3, 1], nums[3, 2], nums[3, 3]) { }
|
||||
public Matrix4x4(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], nums[0, 3], nums[1, 0],
|
||||
nums[1, 1], nums[1, 2], nums[1, 3], nums[2, 0], nums[2, 1], nums[2, 2], nums[2, 3], nums[3, 0],
|
||||
nums[3, 1], nums[3, 2], nums[3, 3]) { }
|
||||
public Matrix4x4(Fill2D<float> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
||||
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
||||
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
||||
public Matrix4x4(Fill2D<int> fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), fill(0, 3), fill(1, 0),
|
||||
fill(1, 1), fill(1, 2), fill(1, 3), fill(2, 0), fill(2, 1), fill(2, 2), fill(2, 3), fill(3, 0),
|
||||
fill(3, 1), fill(3, 2), fill(3, 3)) { }
|
||||
public Matrix4x4(Float4 c1, Float4 c2, Float4 c3, Float4 c4) : this(c1.x, c1.y, c1.z,
|
||||
c1.w, c2.x, c2.y, c2.z, c2.w, c3.x, c3.y, c3.z, c3.w, c4.x, c4.y, c4.z, c4.w) { }
|
||||
public Matrix4x4(Fill<Float4> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public Matrix4x4(Fill<Int4> fill) : this((IEnumerable<int>)fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public Matrix4x4(IEnumerable<float> c1, IEnumerable<float> c2, IEnumerable<float> c3, IEnumerable<float> c4)
|
||||
: this(c1.ToFill(), c2.ToFill(), c3.ToFill(), c4.ToFill()) { }
|
||||
public Matrix4x4(IEnumerable<int> c1, IEnumerable<int> c2, IEnumerable<int> c3, IEnumerable<int> c4)
|
||||
: this(c1.ToFill(), c2.ToFill(), c3.ToFill(), c4.ToFill()) { }
|
||||
public Matrix4x4(Fill<float> c1, Fill<float> c2, Fill<float> c3, Fill<float> c4) : this(c1(0), c1(1),
|
||||
c1(2), c1(3), c2(0), c2(1), c2(2), c2(3), c3(0), c3(1), c3(2), c3(3), c4(0), c4(1), c4(2), c4(3)) { }
|
||||
public Matrix4x4(Fill<int> c1, Fill<int> c2, Fill<int> c3, Fill<int> c4) : this(c1(0), c1(1),
|
||||
c1(2), c1(3), c2(0), c2(1), c2(2), c2(3), c3(0), c3(1), c3(2), c3(3), c4(0), c4(1), c4(2), c4(3)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
// It's definitely better than it was before. Trust me.
|
||||
switch ("r" + (r + 1) + "c" + (c + 1))
|
||||
{
|
||||
case "r1c1":
|
||||
r1c1 = value;
|
||||
break;
|
||||
|
||||
case "r2c1":
|
||||
r2c1 = value;
|
||||
break;
|
||||
|
||||
case "r3c1":
|
||||
r3c1 = value;
|
||||
break;
|
||||
|
||||
case "r4c1":
|
||||
r4c1 = value;
|
||||
break;
|
||||
|
||||
case "r1c2":
|
||||
r1c2 = value;
|
||||
break;
|
||||
|
||||
case "r2c2":
|
||||
r2c2 = value;
|
||||
break;
|
||||
|
||||
case "r3c2":
|
||||
r3c2 = value;
|
||||
break;
|
||||
|
||||
case "r4c2":
|
||||
r4c2 = value;
|
||||
break;
|
||||
|
||||
case "r1c3":
|
||||
r1c3 = value;
|
||||
break;
|
||||
|
||||
case "r2c3":
|
||||
r2c3 = value;
|
||||
break;
|
||||
|
||||
case "r3c3":
|
||||
r3c3 = value;
|
||||
break;
|
||||
|
||||
case "r4c3":
|
||||
r4c3 = value;
|
||||
break;
|
||||
|
||||
case "r1c4":
|
||||
r1c4 = value;
|
||||
break;
|
||||
|
||||
case "r2c4":
|
||||
r2c4 = value;
|
||||
break;
|
||||
|
||||
case "r3c4":
|
||||
r3c4 = value;
|
||||
break;
|
||||
|
||||
case "r4c4":
|
||||
r4c4 = value;
|
||||
break;
|
||||
|
||||
default:
|
||||
string @params = "";
|
||||
if (r < 0 || r > 2) @params += r;
|
||||
if (c < 0 || c > 2) @params += string.IsNullOrEmpty(@params) ? c : " and " + c;
|
||||
throw new IndexOutOfRangeException(@params);
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Int2 index]
|
||||
{
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
|
||||
public static Matrix4x4 Absolute(Matrix4x4 val) =>
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r3c1), Mathf.Absolute(val.r4c1),
|
||||
Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r3c2), Mathf.Absolute(val.r4c2),
|
||||
Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r2c3), Mathf.Absolute(val.r3c3), Mathf.Absolute(val.r4c2),
|
||||
Mathf.Absolute(val.r1c4), Mathf.Absolute(val.r2c4), Mathf.Absolute(val.r3c4), Mathf.Absolute(val.r4c4));
|
||||
public static Matrix4x4 Average(params Matrix4x4[] vals) => Sum(vals) / vals.Length;
|
||||
public static Matrix4x4 Ceiling(Matrix4x4 val) =>
|
||||
new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r2c1), Mathf.Ceiling(val.r3c1), Mathf.Ceiling(val.r4c1),
|
||||
Mathf.Ceiling(val.r1c2), Mathf.Ceiling(val.r2c2), Mathf.Ceiling(val.r3c2), Mathf.Ceiling(val.r4c2),
|
||||
Mathf.Ceiling(val.r1c3), Mathf.Ceiling(val.r2c3), Mathf.Ceiling(val.r3c3), Mathf.Ceiling(val.r4c2),
|
||||
Mathf.Ceiling(val.r1c4), Mathf.Ceiling(val.r2c4), Mathf.Ceiling(val.r3c4), Mathf.Ceiling(val.r4c4));
|
||||
public static Matrix4x4 Clamp(Matrix4x4 val, Matrix4x4 min, Matrix4x4 max) =>
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1),
|
||||
Mathf.Clamp(val.r3c1, min.r3c1, max.r3c1), Mathf.Clamp(val.r4c1, min.r4c1, max.r4c1),
|
||||
Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2), Mathf.Clamp(val.r2c2, min.r2c2, max.r2c2),
|
||||
Mathf.Clamp(val.r3c2, min.r3c2, max.r3c2), Mathf.Clamp(val.r4c2, min.r4c2, max.r4c2),
|
||||
Mathf.Clamp(val.r1c3, min.r1c3, max.r1c3), Mathf.Clamp(val.r2c3, min.r2c3, max.r2c3),
|
||||
Mathf.Clamp(val.r3c3, min.r3c3, max.r3c3), Mathf.Clamp(val.r4c3, min.r4c3, max.r4c3),
|
||||
Mathf.Clamp(val.r1c4, min.r1c4, max.r1c4), Mathf.Clamp(val.r2c4, min.r2c4, max.r2c4),
|
||||
Mathf.Clamp(val.r3c4, min.r3c4, max.r3c4), Mathf.Clamp(val.r4c4, min.r4c4, max.r4c4));
|
||||
public static Matrix4x4 Divide(Matrix4x4 num, params Matrix4x4[] vals)
|
||||
{
|
||||
foreach (Matrix4x4 m in vals) num /= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix4x4 Floor(Matrix4x4 val) =>
|
||||
new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r2c1), Mathf.Floor(val.r3c1), Mathf.Floor(val.r4c1),
|
||||
Mathf.Floor(val.r1c2), Mathf.Floor(val.r2c2), Mathf.Floor(val.r3c2), Mathf.Floor(val.r4c2),
|
||||
Mathf.Floor(val.r1c3), Mathf.Floor(val.r2c3), Mathf.Floor(val.r3c3), Mathf.Floor(val.r4c2),
|
||||
Mathf.Floor(val.r1c4), Mathf.Floor(val.r2c4), Mathf.Floor(val.r3c4), Mathf.Floor(val.r4c4));
|
||||
public static Matrix4x4 Lerp(Matrix4x4 a, Matrix4x4 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r2c1, b.r2c1, t, clamp),
|
||||
Mathf.Lerp(a.r3c1, b.r3c1, t, clamp), Mathf.Lerp(a.r4c1, b.r4c1, t, clamp),
|
||||
Mathf.Lerp(a.r1c2, b.r1c2, t, clamp), Mathf.Lerp(a.r2c2, b.r2c2, t, clamp),
|
||||
Mathf.Lerp(a.r3c2, b.r3c2, t, clamp), Mathf.Lerp(a.r4c2, b.r4c2, t, clamp),
|
||||
Mathf.Lerp(a.r1c3, b.r1c3, t, clamp), Mathf.Lerp(a.r2c3, b.r2c3, t, clamp),
|
||||
Mathf.Lerp(a.r3c3, b.r3c3, t, clamp), Mathf.Lerp(a.r4c3, b.r4c3, t, clamp),
|
||||
Mathf.Lerp(a.r1c4, b.r1c4, t, clamp), Mathf.Lerp(a.r2c4, b.r2c4, t, clamp),
|
||||
Mathf.Lerp(a.r3c4, b.r3c4, t, clamp), Mathf.Lerp(a.r4c4, b.r4c4, t, clamp));
|
||||
public static Matrix4x4 Median(params Matrix4x4[] vals)
|
||||
{
|
||||
float index = Mathf.Average(0, vals.Length - 1);
|
||||
Matrix4x4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static Matrix4x4 Product(params Matrix4x4[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Matrix4x4 val = Identity;
|
||||
foreach (Matrix4x4 m in vals) val *= m;
|
||||
return val;
|
||||
}
|
||||
public static Matrix4x4 Round(Matrix4x4 val) =>
|
||||
new(Mathf.Round(val.r1c1), Mathf.Round(val.r2c1), Mathf.Round(val.r3c1), Mathf.Round(val.r4c1),
|
||||
Mathf.Round(val.r1c2), Mathf.Round(val.r2c2), Mathf.Round(val.r3c2), Mathf.Round(val.r4c2),
|
||||
Mathf.Round(val.r1c3), Mathf.Round(val.r2c3), Mathf.Round(val.r3c3), Mathf.Round(val.r4c2),
|
||||
Mathf.Round(val.r1c4), Mathf.Round(val.r2c4), Mathf.Round(val.r3c4), Mathf.Round(val.r4c4));
|
||||
public static Matrix4x4 Subtract(Matrix4x4 num, params Matrix4x4[] vals)
|
||||
{
|
||||
foreach (Matrix4x4 m in vals) num -= m;
|
||||
return num;
|
||||
}
|
||||
public static Matrix4x4 Sum(params Matrix4x4[] vals)
|
||||
{
|
||||
Matrix4x4 val = Zero;
|
||||
foreach (Matrix4x4 m in vals) val += m;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (float[] r1c1s, float[] r2c1s, float[] r3c1s, float[] r4c1s, float[] r1c2s, float[] r2c2s,
|
||||
float[] r3c2s, float[] r4c2s, float[] r1c3s, float[] r2c3s, float[] r3c3s, float[] r4c3s, float[] r1c4s,
|
||||
float[] r2c4s, float[] r3c4s, float[] r4c4s) SplitArray(params Matrix4x4[] vals)
|
||||
{
|
||||
float[] r1c1s = new float[vals.Length], r2c1s = new float[vals.Length], r3c1s = new float[vals.Length],
|
||||
r4c1s = new float[vals.Length], r1c2s = new float[vals.Length], r2c2s = new float[vals.Length],
|
||||
r3c2s = new float[vals.Length], r4c2s = new float[vals.Length], r1c3s = new float[vals.Length],
|
||||
r2c3s = new float[vals.Length], r3c3s = new float[vals.Length], r4c3s = new float[vals.Length],
|
||||
r1c4s = new float[vals.Length], r2c4s = new float[vals.Length], r3c4s = new float[vals.Length],
|
||||
r4c4s = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
r1c1s[i] = vals[i].r1c1;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r3c1s[i] = vals[i].r3c1;
|
||||
r4c1s[i] = vals[i].r4c1;
|
||||
r1c2s[i] = vals[i].r1c2;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
r3c2s[i] = vals[i].r3c2;
|
||||
r4c2s[i] = vals[i].r4c2;
|
||||
r1c3s[i] = vals[i].r1c3;
|
||||
r2c3s[i] = vals[i].r2c3;
|
||||
r3c3s[i] = vals[i].r3c3;
|
||||
r4c3s[i] = vals[i].r4c3;
|
||||
r4c4s[i] = vals[i].r4c4;
|
||||
}
|
||||
return (r1c1s, r2c1s, r3c1s, r4c1s, r1c2s, r2c2s, r3c2s, r4c2s,
|
||||
r1c3s, r2c3s, r3c3s, r4c3s, r1c4s, r2c4s, r3c4s, r4c4s);
|
||||
}
|
||||
|
||||
public Matrix4x4 Adjugate()
|
||||
{
|
||||
Matrix4x4 dets = new();
|
||||
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;
|
||||
}
|
||||
public float Determinant()
|
||||
{
|
||||
Matrix3x3[,] minors = Minors();
|
||||
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[1, 0].Determinant()) +
|
||||
(r1c3 * minors[2, 0].Determinant()) - (r1c4 * minors[3, 0].Determinant());
|
||||
}
|
||||
public Matrix4x4 Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
}
|
||||
public Matrix3x3[,] Minors() => new Matrix3x3[,]
|
||||
{
|
||||
{
|
||||
new(r2c2, r3c2, r4c2, r2c3, r3c3, r4c3, r2c4, r3c4, r4c4),
|
||||
new(r2c1, r3c1, r4c1, r2c3, r3c3, r4c3, r2c4, r3c4, r4c4),
|
||||
new(r2c1, r3c1, r4c1, r2c2, r3c2, r4c2, r2c4, r3c4, r4c4),
|
||||
new(r2c1, r3c1, r4c1, r2c2, r3c2, r4c2, r2c3, r3c3, r4c3)
|
||||
},
|
||||
{
|
||||
new(r1c2, r3c2, r4c2, r1c3, r3c3, r4c3, r1c4, r3c4, r4c4),
|
||||
new(r1c1, r3c1, r4c1, r1c3, r3c3, r4c3, r1c4, r3c4, r4c4),
|
||||
new(r1c1, r3c1, r4c1, r1c2, r3c2, r4c2, r1c4, r3c4, r4c4),
|
||||
new(r1c1, r3c1, r4c1, r1c2, r3c2, r4c2, r1c3, r3c3, r4c3)
|
||||
},
|
||||
{
|
||||
new(r1c2, r2c2, r4c2, r1c3, r2c3, r4c3, r1c4, r2c4, r4c4),
|
||||
new(r1c1, r2c1, r4c1, r1c3, r2c3, r4c3, r1c4, r2c4, r4c4),
|
||||
new(r1c1, r2c1, r4c1, r1c2, r2c2, r4c2, r1c4, r2c4, r4c4),
|
||||
new(r1c1, r2c1, r4c1, r1c2, r2c2, r4c2, r1c3, r2c3, r4c3)
|
||||
},
|
||||
{
|
||||
new(r1c2, r2c2, r3c2, r1c3, r2c3, r3c3, r1c4, r2c4, r3c4),
|
||||
new(r1c1, r2c1, r3c1, r1c3, r2c3, r3c3, r1c4, r2c4, r3c4),
|
||||
new(r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c4, r2c4, r3c4),
|
||||
new(r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c3, r2c3, r3c3)
|
||||
}
|
||||
};
|
||||
public Matrix4x4 Transpose() => new(new[,]
|
||||
{
|
||||
{ r1c1, r2c1, r3c1, r4c1 },
|
||||
{ r1c2, r2c2, r3c2, r4c2 },
|
||||
{ r1c3, r2c3, r3c3, r4c3 },
|
||||
{ r1c4, r2c4, r3c4, r4c4 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix4x4)) return base.Equals(obj);
|
||||
return Equals((Matrix4x4)obj);
|
||||
}
|
||||
public bool Equals(Matrix4x4 other) =>
|
||||
r1c1 == other.r1c1 && r2c1 == other.r2c1 && r3c1 == other.r3c1 && r4c1 == other.r4c1 &&
|
||||
r1c2 == other.r1c2 && r2c2 == other.r2c2 && r3c2 == other.r3c2 && r4c2 == other.r4c2 &&
|
||||
r1c3 == other.r1c3 && r2c3 == other.r2c3 && r3c3 == other.r3c3 && r4c3 == other.r4c3 &&
|
||||
r1c4 == other.r1c4 && r2c3 == other.r2c4 && r3c4 == other.r3c4 && r4c4 == other.r4c4;
|
||||
public override int GetHashCode() =>
|
||||
r1c1.GetHashCode() ^ r2c1.GetHashCode() ^ r3c1.GetHashCode() ^ r4c1.GetHashCode() ^
|
||||
r1c2.GetHashCode() ^ r2c2.GetHashCode() ^ r3c2.GetHashCode() ^ r4c2.GetHashCode() ^
|
||||
r1c3.GetHashCode() ^ r2c3.GetHashCode() ^ r3c3.GetHashCode() ^ r4c3.GetHashCode() ^
|
||||
r1c4.GetHashCode() ^ r2c4.GetHashCode() ^ r3c4.GetHashCode() ^ r4c4.GetHashCode();
|
||||
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());
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return r1c1;
|
||||
yield return r2c1;
|
||||
yield return r3c1;
|
||||
yield return r4c1;
|
||||
yield return r1c2;
|
||||
yield return r2c2;
|
||||
yield return r3c2;
|
||||
yield return r4c2;
|
||||
yield return r1c3;
|
||||
yield return r2c3;
|
||||
yield return r3c3;
|
||||
yield return r4c3;
|
||||
yield return r1c4;
|
||||
yield return r2c4;
|
||||
yield return r3c4;
|
||||
yield return r4c4;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[]
|
||||
{
|
||||
r1c1, r2c1, r3c1, r4c1,
|
||||
r1c2, r2c2, r3c2, r4c2,
|
||||
r1c3, r2c3, r3c3, r4c3,
|
||||
r1c4, r2c4, r3c4, r4c4
|
||||
};
|
||||
public float[,] ToArray2D() => new[,]
|
||||
{
|
||||
{ r1c1, r1c2, r1c3, r1c4 },
|
||||
{ r2c1, r2c2, r2c3, r2c4 },
|
||||
{ r3c1, r3c2, r3c3, r3c4 },
|
||||
{ r4c1, r4c2, r4c3, r4c4 }
|
||||
};
|
||||
public Dictionary<Int2, float> ToDictionary()
|
||||
{
|
||||
Dictionary<Int2, float> dict = new();
|
||||
float[] arr = ToArray();
|
||||
for (int i = 0; i < arr.Length; i++) dict.Add(new(i % 4, i / 4), arr[i]);
|
||||
return dict;
|
||||
}
|
||||
public Fill<float> ToFill() => ToFillExtension.ToFill(this);
|
||||
public Fill2D<float> ToFill2D()
|
||||
{
|
||||
Matrix4x4 @this = this;
|
||||
return (x, y) => @this[x, y];
|
||||
}
|
||||
public List<float> ToList() => new()
|
||||
{
|
||||
r1c1, r2c1, r3c1, r4c1,
|
||||
r1c2, r2c2, r3c2, r4c2,
|
||||
r1c3, r2c3, r3c3, r4c3,
|
||||
r1c4, r2c4, r3c4, r4c4
|
||||
};
|
||||
|
||||
public static Matrix4x4 operator +(Matrix4x4 a, Matrix4x4 b) =>
|
||||
new(a.r1c1 + b.r1c1, a.r2c1 + b.r2c1, a.r3c1 + b.r3c1, a.r4c1 + b.r4c1,
|
||||
a.r1c2 + b.r1c2, a.r2c2 + b.r2c2, a.r3c2 + b.r3c2, a.r4c2 + b.r4c2,
|
||||
a.r1c3 + b.r1c3, a.r2c3 + b.r2c3, a.r3c3 + b.r3c3, a.r4c3 + b.r4c3,
|
||||
a.r1c4 + b.r1c4, a.r2c4 + b.r2c4, a.r3c4 + b.r3c4, a.r4c4 + b.r4c4);
|
||||
public static Matrix4x4 operator -(Matrix4x4 m) => m.Inverse();
|
||||
public static Matrix4x4 operator -(Matrix4x4 a, Matrix4x4 b) =>
|
||||
new(a.r1c1 - b.r1c1, a.r2c1 - b.r2c1, a.r3c1 - b.r3c1, a.r4c1 - b.r4c1,
|
||||
a.r1c2 - b.r1c2, a.r2c2 - b.r2c2, a.r3c2 - b.r3c2, a.r4c2 - b.r4c2,
|
||||
a.r1c3 - b.r1c3, a.r2c3 - b.r2c3, a.r3c3 - b.r3c3, a.r4c3 - b.r4c3,
|
||||
a.r1c4 - b.r1c4, a.r2c4 - b.r2c4, a.r3c4 - b.r3c4, a.r4c4 - b.r4c4);
|
||||
public static Matrix4x4 operator *(Matrix4x4 a, float b) =>
|
||||
new(a.r1c1 * b, a.r2c1 * b, a.r3c1 * b, a.r4c1 * b,
|
||||
a.r1c2 * b, a.r2c2 * b, a.r3c2 * b, a.r4c2 * b,
|
||||
a.r1c3 * b, a.r2c3 * b, a.r3c3 * b, a.r4c3 * b,
|
||||
a.r1c4 * b, a.r2c4 * b, a.r3c4 * b, a.r4c4 * b);
|
||||
public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b) => new(new[,]
|
||||
{
|
||||
{ Float4.Dot(a.Row1, b.Column1), Float4.Dot(a.Row1, b.Column2),
|
||||
Float4.Dot(a.Row1, b.Column3), Float4.Dot(a.Row1, b.Column4) },
|
||||
{ Float4.Dot(a.Row2, b.Column1), Float4.Dot(a.Row2, b.Column2),
|
||||
Float4.Dot(a.Row2, b.Column3), Float4.Dot(a.Row2, b.Column4) },
|
||||
{ Float4.Dot(a.Row3, b.Column1), Float4.Dot(a.Row3, b.Column2),
|
||||
Float4.Dot(a.Row3, b.Column3), Float4.Dot(a.Row3, b.Column4) },
|
||||
{ Float4.Dot(a.Row4, b.Column1), Float4.Dot(a.Row4, b.Column2),
|
||||
Float4.Dot(a.Row4, b.Column3), Float4.Dot(a.Row4, b.Column4) }
|
||||
});
|
||||
public static Matrix4x4 operator /(Matrix4x4 a, float b) =>
|
||||
new(a.r1c1 / b, a.r2c1 / b, a.r3c1 / b, a.r4c1 / b,
|
||||
a.r1c2 / b, a.r2c2 / b, a.r3c2 / b, a.r4c2 / b,
|
||||
a.r1c3 / b, a.r2c3 / b, a.r3c3 / b, a.r4c3 / b,
|
||||
a.r1c4 / b, a.r2c4 / b, a.r3c4 / b, a.r4c4 / b);
|
||||
public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b) => a * b.Inverse();
|
||||
public static Matrix4x4 operator ^(Matrix4x4 a, Matrix4x4 b) => // Single number multiplication
|
||||
new(a.r1c1 * b.r1c1, a.r2c1 * b.r2c1, a.r3c1 * b.r3c1, a.r4c1 * b.r4c1,
|
||||
a.r1c2 * b.r1c2, a.r2c2 * b.r2c2, a.r3c2 * b.r3c2, a.r4c2 * b.r4c2,
|
||||
a.r1c3 * b.r1c3, a.r2c3 * b.r2c3, a.r3c3 * b.r3c3, a.r4c3 * b.r4c3,
|
||||
a.r1c4 * b.r1c4, a.r2c4 * b.r2c4, a.r3c4 * b.r3c4, 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)
|
||||
{
|
||||
Matrix4x4 res = Zero, identity = Identity;
|
||||
for (int r = 0; r < 4; r++) for (int c = 0; c < 4; c++)
|
||||
res[c, r] = m.Size.x < c && m.Size.y < r ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static implicit operator Matrix4x4(Matrix2x2 m)
|
||||
{
|
||||
Matrix4x4 identity = Identity;
|
||||
return new(new[,]
|
||||
{
|
||||
{ m.r1c1, m.r1c2, identity.r1c3, identity.r1c4 },
|
||||
{ m.r2c1, m.r2c2, identity.r2c3, identity.r2c4 },
|
||||
{ identity.r3c1, identity.r3c2, identity.r3c3, identity.r3c4 },
|
||||
{ identity.r4c1, identity.r4c2, identity.r4c3, identity.r4c4 }
|
||||
});
|
||||
}
|
||||
public static implicit operator Matrix4x4(Matrix3x3 m)
|
||||
{
|
||||
Matrix4x4 identity = Identity;
|
||||
return new(new[,]
|
||||
{
|
||||
{ m.r1c1, m.r1c2, m.r1c3, identity.r1c4 },
|
||||
{ m.r2c1, m.r2c2, m.r2c3, identity.r2c4 },
|
||||
{ m.r3c1, m.r3c2, m.r3c3, identity.r3c4 },
|
||||
{ identity.r4c1, identity.r4c2, identity.r4c3, identity.r4c4 }
|
||||
});
|
||||
}
|
||||
}
|
||||
158
Nerd_STF/Mathematics/Algebra/Vector2d.cs
Normal file
158
Nerd_STF/Mathematics/Algebra/Vector2d.cs
Normal file
@ -0,0 +1,158 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
{
|
||||
public static Vector2d Down => new(Angle.Down);
|
||||
public static Vector2d Left => new(Angle.Left);
|
||||
public static Vector2d Right => new(Angle.Right);
|
||||
public static Vector2d Up => new(Angle.Up);
|
||||
|
||||
public static Vector2d One => new(Angle.Zero);
|
||||
public static Vector2d Zero => new(Angle.Zero, 0);
|
||||
|
||||
public Vector2d Inverse => new(-theta, magnitude);
|
||||
public Vector2d Normalized => new(theta, 1);
|
||||
|
||||
public Angle theta;
|
||||
public float magnitude;
|
||||
|
||||
public Vector2d(Angle theta, float mag = 1)
|
||||
{
|
||||
this.theta = theta;
|
||||
magnitude = mag;
|
||||
}
|
||||
public Vector2d(float theta, Angle.Type rotType, float mag = 1) : this(new(theta, rotType), mag) { }
|
||||
|
||||
public static Vector2d Absolute(Vector2d val) => new(Angle.Absolute(val.theta), Mathf.Absolute(val.magnitude));
|
||||
public static Vector2d Average(params Vector2d[] vals)
|
||||
{
|
||||
(Angle[] thetas, float[] Mags) = SplitArray(vals);
|
||||
return new(Angle.Average(thetas), Mathf.Average(Mags));
|
||||
}
|
||||
public static Vector2d Ceiling(Vector2d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Ceiling(val.theta, angleRound), Mathf.Ceiling(val.magnitude));
|
||||
public static Vector2d ClampMagnitude(Vector2d val, float minMag, float maxMag)
|
||||
{
|
||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||
float mag = Mathf.Clamp(val.magnitude, minMag, maxMag);
|
||||
return new(val.theta, mag);
|
||||
}
|
||||
public static Vector3d Cross(Vector2d a, Vector2d b, bool normalized = false) =>
|
||||
Float2.Cross(a.ToXYZ(), b.ToXYZ(), normalized).ToVector();
|
||||
public static Vector2d Divide(Vector2d num, params Vector2d[] vals)
|
||||
{
|
||||
foreach (Vector2d v in vals) num /= v;
|
||||
return num;
|
||||
}
|
||||
public static float Dot(Vector2d a, Vector2d b) => Float2.Dot(a.ToXYZ(), b.ToXYZ());
|
||||
public static float Dot(params Vector2d[] vals)
|
||||
{
|
||||
Float2[] floats = new Float2[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++) floats[i] = vals[i].ToXYZ();
|
||||
return Float2.Dot(floats);
|
||||
}
|
||||
public static Vector2d Floor(Vector2d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Floor(val.theta, angleRound), Mathf.Floor(val.magnitude));
|
||||
public static Vector2d Lerp(Vector2d a, Vector2d b, float t, bool clamp = true) =>
|
||||
new(Angle.Lerp(a.theta, b.theta, t, clamp), Mathf.Lerp(a.magnitude, b.magnitude, t, clamp));
|
||||
public static Vector2d Median(params Vector2d[] vals)
|
||||
{
|
||||
float index = Mathf.Average(0, vals.Length - 1);
|
||||
Vector2d valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static Vector2d Max(params Vector2d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector2d val = vals[0];
|
||||
foreach (Vector2d f in vals) val = f > val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Vector2d Min(params Vector2d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector2d val = vals[0];
|
||||
foreach (Vector2d f in vals) val = f < val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Vector2d Product(params Vector2d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector2d val = One;
|
||||
foreach (Vector2d v in vals) val *= v;
|
||||
return val;
|
||||
}
|
||||
public static Vector2d Round(Vector2d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Round(val.theta, angleRound), Mathf.Round(val.magnitude));
|
||||
public static Vector2d Subtract(Vector2d num, params Vector2d[] vals)
|
||||
{
|
||||
foreach (Vector2d v in vals) num -= v;
|
||||
return num;
|
||||
}
|
||||
public static Vector2d Sum(params Vector2d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector2d val = One;
|
||||
foreach (Vector2d v in vals) val += v;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (Angle[] Rots, float[] Mags) SplitArray(params Vector2d[] vals)
|
||||
{
|
||||
Angle[] rots = new Angle[vals.Length];
|
||||
float[] mags = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
rots[i] = vals[i].theta;
|
||||
mags[i] = vals[i].magnitude;
|
||||
}
|
||||
return (rots, mags);
|
||||
}
|
||||
|
||||
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 = Angle.Type.Degrees) => 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 Float2 ToXYZ() => new(Mathf.Cos(theta));
|
||||
|
||||
public static Vector2d operator +(Vector2d a, Vector2d b) => new(a.theta + b.theta, a.magnitude + b.magnitude);
|
||||
public static Vector2d operator -(Vector2d v) => v.Inverse;
|
||||
public static Vector2d operator -(Vector2d a, Vector2d b) => new(a.theta - b.theta, a.magnitude - b.magnitude);
|
||||
public static Vector2d operator *(Vector2d a, Angle b) => new(a.theta * b, a.magnitude);
|
||||
public static Vector2d operator *(Vector2d a, float b) => new(a.theta, a.magnitude * b);
|
||||
public static Vector2d operator *(Vector2d a, Vector2d b) => new(a.theta * b.theta, a.magnitude * b.magnitude);
|
||||
public static Vector2d operator *(Vector2d a, Matrix b) => (Vector2d)((Matrix)a * b);
|
||||
public static Vector2d operator /(Vector2d a, Angle b) => new(a.theta / b, a.magnitude);
|
||||
public static Vector2d operator /(Vector2d a, float b) => new(a.theta, a.magnitude / b);
|
||||
public static Vector2d operator /(Vector2d a, Vector2d b) => new(a.theta / b.theta, a.magnitude / b.magnitude);
|
||||
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;
|
||||
public static bool operator <=(Vector2d a, Vector2d b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Vector2d(Complex val) => val.ToVector();
|
||||
public static explicit operator Vector2d(Float2 val) => val.ToVector();
|
||||
public static explicit operator Vector2d(Float3 val) => (Vector2d)val.ToVector();
|
||||
public static explicit operator Vector2d(Int2 val) => val.ToVector();
|
||||
public static explicit operator Vector2d(Int3 val) => (Vector2d)val.ToVector();
|
||||
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);
|
||||
}
|
||||
200
Nerd_STF/Mathematics/Algebra/Vector3d.cs
Normal file
200
Nerd_STF/Mathematics/Algebra/Vector3d.cs
Normal file
@ -0,0 +1,200 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
{
|
||||
public static Vector3d Back => new(Angle.Zero, Angle.Up);
|
||||
public static Vector3d Down => new(Angle.Down, Angle.Zero);
|
||||
public static Vector3d Forward => new(Angle.Zero, Angle.Down);
|
||||
public static Vector3d Left => new(Angle.Left, Angle.Zero);
|
||||
public static Vector3d Right => new(Angle.Right, Angle.Zero);
|
||||
public static Vector3d Up => new(Angle.Up, Angle.Zero);
|
||||
|
||||
public static Vector3d One => new(Angle.Zero);
|
||||
public static Vector3d Zero => new(Angle.Zero, 0);
|
||||
|
||||
public Vector3d Inverse => new(-yaw, -pitch, magnitude);
|
||||
public Vector3d Normalized => new(yaw, pitch, 1);
|
||||
|
||||
public Angle yaw, pitch;
|
||||
public float magnitude;
|
||||
|
||||
public Vector3d(Angle allRot, float mag = 1) : this(allRot, allRot, mag) { }
|
||||
public Vector3d(float allRot, Angle.Type rotType, float mag = 1) : this(allRot, allRot, rotType, mag) { }
|
||||
public Vector3d(Angle yaw, Angle pitch, float mag = 1)
|
||||
{
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
magnitude = mag;
|
||||
}
|
||||
public Vector3d(float yaw, float pitch, Angle.Type rotType, float mag = 1)
|
||||
: this(new Angle(yaw, rotType), new(pitch, rotType), mag) { }
|
||||
public Vector3d(Float2 rots, Angle.Type rotType, float mag = 1) : this(rots.x, rots.y, rotType, mag) { }
|
||||
public Vector3d(Fill<Angle> fill, float mag = 1) : this(fill(0), fill(1), mag) { }
|
||||
public Vector3d(Fill<float> fill, Angle.Type rotType, float mag = 1) : this(fill(0), fill(1), rotType, mag) { }
|
||||
|
||||
public Angle this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
0 => yaw,
|
||||
1 => pitch,
|
||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||
};
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
yaw = value;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
pitch = value;
|
||||
break;
|
||||
|
||||
default: throw new IndexOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3d Absolute(Vector3d val) => new(Angle.Absolute(val.yaw), Angle.Absolute(val.pitch),
|
||||
Mathf.Absolute(val.magnitude));
|
||||
public static Vector3d Average(params Vector3d[] vals)
|
||||
{
|
||||
(Angle[] Thetas, Angle[] Phis, float[] Mags) = SplitArray(vals);
|
||||
return new(Angle.Average(Thetas), Angle.Average(Phis), Mathf.Average(Mags));
|
||||
}
|
||||
public static Vector3d Ceiling(Vector3d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Ceiling(val.yaw, angleRound), Angle.Ceiling(val.pitch, angleRound),
|
||||
Mathf.Ceiling(val.magnitude));
|
||||
public static Vector3d ClampMagnitude(Vector3d val, float minMag, float maxMag)
|
||||
{
|
||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||
float mag = Mathf.Clamp(val.magnitude, minMag, maxMag);
|
||||
return new(val.yaw, val.pitch, mag);
|
||||
}
|
||||
public static Vector3d Cross(Vector3d a, Vector3d b, bool normalized = false) =>
|
||||
Float3.Cross(a.ToXYZ(), b.ToXYZ(), normalized).ToVector();
|
||||
public static Vector3d Divide(Vector3d num, params Vector3d[] vals)
|
||||
{
|
||||
foreach (Vector3d v in vals) num /= v;
|
||||
return num;
|
||||
}
|
||||
public static float Dot(Vector3d a, Vector3d b) => Float3.Dot(a.ToXYZ(), b.ToXYZ());
|
||||
public static float Dot(params Vector3d[] vals)
|
||||
{
|
||||
Float3[] floats = new Float3[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++) floats[i] = vals[i].ToXYZ();
|
||||
return Float3.Dot(floats);
|
||||
}
|
||||
public static Vector3d Floor(Vector3d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Floor(val.yaw, angleRound), Angle.Floor(val.pitch, angleRound), Mathf.Floor(val.magnitude));
|
||||
public static Vector3d Lerp(Vector3d a, Vector3d b, float t, bool clamp = true) =>
|
||||
new(Angle.Lerp(a.yaw, b.yaw, t, clamp), Angle.Lerp(a.pitch, b.pitch, t, clamp),
|
||||
Mathf.Lerp(a.magnitude, b.magnitude, t, clamp));
|
||||
public static Vector3d Median(params Vector3d[] vals)
|
||||
{
|
||||
float index = Mathf.Average(0, vals.Length - 1);
|
||||
Vector3d valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static Vector3d Max(params Vector3d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector3d val = vals[0];
|
||||
foreach (Vector3d f in vals) val = f > val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Vector3d Min(params Vector3d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector3d val = vals[0];
|
||||
foreach (Vector3d f in vals) val = f < val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Vector3d Product(params Vector3d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector3d val = One;
|
||||
foreach (Vector3d v in vals) val *= v;
|
||||
return val;
|
||||
}
|
||||
public static Vector3d Round(Vector3d val, Angle.Type angleRound = Angle.Type.Degrees) =>
|
||||
new(Angle.Round(val.yaw, angleRound), Angle.Round(val.pitch, angleRound), Mathf.Round(val.magnitude));
|
||||
public static Vector3d Subtract(Vector3d num, params Vector3d[] vals)
|
||||
{
|
||||
foreach (Vector3d v in vals) num -= v;
|
||||
return num;
|
||||
}
|
||||
public static Vector3d Sum(params Vector3d[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Vector3d val = One;
|
||||
foreach (Vector3d v in vals) val += v;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (Angle[] Thetas, Angle[] Phis, float[] Mags) SplitArray(params Vector3d[] vals)
|
||||
{
|
||||
Angle[] yaws = new Angle[vals.Length], pitchs = 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;
|
||||
mags[i] = vals[i].magnitude;
|
||||
}
|
||||
return (yaws, pitchs, 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 string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) =>
|
||||
"Mag: " + magnitude.ToString(provider) + " Theta: " + yaw.ToString(provider, outputType) +
|
||||
" Phi: " + 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 static Vector3d operator +(Vector3d a, Vector3d b) => new(a.yaw + b.yaw, a.pitch + b.pitch,
|
||||
a.magnitude + b.magnitude);
|
||||
public static Vector3d operator -(Vector3d v) => v.Inverse;
|
||||
public static Vector3d operator -(Vector3d a, Vector3d b) => new(a.yaw - b.yaw, a.pitch - b.pitch,
|
||||
a.magnitude - b.magnitude);
|
||||
public static Vector3d operator *(Vector3d a, Angle b) => new(a.yaw * b, a.pitch * b, a.magnitude);
|
||||
public static Vector3d operator *(Vector3d a, float b) => new(a.yaw, a.pitch, a.magnitude * b);
|
||||
public static Vector3d operator *(Vector3d a, Vector3d b) => new(a.yaw * b.yaw, a.pitch * b.pitch,
|
||||
a.magnitude * b.magnitude);
|
||||
public static Vector3d operator *(Vector3d a, Matrix b) => (Vector3d)((Matrix)a * b);
|
||||
public static Vector3d operator /(Vector3d a, Angle b) => new(a.yaw / b, a.pitch / b, a.magnitude);
|
||||
public static Vector3d operator /(Vector3d a, float b) => new(a.yaw, a.pitch, a.magnitude / b);
|
||||
public static Vector3d operator /(Vector3d a, Vector3d b) => new(a.yaw / b.yaw, a.pitch / b.pitch,
|
||||
a.magnitude / b.magnitude);
|
||||
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;
|
||||
public static bool operator <=(Vector3d a, Vector3d b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Vector3d(Complex val) => val.ToVector();
|
||||
public static explicit operator Vector3d(Float2 val) => val.ToVector();
|
||||
public static explicit operator Vector3d(Float3 val) => val.ToVector();
|
||||
public static explicit operator Vector3d(Int2 val) => val.ToVector();
|
||||
public static explicit operator Vector3d(Int3 val) => val.ToVector();
|
||||
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);
|
||||
}
|
||||
@ -2,6 +2,11 @@
|
||||
|
||||
public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
{
|
||||
public static Angle Down => new(270);
|
||||
public static Angle Left => new(180);
|
||||
public static Angle Right => new(0);
|
||||
public static Angle Up => new(90);
|
||||
|
||||
public static Angle Full => new(360);
|
||||
public static Angle Half => new(180);
|
||||
public static Angle One => new(1);
|
||||
@ -47,14 +52,18 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
|
||||
public static Angle Absolute(Angle val) => new(Mathf.Absolute(val.p_deg));
|
||||
public static Angle Average(params Angle[] vals) => new(Mathf.Average(SplitArray(Type.Degrees, vals)));
|
||||
public static Angle Ceiling(Angle val, Type type = Type.Degrees) => new(Mathf.Ceiling(val.ValueFromType(type)));
|
||||
public static Angle Ceiling(Angle val, Type type = Type.Degrees) =>
|
||||
new(Mathf.Ceiling(val.ValueFromType(type)), type);
|
||||
public static Angle Clamp(Angle val, Angle min, Angle max) => new(Mathf.Clamp(val.p_deg, min.p_deg, max.p_deg));
|
||||
public static Angle Floor(Angle val, Type type = Type.Degrees) => new(Mathf.Floor(val.ValueFromType(type)));
|
||||
public static Angle Floor(Angle val, Type type = Type.Degrees) =>
|
||||
new(Mathf.Floor(val.ValueFromType(type)), type);
|
||||
public static Angle Lerp(Angle a, Angle b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.p_deg, b.p_deg, t, clamp));
|
||||
public static Angle Max(params Angle[] vals) => new(Mathf.Max(SplitArray(Type.Degrees, vals)));
|
||||
public static Angle Median(params Angle[] vals) => new(Mathf.Median(SplitArray(Type.Degrees, vals)));
|
||||
public static Angle Min(params Angle[] vals) => new(Mathf.Min(SplitArray(Type.Degrees, vals)));
|
||||
public static Angle Round(Angle val, Type type = Type.Degrees) =>
|
||||
new(Mathf.Floor(val.ValueFromType(type)), type);
|
||||
|
||||
public static float[] SplitArray(Type outputType, params Angle[] vals)
|
||||
{
|
||||
@ -76,7 +85,7 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
public int CompareTo(Angle other) => p_deg.CompareTo(other.p_deg);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Angle)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Angle)) return base.Equals(obj);
|
||||
return Equals((Angle)obj);
|
||||
}
|
||||
public bool Equals(Angle other) => p_deg == other.p_deg;
|
||||
|
||||
@ -18,11 +18,11 @@ public static class Calculus
|
||||
(equ(x + DefaultStep) - equ(x)) / step;
|
||||
|
||||
public static float GetIntegral(Equation equ, float lowerBound, float upperBound, float step = DefaultStep)
|
||||
{
|
||||
float val = 0;
|
||||
for (float x = lowerBound; x <= upperBound; x += step) val += equ(x) * step;
|
||||
return val;
|
||||
}
|
||||
{
|
||||
float val = 0;
|
||||
for (float x = lowerBound; x <= upperBound; x += step) val += equ(x) * step;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float GradientDescent(Equation equ, float initial, float rate, float stepCount = 1000,
|
||||
float step = DefaultStep)
|
||||
|
||||
@ -11,7 +11,7 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
public static Float2 Zero => new(0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y);
|
||||
public Float2 Normalized => this / Magnitude;
|
||||
public Float2 Normalized => this * Mathf.InverseSqrt(x * x + y * y);
|
||||
|
||||
public float x, y;
|
||||
|
||||
@ -72,7 +72,7 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
Float3.Cross(a, b, normalized);
|
||||
public static Float2 Divide(Float2 num, params Float2[] vals)
|
||||
{
|
||||
foreach (Float2 d in vals) num /= d;
|
||||
foreach (Float2 f in vals) num /= f;
|
||||
return num;
|
||||
}
|
||||
public static float Dot(Float2 a, Float2 b) => a.x * b.x + a.y * b.y;
|
||||
@ -80,10 +80,10 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
{
|
||||
if (vals.Length < 1) return 0;
|
||||
float x = 1, y = 1;
|
||||
foreach (Float2 d in vals)
|
||||
foreach (Float2 f in vals)
|
||||
{
|
||||
x *= d.x;
|
||||
y *= d.y;
|
||||
x *= f.x;
|
||||
y *= f.y;
|
||||
}
|
||||
return x + y;
|
||||
}
|
||||
@ -101,32 +101,34 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float2 val = vals[0];
|
||||
foreach (Float2 d in vals) val = d > val ? d : val;
|
||||
foreach (Float2 f in vals) val = f > val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Float2 Min(params Float2[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float2 val = vals[0];
|
||||
foreach (Float2 d in vals) val = d < val ? d : val;
|
||||
foreach (Float2 f in vals) val = f < val ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Float2 Product(params Float2[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float2 val = One;
|
||||
foreach (Float2 d in vals) val *= d;
|
||||
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 Float2 Subtract(Float2 num, params Float2[] vals)
|
||||
{
|
||||
foreach (Float2 d in vals) num -= d;
|
||||
foreach (Float2 f in vals) num -= f;
|
||||
return num;
|
||||
}
|
||||
public static Float2 Sum(params Float2[] vals)
|
||||
{
|
||||
Float2 val = Zero;
|
||||
foreach (Float2 d in vals) val += d;
|
||||
foreach (Float2 f in vals) val += f;
|
||||
return val;
|
||||
}
|
||||
|
||||
@ -144,7 +146,7 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
public int CompareTo(Float2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float2)) return false;
|
||||
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;
|
||||
@ -165,15 +167,24 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { x, y };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Float2 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { x, y };
|
||||
|
||||
public Vector2d ToVector() => new(new(Mathf.ArcTan(y / x), Angle.Type.Radians), Magnitude);
|
||||
|
||||
public static Float2 operator +(Float2 a, Float2 b) => new(a.x + b.x, a.y + b.y);
|
||||
public static Float2 operator -(Float2 d) => new(-d.x, -d.y);
|
||||
public static Float2 operator -(Float2 a, Float2 b) => new(a.x - b.x, a.y - b.y);
|
||||
public static Float2 operator *(Float2 a, Float2 b) => new(a.x * b.x, a.y * b.y);
|
||||
public static Float2 operator *(Float2 a, float b) => new(a.x * b, a.y * b);
|
||||
public static Float2 operator *(Float2 a, Matrix b) => (Float2)((Matrix)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);
|
||||
public static bool operator ==(Float2 a, Float2 b) => a.Equals(b);
|
||||
public static bool operator !=(Float2 a, Float2 b) => !a.Equals(b);
|
||||
public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0;
|
||||
@ -181,11 +192,15 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
public static bool operator >=(Float2 a, Float2 b) => a == b || a > b;
|
||||
public static bool operator <=(Float2 a, Float2 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float2(Complex val) => new(val.u, val.i);
|
||||
public static explicit operator Float2(Quaternion val) => new(val.u, val.i);
|
||||
public static explicit operator Float2(Float3 val) => new(val.x, val.y);
|
||||
public static explicit operator Float2(Float4 val) => new(val.x, val.y);
|
||||
public static implicit operator Float2(Int2 val) => new(val.x, val.y);
|
||||
public static explicit operator Float2(Int3 val) => new(val.x, val.y);
|
||||
public static explicit operator Float2(Int4 val) => new(val.x, val.y);
|
||||
public static explicit operator Float2(Matrix m) => new(m[0, 0], m[1, 0]);
|
||||
public static explicit operator Float2(Vector2d val) => val.ToXYZ();
|
||||
public static explicit operator Float2(Vert val) => new(val.position.x, val.position.y);
|
||||
public static implicit operator Float2(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Float2(Fill<int> fill) => new(fill);
|
||||
|
||||
@ -13,7 +13,7 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public static Float3 Zero => new(0, 0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
||||
public Float3 Normalized => this / Magnitude;
|
||||
public Float3 Normalized => this * Mathf.InverseSqrt(x * x + y * y + z * z);
|
||||
|
||||
public Float2 XY => new(x, y);
|
||||
public Float2 XZ => new(x, z);
|
||||
@ -138,6 +138,8 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, 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 Float3 Subtract(Float3 num, params Float3[] vals)
|
||||
{
|
||||
foreach (Float3 d in vals) num -= d;
|
||||
@ -165,7 +167,7 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public int CompareTo(Float3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float3)) return false;
|
||||
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;
|
||||
@ -187,15 +189,28 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { x, y, z };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Float3 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { x, y, z };
|
||||
|
||||
public Vector3d ToVector()
|
||||
{
|
||||
float mag = Magnitude;
|
||||
return new(new Angle(Mathf.ArcTan(y / x), Angle.Type.Radians), new(Mathf.ArcCos(z / mag), Angle.Type.Radians), mag);
|
||||
}
|
||||
|
||||
public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
public static Float3 operator -(Float3 d) => new(-d.x, -d.y, -d.z);
|
||||
public static Float3 operator -(Float3 a, Float3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
public static Float3 operator *(Float3 a, Float3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
public static Float3 operator *(Float3 a, float b) => new(a.x * b, a.y * b, a.z * b);
|
||||
public static Float3 operator *(Float3 a, Matrix b) => (Float3)((Matrix)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);
|
||||
public static bool operator ==(Float3 a, Float3 b) => a.Equals(b);
|
||||
public static bool operator !=(Float3 a, Float3 b) => !a.Equals(b);
|
||||
public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0;
|
||||
@ -203,11 +218,15 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public static bool operator >=(Float3 a, Float3 b) => a == b || a > b;
|
||||
public static bool operator <=(Float3 a, Float3 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float3(Complex val) => new(val.u, val.i, 0);
|
||||
public static explicit operator Float3(Quaternion val) => new(val.u, val.i, val.j);
|
||||
public static implicit operator Float3(Float2 val) => new(val.x, val.y, 0);
|
||||
public static explicit operator Float3(Float4 val) => new(val.x, val.y, val.z);
|
||||
public static implicit operator Float3(Int2 val) => new(val.x, val.y, 0);
|
||||
public static implicit operator Float3(Int3 val) => new(val.x, val.y, val.z);
|
||||
public static explicit operator Float3(Int4 val) => new(val.x, val.y, val.z);
|
||||
public static explicit operator Float3(Matrix m) => new(m[0, 0], m[1, 0], m[2, 0]);
|
||||
public static explicit operator Float3(Vector2d val) => val.ToXYZ();
|
||||
public static implicit operator Float3(Vert val) => new(val.position.x, val.position.y, val.position.z);
|
||||
public static explicit operator Float3(RGBA val) => new(val.R, val.G, val.B);
|
||||
public static explicit operator Float3(HSVA val) => new(val.H.Normalized, val.S, val.V);
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGroup<float>
|
||||
{
|
||||
public static Float4 Back => new(0, 0, -1, 0);
|
||||
public static Float4 Deep => new(0, 0, 0, -1);
|
||||
public static Float4 Down => new(0, -1, 0, 0);
|
||||
public static Float4 Far => new(0, 0, 0, 1);
|
||||
public static Float4 Forward => new(0, 0, 1, 0);
|
||||
public static Float4 Left => new(-1, 0, 0, 0);
|
||||
public static Float4 Near => new(0, 0, 0, -1);
|
||||
public static Float4 Right => new(1, 0, 0, 0);
|
||||
public static Float4 Up => new(0, 1, 0, 0);
|
||||
|
||||
@ -15,7 +15,7 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
public static Float4 Zero => new(0, 0, 0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
||||
public Float4 Normalized => this / Magnitude;
|
||||
public Float4 Normalized => this * Mathf.InverseSqrt(x * x + y * y + z * z + w * w);
|
||||
|
||||
public Float2 XY => new(x, y);
|
||||
public Float2 XZ => new(x, z);
|
||||
@ -144,6 +144,8 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
foreach (Float4 d in vals) val = d < val ? 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 Float4 Product(params Float4[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
@ -180,7 +182,7 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
public int CompareTo(Float4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float4)) return false;
|
||||
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;
|
||||
@ -205,6 +207,11 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { x, y, z, w };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Float4 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { x, y, z, w };
|
||||
|
||||
public static Float4 operator +(Float4 a, Float4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||
@ -212,8 +219,10 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, 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, 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 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);
|
||||
public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0;
|
||||
@ -221,11 +230,15 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
public static bool operator >=(Float4 a, Float4 b) => a == b || a > b;
|
||||
public static bool operator <=(Float4 a, Float4 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0);
|
||||
public static implicit operator Float4(Quaternion val) => new(val.u, val.i, val.j, val.k);
|
||||
public static implicit operator Float4(Float2 val) => new(val.x, val.y, 0, 0);
|
||||
public static implicit operator Float4(Float3 val) => new(val.x, val.y, val.z, 0);
|
||||
public static implicit operator Float4(Int2 val) => new(val.x, val.y, 0, 0);
|
||||
public static implicit operator Float4(Int3 val) => new(val.x, val.y, val.z, 0);
|
||||
public static implicit operator Float4(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static explicit operator Float4(Matrix m) => new(m[0, 0], m[1, 0], m[2, 0], m[3, 0]);
|
||||
public static explicit operator Float4(Vector2d val) => val.ToXYZ();
|
||||
public static implicit operator Float4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0);
|
||||
public static implicit operator Float4(RGBA val) => new(val.R, val.G, val.B, val.A);
|
||||
public static explicit operator Float4(CMYKA val) => new(val.C, val.M, val.Y, val.K);
|
||||
|
||||
@ -86,7 +86,7 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Box2D)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Box2D)) return base.Equals(obj);
|
||||
return Equals((Box2D)obj);
|
||||
}
|
||||
public bool Equals(Box2D other) => center == other.center && size == other.size;
|
||||
|
||||
@ -87,7 +87,7 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Box3D)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Box3D)) return base.Equals(obj);
|
||||
return Equals((Box3D)obj);
|
||||
}
|
||||
public bool Equals(Box3D other) => center == other.center && size == other.size;
|
||||
|
||||
@ -98,7 +98,7 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Line)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Line)) return base.Equals(obj);
|
||||
return Equals((Line)obj);
|
||||
}
|
||||
public bool Equals(Line other) => a == other.a && b == other.b;
|
||||
@ -161,12 +161,17 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
}
|
||||
|
||||
public Vert[] ToArray() => new Vert[] { a, b };
|
||||
public Fill<Vert> ToFill()
|
||||
{
|
||||
Line @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<Vert> ToList() => new() { a, b };
|
||||
|
||||
public float[] ToFloatArray() => new float[] { a.position.x, a.position.y, a.position.z,
|
||||
b.position.x, b.position.y, b.position.z };
|
||||
b.position.x, b.position.y, b.position.z };
|
||||
public List<float> ToFloatList() => new() { a.position.x, a.position.y, a.position.z,
|
||||
b.position.x, b.position.y, b.position.z };
|
||||
b.position.x, b.position.y, b.position.z };
|
||||
|
||||
public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b);
|
||||
public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b);
|
||||
|
||||
@ -256,7 +256,7 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Polygon)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Polygon)) return base.Equals(obj);
|
||||
return Equals((Polygon)obj);
|
||||
}
|
||||
public bool Equals(Polygon other)
|
||||
@ -285,6 +285,11 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
public IEnumerator<Vert> GetEnumerator() { foreach (Vert v in Verts) yield return v; }
|
||||
|
||||
public Vert[] ToArray() => Verts;
|
||||
public Fill<Vert> ToFill()
|
||||
{
|
||||
Polygon @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<Vert> ToList() => new(Verts);
|
||||
|
||||
public float[] ToFloatArray()
|
||||
|
||||
@ -266,7 +266,7 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Quadrilateral)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Quadrilateral)) return base.Equals(obj);
|
||||
return Equals((Quadrilateral)obj);
|
||||
}
|
||||
public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D;
|
||||
@ -289,6 +289,11 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
}
|
||||
|
||||
public Vert[] ToArray() => new Vert[] { A, B, C, D };
|
||||
public Fill<Vert> ToFill()
|
||||
{
|
||||
Quadrilateral @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<Vert> ToList() => new() { A, B, C, D };
|
||||
|
||||
public float[] ToFloatArray() => new float[] { A.position.x, A.position.y, A.position.z,
|
||||
|
||||
@ -69,11 +69,11 @@ public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, ICompara
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return false;
|
||||
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 false;
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public bool Equals(float other) => Volume == other;
|
||||
public bool Equals(Sphere other) => center == other.center && radius == other.radius;
|
||||
|
||||
@ -218,7 +218,7 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Triangle)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Triangle)) return base.Equals(obj);
|
||||
return Equals((Triangle)obj);
|
||||
}
|
||||
public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C;
|
||||
@ -240,14 +240,19 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
}
|
||||
|
||||
public Vert[] ToArray() => new Vert[] { A, B, C };
|
||||
public Fill<Vert> ToFill()
|
||||
{
|
||||
Triangle @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<Vert> ToList() => new() { A, B, C };
|
||||
|
||||
public float[] ToFloatArray() => new float[] { A.position.x, A.position.y, A.position.z,
|
||||
B.position.x, B.position.y, B.position.z,
|
||||
C.position.x, C.position.y, C.position.z };
|
||||
B.position.x, B.position.y, B.position.z,
|
||||
C.position.x, C.position.y, C.position.z };
|
||||
public List<float> 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 };
|
||||
B.position.x, B.position.y, B.position.z,
|
||||
C.position.x, C.position.y, C.position.z };
|
||||
public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C);
|
||||
public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b);
|
||||
public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C);
|
||||
|
||||
@ -17,7 +17,7 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
|
||||
public Float3 position;
|
||||
|
||||
public Vert(Float2 pos) : this(pos.x, pos.y, 0) { }
|
||||
public Vert(Float2 pos) : this((Float3)pos) { }
|
||||
public Vert(Float3 pos) => position = pos;
|
||||
public Vert(float x, float y) : this(new Float2(x, y)) { }
|
||||
public Vert(float x, float y, float z) : this(new Float3(x, y, z)) { }
|
||||
@ -61,7 +61,7 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Vert)) return false;
|
||||
if (obj == null || obj.GetType() != typeof(Vert)) return base.Equals(obj);
|
||||
return Equals((Vert)obj);
|
||||
}
|
||||
public bool Equals(Vert other) => position == other.position;
|
||||
@ -76,8 +76,15 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
public IEnumerator<float> GetEnumerator() => position.GetEnumerator();
|
||||
|
||||
public float[] ToArray() => position.ToArray();
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Vert @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => position.ToList();
|
||||
|
||||
public Vector3d ToVector() => ((Float3)this).ToVector();
|
||||
|
||||
public static Vert operator +(Vert a, Vert b) => new(a.position + b.position);
|
||||
public static Vert operator -(Vert d) => new(-d.position);
|
||||
public static Vert operator -(Vert a, Vert b) => new(a.position - b.position);
|
||||
|
||||
@ -11,7 +11,7 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
public static Int2 Zero => new(0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y);
|
||||
public Int2 Normalized => (Int2)((Float2)this / Magnitude);
|
||||
public Int2 Normalized => (Int2)((Float2)this * Mathf.InverseSqrt(x * x + y * y));
|
||||
|
||||
public int x, y;
|
||||
|
||||
@ -139,7 +139,7 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Int2)) return false;
|
||||
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;
|
||||
@ -160,15 +160,24 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
}
|
||||
|
||||
public int[] ToArray() => new[] { x, y };
|
||||
public Fill<int> ToFill()
|
||||
{
|
||||
Int2 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<int> ToList() => new() { x, y };
|
||||
|
||||
public Vector2d ToVector() => ((Float2)this).ToVector();
|
||||
|
||||
public static Int2 operator +(Int2 a, Int2 b) => new(a.x + b.x, a.y + b.y);
|
||||
public static Int2 operator -(Int2 i) => new(-i.x, -i.y);
|
||||
public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y);
|
||||
public static Int2 operator *(Int2 a, Int2 b) => new(a.x * b.x, a.y * b.y);
|
||||
public static Int2 operator *(Int2 a, int b) => new(a.x * b, a.y * b);
|
||||
public static Int2 operator *(Int2 a, Matrix b) => (Int2)((Matrix)(Float2)a * b);
|
||||
public static Int2 operator /(Int2 a, Int2 b) => new(a.x / b.x, a.y / b.y);
|
||||
public static Int2 operator /(Int2 a, int b) => new(a.x / b, a.y / b);
|
||||
public static Int2 operator /(Int2 a, Matrix b) => (Int2)((Matrix)(Float2)a / b);
|
||||
public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y);
|
||||
public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y);
|
||||
public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y);
|
||||
@ -179,9 +188,13 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
public static bool operator >=(Int2 a, Int2 b) => a == b || a > b;
|
||||
public static bool operator <=(Int2 a, Int2 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i);
|
||||
public static explicit operator Int2(Quaternion val) => new((int)val.u, (int)val.i);
|
||||
public static explicit operator Int2(Float2 val) => new((int)val.x, (int)val.y);
|
||||
public static explicit operator Int2(Float3 val) => new((int)val.x, (int)val.y);
|
||||
public static explicit operator Int2(Float4 val) => new((int)val.x, (int)val.y);
|
||||
public static explicit operator Int2(Matrix m) => new((int)m[0, 0], (int)m[1, 0]);
|
||||
public static explicit operator Int2(Vector2d val) => (Int2)val.ToXYZ();
|
||||
public static explicit operator Int2(Int3 val) => new(val.x, val.y);
|
||||
public static explicit operator Int2(Int4 val) => new(val.x, val.y);
|
||||
public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y);
|
||||
|
||||
@ -13,7 +13,7 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
public static Int3 Zero => new(0, 0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
||||
public Int3 Normalized => (Int3)((Float3)this / Magnitude);
|
||||
public Int3 Normalized => (Int3)((Float3)this * Mathf.InverseSqrt(x * x + y * y + z * z));
|
||||
|
||||
public Int2 XY => new(x, y);
|
||||
public Int2 XZ => new(x, z);
|
||||
@ -159,7 +159,7 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Int3)) return false;
|
||||
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;
|
||||
@ -179,15 +179,24 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
}
|
||||
|
||||
public int[] ToArray() => new[] { x, y, z };
|
||||
public Fill<int> ToFill()
|
||||
{
|
||||
Int3 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<int> ToList() => new() { x, y, z };
|
||||
|
||||
public Vector3d ToVector() => ((Float3)this).ToVector();
|
||||
|
||||
public static Int3 operator +(Int3 a, Int3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
public static Int3 operator -(Int3 i) => new(-i.x, -i.y, -i.z);
|
||||
public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
public static Int3 operator *(Int3 a, Int3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
public static Int3 operator *(Int3 a, int b) => new(a.x * b, a.y * b, a.z * b);
|
||||
public static Int3 operator *(Int3 a, Matrix b) => (Int3)((Matrix)(Float3)a * b);
|
||||
public static Int3 operator /(Int3 a, Int3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||
public static Int3 operator /(Int3 a, int b) => new(a.x / b, a.y / b, a.z / b);
|
||||
public static Int3 operator /(Int3 a, Matrix b) => (Int3)((Matrix)(Float3)a / b);
|
||||
public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z);
|
||||
public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z);
|
||||
public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z);
|
||||
@ -198,11 +207,15 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
public static bool operator >=(Int3 a, Int3 b) => a == b || a > b;
|
||||
public static bool operator <=(Int3 a, Int3 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0);
|
||||
public static explicit operator Int3(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j);
|
||||
public static explicit operator Int3(Float2 val) => new((int)val.x, (int)val.y, 0);
|
||||
public static explicit operator Int3(Float3 val) => new((int)val.x, (int)val.y, (int)val.z);
|
||||
public static explicit operator Int3(Float4 val) => new((int)val.x, (int)val.y, (int)val.z);
|
||||
public static implicit operator Int3(Int2 val) => new(val.x, val.y, 0);
|
||||
public static explicit operator Int3(Int4 val) => new(val.x, val.y, val.z);
|
||||
public static explicit operator Int3(Matrix m) => new((int)m[0, 0], (int)m[1, 0], (int)m[2, 0]);
|
||||
public static explicit operator Int3(Vector2d val) => (Int3)val.ToXYZ();
|
||||
public static explicit operator Int3(Vert val) => new((int)val.position.x, (int)val.position.y,
|
||||
(int)val.position.z);
|
||||
public static explicit operator Int3(RGBA val) => (Int3)val.ToRGBAByte();
|
||||
|
||||
@ -15,7 +15,7 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
public static Int4 Zero => new(0, 0, 0, 0);
|
||||
|
||||
public float Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
||||
public Int4 Normalized => (Int4)((Float4)this / Magnitude);
|
||||
public Int4 Normalized => (Int4)((Float4)this * Mathf.InverseSqrt(x * x + y * y + z * z + w * w));
|
||||
|
||||
public Int2 XY => new(x, y);
|
||||
public Int2 XZ => new(x, z);
|
||||
@ -175,7 +175,7 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Int4)) return false;
|
||||
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;
|
||||
@ -200,6 +200,11 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
}
|
||||
|
||||
public int[] ToArray() => new[] { x, y, z, w };
|
||||
public Fill<int> ToFill()
|
||||
{
|
||||
Int4 @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<int> ToList() => new() { x, y, z, w };
|
||||
|
||||
public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||
@ -207,8 +212,10 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
public static Int4 operator -(Int4 a, Int4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
||||
public static Int4 operator *(Int4 a, Int4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
|
||||
public static Int4 operator *(Int4 a, int b) => new(a.x * b, a.y * b, a.z * b, a.w * b);
|
||||
public static Int4 operator *(Int4 a, Matrix b) => (Int4)((Matrix)(Float4)a * b);
|
||||
public static Int4 operator /(Int4 a, Int4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
||||
public static Int4 operator /(Int4 a, int b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
||||
public static Int4 operator /(Int4 a, Matrix b) => (Int4)((Matrix)(Float4)a / b);
|
||||
public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
|
||||
public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
|
||||
public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
||||
@ -219,11 +226,15 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
public static bool operator >=(Int4 a, Int4 b) => a == b || a > b;
|
||||
public static bool operator <=(Int4 a, Int4 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0);
|
||||
public static explicit operator Int4(Quaternion val) => new((int)val.u, (int)val.i, (int)val.j, (int)val.k);
|
||||
public static explicit operator Int4(Float2 val) => new((int)val.x, (int)val.y, 0, 0);
|
||||
public static explicit operator Int4(Float3 val) => new((int)val.x, (int)val.y, (int)val.z, 0);
|
||||
public static explicit operator Int4(Float4 val) => new((int)val.x, (int)val.y, (int)val.z, (int)val.w);
|
||||
public static implicit operator Int4(Int2 val) => new(val.x, val.y, 0, 0);
|
||||
public static implicit operator Int4(Int3 val) => new(val.x, val.y, val.z, 0);
|
||||
public static explicit operator Int4(Matrix m) => new((int)m[0, 0], (int)m[1, 0], (int)m[2, 0], (int)m[3, 0]);
|
||||
public static explicit operator Int4(Vector2d val) => (Int4)val.ToXYZ();
|
||||
public static explicit operator Int4(Vert val) => new((int)val.position.x, (int)val.position.y,
|
||||
(int)val.position.z, 0);
|
||||
public static explicit operator Int4(RGBA val) => val.ToRGBAByte();
|
||||
|
||||
@ -17,6 +17,7 @@ public static class Mathf
|
||||
public static float ArcSin(float value) => (float)Math.Asin(value);
|
||||
|
||||
public static float ArcTan(float value) => ArcSin(value / Sqrt(1 + value * value));
|
||||
public static float ArcTan2(float a, float b) => ArcTan(a / b);
|
||||
|
||||
public static float Average(Equation equ, float min, float max, float step = Calculus.DefaultStep)
|
||||
{
|
||||
@ -50,10 +51,13 @@ public static class Mathf
|
||||
public static int Combinations(int total, int size) => Factorial(total) /
|
||||
(Factorial(size) * Factorial(total - size));
|
||||
|
||||
public static float Cos(Angle angle) => Cos(angle.Radians);
|
||||
public static float Cos(float radians) => Sin(radians + Constants.HalfPi);
|
||||
|
||||
public static float Cot(Angle angle) => Cot(angle.Radians);
|
||||
public static float Cot(float radians) => Cos(radians) / Sin(radians);
|
||||
|
||||
public static float Csc(Angle angle) => Csc(angle.Radians);
|
||||
public static float Csc(float radians) => 1 / Sin(radians);
|
||||
|
||||
public static float Divide(float val, params float[] dividends)
|
||||
@ -67,6 +71,25 @@ public static class Mathf
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float Dot(float[] a, float[] b)
|
||||
{
|
||||
if (a.Length != b.Length) throw new InvalidSizeException("Both arrays must have the same length");
|
||||
float[] vals = new float[a.Length];
|
||||
for (int i = 0; i < a.Length; i++) vals[i] = a[i] * b[i];
|
||||
return Sum(vals);
|
||||
}
|
||||
public static float Dot(params float[][] vals)
|
||||
{
|
||||
float[] res = new float[vals[0].Length];
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
float m = 1;
|
||||
for (int j = 0; j < vals.Length; j++) m *= vals[j][i];
|
||||
res[i] = m;
|
||||
}
|
||||
return Sum(res);
|
||||
}
|
||||
|
||||
public static int Factorial(int amount)
|
||||
{
|
||||
if (amount < 0) return 0;
|
||||
@ -147,6 +170,13 @@ public static class Mathf
|
||||
foreach (int i in vals) val = i > val ? i : val;
|
||||
return val;
|
||||
}
|
||||
public static T? Max<T>(params T[] vals) where T : IComparable<T>
|
||||
{
|
||||
if (vals.Length < 1) return default;
|
||||
T val = vals[0];
|
||||
foreach (T t in vals) val = t.CompareTo(val) > 0 ? t : val;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static float Median(params float[] vals)
|
||||
{
|
||||
@ -154,7 +184,8 @@ public static class Mathf
|
||||
float valA = vals[Floor(index)], valB = vals[Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static int Median(params int[] vals) => vals[Floor(Average(0, vals.Length - 1))];
|
||||
public static int Median(params int[] vals) => Median<int>(vals);
|
||||
public static T Median<T>(params T[] vals) => vals[Floor(Average(0, vals.Length - 1))];
|
||||
|
||||
public static float Min(Equation equ, float min, float max, float step = Calculus.DefaultStep)
|
||||
{
|
||||
@ -180,6 +211,13 @@ public static class Mathf
|
||||
foreach (int i in vals) val = i < val ? i : val;
|
||||
return val;
|
||||
}
|
||||
public static T? Min<T>(params T[] vals) where T : IComparable<T>
|
||||
{
|
||||
if (vals.Length < 1) return default;
|
||||
T val = vals[0];
|
||||
foreach (T t in vals) val = t.CompareTo(val) < 0 ? t : val;
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (T value, int occurences) Mode<T>(params T[] vals) where T : IEquatable<T>
|
||||
{
|
||||
@ -245,8 +283,10 @@ public static class Mathf
|
||||
public static float Round(float num, float nearest) => nearest * Round(num / nearest);
|
||||
public static int RoundInt(float num) => (int)Round(num);
|
||||
|
||||
public static float Sec(Angle angle) => Sec(angle.Radians);
|
||||
public static float Sec(float radians) => 1 / Cos(radians);
|
||||
|
||||
public static float Sin(Angle angle) => Sin(angle.Radians);
|
||||
public static float Sin(float radians)
|
||||
{
|
||||
// Really close polynomial to sin(x) (when modded by 2pi). RMSE of 0.000003833
|
||||
@ -303,6 +343,7 @@ public static class Mathf
|
||||
// Known as stdev
|
||||
public static float StandardDeviation(params float[] vals) => Sqrt(Variance(vals));
|
||||
|
||||
public static float Tan(Angle angle) => Tan(angle.Radians);
|
||||
public static float Tan(float radians) => Sin(radians) / Cos(radians);
|
||||
|
||||
public static T[] UniqueItems<T>(params T[] vals) where T : IEquatable<T>
|
||||
|
||||
193
Nerd_STF/Mathematics/NumberSystems/Complex.cs
Normal file
193
Nerd_STF/Mathematics/NumberSystems/Complex.cs
Normal file
@ -0,0 +1,193 @@
|
||||
namespace Nerd_STF.Mathematics.NumberSystems;
|
||||
|
||||
public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, IGroup<float>
|
||||
{
|
||||
public static Complex Down => new(0, -1);
|
||||
public static Complex Left => new(-1, 0);
|
||||
public static Complex Right => new(1, 0);
|
||||
public static Complex Up => new(0, 1);
|
||||
|
||||
public static Complex One => new(1, 1);
|
||||
public static Complex Zero => new(0, 0);
|
||||
|
||||
public Complex Conjugate => new(u, -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 Complex(float all) : this(all, all) { }
|
||||
public Complex(float u, float i)
|
||||
{
|
||||
this.u = u;
|
||||
this.i = i;
|
||||
}
|
||||
public Complex(Fill<float> fill) : this(fill(0), fill(1)) { }
|
||||
public Complex(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
0 => u,
|
||||
1 => i,
|
||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||
};
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
u = value;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
i = value;
|
||||
break;
|
||||
|
||||
default: throw new IndexOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Complex Absolute(Complex val) => Float2.Absolute(val);
|
||||
public static Complex Average(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Average(floats.ToArray());
|
||||
}
|
||||
public static Complex Ceiling(Complex val) => Float2.Ceiling(val);
|
||||
public static Complex Clamp(Complex val, Complex min, Complex max) => Float2.Clamp(val, min, max);
|
||||
public static Complex ClampMagnitude(Complex val, float minMag, float maxMag) =>
|
||||
Float2.ClampMagnitude(val, minMag, maxMag);
|
||||
public static Complex Divide(Complex num, params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Divide(num, floats.ToArray());
|
||||
}
|
||||
public static float Dot(Complex a, Complex b) => Float2.Dot(a, b);
|
||||
public static float Dot(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Dot(floats.ToArray());
|
||||
}
|
||||
public static Complex Floor(Complex val) => Float2.Floor(val);
|
||||
public static Complex Lerp(Complex a, Complex b, float t, bool clamp = true) => Float2.Lerp(a, b, t, clamp);
|
||||
public static Complex Median(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Median(floats.ToArray());
|
||||
}
|
||||
public static Complex Max(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Max(floats.ToArray());
|
||||
}
|
||||
public static Complex Min(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Min(floats.ToArray());
|
||||
}
|
||||
public static Complex Product(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Product(floats.ToArray());
|
||||
}
|
||||
public static Complex Round(Complex val) => Float2.Round(val);
|
||||
public static Complex Subtract(Complex num, params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Subtract(num, floats.ToArray());
|
||||
}
|
||||
public static Complex Sum(params Complex[] vals)
|
||||
{
|
||||
List<Float2> floats = new();
|
||||
foreach (Complex c in vals) floats.Add(c);
|
||||
return Float2.Sum(floats.ToArray());
|
||||
}
|
||||
|
||||
public static (float[] Us, float[] Is) SplitArray(params Complex[] vals)
|
||||
{
|
||||
float[] Us = new float[vals.Length], Is = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
Us[i] = vals[i].u;
|
||||
Is[i] = vals[i].i;
|
||||
}
|
||||
return (Us, Is);
|
||||
}
|
||||
|
||||
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 ? " + " : " - ") + i.ToString(provider) + "i";
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
u.ToString(provider) + (i >= 0 ? " + " : " - ") + i.ToString(provider) + "i";
|
||||
|
||||
public object Clone() => new Complex(u, i);
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return u;
|
||||
yield return i;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { u, i };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Complex @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { u, i };
|
||||
|
||||
public Vector2d ToVector() => ((Float2)this).ToVector();
|
||||
|
||||
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);
|
||||
public static Complex operator *(Complex a, Complex b) => new(a.u * b.u - a.i * b.i, a.u * b.i + a.i * b.u);
|
||||
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 a, Complex b)
|
||||
{
|
||||
float c = b.u * b.u + b.i * b.i;
|
||||
return new((a.u * b.u + a.i * b.i) / c, (a.i * b.u - a.u * b.i) / c);
|
||||
}
|
||||
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 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;
|
||||
public static bool operator <(Complex a, Complex b) => a.CompareTo(b) < 0;
|
||||
public static bool operator >=(Complex a, Complex b) => a == b || a > b;
|
||||
public static bool operator <=(Complex a, Complex b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Complex(Quaternion val) => new(val.u, val.i);
|
||||
public static implicit operator Complex(Float2 val) => new(val.x, val.y);
|
||||
public static explicit operator Complex(Float3 val) => new(val.x, val.y);
|
||||
public static explicit operator Complex(Float4 val) => new(val.x, val.y);
|
||||
public static implicit operator Complex(Int2 val) => new(val.x, val.y);
|
||||
public static explicit operator Complex(Int3 val) => new(val.x, val.y);
|
||||
public static explicit operator Complex(Int4 val) => new(val.x, val.y);
|
||||
public static explicit operator Complex(Matrix m) => new(m[0, 0], m[1, 0]);
|
||||
public static explicit operator Complex(Vector2d val) => val.ToXYZ();
|
||||
public static explicit operator Complex(Vert val) => new(val.position.x, val.position.y);
|
||||
public static implicit operator Complex(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Complex(Fill<int> fill) => new(fill);
|
||||
}
|
||||
309
Nerd_STF/Mathematics/NumberSystems/Quaternion.cs
Normal file
309
Nerd_STF/Mathematics/NumberSystems/Quaternion.cs
Normal file
@ -0,0 +1,309 @@
|
||||
namespace Nerd_STF.Mathematics.NumberSystems;
|
||||
|
||||
public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quaternion>, IGroup<float>
|
||||
{
|
||||
public static Quaternion Back => new(0, 0, -1, 0);
|
||||
public static Quaternion Down => new(0, -1, 0, 0);
|
||||
public static Quaternion Far => new(0, 0, 0, 1);
|
||||
public static Quaternion Forward => new(0, 0, 1, 0);
|
||||
public static Quaternion Left => new(-1, 0, 0, 0);
|
||||
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);
|
||||
|
||||
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 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 float u, i, j, k;
|
||||
|
||||
public Quaternion(float all) : this(all, all, all, all) { }
|
||||
public Quaternion(float i, float j, float k) : this(0, i, j, k) { }
|
||||
public Quaternion(Float3 ijk) : this(0, ijk.x, ijk.y, ijk.z) { }
|
||||
public Quaternion(float u, Float3 ijk) : this(u, ijk.x, ijk.y, ijk.z) { }
|
||||
public Quaternion(float u, float i, float j, float k)
|
||||
{
|
||||
this.u = u;
|
||||
this.i = i;
|
||||
this.j = j;
|
||||
this.k = k;
|
||||
}
|
||||
public Quaternion(Fill<float> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||
public Quaternion(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
0 => u,
|
||||
1 => i,
|
||||
2 => j,
|
||||
3 => k,
|
||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||
};
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
u = value;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
i = value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
j = value;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
k = value;
|
||||
break;
|
||||
|
||||
default: throw new IndexOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Quaternion Absolute(Quaternion val) => Float4.Absolute(val);
|
||||
public static Quaternion Average(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Average(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Ceiling(Quaternion val) => Float4.Ceiling(val);
|
||||
public static Quaternion Clamp(Quaternion val, Quaternion min, Quaternion max) => Float4.Clamp(val, min, max);
|
||||
public static Quaternion ClampMagnitude(Quaternion val, float minMag, float maxMag) =>
|
||||
Float4.ClampMagnitude(val, minMag, maxMag);
|
||||
public static Quaternion Divide(Quaternion num, params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Divide(num, floats.ToArray());
|
||||
}
|
||||
public static float Dot(Quaternion a, Quaternion b) => a.u * b.u + a.i * b.i + a.j * b.j + a.k * b.k;
|
||||
public static float Dot(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Dot(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Floor(Quaternion val) => Float4.Floor(val);
|
||||
public static Quaternion Lerp(Quaternion a, Quaternion b, float t, bool clamp = true) => Float4.Lerp(a, b, t, clamp);
|
||||
public static Quaternion Median(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Median(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Max(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Max(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Min(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Min(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Product(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Product(floats.ToArray());
|
||||
}
|
||||
public static Quaternion Round(Quaternion val) => Float4.Round(val);
|
||||
public static Quaternion Subtract(Quaternion num, params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Subtract(num, floats.ToArray());
|
||||
}
|
||||
public static Quaternion Sum(params Quaternion[] vals)
|
||||
{
|
||||
List<Float4> floats = new();
|
||||
foreach (Quaternion q in vals) floats.Add(q);
|
||||
return Float4.Sum(floats.ToArray());
|
||||
}
|
||||
|
||||
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 cosYawCosPitch = cosYaw * cosPitch,
|
||||
cosYawSinPitch = cosYaw * sinPitch,
|
||||
sinYawCosPitch = sinYaw * cosPitch,
|
||||
sinYawSinPitch = sinYaw * sinPitch;
|
||||
|
||||
return new(cosYawCosPitch * cosRoll + sinYawSinPitch * sinRoll,
|
||||
cosYawCosPitch * sinRoll + sinYawSinPitch * cosRoll,
|
||||
cosYawSinPitch * cosRoll + sinYawCosPitch * sinRoll,
|
||||
sinYawCosPitch * cosRoll + cosYawSinPitch * sinRoll);
|
||||
}
|
||||
public static Quaternion FromAngles(Float3 vals, Angle.Type valType) =>
|
||||
FromAngles(new(vals.x, valType), new(vals.y, valType), new(vals.z, valType));
|
||||
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)
|
||||
{
|
||||
float[] Us = new float[vals.Length], Is = new float[vals.Length], Js = new float[vals.Length],
|
||||
Ks = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
Us[i] = vals[i].u;
|
||||
Is[i] = vals[i].i;
|
||||
Js[i] = vals[i].j;
|
||||
Ks[i] = vals[i].k;
|
||||
}
|
||||
return (Us, Is, Js, Ks);
|
||||
}
|
||||
|
||||
public int CompareTo(Quaternion other) => 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 ? " + " : " - ") + i.ToString(provider) + "i"
|
||||
+ (j >= 0 ? " + " : " - ") + j.ToString(provider) + "j"
|
||||
+ (k >= 0 ? " + " : " - ") + k.ToString(provider) + "k";
|
||||
public string ToString(IFormatProvider provider) => u.ToString(provider)
|
||||
+ (i >= 0 ? " + " : " - ") + i.ToString(provider) + "i"
|
||||
+ (j >= 0 ? " + " : " - ") + j.ToString(provider) + "j"
|
||||
+ (k >= 0 ? " + " : " - ") + k.ToString(provider) + "k";
|
||||
|
||||
public object Clone() => new Quaternion(u, i, j, k);
|
||||
|
||||
public Angle GetAngle() => new(2 * Mathf.ArcCos(u), Angle.Type.Radians);
|
||||
public Float3 GetAxis()
|
||||
{
|
||||
Float3 axis = IJK;
|
||||
float mag = Magnitude;
|
||||
|
||||
if (mag < 0) return Float3.Zero;
|
||||
return axis / mag;
|
||||
}
|
||||
public (Angle yaw, Angle pitch, Angle roll) ToAngles()
|
||||
{
|
||||
Quaternion doubled = this;
|
||||
doubled.u *= u;
|
||||
doubled.i *= i;
|
||||
doubled.j *= j;
|
||||
doubled.k *= k;
|
||||
|
||||
Matrix3x3 rotMatrix = 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 }
|
||||
});
|
||||
|
||||
Angle yaw, pitch, roll;
|
||||
|
||||
float r3c1Abs = Mathf.Absolute(rotMatrix.r3c1);
|
||||
if (r3c1Abs >= 1)
|
||||
{
|
||||
rotMatrix.r1c2 = 2 * (i * j - u * k);
|
||||
rotMatrix.r1c3 = 2 * (i * k + u * j);
|
||||
|
||||
yaw = new(Mathf.ArcTan2(-rotMatrix.r1c2, -rotMatrix.r3c1 * rotMatrix.r1c3), Angle.Type.Radians);
|
||||
pitch = new(-Constants.HalfPi * rotMatrix.r3c1 / r3c1Abs, Angle.Type.Radians);
|
||||
roll = Angle.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = new(Mathf.ArcTan2(rotMatrix.r2c1, rotMatrix.r1c1), Angle.Type.Radians);
|
||||
pitch = new(Mathf.ArcSin(-rotMatrix.r3c1), Angle.Type.Radians);
|
||||
roll = new(Mathf.ArcTan2(rotMatrix.r3c2, rotMatrix.r3c3), Angle.Type.Radians);
|
||||
}
|
||||
|
||||
return (yaw, pitch, roll);
|
||||
}
|
||||
public Vector3d ToVector()
|
||||
{
|
||||
(Angle yaw, Angle pitch, _) = ToAngles();
|
||||
return new(yaw, pitch);
|
||||
}
|
||||
|
||||
public Quaternion Rotate(Quaternion other) => other * this * other.Conjugate;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return u;
|
||||
yield return i;
|
||||
yield return j;
|
||||
yield return k;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { u, i, j, k };
|
||||
public Fill<float> ToFill()
|
||||
{
|
||||
Quaternion @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<float> ToList() => new() { u, i, j, 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 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)
|
||||
{
|
||||
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,
|
||||
k = a * h + b * g + d * e - c * f;
|
||||
return new(u, i, j, k);
|
||||
}
|
||||
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 x, Quaternion y)
|
||||
{
|
||||
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 = b * e + c * h + d * g - a * f,
|
||||
j = c * e + d * f - a * g - b * h,
|
||||
k = c * f + d * e - a * h - b * g,
|
||||
q = e * e + f * f + g * g + h * h;
|
||||
return new(u / q, i / q, j / q, k / q);
|
||||
}
|
||||
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 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;
|
||||
public static bool operator <(Quaternion a, Quaternion b) => a.CompareTo(b) < 0;
|
||||
public static bool operator >=(Quaternion a, Quaternion b) => a == b || a > b;
|
||||
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);
|
||||
public static implicit operator Quaternion(Int2 val) => new(val);
|
||||
public static implicit operator Quaternion(Int3 val) => new(val);
|
||||
public static implicit operator Quaternion(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static explicit operator Quaternion(Float2 val) => new(val);
|
||||
public static explicit operator Quaternion(Float3 val) => new(val);
|
||||
public static implicit operator Quaternion(Float4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static explicit operator Quaternion(Matrix m) => new(m[0, 0], m[1, 0], m[2, 0], m[3, 0]);
|
||||
public static explicit operator Quaternion(Vector2d val) => (Quaternion)val.ToXYZ();
|
||||
public static implicit operator Quaternion(Vert val) => new(val);
|
||||
public static implicit operator Quaternion(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Quaternion(Fill<int> fill) => new(fill);
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
namespace Nerd_STF.Mathematics.Samples;
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
26
Nerd_STF/Mathematics/Samples/Equations.cs
Normal file
26
Nerd_STF/Mathematics/Samples/Equations.cs
Normal file
@ -0,0 +1,26 @@
|
||||
namespace Nerd_STF.Mathematics.Samples;
|
||||
|
||||
public static class Equations
|
||||
{
|
||||
public static readonly Fill<int> SgnFill = i => i % 2 == 0 ? 1 : -1;
|
||||
|
||||
public static readonly Equation CosWave = x => Mathf.Cos(x);
|
||||
public static readonly Equation SinWave = x => Mathf.Sin(x);
|
||||
public static readonly Equation SawWave = x => x % 1;
|
||||
public static readonly Equation SquareWave = x => x % 2 < 1 ? 1 : 0;
|
||||
|
||||
public static Equation Scale(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),
|
||||
_ => throw new ArgumentException("Unknown scale type " + type)
|
||||
};
|
||||
|
||||
public enum ScaleType
|
||||
{
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Both = X | Y
|
||||
}
|
||||
}
|
||||
@ -10,5 +10,9 @@ 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;
|
||||
|
||||
5
Nerd_STF/Modifier.cs
Normal file
5
Nerd_STF/Modifier.cs
Normal file
@ -0,0 +1,5 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public delegate float Modifier(int index, float value);
|
||||
public delegate T Modifier<T>(int index, T value);
|
||||
public delegate VT Modifier<IT, VT>(IT index, VT value);
|
||||
5
Nerd_STF/Modifier2D.cs
Normal file
5
Nerd_STF/Modifier2D.cs
Normal file
@ -0,0 +1,5 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public delegate float Modifier2D(Int2 index, float value);
|
||||
public delegate T Modifier2D<T>(Int2 index, T value);
|
||||
public delegate VT Modifier2D<IT, VT>(IT x, IT y, VT value);
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user