Compare commits
8 Commits
v2.3.1.39-
...
v2.3
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d44cbe438 | |||
| fe83380366 | |||
| ed967797e6 | |||
| e895bbb5b2 | |||
| efcf2b94e9 | |||
| 9a1821cb10 | |||
| deff917a60 | |||
| 07cb6a2369 |
18
.gitignore
vendored
18
.gitignore
vendored
@ -1,13 +1,14 @@
|
||||
# Visual Studio stuff
|
||||
*.csproj
|
||||
*.editorconfig
|
||||
*.sln
|
||||
# Useless Visual Studio stuff
|
||||
.vs/
|
||||
/Nerd_STF/.vs/
|
||||
/Nerd_STF/Nerd_STF.csproj.user
|
||||
*.sln
|
||||
|
||||
# Build Stuff
|
||||
/Nerd_STF/obj
|
||||
/Nerd_STF/bin/Debug
|
||||
/Nerd_STF/bin/Release/net6.0/Nerd_STF.deps.json
|
||||
/Nerd_STF/bin/Release/net6.0/Nerd_STF.dll
|
||||
/Nerd_STF/bin/Release/net6.0/Nerd_STF.pdb
|
||||
/Nerd_STF/bin
|
||||
*.dll
|
||||
*.pdb
|
||||
|
||||
# Testing project
|
||||
/Testing
|
||||
@ -15,6 +16,7 @@
|
||||
# Nuget
|
||||
/Nerd_STF/LICENSE
|
||||
*.nupkg
|
||||
*.snupkg
|
||||
|
||||
# Personal
|
||||
/Nerd_STF/TODO.md
|
||||
|
||||
1296
Changelog.md
1296
Changelog.md
File diff suppressed because it is too large
Load Diff
BIN
Extras/Logo Square.png
Normal file
BIN
Extras/Logo Square.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 58 KiB |
4
Nerd_STF/.editorconfig
Normal file
4
Nerd_STF/.editorconfig
Normal file
@ -0,0 +1,4 @@
|
||||
[*.cs]
|
||||
|
||||
# CA1050: Declare types in namespaces
|
||||
dotnet_diagnostic.CA1050.severity = warning
|
||||
@ -1,8 +1,7 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
[Obsolete("The Polygon struct is a garbage fire, and will be fixed in v2.4.0", false)]
|
||||
public class DifferingVertCountException : Nerd_STFException
|
||||
{
|
||||
public string? ParamName;
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class DisconnectedLinesException : Nerd_STFException
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class InvalidSizeException : Nerd_STFException
|
||||
{
|
||||
public InvalidSizeException() : this("Argument size is invalid.") { }
|
||||
public InvalidSizeException() : base("Argument size is invalid.") { }
|
||||
public InvalidSizeException(string message) : base(message) { }
|
||||
public InvalidSizeException(string message, Exception inner) : base(message, inner) { }
|
||||
protected InvalidSizeException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class MathException : Nerd_STFException
|
||||
{
|
||||
public MathException() : base() { }
|
||||
public MathException() : base("A calculation error occured.") { }
|
||||
public MathException(string message) : base(message) { }
|
||||
public MathException(string message, Exception inner) : base(message, inner) { }
|
||||
protected MathException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class Nerd_STFException : Exception
|
||||
{
|
||||
public Nerd_STFException() { }
|
||||
public Nerd_STFException() : base("An unknown error occured within Nerd_STF.") { }
|
||||
public Nerd_STFException(Exception inner)
|
||||
: base("An unknown error occured within Nerd_STF.", inner) { }
|
||||
public Nerd_STFException(string message) : base(message) { }
|
||||
public Nerd_STFException(string message, Exception inner) : base(message, inner) { }
|
||||
protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
|
||||
@ -1,9 +1,7 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class NoInverseException : Exception
|
||||
public class NoInverseException : Nerd_STFException
|
||||
{
|
||||
public Matrix? Matrix;
|
||||
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Nerd_STF.Exceptions;
|
||||
namespace Nerd_STF.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class UndefinedException : MathException
|
||||
{
|
||||
public UndefinedException() : this("The equation calculated resulted in an undefined number.") { }
|
||||
public UndefinedException() : this("A calculation has produced an undefined number.") { }
|
||||
public UndefinedException(string message) : base(message) { }
|
||||
public UndefinedException(string message, Exception inner) : base(message, inner) { }
|
||||
protected UndefinedException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||
|
||||
@ -2,23 +2,60 @@
|
||||
|
||||
public static class Container2DExtension
|
||||
{
|
||||
public static T[] Flatten<T>(this T[,] array, Int2 size)
|
||||
public static T[] Flatten<T>(this T[,] array, Int2? size = null)
|
||||
{
|
||||
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];
|
||||
size ??= GetSize(array);
|
||||
T[] res = new T[size.Value.x * size.Value.y];
|
||||
for (int x = 0; x < size.Value.x; x++) for (int y = 0; y < size.Value.y; y++)
|
||||
res[x + y * size.Value.x] = array[y, x];
|
||||
return res;
|
||||
}
|
||||
|
||||
public static T[] GetColumn<T>(this T[,] array, int column, int length)
|
||||
{
|
||||
T[] res = new T[length];
|
||||
for (int i = 0; i < length; i++) res[i] = array[column, i];
|
||||
for (int i = 0; i < length; i++) res[i] = array[i, column];
|
||||
return res;
|
||||
}
|
||||
public static T[] GetRow<T>(this T[,] array, int row, int length)
|
||||
{
|
||||
T[] res = new T[length];
|
||||
for (int i = 0; i < length; i++) res[i] = array[i, row];
|
||||
for (int i = 0; i < length; i++) res[i] = array[row, i];
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Int2 GetSize<T>(this T[,] array)
|
||||
{
|
||||
Int2 size = Int2.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_ = array[size.x, 0];
|
||||
size.x++;
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException) { }
|
||||
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
_ = array[0, size.y];
|
||||
size.y++;
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException) { }
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public static T[,] SwapDimensions<T>(this T[,] array, Int2? size = null)
|
||||
{
|
||||
size ??= GetSize(array);
|
||||
T[,] vals = new T[size.Value.y, size.Value.x];
|
||||
for (int x = 0; x < size.Value.y; x++) for (int y = 0; y < size.Value.x; y++) vals[x, y] = array[y, x];
|
||||
return vals;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
|
||||
public static class ConversionExtension
|
||||
{
|
||||
[Obsolete("This extension turns out to already exist as a constructor in the " +
|
||||
"System.Collections.Generic.Dictionary<TKey, TValue> type. This will be removed in v2.4.0")]
|
||||
public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>
|
||||
(this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
|
||||
where TKey : notnull
|
||||
@ -10,4 +12,8 @@ public static class ConversionExtension
|
||||
foreach (KeyValuePair<TKey, TValue> pair in pairs) res.Add(pair.Key, pair.Value);
|
||||
return res;
|
||||
}
|
||||
|
||||
public static Fill<T> ToFill<T>(this T[] arr) => i => arr[i];
|
||||
public static Fill<T> ToFill<T>(this T[,] arr, Int2? size) => arr.Flatten(size).ToFill();
|
||||
public static Fill2D<T> ToFill2D<T>(this T[,] arr) => (x, y) => arr[x, y];
|
||||
}
|
||||
|
||||
@ -4,16 +4,9 @@ public static class EquationExtension
|
||||
{
|
||||
public static Equation Scale(this Equation equ, float value, ScaleType type = ScaleType.Both) => type switch
|
||||
{
|
||||
ScaleType.X => x => equ(value / x),
|
||||
ScaleType.Y => x => x * equ(value),
|
||||
ScaleType.Both => x => x * equ(value / x),
|
||||
ScaleType.X => x => equ(x / value),
|
||||
ScaleType.Y => x => value * equ(x),
|
||||
ScaleType.Both => x => value * equ(x / value),
|
||||
_ => throw new ArgumentException("Unknown scale type " + type)
|
||||
};
|
||||
|
||||
public enum ScaleType
|
||||
{
|
||||
X = 1,
|
||||
Y = 2,
|
||||
Both = X | Y
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")]
|
||||
public delegate void Foreach(object item);
|
||||
[Obsolete("This delegate is kind of useless and will be removed in Nerd_STF v2.4.0.")]
|
||||
public delegate void Foreach<T>(T item);
|
||||
|
||||
29
Nerd_STF/Graphics/Abstract/IColor.cs
Normal file
29
Nerd_STF/Graphics/Abstract/IColor.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Graphics.Abstract;
|
||||
|
||||
public interface IColor : IEquatable<IColor>
|
||||
{
|
||||
public CMYKA ToCMYKA();
|
||||
public HSVA ToHSVA();
|
||||
public RGBA ToRGBA();
|
||||
|
||||
public CMYKAByte ToCMYKAByte();
|
||||
public HSVAByte ToHSVAByte();
|
||||
public RGBAByte ToRGBAByte();
|
||||
}
|
||||
public interface IColor<T> : IColor where T : IColor<T>
|
||||
{
|
||||
public static abstract bool operator ==(T a, CMYKA b);
|
||||
public static abstract bool operator !=(T a, CMYKA b);
|
||||
public static abstract bool operator ==(T a, CMYKAByte b);
|
||||
public static abstract bool operator !=(T a, CMYKAByte b);
|
||||
public static abstract bool operator ==(T a, HSVA b);
|
||||
public static abstract bool operator !=(T a, HSVA b);
|
||||
public static abstract bool operator ==(T a, HSVAByte b);
|
||||
public static abstract bool operator !=(T a, HSVAByte b);
|
||||
public static abstract bool operator ==(T a, RGBA b);
|
||||
public static abstract bool operator !=(T a, RGBA b);
|
||||
public static abstract bool operator ==(T a, RGBAByte b);
|
||||
public static abstract bool operator !=(T a, RGBAByte b);
|
||||
}
|
||||
9
Nerd_STF/Graphics/Abstract/IColorByte.cs
Normal file
9
Nerd_STF/Graphics/Abstract/IColorByte.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nerd_STF.Graphics.Abstract;
|
||||
|
||||
public interface IColorByte : IColor, IGroup<byte>
|
||||
{
|
||||
public int[] ToArrayInt();
|
||||
public Fill<int> ToFillInt();
|
||||
public List<int> ToListInt();
|
||||
}
|
||||
public interface IColorByte<T> : IColor<T>, IColorByte where T : struct, IColorByte<T> { }
|
||||
4
Nerd_STF/Graphics/Abstract/IColorFloat.cs
Normal file
4
Nerd_STF/Graphics/Abstract/IColorFloat.cs
Normal file
@ -0,0 +1,4 @@
|
||||
namespace Nerd_STF.Graphics.Abstract;
|
||||
|
||||
public interface IColorFloat : IColor, IGroup<float> { }
|
||||
public interface IColorFloat<T> : IColor<T>, IColorFloat where T : struct, IColorFloat<T> { }
|
||||
17
Nerd_STF/Graphics/Abstract/IColorPresets.cs
Normal file
17
Nerd_STF/Graphics/Abstract/IColorPresets.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace Nerd_STF.Graphics.Abstract;
|
||||
|
||||
public interface IColorPresets<T> where T : IColorPresets<T>
|
||||
{
|
||||
public static abstract T Black { get; }
|
||||
public static abstract T Blue { get; }
|
||||
public static abstract T Clear { get; }
|
||||
public static abstract T Cyan { get; }
|
||||
public static abstract T Gray { get; }
|
||||
public static abstract T Green { get; }
|
||||
public static abstract T Magenta { get; }
|
||||
public static abstract T Orange { get; }
|
||||
public static abstract T Purple { get; }
|
||||
public static abstract T Red { get; }
|
||||
public static abstract T White { get; }
|
||||
public static abstract T Yellow { get; }
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
public record struct CMYKA : IAverage<CMYKA>, IClamp<CMYKA>, IColorFloat<CMYKA>, IColorPresets<CMYKA>,
|
||||
IEquatable<CMYKA>, IIndexAll<float>, IIndexRangeAll<float>, ILerp<CMYKA, float>, IMedian<CMYKA>,
|
||||
ISplittable<CMYKA, (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As)>
|
||||
{
|
||||
public static CMYKA Black => new(0, 0, 0, 1);
|
||||
public static CMYKA Blue => new(1, 1, 0, 0);
|
||||
@ -103,6 +105,28 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 5 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 5 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static CMYKA Average(params CMYKA[] vals)
|
||||
{
|
||||
@ -111,16 +135,12 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
|
||||
return val / vals.Length;
|
||||
}
|
||||
public static CMYKA Ceiling(CMYKA val) => new(Mathf.Ceiling(val.C), Mathf.Ceiling(val.M),
|
||||
Mathf.Ceiling(val.Y), Mathf.Ceiling(val.K), Mathf.Ceiling(val.A));
|
||||
public static CMYKA Clamp(CMYKA val, CMYKA min, CMYKA max) =>
|
||||
new(Mathf.Clamp(val.C, min.C, max.C),
|
||||
Mathf.Clamp(val.M, min.M, max.M),
|
||||
Mathf.Clamp(val.Y, min.Y, max.Y),
|
||||
Mathf.Clamp(val.K, min.K, max.K),
|
||||
Mathf.Clamp(val.A, min.A, max.A));
|
||||
public static CMYKA Floor(CMYKA val) => new(Mathf.Floor(val.C), Mathf.Floor(val.M),
|
||||
Mathf.Floor(val.Y), Mathf.Floor(val.K), Mathf.Floor(val.A));
|
||||
public static CMYKA Lerp(CMYKA a, CMYKA b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.C, b.C, t, clamp), Mathf.Lerp(a.M, b.M, t, clamp), Mathf.Lerp(a.Y, b.Y, t, clamp),
|
||||
Mathf.Lerp(a.K, b.K, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp));
|
||||
@ -136,18 +156,6 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
CMYKA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static CMYKA Max(params CMYKA[] vals)
|
||||
{
|
||||
(float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) = SplitArray(vals);
|
||||
return new(Mathf.Max(Cs), Mathf.Max(Ms), Mathf.Max(Ys), Mathf.Max(Ks), Mathf.Max(As));
|
||||
}
|
||||
public static CMYKA Min(params CMYKA[] vals)
|
||||
{
|
||||
(float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) = SplitArray(vals);
|
||||
return new(Mathf.Min(Cs), Mathf.Min(Ms), Mathf.Min(Ys), Mathf.Min(Ks), Mathf.Min(As));
|
||||
}
|
||||
public static CMYKA Round(CMYKA val) => new(Mathf.Round(val.C), Mathf.Round(val.M),
|
||||
Mathf.Round(val.Y), Mathf.Round(val.K), Mathf.Round(val.A));
|
||||
|
||||
public static (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) SplitArray(params CMYKA[] vals)
|
||||
{
|
||||
@ -166,37 +174,14 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKA());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKA());
|
||||
public bool Equals(CMYKA col) => A == 0 && col.A == 0 || K == 1 && col.K == 1 || C == col.C && M == col.M
|
||||
&& Y == col.Y && K == col.K && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(CMYKA)) return Equals((CMYKA)obj);
|
||||
else if (t == typeof(RGBA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode() ^ K.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider)
|
||||
+ " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider)
|
||||
+ " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider)
|
||||
+ " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider)
|
||||
+ " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA()
|
||||
{
|
||||
float kInv = 1 - K, r = 1 - C, g = 1 - M, b = 1 - Y;
|
||||
return new(r * kInv, g * kInv, b * kInv);
|
||||
return new(r * kInv, g * kInv, b * kInv, A);
|
||||
}
|
||||
public CMYKA ToCMYKA() => this;
|
||||
public HSVA ToHSVA() => ToRGBA().ToHSVA();
|
||||
@ -224,7 +209,20 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
yield return A;
|
||||
}
|
||||
|
||||
public object Clone() => new CMYKA(C, M, Y, K, A);
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("C = ");
|
||||
builder.Append(C);
|
||||
builder.Append(", M = ");
|
||||
builder.Append(M);
|
||||
builder.Append(", Y = ");
|
||||
builder.Append(Y);
|
||||
builder.Append(", K = ");
|
||||
builder.Append(K);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static CMYKA operator +(CMYKA a, CMYKA b) => new(a.C + b.C, a.M + b.M, a.Y + b.Y, a.K + b.K, a.A + b.A);
|
||||
public static CMYKA operator -(CMYKA c) => new(1 - c.C, 1 - c.M, 1 - c.Y, 1 - c.K, c.A != 1 ? 1 - c.A : 1);
|
||||
@ -233,25 +231,23 @@ public struct CMYKA : IColor, IEquatable<CMYKA>
|
||||
public static CMYKA operator *(CMYKA a, float b) => new(a.C * b, a.M * b, a.Y * b, a.K * b, a.A * b);
|
||||
public static CMYKA operator /(CMYKA a, CMYKA b) => new(a.C / b.C, a.M / b.M, a.Y / b.Y, a.K / b.K, a.A / b.A);
|
||||
public static CMYKA operator /(CMYKA a, float b) => new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / b);
|
||||
public static bool operator ==(CMYKA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, RGBA b) => !a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, CMYKA b) => !a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, HSVA b) => !a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, RGBAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(CMYKA a, RGBAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(CMYKA a, CMYKAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(CMYKA a, HSVAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(CMYKA a, HSVA b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKA a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKA a, RGBAByte b) => a.Equals(b);
|
||||
|
||||
public static explicit operator CMYKA(Float3 val) => new(val.x, val.y, val.z, 0);
|
||||
public static implicit operator CMYKA(Float4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static implicit operator CMYKA(RGBA val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(HSVA val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(RGBAByte val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(RGBA val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(CMYKAByte val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(HSVAByte val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(RGBAByte val) => val.ToCMYKA();
|
||||
public static implicit operator CMYKA(Fill<float> val) => new(val);
|
||||
}
|
||||
|
||||
@ -1,21 +1,50 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
public record struct CMYKAByte : IAverage<CMYKAByte>, IClamp<CMYKAByte>, IColorByte<CMYKAByte>,
|
||||
IColorPresets<CMYKAByte>, IEquatable<CMYKAByte>, IIndexAll<int>, IIndexRangeAll<int>,
|
||||
ILerp<CMYKAByte, float>, IMedian<CMYKAByte>,
|
||||
ISplittable<CMYKAByte, (byte[] Cs, byte[] Ms, byte[] Ys, byte[] Ks, byte[] As)>
|
||||
{
|
||||
public static CMYKA Black => new(0, 0, 0, 255);
|
||||
public static CMYKA Blue => new(255, 255, 0, 0);
|
||||
public static CMYKA Clear => new(0, 0, 0, 0, 0);
|
||||
public static CMYKA Cyan => new(255, 0, 0, 0);
|
||||
public static CMYKA Gray => new(0, 0, 0, 127);
|
||||
public static CMYKA Green => new(255, 0, 255, 0);
|
||||
public static CMYKA Magenta => new(0, 255, 0, 0);
|
||||
public static CMYKA Orange => new(0, 127, 255, 0);
|
||||
public static CMYKA Purple => new(127, 255, 0, 0);
|
||||
public static CMYKA Red => new(0, 255, 255, 0);
|
||||
public static CMYKA White => new(0, 0, 0, 0);
|
||||
public static CMYKA Yellow => new(0, 0, 255, 0);
|
||||
public static CMYKAByte Black => new(0, 0, 0, 255);
|
||||
public static CMYKAByte Blue => new(255, 255, 0, 0);
|
||||
public static CMYKAByte Clear => new(0, 0, 0, 0, 0);
|
||||
public static CMYKAByte Cyan => new(255, 0, 0, 0);
|
||||
public static CMYKAByte Gray => new(0, 0, 0, 127);
|
||||
public static CMYKAByte Green => new(255, 0, 255, 0);
|
||||
public static CMYKAByte Magenta => new(0, 255, 0, 0);
|
||||
public static CMYKAByte Orange => new(0, 127, 255, 0);
|
||||
public static CMYKAByte Purple => new(127, 255, 0, 0);
|
||||
public static CMYKAByte Red => new(0, 255, 255, 0);
|
||||
public static CMYKAByte White => new(0, 0, 0, 0);
|
||||
public static CMYKAByte Yellow => new(0, 0, 255, 0);
|
||||
|
||||
public byte C, M, Y, K, A;
|
||||
public int C
|
||||
{
|
||||
get => p_c;
|
||||
set => p_c = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int M
|
||||
{
|
||||
get => p_m;
|
||||
set => p_m = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => p_y;
|
||||
set => p_y = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int K
|
||||
{
|
||||
get => p_k;
|
||||
set => p_k = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int A
|
||||
{
|
||||
get => p_a;
|
||||
set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
|
||||
private byte p_c, p_m, p_y, p_k, p_a;
|
||||
|
||||
public bool HasCyan => C > 0;
|
||||
public bool HasMagenta => M > 0;
|
||||
@ -30,16 +59,16 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
public CMYKAByte(int c, int m, int y, int k) : this(c, m, y, k, 255) { }
|
||||
public CMYKAByte(int c, int m, int y, int k, int a)
|
||||
{
|
||||
C = (byte)Mathf.Clamp(c, 0, 255);
|
||||
M = (byte)Mathf.Clamp(m, 0, 255);
|
||||
Y = (byte)Mathf.Clamp(y, 0, 255);
|
||||
K = (byte)Mathf.Clamp(k, 0, 255);
|
||||
A = (byte)Mathf.Clamp(a, 0, 255);
|
||||
p_c = (byte)Mathf.Clamp(c, 0, 255);
|
||||
p_m = (byte)Mathf.Clamp(m, 0, 255);
|
||||
p_y = (byte)Mathf.Clamp(y, 0, 255);
|
||||
p_k = (byte)Mathf.Clamp(k, 0, 255);
|
||||
p_a = (byte)Mathf.Clamp(a, 0, 255);
|
||||
}
|
||||
public CMYKAByte(Fill<byte> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4)) { }
|
||||
public CMYKAByte(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4)) { }
|
||||
|
||||
public byte this[int index]
|
||||
public int this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
@ -78,6 +107,28 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 5 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 5 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 5 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 5 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static CMYKAByte Average(params CMYKAByte[] vals)
|
||||
{
|
||||
@ -101,16 +152,6 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
CMYKAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static CMYKAByte Max(params CMYKAByte[] vals)
|
||||
{
|
||||
(int[] Cs, int[] Ms, int[] Ys, int[] Ks, int[] As) = SplitArrayInt(vals);
|
||||
return new(Mathf.Max(Cs), Mathf.Max(Ms), Mathf.Max(Ys), Mathf.Max(Ks), Mathf.Max(As));
|
||||
}
|
||||
public static CMYKAByte Min(params CMYKAByte[] vals)
|
||||
{
|
||||
(int[] Cs, int[] Ms, int[] Ys, int[] Ks, int[] As) = SplitArrayInt(vals);
|
||||
return new(Mathf.Min(Cs), Mathf.Min(Ms), Mathf.Min(Ys), Mathf.Min(Ks), Mathf.Min(As));
|
||||
}
|
||||
|
||||
public static (byte[] Cs, byte[] Ms, byte[] Ys, byte[] Ks, byte[] As) SplitArray(params CMYKAByte[] vals)
|
||||
{
|
||||
@ -119,11 +160,11 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
As = new byte[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
Cs[i] = vals[i].C;
|
||||
Ms[i] = vals[i].M;
|
||||
Ys[i] = vals[i].Y;
|
||||
Ks[i] = vals[i].K;
|
||||
As[i] = vals[i].A;
|
||||
Cs[i] = vals[i].p_c;
|
||||
Ms[i] = vals[i].p_m;
|
||||
Ys[i] = vals[i].p_y;
|
||||
Ks[i] = vals[i].p_k;
|
||||
As[i] = vals[i].p_a;
|
||||
}
|
||||
return (Cs, Ms, Ys, Ks, As);
|
||||
}
|
||||
@ -143,62 +184,58 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
return (Cs, Ms, Ys, Ks, As);
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKAByte());
|
||||
public bool Equals(CMYKAByte col) => A == 0 && col.A == 0 || K == 1 && col.K == 255 || C == col.C && M == col.M
|
||||
&& Y == col.Y && K == col.K && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(CMYKAByte)) return Equals((CMYKAByte)obj);
|
||||
else if (t == typeof(RGBA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode()
|
||||
^ K.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider)
|
||||
+ " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider)
|
||||
+ " K: " + K.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "C: " + C.ToString(provider)
|
||||
+ " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider)
|
||||
+ " K: " + K.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte());
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA() => ToCMYKA().ToRGBA();
|
||||
public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f);
|
||||
public HSVA ToHSVA() => ToRGBA().ToHSVA();
|
||||
public HSVA ToHSVA() => ToCMYKA().ToHSVA();
|
||||
|
||||
public RGBAByte ToRGBAByte() => ToCMYKA().ToRGBAByte();
|
||||
public CMYKAByte ToCMYKAByte() => this;
|
||||
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
|
||||
public HSVAByte ToHSVAByte() => ToCMYKA().ToHSVAByte();
|
||||
|
||||
public byte[] ToArray() => new[] { C, M, Y, K, A };
|
||||
public byte[] ToArray() => new[] { p_c, p_m, p_y, p_k, p_a };
|
||||
public int[] ToArrayInt() => new[] { C, M, Y, K, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
CMYKAByte @this = this;
|
||||
return i => (byte)@this[i];
|
||||
}
|
||||
public Fill<int> ToFillInt()
|
||||
{
|
||||
CMYKAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { C, M, Y, K, A };
|
||||
public List<byte> ToList() => new() { p_c, p_m, p_y, p_k, p_a };
|
||||
public List<int> ToListInt() => new() { C, M, Y, K, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<byte> GetEnumerator()
|
||||
{
|
||||
yield return C;
|
||||
yield return M;
|
||||
yield return Y;
|
||||
yield return K;
|
||||
yield return A;
|
||||
yield return p_c;
|
||||
yield return p_m;
|
||||
yield return p_y;
|
||||
yield return p_k;
|
||||
yield return p_a;
|
||||
}
|
||||
|
||||
public object Clone() => new CMYKAByte(C, M, Y, K, A);
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("C = ");
|
||||
builder.Append(C);
|
||||
builder.Append(", M = ");
|
||||
builder.Append(M);
|
||||
builder.Append(", Y = ");
|
||||
builder.Append(Y);
|
||||
builder.Append(", K = ");
|
||||
builder.Append(K);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static CMYKAByte operator +(CMYKAByte a, CMYKAByte b) =>
|
||||
new(a.C + b.C, a.M + b.M, a.Y + b.Y, a.K + b.K, a.A + b.A);
|
||||
@ -216,26 +253,24 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
|
||||
public static CMYKAByte operator /(CMYKAByte a, int b) =>
|
||||
new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / b);
|
||||
public static CMYKAByte operator /(CMYKAByte a, float b) => (a.ToCMYKA() / b).ToCMYKAByte();
|
||||
public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(CMYKAByte a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, RGBAByte b) => !a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, CMYKAByte b) => !a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, HSVAByte b) => !a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator ==(CMYKAByte a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(CMYKAByte a, RGBAByte b) => a.Equals(b);
|
||||
|
||||
public static explicit operator CMYKAByte(Int3 val) => new(val.x, val.y, val.z, 0);
|
||||
public static implicit operator CMYKAByte(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static implicit operator CMYKAByte(RGBA val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(HSVA val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(RGBAByte val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(RGBA val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(CMYKA val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(HSVAByte val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(RGBAByte val) => val.ToCMYKAByte();
|
||||
public static implicit operator CMYKAByte(Fill<byte> val) => new(val);
|
||||
public static implicit operator CMYKAByte(Fill<int> val) => new(val);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct HSVA : IColor, IEquatable<HSVA>
|
||||
public record struct HSVA : IAverage<HSVA>, IClamp<HSVA>, IColorFloat<HSVA>, IColorPresets<HSVA>, IEquatable<HSVA>,
|
||||
IIndexAll<float>, IIndexRangeAll<float>, ILerp<HSVA, float>, IMedian<HSVA>,
|
||||
ISplittable<HSVA, (Angle[] Hs, float[] Ss, float[] Vs, float[] As)>
|
||||
{
|
||||
public static HSVA Black => new(Angle.Zero, 0, 0);
|
||||
public static HSVA Blue => new(new Angle(240), 1, 1);
|
||||
@ -74,25 +76,47 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
H = new(Mathf.Clamp(value, 0, 1), Angle.Type.Normalized);
|
||||
H = new(value, Angle.Type.Normalized);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
S = Mathf.Clamp(value, 0, 1);
|
||||
S = value;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
V = Mathf.Clamp(value, 0, 1);
|
||||
V = value;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
A = Mathf.Clamp(value, 0, 1);
|
||||
A = value;
|
||||
break;
|
||||
|
||||
default: throw new IndexOutOfRangeException(nameof(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static HSVA Average(params HSVA[] vals)
|
||||
{
|
||||
@ -100,15 +124,11 @@ public struct HSVA : 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 = Angle.Type.Degrees) => new(Angle.Ceiling(val.H, type),
|
||||
Mathf.Ceiling(val.S), Mathf.Ceiling(val.V), Mathf.Ceiling(val.A));
|
||||
public static HSVA Clamp(HSVA val, HSVA min, HSVA max) =>
|
||||
new(Angle.Clamp(val.H, min.H, max.H),
|
||||
Mathf.Clamp(val.S, min.S, max.S),
|
||||
Mathf.Clamp(val.V, min.V, max.V),
|
||||
Mathf.Clamp(val.A, min.A, max.A));
|
||||
public static HSVA Floor(HSVA val, Angle.Type type = Angle.Type.Degrees) => new(Angle.Floor(val.H, type),
|
||||
Mathf.Floor(val.S), Mathf.Floor(val.V), Mathf.Floor(val.A));
|
||||
public static HSVA Lerp(HSVA a, HSVA b, float t, bool clamp = true) =>
|
||||
new(Angle.Lerp(a.H, b.H, t, clamp), Mathf.Lerp(a.S, b.S, t, clamp), Mathf.Lerp(a.V, b.V, t, clamp),
|
||||
Mathf.Lerp(a.A, b.A, t, clamp));
|
||||
@ -118,18 +138,6 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
HSVA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static HSVA Max(params HSVA[] vals)
|
||||
{
|
||||
(Angle[] Hs, float[] Ss, float[] Vs, float[] As) = SplitArray(vals);
|
||||
return new(Angle.Max(Hs), Mathf.Max(Ss), Mathf.Max(Vs), Mathf.Max(As));
|
||||
}
|
||||
public static HSVA Min(params HSVA[] vals)
|
||||
{
|
||||
(Angle[] Hs, float[] Ss, float[] Vs, float[] As) = SplitArray(vals);
|
||||
return new(Angle.Min(Hs), Mathf.Min(Ss), Mathf.Min(Vs), Mathf.Min(As));
|
||||
}
|
||||
public static HSVA Round(HSVA val, Angle.Type type = Angle.Type.Degrees) => new(Angle.Round(val.H, type),
|
||||
Mathf.Round(val.S), Mathf.Round(val.V), Mathf.Round(val.A));
|
||||
|
||||
public static (Angle[] Hs, float[] Ss, float[] Vs, float[] As) SplitArray(params HSVA[] vals)
|
||||
{
|
||||
@ -160,30 +168,9 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToHSVA());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVA());
|
||||
public bool Equals(HSVA col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0
|
||||
|| H == col.H && S == col.S && V == col.V && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(HSVA)) return Equals((HSVA)obj);
|
||||
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
|
||||
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
|
||||
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA()
|
||||
{
|
||||
@ -195,7 +182,7 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
else if (d < 240) vals = (0, x, c);
|
||||
else if (d < 300) vals = (x, 0, c);
|
||||
else if (d < 360) vals = (c, 0, x);
|
||||
return new(vals.r + m, vals.g + m, vals.b + m);
|
||||
return new(vals.r + m, vals.g + m, vals.b + m, A);
|
||||
}
|
||||
public CMYKA ToCMYKA() => ToRGBA().ToCMYKA();
|
||||
public HSVA ToHSVA() => this;
|
||||
@ -222,32 +209,41 @@ public struct HSVA : IColor, IEquatable<HSVA>
|
||||
yield return A;
|
||||
}
|
||||
|
||||
public object Clone() => new HSVA(H, S, V, A);
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("H = ");
|
||||
builder.Append(H);
|
||||
builder.Append(", S = ");
|
||||
builder.Append(S);
|
||||
builder.Append(", V = ");
|
||||
builder.Append(V);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static HSVA operator +(HSVA a, HSVA b) => new(a.H + b.H, a.S + b.S, a.V + b.V, a.A + b.A);
|
||||
public static HSVA operator -(HSVA c) => new(1 - c.H.Normalized, 1 - c.S, 1 - c.V, c.A != 1 ? 1 - c.A : 1);
|
||||
public static HSVA operator -(HSVA a, HSVA b) => new(a.H - b.H, a.S - b.S, a.V - b.V, a.A - b.A);
|
||||
public static HSVA operator *(HSVA a, float b) => new(a.H * b, a.S * b, a.V * b, a.A * b);
|
||||
public static HSVA operator /(HSVA a, float b) => new(a.H / b, a.S / b, a.V / b, a.A / b);
|
||||
public static bool operator ==(HSVA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, RGBA b) => !a.Equals(b);
|
||||
public static bool operator ==(HSVA a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, CMYKA b) => !a.Equals(b);
|
||||
public static bool operator ==(HSVA a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, HSVA b) => !a.Equals(b);
|
||||
public static bool operator ==(HSVA a, RGBAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(HSVA a, RGBAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(HSVA a, CMYKAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(HSVA a, HSVAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(HSVA a, HSVAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(HSVA a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator ==(HSVA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator ==(HSVA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator ==(HSVA a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVA a, RGBAByte b) => a.Equals(b);
|
||||
|
||||
public static explicit operator HSVA(Float3 val) => new(val.x, val.y, val.z);
|
||||
public static explicit operator HSVA(Float4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static implicit operator HSVA(CMYKA val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(RGBA val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(RGBAByte val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(CMYKAByte val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(HSVAByte val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(RGBAByte val) => val.ToHSVA();
|
||||
public static implicit operator HSVA(Fill<float> val) => new(val);
|
||||
}
|
||||
|
||||
@ -1,21 +1,44 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
public record struct HSVAByte : IAverage<HSVAByte>, IClamp<HSVAByte>, IColorByte<HSVAByte>, IColorPresets<HSVAByte>,
|
||||
IEquatable<HSVAByte>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<HSVAByte, float>, IMedian<HSVAByte>,
|
||||
ISplittable<HSVAByte, (byte[] Hs, byte[] Ss, byte[] Vs, byte[] As)>
|
||||
{
|
||||
public static HSVA Black => new(Angle.Zero, 0, 0);
|
||||
public static HSVA Blue => new(new Angle(240), 255, 255);
|
||||
public static HSVA Clear => new(Angle.Zero, 0, 0, 0);
|
||||
public static HSVA Cyan => new(new Angle(180), 255, 255);
|
||||
public static HSVA Gray => new(Angle.Zero, 0, 127);
|
||||
public static HSVA Green => new(new Angle(120), 255, 255);
|
||||
public static HSVA Magenta => new(new Angle(300), 255, 255);
|
||||
public static HSVA Orange => new(new Angle(30), 255, 255);
|
||||
public static HSVA Purple => new(new Angle(270), 255, 255);
|
||||
public static HSVA Red => new(Angle.Zero, 255, 255);
|
||||
public static HSVA White => new(Angle.Zero, 0, 255);
|
||||
public static HSVA Yellow => new(new Angle(60), 255, 255);
|
||||
public static HSVAByte Black => new(Angle.Zero, 0, 0);
|
||||
public static HSVAByte Blue => new(new Angle(240), 255, 255);
|
||||
public static HSVAByte Clear => new(Angle.Zero, 0, 0, 0);
|
||||
public static HSVAByte Cyan => new(new Angle(180), 255, 255);
|
||||
public static HSVAByte Gray => new(Angle.Zero, 0, 127);
|
||||
public static HSVAByte Green => new(new Angle(120), 255, 255);
|
||||
public static HSVAByte Magenta => new(new Angle(300), 255, 255);
|
||||
public static HSVAByte Orange => new(new Angle(30), 255, 255);
|
||||
public static HSVAByte Purple => new(new Angle(270), 255, 255);
|
||||
public static HSVAByte Red => new(Angle.Zero, 255, 255);
|
||||
public static HSVAByte White => new(Angle.Zero, 0, 255);
|
||||
public static HSVAByte Yellow => new(new Angle(60), 255, 255);
|
||||
|
||||
public byte H, S, V, A;
|
||||
public int H
|
||||
{
|
||||
get => p_h;
|
||||
set => p_h = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int S
|
||||
{
|
||||
get => p_s;
|
||||
set => p_s = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int V
|
||||
{
|
||||
get => p_v;
|
||||
set => p_v = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int A
|
||||
{
|
||||
get => p_a;
|
||||
set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
|
||||
private byte p_h, p_s, p_v, p_a;
|
||||
|
||||
public bool HasColor => S != 0 && V != 0;
|
||||
public bool IsOpaque => A == 255;
|
||||
@ -27,17 +50,17 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
public HSVAByte(int h, int s, int v) : this(h, s, v, 255) { }
|
||||
public HSVAByte(int h, int s, int v, int a)
|
||||
{
|
||||
H = (byte)Mathf.Clamp(h, 0, 255);
|
||||
S = (byte)Mathf.Clamp(s, 0, 255);
|
||||
V = (byte)Mathf.Clamp(v, 0, 255);
|
||||
A = (byte)Mathf.Clamp(a, 0, 255);
|
||||
p_h = (byte)Mathf.Clamp(h, 0, 255);
|
||||
p_s = (byte)Mathf.Clamp(s, 0, 255);
|
||||
p_v = (byte)Mathf.Clamp(v, 0, 255);
|
||||
p_a = (byte)Mathf.Clamp(a, 0, 255);
|
||||
}
|
||||
public HSVAByte(Angle h, int s, int v) : this(h, s, v, 255) { }
|
||||
public HSVAByte(Angle h, int s, int v, int a) : this(Mathf.RoundInt(h.Normalized * 255), s, v, a) { }
|
||||
public HSVAByte(Fill<byte> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public HSVAByte(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
|
||||
public byte this[int index]
|
||||
public int this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
@ -71,6 +94,28 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static HSVAByte Average(params HSVAByte[] vals)
|
||||
{
|
||||
@ -83,7 +128,7 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
Mathf.Clamp(val.S, min.S, max.S),
|
||||
Mathf.Clamp(val.V, min.V, max.V),
|
||||
Mathf.Clamp(val.A, min.A, max.A));
|
||||
public static HSVAByte Lerp(HSVAByte a, HSVAByte b, byte t, bool clamp = true) =>
|
||||
public static HSVAByte Lerp(HSVAByte a, HSVAByte b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.H, b.H, t, clamp), Mathf.Lerp(a.S, b.S, t, clamp), Mathf.Lerp(a.V, b.V, t, clamp),
|
||||
Mathf.Lerp(a.A, b.A, t, clamp));
|
||||
public static HSVAByte Median(params HSVAByte[] vals)
|
||||
@ -92,16 +137,6 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
HSVAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static HSVAByte Max(params HSVAByte[] vals)
|
||||
{
|
||||
(int[] Hs, int[] Ss, int[] Vs, int[] As) = SplitArrayInt(vals);
|
||||
return new(Mathf.Max(Hs), Mathf.Max(Ss), Mathf.Max(Vs), Mathf.Max(As));
|
||||
}
|
||||
public static HSVAByte Min(params HSVAByte[] vals)
|
||||
{
|
||||
(int[] Hs, int[] Ss, int[] Vs, int[] As) = SplitArrayInt(vals);
|
||||
return new(Mathf.Min(Hs), Mathf.Min(Ss), Mathf.Min(Vs), Mathf.Min(As));
|
||||
}
|
||||
|
||||
public static (byte[] Hs, byte[] Ss, byte[] Vs, byte[] As) SplitArray(params HSVAByte[] vals)
|
||||
{
|
||||
@ -109,10 +144,10 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
Vs = new byte[vals.Length], As = new byte[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
Hs[i] = vals[i].H;
|
||||
Ss[i] = vals[i].S;
|
||||
Vs[i] = vals[i].V;
|
||||
As[i] = vals[i].A;
|
||||
Hs[i] = vals[i].p_h;
|
||||
Ss[i] = vals[i].p_s;
|
||||
Vs[i] = vals[i].p_v;
|
||||
As[i] = vals[i].p_a;
|
||||
}
|
||||
return (Hs, Ss, Vs, As);
|
||||
}
|
||||
@ -131,30 +166,9 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToHSVAByte());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToHSVAByte());
|
||||
public bool Equals(HSVAByte col) => S == 0 && col.S == 0 || V == 0 && col.V == 0 || A == 0 && col.A == 0
|
||||
|| H == col.H && S == col.S && V == col.V && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(HSVAByte)) return Equals((HSVAByte)obj);
|
||||
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
|
||||
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
|
||||
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA() => ToHSVA().ToRGBA();
|
||||
public CMYKA ToCMYKA() => ToHSVA().ToCMYKA();
|
||||
@ -164,24 +178,42 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
public CMYKAByte ToCMYKAByte() => ToHSVA().ToCMYKAByte();
|
||||
public HSVAByte ToHSVAByte() => this;
|
||||
|
||||
public byte[] ToArray() => new[] { H, S, V, A };
|
||||
public byte[] ToArray() => new[] { p_h, p_s, p_v, p_a };
|
||||
public int[] ToArrayInt() => new[] { H, S, V, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
HSVAByte @this = this;
|
||||
return i => (byte)@this[i];
|
||||
}
|
||||
public Fill<int> ToFillInt()
|
||||
{
|
||||
HSVAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { H, S, V, A };
|
||||
public List<byte> ToList() => new() { p_h, p_s, p_v, p_a };
|
||||
public List<int> ToListInt() => new() { H, S, V, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<byte> GetEnumerator()
|
||||
{
|
||||
yield return H;
|
||||
yield return S;
|
||||
yield return V;
|
||||
yield return A;
|
||||
yield return p_h;
|
||||
yield return p_s;
|
||||
yield return p_v;
|
||||
yield return p_a;
|
||||
}
|
||||
|
||||
public object Clone() => new HSVAByte(H, S, V, A);
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("H = ");
|
||||
builder.Append(H);
|
||||
builder.Append(", S = ");
|
||||
builder.Append(S);
|
||||
builder.Append(", V = ");
|
||||
builder.Append(V);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static HSVAByte operator +(HSVAByte a, HSVAByte b) => new(a.H + b.H, a.S + b.S, a.V + b.V, a.A + b.A);
|
||||
public static HSVAByte operator -(HSVAByte c) => new(255 - c.H, 255 - c.S, 255 - c.V, c.A != 255 ? 255 - c.A : 255);
|
||||
@ -192,18 +224,16 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
|
||||
public static HSVAByte operator /(HSVAByte a, HSVAByte b) => new(a.H / b.H, a.S / b.S, a.V / b.V, a.A / b.A);
|
||||
public static HSVAByte operator /(HSVAByte a, int b) => new(a.H / b, a.S / b, a.V / b, a.A / b);
|
||||
public static HSVAByte operator /(HSVAByte a, float b) => (a.ToHSVA() * b).ToHSVAByte();
|
||||
public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(HSVAByte a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, RGBAByte b) => !a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, CMYKAByte b) => !a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, HSVAByte b) => !a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator ==(HSVAByte a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(HSVAByte a, RGBAByte b) => a.Equals(b);
|
||||
|
||||
public static implicit operator HSVAByte(Int3 val) => new(val.x, val.y, val.z);
|
||||
public static implicit operator HSVAByte(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public interface IColor : ICloneable, IEquatable<IColor?>, IEquatable<IColorByte?>, IGroup<float>
|
||||
{
|
||||
public RGBA ToRGBA();
|
||||
public CMYKA ToCMYKA();
|
||||
public HSVA ToHSVA();
|
||||
|
||||
public RGBAByte ToRGBAByte();
|
||||
public CMYKAByte ToCMYKAByte();
|
||||
public HSVAByte ToHSVAByte();
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public interface IColorByte : ICloneable, IEquatable<IColor?>, IEquatable<IColorByte?>, IGroup<byte>
|
||||
{
|
||||
public RGBA ToRGBA();
|
||||
public CMYKA ToCMYKA();
|
||||
public HSVA ToHSVA();
|
||||
|
||||
public RGBAByte ToRGBAByte();
|
||||
public CMYKAByte ToCMYKAByte();
|
||||
public HSVAByte ToHSVAByte();
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
public class Image : ICloneable, IEnumerable<IColor>, IEquatable<Image>
|
||||
{
|
||||
public IColor[,] Pixels { get; init; }
|
||||
public Int2 Size { get; init; }
|
||||
public IColor[,] Pixels { get; private set; }
|
||||
public Int2 Size { get; private set; }
|
||||
|
||||
public Image(int width, int height)
|
||||
{
|
||||
@ -15,12 +15,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
{
|
||||
Pixels = new IColor[width, height];
|
||||
Size = new(width, height);
|
||||
for (int y = 0; y < width; y++) for (int x = 0; x < height; x++) Pixels[x, y] = cols[y * width + x];
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y * width + x];
|
||||
}
|
||||
public Image(int width, int height, IColor[,] cols)
|
||||
{
|
||||
Pixels = cols;
|
||||
Pixels = new IColor[width, height];
|
||||
Size = new(width, height);
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = cols[y, x];
|
||||
}
|
||||
public Image(int width, int height, Fill<IColor> fill)
|
||||
{
|
||||
@ -32,28 +33,13 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
{
|
||||
Pixels = new IColor[width, height];
|
||||
Size = new(width, height);
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(x, y);
|
||||
}
|
||||
public Image(int width, int height, Fill<IColorByte> fill)
|
||||
{
|
||||
Pixels = new IColor[width, height];
|
||||
Size = new(width, height);
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++)
|
||||
Pixels[x, y] = (IColor)fill(y * width + x);
|
||||
}
|
||||
public Image(int width, int height, Fill2D<IColorByte> fill)
|
||||
{
|
||||
Pixels = new IColor[width, height];
|
||||
Size = new(width, height);
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = (IColor)fill(x, y);
|
||||
for (int y = 0; y < height; y++) for (int x = 0; x < width; x++) Pixels[x, y] = fill(y, x);
|
||||
}
|
||||
public Image(Int2 size) : this(size.x, size.y) { }
|
||||
public Image(Int2 size, IColor[] cols) : this(size.x, size.y, cols) { }
|
||||
public Image(Int2 size, IColor[,] cols) : this(size.x, size.y, cols) { }
|
||||
public Image(Int2 size, Fill<IColor> fill) : this(size.x, size.y, fill) { }
|
||||
public Image(Int2 size, Fill2D<IColor> fill) : this(size.x, size.y, fill) { }
|
||||
public Image(Int2 size, Fill<IColorByte> fill) : this(size.x, size.y, fill) { }
|
||||
public Image(Int2 size, Fill2D<IColorByte> fill) : this(size.x, size.y, fill) { }
|
||||
|
||||
public IColor this[int indexX, int indexY]
|
||||
{
|
||||
@ -72,7 +58,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
|
||||
public object Clone() => new Image(Size, Pixels);
|
||||
|
||||
public bool Equals(Image other) => Pixels == other.Pixels;
|
||||
public bool Equals(Image? other) => other is not null && Pixels == other.Pixels;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
@ -124,7 +110,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
for (int y = 0; y < Size.y; y++) for (int x = 0; x < Size.x; x++)
|
||||
{
|
||||
HSVA col = Pixels[x, y].ToHSVA();
|
||||
col.S = (set ? 0 : col.S) + value;
|
||||
col.S = (set ? 1 : col.S) * value;
|
||||
Pixels[x, y] = col;
|
||||
}
|
||||
}
|
||||
@ -144,10 +130,11 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
|
||||
for (int y = 0; y < newSize.y; y++) for (int x = 0; x < newSize.x; x++)
|
||||
{
|
||||
Float2 f = new((float)x / newSize.x, (float)y / newSize.y);
|
||||
RGBA col = Pixels[Mathf.RoundInt(f.x * Size.x), Mathf.RoundInt(f.y * Size.y)].ToRGBA();
|
||||
RGBA col = Pixels[Mathf.Floor(f.x * Size.x), Mathf.Floor(f.y * Size.y)].ToRGBA();
|
||||
img[x, y] = col;
|
||||
}
|
||||
this = img;
|
||||
Pixels = img.Pixels;
|
||||
Size = img.Size;
|
||||
}
|
||||
|
||||
public IColor[] ToArray()
|
||||
|
||||
@ -1,21 +1,23 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
using Nerd_STF.Graphics.Abstract;
|
||||
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct Material : ICloneable, IEquatable<Material>
|
||||
{
|
||||
public float Alpha;
|
||||
public float Anisotropy;
|
||||
public float AnisotropyRoughness;
|
||||
public IColor AmbientColor;
|
||||
public IColorFloat AmbientColor;
|
||||
public float ClearcoatRoughness;
|
||||
public float ClearcoatThickness;
|
||||
public IColor DiffuseColor;
|
||||
public IColor Emissive;
|
||||
public IColorFloat DiffuseColor;
|
||||
public IColorFloat Emissive;
|
||||
public IlluminationModel IllumModel;
|
||||
public float Metallic;
|
||||
public float OpticalDensity;
|
||||
public float Roughness;
|
||||
public float Sheen;
|
||||
public IColor SpecularColor;
|
||||
public IColorFloat SpecularColor;
|
||||
public float SpecularExponent;
|
||||
|
||||
public (Image Image, TextureConfig Config) AlphaTexture;
|
||||
@ -67,17 +69,17 @@ public struct Material : ICloneable, IEquatable<Material>
|
||||
Alpha = (float)fill(0);
|
||||
Anisotropy = (float)fill(1);
|
||||
AnisotropyRoughness = (float)fill(2);
|
||||
AmbientColor = (IColor)fill(3);
|
||||
AmbientColor = (IColorFloat)fill(3);
|
||||
ClearcoatRoughness = (float)fill(4);
|
||||
ClearcoatThickness = (float)fill(5);
|
||||
DiffuseColor = (IColor)fill(6);
|
||||
Emissive = (IColor)fill(7);
|
||||
DiffuseColor = (IColorFloat)fill(6);
|
||||
Emissive = (IColorFloat)fill(7);
|
||||
IllumModel = (IlluminationModel)fill(8);
|
||||
Metallic = (float)fill(9);
|
||||
OpticalDensity = (float)fill(10);
|
||||
Roughness = (float)fill(11);
|
||||
Sheen = (float)fill(12);
|
||||
SpecularColor = (IColor)fill(13);
|
||||
SpecularColor = (IColorFloat)fill(13);
|
||||
SpecularExponent = (float)fill(14);
|
||||
|
||||
AlphaTexture = ((Image, TextureConfig))fill(15);
|
||||
@ -93,7 +95,7 @@ public struct Material : ICloneable, IEquatable<Material>
|
||||
SpecularHighlightTexture = ((Image, TextureConfig))fill(25);
|
||||
StencilTexture = ((Image, TextureConfig))fill(26);
|
||||
}
|
||||
public Material(IlluminationModel illum, Fill<float> floats, Fill<IColor> colors, Fill<(Image, TextureConfig)> images)
|
||||
public Material(IlluminationModel illum, Fill<float> floats, Fill<IColorFloat> colors, Fill<(Image, TextureConfig)> images)
|
||||
{
|
||||
Alpha = floats(0);
|
||||
Anisotropy = floats(1);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct RGBA : IColor, IEquatable<RGBA>
|
||||
public record struct RGBA : IAverage<RGBA>, IClamp<RGBA>, IColorFloat<RGBA>, IEquatable<RGBA>, IIndexAll<float>,
|
||||
IIndexRangeAll<float>, ILerp<RGBA, float>, IMedian<RGBA>,
|
||||
ISplittable<RGBA, (float[] Rs, float[] Gs, float[] Bs, float[] As)>
|
||||
{
|
||||
public static RGBA Black => new(0, 0, 0);
|
||||
public static RGBA Blue => new(0, 0, 1);
|
||||
@ -91,6 +93,28 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static RGBA Average(params RGBA[] vals)
|
||||
{
|
||||
@ -98,15 +122,11 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
for (int i = 0; i < vals.Length; i++) val += vals[i];
|
||||
return val / vals.Length;
|
||||
}
|
||||
public static RGBA Ceiling(RGBA val) =>
|
||||
new(Mathf.Ceiling(val.R), Mathf.Ceiling(val.G), Mathf.Ceiling(val.B), Mathf.Ceiling(val.A));
|
||||
public static RGBA Clamp(RGBA val, RGBA min, RGBA max) =>
|
||||
new(Mathf.Clamp(val.R, min.R, max.R),
|
||||
Mathf.Clamp(val.G, min.G, max.G),
|
||||
Mathf.Clamp(val.B, min.B, max.B),
|
||||
Mathf.Clamp(val.A, min.A, max.A));
|
||||
public static RGBA Floor(RGBA val) =>
|
||||
new(Mathf.Floor(val.R), Mathf.Floor(val.G), Mathf.Floor(val.B), Mathf.Floor(val.A));
|
||||
public static RGBA Lerp(RGBA a, RGBA b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.R, b.R, t, clamp), Mathf.Lerp(a.G, b.G, t, clamp), Mathf.Lerp(a.B, b.B, t, clamp),
|
||||
Mathf.Lerp(a.A, b.A, t, clamp));
|
||||
@ -122,18 +142,6 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
RGBA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||
return Average(valA, valB);
|
||||
}
|
||||
public static RGBA Max(params RGBA[] vals)
|
||||
{
|
||||
(float[] Rs, float[] Gs, float[] Bs, float[] As) = SplitArray(vals);
|
||||
return new(Mathf.Max(Rs), Mathf.Max(Gs), Mathf.Max(Bs), Mathf.Max(As));
|
||||
}
|
||||
public static RGBA Min(params RGBA[] vals)
|
||||
{
|
||||
(float[] Rs, float[] Gs, float[] Bs, float[] As) = SplitArray(vals);
|
||||
return new(Mathf.Min(Rs), Mathf.Min(Gs), Mathf.Min(Bs), Mathf.Min(As));
|
||||
}
|
||||
public static RGBA Round(RGBA val) =>
|
||||
new(Mathf.Round(val.R), Mathf.Round(val.G), Mathf.Round(val.B), Mathf.Round(val.A));
|
||||
|
||||
public static (float[] Rs, float[] Gs, float[] Bs, float[] As) SplitArray(params RGBA[] vals)
|
||||
{
|
||||
@ -150,29 +158,8 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToRGBA());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBA());
|
||||
public bool Equals(RGBA col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(RGBA)) return Equals((RGBA)obj);
|
||||
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
|
||||
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
|
||||
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA() => this;
|
||||
public CMYKA ToCMYKA()
|
||||
@ -223,10 +210,21 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
yield return A;
|
||||
}
|
||||
|
||||
public object Clone() => new RGBA(R, G, B, A);
|
||||
|
||||
public Vector3d ToVector() => ((Float3)this).ToVector();
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("R = ");
|
||||
builder.Append(R);
|
||||
builder.Append(", G = ");
|
||||
builder.Append(G);
|
||||
builder.Append(", B = ");
|
||||
builder.Append(B);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static RGBA operator +(RGBA a, RGBA b) => new(a.R + b.R, a.G + b.G, a.B + b.B, a.A + b.A);
|
||||
public static RGBA operator -(RGBA c) => new(1 - c.R, 1 - c.G, 1 - c.B, c.A != 1 ? 1 - c.A : 1);
|
||||
public static RGBA operator -(RGBA a, RGBA b) => new(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A);
|
||||
@ -234,25 +232,23 @@ public struct RGBA : IColor, IEquatable<RGBA>
|
||||
public static RGBA operator *(RGBA a, float b) => new(a.R * b, a.G * b, a.B * b, a.A * b);
|
||||
public static RGBA operator /(RGBA a, RGBA b) => new(a.R / b.R, a.G / b.G, a.B / b.B, a.A / b.A);
|
||||
public static RGBA operator /(RGBA a, float b) => new(a.R / b, a.G / b, a.B / b, a.A / b);
|
||||
public static bool operator ==(RGBA a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, RGBA b) => !a.Equals(b);
|
||||
public static bool operator ==(RGBA a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, CMYKA b) => !a.Equals(b);
|
||||
public static bool operator !=(RGBA a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator ==(RGBA a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, HSVA b) => !a.Equals(b);
|
||||
public static bool operator ==(RGBA a, RGBAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(RGBA a, RGBAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(RGBA a, CMYKAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(RGBA a, CMYKAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator ==(RGBA a, HSVAByte b) => a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(RGBA a, HSVAByte b) => !a.Equals((IColorByte?)b);
|
||||
public static bool operator !=(RGBA a, HSVA b) => a.Equals(b);
|
||||
public static bool operator ==(RGBA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator ==(RGBA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator ==(RGBA a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBA a, RGBAByte b) => a.Equals(b);
|
||||
|
||||
public static implicit operator RGBA(Float3 val) => new(val.x, val.y, val.z);
|
||||
public static implicit operator RGBA(Float4 val) => new(val.x, val.y, val.z, val.w);
|
||||
public static implicit operator RGBA(CMYKA val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(HSVA val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(RGBAByte val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(CMYKAByte val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(HSVAByte val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(RGBAByte val) => val.ToRGBA();
|
||||
public static implicit operator RGBA(Fill<float> val) => new(val);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Graphics;
|
||||
|
||||
public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public record struct RGBAByte : IAverage<RGBAByte>, IClamp<RGBAByte>, IColorByte<RGBAByte>, IColorPresets<RGBAByte>,
|
||||
IEquatable<RGBAByte>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<RGBAByte, float>, IMedian<RGBAByte>,
|
||||
ISplittable<RGBAByte, (byte[] Rs, byte[] Gs, byte[] Bs, byte[] As)>
|
||||
{
|
||||
public static RGBAByte Black => new(0, 0, 0);
|
||||
public static RGBAByte Blue => new(0, 0, 255);
|
||||
@ -15,7 +17,28 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public static RGBAByte White => new(255, 255, 255);
|
||||
public static RGBAByte Yellow => new(255, 255, 0);
|
||||
|
||||
public byte R, G, B, A;
|
||||
public int R
|
||||
{
|
||||
get => p_r;
|
||||
set => p_r = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int G
|
||||
{
|
||||
get => p_g;
|
||||
set => p_g = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int B
|
||||
{
|
||||
get => p_b;
|
||||
set => p_b = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
public int A
|
||||
{
|
||||
get => p_a;
|
||||
set => p_a = (byte)Mathf.Clamp(value, byte.MinValue, byte.MaxValue);
|
||||
}
|
||||
|
||||
private byte p_r, p_g, p_b, p_a;
|
||||
|
||||
public bool HasBlue => B > 0;
|
||||
public bool HasGreen => G > 0;
|
||||
@ -37,7 +60,7 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public RGBAByte(Fill<byte> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
public RGBAByte(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||
|
||||
public byte this[int index]
|
||||
public int this[int index]
|
||||
{
|
||||
get => index switch
|
||||
{
|
||||
@ -71,6 +94,28 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static RGBAByte Average(params RGBAByte[] vals)
|
||||
{
|
||||
@ -83,7 +128,7 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
Mathf.Clamp(val.G, min.G, max.G),
|
||||
Mathf.Clamp(val.B, min.B, max.B),
|
||||
Mathf.Clamp(val.A, min.A, max.A));
|
||||
public static RGBAByte Lerp(RGBAByte a, RGBAByte b, byte t, bool clamp = true) =>
|
||||
public static RGBAByte Lerp(RGBAByte a, RGBAByte b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.R, b.R, t, clamp), Mathf.Lerp(a.G, b.G, t, clamp), Mathf.Lerp(a.B, b.B, t, clamp),
|
||||
Mathf.Lerp(a.A, b.A, t, clamp));
|
||||
public static RGBAByte LerpSquared(RGBAByte a, RGBAByte b, byte t, bool clamp = true) =>
|
||||
@ -111,10 +156,10 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
Bs = new byte[vals.Length], As = new byte[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
Rs[i] = vals[i].R;
|
||||
Gs[i] = vals[i].G;
|
||||
Bs[i] = vals[i].B;
|
||||
As[i] = vals[i].A;
|
||||
Rs[i] = vals[i].p_r;
|
||||
Gs[i] = vals[i].p_g;
|
||||
Bs[i] = vals[i].p_b;
|
||||
As[i] = vals[i].p_a;
|
||||
}
|
||||
return (Rs, Gs, Bs, As);
|
||||
}
|
||||
@ -133,29 +178,8 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
}
|
||||
|
||||
public bool Equals(IColor? col) => col != null && Equals(col.ToRGBAByte());
|
||||
public bool Equals(IColorByte? col) => col != null && Equals(col.ToRGBAByte());
|
||||
public bool Equals(RGBAByte col) => A == 0 && col.A == 0 || R == col.R && G == col.G && B == col.B && A == col.A;
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type t = obj.GetType();
|
||||
if (t == typeof(RGBAByte)) return Equals((RGBAByte)obj);
|
||||
else if (t == typeof(CMYKA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(HSVA)) return Equals((IColor)obj);
|
||||
else if (t == typeof(IColor)) return Equals((IColor)obj);
|
||||
else if (t == typeof(RGBA)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
|
||||
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
|
||||
|
||||
return base.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode();
|
||||
public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
|
||||
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
|
||||
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public RGBA ToRGBA() => new(R / 255f, G / 255f, B / 255f, A / 255f);
|
||||
public CMYKA ToCMYKA() => ToRGBA().ToCMYKA();
|
||||
@ -165,27 +189,45 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public CMYKAByte ToCMYKAByte() => ToRGBA().ToCMYKAByte();
|
||||
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte();
|
||||
|
||||
public byte[] ToArray() => new[] { R, G, B, A };
|
||||
public byte[] ToArray() => new[] { p_r, p_g, p_b, p_a };
|
||||
public int[] ToArrayInt() => new[] { R, G, B, A };
|
||||
public Fill<byte> ToFill()
|
||||
{
|
||||
HSVAByte @this = this;
|
||||
RGBAByte @this = this;
|
||||
return i => (byte)@this[i];
|
||||
}
|
||||
public Fill<int> ToFillInt()
|
||||
{
|
||||
RGBAByte @this = this;
|
||||
return i => @this[i];
|
||||
}
|
||||
public List<byte> ToList() => new() { R, G, B, A };
|
||||
public List<byte> ToList() => new() { p_r, p_g, p_b, p_a };
|
||||
public List<int> ToListInt() => new() { R, G, B, A };
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<byte> GetEnumerator()
|
||||
{
|
||||
yield return R;
|
||||
yield return G;
|
||||
yield return B;
|
||||
yield return A;
|
||||
yield return p_r;
|
||||
yield return p_g;
|
||||
yield return p_b;
|
||||
yield return p_a;
|
||||
}
|
||||
|
||||
public object Clone() => new RGBAByte(R, G, B, A);
|
||||
|
||||
public Vector3d ToVector() => ((RGBA)this).ToVector();
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("R = ");
|
||||
builder.Append(R);
|
||||
builder.Append(", G = ");
|
||||
builder.Append(G);
|
||||
builder.Append(", B = ");
|
||||
builder.Append(B);
|
||||
builder.Append(", A = ");
|
||||
builder.Append(A);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static RGBAByte operator +(RGBAByte a, RGBAByte b) => new(a.R + b.R, a.G + b.G, a.B + b.B, a.A + b.A);
|
||||
public static RGBAByte operator -(RGBAByte c) => new(255 - c.R, 255 - c.G, 255 - c.B, c.A != 255 ? 255 - c.A : 255);
|
||||
public static RGBAByte operator -(RGBAByte a, RGBAByte b) => new(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A);
|
||||
@ -195,18 +237,16 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
|
||||
public static RGBAByte operator /(RGBAByte a, RGBAByte b) => new(a.R / b.R, a.G / b.G, a.B / b.B, a.A / b.A);
|
||||
public static RGBAByte operator /(RGBAByte a, int b) => new(a.R / b, a.G / b, a.B / b, a.A / b);
|
||||
public static RGBAByte operator /(RGBAByte a, float b) => (a.ToRGBA() / b).ToRGBAByte();
|
||||
public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColor?)b);
|
||||
public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColor?)b);
|
||||
public static bool operator ==(RGBAByte a, RGBAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, RGBAByte b) => !a.Equals(b);
|
||||
public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, CMYKA b) => a.Equals(b);
|
||||
public static bool operator ==(RGBAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, HSVA b) => a.Equals(b);
|
||||
public static bool operator ==(RGBAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, RGBA b) => a.Equals(b);
|
||||
public static bool operator ==(RGBAByte a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, CMYKAByte b) => !a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, CMYKAByte b) => a.Equals(b);
|
||||
public static bool operator ==(RGBAByte a, HSVAByte b) => a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, HSVAByte b) => !a.Equals(b);
|
||||
public static bool operator !=(RGBAByte a, HSVAByte b) => a.Equals(b);
|
||||
|
||||
public static implicit operator RGBAByte(Int3 val) => new(val.x, val.y, val.z);
|
||||
public static implicit operator RGBAByte(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public interface IClosest<T> where T : IEquatable<T>
|
||||
{
|
||||
public T ClosestTo(T item);
|
||||
}
|
||||
@ -1,6 +0,0 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public interface IContainer<T> where T : IEquatable<T>
|
||||
{
|
||||
public bool Contains(T item);
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
namespace Nerd_STF;
|
||||
|
||||
public interface IEncapsulator<T, TE> : IContainer<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
||||
public interface IEncapsulator<T, TE> : IContains<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
||||
{
|
||||
public T Encapsulate(TE val);
|
||||
}
|
||||
|
||||
6
Nerd_STF/Mathematics/Abstract/IAbsolute.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IAbsolute.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IAbsolute<T> where T : IAbsolute<T>
|
||||
{
|
||||
public static abstract T Absolute(T val);
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IAverage.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IAverage.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IAverage<T> where T : IAverage<T>
|
||||
{
|
||||
public static abstract T Average(params T[] vals);
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/ICeiling.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/ICeiling.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ICeiling<TSelf> : ICeiling<TSelf, TSelf> where TSelf : ICeiling<TSelf> { }
|
||||
public interface ICeiling<TSelf, TRound> where TSelf : ICeiling<TSelf, TRound>
|
||||
{
|
||||
public static abstract TRound Ceiling(TSelf val);
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IClamp.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IClamp.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IClamp<T> where T : IClamp<T>
|
||||
{
|
||||
public static abstract T Clamp(T val, T min, T max);
|
||||
}
|
||||
15
Nerd_STF/Mathematics/Abstract/IClampMagnitude.cs
Normal file
15
Nerd_STF/Mathematics/Abstract/IClampMagnitude.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IClampMagnitude<TSelf, TNumber>
|
||||
where TSelf : IClampMagnitude<TSelf, TNumber>
|
||||
where TNumber : INumber<TNumber>
|
||||
{
|
||||
public static abstract TSelf ClampMagnitude(TSelf val, TNumber minMag, TNumber maxMag);
|
||||
}
|
||||
public interface IClampMagnitude<TSelf> where TSelf : IClampMagnitude<TSelf>
|
||||
{
|
||||
public static abstract TSelf ClampMagnitude<TNumber>(TSelf val, TNumber minMag, TNumber maxMag)
|
||||
where TNumber : INumber<TNumber>;
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IClosestTo.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IClosestTo.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IClosestTo<T> where T : IEquatable<T>
|
||||
{
|
||||
public T ClosestTo(T item);
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IContains.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IContains.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IContains<T> where T : IEquatable<T>
|
||||
{
|
||||
public bool Contains(T item);
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/ICross.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/ICross.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ICross<TSelf> : ICross<TSelf, TSelf>
|
||||
where TSelf : ICross<TSelf> { }
|
||||
public interface ICross<TSelf, TOut> where TSelf : ICross<TSelf, TOut>
|
||||
{
|
||||
public static abstract TOut Cross(TSelf a, TSelf b, bool normalized = false);
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/IDivide.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/IDivide.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IDivide<T> : IDivisionOperators<T, T, T> where T : IDivide<T>
|
||||
{
|
||||
public static abstract T Divide(T num, params T[] vals);
|
||||
}
|
||||
18
Nerd_STF/Mathematics/Abstract/IDot.cs
Normal file
18
Nerd_STF/Mathematics/Abstract/IDot.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IDot<TSelf, TNumber>
|
||||
where TSelf : IDot<TSelf, TNumber>
|
||||
where TNumber : INumber<TNumber>
|
||||
{
|
||||
public static abstract TNumber Dot(TSelf a, TSelf b);
|
||||
public static abstract TNumber Dot(TSelf[] vals);
|
||||
}
|
||||
public interface IDot<TSelf> where TSelf : IDot<TSelf>
|
||||
{
|
||||
public static abstract TNumber Dot<TNumber>(TSelf a, TSelf b)
|
||||
where TNumber : INumber<TNumber>;
|
||||
public static abstract TNumber Dot<TNumber>(TSelf[] vals)
|
||||
where TNumber : INumber<TNumber>;
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IFloor.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IFloor.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IFloor<TSelf> : IFloor<TSelf, TSelf>
|
||||
where TSelf : IFloor<TSelf> { }
|
||||
public interface IFloor<TSelf, TRound>
|
||||
where TSelf : IFloor<TSelf, TRound>
|
||||
{
|
||||
public static abstract TRound Floor(TSelf val);
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IFromTuple.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IFromTuple.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IFromTuple<TSelf, TTuple> where TSelf : IFromTuple<TSelf, TTuple>
|
||||
where TTuple : ITuple
|
||||
{
|
||||
public static abstract implicit operator TSelf(TTuple val);
|
||||
}
|
||||
3
Nerd_STF/Mathematics/Abstract/IIndexAll.cs
Normal file
3
Nerd_STF/Mathematics/Abstract/IIndexAll.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexAll<TSub> : IIndexGet<TSub>, IIndexSet<TSub> { }
|
||||
7
Nerd_STF/Mathematics/Abstract/IIndexGet.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IIndexGet.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexGet<TSub>
|
||||
{
|
||||
public TSub this[int index] { get; }
|
||||
public TSub this[Index index] { get; }
|
||||
}
|
||||
3
Nerd_STF/Mathematics/Abstract/IIndexRangeAll.cs
Normal file
3
Nerd_STF/Mathematics/Abstract/IIndexRangeAll.cs
Normal file
@ -0,0 +1,3 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexRangeAll<TSub> : IIndexRangeGet<TSub>, IIndexRangeSet<TSub> { }
|
||||
6
Nerd_STF/Mathematics/Abstract/IIndexRangeGet.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IIndexRangeGet.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexRangeGet<TSub>
|
||||
{
|
||||
public TSub[] this[Range range] { get; }
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IIndexRangeSet.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IIndexRangeSet.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexRangeSet<TSub>
|
||||
{
|
||||
public TSub[] this[Range range] { set; }
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/IIndexSet.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IIndexSet.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IIndexSet<TSub>
|
||||
{
|
||||
public TSub this[int index] { set; }
|
||||
public TSub this[Index index] { set; }
|
||||
}
|
||||
15
Nerd_STF/Mathematics/Abstract/ILerp.cs
Normal file
15
Nerd_STF/Mathematics/Abstract/ILerp.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ILerp<TSelf, TNumber>
|
||||
where TSelf : ILerp<TSelf, TNumber>
|
||||
where TNumber : INumber<TNumber>
|
||||
{
|
||||
public static abstract TSelf Lerp(TSelf a, TSelf b, TNumber t, bool clamp = true);
|
||||
}
|
||||
public interface ILerp<TSelf> where TSelf : ILerp<TSelf>
|
||||
{
|
||||
public static abstract TSelf Lerp<TNumber>(TSelf a, TSelf b, TNumber t, bool clamp = true)
|
||||
where TNumber : INumber<TNumber>;
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/IMagnitude.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/IMagnitude.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMagnitude<TNumber> where TNumber : INumber<TNumber>
|
||||
{
|
||||
public TNumber Magnitude { get; }
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/IMathOperators.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/IMathOperators.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMathOperators<TSelf> : IAdditionOperators<TSelf, TSelf, TSelf>,
|
||||
ISubtractionOperators<TSelf, TSelf, TSelf>, IMultiplyOperators<TSelf, TSelf, TSelf>,
|
||||
IDivisionOperators<TSelf, TSelf, TSelf>
|
||||
where TSelf : IMathOperators<TSelf> { }
|
||||
@ -1,14 +1,14 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMatrix<T> : ICloneable, IEnumerable, IEquatable<T>, IGroup2D<float>
|
||||
public interface IMatrix<T> : IAbsolute<T>, ICeiling<T>, IClamp<T>, IDivide<T>,
|
||||
IEquatable<T>, IFloor<T>, IGroup2D<float>, ILerp<T, float>, IProduct<T>, IRound<T>,
|
||||
ISubtract<T>, ISum<T>
|
||||
where T : IMatrix<T>
|
||||
{
|
||||
public T Adjugate();
|
||||
public float Determinant();
|
||||
public T Inverse();
|
||||
public T? Inverse();
|
||||
public T Transpose();
|
||||
|
||||
public Dictionary<Int2, float> ToDictionary();
|
||||
}
|
||||
|
||||
public interface IMatrix<This, TMinor> : IMatrix<This> where This : IMatrix<This, TMinor>
|
||||
9
Nerd_STF/Mathematics/Abstract/IMatrixPresets.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IMatrixPresets.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMatrixPresets<T> where T : IMatrix<T>, IMatrixPresets<T>
|
||||
{
|
||||
public static abstract T Identity { get; }
|
||||
public static abstract T One { get; }
|
||||
public static abstract T SignGrid { get; }
|
||||
public static abstract T Zero { get; }
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IMax.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IMax.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMax<T> where T : IMax<T>, IComparable<T>
|
||||
{
|
||||
public static virtual T Max(params T[] vals) => Mathf.Max(vals);
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IMedian.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IMedian.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMedian<T> where T : IMedian<T>
|
||||
{
|
||||
public static virtual T Median(params T[] vals) => Mathf.Median(vals);
|
||||
}
|
||||
6
Nerd_STF/Mathematics/Abstract/IMin.cs
Normal file
6
Nerd_STF/Mathematics/Abstract/IMin.cs
Normal file
@ -0,0 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IMin<T> where T : IMin<T>, IComparable<T>
|
||||
{
|
||||
public static virtual T Min(params T[] vals) => Mathf.Min(vals);
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/IPresets1D.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IPresets1D.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IPresets1D<T> where T : IPresets1D<T>
|
||||
{
|
||||
public static abstract T One { get; }
|
||||
public static abstract T Zero { get; }
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IPresets2D.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IPresets2D.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IPresets2D<T> : IPresets1D<T> where T : IPresets2D<T>
|
||||
{
|
||||
public static abstract T Down { get; }
|
||||
public static abstract T Left { get; }
|
||||
public static abstract T Right { get; }
|
||||
public static abstract T Up { get; }
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/IPresets3D.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IPresets3D.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IPresets3D<T> : IPresets2D<T> where T : IPresets3D<T>
|
||||
{
|
||||
public static abstract T Back { get; }
|
||||
public static abstract T Forward { get; }
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/IPresets4D.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IPresets4D.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IPresets4D<T> : IPresets2D<T>, IPresets3D<T> where T : IPresets4D<T>
|
||||
{
|
||||
public static abstract T HighW { get; }
|
||||
public static abstract T LowW { get; }
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IProduct.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IProduct.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IProduct<T> : IMultiplyOperators<T, T, T>
|
||||
where T : IProduct<T>
|
||||
{
|
||||
public static abstract T Product(params T[] vals);
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IRound.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IRound.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IRound<TSelf> : IRound<TSelf, TSelf>
|
||||
where TSelf : IRound<TSelf> { }
|
||||
public interface IRound<TSelf, TRound>
|
||||
where TSelf : IRound<TSelf, TRound>
|
||||
{
|
||||
public static abstract TRound Round(TSelf val);
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IShape2D.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IShape2D.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IShape2D<TNumber> where TNumber : INumber<TNumber>
|
||||
{
|
||||
public TNumber Area { get; }
|
||||
public TNumber Perimeter { get; }
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/IShape3D.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/IShape3D.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IShape3D<TNumber> where TNumber : INumber<TNumber>
|
||||
{
|
||||
public TNumber SurfaceArea { get; }
|
||||
public TNumber Volume { get; }
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/ISplittable.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/ISplittable.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ISplittable<TSelf, TTuple> where TTuple : ITuple
|
||||
{
|
||||
public static abstract TTuple SplitArray(params TSelf[] vals);
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/IStaticMatrix.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/IStaticMatrix.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface IStaticMatrix<T> : IAverage<T>, IMatrix<T>, IMedian<T>,
|
||||
IMatrixPresets<T> where T : IStaticMatrix<T>
|
||||
{
|
||||
|
||||
}
|
||||
7
Nerd_STF/Mathematics/Abstract/ISubdivide.cs
Normal file
7
Nerd_STF/Mathematics/Abstract/ISubdivide.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ISubdivide<T>
|
||||
{
|
||||
public T Subdivide();
|
||||
public T Subdivide(int iterations);
|
||||
}
|
||||
8
Nerd_STF/Mathematics/Abstract/ISubtract.cs
Normal file
8
Nerd_STF/Mathematics/Abstract/ISubtract.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ISubtract<T> : ISubtractionOperators<T, T, T> where T : ISubtract<T>
|
||||
{
|
||||
public static abstract T Subtract(T num, params T[] vals);
|
||||
}
|
||||
9
Nerd_STF/Mathematics/Abstract/ISum.cs
Normal file
9
Nerd_STF/Mathematics/Abstract/ISum.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using System.Numerics;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ISum<T> : IAdditionOperators<T, T, T>
|
||||
where T : ISum<T>
|
||||
{
|
||||
public static abstract T Sum(params T[] vals);
|
||||
}
|
||||
19
Nerd_STF/Mathematics/Abstract/ITriangulate.cs
Normal file
19
Nerd_STF/Mathematics/Abstract/ITriangulate.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public interface ITriangulate
|
||||
{
|
||||
public static Triangle[] TriangulateAll(params ITriangulate[] triangulatables)
|
||||
{
|
||||
List<Triangle> res = new();
|
||||
foreach (ITriangulate triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
|
||||
return res.ToArray();
|
||||
}
|
||||
public static Triangle[] TriangulateAll<T>(params T[] triangulatables) where T : ITriangulate
|
||||
{
|
||||
List<Triangle> res = new();
|
||||
foreach (ITriangulate triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
public Triangle[] Triangulate();
|
||||
}
|
||||
@ -1,8 +1,18 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
using System.Buffers;
|
||||
|
||||
public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public class Matrix : IMatrix<Matrix, Matrix>
|
||||
{
|
||||
public static Matrix Identity(Int2 size)
|
||||
{
|
||||
if (size.x != size.y) throw new InvalidSizeException("Can only create an identity matrix of a square matrix." +
|
||||
" You may want to use " + nameof(IdentityIsh) + " instead.");
|
||||
Matrix m = Zero(size);
|
||||
for (int i = 0; i < size.x; i++) m[i, i] = 1;
|
||||
return m;
|
||||
}
|
||||
public static Matrix IdentityIsh(Int2 size)
|
||||
{
|
||||
Matrix m = Zero(size);
|
||||
int max = Mathf.Min(size.x, size.y);
|
||||
@ -27,7 +37,7 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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;
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = all;
|
||||
}
|
||||
public Matrix(Int2 size, float[] vals)
|
||||
{
|
||||
@ -37,7 +47,7 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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];
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals[c + r * size.y];
|
||||
}
|
||||
public Matrix(Int2 size, int[] vals)
|
||||
{
|
||||
@ -47,45 +57,45 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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];
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = 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);
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = 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);
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = 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];
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals[r, c];
|
||||
}
|
||||
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];
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals[r, c];
|
||||
}
|
||||
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);
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals(r, c);
|
||||
}
|
||||
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);
|
||||
for (int r = 0; r < size.x; r++) for (int c = 0; c < size.y; c++) array[r, c] = vals(r, c);
|
||||
}
|
||||
|
||||
public float this[int r, int c]
|
||||
@ -98,6 +108,51 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
public float this[Index r, Index c]
|
||||
{
|
||||
get
|
||||
{
|
||||
int row = r.IsFromEnd ? Size.x - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? Size.y - c.Value : c.Value;
|
||||
return array[row, col];
|
||||
}
|
||||
set
|
||||
{
|
||||
int row = r.IsFromEnd ? Size.x - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? Size.y - c.Value : c.Value;
|
||||
array[row, col] = value;
|
||||
}
|
||||
}
|
||||
public Matrix this[Range rs, Range cs]
|
||||
{
|
||||
get
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? Size.x - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? Size.x - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? Size.y - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? Size.y - cs.End.Value : cs.End.Value;
|
||||
|
||||
Matrix newMatrix = new((rowEnd - rowStart - 1, colEnd - colStart - 1));
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
newMatrix[r, c] = array[r, c];
|
||||
return newMatrix;
|
||||
}
|
||||
set
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? Size.x - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? Size.x - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? Size.y - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? Size.y - cs.End.Value : cs.End.Value;
|
||||
|
||||
if (value.Size != (rowEnd - rowStart - 1, colEnd - colStart - 1))
|
||||
throw new InvalidSizeException("Matrix has invalid size.");
|
||||
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
array[r, c] = value[r, c];
|
||||
}
|
||||
}
|
||||
|
||||
public static Matrix Absolute(Matrix val) => new(val.Size, (r, c) => Mathf.Absolute(val[r, c]));
|
||||
public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c]));
|
||||
@ -135,37 +190,38 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
|
||||
public void Apply(Modifier2D modifier)
|
||||
{
|
||||
for (int r = 0; r < Size.y; r++) for (int c = 0; c < Size.x; c++)
|
||||
for (int r = 0; r < Size.x; r++) for (int c = 0; c < Size.y; 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];
|
||||
float[] vals = new float[Size.x];
|
||||
for (int i = 0; i < Size.x; 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];
|
||||
float[] vals = new float[Size.y];
|
||||
for (int i = 0; i < Size.y; i++) vals[i] = array[row, i];
|
||||
return vals;
|
||||
}
|
||||
|
||||
public void SetColumn(int column, float[] vals)
|
||||
{
|
||||
if (vals.Length < Size.y)
|
||||
if (vals.Length < Size.x)
|
||||
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];
|
||||
for (int i = 0; i < Size.x; i++) array[i, column] = vals[i];
|
||||
}
|
||||
public void SetRow(int row, float[] vals)
|
||||
{
|
||||
if (vals.Length < Size.x)
|
||||
if (vals.Length < Size.y)
|
||||
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];
|
||||
for (int i = 0; i < Size.y; i++) array[row, i] = vals[i];
|
||||
}
|
||||
|
||||
public Matrix Adjugate()
|
||||
|
||||
public Matrix Adjugate() => Cofactor().Transpose();
|
||||
public Matrix Cofactor()
|
||||
{
|
||||
Matrix dets = new(Size);
|
||||
Matrix[,] minors = Minors();
|
||||
@ -175,58 +231,44 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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];
|
||||
if (Size.x <= 0) return 0;
|
||||
if (Size.x == 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);
|
||||
for (int i = 0; i < minors.Length; i++) det += array[0, i] * minors[i].Determinant() * (i % 2 == 0 ? 1 : -1);
|
||||
|
||||
return det;
|
||||
}
|
||||
public Matrix Inverse()
|
||||
public Matrix? Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
if (d == 0) return null;
|
||||
|
||||
return 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;
|
||||
Matrix[,] minors = new Matrix[Size.x, Size.y];
|
||||
for (int r = 0; r < Size.x; r++) for (int c = 0; c < Size.y; c++) minors[r, c] = MinorOf(new(r, c));
|
||||
return minors;
|
||||
}
|
||||
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;
|
||||
Matrix @this = this;
|
||||
return new(Size, (r, c) => @this[c, r]);
|
||||
}
|
||||
|
||||
public Matrix MinorOf(Int2 index)
|
||||
{
|
||||
Matrix @this = this;
|
||||
return new(@this.Size - Int2.One, delegate (int r, int c)
|
||||
{
|
||||
if (r >= index.x) r++;
|
||||
if (c >= index.y) c++;
|
||||
return @this[r, c];
|
||||
});
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
@ -240,25 +282,18 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
|
||||
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)
|
||||
public bool Equals(Matrix? other)
|
||||
{
|
||||
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;
|
||||
if (other is null) return false;
|
||||
return array.Equals(other.array);
|
||||
}
|
||||
public string ToString(IFormatProvider provider)
|
||||
public override int GetHashCode() => array.GetHashCode();
|
||||
public override string ToString()
|
||||
{
|
||||
string res = "";
|
||||
for (int r = 0; r < Size.y; r++)
|
||||
for (int r = 0; r < Size.x; r++)
|
||||
{
|
||||
for (int c = 0; c < Size.x; c++) res += array[c, r].ToString(provider) + " ";
|
||||
for (int c = 0; c < Size.y; c++) res += array[r, c] + " ";
|
||||
res += "\n";
|
||||
}
|
||||
return res;
|
||||
@ -272,14 +307,8 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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[] ToArray() => array.Flatten(new(Size.y, Size.x));
|
||||
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()
|
||||
{
|
||||
@ -289,11 +318,14 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
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 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 Matrix operator *(Matrix a, Matrix b)
|
||||
{
|
||||
if (a.Size.y != b.Size.x) throw new InvalidSizeException("Incompatible Dimensions.");
|
||||
return new(new(a.Size.x, b.Size.y), (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);
|
||||
@ -302,7 +334,12 @@ public struct Matrix : IMatrix<Matrix, Matrix>
|
||||
public static Vector2d operator *(Matrix a, Vector2d b) => (Vector2d)(a * (Matrix)b);
|
||||
public static Vector3d operator *(Matrix a, Vector3d b) => (Vector3d)(a * (Matrix)b);
|
||||
public static Matrix operator /(Matrix a, float b) => new(a.Size, (r, c) => a[r, c] / b);
|
||||
public static Matrix operator /(Matrix a, Matrix b) => a * b.Inverse();
|
||||
public static Matrix operator /(Matrix a, Matrix b)
|
||||
{
|
||||
Matrix? bInv = b.Inverse();
|
||||
if (bInv is null) throw new NoInverseException(b);
|
||||
return a * bInv;
|
||||
}
|
||||
public static Complex operator /(Matrix a, Complex b) => (Complex)(a / (Matrix)b);
|
||||
public static Quaternion operator /(Matrix a, Quaternion b) => (Quaternion)(a / (Matrix)b);
|
||||
public static Float2 operator /(Matrix a, Float2 b) => (Float2)(a / (Matrix)b);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
public record class Matrix2x2 : IStaticMatrix<Matrix2x2>
|
||||
{
|
||||
public static Matrix2x2 Identity => new(new[,]
|
||||
{
|
||||
@ -55,11 +55,11 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
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)
|
||||
public Matrix2x2(float r1c1, float r1c2, float r2c1, float r2c2)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
this.r1c2 = r1c2;
|
||||
this.r2c1 = r2c1;
|
||||
this.r2c2 = r2c2;
|
||||
}
|
||||
public Matrix2x2(float[] nums) : this(nums[0], nums[1], nums[2], nums[3]) { }
|
||||
@ -70,17 +70,17 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
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(Float2 r1, Float2 r2) : this(r1.x, r1.y, r2.x, r2.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 Matrix2x2(IEnumerable<float> r1, IEnumerable<float> r2) : this(r1.ToFill(), r2.ToFill()) { }
|
||||
public Matrix2x2(IEnumerable<int> r1, IEnumerable<int> r2) : this(r1.ToFill(), r2.ToFill()) { }
|
||||
public Matrix2x2(Fill<float> r1, Fill<float> r2) : this(r1(0), r1(1), r2(0), r2(1)) { }
|
||||
public Matrix2x2(Fill<int> r1, Fill<int> r2) : this(r1(0), r1(1), r2(0), r2(1)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
get => ToArray2D()[r, c];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
@ -116,25 +116,67 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
public float this[Index r, Index c]
|
||||
{
|
||||
get
|
||||
{
|
||||
int row = r.IsFromEnd ? 2 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 2 - c.Value : c.Value;
|
||||
return this[row, col];
|
||||
}
|
||||
set
|
||||
{
|
||||
int row = r.IsFromEnd ? 2 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 2 - c.Value : c.Value;
|
||||
this[row, col] = value;
|
||||
}
|
||||
}
|
||||
public float[,] this[Range rs, Range cs]
|
||||
{
|
||||
get
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value;
|
||||
|
||||
public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r2c1),
|
||||
Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c2));
|
||||
float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1];
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
vals[r, c] = this[r, c];
|
||||
return vals;
|
||||
}
|
||||
set
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value;
|
||||
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
this[r, c] = value[r, c];
|
||||
}
|
||||
}
|
||||
|
||||
public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2),
|
||||
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2));
|
||||
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 Ceiling(Matrix2x2 val) => new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r1c2),
|
||||
Mathf.Ceiling(val.r2c1), 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));
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2),
|
||||
Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1), 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 Floor(Matrix2x2 val) => new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r1c2),
|
||||
Mathf.Floor(val.r2c1), 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));
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r1c2, b.r1c2, t, clamp),
|
||||
Mathf.Lerp(a.r2c1, b.r2c1, 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);
|
||||
@ -148,8 +190,8 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
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 Round(Matrix2x2 val) => new(Mathf.Round(val.r1c1), Mathf.Round(val.r1c2),
|
||||
Mathf.Round(val.r2c1), Mathf.Round(val.r2c2));
|
||||
public static Matrix2x2 Subtract(Matrix2x2 num, params Matrix2x2[] vals)
|
||||
{
|
||||
foreach (Matrix2x2 m in vals) num -= m;
|
||||
@ -162,21 +204,22 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (float[] r1c1s, float[] r2c1s, float[] r1c2s, float[] r2c2s) SplitArray(params Matrix2x2[] vals)
|
||||
public static (float[] r1c1s, float[] r1c2s, float[] r2c1s, float[] r2c2s) SplitArray(params Matrix2x2[] vals)
|
||||
{
|
||||
float[] r1c1s = new float[vals.Length], r2c1s = new float[vals.Length], r1c2s = new float[vals.Length],
|
||||
float[] r1c1s = new float[vals.Length], r1c2s = new float[vals.Length], r2c1s = 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;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
}
|
||||
return (r1c1s, r2c1s, r1c2s, r2c2s);
|
||||
return (r1c1s, r1c2s, r2c1s, r2c2s);
|
||||
}
|
||||
|
||||
public Matrix2x2 Adjugate()
|
||||
public Matrix2x2 Adjugate() => Cofactor().Transpose();
|
||||
public Matrix2x2 Cofactor()
|
||||
{
|
||||
Matrix2x2 swapped = new(new[,]
|
||||
{
|
||||
@ -186,10 +229,10 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
return swapped ^ SignGrid;
|
||||
}
|
||||
public float Determinant() => r1c1 * r2c2 - r1c2 * r2c1;
|
||||
public Matrix2x2 Inverse()
|
||||
public Matrix2x2? Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
if (d == 0) return null;
|
||||
return Transpose().Adjugate() / d;
|
||||
}
|
||||
public Matrix2x2 Transpose() => new(new[,]
|
||||
@ -198,76 +241,65 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
|
||||
{ r1c2, r2c2 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Matrix2x2? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix2x2)) return base.Equals(obj);
|
||||
return Equals((Matrix2x2)obj);
|
||||
if (other is null) return false;
|
||||
return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r2c1 == other.r2c1 && r2c2 == other.r2c2;
|
||||
}
|
||||
public bool Equals(Matrix2x2 other) => r1c1 == other.r1c1 && 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());
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
public override string ToString() => r1c1 + " " + r1c2 + "\n" + r2c1 + " " + r2c2;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
{
|
||||
yield return r1c1;
|
||||
yield return r2c1;
|
||||
yield return r1c2;
|
||||
yield return r2c1;
|
||||
yield return r2c2;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { r1c1, r2c1, r1c2, r2c2 };
|
||||
public float[] ToArray() => new[] { r1c1, r1c2, r2c1, 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 List<float> ToList() => new() { r1c1, r1c2, r2c1, 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 a, Matrix2x2 b) => new(a.r1c1 + b.r1c1, a.r1c2 + b.r1c2,
|
||||
a.r2c1 + b.r2c1, 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(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2,
|
||||
a.r2c1 - b.r2c1, a.r2c2 - b.r2c2);
|
||||
public static Matrix2x2 operator *(Matrix2x2 a, float b) => new(a.r1c1 * b, a.r1c2 * b, a.r2c1 * b, a.r2c2 * b);
|
||||
public static Matrix2x2 operator *(Matrix2x2 a, Matrix2x2 b) => 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 Float2 operator *(Matrix2x2 a, Float2 b) => (Matrix)a * b;
|
||||
public static Matrix2x2 operator /(Matrix2x2 a, float b) => new(a.r1c1 / b, a.r1c2 / b, a.r2c1 / b, a.r2c2 / b);
|
||||
public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b)
|
||||
{
|
||||
Matrix2x2? bInv = b.Inverse();
|
||||
if (bInv is null) throw new NoInverseException(b);
|
||||
return a * bInv;
|
||||
}
|
||||
public static Float2 operator /(Matrix2x2 a, Float2 b) => (Matrix)a / b;
|
||||
public static Matrix2x2 operator ^(Matrix2x2 a, Matrix2x2 b) => // Single number multiplication.
|
||||
new(a.r1c1 * b.r1c1, a.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);
|
||||
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2);
|
||||
|
||||
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];
|
||||
res[c, r] = m.Size.x > r && m.Size.y > c ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static explicit operator Matrix2x2(Matrix3x3 m) => new(m.r1c1, m.r2c1, m.r1c2, m.r2c2);
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
public record class Matrix3x3 : IStaticMatrix<Matrix3x3>
|
||||
{
|
||||
public static Matrix3x3 Identity => new(new[,]
|
||||
{
|
||||
@ -81,17 +81,17 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
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)
|
||||
public Matrix3x3(float r1c1, float r1c2, float r1c3, float r2c1,
|
||||
float r2c2, float r2c3, float r3c1, float r3c2, float r3c3)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
this.r3c1 = r3c1;
|
||||
this.r1c2 = r1c2;
|
||||
this.r2c2 = r2c2;
|
||||
this.r3c2 = r3c2;
|
||||
this.r1c3 = r1c3;
|
||||
this.r2c1 = r2c1;
|
||||
this.r2c2 = r2c2;
|
||||
this.r2c3 = r2c3;
|
||||
this.r3c1 = r3c1;
|
||||
this.r3c2 = r3c2;
|
||||
this.r3c3 = r3c3;
|
||||
}
|
||||
public Matrix3x3(float[] nums) : this(nums[0], nums[1], nums[2],
|
||||
@ -110,21 +110,21 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
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(Float3 r1, Float3 r2, Float3 r3) : this(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.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 Matrix3x3(IEnumerable<float> r1, IEnumerable<float> r2, IEnumerable<float> r3)
|
||||
: this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { }
|
||||
public Matrix3x3(IEnumerable<int> r1, IEnumerable<int> r2, IEnumerable<int> r3)
|
||||
: this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { }
|
||||
public Matrix3x3(Fill<float> r1, Fill<float> r2, Fill<float> r3)
|
||||
: this(r1(0), r1(1), r1(2), r2(0), r2(1), r2(2), r3(0), r3(1), r3(2)) { }
|
||||
public Matrix3x3(Fill<int> r1, Fill<int> r2, Fill<int> r3)
|
||||
: this(r1(0), r1(1), r1(2), r2(0), r2(1), r2(2), r3(0), r3(1), r3(2)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
get => ToArray2D()[r, c];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
@ -180,21 +180,63 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
public float this[Index r, Index c]
|
||||
{
|
||||
get
|
||||
{
|
||||
int row = r.IsFromEnd ? 3 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 3 - c.Value : c.Value;
|
||||
return this[row, col];
|
||||
}
|
||||
set
|
||||
{
|
||||
int row = r.IsFromEnd ? 3 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 3 - c.Value : c.Value;
|
||||
this[row, col] = value;
|
||||
}
|
||||
}
|
||||
public float[,] this[Range rs, Range cs]
|
||||
{
|
||||
get
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 3 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 3 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 3 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 3 - cs.End.Value : cs.End.Value;
|
||||
|
||||
float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1];
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
vals[r, c] = this[r, c];
|
||||
return vals;
|
||||
}
|
||||
set
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 3 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 3 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 3 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 3 - cs.End.Value : cs.End.Value;
|
||||
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
this[r, c] = value[r, c];
|
||||
}
|
||||
}
|
||||
|
||||
public static Matrix3x3 Absolute(Matrix3x3 val) =>
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.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));
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3),
|
||||
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r2c3),
|
||||
Mathf.Absolute(val.r3c1), Mathf.Absolute(val.r3c2), 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));
|
||||
new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r1c2), Mathf.Ceiling(val.r1c3),
|
||||
Mathf.Ceiling(val.r2c1), Mathf.Ceiling(val.r2c2), Mathf.Ceiling(val.r2c3),
|
||||
Mathf.Ceiling(val.r3c1), Mathf.Ceiling(val.r3c2), 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),
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2),
|
||||
Mathf.Clamp(val.r1c3, min.r1c3, max.r1c3), Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1),
|
||||
Mathf.Clamp(val.r2c2, min.r2c2, max.r2c2), Mathf.Clamp(val.r2c3, min.r2c3, max.r2c3),
|
||||
Mathf.Clamp(val.r3c1, min.r3c1, max.r3c1), Mathf.Clamp(val.r3c2, min.r3c2, max.r3c2),
|
||||
Mathf.Clamp(val.r3c3, min.r3c3, max.r3c3));
|
||||
public static Matrix3x3 Divide(Matrix3x3 num, params Matrix3x3[] vals)
|
||||
{
|
||||
@ -202,14 +244,14 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
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));
|
||||
new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r1c2), Mathf.Floor(val.r1c3),
|
||||
Mathf.Floor(val.r2c1), Mathf.Floor(val.r2c2), Mathf.Floor(val.r2c3),
|
||||
Mathf.Floor(val.r3c1), Mathf.Floor(val.r3c2), 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),
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r1c2, b.r1c2, t, clamp),
|
||||
Mathf.Lerp(a.r1c3, b.r1c3, t, clamp), Mathf.Lerp(a.r2c1, b.r2c1, t, clamp),
|
||||
Mathf.Lerp(a.r2c2, b.r2c2, t, clamp), Mathf.Lerp(a.r2c3, b.r2c3, t, clamp),
|
||||
Mathf.Lerp(a.r3c1, b.r3c1, t, clamp), Mathf.Lerp(a.r3c2, b.r3c2, t, clamp),
|
||||
Mathf.Lerp(a.r3c3, b.r3c3, t, clamp));
|
||||
public static Matrix3x3 Median(params Matrix3x3[] vals)
|
||||
{
|
||||
@ -225,9 +267,9 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
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));
|
||||
new(Mathf.Round(val.r1c1), Mathf.Round(val.r1c2), Mathf.Round(val.r1c3),
|
||||
Mathf.Round(val.r2c1), Mathf.Round(val.r2c2), Mathf.Round(val.r2c3),
|
||||
Mathf.Round(val.r3c1), Mathf.Round(val.r3c2), Mathf.Round(val.r3c3));
|
||||
public static Matrix3x3 Subtract(Matrix3x3 num, params Matrix3x3[] vals)
|
||||
{
|
||||
foreach (Matrix3x3 m in vals) num -= m;
|
||||
@ -240,30 +282,31 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
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)
|
||||
public static (float[] r1c1s, float[] r1c2s, float[] r1c3s, float[] r2c1s, float[] r2c2s,
|
||||
float[] r2c3s, float[] r3c1s, float[] r3c2s, 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];
|
||||
float[] r1c1s = new float[vals.Length], r1c2s = new float[vals.Length], r1c3s = new float[vals.Length],
|
||||
r2c1s = new float[vals.Length], r2c2s = new float[vals.Length], r2c3s = new float[vals.Length],
|
||||
r3c1s = new float[vals.Length], r3c2s = 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;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
r2c3s[i] = vals[i].r2c3;
|
||||
r3c1s[i] = vals[i].r3c1;
|
||||
r3c2s[i] = vals[i].r3c2;
|
||||
r3c3s[i] = vals[i].r3c3;
|
||||
}
|
||||
return (r1c1s, r2c1s, r3c1s, r1c2s, r2c2s, r3c2s, r1c3s, r2c3s, r3c3s);
|
||||
return (r1c1s, r1c2s, r1c3s, r2c1s, r2c2s, r2c3s, r3c1s, r3c2s, r3c3s);
|
||||
}
|
||||
|
||||
public Matrix3x3 Adjugate()
|
||||
public Matrix3x3 Adjugate() => Cofactor().Transpose();
|
||||
public Matrix3x3 Cofactor()
|
||||
{
|
||||
Matrix3x3 dets = new();
|
||||
Matrix3x3 dets = Zero;
|
||||
Matrix2x2[,] minors = Minors();
|
||||
for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) dets[r, c] = minors[r, c].Determinant();
|
||||
return dets ^ SignGrid;
|
||||
@ -271,20 +314,20 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
public float Determinant()
|
||||
{
|
||||
Matrix2x2[,] minors = Minors();
|
||||
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[1, 0].Determinant())
|
||||
+ (r1c3 * minors[2, 0].Determinant());
|
||||
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant())
|
||||
+ (r1c3 * minors[0, 2].Determinant());
|
||||
}
|
||||
public Matrix3x3 Inverse()
|
||||
public Matrix3x3? Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
if (d == 0) return null;
|
||||
return 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) }
|
||||
{ new(r2c2, r2c3, r3c2, r3c3), new(r2c1, r2c3, r3c1, r3c3), new(r2c1, r2c2, r3c1, r3c2) },
|
||||
{ new(r1c2, r1c3, r3c2, r3c3), new(r1c1, r1c3, r3c1, r3c3), new(r1c1, r1c2, r3c1, r3c2) },
|
||||
{ new(r1c2, r1c3, r2c2, r2c3), new(r1c1, r1c3, r2c1, r2c3), new(r1c1, r1c2, r2c1, r2c2) }
|
||||
};
|
||||
public Matrix3x3 Transpose() => new(new[,]
|
||||
{
|
||||
@ -293,103 +336,89 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
|
||||
{ r1c3, r2c3, r3c3 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Matrix3x3? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix3x3)) return base.Equals(obj);
|
||||
return Equals((Matrix3x3)obj);
|
||||
if (other is null) return false;
|
||||
return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 &&
|
||||
r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 &&
|
||||
r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3;
|
||||
}
|
||||
public bool Equals(Matrix3x3 other) =>
|
||||
r1c1 == other.r1c1 && 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());
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
public override string ToString() =>
|
||||
r1c1 + " " + r1c2 + " " + r1c3 + "\n" +
|
||||
r2c1 + " " + r2c2 + " " + r2c3 + "\n" +
|
||||
r3c1 + " " + r3c2 + " " + r3c3;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<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 r2c1;
|
||||
yield return r2c2;
|
||||
yield return r2c3;
|
||||
yield return r3c1;
|
||||
yield return r3c2;
|
||||
yield return r3c3;
|
||||
}
|
||||
|
||||
public float[] ToArray() => new[] { r1c1, r2c1, r3c1, r1c2, r2c2, r3c2, r1c3, r2c3, r3c3 };
|
||||
public float[] ToArray() => new[] { r1c1, r1c2, r1c3, r2c1, r2c2, r2c3, r3c1, r3c2, 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 List<float> ToList() => new() { r1c1, r1c2, r1c3, r2c1, r2c2, r2c3, r3c1, r3c2, 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();
|
||||
new(a.r1c1 + b.r1c1, a.r1c2 + b.r1c2, a.r1c3 + b.r1c3,
|
||||
a.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3,
|
||||
a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3);
|
||||
public static Matrix3x3? operator -(Matrix3x3 m) => m.Inverse();
|
||||
public static Matrix3x3 operator -(Matrix3x3 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);
|
||||
new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3,
|
||||
a.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3,
|
||||
a.r3c1 - b.r3c1, a.r3c2 - b.r3c2, a.r3c3 - b.r3c3);
|
||||
public static Matrix3x3 operator *(Matrix3x3 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);
|
||||
new(a.r1c1 * b, a.r1c2 * b, a.r1c3 * b,
|
||||
a.r2c1 * b, a.r2c2 * b, a.r2c3 * b,
|
||||
a.r3c1 * b, a.r3c2 * b, a.r3c3 * b);
|
||||
public static Matrix3x3 operator *(Matrix3x3 a, Matrix3x3 b) => 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 Float3 operator *(Matrix3x3 a, Float3 b) => (Matrix)a * b;
|
||||
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();
|
||||
new(a.r1c1 / b, a.r1c2 / b, a.r1c3 / b,
|
||||
a.r2c1 / b, a.r2c2 / b, a.r2c3 / b,
|
||||
a.r3c1 / b, a.r3c2 / b, a.r3c3 / b);
|
||||
public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b)
|
||||
{
|
||||
Matrix3x3? bInv = b.Inverse();
|
||||
if (bInv is null) throw new NoInverseException(b);
|
||||
return a * bInv;
|
||||
}
|
||||
public static Float3 operator /(Matrix3x3 a, Float3 b) => (Matrix)a / b;
|
||||
public static Matrix3x3 operator ^(Matrix3x3 a, Matrix3x3 b) => // Single number multiplication
|
||||
new(a.r1c1 * b.r1c1, a.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);
|
||||
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3,
|
||||
a.r2c1 * b.r2c1, a.r2c2 * b.r2c2, a.r2c3 * b.r2c3,
|
||||
a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3);
|
||||
|
||||
public static 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];
|
||||
res[c, r] = m.Size.x > r && m.Size.y > c ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static implicit operator Matrix3x3(Matrix2x2 m)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
public record class Matrix4x4 : IStaticMatrix<Matrix4x4>
|
||||
{
|
||||
public static Matrix4x4 Identity => new(new[,]
|
||||
{
|
||||
@ -65,7 +65,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
}
|
||||
public Float4 Row1
|
||||
{
|
||||
get => new(r1c1, r1c2, r1c3, r1c3);
|
||||
get => new(r1c1, r1c2, r1c3, r1c4);
|
||||
set
|
||||
{
|
||||
r1c1 = value.x;
|
||||
@ -76,7 +76,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
}
|
||||
public Float4 Row2
|
||||
{
|
||||
get => new(r2c1, r2c2, r2c3, r2c3);
|
||||
get => new(r2c1, r2c2, r2c3, r2c4);
|
||||
set
|
||||
{
|
||||
r2c1 = value.x;
|
||||
@ -87,7 +87,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
}
|
||||
public Float4 Row3
|
||||
{
|
||||
get => new(r3c1, r3c2, r3c3, r3c3);
|
||||
get => new(r3c1, r3c2, r3c3, r3c4);
|
||||
set
|
||||
{
|
||||
r3c1 = value.x;
|
||||
@ -98,7 +98,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
}
|
||||
public Float4 Row4
|
||||
{
|
||||
get => new(r4c1, r4c2, r4c3, r4c3);
|
||||
get => new(r4c1, r4c2, r4c3, r4c4);
|
||||
set
|
||||
{
|
||||
r4c1 = value.x;
|
||||
@ -112,8 +112,8 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
|
||||
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)
|
||||
public Matrix4x4(float r1c1, float r1c2, float r1c3, float r1c4, float r2c1, float r2c2, float r2c3,
|
||||
float r2c4, float r3c1, float r3c2, float r3c3, float r3c4, float r4c1, float r4c2, float r4c3, float r4c4)
|
||||
{
|
||||
this.r1c1 = r1c1;
|
||||
this.r2c1 = r2c1;
|
||||
@ -152,22 +152,22 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
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(Float4 r1, Float4 r2, Float4 r3, Float4 r4) : this(r1.x, r1.y, r1.z,
|
||||
r1.w, r2.x, r2.y, r2.z, r2.w, r3.x, r3.y, r3.z, r3.w, r4.x, r4.y, r4.z, r4.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 Matrix4x4(IEnumerable<float> r1, IEnumerable<float> r2, IEnumerable<float> r3, IEnumerable<float> r4)
|
||||
: this(r1.ToFill(), r2.ToFill(), r3.ToFill(), r4.ToFill()) { }
|
||||
public Matrix4x4(IEnumerable<int> r1, IEnumerable<int> r2, IEnumerable<int> r3, IEnumerable<int> r4)
|
||||
: this(r1.ToFill(), r2.ToFill(), r3.ToFill(), r4.ToFill()) { }
|
||||
public Matrix4x4(Fill<float> r1, Fill<float> r2, Fill<float> r3, Fill<float> r4) : this(r1(0), r1(1),
|
||||
r1(2), r1(3), r2(0), r2(1), r2(2), r2(3), r3(0), r3(1), r3(2), r3(3), r4(0), r4(1), r4(2), r4(3)) { }
|
||||
public Matrix4x4(Fill<int> r1, Fill<int> r2, Fill<int> r3, Fill<int> r4) : this(r1(0), r1(1),
|
||||
r1(2), r1(3), r2(0), r2(1), r2(2), r2(3), r3(0), r3(1), r3(2), r3(3), r4(0), r4(1), r4(2), r4(3)) { }
|
||||
|
||||
public float this[int r, int c]
|
||||
{
|
||||
get => ToArray2D()[c, r];
|
||||
get => ToArray2D()[r, c];
|
||||
set
|
||||
{
|
||||
// Maybe this could be improved?
|
||||
@ -251,46 +251,88 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
get => this[index.x, index.y];
|
||||
set => this[index.x, index.y] = value;
|
||||
}
|
||||
public float this[Index r, Index c]
|
||||
{
|
||||
get
|
||||
{
|
||||
int row = r.IsFromEnd ? 4 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 4 - c.Value : c.Value;
|
||||
return this[row, col];
|
||||
}
|
||||
set
|
||||
{
|
||||
int row = r.IsFromEnd ? 4 - r.Value : r.Value,
|
||||
col = c.IsFromEnd ? 4 - c.Value : c.Value;
|
||||
this[row, col] = value;
|
||||
}
|
||||
}
|
||||
public float[,] this[Range rs, Range cs]
|
||||
{
|
||||
get
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 4 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 4 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 4 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 4 - cs.End.Value : cs.End.Value;
|
||||
|
||||
float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1];
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
vals[r, c] = this[r, c];
|
||||
return vals;
|
||||
}
|
||||
set
|
||||
{
|
||||
int rowStart = rs.Start.IsFromEnd ? 4 - rs.Start.Value : rs.Start.Value,
|
||||
rowEnd = rs.End.IsFromEnd ? 4 - rs.End.Value : rs.End.Value,
|
||||
colStart = cs.Start.IsFromEnd ? 4 - cs.Start.Value : cs.Start.Value,
|
||||
colEnd = cs.End.IsFromEnd ? 4 - cs.End.Value : cs.End.Value;
|
||||
|
||||
for (int r = rowStart; r < rowEnd; r++)
|
||||
for (int c = colStart; c < colEnd; c++)
|
||||
this[r, c] = value[r, c];
|
||||
}
|
||||
}
|
||||
|
||||
public static Matrix4x4 Absolute(Matrix4x4 val) =>
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.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));
|
||||
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r1c4),
|
||||
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r2c3), Mathf.Absolute(val.r2c4),
|
||||
Mathf.Absolute(val.r3c1), Mathf.Absolute(val.r3c2), Mathf.Absolute(val.r3c3), Mathf.Absolute(val.r3c4),
|
||||
Mathf.Absolute(val.r4c1), Mathf.Absolute(val.r4c2), Mathf.Absolute(val.r4c3), 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));
|
||||
new(Mathf.Ceiling(val.r1c1), Mathf.Ceiling(val.r1c2), Mathf.Ceiling(val.r1c3), Mathf.Ceiling(val.r1c4),
|
||||
Mathf.Ceiling(val.r2c1), Mathf.Ceiling(val.r2c2), Mathf.Ceiling(val.r2c3), Mathf.Ceiling(val.r2c4),
|
||||
Mathf.Ceiling(val.r3c1), Mathf.Ceiling(val.r3c2), Mathf.Ceiling(val.r3c3), Mathf.Ceiling(val.r3c4),
|
||||
Mathf.Ceiling(val.r4c1), Mathf.Ceiling(val.r4c2), Mathf.Ceiling(val.r4c3), 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));
|
||||
new(Mathf.Clamp(val.r1c1, min.r1c1, max.r1c1), Mathf.Clamp(val.r1c2, min.r1c2, max.r1c2),
|
||||
Mathf.Clamp(val.r1c3, min.r1c3, max.r1c3), Mathf.Clamp(val.r1c4, min.r1c4, max.r1c4),
|
||||
Mathf.Clamp(val.r2c1, min.r2c1, max.r2c1), Mathf.Clamp(val.r2c2, min.r2c2, max.r2c2),
|
||||
Mathf.Clamp(val.r2c3, min.r2c3, max.r2c3), Mathf.Clamp(val.r2c4, min.r2c4, max.r2c4),
|
||||
Mathf.Clamp(val.r3c1, min.r3c1, max.r3c1), Mathf.Clamp(val.r3c2, min.r3c2, max.r3c2),
|
||||
Mathf.Clamp(val.r3c3, min.r3c3, max.r3c3), Mathf.Clamp(val.r3c4, min.r3c4, max.r3c4),
|
||||
Mathf.Clamp(val.r4c1, min.r4c1, max.r4c1), Mathf.Clamp(val.r4c2, min.r4c2, max.r4c2),
|
||||
Mathf.Clamp(val.r4c3, min.r4c3, max.r4c3), 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));
|
||||
new(Mathf.Floor(val.r1c1), Mathf.Floor(val.r1c2), Mathf.Floor(val.r1c3), Mathf.Floor(val.r1c4),
|
||||
Mathf.Floor(val.r2c1), Mathf.Floor(val.r2c2), Mathf.Floor(val.r2c3), Mathf.Floor(val.r2c4),
|
||||
Mathf.Floor(val.r3c1), Mathf.Floor(val.r3c2), Mathf.Floor(val.r3c3), Mathf.Floor(val.r3c4),
|
||||
Mathf.Floor(val.r4c1), Mathf.Floor(val.r4c2), Mathf.Floor(val.r4c3), 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));
|
||||
new(Mathf.Lerp(a.r1c1, b.r1c1, t, clamp), Mathf.Lerp(a.r1c2, b.r1c2, t, clamp),
|
||||
Mathf.Lerp(a.r1c3, b.r1c3, t, clamp), Mathf.Lerp(a.r1c4, b.r1c4, t, clamp),
|
||||
Mathf.Lerp(a.r2c1, b.r2c1, t, clamp), Mathf.Lerp(a.r2c2, b.r2c2, t, clamp),
|
||||
Mathf.Lerp(a.r2c3, b.r2c3, t, clamp), Mathf.Lerp(a.r2c4, b.r2c4, t, clamp),
|
||||
Mathf.Lerp(a.r3c1, b.r3c1, t, clamp), Mathf.Lerp(a.r3c2, b.r3c2, t, clamp),
|
||||
Mathf.Lerp(a.r3c3, b.r3c3, t, clamp), Mathf.Lerp(a.r3c4, b.r3c4, t, clamp),
|
||||
Mathf.Lerp(a.r4c1, b.r4c1, t, clamp), Mathf.Lerp(a.r4c2, b.r4c2, t, clamp),
|
||||
Mathf.Lerp(a.r4c3, b.r4c3, 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);
|
||||
@ -305,10 +347,10 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
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));
|
||||
new(Mathf.Round(val.r1c1), Mathf.Round(val.r1c2), Mathf.Round(val.r1c3), Mathf.Round(val.r1c4),
|
||||
Mathf.Round(val.r2c1), Mathf.Round(val.r2c2), Mathf.Round(val.r2c3), Mathf.Round(val.r2c4),
|
||||
Mathf.Round(val.r3c1), Mathf.Round(val.r3c2), Mathf.Round(val.r3c3), Mathf.Round(val.r3c4),
|
||||
Mathf.Round(val.r4c1), Mathf.Round(val.r4c2), Mathf.Round(val.r4c3), Mathf.Round(val.r4c4));
|
||||
public static Matrix4x4 Subtract(Matrix4x4 num, params Matrix4x4[] vals)
|
||||
{
|
||||
foreach (Matrix4x4 m in vals) num -= m;
|
||||
@ -321,39 +363,43 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
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)
|
||||
public static (float[] r1c1s, float[] r1c2, float[] r1c3, float[] r1c4, float[] r2c1, float[] r2c2s,
|
||||
float[] r2c3, float[] r2c4, float[] r3c1, float[] r3c2, float[] r3c3s, float[] r3c4, float[] r4c1,
|
||||
float[] r4c2, float[] r4c3, 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],
|
||||
float[] r1c1s = new float[vals.Length], r1c2s = new float[vals.Length], r1c3s = new float[vals.Length],
|
||||
r1c4s = new float[vals.Length], r2c1s = new float[vals.Length], r2c2s = new float[vals.Length],
|
||||
r2c3s = new float[vals.Length], r2c4s = new float[vals.Length], r3c1s = new float[vals.Length],
|
||||
r3c2s = new float[vals.Length], r3c3s = new float[vals.Length], r3c4s = new float[vals.Length],
|
||||
r4c1s = new float[vals.Length], r4c2s = new float[vals.Length], r4c3s = 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;
|
||||
r1c4s[i] = vals[i].r1c4;
|
||||
r2c1s[i] = vals[i].r2c1;
|
||||
r2c2s[i] = vals[i].r2c2;
|
||||
r2c3s[i] = vals[i].r2c3;
|
||||
r2c4s[i] = vals[i].r2c4;
|
||||
r3c1s[i] = vals[i].r3c1;
|
||||
r3c2s[i] = vals[i].r3c2;
|
||||
r3c3s[i] = vals[i].r3c3;
|
||||
r3c4s[i] = vals[i].r3c4;
|
||||
r4c1s[i] = vals[i].r4c1;
|
||||
r4c2s[i] = vals[i].r4c2;
|
||||
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);
|
||||
return (r1c1s, r1c2s, r1c3s, r1c4s, r2c1s, r2c2s, r2c3s, r2c4s,
|
||||
r3c1s, r3c2s, r3c3s, r3c4s, r4c1s, r4c2s, r4c3s, r4c4s);
|
||||
}
|
||||
|
||||
public Matrix4x4 Adjugate()
|
||||
public Matrix4x4 Adjugate() => Cofactor().Transpose();
|
||||
public Matrix4x4 Cofactor()
|
||||
{
|
||||
Matrix4x4 dets = new();
|
||||
Matrix4x4 dets = Zero;
|
||||
Matrix3x3[,] minors = Minors();
|
||||
for (int r = 0; r < 4; r++) for (int c = 0; c < 4; c++) dets[r, c] = minors[r, c].Determinant();
|
||||
return dets ^ SignGrid;
|
||||
@ -361,40 +407,40 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
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());
|
||||
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) +
|
||||
(r1c3 * minors[0, 2].Determinant()) - (r1c4 * minors[0, 3].Determinant());
|
||||
}
|
||||
public Matrix4x4 Inverse()
|
||||
public Matrix4x4? Inverse()
|
||||
{
|
||||
float d = Determinant();
|
||||
if (d == 0) throw new NoInverseException();
|
||||
return Transpose().Adjugate() / d;
|
||||
if (d == 0) return null;
|
||||
return 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(r2c2, r2c3, r2c4, r3c2, r3c3, r3c4, r4c2, r4c3, r4c4),
|
||||
new(r2c1, r2c3, r2c4, r3c1, r3c3, r3c4, r4c1, r4c3, r4c4),
|
||||
new(r2c1, r2c2, r2c4, r3c1, r3c2, r3c4, r4c1, r4c2, r4c4),
|
||||
new(r2c1, r2c2, r2c3, r3c1, r3c2, r3c3, r4c1, r4c2, 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, r1c3, r1c4, r3c2, r3c3, r3c4, r4c2, r4c3, r4c4),
|
||||
new(r1c1, r1c3, r1c4, r3c1, r3c3, r3c4, r4c1, r4c3, r4c4),
|
||||
new(r1c1, r1c2, r1c4, r3c1, r3c2, r3c4, r4c1, r4c2, r4c4),
|
||||
new(r1c1, r1c2, r1c3, r3c1, r3c2, r3c3, r4c1, r4c2, 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, r1c3, r1c4, r2c2, r2c3, r2c4, r4c2, r4c3, r4c4),
|
||||
new(r1c1, r1c3, r1c4, r2c1, r2c3, r2c4, r4c1, r4c3, r4c4),
|
||||
new(r1c1, r1c2, r1c4, r2c1, r2c2, r2c4, r4c1, r4c2, r4c4),
|
||||
new(r1c1, r1c2, r1c3, r2c1, r2c2, r2c3, r4c1, r4c2, 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)
|
||||
new(r1c2, r1c3, r1c4, r2c2, r2c3, r2c4, r3c2, r3c3, r3c4),
|
||||
new(r1c1, r1c3, r1c4, r2c1, r2c3, r2c4, r3c1, r3c3, r3c4),
|
||||
new(r1c1, r1c2, r1c4, r2c1, r2c2, r2c4, r3c1, r3c2, r3c4),
|
||||
new(r1c1, r1c2, r1c3, r2c1, r2c2, r2c3, r3c1, r3c2, r3c3)
|
||||
}
|
||||
};
|
||||
public Matrix4x4 Transpose() => new(new[,]
|
||||
@ -405,56 +451,39 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
{ r1c4, r2c4, r3c4, r4c4 }
|
||||
});
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Matrix4x4? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Matrix4x4)) return base.Equals(obj);
|
||||
return Equals((Matrix4x4)obj);
|
||||
if (other is null) return false;
|
||||
return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && r1c4 == other.r1c4 &&
|
||||
r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && r2c4 == other.r2c4 &&
|
||||
r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3 && r3c4 == other.r3c4 &&
|
||||
r4c1 == other.r4c1 && r4c2 == other.r4c2 && r4c3 == other.r4c3 && r4c4 == other.r4c4;
|
||||
}
|
||||
public bool Equals(Matrix4x4 other) =>
|
||||
r1c1 == other.r1c1 && 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());
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
public override string ToString() =>
|
||||
r1c1 + " " + r1c2 + " " + r1c3 + " " + r1c4 + "\n" +
|
||||
r2c1 + " " + r2c2 + " " + r2c3 + " " + r2c4 + "\n" +
|
||||
r3c1 + " " + r3c2 + " " + r3c3 + " " + r3c4 + "\n" +
|
||||
r4c1 + " " + r4c2 + " " + r4c3 + " " + r4c4;
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<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 r2c1;
|
||||
yield return r2c2;
|
||||
yield return r2c3;
|
||||
yield return r2c4;
|
||||
yield return r3c1;
|
||||
yield return r3c2;
|
||||
yield return r3c3;
|
||||
yield return r3c4;
|
||||
yield return r4c1;
|
||||
yield return r4c2;
|
||||
yield return r4c3;
|
||||
yield return r4c4;
|
||||
}
|
||||
|
||||
@ -472,13 +501,6 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
{ 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()
|
||||
{
|
||||
@ -494,21 +516,21 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
};
|
||||
|
||||
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();
|
||||
new(a.r1c1 + b.r1c1, a.r1c2 + b.r1c2, a.r1c3 + b.r1c3, a.r1c4 + b.r1c4,
|
||||
a.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3, a.r2c4 + b.r2c4,
|
||||
a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3, a.r3c4 + b.r3c4,
|
||||
a.r4c1 + b.r4c1, a.r4c2 + b.r4c2, a.r4c3 + b.r4c3, a.r4c4 + b.r4c4);
|
||||
public static 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);
|
||||
new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3, a.r1c4 - b.r1c4,
|
||||
a.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3, a.r2c4 - b.r2c4,
|
||||
a.r3c1 - b.r3c1, a.r3c2 - b.r3c2, a.r3c3 - b.r3c3, a.r3c4 - b.r3c4,
|
||||
a.r4c1 - b.r4c1, a.r4c2 - b.r4c2, a.r4c3 - b.r4c3, a.r4c4 - b.r4c4);
|
||||
public static 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);
|
||||
new(a.r1c1 * b, a.r1c2 * b, a.r1c3 * b, a.r1c4 * b,
|
||||
a.r2c1 * b, a.r2c2 * b, a.r2c3 * b, a.r2c4 * b,
|
||||
a.r3c1 * b, a.r3c2 * b, a.r3c3 * b, a.r3c4 * b,
|
||||
a.r4c1 * b, a.r4c2 * b, a.r4c3 * b, a.r4c4 * b);
|
||||
public static Matrix4x4 operator *(Matrix4x4 a, Matrix4x4 b) => new(new[,]
|
||||
{
|
||||
{ Float4.Dot(a.Row1, b.Column1), Float4.Dot(a.Row1, b.Column2),
|
||||
@ -520,25 +542,30 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
|
||||
{ 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 Float4 operator *(Matrix4x4 a, Float4 b) => (Matrix)a * b;
|
||||
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();
|
||||
new(a.r1c1 / b, a.r1c2 / b, a.r1c3 / b, a.r1c4 / b,
|
||||
a.r2c1 / b, a.r2c2 / b, a.r2c3 / b, a.r2c4 / b,
|
||||
a.r3c1 / b, a.r3c2 / b, a.r3c3 / b, a.r3c4 / b,
|
||||
a.r4c1 / b, a.r4c2 / b, a.r4c3 / b, a.r4c4 / b);
|
||||
public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b)
|
||||
{
|
||||
Matrix4x4? bInv = b.Inverse();
|
||||
if (bInv is null) throw new NoInverseException(b);
|
||||
return a * bInv;
|
||||
}
|
||||
public static Float4 operator /(Matrix4x4 a, Float4 b) => (Matrix)a / b;
|
||||
public static Matrix4x4 operator ^(Matrix4x4 a, Matrix4x4 b) => // Single number multiplication
|
||||
new(a.r1c1 * b.r1c1, a.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);
|
||||
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3, a.r1c4 * b.r1c4,
|
||||
a.r2c1 * b.r2c1, a.r2c2 * b.r2c2, a.r2c3 * b.r2c3, a.r2c4 * b.r2c4,
|
||||
a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3, a.r3c4 * b.r3c4,
|
||||
a.r4c1 * b.r4c1, a.r4c2 * b.r4c2, a.r4c3 * b.r4c3, a.r4c4 * b.r4c4);
|
||||
|
||||
public static 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];
|
||||
res[c, r] = m.Size.x > r && m.Size.y > c ? m[r, c] : identity[r, c];
|
||||
return res;
|
||||
}
|
||||
public static implicit operator Matrix4x4(Matrix2x2 m)
|
||||
|
||||
@ -1,6 +1,11 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
public record struct Vector2d : IAbsolute<Vector2d>, IAverage<Vector2d>,
|
||||
IClampMagnitude<Vector2d, float>, IComparable<Vector2d>, ICross<Vector2d, Vector3d>,
|
||||
IDot<Vector2d, float>, IEquatable<Vector2d>, IFromTuple<Vector2d, (Angle angle, float mag)>,
|
||||
ILerp<Vector2d, float>, IMax<Vector2d>, IMagnitude<float>, IMedian<Vector2d>, IMin<Vector2d>,
|
||||
IPresets2D<Vector2d>, ISplittable<Vector2d, (Angle[] rots, float[] mags)>, ISubtract<Vector2d>,
|
||||
ISum<Vector2d>
|
||||
{
|
||||
public static Vector2d Down => new(Angle.Down);
|
||||
public static Vector2d Left => new(Angle.Left);
|
||||
@ -10,6 +15,12 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
public static Vector2d One => new(Angle.Zero);
|
||||
public static Vector2d Zero => new(Angle.Zero, 0);
|
||||
|
||||
public float Magnitude
|
||||
{
|
||||
get => magnitude;
|
||||
set => magnitude = value;
|
||||
}
|
||||
|
||||
public Vector2d Inverse => new(-theta, magnitude);
|
||||
public Vector2d Normalized => new(theta, 1);
|
||||
|
||||
@ -86,7 +97,7 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (Angle[] Rots, float[] Mags) SplitArray(params Vector2d[] vals)
|
||||
public static (Angle[] rots, float[] mags) SplitArray(params Vector2d[] vals)
|
||||
{
|
||||
Angle[] rots = new Angle[vals.Length];
|
||||
float[] mags = new float[vals.Length];
|
||||
@ -99,21 +110,11 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
}
|
||||
|
||||
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 override int GetHashCode() => base.GetHashCode();
|
||||
public override string ToString() => ToString(Angle.Type.Degrees);
|
||||
public string ToString(Angle.Type outputType) =>
|
||||
nameof(Vector2d) + " { Mag = " + magnitude + ", Rot = " + theta.ToString(outputType) + " }";
|
||||
|
||||
public Float2 ToXYZ() => new Float2(Mathf.Cos(theta), Mathf.Sin(theta)) * magnitude;
|
||||
|
||||
@ -124,8 +125,6 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
public static Vector2d operator *(Vector2d a, Matrix b) => (Vector2d)((Matrix)a * b);
|
||||
public static Vector2d operator /(Vector2d a, float b) => new(a.theta, a.magnitude / b);
|
||||
public static Vector2d operator /(Vector2d a, Matrix b) => (Vector2d)((Matrix)a / b);
|
||||
public static bool operator ==(Vector2d a, Vector2d b) => a.Equals(b);
|
||||
public static bool operator !=(Vector2d a, Vector2d b) => !a.Equals(b);
|
||||
public static bool operator >(Vector2d a, Vector2d b) => a.CompareTo(b) > 0;
|
||||
public static bool operator <(Vector2d a, Vector2d b) => a.CompareTo(b) < 0;
|
||||
public static bool operator >=(Vector2d a, Vector2d b) => a == b || a > b;
|
||||
@ -139,4 +138,5 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
|
||||
public static explicit operator Vector2d(Matrix m) => ((Float2)m).ToVector();
|
||||
public static explicit operator Vector2d(Vert val) => (Vector2d)val.ToVector();
|
||||
public static explicit operator Vector2d(Vector3d val) => new(val.yaw, val.magnitude);
|
||||
public static implicit operator Vector2d((Angle angle, float mag) val) => new(val.angle, val.mag);
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
namespace Nerd_STF.Mathematics.Algebra;
|
||||
|
||||
public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
public record struct Vector3d : IAbsolute<Vector3d>, IAverage<Vector3d>, IClampMagnitude<Vector3d, float>,
|
||||
IComparable<Vector3d>, ICross<Vector3d>, IDot<Vector3d, float>, IEquatable<Vector3d>,
|
||||
IFromTuple<Vector3d, (Angle yaw, Angle pitch, float mag)>, IIndexAll<Angle>, IIndexRangeAll<Angle>,
|
||||
ILerp<Vector3d, float>, IMagnitude<float>, IMax<Vector3d>, IMedian<Vector3d>, IMin<Vector3d>,
|
||||
IPresets3D<Vector3d>, ISubtract<Vector3d>, ISum<Vector3d>
|
||||
{
|
||||
public static Vector3d Back => new(Angle.Zero, Angle.Up);
|
||||
public static Vector3d Down => new(Angle.Down, Angle.Zero);
|
||||
@ -12,6 +16,12 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
public static Vector3d One => new(Angle.Zero);
|
||||
public static Vector3d Zero => new(Angle.Zero, 0);
|
||||
|
||||
public float Magnitude
|
||||
{
|
||||
get => magnitude;
|
||||
set => magnitude = value;
|
||||
}
|
||||
|
||||
public Vector3d Inverse => new(-yaw, -pitch, magnitude);
|
||||
public Vector3d Normalized => new(yaw, pitch, 1);
|
||||
|
||||
@ -56,6 +66,28 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
}
|
||||
}
|
||||
}
|
||||
public Angle this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value;
|
||||
}
|
||||
public Angle[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
List<Angle> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3d Absolute(Vector3d val) => new(Angle.Absolute(val.yaw), Angle.Absolute(val.pitch),
|
||||
Mathf.Absolute(val.magnitude));
|
||||
@ -123,37 +155,31 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
return val;
|
||||
}
|
||||
|
||||
public static (Angle[] Thetas, Angle[] Phis, float[] Mags) SplitArray(params Vector3d[] vals)
|
||||
public static (Angle[] yaws, Angle[] pitches, float[] mags) SplitArray(params Vector3d[] vals)
|
||||
{
|
||||
Angle[] yaws = new Angle[vals.Length], pitchs = new Angle[vals.Length];
|
||||
Angle[] yaws = new Angle[vals.Length], pitches = new Angle[vals.Length];
|
||||
float[] mags = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
yaws[i] = vals[i].yaw;
|
||||
pitchs[i] = vals[i].pitch;
|
||||
pitches[i] = vals[i].pitch;
|
||||
mags[i] = vals[i].magnitude;
|
||||
}
|
||||
return (yaws, pitchs, mags);
|
||||
return (yaws, pitches, mags);
|
||||
}
|
||||
|
||||
public int CompareTo(Vector3d other) => magnitude.CompareTo(other.magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Vector3d)) return base.Equals(obj);
|
||||
return Equals((Vector3d)obj);
|
||||
}
|
||||
public bool Equals(Vector3d other) => yaw == other.yaw && pitch == other.pitch
|
||||
&& magnitude == other.magnitude;
|
||||
public override int GetHashCode() => yaw.GetHashCode() ^ pitch.GetHashCode() ^ magnitude.GetHashCode();
|
||||
public 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 override int GetHashCode() => base.GetHashCode();
|
||||
public override string ToString() => ToString(Angle.Type.Degrees);
|
||||
public string ToString(Angle.Type outputType) =>
|
||||
nameof(Vector3d) + " { Mag = " + magnitude + ", Yaw = " + yaw.ToString(outputType) +
|
||||
", Pitch = " + pitch.ToString(outputType) + " }";
|
||||
|
||||
public object Clone() => new Vector3d(yaw, pitch, magnitude);
|
||||
|
||||
public Float3 ToXYZ() => new(Mathf.Sin(pitch) * Mathf.Cos(yaw) * magnitude,
|
||||
Mathf.Sin(pitch) * Mathf.Sin(yaw) * magnitude,
|
||||
Mathf.Cos(pitch) * magnitude);
|
||||
public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw),
|
||||
Mathf.Cos(yaw),
|
||||
Mathf.Cos(pitch) * Mathf.Sin(yaw)) * magnitude;
|
||||
|
||||
public static Vector3d operator +(Vector3d a, Vector3d b) => new(a.yaw + b.yaw, a.pitch + b.pitch,
|
||||
a.magnitude + b.magnitude);
|
||||
@ -164,8 +190,6 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
public static Vector3d operator *(Vector3d a, Matrix b) => (Vector3d)((Matrix)a * b);
|
||||
public static Vector3d operator /(Vector3d a, float b) => new(a.yaw, a.pitch, a.magnitude / b);
|
||||
public static Vector3d operator /(Vector3d a, Matrix b) => (Vector3d)((Matrix)a / b);
|
||||
public static bool operator ==(Vector3d a, Vector3d b) => a.Equals(b);
|
||||
public static bool operator !=(Vector3d a, Vector3d b) => !a.Equals(b);
|
||||
public static bool operator >(Vector3d a, Vector3d b) => a.CompareTo(b) > 0;
|
||||
public static bool operator <(Vector3d a, Vector3d b) => a.CompareTo(b) < 0;
|
||||
public static bool operator >=(Vector3d a, Vector3d b) => a == b || a > b;
|
||||
@ -179,4 +203,6 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
|
||||
public static explicit operator Vector3d(Matrix m) => ((Float3)m).ToVector();
|
||||
public static explicit operator Vector3d(Vert val) => val.ToVector();
|
||||
public static implicit operator Vector3d(Vector2d v) => new(v.theta, Angle.Zero, v.magnitude);
|
||||
public static implicit operator Vector3d((Angle yaw, Angle pitch, float mag) val) =>
|
||||
new(val.yaw, val.pitch, val.mag);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
public struct Angle : IAbsolute<Angle>, IAverage<Angle>, IClamp<Angle>, ICloneable,
|
||||
IComparable<Angle>, IEquatable<Angle>, ILerp<Angle, float>, IMax<Angle>, IMedian<Angle>,
|
||||
IMin<Angle>, IPresets2D<Angle>
|
||||
{
|
||||
public static Angle Down => new(270);
|
||||
public static Angle Left => new(180);
|
||||
@ -35,6 +37,8 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
}
|
||||
|
||||
public Angle Bounded => new(Mathf.AbsoluteMod(p_deg, 360));
|
||||
public Angle Complimentary => Quarter - this;
|
||||
public Angle Supplementary => Half - this;
|
||||
public Angle Reflected => new Angle(-p_deg).Bounded;
|
||||
|
||||
private float p_deg;
|
||||
@ -82,17 +86,7 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
public static float[] SplitArray(Type outputType, params Angle[] vals)
|
||||
{
|
||||
float[] res = new float[vals.Length];
|
||||
for (int i = 0; i < vals.Length; i++)
|
||||
{
|
||||
res[i] = outputType switch
|
||||
{
|
||||
Type.Degrees => vals[i].Degrees,
|
||||
Type.Gradians => vals[i].Gradians,
|
||||
Type.Normalized => vals[i].Normalized,
|
||||
Type.Radians => vals[i].Radians,
|
||||
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
||||
};
|
||||
}
|
||||
for (int i = 0; i < vals.Length; i++) res[i] = vals[i].ValueFromType(outputType);
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -104,22 +98,13 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
}
|
||||
public bool Equals(Angle other) => p_deg == other.p_deg;
|
||||
public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(Type outputType) => ToString((string?)null, outputType);
|
||||
public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch
|
||||
public override string ToString() => ToString(Type.Degrees);
|
||||
public string ToString(Type outputType) => outputType switch
|
||||
{
|
||||
Type.Degrees => p_deg.ToString(provider) + "°",
|
||||
Type.Gradians => Gradians.ToString(provider) + "grad",
|
||||
Type.Normalized => Normalized.ToString(provider) + "%",
|
||||
Type.Radians => Radians.ToString(provider) + "rad",
|
||||
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
||||
};
|
||||
public string ToString(IFormatProvider provider, Type outputType = Type.Degrees) => outputType switch
|
||||
{
|
||||
Type.Degrees => p_deg.ToString(provider) + "°",
|
||||
Type.Gradians => Gradians.ToString(provider) + "grad",
|
||||
Type.Normalized => Normalized.ToString(provider) + "%",
|
||||
Type.Radians => Radians.ToString(provider) + "rad",
|
||||
Type.Degrees => p_deg + "°",
|
||||
Type.Gradians => Gradians + "grad",
|
||||
Type.Normalized => Normalized + "%",
|
||||
Type.Radians => Radians + "rad",
|
||||
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
||||
};
|
||||
|
||||
@ -131,7 +116,7 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
Type.Gradians => Gradians,
|
||||
Type.Normalized => Normalized,
|
||||
Type.Radians => Radians,
|
||||
_ => throw new ArgumentException("Unknown type.", nameof(type)),
|
||||
_ => throw new ArgumentException("Unknown type.", nameof(type))
|
||||
};
|
||||
|
||||
public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg);
|
||||
@ -146,6 +131,8 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||
public static bool operator >=(Angle a, Angle b) => a == b || a > b;
|
||||
public static bool operator <=(Angle a, Angle b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Angle((float val, Type type) obj) => new(obj.val, obj.type);
|
||||
|
||||
public enum Type
|
||||
{
|
||||
Degrees,
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGroup<float>
|
||||
public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Float2, Int2>,
|
||||
IClamp<Float2>, IClampMagnitude<Float2, float>, IComparable<Float2>,
|
||||
ICross<Float2, Float3>, IDivide<Float2>, IDot<Float2, float>, IEquatable<Float2>,
|
||||
IFloor<Float2, Int2>, IFromTuple<Float2, (float x, float y)>, IGroup<float>,
|
||||
ILerp<Float2, float>, IMathOperators<Float2>, IMax<Float2>, IMedian<Float2>, IMin<Float2>,
|
||||
IIndexAll<float>, IIndexRangeAll<float>, IPresets2D<Float2>, IProduct<Float2>, IRound<Float2, Int2>,
|
||||
ISplittable<Float2, (float[] Xs, float[] Ys)>, ISubtract<Float2>, ISum<Float2>
|
||||
{
|
||||
public static Float2 Down => new(0, -1);
|
||||
public static Float2 Left => new(-1, 0);
|
||||
@ -16,14 +22,13 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
public float x, y;
|
||||
|
||||
public Float2(float all) : this(all, all) { }
|
||||
public Float2(Fill<float> fill) : this(fill(0), fill(1)) { }
|
||||
public Float2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||
public Float2(float x, float y)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
public Float2(Fill<float> fill) : this(fill(0), fill(1)) { }
|
||||
public Float2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||
|
||||
public float this[int index]
|
||||
{
|
||||
get => index switch
|
||||
@ -48,11 +53,33 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Float2 Absolute(Float2 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
||||
public static Float2 Average(params Float2[] vals) => Sum(vals) / vals.Length;
|
||||
public static Float2 Ceiling(Float2 val) =>
|
||||
public static Int2 Ceiling(Float2 val) =>
|
||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y));
|
||||
public static Float2 Clamp(Float2 val, Float2 min, Float2 max) =>
|
||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||
@ -83,7 +110,7 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
}
|
||||
return x + y;
|
||||
}
|
||||
public static Float2 Floor(Float2 val) =>
|
||||
public static Int2 Floor(Float2 val) =>
|
||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y));
|
||||
public static Float2 Lerp(Float2 a, Float2 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp));
|
||||
@ -97,14 +124,14 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float2 val = vals[0];
|
||||
foreach (Float2 f in vals) val = f > val ? f : val;
|
||||
foreach (Float2 f in vals) val = f.Magnitude > val.Magnitude ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Float2 Min(params Float2[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float2 val = vals[0];
|
||||
foreach (Float2 f in vals) val = f < val ? f : val;
|
||||
foreach (Float2 f in vals) val = f.Magnitude < val.Magnitude ? f : val;
|
||||
return val;
|
||||
}
|
||||
public static Float2 Product(params Float2[] vals)
|
||||
@ -114,8 +141,8 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
foreach (Float2 f in vals) val *= f;
|
||||
return val;
|
||||
}
|
||||
public static Float2 Round(Float2 val) =>
|
||||
new(Mathf.Round(val.x), Mathf.Round(val.y));
|
||||
public static Int2 Round(Float2 val) =>
|
||||
new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y));
|
||||
public static Float2 Subtract(Float2 num, params Float2[] vals) => num - Sum(vals);
|
||||
public static Float2 Sum(params Float2[] vals)
|
||||
{
|
||||
@ -135,21 +162,11 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
return (Xs, Ys);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public int CompareTo(Float2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float2)) return base.Equals(obj);
|
||||
return Equals((Float2)obj);
|
||||
}
|
||||
public bool Equals(Float2 other) => x == other.x && y == other.y;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||
|
||||
public object Clone() => new Float2(x, y);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
@ -168,20 +185,36 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
|
||||
public Vector2d ToVector() => new(Mathf.ArcTan(y / x), Magnitude);
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Float2 operator +(Float2 a, Float2 b) => new(a.x + b.x, a.y + b.y);
|
||||
public static Float2 operator -(Float2 d) => new(-d.x, -d.y);
|
||||
public static Float2 operator -(Float2 a, Float2 b) => new(a.x - b.x, a.y - b.y);
|
||||
public static Float2 operator *(Float2 a, Float2 b) => new(a.x * b.x, a.y * b.y);
|
||||
public static Float2 operator *(Float2 a, float b) => new(a.x * b, a.y * b);
|
||||
public static Float2 operator *(Float2 a, Matrix b) => (Float2)((Matrix)a * b);
|
||||
public static Quaternion operator *(Float2 a, Quaternion b) => (Quaternion)a * b;
|
||||
public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y);
|
||||
public static Float2 operator /(Float2 a, float b) => new(a.x / b, a.y / b);
|
||||
public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b);
|
||||
public static bool operator ==(Float2 a, Float2 b) => a.Equals(b);
|
||||
public static bool operator !=(Float2 a, Float2 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Float2 a, Float2 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Float2 a, Float2 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Float2 a, Float2 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float2(Complex val) => new(val.u, val.i);
|
||||
@ -196,4 +229,5 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
|
||||
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);
|
||||
public static implicit operator Float2((float x, float y) val) => new(val.x, val.y);
|
||||
}
|
||||
|
||||
@ -1,6 +1,14 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
using System;
|
||||
|
||||
public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGroup<float>
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public record struct Float3 : IAbsolute<Float3>, IAverage<Float3>,
|
||||
ICeiling<Float3, Int3>, IClamp<Float3>, IClampMagnitude<Float3, float>, IComparable<Float3>,
|
||||
ICross<Float3>, IDivide<Float3>, IDot<Float3, float>, IEquatable<Float3>,
|
||||
IFloor<Float3, Int3>, IFromTuple<Float3, (float x, float y, float z)>, IGroup<float>,
|
||||
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float3, float>, IMathOperators<Float3>, IMax<Float3>,
|
||||
IMedian<Float3>, IMin<Float3>, IPresets3D<Float3>, IProduct<Float3>, IRound<Float3, Int3>,
|
||||
ISplittable<Float3, (float[] Xs, float[] Ys, float[] Zs)>, ISubtract<Float3>, ISum<Float3>
|
||||
{
|
||||
public static Float3 Back => new(0, 0, -1);
|
||||
public static Float3 Down => new(0, -1, 0);
|
||||
@ -61,11 +69,33 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 3 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Float3 Absolute(Float3 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
||||
public static Float3 Average(params Float3[] vals) => Sum(vals) / vals.Length;
|
||||
public static Float3 Ceiling(Float3 val) =>
|
||||
public static Int3 Ceiling(Float3 val) =>
|
||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z));
|
||||
public static Float3 Clamp(Float3 val, Float3 min, Float3 max) =>
|
||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||
@ -103,7 +133,7 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
}
|
||||
return x + y + z;
|
||||
}
|
||||
public static Float3 Floor(Float3 val) =>
|
||||
public static Int3 Floor(Float3 val) =>
|
||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z));
|
||||
public static Float3 Lerp(Float3 a, Float3 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp));
|
||||
@ -117,14 +147,14 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float3 val = vals[0];
|
||||
foreach (Float3 d in vals) val = d > val ? d : val;
|
||||
foreach (Float3 d in vals) val = d.Magnitude > val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Float3 Min(params Float3[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float3 val = vals[0];
|
||||
foreach (Float3 d in vals) val = d < val ? d : val;
|
||||
foreach (Float3 d in vals) val = d.Magnitude < val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Float3 Product(params Float3[] vals)
|
||||
@ -134,8 +164,8 @@ public struct Float3 : ICloneable, IComparable<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 Int3 Round(Float3 val) =>
|
||||
new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y), Mathf.RoundInt(val.z));
|
||||
public static Float3 Subtract(Float3 num, params Float3[] vals) => num - Sum(vals);
|
||||
public static Float3 Sum(params Float3[] vals)
|
||||
{
|
||||
@ -156,21 +186,11 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
return (Xs, Ys, Zs);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public int CompareTo(Float3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float3)) return base.Equals(obj);
|
||||
return Equals((Float3)obj);
|
||||
}
|
||||
public bool Equals(Float3 other) => x == other.x && y == other.y && z == other.z;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||
|
||||
public object Clone() => new Float3(x, y, z);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
@ -191,7 +211,21 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public Vector3d ToVector()
|
||||
{
|
||||
float mag = Magnitude;
|
||||
return new(Mathf.ArcTan(y / x), Mathf.ArcCos(z / mag), mag);
|
||||
Float3 normalized = Normalized;
|
||||
Angle yaw = Mathf.ArcCos(normalized.y);
|
||||
Angle pitch = Mathf.ArcSin(normalized.x / Mathf.Sin(yaw));
|
||||
return new(yaw, pitch, mag);
|
||||
}
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
builder.Append(", z = ");
|
||||
builder.Append(z);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
@ -200,14 +234,21 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public static Float3 operator *(Float3 a, Float3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
public static Float3 operator *(Float3 a, float b) => new(a.x * b, a.y * b, a.z * b);
|
||||
public static Float3 operator *(Float3 a, Matrix b) => (Float3)((Matrix)a * b);
|
||||
public static Quaternion operator *(Float3 a, Quaternion b) => (Quaternion)a * b;
|
||||
public static Float3 operator /(Float3 a, Float3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||
public static Float3 operator /(Float3 a, float b) => new(a.x / b, a.y / b, a.z / b);
|
||||
public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b);
|
||||
public static bool operator ==(Float3 a, Float3 b) => a.Equals(b);
|
||||
public static bool operator !=(Float3 a, Float3 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Float3 a, Float3 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Float3 a, Float3 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Float3 a, Float3 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float3(Complex val) => new(val.u, val.i, 0);
|
||||
@ -226,4 +267,6 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
|
||||
public static explicit operator Float3(HSVAByte val) => (Float3)val.ToHSVA();
|
||||
public static implicit operator Float3(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Float3(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Float3((float x, float y, float z) val) =>
|
||||
new(val.x, val.y, val.z);
|
||||
}
|
||||
|
||||
@ -1,18 +1,25 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGroup<float>
|
||||
public record struct Float4 : IAbsolute<Float4>,
|
||||
IAverage<Float4>, ICeiling<Float4, Int4>, IClamp<Float4>, IClampMagnitude<Float4, float>,
|
||||
IComparable<Float4>, IDivide<Float4>, IDot<Float4, float>, IEquatable<Float4>,
|
||||
IFloor<Float4, Int4>, IFromTuple<Float4, (float x, float y, float z, float w)>,
|
||||
IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>, ILerp<Float4, float>, IMathOperators<Float4>,
|
||||
IMax<Float4>, IMedian<Float4>, IMin<Float4>, IPresets4D<Float4>, IProduct<Float4>, IRound<Float4, Int4>,
|
||||
ISplittable<Float4, (float[] Xs, float[] Ys, float[] Zs, float[] Ws)>, ISubtract<Float4>,
|
||||
ISum<Float4>
|
||||
{
|
||||
public static Float4 Back => new(0, 0, -1, 0);
|
||||
public static Float4 Down => new(0, -1, 0, 0);
|
||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
public static Float4 Far => new(0, 0, 0, 1);
|
||||
public static Float4 Forward => new(0, 0, 1, 0);
|
||||
public static Float4 HighW => new(0, 0, 0, 1);
|
||||
public static Float4 Left => new(-1, 0, 0, 0);
|
||||
public static Float4 LowW => new(0, 0, 0, -1);
|
||||
[Obsolete("Field has been replaced by " + nameof(LowW) + ", because it has a better name. " +
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
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);
|
||||
@ -84,11 +91,33 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Float4 Absolute(Float4 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
||||
public static Float4 Average(params Float4[] vals) => Sum(vals) / vals.Length;
|
||||
public static Float4 Ceiling(Float4 val) =>
|
||||
public static Int4 Ceiling(Float4 val) =>
|
||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w));
|
||||
public static Float4 Clamp(Float4 val, Float4 min, Float4 max) =>
|
||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||
@ -121,7 +150,7 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
}
|
||||
return x + y + z;
|
||||
}
|
||||
public static Float4 Floor(Float4 val) =>
|
||||
public static Int4 Floor(Float4 val) =>
|
||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w));
|
||||
public static Float4 Lerp(Float4 a, Float4 b, float t, bool clamp = true) =>
|
||||
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp), Mathf.Lerp(a.z, b.z, t, clamp),
|
||||
@ -136,18 +165,19 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float4 val = vals[0];
|
||||
foreach (Float4 d in vals) val = d > val ? d : val;
|
||||
foreach (Float4 d in vals) val = d.Magnitude > val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Float4 Min(params Float4[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Float4 val = vals[0];
|
||||
foreach (Float4 d in vals) val = d < val ? d : val;
|
||||
foreach (Float4 d in vals) val = d.Magnitude < val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Float4 Round(Float4 val) =>
|
||||
new(Mathf.Round(val.x), Mathf.Round(val.y), Mathf.Round(val.z), Mathf.Round(val.w));
|
||||
public static Int4 Round(Float4 val) =>
|
||||
new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y), Mathf.RoundInt(val.z),
|
||||
Mathf.RoundInt(val.w));
|
||||
public static Float4 Product(params Float4[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
@ -177,23 +207,11 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
return (Xs, Ys, Zs, Ws);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public int CompareTo(Float4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Float4)) return base.Equals(obj);
|
||||
return Equals((Float4)obj);
|
||||
}
|
||||
public bool Equals(Float4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||
+ " W: " + w.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||
+ " W: " + w.ToString(provider);
|
||||
|
||||
public object Clone() => new Float4(x, y, z, w);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
@ -212,6 +230,19 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
}
|
||||
public List<float> ToList() => new() { x, y, z, w };
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
builder.Append(", z = ");
|
||||
builder.Append(z);
|
||||
builder.Append(", w = ");
|
||||
builder.Append(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Float4 operator +(Float4 a, Float4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||
public static Float4 operator -(Float4 d) => new(-d.x, -d.y, -d.z, -d.w);
|
||||
public static Float4 operator -(Float4 a, Float4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
||||
@ -221,11 +252,17 @@ public struct Float4 : ICloneable, IComparable<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, float b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
||||
public static Float4 operator /(Float4 a, Matrix b) => (Float4)((Matrix)a / b);
|
||||
public static bool operator ==(Float4 a, Float4 b) => a.Equals(b);
|
||||
public static bool operator !=(Float4 a, Float4 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Float4 a, Float4 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Float4 a, Float4 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Float4 a, Float4 b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0);
|
||||
@ -246,4 +283,6 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
|
||||
public static implicit operator Float4(HSVAByte val) => (Float4)val.ToHSVA();
|
||||
public static implicit operator Float4(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Float4(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Float4((float x, float y, float z, float w) vals) =>
|
||||
new(vals.x, vals.y, vals.z, vals.w);
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
public record class Box2D : IAbsolute<Box2D>, IAverage<Box2D>, ICeiling<Box2D>, IClamp<Box2D>, IContains<Vert>,
|
||||
IEquatable<Box2D>, IFloor<Box2D>, ILerp<Box2D, float>, IMedian<Box2D>, IRound<Box2D>, IShape2D<float>,
|
||||
ISplittable<Box2D, (Vert[] centers, Float2[] sizes)>
|
||||
{
|
||||
public static Box2D Unit => new(Vert.Zero, Float2.One);
|
||||
|
||||
@ -10,7 +12,7 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
set
|
||||
{
|
||||
Vert diff = center - value;
|
||||
size = (Float2)diff.position * 2;
|
||||
size = (Float2)diff.position * 2f;
|
||||
}
|
||||
}
|
||||
public Vert MinVert
|
||||
@ -19,12 +21,12 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
set
|
||||
{
|
||||
Vert diff = center + value;
|
||||
size = (Float2)diff.position * 2;
|
||||
size = (Float2)diff.position * 2f;
|
||||
}
|
||||
}
|
||||
|
||||
public float Area => size.x * size.y;
|
||||
public float Perimeter => size.x * 2 + size.y * 2;
|
||||
public float Perimeter => 2 * (size.x + size.y);
|
||||
|
||||
public Vert center;
|
||||
public Float2 size;
|
||||
@ -60,16 +62,8 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
(Vert[] verts, Float2[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Median(verts), Float2.Median(sizes));
|
||||
}
|
||||
public static Box2D Max(params Box2D[] vals)
|
||||
{
|
||||
(Vert[] verts, Float2[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Max(verts), Float2.Max(sizes));
|
||||
}
|
||||
public static Box2D Min(params Box2D[] vals)
|
||||
{
|
||||
(Vert[] verts, Float2[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Min(verts), Float2.Min(sizes));
|
||||
}
|
||||
public static Box2D Round(Box2D val) => new(Vert.Round(val.center), Float2.Round(val.size));
|
||||
|
||||
public static (Vert[] centers, Float2[] sizes) SplitArray(params Box2D[] vals)
|
||||
{
|
||||
Vert[] centers = new Vert[vals.Length];
|
||||
@ -84,18 +78,12 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
return (centers, sizes);
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Box2D? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Box2D)) return base.Equals(obj);
|
||||
return Equals((Box2D)obj);
|
||||
if (other is null) return false;
|
||||
return center == other.center && size == other.size;
|
||||
}
|
||||
public bool Equals(Box2D other) => center == other.center && size == other.size;
|
||||
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public bool Contains(Vert vert)
|
||||
{
|
||||
@ -103,7 +91,14 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
return diff.x <= size.x && diff.y <= size.y;
|
||||
}
|
||||
|
||||
public object Clone() => new Box2D(center, size);
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("Min = ");
|
||||
builder.Append(MinVert);
|
||||
builder.Append(", Max = ");
|
||||
builder.Append(MaxVert);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size);
|
||||
public static Box2D operator +(Box2D a, Float2 b) => new(a.center, a.size + b);
|
||||
@ -114,8 +109,6 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||
public static Box2D operator *(Box2D a, Float2 b) => new(a.center, a.size * b);
|
||||
public static Box2D operator /(Box2D a, float b) => new(a.center / b, a.size / b);
|
||||
public static Box2D operator /(Box2D a, Float2 b) => new(a.center, a.size / b);
|
||||
public static bool operator ==(Box2D a, Box2D b) => a.Equals(b);
|
||||
public static bool operator !=(Box2D a, Box2D b) => !a.Equals(b);
|
||||
|
||||
public static implicit operator Box2D(Fill<float> fill) => new(fill);
|
||||
public static explicit operator Box2D(Box3D box) => new(box.center, (Float2)box.size);
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
public record class Box3D : IAbsolute<Box3D>, IAverage<Box3D>, ICeiling<Box3D>, IClamp<Box3D>,
|
||||
IContains<Vert>, IEquatable<Box3D>, IFloor<Box3D>, ILerp<Box3D, float>, IMedian<Box3D>,
|
||||
IRound<Box3D>, IShape3D<float>, ISplittable<Box3D, (Vert[] centers, Float3[] sizes)>
|
||||
{
|
||||
public static Box3D Unit => new(Vert.Zero, Float3.One);
|
||||
|
||||
@ -23,8 +25,9 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
}
|
||||
}
|
||||
|
||||
public float Area => size.x * size.y * size.z;
|
||||
public float Perimeter => size.x * 2 + size.y * 2 + size.z * 2;
|
||||
public float Perimeter => 2 * (size.x + size.y + size.z);
|
||||
public float SurfaceArea => 2 * (size.x * size.y + size.y * size.z + size.x * size.z);
|
||||
public float Volume => size.x * size.y * size.z;
|
||||
|
||||
public Vert center;
|
||||
public Float3 size;
|
||||
@ -50,10 +53,12 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
(Vert[] centers, Float3[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Average(centers), Float3.Average(sizes));
|
||||
}
|
||||
public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Float3.Ceiling(val.size));
|
||||
public static Box3D Ceiling(Box3D val) =>
|
||||
new(Vert.Ceiling(val.center), (Float3)Float3.Ceiling(val.size));
|
||||
public static Box3D Clamp(Box3D val, Box3D min, Box3D max) =>
|
||||
new(Vert.Clamp(val.center, min.center, max.center), Float3.Clamp(val.size, min.size, max.size));
|
||||
public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Float3.Floor(val.size));
|
||||
public static Box3D Floor(Box3D val) =>
|
||||
new(Vert.Floor(val.center), (Float3)Float3.Floor(val.size));
|
||||
public static Box3D Lerp(Box3D a, Box3D b, float t, bool clamp = true) =>
|
||||
new(Vert.Lerp(a.center, b.center, t, clamp), Float3.Lerp(a.size, b.size, t, clamp));
|
||||
public static Box3D Median(params Box3D[] vals)
|
||||
@ -61,16 +66,8 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
(Vert[] verts, Float3[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Median(verts), Float3.Median(sizes));
|
||||
}
|
||||
public static Box3D Max(params Box3D[] vals)
|
||||
{
|
||||
(Vert[] verts, Float3[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Max(verts), Float3.Max(sizes));
|
||||
}
|
||||
public static Box3D Min(params Box3D[] vals)
|
||||
{
|
||||
(Vert[] verts, Float3[] sizes) = SplitArray(vals);
|
||||
return new(Vert.Min(verts), Float3.Min(sizes));
|
||||
}
|
||||
public static Box3D Round(Box3D val) => new(Vert.Ceiling(val.center), (Float3)Float3.Ceiling(val.size));
|
||||
|
||||
public static (Vert[] centers, Float3[] sizes) SplitArray(params Box3D[] vals)
|
||||
{
|
||||
Vert[] centers = new Vert[vals.Length];
|
||||
@ -85,25 +82,27 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
return (centers, sizes);
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Box3D? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Box3D)) return base.Equals(obj);
|
||||
return Equals((Box3D)obj);
|
||||
if (other is null) return false;
|
||||
return center == other.center && size == other.size;
|
||||
}
|
||||
public bool Equals(Box3D other) => center == other.center && size == other.size;
|
||||
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public bool Contains(Vert vert)
|
||||
{
|
||||
Float3 diff = Float3.Absolute(center - vert);
|
||||
return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z;
|
||||
}
|
||||
public object Clone() => new Box3D(center, size);
|
||||
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("Min = ");
|
||||
builder.Append(MinVert);
|
||||
builder.Append(", Max = ");
|
||||
builder.Append(MaxVert);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size);
|
||||
public static Box3D operator +(Box3D a, Float3 b) => new(a.center, a.size + b);
|
||||
@ -114,8 +113,6 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||
public static Box3D operator *(Box3D a, Float3 b) => new(a.center, a.size * b);
|
||||
public static Box3D operator /(Box3D a, float b) => new(a.center / b, a.size / b);
|
||||
public static Box3D operator /(Box3D a, Float3 b) => new(a.center, a.size / b);
|
||||
public static bool operator ==(Box3D a, Box3D b) => a.Equals(b);
|
||||
public static bool operator !=(Box3D a, Box3D b) => !a.Equals(b);
|
||||
|
||||
public static implicit operator Box3D(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Box3D(Box2D box) => new(box);
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public interface ISubdividable<T>
|
||||
{
|
||||
public T Subdivide();
|
||||
public T Subdivide(int iterations);
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public interface ITriangulatable
|
||||
{
|
||||
public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables)
|
||||
{
|
||||
List<Triangle> res = new();
|
||||
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
|
||||
return res.ToArray();
|
||||
}
|
||||
|
||||
public Triangle[] Triangulate();
|
||||
}
|
||||
@ -1,7 +1,11 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<Vert>, IEquatable<Line>,
|
||||
IGroup<Vert>, ISubdividable<Line[]>
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public record class Line : IAbsolute<Line>, IAverage<Line>, ICeiling<Line>, IClamp<Line>, IClosestTo<Vert>,
|
||||
IComparable<Line>, IContains<Vert>, IEquatable<Line>, IFloor<Line>, IFromTuple<Line, (Vert start, Vert end)>,
|
||||
IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Line, float>, IMedian<Line>, IPresets3D<Line>,
|
||||
IRound<Line>, ISplittable<Line, (Vert[] starts, Vert[] ends)>, ISubdivide<Line[]>
|
||||
{
|
||||
public static Line Back => new(Vert.Zero, Vert.Back);
|
||||
public static Line Down => new(Vert.Zero, Vert.Down);
|
||||
@ -56,6 +60,28 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
}
|
||||
}
|
||||
}
|
||||
public Vert this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value;
|
||||
}
|
||||
public Vert[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
List<Vert> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b));
|
||||
public static Line Average(params Line[] vals)
|
||||
@ -74,16 +100,7 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||
return new(Vert.Median(starts), Vert.Median(ends));
|
||||
}
|
||||
public static Line Max(params Line[] vals)
|
||||
{
|
||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||
return new(Vert.Max(starts), Vert.Max(ends));
|
||||
}
|
||||
public static Line Min(params Line[] vals)
|
||||
{
|
||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||
return new(Vert.Min(starts), Vert.Min(ends));
|
||||
}
|
||||
public static Line Round(Line val) => new(Vert.Round(val.a), Vert.Round(val.b));
|
||||
|
||||
public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines)
|
||||
{
|
||||
@ -96,22 +113,20 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
return (starts, ends);
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Line? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Line)) return base.Equals(obj);
|
||||
return Equals((Line)obj);
|
||||
if (other is null) return false;
|
||||
return a == other.a && b == other.b;
|
||||
}
|
||||
public bool Equals(Line other) => a == other.a && b == other.b;
|
||||
public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public object Clone() => new Line(a, b);
|
||||
|
||||
public int CompareTo(Line line) => Length.CompareTo(line.Length);
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Length) + "s directly.")]
|
||||
public int CompareTo(Line? line)
|
||||
{
|
||||
if (line is null) return -1;
|
||||
return Length.CompareTo(line.Length);
|
||||
}
|
||||
|
||||
public bool Contains(Vert vert)
|
||||
{
|
||||
@ -173,6 +188,15 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
public List<float> ToFloatList() => new() { a.position.x, a.position.y, a.position.z,
|
||||
b.position.x, b.position.y, b.position.z };
|
||||
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("A = ");
|
||||
builder.Append(a);
|
||||
builder.Append(", B = ");
|
||||
builder.Append(b);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b);
|
||||
public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b);
|
||||
public static Line operator -(Line l) => new(-l.a, -l.b);
|
||||
@ -184,11 +208,17 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
public static Line operator /(Line a, Line b) => new(a.a / b.a, a.b / b.b);
|
||||
public static Line operator /(Line a, Vert b) => new(a.a / b, a.b / b);
|
||||
public static Line operator /(Line a, float b) => new(a.a / b, a.b / b);
|
||||
public static bool operator ==(Line a, Line b) => a.Equals(b);
|
||||
public static bool operator !=(Line a, Line b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Length) + "s directly.")]
|
||||
public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Length) + "s directly.")]
|
||||
public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Length) + "s directly.")]
|
||||
public static bool operator >=(Line a, Line b) => a > b || a == b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Length) + "s directly.")]
|
||||
public static bool operator <=(Line a, Line b) => a < b || a == b;
|
||||
|
||||
public static implicit operator Line(Fill<Vert> fill) => new(fill);
|
||||
@ -196,4 +226,5 @@ public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<V
|
||||
public static implicit operator Line(Fill<Int3> fill) => new(fill);
|
||||
public static implicit operator Line(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Line(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Line((Vert start, Vert end) val) => new(val.start, val.end);
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdividable<Polygon>, ITriangulatable
|
||||
[Obsolete("This struct is a garbage fire. This will be completely redesigned in v2.5.0")]
|
||||
public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivide<Polygon>, ITriangulate
|
||||
{
|
||||
public Line[] Lines
|
||||
{
|
||||
@ -82,8 +83,8 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
while (true)
|
||||
{
|
||||
Line? v = fill(i);
|
||||
if (!v.HasValue) break;
|
||||
lines.Add(v.Value);
|
||||
if (v is null) break;
|
||||
lines.Add(v);
|
||||
}
|
||||
this = new(lines.ToArray());
|
||||
}
|
||||
@ -189,24 +190,6 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
||||
Line[] res = new Line[a.Lines.Length];
|
||||
for (int i = 0; i < res.Length; i++) res[i] = Line.Lerp(lines[0][i], lines[1][i], t, clamp);
|
||||
return new(res);
|
||||
}
|
||||
public static Polygon Max(params Polygon[] vals)
|
||||
{
|
||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||
if (vals.Length < 1) return default;
|
||||
|
||||
Line[][] lines = new Line[vals.Length][];
|
||||
for (int i = 0; i < vals.Length; i++) lines[i] = vals[i].Lines;
|
||||
|
||||
Line[] res = new Line[vals[0].Lines.Length];
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
Line[] row = new Line[vals.Length];
|
||||
for (int j = 0; j < vals[0].Lines.Length; j++) row[j] = vals[j].Lines[i];
|
||||
res[i] = Line.Max(row);
|
||||
}
|
||||
|
||||
return new(res);
|
||||
}
|
||||
public static Polygon Median(params Polygon[] vals)
|
||||
@ -225,24 +208,6 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
res[i] = Line.Median(row);
|
||||
}
|
||||
|
||||
return new(res);
|
||||
}
|
||||
public static Polygon Min(params Polygon[] vals)
|
||||
{
|
||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||
if (vals.Length < 1) return default;
|
||||
|
||||
Line[][] lines = new Line[vals.Length][];
|
||||
for (int i = 0; i < vals.Length; i++) lines[i] = vals[i].Lines;
|
||||
|
||||
Line[] res = new Line[vals[0].Lines.Length];
|
||||
for (int i = 0; i < res.Length; i++)
|
||||
{
|
||||
Line[] row = new Line[vals.Length];
|
||||
for (int j = 0; j < vals[0].Lines.Length; j++) row[j] = vals[j].Lines[i];
|
||||
res[i] = Line.Min(row);
|
||||
}
|
||||
|
||||
return new(res);
|
||||
}
|
||||
|
||||
@ -265,19 +230,12 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
return Lines == other.Lines;
|
||||
}
|
||||
public override int GetHashCode() => Lines.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider)
|
||||
{
|
||||
string s = "";
|
||||
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
||||
return s;
|
||||
}
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
string s = "";
|
||||
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
||||
return s;
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
string s = "";
|
||||
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i] + " ";
|
||||
return s;
|
||||
}
|
||||
|
||||
public object Clone() => new Polygon(Lines);
|
||||
|
||||
@ -374,13 +332,16 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
|
||||
}
|
||||
}
|
||||
|
||||
if (closest == null) throw new("Unknown error triangulating the polygon.");
|
||||
if (closest == null)
|
||||
throw new Nerd_STFException("Unknown error triangulating the polygon.");
|
||||
|
||||
if (closest.Value.posB > closest.Value.posA)
|
||||
closest = (closest.Value.posB, closest.Value.posA, closest.Value.line);
|
||||
|
||||
List<Line> partA = new(Lines[closest.Value.posA..(closest.Value.posB - 1)]);
|
||||
partA.Add(closest.Value.line);
|
||||
List<Line> partA = new(Lines[closest.Value.posA..(closest.Value.posB - 1)])
|
||||
{
|
||||
closest.Value.line
|
||||
};
|
||||
|
||||
Polygon pA = new(partA.ToArray());
|
||||
|
||||
|
||||
@ -1,6 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert>, ITriangulatable
|
||||
public record class Quadrilateral : IAbsolute<Quadrilateral>, IAverage<Quadrilateral>, ICeiling<Quadrilateral>,
|
||||
IClamp<Quadrilateral>, IEquatable<Quadrilateral>, IFloor<Quadrilateral>,
|
||||
IFromTuple<Quadrilateral, (Vert a, Vert b, Vert c, Vert d)>, IGroup<Vert>, IIndexAll<Vert>, IIndexRangeAll<Vert>,
|
||||
ILerp<Quadrilateral, float>, IRound<Quadrilateral>, IShape2D<float>, ITriangulate
|
||||
{
|
||||
public Vert A
|
||||
{
|
||||
@ -94,6 +97,7 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
private Vert p_a, p_b, p_c, p_d;
|
||||
private Line p_ab, p_bc, p_cd, p_da;
|
||||
|
||||
[Obsolete("This field doesn't account for the Z-axis. This will be fixed in v2.4.0")]
|
||||
public float Area
|
||||
{
|
||||
get
|
||||
@ -178,6 +182,28 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
}
|
||||
}
|
||||
}
|
||||
public Vert this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public Vert[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<Vert> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Quadrilateral Absolute(Quadrilateral val) =>
|
||||
new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D));
|
||||
@ -211,6 +237,8 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
||||
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs), Vert.Min(Ds));
|
||||
}
|
||||
public static Quadrilateral Round(Quadrilateral val) =>
|
||||
new(Vert.Round(val.A), Vert.Round(val.B), Vert.Round(val.C), Vert.Round(val.D));
|
||||
|
||||
public static (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) SplitVertArray(params Quadrilateral[] quads)
|
||||
{
|
||||
@ -264,20 +292,12 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
}
|
||||
public static List<float> ToFloatListAll(params Quadrilateral[] quads) => new(ToFloatArrayAll(quads));
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Quadrilateral? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Quadrilateral)) return base.Equals(obj);
|
||||
return Equals((Quadrilateral)obj);
|
||||
if (other is null) return false;
|
||||
return A == other.A && B == other.B && C == other.C && D == other.D;
|
||||
}
|
||||
public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D;
|
||||
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider)
|
||||
+ " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: "
|
||||
+ B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
||||
|
||||
public object Clone() => new Quadrilateral(A, B, C, D);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<Vert> GetEnumerator()
|
||||
@ -308,6 +328,19 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
public Triangle[] Triangulate() => new Line(A, C).Length > new Line(B, D).Length ?
|
||||
new Triangle[] { new(A, B, C), new(C, D, A) } : new Triangle[] { new(B, C, D), new(D, A, B) };
|
||||
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("A = ");
|
||||
builder.Append(A);
|
||||
builder.Append(", B = ");
|
||||
builder.Append(B);
|
||||
builder.Append(", C = ");
|
||||
builder.Append(C);
|
||||
builder.Append(", D = ");
|
||||
builder.Append(D);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Quadrilateral operator +(Quadrilateral a, Quadrilateral b) => new(a.A + b.A, a.B + b.B,
|
||||
a.C + b.C, a.D + b.D);
|
||||
public static Quadrilateral operator +(Quadrilateral a, Vert b) => new(a.A + b, a.B + b, a.C + b, a.D + b);
|
||||
@ -323,8 +356,6 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
a.C / b.C, a.D / b.D);
|
||||
public static Quadrilateral operator /(Quadrilateral a, Vert b) => new(a.A / b, a.B / b, a.C / b, a.D / b);
|
||||
public static Quadrilateral operator /(Quadrilateral a, float b) => new(a.A / b, a.B / b, a.C / b, a.D / b);
|
||||
public static bool operator ==(Quadrilateral a, Quadrilateral b) => a.Equals(b);
|
||||
public static bool operator !=(Quadrilateral a, Quadrilateral b) => !a.Equals(b);
|
||||
|
||||
public static implicit operator Quadrilateral(Fill<Vert> fill) => new(fill);
|
||||
public static implicit operator Quadrilateral(Fill<Float3> fill) => new(fill);
|
||||
@ -332,6 +363,6 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
|
||||
public static implicit operator Quadrilateral(Fill<Line> fill) => new(fill);
|
||||
public static implicit operator Quadrilateral(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Quadrilateral(Fill<int> fill) => new(fill);
|
||||
public static explicit operator Quadrilateral(Polygon poly) => new(poly.Lines[0], poly.Lines[1],
|
||||
poly.Lines[2], poly.Lines[3]);
|
||||
public static implicit operator Quadrilateral((Vert a, Vert b, Vert c, Vert d) val) =>
|
||||
new(val.a, val.b, val.c, val.d);
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, IComparable<float>, IContainer<Vert>,
|
||||
IEquatable<Sphere>, IEquatable<float>
|
||||
public record class Sphere : IAverage<Sphere>, ICeiling<Sphere>, IClamp<Sphere>, IClosestTo<Vert>,
|
||||
IComparable<Sphere>, IComparable<float>, IContains<Vert>, IEquatable<Sphere>, IEquatable<float>, IFloor<Sphere>,
|
||||
IFromTuple<Sphere, (Vert center, float radius)>, ILerp<Sphere, float>, IMax<Sphere>, IMedian<Sphere>,
|
||||
IMin<Sphere>, IRound<Sphere>, ISplittable<Sphere, (Vert[] centers, float[] radii)>
|
||||
{
|
||||
public static Sphere Unit => new(Vert.Zero, 1);
|
||||
|
||||
@ -54,6 +56,7 @@ public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, ICompara
|
||||
(Vert[] centers, float[] radii) = SplitArray(vals);
|
||||
return new(Vert.Min(centers), Mathf.Min(radii));
|
||||
}
|
||||
public static Sphere Round(Sphere val) => new(Vert.Round(val.center), Mathf.Round(val.radius));
|
||||
|
||||
public static (Vert[] centers, float[] radii) SplitArray(params Sphere[] spheres)
|
||||
{
|
||||
@ -67,31 +70,37 @@ public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, ICompara
|
||||
return (centers, radii);
|
||||
}
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null) return base.Equals(obj);
|
||||
Type type = obj.GetType();
|
||||
if (type == typeof(Sphere)) return Equals((Sphere)obj);
|
||||
if (type == typeof(float)) return Equals((float)obj);
|
||||
return base.Equals(obj);
|
||||
}
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public bool Equals(float other) => Volume == other;
|
||||
public bool Equals(Sphere other) => center == other.center && radius == other.radius;
|
||||
public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) => "Center: " + center.ToString(provider)
|
||||
+ " Radius: " + radius.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider)
|
||||
+ " Radius: " + radius.ToString(provider);
|
||||
public virtual bool Equals(Sphere? other)
|
||||
{
|
||||
if (other is null) return false;
|
||||
return center == other.center && radius == other.radius;
|
||||
}
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public object Clone() => new Sphere(center, radius);
|
||||
|
||||
public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume);
|
||||
public int CompareTo(Sphere? other)
|
||||
{
|
||||
if (other is null) return -1;
|
||||
return Volume.CompareTo(other.Volume);
|
||||
}
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public int CompareTo(float volume) => Volume.CompareTo(volume);
|
||||
|
||||
public bool Contains(Vert vert) => (center - vert).Magnitude <= radius;
|
||||
|
||||
public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + vert;
|
||||
public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + center;
|
||||
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("Center = ");
|
||||
builder.Append(builder);
|
||||
builder.Append(", Radius = ");
|
||||
builder.Append(radius);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Sphere operator +(Sphere a, Sphere b) => new(a.center + b.center, a.radius + b.radius);
|
||||
public static Sphere operator +(Sphere a, Vert b) => new(a.center + b, a.radius);
|
||||
@ -103,16 +112,37 @@ public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, ICompara
|
||||
public static Sphere operator *(Sphere a, float b) => new(a.center * b, a.radius * b);
|
||||
public static Sphere operator /(Sphere a, Sphere b) => new(a.center * b.center, a.radius * b.radius);
|
||||
public static Sphere operator /(Sphere a, float b) => new(a.center * b, a.radius * b);
|
||||
public static bool operator ==(Sphere a, Sphere b) => a.Equals(b);
|
||||
public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b);
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator ==(Sphere a, float b) => a.Equals(b);
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator !=(Sphere a, float b) => !a.Equals(b);
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator >(Sphere a, float b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator <(Sphere a, float b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator >=(Sphere a, Sphere b) => a > b || a == b;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator <=(Sphere a, Sphere b) => a < b || a == b;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator >=(Sphere a, float b) => a > b || a == b;
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " + nameof(radius) + "es directly. " +
|
||||
"This method will be removed in Nerd_STF 2.5.0.")]
|
||||
public static bool operator <=(Sphere a, float b) => a < b || a == b;
|
||||
|
||||
public static implicit operator Sphere((Vert center, float radius) val) =>
|
||||
new(val.center, val.radius);
|
||||
}
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
using System.Net.Security;
|
||||
|
||||
public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
namespace Nerd_STF.Mathematics.Geometry;
|
||||
|
||||
public record class Triangle : IAbsolute<Triangle>, IAverage<Triangle>, ICeiling<Triangle>, IClamp<Triangle>,
|
||||
IEquatable<Triangle>, IFloor<Triangle>, IFromTuple<Triangle, (Vert a, Vert b, Vert c)>, IGroup<Vert>,
|
||||
IIndexAll<Vert>, IIndexRangeAll<Vert>, ILerp<Triangle, float>, IRound<Triangle>, IShape2D<float>
|
||||
{
|
||||
public Vert A
|
||||
{
|
||||
@ -72,6 +76,7 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
private Vert p_a, p_b, p_c;
|
||||
private Line p_ab, p_bc, p_ca;
|
||||
|
||||
[Obsolete("This field doesn't account for the Z-axis. This will be fixed in v2.4.0")]
|
||||
public float Area => (float)Mathf.Absolute((A.position.x * B.position.y) + (B.position.x * C.position.y) +
|
||||
(C.position.x * A.position.y) - ((B.position.x * A.position.y) + (C.position.x * B.position.y) +
|
||||
(A.position.x * C.position.y))) * 0.5f;
|
||||
@ -141,6 +146,28 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
}
|
||||
}
|
||||
}
|
||||
public Vert this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 3 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value;
|
||||
}
|
||||
public Vert[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
List<Vert> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Triangle Absolute(Triangle val) =>
|
||||
new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C));
|
||||
@ -172,6 +199,8 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
||||
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs));
|
||||
}
|
||||
public static Triangle Round(Triangle val) =>
|
||||
new(Vert.Round(val.A), Vert.Round(val.B), Vert.Round(val.C));
|
||||
|
||||
public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris)
|
||||
{
|
||||
@ -216,20 +245,12 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
}
|
||||
public static List<float> ToFloatListAll(params Triangle[] tris) => new(ToFloatArrayAll(tris));
|
||||
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
public virtual bool Equals(Triangle? other)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Triangle)) return base.Equals(obj);
|
||||
return Equals((Triangle)obj);
|
||||
if (other is null) return false;
|
||||
return A == other.A && B == other.B && C == other.C;
|
||||
}
|
||||
public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C;
|
||||
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider);
|
||||
|
||||
public object Clone() => new Triangle(A, B, C);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<Vert> GetEnumerator()
|
||||
@ -253,6 +274,18 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
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 };
|
||||
|
||||
protected virtual bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("A = ");
|
||||
builder.Append(A);
|
||||
builder.Append(", B = ");
|
||||
builder.Append(B);
|
||||
builder.Append(", C = ");
|
||||
builder.Append(C);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C);
|
||||
public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b);
|
||||
public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C);
|
||||
@ -264,8 +297,6 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
public static Triangle operator /(Triangle a, Triangle b) => new(a.A / b.A, a.B / b.B, a.C / b.C);
|
||||
public static Triangle operator /(Triangle a, Vert b) => new(a.A / b, a.B / b, a.C / b);
|
||||
public static Triangle operator /(Triangle a, float b) => new(a.A / b, a.B / b, a.C / b);
|
||||
public static bool operator ==(Triangle a, Triangle b) => a.Equals(b);
|
||||
public static bool operator !=(Triangle a, Triangle b) => !a.Equals(b);
|
||||
|
||||
public static implicit operator Triangle(Fill<Vert> fill) => new(fill);
|
||||
public static implicit operator Triangle(Fill<Float3> fill) => new(fill);
|
||||
@ -273,5 +304,6 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||
public static implicit operator Triangle(Fill<Line> fill) => new(fill);
|
||||
public static implicit operator Triangle(Fill<float> fill) => new(fill);
|
||||
public static implicit operator Triangle(Fill<int> fill) => new(fill);
|
||||
public static explicit operator Triangle(Polygon poly) => new(poly.Lines[0], poly.Lines[1], poly.Lines[2]);
|
||||
public static implicit operator Triangle((Vert a, Vert b, Vert c) val) =>
|
||||
new(val.a, val.b, val.c);
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
public static Vert Zero => new(0, 0, 0);
|
||||
|
||||
public float Magnitude => position.Magnitude;
|
||||
public Vert Normalized => new(this / Magnitude);
|
||||
public Vert Normalized => this / Magnitude;
|
||||
|
||||
public Float3 position;
|
||||
|
||||
@ -50,6 +50,8 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
Float3.Max(ToFloat3Array(vals));
|
||||
public static Vert Min(params Vert[] vals) =>
|
||||
Float3.Min(ToFloat3Array(vals));
|
||||
public static Vert Round(Vert val) =>
|
||||
Float3.Round(val);
|
||||
|
||||
public static Float3[] ToFloat3Array(params Vert[] vals)
|
||||
{
|
||||
@ -66,9 +68,7 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
|
||||
}
|
||||
public bool Equals(Vert other) => position == other.position;
|
||||
public override int GetHashCode() => position.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) => position.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) => position.ToString(provider);
|
||||
public override string ToString() => position.ToString();
|
||||
|
||||
public object Clone() => new Vert(position);
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int>
|
||||
public record struct Int2 : IAbsolute<Int2>, IAverage<Int2>, IClamp<Int2>, IClampMagnitude<Int2, int>,
|
||||
IComparable<Int2>, ICross<Int2, Int3>, IDivide<Int2>, IDot<Int2, int>, IEquatable<Int2>,
|
||||
IFromTuple<Int2, (int x, int y)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int2, float>,
|
||||
IMathOperators<Int2>, IMax<Int2>, IMedian<Int2>, IMin<Int2>, IPresets2D<Int2>, IProduct<Int2>,
|
||||
ISplittable<Int2, (int[] Xs, int[] Ys)>, ISubtract<Int2>, ISum<Int2>
|
||||
{
|
||||
public static Int2 Down => new(0, -1);
|
||||
public static Int2 Left => new(-1, 0);
|
||||
@ -47,6 +51,28 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Int2 Absolute(Int2 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
||||
@ -92,14 +118,14 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int2 val = vals[0];
|
||||
foreach (Int2 d in vals) val = d > val ? d : val;
|
||||
foreach (Int2 d in vals) val = d.Magnitude > val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int2 Min(params Int2[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int2 val = vals[0];
|
||||
foreach (Int2 d in vals) val = d < val ? d : val;
|
||||
foreach (Int2 d in vals) val = d.Magnitude < val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int2 Product(params Int2[] vals)
|
||||
@ -128,21 +154,11 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
return (Xs, Ys);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
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 base.Equals(obj);
|
||||
return Equals((Int2)obj);
|
||||
}
|
||||
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||
|
||||
public object Clone() => new Int2(x, y);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<int> GetEnumerator()
|
||||
@ -161,6 +177,15 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
|
||||
public Vector2d ToVector() => ((Float2)this).ToVector();
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Int2 operator +(Int2 a, Int2 b) => new(a.x + b.x, a.y + b.y);
|
||||
public static Int2 operator -(Int2 i) => new(-i.x, -i.y);
|
||||
public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y);
|
||||
@ -173,11 +198,17 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
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);
|
||||
public static bool operator ==(Int2 a, Int2 b) => a.Equals(b);
|
||||
public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Int2 a, Int2 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Int2 a, Int2 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i);
|
||||
@ -191,4 +222,5 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
|
||||
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);
|
||||
public static implicit operator Int2(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Int2((int x, int y) val) => new(val.x, val.y);
|
||||
}
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
using System.Data;
|
||||
|
||||
public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int>
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public record struct Int3 : IAbsolute<Int3>, IAverage<Int3>, IClamp<Int3>, IClampMagnitude<Int3, int>,
|
||||
IComparable<Int3>, ICross<Int3>, IDivide<Int3>, IDot<Int3, int>, IEquatable<Int3>,
|
||||
IFromTuple<Int3, (int x, int y, int z)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>, ILerp<Int3, float>,
|
||||
IMathOperators<Int3>, IMax<Int3>, IMedian<Int3>, IMin<Int3>, IPresets3D<Int3>, IProduct<Int3>,
|
||||
ISplittable<Int3, (int[] Xs, int[] Ys, int[] Zs)>, ISubtract<Int3>, ISum<Int3>
|
||||
{
|
||||
public static Int3 Back => new(0, 0, -1);
|
||||
public static Int3 Down => new(0, -1, 0);
|
||||
@ -60,6 +66,28 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 3 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 3 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 3 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 3 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Int3 Absolute(Int3 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
||||
@ -112,14 +140,14 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int3 val = vals[0];
|
||||
foreach (Int3 d in vals) val = d > val ? d : val;
|
||||
foreach (Int3 d in vals) val = d.Magnitude > val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int3 Min(params Int3[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int3 val = vals[0];
|
||||
foreach (Int3 d in vals) val = d < val ? d : val;
|
||||
foreach (Int3 d in vals) val = d.Magnitude < val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int3 Product(params Int3[] vals)
|
||||
@ -148,20 +176,13 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
}
|
||||
return (Xs, Ys, Zs);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
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 base.Equals(obj);
|
||||
return Equals((Int3)obj);
|
||||
}
|
||||
public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||
public object Clone() => new Int3(x, y, z);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<int> GetEnumerator()
|
||||
{
|
||||
@ -180,6 +201,17 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
|
||||
public Vector3d ToVector() => ((Float3)this).ToVector();
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
builder.Append(", z = ");
|
||||
builder.Append(z);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Int3 operator +(Int3 a, Int3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
public static Int3 operator -(Int3 i) => new(-i.x, -i.y, -i.z);
|
||||
public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
@ -192,11 +224,17 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
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);
|
||||
public static bool operator ==(Int3 a, Int3 b) => a.Equals(b);
|
||||
public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Int3 a, Int3 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Int3 a, Int3 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0);
|
||||
@ -215,4 +253,6 @@ public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int
|
||||
public static explicit operator Int3(RGBAByte val) => new(val.R, val.G, val.B);
|
||||
public static explicit operator Int3(HSVAByte val) => new(val.H, val.S, val.V);
|
||||
public static implicit operator Int3(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Int3((int x, int y, int z) vals) =>
|
||||
new(vals.x, vals.y, vals.z);
|
||||
}
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
namespace Nerd_STF.Mathematics;
|
||||
|
||||
public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int>
|
||||
public record struct Int4 : IAbsolute<Int4>, IAverage<Int4>, IClamp<Int4>, IClampMagnitude<Int4, int>,
|
||||
IComparable<Int4>, IDivide<Int4>, IDot<Int4, int>, IEquatable<Int4>,
|
||||
IFromTuple<Int4, (int x, int y, int z, int w)>, IGroup<int>, IIndexAll<int>, IIndexRangeAll<int>,
|
||||
ILerp<Int4, float>, IMathOperators<Int4>, IMax<Int4>, IMedian<Int4>, IMin<Int4>, IPresets4D<Int4>,
|
||||
IProduct<Int4>, ISplittable<Int4, (int[] Xs, int[] Ys, int[] Zs, int[] Ws)>, ISubtract<Int4>, ISum<Int4>
|
||||
{
|
||||
public static Int4 Back => new(0, 0, -1, 0);
|
||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
public static Int4 Deep => new(0, 0, 0, -1);
|
||||
public static Int4 Down => new(0, -1, 0, 0);
|
||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
||||
@ -81,6 +87,28 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
}
|
||||
}
|
||||
}
|
||||
public int this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public int[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<int> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Int4 Absolute(Int4 val) =>
|
||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
||||
@ -129,14 +157,14 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int4 val = vals[0];
|
||||
foreach (Int4 d in vals) val = d > val ? d : val;
|
||||
foreach (Int4 d in vals) val = d.Magnitude > val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int4 Min(params Int4[] vals)
|
||||
{
|
||||
if (vals.Length < 1) return Zero;
|
||||
Int4 val = vals[0];
|
||||
foreach (Int4 d in vals) val = d < val ? d : val;
|
||||
foreach (Int4 d in vals) val = d.Magnitude < val.Magnitude ? d : val;
|
||||
return val;
|
||||
}
|
||||
public static Int4 Product(params Int4[] vals)
|
||||
@ -168,23 +196,11 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
return (Xs, Ys, Zs, Ws);
|
||||
}
|
||||
|
||||
[Obsolete("This method is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
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 base.Equals(obj);
|
||||
return Equals((Int4)obj);
|
||||
}
|
||||
public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||
+ " W: " + w.ToString(provider);
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||
+ " W: " + w.ToString(provider);
|
||||
|
||||
public object Clone() => new Int4(x, y, z, w);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<int> GetEnumerator()
|
||||
@ -203,6 +219,19 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
}
|
||||
public List<int> ToList() => new() { x, y, z, w };
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append("x = ");
|
||||
builder.Append(x);
|
||||
builder.Append(", y = ");
|
||||
builder.Append(y);
|
||||
builder.Append(", z = ");
|
||||
builder.Append(z);
|
||||
builder.Append(", w = ");
|
||||
builder.Append(w);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||
public static Int4 operator -(Int4 d) => new(-d.x, -d.y, -d.z, -d.w);
|
||||
public static Int4 operator -(Int4 a, Int4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
||||
@ -215,11 +244,17 @@ public struct Int4 : ICloneable, IComparable<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, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
||||
public static bool operator ==(Int4 a, Int4 b) => a.Equals(b);
|
||||
public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b);
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Int4 a, Int4 b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Int4 a, Int4 b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0);
|
||||
@ -240,4 +275,6 @@ public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int
|
||||
public static explicit operator Int4(CMYKAByte val) => new(val.C, val.M, val.Y, val.K);
|
||||
public static implicit operator Int4(HSVAByte val) => new(val.H, val.S, val.V, val.A);
|
||||
public static implicit operator Int4(Fill<int> fill) => new(fill);
|
||||
public static implicit operator Int4((int x, int y, int z, int w) vals) =>
|
||||
new(vals.x, vals.y, vals.z, vals.w);
|
||||
}
|
||||
|
||||
@ -105,8 +105,7 @@ public static class Mathf
|
||||
|
||||
public static int[] Factors(int val)
|
||||
{
|
||||
List<int> factors = new();
|
||||
factors.Add(1);
|
||||
List<int> factors = new() { 1 };
|
||||
for (int i = 2; i < val; i++) if (val % i == 0) factors.Add(i);
|
||||
factors.Add(val);
|
||||
return factors.ToArray();
|
||||
@ -144,14 +143,14 @@ public static class Mathf
|
||||
if (clamp) v = Clamp(v, Min(a, b), Max(a, b));
|
||||
return v;
|
||||
}
|
||||
public static int Lerp(int a, int b, float value, bool clamp = true) => (int)Lerp((float)a, b, value, clamp);
|
||||
public static int Lerp(int a, int b, float t, bool clamp = true) => (int)Lerp((float)a, b, t, clamp);
|
||||
|
||||
public static Equation MakeEquation(Dictionary<float, float> vals) => delegate (float x)
|
||||
{
|
||||
if (vals.Count < 1) throw new UndefinedException();
|
||||
if (vals.Count == 1) return vals.Values.First();
|
||||
|
||||
if (vals.ContainsKey(x)) return vals[x];
|
||||
if (vals.TryGetValue(x, out float value)) return value;
|
||||
float? min, max;
|
||||
|
||||
if (x < (min = vals.Keys.Min()))
|
||||
@ -212,9 +211,9 @@ public static class Mathf
|
||||
foreach (int i in vals) val = i > val ? i : val;
|
||||
return val;
|
||||
}
|
||||
public static T? Max<T>(params T[] vals) where T : IComparable<T>
|
||||
public static T Max<T>(params T[] vals) where T : IComparable<T>
|
||||
{
|
||||
if (vals.Length < 1) return default;
|
||||
if (vals.Length < 1) return default!;
|
||||
T val = vals[0];
|
||||
foreach (T t in vals) val = t.CompareTo(val) > 0 ? t : val;
|
||||
return val;
|
||||
@ -254,9 +253,9 @@ public static class Mathf
|
||||
foreach (int i in vals) val = i < val ? i : val;
|
||||
return val;
|
||||
}
|
||||
public static T? Min<T>(params T[] vals) where T : IComparable<T>
|
||||
public static T Min<T>(params T[] vals) where T : IComparable<T>
|
||||
{
|
||||
if (vals.Length < 1) return default;
|
||||
if (vals.Length < 1) return default!;
|
||||
T val = vals[0];
|
||||
foreach (T t in vals) val = t.CompareTo(val) < 0 ? t : val;
|
||||
return val;
|
||||
@ -327,8 +326,7 @@ public static class Mathf
|
||||
if (pow == 1) return num;
|
||||
if (pow < 1) return 0;
|
||||
int val = 1;
|
||||
int abs = Absolute(pow);
|
||||
for (int i = 0; i < abs; i++) val = val * num % mod;
|
||||
for (int i = 0; i < pow; i++) val = val * num % mod;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
namespace Nerd_STF.Mathematics.NumberSystems;
|
||||
|
||||
public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, IGroup<float>
|
||||
public record struct Complex(float u, float i) : IAbsolute<Complex>, IAverage<Complex>, ICeiling<Complex>,
|
||||
IClampMagnitude<Complex, float>, IComparable<Complex>, IDivide<Complex>, IDot<Complex, float>,
|
||||
IEquatable<Complex>, IFloor<Complex>, IGroup<float>, IIndexAll<float>, IIndexRangeAll<float>,
|
||||
ILerp<Complex, float>, IMax<Complex>, IMedian<Complex>, IMin<Complex>, IPresets2D<Complex>, IProduct<Complex>,
|
||||
IRound<Complex>, ISplittable<Complex, (float[] Us, float[] Is)>, ISum<Complex>
|
||||
{
|
||||
public static Complex Down => new(0, -1);
|
||||
public static Complex Left => new(-1, 0);
|
||||
@ -15,14 +19,10 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
public float Magnitude => Mathf.Sqrt(u * u + i * i);
|
||||
public Complex Normalized => this * Mathf.InverseSqrt(u * u + i * i);
|
||||
|
||||
public float u, i;
|
||||
public float u = u;
|
||||
public float i = i;
|
||||
|
||||
public Complex(float all) : this(all, all) { }
|
||||
public Complex(float u, float i)
|
||||
{
|
||||
this.u = u;
|
||||
this.i = i;
|
||||
}
|
||||
public Complex(Fill<float> fill) : this(fill(0), fill(1)) { }
|
||||
public Complex(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||
|
||||
@ -50,6 +50,28 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 2 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 2 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 2 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 2 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Complex Absolute(Complex val) => Float2.Absolute(val);
|
||||
public static Complex Average(params Complex[] vals)
|
||||
@ -129,20 +151,8 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
public Angle GetAngle() => Mathf.ArcTan(i / u);
|
||||
|
||||
public int CompareTo(Complex other) => Magnitude.CompareTo(other.Magnitude);
|
||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||
{
|
||||
if (obj == null || obj.GetType() != typeof(Complex)) return base.Equals(obj);
|
||||
return Equals((Complex)obj);
|
||||
}
|
||||
public bool Equals(Complex other) => u == other.u && i == other.i;
|
||||
public override int GetHashCode() => u.GetHashCode() ^ i.GetHashCode();
|
||||
public override string ToString() => ToString((string?)null);
|
||||
public string ToString(string? provider) =>
|
||||
u.ToString(provider) + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i";
|
||||
public string ToString(IFormatProvider provider) =>
|
||||
u.ToString(provider) + (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i";
|
||||
|
||||
public object Clone() => new Complex(u, i);
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
@ -161,6 +171,15 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
|
||||
public Vector2d ToVector() => ((Float2)this).ToVector();
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append(u);
|
||||
builder.Append(i >= 0 ? " + " : " - ");
|
||||
builder.Append(Mathf.Absolute(i));
|
||||
builder.Append('i');
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Complex operator +(Complex a, Complex b) => new(a.u + b.u, a.i + b.i);
|
||||
public static Complex operator -(Complex c) => new(-c.u, -c.i);
|
||||
public static Complex operator -(Complex a, Complex b) => new(a.u - b.u, a.i - b.i);
|
||||
@ -170,11 +189,18 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
public static Complex operator /(Complex a, Complex b) => a * b.Inverse;
|
||||
public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b);
|
||||
public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b);
|
||||
public static bool operator ==(Complex a, Complex b) => a.Equals(b);
|
||||
public static bool operator !=(Complex a, Complex b) => !a.Equals(b);
|
||||
public static Complex operator ~(Complex v) => v.Conjugate;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Complex a, Complex b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Complex a, Complex b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Complex a, Complex b) => a == b || a < b;
|
||||
|
||||
public static explicit operator Complex(Quaternion val) => new(val.u, val.i);
|
||||
@ -189,4 +215,5 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
|
||||
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);
|
||||
public static implicit operator Complex((float u, float i) val) => new(val.u, val.i);
|
||||
}
|
||||
|
||||
@ -1,12 +1,23 @@
|
||||
namespace Nerd_STF.Mathematics.NumberSystems;
|
||||
|
||||
public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quaternion>, IGroup<float>
|
||||
public record struct Quaternion(float u, float i, float j, float k) : IAbsolute<Quaternion>, IAverage<Quaternion>,
|
||||
ICeiling<Quaternion>, IClamp<Quaternion>, IClampMagnitude<Quaternion, float>, IComparable<Quaternion>,
|
||||
IDivide<Quaternion>, IDot<Quaternion, float>, IEquatable<Quaternion>, IFloor<Quaternion>, IGroup<float>,
|
||||
IIndexAll<float>, IIndexRangeAll<float>, ILerp<Quaternion, float>, IMax<Quaternion>, IMedian<Quaternion>,
|
||||
IMin<Quaternion>, IPresets4D<Quaternion>, IProduct<Quaternion>, IRound<Quaternion>,
|
||||
ISplittable<Quaternion, (float[] Us, float[] Is, float[] Js, float[] Ks)>, ISum<Quaternion>
|
||||
{
|
||||
public static Quaternion Back => new(0, 0, -1, 0);
|
||||
public static Quaternion Down => new(0, -1, 0, 0);
|
||||
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " +
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
public static Quaternion Far => new(0, 0, 0, 1);
|
||||
public static Quaternion Forward => new(0, 0, 1, 0);
|
||||
public static Quaternion HighW => new(0, 0, 0, 1);
|
||||
public static Quaternion Left => new(-1, 0, 0, 0);
|
||||
public static Quaternion LowW => new(0, 0, 0, -1);
|
||||
[Obsolete("Field has been replaced by " + nameof(LowW) + ", because it has a better name. " +
|
||||
"This field will be removed in v2.4.0.", false)]
|
||||
public static Quaternion Near => new(0, 0, 0, -1);
|
||||
public static Quaternion Right => new(1, 0, 0, 0);
|
||||
public static Quaternion Up => new(0, 1, 0, 0);
|
||||
@ -14,26 +25,31 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
public static Quaternion One => new(1, 1, 1, 1);
|
||||
public static Quaternion Zero => new(0, 0, 0, 0);
|
||||
|
||||
public Quaternion Conjugate => new(u, -i, -j, -k);
|
||||
public Quaternion Conjugate => new(u, -IJK);
|
||||
public Quaternion Inverse => Conjugate / (u * u + i * i + j * j + k * k);
|
||||
public float Magnitude => Mathf.Sqrt(u * u + i * i + j * j + k * k);
|
||||
public Quaternion Normalized => this * Mathf.InverseSqrt(u * u + i * i + j * j + k * k);
|
||||
|
||||
public Float3 IJK => new(i, j, k);
|
||||
public Float3 IJK
|
||||
{
|
||||
get => new(i, j, k);
|
||||
set
|
||||
{
|
||||
i = value.x;
|
||||
j = value.y;
|
||||
k = value.z;
|
||||
}
|
||||
}
|
||||
|
||||
public float u, i, j, k;
|
||||
public float u = u;
|
||||
public float i = i;
|
||||
public float j = j;
|
||||
public float k = 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)) { }
|
||||
|
||||
@ -71,6 +87,28 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
}
|
||||
}
|
||||
}
|
||||
public float this[Index index]
|
||||
{
|
||||
get => this[index.IsFromEnd ? 4 - index.Value : index.Value];
|
||||
set => this[index.IsFromEnd ? 4 - index.Value : index.Value] = value;
|
||||
}
|
||||
public float[] this[Range range]
|
||||
{
|
||||
get
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
List<float> res = new();
|
||||
for (int i = start; i < end; i++) res.Add(this[i]);
|
||||
return res.ToArray();
|
||||
}
|
||||
set
|
||||
{
|
||||
int start = range.Start.IsFromEnd ? 4 - range.Start.Value : range.Start.Value;
|
||||
int end = range.End.IsFromEnd ? 4 - range.End.Value : range.End.Value;
|
||||
for (int i = start; i < end; i++) this[i] = value[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static Quaternion Absolute(Quaternion val) => Float4.Absolute(val);
|
||||
public static Quaternion Average(params Quaternion[] vals)
|
||||
@ -136,27 +174,31 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
return Float4.Sum(floats.ToArray());
|
||||
}
|
||||
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public static Quaternion FromAngles(Angle yaw, Angle pitch, Angle? roll = null)
|
||||
{
|
||||
roll ??= Angle.Zero;
|
||||
float cosYaw = Mathf.Cos(yaw), cosPitch = Mathf.Cos(pitch), cosRoll = Mathf.Cos(roll.Value),
|
||||
sinYaw = Mathf.Sin(yaw), sinPitch = Mathf.Sin(pitch), sinRoll = Mathf.Sin(roll.Value);
|
||||
float cosYaw, cosPitch, cosRoll, sinYaw, sinPitch, sinRoll,
|
||||
cosYawCosPitch, sinYawSinPitch, cosYawSinPitch, sinYawCosPitch;
|
||||
|
||||
float cosYawCosPitch = cosYaw * cosPitch,
|
||||
cosYawSinPitch = cosYaw * sinPitch,
|
||||
sinYawCosPitch = sinYaw * cosPitch,
|
||||
sinYawSinPitch = sinYaw * sinPitch;
|
||||
cosYaw = Mathf.Cos(yaw * 0.5f);
|
||||
cosPitch = Mathf.Cos(pitch * 0.5f);
|
||||
cosRoll = Mathf.Cos(roll.Value * 0.5f);
|
||||
sinYaw = Mathf.Sin(yaw * 0.5f);
|
||||
sinPitch = Mathf.Sin(pitch * 0.5f);
|
||||
sinRoll = Mathf.Sin(roll.Value * 0.5f);
|
||||
|
||||
cosYawCosPitch = cosYaw * cosPitch;
|
||||
sinYawSinPitch = sinYaw * sinPitch;
|
||||
cosYawSinPitch = cosYaw * sinPitch;
|
||||
sinYawCosPitch = sinYaw * cosPitch;
|
||||
|
||||
return new(cosYawCosPitch * cosRoll + sinYawSinPitch * sinRoll,
|
||||
cosYawCosPitch * sinRoll + sinYawSinPitch * cosRoll,
|
||||
cosYawCosPitch * sinRoll - sinYawSinPitch * cosRoll,
|
||||
cosYawSinPitch * cosRoll + sinYawCosPitch * sinRoll,
|
||||
sinYawCosPitch * cosRoll + cosYawSinPitch * sinRoll);
|
||||
sinYawCosPitch * cosRoll - cosYawSinPitch * sinRoll);
|
||||
}
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public static Quaternion FromAngles(Float3 vals, Angle.Type valType) =>
|
||||
FromAngles(new(vals.x, valType), new(vals.y, valType), new(vals.z, valType));
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public static Quaternion FromVector(Vector3d vec) => FromAngles(vec.yaw, vec.pitch);
|
||||
|
||||
public static (float[] Us, float[] Is, float[] Js, float[] Ks) SplitArray(params Quaternion[] vals)
|
||||
@ -174,37 +216,11 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
}
|
||||
|
||||
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 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"
|
||||
+ (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j"
|
||||
+ (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k";
|
||||
public string ToString(IFormatProvider provider) => u.ToString(provider)
|
||||
+ (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"
|
||||
+ (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j"
|
||||
+ (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k";
|
||||
public override int GetHashCode() => base.GetHashCode();
|
||||
|
||||
public object Clone() => new Quaternion(u, i, j, k);
|
||||
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public Angle GetAngle() => Mathf.ArcCos(u) * 2;
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public Float3 GetAxis()
|
||||
{
|
||||
Float3 axis = IJK;
|
||||
float mag = Magnitude;
|
||||
|
||||
if (mag < 0) return Float3.Zero;
|
||||
return axis / mag;
|
||||
}
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public Float3 GetAxis() => IJK.Normalized;
|
||||
public (Angle yaw, Angle pitch, Angle roll) ToAngles()
|
||||
{
|
||||
Quaternion doubled = this;
|
||||
@ -213,42 +229,47 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
doubled.j *= j;
|
||||
doubled.k *= k;
|
||||
|
||||
Matrix3x3 rotMatrix = new(new[,]
|
||||
Matrix3x3 rot = new(new[,]
|
||||
{
|
||||
{ doubled.u + doubled.i - doubled.j - doubled.k, 0, 0 },
|
||||
{ 2 * (i * j + u * k), 0, 0 },
|
||||
{ 2 * (i * k + u * j), 2 * (j * k + u * i), doubled.u - doubled.i - doubled.j + doubled.k }
|
||||
{ u * u + i * i - j * j - k * k, 2 * i * j + 2 * k * u, 2 * i * k - 2 * j * u },
|
||||
{ 2 * i * j - 2 * k * u, u * u - i * i + j * j - k * k, 2 * j * k + 2 * i * u },
|
||||
{ 2 * k * i + 2 * j * u, 2 * k * j - 2 * i * u, u * u - i * i - j * j + k * k }
|
||||
});
|
||||
|
||||
Angle yaw, pitch, roll;
|
||||
|
||||
float r3c1Abs = Mathf.Absolute(rotMatrix.r3c1);
|
||||
if (r3c1Abs >= 1)
|
||||
float absr3c1 = Mathf.Absolute(rot.r3c1);
|
||||
if (absr3c1 >= 1)
|
||||
{
|
||||
rotMatrix.r1c2 = 2 * (i * j - u * k);
|
||||
rotMatrix.r1c3 = 2 * (i * k + u * j);
|
||||
|
||||
yaw = Mathf.ArcTan2(-rotMatrix.r1c2, -rotMatrix.r3c1 * rotMatrix.r1c3);
|
||||
pitch = new(-Constants.HalfPi * rotMatrix.r3c1 / r3c1Abs, Angle.Type.Radians);
|
||||
yaw = Mathf.ArcTan2(-rot.r1c2, -rot.r3c1 * rot.r1c3);
|
||||
pitch = new(-Constants.HalfPi * rot.r3c1 / absr3c1, Angle.Type.Radians);
|
||||
roll = Angle.Zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
yaw = Mathf.ArcTan2(rotMatrix.r2c1, rotMatrix.r1c1);
|
||||
pitch = Mathf.ArcSin(-rotMatrix.r3c1);
|
||||
roll = Mathf.ArcTan2(rotMatrix.r3c2, rotMatrix.r3c3);
|
||||
yaw = Mathf.ArcTan2(rot.r2c1, rot.r1c1);
|
||||
pitch = Mathf.ArcSin(-rot.r3c1);
|
||||
roll = Mathf.ArcTan2(rot.r3c2, rot.r3c3);
|
||||
}
|
||||
|
||||
return (yaw, pitch, roll);
|
||||
}
|
||||
[Obsolete("This method does not produce the correct output. Please update to a newer release.")]
|
||||
public Vector3d ToVector()
|
||||
public Float3 ToAnglesFloat3(Angle.Type type = Angle.Type.Degrees)
|
||||
{
|
||||
(Angle yaw, Angle pitch, _) = ToAngles();
|
||||
return new(yaw, pitch);
|
||||
(Angle yaw, Angle pitch, Angle roll) = ToAngles();
|
||||
return new(yaw.ValueFromType(type), pitch.ValueFromType(type), roll.ValueFromType(type));
|
||||
}
|
||||
|
||||
public Quaternion Rotate(Quaternion other) => other * this * other.Conjugate;
|
||||
public Quaternion Rotate(Quaternion other) => this * other * Conjugate;
|
||||
public Float3 Rotate(Float3 other)
|
||||
{
|
||||
const float tolerance = 0.001f;
|
||||
Quaternion res = this * other * Conjugate;
|
||||
if (Mathf.Absolute(res.u) > tolerance)
|
||||
throw new MathException("A rotated vector should never have non-zero scalar part.");
|
||||
return res.IJK;
|
||||
}
|
||||
public Vector3d Rotate(Vector3d other) => Rotate(other.ToXYZ()).ToVector();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
public IEnumerator<float> GetEnumerator()
|
||||
@ -267,15 +288,30 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
}
|
||||
public List<float> ToList() => new() { u, i, j, k };
|
||||
|
||||
private bool PrintMembers(StringBuilder builder)
|
||||
{
|
||||
builder.Append(u);
|
||||
builder.Append(i >= 0 ? " + " : " - ");
|
||||
builder.Append(Mathf.Absolute(i));
|
||||
builder.Append('i');
|
||||
builder.Append(j >= 0 ? " + " : " - ");
|
||||
builder.Append(Mathf.Absolute(j));
|
||||
builder.Append('j');
|
||||
builder.Append(k >= 0 ? " + " : " - ");
|
||||
builder.Append('k');
|
||||
builder.Append(Mathf.Absolute(k));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Quaternion operator +(Quaternion a, Quaternion b) => new(a.u + b.u, a.i + b.i, a.j + b.j, a.k + b.k);
|
||||
public static Quaternion operator -(Quaternion q) => new(q.u, q.i, q.j, q.k);
|
||||
public static Quaternion operator -(Quaternion q) => new(-q.u, -q.i, -q.j, -q.k);
|
||||
public static Quaternion operator -(Quaternion a, Quaternion b) => new(a.u - b.u, a.i - b.i, a.j - b.j, a.k - b.k);
|
||||
public static Quaternion operator *(Quaternion x, Quaternion y)
|
||||
{
|
||||
float a = x.u, b = x.i, c = x.j, d = x.k, e = y.u, f = y.i, g = y.j, h = y.k,
|
||||
u = a * e - b * f - c * g - d * h,
|
||||
i = a * f + b * e + c * h - d * g,
|
||||
j = a * g + c * e + b * h - d * f,
|
||||
j = a * g - b * h + c * e + d * f,
|
||||
k = a * h + b * g + d * e - c * f;
|
||||
return new(u, i, j, k);
|
||||
}
|
||||
@ -286,11 +322,18 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
public static Quaternion operator /(Quaternion a, float b) => new(a.u / b, a.i / b, a.j / b, a.k / b);
|
||||
public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b);
|
||||
public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b);
|
||||
public static bool operator ==(Quaternion a, Quaternion b) => a.Equals(b);
|
||||
public static bool operator !=(Quaternion a, Quaternion b) => !a.Equals(b);
|
||||
public static Quaternion operator ~(Quaternion v) => v.Conjugate;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0;
|
||||
[Obsolete("This operator is a bit ambiguous. You should instead compare " +
|
||||
nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <(Quaternion a, Quaternion b) => a.CompareTo(b) < 0;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator >=(Quaternion a, Quaternion b) => a == b || a > b;
|
||||
[Obsolete("This operator is a bit ambiguous (and misleading at times). " +
|
||||
"You should instead compare " + nameof(Magnitude) + "s directly.")]
|
||||
public static bool operator <=(Quaternion a, Quaternion b) => a == b || a < b;
|
||||
|
||||
public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0);
|
||||
@ -305,4 +348,6 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
|
||||
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);
|
||||
public static implicit operator Quaternion((float u, float i, float j, float k) val) =>
|
||||
new(val.u, val.i, val.j, val.k);
|
||||
}
|
||||
|
||||
@ -33,7 +33,7 @@ public static class Constants
|
||||
public const float Sqrt3 = 1.7320508076f;
|
||||
public const float Sqrt5 = 2.2360679775f;
|
||||
public const float Sqrt10 = 3.16227766017f;
|
||||
public const float TwelthRoot2 = 1.05946309436f;
|
||||
public const float TwelfthRoot2 = 1.05946309436f;
|
||||
|
||||
public const float Cos0Deg = 1;
|
||||
public const float Cos30Deg = Sqrt3 / 2;
|
||||
@ -85,7 +85,7 @@ public static class Constants
|
||||
public const float ConnectiveConstant = 1.847759065f;
|
||||
public const float DeVicciTesseractConstant = 1.0074347568f;
|
||||
public const float EmbreeTrefethenConstant = 0.70258f;
|
||||
public const float EulerMascheroniConstant = 0.5772156649f;
|
||||
public const float EulerMascheroniConstant = EulerConstant;
|
||||
public const float ErdosBorweinConstant = 1.6066951524f;
|
||||
public const float ErdosTenenbaumFordConstant = 0.8607133205f;
|
||||
public const float FeigenbaumConstant1 = 4.6692016091f;
|
||||
@ -108,7 +108,7 @@ public static class Constants
|
||||
public const float LandauConstant = (0.5f + 0.54326f) / 2;
|
||||
public const float LandauThirdConstant = (0.5f + 0.7853f) / 2;
|
||||
public const float LandauRamanujanConstant = 0.7642236535f;
|
||||
public const float LiebSquareIceConstant = 8 / (3 * Sqrt3);
|
||||
public const float LiebSquareIceConstant = 8 * Sqrt3 / 9;
|
||||
public const float LemniscateConstant = 2.6220575542f;
|
||||
public const float LevyConstant1 = Pi * Pi / (12 * Ln2);
|
||||
public const float LevyConstant2 = 3.2758229187f;
|
||||
@ -141,8 +141,8 @@ public static class Constants
|
||||
public const float FirstNielsenRamanujanConstant = Pi * Pi / 12;
|
||||
public const float SecondDuBoisRaymondConstant = (E * E - 7) / 2;
|
||||
public const float SecondFavardConstant = 1.2337005501f;
|
||||
public const float SecondHermiteConstant = 2 / Sqrt3;
|
||||
public const float UniversalHyperbolicConstant = 2.2955871493f;
|
||||
public const float SecondHermiteConstant = 2 * Sqrt3 / 9;
|
||||
public const float UniversalParabolicConstant = 2.2955871493f;
|
||||
|
||||
public const float DottieNumber = 0.7390851332f;
|
||||
public const float FractalDimensionOfTheApollonianPackingOfCircles = 1.305688f;
|
||||
@ -152,5 +152,5 @@ public static class Constants
|
||||
public const float PlasticNumber = 1.3247179572f;
|
||||
public const float LaplaceLimit = 0.6627434193f;
|
||||
public const float LogarithmicCapacityOfTheUnitDisk = 0.5901702995f;
|
||||
public const float RegularPaperfoldingSequence = 0.8507361882f;
|
||||
public const float RegularPaperfoldingConstant = 0.8507361882f;
|
||||
}
|
||||
|
||||
4
Nerd_STF/Miscellaneous/AssemblyInfo.cs
Normal file
4
Nerd_STF/Miscellaneous/AssemblyInfo.cs
Normal file
@ -0,0 +1,4 @@
|
||||
using System.Reflection;
|
||||
|
||||
// Includes assembly configuration that isn't automatically handled by the compiler.
|
||||
// So far, there is none. There may be some in the future. We will see.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user