Released v2.3.2

This commit is contained in:
That_One_Nerd 2023-03-09 16:44:23 -05:00
parent fe83380366
commit 6d44cbe438
101 changed files with 3124 additions and 1160 deletions

3
.gitignore vendored
View File

@ -1,5 +1,7 @@
# Useless Visual Studio stuff # Useless Visual Studio stuff
.vs/
/Nerd_STF/.vs/ /Nerd_STF/.vs/
/Nerd_STF/Nerd_STF.csproj.user
*.sln *.sln
# Build Stuff # Build Stuff
@ -14,6 +16,7 @@
# Nuget # Nuget
/Nerd_STF/LICENSE /Nerd_STF/LICENSE
*.nupkg *.nupkg
*.snupkg
# Personal # Personal
/Nerd_STF/TODO.md /Nerd_STF/TODO.md

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,4 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
[Obsolete("The Polygon struct is a garbage fire, and will be fixed in v2.4.0", false)] [Obsolete("The Polygon struct is a garbage fire, and will be fixed in v2.4.0", false)]

View File

@ -1,6 +1,4 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class DisconnectedLinesException : Nerd_STFException public class DisconnectedLinesException : Nerd_STFException

View File

@ -1,11 +1,9 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class InvalidSizeException : Nerd_STFException 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) : base(message) { }
public InvalidSizeException(string message, Exception inner) : base(message, inner) { } public InvalidSizeException(string message, Exception inner) : base(message, inner) { }
protected InvalidSizeException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected InvalidSizeException(SerializationInfo info, StreamingContext context) : base(info, context) { }

View File

@ -1,11 +1,9 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class MathException : Nerd_STFException 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) : base(message) { }
public MathException(string message, Exception inner) : base(message, inner) { } public MathException(string message, Exception inner) : base(message, inner) { }
protected MathException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected MathException(SerializationInfo info, StreamingContext context) : base(info, context) { }

View File

@ -1,11 +1,11 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class Nerd_STFException : Exception 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) : base(message) { }
public Nerd_STFException(string message, Exception inner) : base(message, inner) { } public Nerd_STFException(string message, Exception inner) : base(message, inner) { }
protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { }

View File

@ -1,9 +1,7 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class NoInverseException : Exception public class NoInverseException : Nerd_STFException
{ {
public Matrix? Matrix; public Matrix? Matrix;

View File

@ -1,11 +1,9 @@
using System.Runtime.Serialization; namespace Nerd_STF.Exceptions;
namespace Nerd_STF.Exceptions;
[Serializable] [Serializable]
public class UndefinedException : MathException 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) : base(message) { }
public UndefinedException(string message, Exception inner) : base(message, inner) { } public UndefinedException(string message, Exception inner) : base(message, inner) { }
protected UndefinedException(SerializationInfo info, StreamingContext context) : base(info, context) { } protected UndefinedException(SerializationInfo info, StreamingContext context) : base(info, context) { }

View File

@ -2,6 +2,8 @@
public static class ConversionExtension 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> public static Dictionary<TKey, TValue> ToDictionary<TKey, TValue>
(this IEnumerable<KeyValuePair<TKey, TValue>> pairs) (this IEnumerable<KeyValuePair<TKey, TValue>> pairs)
where TKey : notnull where TKey : notnull
@ -12,6 +14,6 @@ public static class ConversionExtension
} }
public static Fill<T> ToFill<T>(this T[] arr) => i => arr[i]; 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 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]; public static Fill2D<T> ToFill2D<T>(this T[,] arr) => (x, y) => arr[x, y];
} }

View File

@ -1,4 +1,6 @@
namespace Nerd_STF; 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); 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); public delegate void Foreach<T>(T item);

View 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);
}

View 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> { }

View 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> { }

View 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; }
}

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Graphics; namespace Nerd_STF.Graphics;
public struct CMYKA : IColorFloat, 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 Black => new(0, 0, 0, 1);
public static CMYKA Blue => new(1, 1, 0, 0); public static CMYKA Blue => new(1, 1, 0, 0);
@ -103,6 +105,28 @@ public struct CMYKA : IColorFloat, 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) public static CMYKA Average(params CMYKA[] vals)
{ {
@ -111,16 +135,12 @@ public struct CMYKA : IColorFloat, IEquatable<CMYKA>
return val / vals.Length; 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) => public static CMYKA Clamp(CMYKA val, CMYKA min, CMYKA max) =>
new(Mathf.Clamp(val.C, min.C, max.C), new(Mathf.Clamp(val.C, min.C, max.C),
Mathf.Clamp(val.M, min.M, max.M), Mathf.Clamp(val.M, min.M, max.M),
Mathf.Clamp(val.Y, min.Y, max.Y), Mathf.Clamp(val.Y, min.Y, max.Y),
Mathf.Clamp(val.K, min.K, max.K), Mathf.Clamp(val.K, min.K, max.K),
Mathf.Clamp(val.A, min.A, max.A)); 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) => 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), 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)); Mathf.Lerp(a.K, b.K, t, clamp), Mathf.Lerp(a.A, b.A, t, clamp));
@ -136,18 +156,6 @@ public struct CMYKA : IColorFloat, IEquatable<CMYKA>
CMYKA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; CMYKA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
return Average(valA, valB); 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) public static (float[] Cs, float[] Ms, float[] Ys, float[] Ks, float[] As) SplitArray(params CMYKA[] vals)
{ {
@ -165,33 +173,10 @@ public struct CMYKA : IColorFloat, IEquatable<CMYKA>
return (Cs, Ms, Ys, Ks, As); return (Cs, Ms, Ys, Ks, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKA()); 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 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; && Y == col.Y && K == col.K && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj) public override int GetHashCode() => base.GetHashCode();
{
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(CMYKA)) return Equals((CMYKA)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode() ^ K.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider)
+ " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider)
+ " A: " + A.ToString(provider);
public string ToString(string? provider) => "C: " + C.ToString(provider) + " M: " + M.ToString(provider)
+ " Y: " + Y.ToString(provider) + " K: " + K.ToString(provider)
+ " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() public RGBA ToRGBA()
{ {
@ -224,7 +209,20 @@ public struct CMYKA : IColorFloat, IEquatable<CMYKA>
yield return A; 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 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); public static CMYKA operator -(CMYKA c) => new(1 - c.C, 1 - c.M, 1 - c.Y, 1 - c.K, c.A != 1 ? 1 - c.A : 1);
@ -233,25 +231,23 @@ public struct CMYKA : IColorFloat, IEquatable<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, 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, 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 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, 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, RGBA b) => a.Equals(b);
public static bool operator !=(CMYKA a, RGBAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(CMYKA a, RGBA b) => a.Equals(b);
public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(CMYKA a, CMYKAByte b) => a.Equals(b);
public static bool operator !=(CMYKA a, CMYKAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(CMYKA a, CMYKAByte b) => a.Equals(b);
public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(CMYKA a, HSVAByte b) => a.Equals(b);
public static bool operator !=(CMYKA a, HSVAByte b) => !a.Equals((IColorByte?)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 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(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(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(CMYKAByte val) => val.ToCMYKA();
public static implicit operator CMYKA(HSVAByte 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); public static implicit operator CMYKA(Fill<float> val) => new(val);
} }

View File

@ -1,21 +1,50 @@
namespace Nerd_STF.Graphics; 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 CMYKAByte Black => new(0, 0, 0, 255);
public static CMYKA Blue => new(255, 255, 0, 0); public static CMYKAByte Blue => new(255, 255, 0, 0);
public static CMYKA Clear => new(0, 0, 0, 0, 0); public static CMYKAByte Clear => new(0, 0, 0, 0, 0);
public static CMYKA Cyan => new(255, 0, 0, 0); public static CMYKAByte Cyan => new(255, 0, 0, 0);
public static CMYKA Gray => new(0, 0, 0, 127); public static CMYKAByte Gray => new(0, 0, 0, 127);
public static CMYKA Green => new(255, 0, 255, 0); public static CMYKAByte Green => new(255, 0, 255, 0);
public static CMYKA Magenta => new(0, 255, 0, 0); public static CMYKAByte Magenta => new(0, 255, 0, 0);
public static CMYKA Orange => new(0, 127, 255, 0); public static CMYKAByte Orange => new(0, 127, 255, 0);
public static CMYKA Purple => new(127, 255, 0, 0); public static CMYKAByte Purple => new(127, 255, 0, 0);
public static CMYKA Red => new(0, 255, 255, 0); public static CMYKAByte Red => new(0, 255, 255, 0);
public static CMYKA White => new(0, 0, 0, 0); public static CMYKAByte White => new(0, 0, 0, 0);
public static CMYKA Yellow => new(0, 0, 255, 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 HasCyan => C > 0;
public bool HasMagenta => M > 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) : this(c, m, y, k, 255) { }
public CMYKAByte(int c, int m, int y, int k, int a) public CMYKAByte(int c, int m, int y, int k, int a)
{ {
C = (byte)Mathf.Clamp(c, 0, 255); p_c = (byte)Mathf.Clamp(c, 0, 255);
M = (byte)Mathf.Clamp(m, 0, 255); p_m = (byte)Mathf.Clamp(m, 0, 255);
Y = (byte)Mathf.Clamp(y, 0, 255); p_y = (byte)Mathf.Clamp(y, 0, 255);
K = (byte)Mathf.Clamp(k, 0, 255); p_k = (byte)Mathf.Clamp(k, 0, 255);
A = (byte)Mathf.Clamp(a, 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<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 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 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) 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)]; CMYKAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
return Average(valA, valB); 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) 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]; As = new byte[vals.Length];
for (int i = 0; i < vals.Length; i++) for (int i = 0; i < vals.Length; i++)
{ {
Cs[i] = vals[i].C; Cs[i] = vals[i].p_c;
Ms[i] = vals[i].M; Ms[i] = vals[i].p_m;
Ys[i] = vals[i].Y; Ys[i] = vals[i].p_y;
Ks[i] = vals[i].K; Ks[i] = vals[i].p_k;
As[i] = vals[i].A; As[i] = vals[i].p_a;
} }
return (Cs, Ms, Ys, Ks, As); return (Cs, Ms, Ys, Ks, As);
} }
@ -143,34 +184,10 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
return (Cs, Ms, Ys, Ks, As); return (Cs, Ms, Ys, Ks, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToCMYKAByte());
public bool Equals(IColorByte? col) => col != null && Equals(col.ToCMYKAByte());
public bool Equals(CMYKAByte col) => A == 0 && col.A == 0 || K == 1 && col.K == 255 || C == col.C && M == col.M 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; && Y == col.Y && K == col.K && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj) public bool Equals(IColor? col) => col != null && Equals(col.ToCMYKAByte());
{ public override int GetHashCode() => base.GetHashCode();
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(CMYKAByte)) return Equals((CMYKAByte)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => C.GetHashCode() ^ M.GetHashCode() ^ Y.GetHashCode()
^ K.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "C: " + C.ToString(provider)
+ " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider)
+ " K: " + K.ToString(provider) + " A: " + A.ToString(provider);
public string ToString(string? provider) => "C: " + C.ToString(provider)
+ " M: " + M.ToString(provider) + " Y: " + Y.ToString(provider)
+ " K: " + K.ToString(provider) + " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() => ToCMYKA().ToRGBA(); public RGBA ToRGBA() => ToCMYKA().ToRGBA();
public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f); public CMYKA ToCMYKA() => new(C / 255f, M / 255f, Y / 255f, K / 255f, A / 255f);
@ -180,25 +197,45 @@ public struct CMYKAByte : IColorByte, IEquatable<CMYKAByte>
public CMYKAByte ToCMYKAByte() => this; public CMYKAByte ToCMYKAByte() => this;
public HSVAByte ToHSVAByte() => ToCMYKA().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() public Fill<byte> ToFill()
{
CMYKAByte @this = this;
return i => (byte)@this[i];
}
public Fill<int> ToFillInt()
{ {
CMYKAByte @this = this; CMYKAByte @this = this;
return i => @this[i]; 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<byte> GetEnumerator() public IEnumerator<byte> GetEnumerator()
{ {
yield return C; yield return p_c;
yield return M; yield return p_m;
yield return Y; yield return p_y;
yield return K; yield return p_k;
yield return A; 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) => 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); 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) => public static CMYKAByte operator /(CMYKAByte a, int b) =>
new(a.C / b, a.M / b, a.Y / b, a.K / b, a.A / 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 CMYKAByte operator /(CMYKAByte a, float b) => (a.ToCMYKA() / b).ToCMYKAByte();
public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals((IColorFloat?)b); public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals(b);
public static bool operator !=(CMYKAByte a, RGBA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(CMYKAByte a, CMYKA b) => a.Equals(b);
public static bool operator ==(CMYKAByte a, CMYKA b) => a.Equals((IColorFloat?)b); public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals(b);
public static bool operator !=(CMYKAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(CMYKAByte a, HSVA b) => a.Equals(b);
public static bool operator ==(CMYKAByte a, HSVA b) => a.Equals((IColorFloat?)b); public static bool operator ==(CMYKAByte a, RGBA b) => a.Equals(b);
public static bool operator !=(CMYKAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(CMYKAByte a, RGBA 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 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, 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, 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 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(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(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(CMYKA val) => val.ToCMYKAByte();
public static implicit operator CMYKAByte(HSVAByte 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<byte> val) => new(val);
public static implicit operator CMYKAByte(Fill<int> val) => new(val); public static implicit operator CMYKAByte(Fill<int> val) => new(val);
} }

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Graphics; namespace Nerd_STF.Graphics;
public struct HSVA : IColorFloat, 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 Black => new(Angle.Zero, 0, 0);
public static HSVA Blue => new(new Angle(240), 1, 1); public static HSVA Blue => new(new Angle(240), 1, 1);
@ -74,25 +76,47 @@ public struct HSVA : IColorFloat, IEquatable<HSVA>
switch (index) switch (index)
{ {
case 0: case 0:
H = new(Mathf.Clamp(value, 0, 1), Angle.Type.Normalized); H = new(value, Angle.Type.Normalized);
break; break;
case 1: case 1:
S = Mathf.Clamp(value, 0, 1); S = value;
break; break;
case 2: case 2:
V = Mathf.Clamp(value, 0, 1); V = value;
break; break;
case 3: case 3:
A = Mathf.Clamp(value, 0, 1); A = value;
break; break;
default: throw new IndexOutOfRangeException(nameof(index)); 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) public static HSVA Average(params HSVA[] vals)
{ {
@ -100,15 +124,11 @@ public struct HSVA : IColorFloat, IEquatable<HSVA>
for (int i = 0; i < vals.Length; i++) val += vals[i]; for (int i = 0; i < vals.Length; i++) val += vals[i];
return val / vals.Length; 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) => public static HSVA Clamp(HSVA val, HSVA min, HSVA max) =>
new(Angle.Clamp(val.H, min.H, max.H), new(Angle.Clamp(val.H, min.H, max.H),
Mathf.Clamp(val.S, min.S, max.S), Mathf.Clamp(val.S, min.S, max.S),
Mathf.Clamp(val.V, min.V, max.V), Mathf.Clamp(val.V, min.V, max.V),
Mathf.Clamp(val.A, min.A, max.A)); 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) => 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), 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)); Mathf.Lerp(a.A, b.A, t, clamp));
@ -118,18 +138,6 @@ public struct HSVA : IColorFloat, IEquatable<HSVA>
HSVA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; HSVA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
return Average(valA, valB); 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) public static (Angle[] Hs, float[] Ss, float[] Vs, float[] As) SplitArray(params HSVA[] vals)
{ {
@ -159,31 +167,10 @@ public struct HSVA : IColorFloat, IEquatable<HSVA>
return (Hs, Ss, Vs, As); return (Hs, Ss, Vs, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVA()); 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 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; || H == col.H && S == col.S && V == col.V && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj) public override int GetHashCode() => base.GetHashCode();
{
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(HSVA)) return Equals((HSVA)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() public RGBA ToRGBA()
{ {
@ -222,32 +209,41 @@ public struct HSVA : IColorFloat, IEquatable<HSVA>
yield return A; 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 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 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, 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 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, 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, RGBA b) => a.Equals(b);
public static bool operator !=(HSVA a, HSVA b) => !a.Equals(b); public static bool operator !=(HSVA a, RGBA b) => a.Equals(b);
public static bool operator ==(HSVA a, RGBAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals(b);
public static bool operator !=(HSVA a, RGBAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(HSVA a, CMYKAByte b) => a.Equals(b);
public static bool operator ==(HSVA a, CMYKAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(HSVA a, HSVAByte b) => a.Equals(b);
public static bool operator !=(HSVA a, CMYKAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(HSVA a, HSVAByte b) => a.Equals(b);
public static bool operator ==(HSVA a, HSVAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(HSVA a, RGBAByte b) => a.Equals(b);
public static bool operator !=(HSVA a, HSVAByte b) => !a.Equals((IColorByte?)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(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 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(CMYKA val) => val.ToHSVA();
public static implicit operator HSVA(RGBA 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(CMYKAByte val) => val.ToHSVA();
public static implicit operator HSVA(HSVAByte 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); public static implicit operator HSVA(Fill<float> val) => new(val);
} }

View File

@ -1,21 +1,44 @@
namespace Nerd_STF.Graphics; 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 HSVAByte Black => new(Angle.Zero, 0, 0);
public static HSVA Blue => new(new Angle(240), 255, 255); public static HSVAByte Blue => new(new Angle(240), 255, 255);
public static HSVA Clear => new(Angle.Zero, 0, 0, 0); public static HSVAByte Clear => new(Angle.Zero, 0, 0, 0);
public static HSVA Cyan => new(new Angle(180), 255, 255); public static HSVAByte Cyan => new(new Angle(180), 255, 255);
public static HSVA Gray => new(Angle.Zero, 0, 127); public static HSVAByte Gray => new(Angle.Zero, 0, 127);
public static HSVA Green => new(new Angle(120), 255, 255); public static HSVAByte Green => new(new Angle(120), 255, 255);
public static HSVA Magenta => new(new Angle(300), 255, 255); public static HSVAByte Magenta => new(new Angle(300), 255, 255);
public static HSVA Orange => new(new Angle(30), 255, 255); public static HSVAByte Orange => new(new Angle(30), 255, 255);
public static HSVA Purple => new(new Angle(270), 255, 255); public static HSVAByte Purple => new(new Angle(270), 255, 255);
public static HSVA Red => new(Angle.Zero, 255, 255); public static HSVAByte Red => new(Angle.Zero, 255, 255);
public static HSVA White => new(Angle.Zero, 0, 255); public static HSVAByte White => new(Angle.Zero, 0, 255);
public static HSVA Yellow => new(new Angle(60), 255, 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 HasColor => S != 0 && V != 0;
public bool IsOpaque => A == 255; 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) : this(h, s, v, 255) { }
public HSVAByte(int h, int s, int v, int a) public HSVAByte(int h, int s, int v, int a)
{ {
H = (byte)Mathf.Clamp(h, 0, 255); p_h = (byte)Mathf.Clamp(h, 0, 255);
S = (byte)Mathf.Clamp(s, 0, 255); p_s = (byte)Mathf.Clamp(s, 0, 255);
V = (byte)Mathf.Clamp(v, 0, 255); p_v = (byte)Mathf.Clamp(v, 0, 255);
A = (byte)Mathf.Clamp(a, 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) : 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(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<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 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 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) 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.S, min.S, max.S),
Mathf.Clamp(val.V, min.V, max.V), Mathf.Clamp(val.V, min.V, max.V),
Mathf.Clamp(val.A, min.A, max.A)); 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), 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)); Mathf.Lerp(a.A, b.A, t, clamp));
public static HSVAByte Median(params HSVAByte[] vals) 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)]; HSVAByte valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
return Average(valA, valB); 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) 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]; Vs = new byte[vals.Length], As = new byte[vals.Length];
for (int i = 0; i < vals.Length; i++) for (int i = 0; i < vals.Length; i++)
{ {
Hs[i] = vals[i].H; Hs[i] = vals[i].p_h;
Ss[i] = vals[i].S; Ss[i] = vals[i].p_s;
Vs[i] = vals[i].V; Vs[i] = vals[i].p_v;
As[i] = vals[i].A; As[i] = vals[i].p_a;
} }
return (Hs, Ss, Vs, As); return (Hs, Ss, Vs, As);
} }
@ -130,31 +165,10 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
return (Hs, Ss, Vs, As); return (Hs, Ss, Vs, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToHSVAByte()); 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 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; || H == col.H && S == col.S && V == col.V && A == col.A;
public override bool Equals([NotNullWhen(true)] object? obj) public override int GetHashCode() => base.GetHashCode();
{
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(HSVAByte)) return Equals((HSVAByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => H.GetHashCode() ^ S.GetHashCode() ^ V.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
public string ToString(string? provider) => "H: " + H.ToString(provider) + " S: " + S.ToString(provider)
+ " V: " + V.ToString(provider) + " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() => ToHSVA().ToRGBA(); public RGBA ToRGBA() => ToHSVA().ToRGBA();
public CMYKA ToCMYKA() => ToHSVA().ToCMYKA(); public CMYKA ToCMYKA() => ToHSVA().ToCMYKA();
@ -164,24 +178,42 @@ public struct HSVAByte : IColorByte, IEquatable<HSVAByte>
public CMYKAByte ToCMYKAByte() => ToHSVA().ToCMYKAByte(); public CMYKAByte ToCMYKAByte() => ToHSVA().ToCMYKAByte();
public HSVAByte ToHSVAByte() => this; 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() public Fill<byte> ToFill()
{
HSVAByte @this = this;
return i => (byte)@this[i];
}
public Fill<int> ToFillInt()
{ {
HSVAByte @this = this; HSVAByte @this = this;
return i => @this[i]; 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<byte> GetEnumerator() public IEnumerator<byte> GetEnumerator()
{ {
yield return H; yield return p_h;
yield return S; yield return p_s;
yield return V; yield return p_v;
yield return A; 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 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); 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, 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, 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 HSVAByte operator /(HSVAByte a, float b) => (a.ToHSVA() * b).ToHSVAByte();
public static bool operator ==(HSVAByte a, RGBA b) => a.Equals((IColorFloat?)b); public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals(b);
public static bool operator !=(HSVAByte a, RGBA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(HSVAByte a, CMYKA b) => a.Equals(b);
public static bool operator ==(HSVAByte a, CMYKA b) => a.Equals((IColorFloat?)b); public static bool operator ==(HSVAByte a, HSVA b) => a.Equals(b);
public static bool operator !=(HSVAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(HSVAByte a, HSVA b) => a.Equals(b);
public static bool operator ==(HSVAByte a, HSVA b) => a.Equals((IColorFloat?)b); public static bool operator ==(HSVAByte a, RGBA b) => a.Equals(b);
public static bool operator !=(HSVAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(HSVAByte a, RGBA 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 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, 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, RGBAByte b) => a.Equals(b);
public static bool operator !=(HSVAByte a, HSVAByte 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(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); public static implicit operator HSVAByte(Int4 val) => new(val.x, val.y, val.z, val.w);

View File

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

View File

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

View File

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

View File

@ -1,9 +1,9 @@
namespace Nerd_STF.Graphics; 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 IColor[,] Pixels { get; private set; }
public Int2 Size { get; init; } public Int2 Size { get; private set; }
public Image(int width, int height) public Image(int width, int height)
{ {
@ -58,7 +58,7 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
public object Clone() => new Image(Size, Pixels); 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) public override bool Equals([NotNullWhen(true)] object? obj)
{ {
if (obj == null) return base.Equals(obj); if (obj == null) return base.Equals(obj);
@ -110,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++) for (int y = 0; y < Size.y; y++) for (int x = 0; x < Size.x; x++)
{ {
HSVA col = Pixels[x, y].ToHSVA(); HSVA col = Pixels[x, y].ToHSVA();
col.S = (set ? 0 : col.S) * value; col.S = (set ? 1 : col.S) * value;
Pixels[x, y] = col; Pixels[x, y] = col;
} }
} }
@ -133,7 +133,8 @@ public struct Image : ICloneable, IEnumerable, IEquatable<Image>
RGBA col = Pixels[Mathf.Floor(f.x * Size.x), Mathf.Floor(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; img[x, y] = col;
} }
this = img; Pixels = img.Pixels;
Size = img.Size;
} }
public IColor[] ToArray() public IColor[] ToArray()

View File

@ -1,4 +1,6 @@
namespace Nerd_STF.Graphics; using Nerd_STF.Graphics.Abstract;
namespace Nerd_STF.Graphics;
public struct Material : ICloneable, IEquatable<Material> public struct Material : ICloneable, IEquatable<Material>
{ {

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Graphics; namespace Nerd_STF.Graphics;
public struct RGBA : IColorFloat, 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 Black => new(0, 0, 0);
public static RGBA Blue => new(0, 0, 1); public static RGBA Blue => new(0, 0, 1);
@ -91,6 +93,28 @@ public struct RGBA : IColorFloat, 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) public static RGBA Average(params RGBA[] vals)
{ {
@ -98,15 +122,11 @@ public struct RGBA : IColorFloat, IEquatable<RGBA>
for (int i = 0; i < vals.Length; i++) val += vals[i]; for (int i = 0; i < vals.Length; i++) val += vals[i];
return val / vals.Length; 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) => public static RGBA Clamp(RGBA val, RGBA min, RGBA max) =>
new(Mathf.Clamp(val.R, min.R, max.R), new(Mathf.Clamp(val.R, min.R, max.R),
Mathf.Clamp(val.G, min.G, max.G), Mathf.Clamp(val.G, min.G, max.G),
Mathf.Clamp(val.B, min.B, max.B), Mathf.Clamp(val.B, min.B, max.B),
Mathf.Clamp(val.A, min.A, max.A)); 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) => 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), 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)); Mathf.Lerp(a.A, b.A, t, clamp));
@ -122,18 +142,6 @@ public struct RGBA : IColorFloat, IEquatable<RGBA>
RGBA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)]; RGBA valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
return Average(valA, valB); 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) public static (float[] Rs, float[] Gs, float[] Bs, float[] As) SplitArray(params RGBA[] vals)
{ {
@ -149,30 +157,9 @@ public struct RGBA : IColorFloat, IEquatable<RGBA>
return (Rs, Gs, Bs, As); return (Rs, Gs, Bs, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBA()); 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 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) public override int GetHashCode() => base.GetHashCode();
{
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(RGBA)) return Equals((RGBA)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBAByte)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() => this; public RGBA ToRGBA() => this;
public CMYKA ToCMYKA() public CMYKA ToCMYKA()
@ -223,10 +210,21 @@ public struct RGBA : IColorFloat, IEquatable<RGBA>
yield return A; yield return A;
} }
public object Clone() => new RGBA(R, G, B, A);
public Vector3d ToVector() => ((Float3)this).ToVector(); 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 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 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); public static RGBA operator -(RGBA a, RGBA b) => new(a.R - b.R, a.G - b.G, a.B - b.B, a.A - b.A);
@ -234,25 +232,23 @@ public struct RGBA : IColorFloat, IEquatable<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, 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, 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 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, 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, 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, CMYKAByte b) => a.Equals(b);
public static bool operator !=(RGBA a, RGBAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(RGBA a, CMYKAByte b) => a.Equals(b);
public static bool operator ==(RGBA a, CMYKAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(RGBA a, HSVAByte b) => a.Equals(b);
public static bool operator !=(RGBA a, CMYKAByte b) => !a.Equals((IColorByte?)b); public static bool operator !=(RGBA a, HSVAByte b) => a.Equals(b);
public static bool operator ==(RGBA a, HSVAByte b) => a.Equals((IColorByte?)b); public static bool operator ==(RGBA a, RGBAByte b) => a.Equals(b);
public static bool operator !=(RGBA a, HSVAByte b) => !a.Equals((IColorByte?)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(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(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(CMYKA val) => val.ToRGBA();
public static implicit operator RGBA(HSVA 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(CMYKAByte val) => val.ToRGBA();
public static implicit operator RGBA(HSVAByte 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); public static implicit operator RGBA(Fill<float> val) => new(val);
} }

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Graphics; 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 Black => new(0, 0, 0);
public static RGBAByte Blue => new(0, 0, 255); 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 White => new(255, 255, 255);
public static RGBAByte Yellow => new(255, 255, 0); 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 HasBlue => B > 0;
public bool HasGreen => G > 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<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 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 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) 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.G, min.G, max.G),
Mathf.Clamp(val.B, min.B, max.B), Mathf.Clamp(val.B, min.B, max.B),
Mathf.Clamp(val.A, min.A, max.A)); 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), 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)); Mathf.Lerp(a.A, b.A, t, clamp));
public static RGBAByte LerpSquared(RGBAByte a, RGBAByte b, byte t, bool clamp = true) => 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]; Bs = new byte[vals.Length], As = new byte[vals.Length];
for (int i = 0; i < vals.Length; i++) for (int i = 0; i < vals.Length; i++)
{ {
Rs[i] = vals[i].R; Rs[i] = vals[i].p_r;
Gs[i] = vals[i].G; Gs[i] = vals[i].p_g;
Bs[i] = vals[i].B; Bs[i] = vals[i].p_b;
As[i] = vals[i].A; As[i] = vals[i].p_a;
} }
return (Rs, Gs, Bs, As); return (Rs, Gs, Bs, As);
} }
@ -132,30 +177,9 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
return (Rs, Gs, Bs, As); return (Rs, Gs, Bs, As);
} }
public bool Equals(IColorFloat? col) => col != null && Equals(col.ToRGBAByte()); 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 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) public override int GetHashCode() => base.GetHashCode();
{
if (obj == null) return base.Equals(obj);
Type t = obj.GetType();
if (t == typeof(RGBAByte)) return Equals((RGBAByte)obj);
else if (t == typeof(CMYKA)) return Equals((IColorFloat)obj);
else if (t == typeof(HSVA)) return Equals((IColorFloat)obj);
else if (t == typeof(IColorFloat)) return Equals((IColorFloat)obj);
else if (t == typeof(RGBA)) return Equals((IColorByte)obj);
else if (t == typeof(CMYKAByte)) return Equals((IColorByte)obj);
else if (t == typeof(HSVAByte)) return Equals((IColorByte)obj);
else if (t == typeof(IColorByte)) return Equals((IColorByte)obj);
return base.Equals(obj);
}
public override int GetHashCode() => R.GetHashCode() ^ G.GetHashCode() ^ B.GetHashCode() ^ A.GetHashCode();
public string ToString(IFormatProvider provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
public string ToString(string? provider) => "R: " + R.ToString(provider) + " G: " + G.ToString(provider) +
" B: " + B.ToString(provider) + " A: " + A.ToString(provider);
public override string ToString() => ToString((string?)null);
public RGBA ToRGBA() => new(R / 255f, G / 255f, B / 255f, A / 255f); public RGBA ToRGBA() => new(R / 255f, G / 255f, B / 255f, A / 255f);
public CMYKA ToCMYKA() => ToRGBA().ToCMYKA(); public CMYKA ToCMYKA() => ToRGBA().ToCMYKA();
@ -165,27 +189,45 @@ public struct RGBAByte : IColorByte, IEquatable<RGBAByte>
public CMYKAByte ToCMYKAByte() => ToRGBA().ToCMYKAByte(); public CMYKAByte ToCMYKAByte() => ToRGBA().ToCMYKAByte();
public HSVAByte ToHSVAByte() => ToRGBA().ToHSVAByte(); 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() 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]; 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(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<byte> GetEnumerator() public IEnumerator<byte> GetEnumerator()
{ {
yield return R; yield return p_r;
yield return G; yield return p_g;
yield return B; yield return p_b;
yield return A; yield return p_a;
} }
public object Clone() => new RGBAByte(R, G, B, A);
public Vector3d ToVector() => ((RGBA)this).ToVector(); 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 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 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); 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, 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, 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 RGBAByte operator /(RGBAByte a, float b) => (a.ToRGBA() / b).ToRGBAByte();
public static bool operator ==(RGBAByte a, RGBA b) => a.Equals((IColorFloat?)b); public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals(b);
public static bool operator !=(RGBAByte a, RGBA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(RGBAByte a, CMYKA b) => a.Equals(b);
public static bool operator ==(RGBAByte a, CMYKA b) => a.Equals((IColorFloat?)b); public static bool operator ==(RGBAByte a, HSVA b) => a.Equals(b);
public static bool operator !=(RGBAByte a, CMYKA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(RGBAByte a, HSVA b) => a.Equals(b);
public static bool operator ==(RGBAByte a, HSVA b) => a.Equals((IColorFloat?)b); public static bool operator ==(RGBAByte a, RGBA b) => a.Equals(b);
public static bool operator !=(RGBAByte a, HSVA b) => !a.Equals((IColorFloat?)b); public static bool operator !=(RGBAByte a, RGBA b) => a.Equals(b);
public static bool operator ==(RGBAByte a, RGBAByte b) => a.Equals(b);
public static bool operator !=(RGBAByte a, RGBAByte b) => !a.Equals(b);
public static bool operator ==(RGBAByte a, CMYKAByte b) => a.Equals(b); 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 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(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); public static implicit operator RGBAByte(Int4 val) => new(val.x, val.y, val.z, val.w);

View File

@ -1,6 +0,0 @@
namespace Nerd_STF;
public interface IClosest<T> where T : IEquatable<T>
{
public T ClosestTo(T item);
}

View File

@ -1,6 +0,0 @@
namespace Nerd_STF;
public interface IContainer<T> where T : IEquatable<T>
{
public bool Contains(T item);
}

View File

@ -1,6 +1,6 @@
namespace Nerd_STF; 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); public T Encapsulate(TE val);
} }

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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>;
}

View File

@ -0,0 +1,6 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IClosestTo<T> where T : IEquatable<T>
{
public T ClosestTo(T item);
}

View File

@ -0,0 +1,6 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IContains<T> where T : IEquatable<T>
{
public bool Contains(T item);
}

View 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);
}

View 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);
}

View 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>;
}

View 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);
}

View 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);
}

View File

@ -0,0 +1,3 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IIndexAll<TSub> : IIndexGet<TSub>, IIndexSet<TSub> { }

View 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; }
}

View File

@ -0,0 +1,3 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IIndexRangeAll<TSub> : IIndexRangeGet<TSub>, IIndexRangeSet<TSub> { }

View File

@ -0,0 +1,6 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IIndexRangeGet<TSub>
{
public TSub[] this[Range range] { get; }
}

View File

@ -0,0 +1,6 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface IIndexRangeSet<TSub>
{
public TSub[] this[Range range] { set; }
}

View 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; }
}

View 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>;
}

View 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; }
}

View 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> { }

View File

@ -1,11 +1,13 @@
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> where T : IMatrix<T>
{ {
public T Adjugate(); public T Adjugate();
public float Determinant(); public float Determinant();
public T Inverse(); public T? Inverse();
public T Transpose(); public T Transpose();
} }

View 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; }
}

View 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);
}

View 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);
}

View 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);
}

View 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; }
}

View 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; }
}

View 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; }
}

View 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; }
}

View 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);
}

View 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);
}

View 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; }
}

View 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; }
}

View 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);
}

View 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>
{
}

View File

@ -0,0 +1,7 @@
namespace Nerd_STF.Mathematics.Abstract;
public interface ISubdivide<T>
{
public T Subdivide();
public T Subdivide(int iterations);
}

View 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);
}

View 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);
}

View 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();
}

View File

@ -1,10 +1,13 @@
namespace Nerd_STF.Mathematics.Algebra; using System.Buffers;
public readonly struct Matrix : IMatrix<Matrix, Matrix> namespace Nerd_STF.Mathematics.Algebra;
public class Matrix : IMatrix<Matrix, Matrix>
{ {
public static Matrix Identity(Int2 size) public static Matrix Identity(Int2 size)
{ {
if (size.x != size.y) throw new InvalidSizeException("Can only create an identity matrix of a square matrix."); if (size.x != size.y) throw new InvalidSizeException("Can only create an identity matrix of a square matrix." +
" You may want to use " + nameof(IdentityIsh) + " instead.");
Matrix m = Zero(size); Matrix m = Zero(size);
for (int i = 0; i < size.x; i++) m[i, i] = 1; for (int i = 0; i < size.x; i++) m[i, i] = 1;
return m; return m;
@ -105,6 +108,51 @@ public readonly struct Matrix : IMatrix<Matrix, Matrix>
get => this[index.x, index.y]; get => this[index.x, index.y];
set => this[index.x, index.y] = value; 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 Absolute(Matrix val) => new(val.Size, (r, c) => Mathf.Absolute(val[r, c]));
public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c])); public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c]));
@ -192,10 +240,11 @@ public readonly struct Matrix : IMatrix<Matrix, Matrix>
return det; return det;
} }
public Matrix Inverse() public Matrix? Inverse()
{ {
float d = Determinant(); float d = Determinant();
if (d == 0) throw new NoInverseException(); if (d == 0) return null;
return Adjugate() / d; return Adjugate() / d;
} }
public Matrix[,] Minors() public Matrix[,] Minors()
@ -233,25 +282,18 @@ public readonly struct Matrix : IMatrix<Matrix, Matrix>
return base.Equals(obj); return base.Equals(obj);
} }
public bool Equals(Matrix other) => array == other.array; public bool Equals(Matrix? other)
{
if (other is null) return false;
return array.Equals(other.array);
}
public override int GetHashCode() => array.GetHashCode(); public override int GetHashCode() => array.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString()
public string ToString(string? provider)
{ {
string res = ""; string res = "";
for (int r = 0; r < Size.x; r++) for (int r = 0; r < Size.x; r++)
{ {
for (int c = 0; c < Size.y; c++) res += array[r, c].ToString(provider) + " "; for (int c = 0; c < Size.y; c++) res += array[r, c] + " ";
res += "\n";
}
return res;
}
public string ToString(IFormatProvider provider)
{
string res = "";
for (int r = 0; r < Size.y; r++)
{
for (int c = 0; c < Size.x; c++) res += array[r, c].ToString(provider) + " ";
res += "\n"; res += "\n";
} }
return res; return res;
@ -276,7 +318,7 @@ public readonly struct Matrix : IMatrix<Matrix, Matrix>
public List<float> ToList() => ToArray().ToList(); 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 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, 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, float b) => new(a.Size, (r, c) => a[r, c] * b);
public static Matrix operator *(Matrix a, Matrix b) public static Matrix operator *(Matrix a, Matrix b)
@ -292,7 +334,12 @@ public readonly struct Matrix : IMatrix<Matrix, Matrix>
public static Vector2d operator *(Matrix a, Vector2d b) => (Vector2d)(a * (Matrix)b); public static Vector2d operator *(Matrix a, Vector2d b) => (Vector2d)(a * (Matrix)b);
public static Vector3d operator *(Matrix a, Vector3d b) => (Vector3d)(a * (Matrix)b); public static 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, 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 Complex operator /(Matrix a, Complex b) => (Complex)(a / (Matrix)b);
public static Quaternion operator /(Matrix a, Quaternion b) => (Quaternion)(a / (Matrix)b); public static Quaternion operator /(Matrix a, Quaternion b) => (Quaternion)(a / (Matrix)b);
public static Float2 operator /(Matrix a, Float2 b) => (Float2)(a / (Matrix)b); public static Float2 operator /(Matrix a, Float2 b) => (Float2)(a / (Matrix)b);

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Mathematics.Algebra; namespace Nerd_STF.Mathematics.Algebra;
public struct Matrix2x2 : IMatrix<Matrix2x2> public record class Matrix2x2 : IStaticMatrix<Matrix2x2>
{ {
public static Matrix2x2 Identity => new(new[,] public static Matrix2x2 Identity => new(new[,]
{ {
@ -116,6 +116,48 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
get => this[index.x, index.y]; get => this[index.x, index.y];
set => this[index.x, index.y] = value; set => this[index.x, index.y] = value;
} }
public float this[Index r, Index c]
{
get
{
int row = r.IsFromEnd ? 2 - r.Value : r.Value,
col = c.IsFromEnd ? 2 - c.Value : c.Value;
return this[row, col];
}
set
{
int row = r.IsFromEnd ? 2 - r.Value : r.Value,
col = c.IsFromEnd ? 2 - c.Value : c.Value;
this[row, col] = value;
}
}
public float[,] this[Range rs, Range cs]
{
get
{
int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value,
rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value,
colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value,
colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value;
float[,] vals = new float[rowEnd - rowStart - 1, colEnd - colStart - 1];
for (int r = rowStart; r < rowEnd; r++)
for (int c = colStart; c < colEnd; c++)
vals[r, c] = this[r, c];
return vals;
}
set
{
int rowStart = rs.Start.IsFromEnd ? 2 - rs.Start.Value : rs.Start.Value,
rowEnd = rs.End.IsFromEnd ? 2 - rs.End.Value : rs.End.Value,
colStart = cs.Start.IsFromEnd ? 2 - cs.Start.Value : cs.Start.Value,
colEnd = cs.End.IsFromEnd ? 2 - cs.End.Value : cs.End.Value;
for (int r = rowStart; r < rowEnd; r++)
for (int c = colStart; c < colEnd; c++)
this[r, c] = value[r, c];
}
}
public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2),
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2)); Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2));
@ -187,10 +229,10 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
return swapped ^ SignGrid; return swapped ^ SignGrid;
} }
public float Determinant() => r1c1 * r2c2 - r1c2 * r2c1; public float Determinant() => r1c1 * r2c2 - r1c2 * r2c1;
public Matrix2x2 Inverse() public Matrix2x2? Inverse()
{ {
float d = Determinant(); float d = Determinant();
if (d == 0) throw new NoInverseException(); if (d == 0) return null;
return Transpose().Adjugate() / d; return Transpose().Adjugate() / d;
} }
public Matrix2x2 Transpose() => new(new[,] public Matrix2x2 Transpose() => new(new[,]
@ -199,22 +241,13 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
{ r1c2, r2c2 } { 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); if (other is null) return false;
return Equals((Matrix2x2)obj); return r1c1 == other.r1c1 && r1c2 == other.r1c2 && r2c1 == other.r2c1 && r2c2 == other.r2c2;
} }
public bool Equals(Matrix2x2 other) => r1c1 == other.r1c1 && r1c2 == other.r1c2 public override int GetHashCode() => base.GetHashCode();
&& r2c1 == other.r2c1 && r2c2 == other.r2c2; public override string ToString() => r1c1 + " " + r1c2 + "\n" + r2c1 + " " + r2c2;
public override int GetHashCode() => r1c1.GetHashCode() ^ r1c2.GetHashCode()
^ r2c1.GetHashCode() ^ r2c2.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(string? provider) => r1c1.ToString(provider) + " " + r1c2.ToString(provider) + "\n"
+ r2c1.ToString(provider) + " " + r2c2.ToString(provider);
public string ToString(IFormatProvider provider) => r1c1.ToString(provider) + " " + r1c2.ToString(provider) + "\n"
+ r2c1.ToString(provider) + " " + r2c2.ToString(provider);
public object Clone() => new Matrix2x2(ToArray2D());
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -252,12 +285,15 @@ public struct Matrix2x2 : IMatrix<Matrix2x2>
}); });
public static Float2 operator *(Matrix2x2 a, Float2 b) => (Matrix)a * b; 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, float b) => new(a.r1c1 / b, a.r1c2 / b, a.r2c1 / b, a.r2c2 / b);
public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b) => a * b.Inverse(); public static Matrix2x2 operator /(Matrix2x2 a, Matrix2x2 b)
{
Matrix2x2? bInv = b.Inverse();
if (bInv is null) throw new NoInverseException(b);
return a * bInv;
}
public static Float2 operator /(Matrix2x2 a, Float2 b) => (Matrix)a / b; public static Float2 operator /(Matrix2x2 a, Float2 b) => (Matrix)a / b;
public static Matrix2x2 operator ^(Matrix2x2 a, Matrix2x2 b) => // Single number multiplication. public static Matrix2x2 operator ^(Matrix2x2 a, Matrix2x2 b) => // Single number multiplication.
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2); new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r2c1 * b.r2c1, a.r2c2 * b.r2c2);
public static bool operator ==(Matrix2x2 a, Matrix2x2 b) => a.Equals(b);
public static bool operator !=(Matrix2x2 a, Matrix2x2 b) => !a.Equals(b);
public static explicit operator Matrix2x2(Matrix m) public static explicit operator Matrix2x2(Matrix m)
{ {

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Mathematics.Algebra; namespace Nerd_STF.Mathematics.Algebra;
public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2> public record class Matrix3x3 : IStaticMatrix<Matrix3x3>
{ {
public static Matrix3x3 Identity => new(new[,] public static Matrix3x3 Identity => new(new[,]
{ {
@ -180,6 +180,48 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
get => this[index.x, index.y]; get => this[index.x, index.y];
set => this[index.x, index.y] = value; 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) => public static Matrix3x3 Absolute(Matrix3x3 val) =>
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3),
@ -264,7 +306,7 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
public Matrix3x3 Adjugate() => Cofactor().Transpose(); public Matrix3x3 Adjugate() => Cofactor().Transpose();
public Matrix3x3 Cofactor() public Matrix3x3 Cofactor()
{ {
Matrix3x3 dets = new(); Matrix3x3 dets = Zero;
Matrix2x2[,] minors = Minors(); Matrix2x2[,] minors = Minors();
for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) dets[r, c] = minors[r, c].Determinant(); for (int r = 0; r < 3; r++) for (int c = 0; c < 3; c++) dets[r, c] = minors[r, c].Determinant();
return dets ^ SignGrid; return dets ^ SignGrid;
@ -275,10 +317,10 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant())
+ (r1c3 * minors[0, 2].Determinant()); + (r1c3 * minors[0, 2].Determinant());
} }
public Matrix3x3 Inverse() public Matrix3x3? Inverse()
{ {
float d = Determinant(); float d = Determinant();
if (d == 0) throw new NoInverseException(); if (d == 0) return null;
return Adjugate() / d; return Adjugate() / d;
} }
public Matrix2x2[,] Minors() => new Matrix2x2[,] public Matrix2x2[,] Minors() => new Matrix2x2[,]
@ -294,30 +336,18 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
{ r1c3, r2c3, r3c3 } { 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); if (other is null) return false;
return Equals((Matrix3x3)obj); 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) => public override int GetHashCode() => base.GetHashCode();
r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && public override string ToString() =>
r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && r1c1 + " " + r1c2 + " " + r1c3 + "\n" +
r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3; r2c1 + " " + r2c2 + " " + r2c3 + "\n" +
public override int GetHashCode() => r3c1 + " " + r3c2 + " " + r3c3;
r1c1.GetHashCode() ^ r1c2.GetHashCode() ^ r1c3.GetHashCode() ^
r2c1.GetHashCode() ^ r2c2.GetHashCode() ^ r2c3.GetHashCode() ^
r3c1.GetHashCode() ^ r3c2.GetHashCode() ^ r3c3.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(string? provider) =>
r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + "\n" +
r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + r2c3.ToString(provider) + "\n" +
r3c1.ToString(provider) + " " + r3c2.ToString(provider) + " " + r3c3.ToString(provider);
public string ToString(IFormatProvider provider) =>
r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + "\n" +
r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " + r2c3.ToString(provider) + "\n" +
r3c1.ToString(provider) + " " + r3c2.ToString(provider) + " " + r3c3.ToString(provider);
public object Clone() => new Matrix3x3(ToArray2D());
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -352,7 +382,7 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
new(a.r1c1 + b.r1c1, a.r1c2 + b.r1c2, a.r1c3 + b.r1c3, 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.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3,
a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3); a.r3c1 + b.r3c1, a.r3c2 + b.r3c2, a.r3c3 + b.r3c3);
public static Matrix3x3 operator -(Matrix3x3 m) => m.Inverse(); public static Matrix3x3? operator -(Matrix3x3 m) => m.Inverse();
public static Matrix3x3 operator -(Matrix3x3 a, Matrix3x3 b) => public static Matrix3x3 operator -(Matrix3x3 a, Matrix3x3 b) =>
new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3, 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.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3,
@ -372,14 +402,17 @@ public struct Matrix3x3 : IMatrix<Matrix3x3, Matrix2x2>
new(a.r1c1 / b, a.r1c2 / b, a.r1c3 / b, new(a.r1c1 / b, a.r1c2 / b, a.r1c3 / b,
a.r2c1 / b, a.r2c2 / b, a.r2c3 / b, a.r2c1 / b, a.r2c2 / b, a.r2c3 / b,
a.r3c1 / b, a.r3c2 / b, a.r3c3 / b); a.r3c1 / b, a.r3c2 / b, a.r3c3 / b);
public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b) => a * b.Inverse(); public static Matrix3x3 operator /(Matrix3x3 a, Matrix3x3 b)
{
Matrix3x3? bInv = b.Inverse();
if (bInv is null) throw new NoInverseException(b);
return a * bInv;
}
public static Float3 operator /(Matrix3x3 a, Float3 b) => (Matrix)a / b; public static Float3 operator /(Matrix3x3 a, Float3 b) => (Matrix)a / b;
public static Matrix3x3 operator ^(Matrix3x3 a, Matrix3x3 b) => // Single number multiplication public static Matrix3x3 operator ^(Matrix3x3 a, Matrix3x3 b) => // Single number multiplication
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3, 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.r2c1 * b.r2c1, a.r2c2 * b.r2c2, a.r2c3 * b.r2c3,
a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3); a.r3c1 * b.r3c1, a.r3c2 * b.r3c2, a.r3c3 * b.r3c3);
public static bool operator ==(Matrix3x3 a, Matrix3x3 b) => a.Equals(b);
public static bool operator !=(Matrix3x3 a, Matrix3x3 b) => !a.Equals(b);
public static explicit operator Matrix3x3(Matrix m) public static explicit operator Matrix3x3(Matrix m)
{ {

View File

@ -1,6 +1,6 @@
namespace Nerd_STF.Mathematics.Algebra; namespace Nerd_STF.Mathematics.Algebra;
public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3> public record class Matrix4x4 : IStaticMatrix<Matrix4x4>
{ {
public static Matrix4x4 Identity => new(new[,] public static Matrix4x4 Identity => new(new[,]
{ {
@ -251,6 +251,48 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
get => this[index.x, index.y]; get => this[index.x, index.y];
set => this[index.x, index.y] = value; 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) => public static Matrix4x4 Absolute(Matrix4x4 val) =>
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r1c4), new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r1c4),
@ -357,7 +399,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
public Matrix4x4 Adjugate() => Cofactor().Transpose(); public Matrix4x4 Adjugate() => Cofactor().Transpose();
public Matrix4x4 Cofactor() public Matrix4x4 Cofactor()
{ {
Matrix4x4 dets = new(); Matrix4x4 dets = Zero;
Matrix3x3[,] minors = Minors(); Matrix3x3[,] minors = Minors();
for (int r = 0; r < 4; r++) for (int c = 0; c < 4; c++) dets[r, c] = minors[r, c].Determinant(); for (int r = 0; r < 4; r++) for (int c = 0; c < 4; c++) dets[r, c] = minors[r, c].Determinant();
return dets ^ SignGrid; return dets ^ SignGrid;
@ -368,10 +410,10 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) + return (r1c1 * minors[0, 0].Determinant()) - (r1c2 * minors[0, 1].Determinant()) +
(r1c3 * minors[0, 2].Determinant()) - (r1c4 * minors[0, 3].Determinant()); (r1c3 * minors[0, 2].Determinant()) - (r1c4 * minors[0, 3].Determinant());
} }
public Matrix4x4 Inverse() public Matrix4x4? Inverse()
{ {
float d = Determinant(); float d = Determinant();
if (d == 0) throw new NoInverseException(); if (d == 0) return null;
return Adjugate() / d; return Adjugate() / d;
} }
public Matrix3x3[,] Minors() => new Matrix3x3[,] public Matrix3x3[,] Minors() => new Matrix3x3[,]
@ -409,38 +451,20 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
{ r1c4, r2c4, r3c4, r4c4 } { 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); if (other is null) return false;
return Equals((Matrix4x4)obj); 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) => public override int GetHashCode() => base.GetHashCode();
r1c1 == other.r1c1 && r1c2 == other.r1c2 && r1c3 == other.r1c3 && r1c4 == other.r1c4 && public override string ToString() =>
r2c1 == other.r2c1 && r2c2 == other.r2c2 && r2c3 == other.r2c3 && r2c4 == other.r2c4 && r1c1 + " " + r1c2 + " " + r1c3 + " " + r1c4 + "\n" +
r3c1 == other.r3c1 && r3c2 == other.r3c2 && r3c3 == other.r3c3 && r3c4 == other.r3c4 && r2c1 + " " + r2c2 + " " + r2c3 + " " + r2c4 + "\n" +
r4c1 == other.r4c1 && r4c2 == other.r4c2 && r4c3 == other.r4c3 && r4c4 == other.r4c4; r3c1 + " " + r3c2 + " " + r3c3 + " " + r3c4 + "\n" +
public override int GetHashCode() => r4c1 + " " + r4c2 + " " + r4c3 + " " + r4c4;
r1c1.GetHashCode() ^ r1c2.GetHashCode() ^ r1c3.GetHashCode() ^ r1c4.GetHashCode() ^
r2c1.GetHashCode() ^ r2c2.GetHashCode() ^ r2c3.GetHashCode() ^ r2c4.GetHashCode() ^
r3c1.GetHashCode() ^ r3c2.GetHashCode() ^ r3c3.GetHashCode() ^ r3c4.GetHashCode() ^
r4c1.GetHashCode() ^ r4c2.GetHashCode() ^ r4c3.GetHashCode() ^ r4c4.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(string? provider) =>
r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + " " +
r1c4.ToString(provider) + "\n" + r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " +
r2c3.ToString(provider) + " " + r2c4.ToString(provider) + "\n" + r3c1.ToString(provider) + " " +
r3c2.ToString(provider) + " " + r3c3.ToString(provider) + " " + r3c4.ToString(provider) + "\n" +
r4c1.ToString(provider) + " " + r4c2.ToString(provider) + " " + r4c3.ToString(provider) + " " +
r4c4.ToString(provider);
public string ToString(IFormatProvider provider) =>
r1c1.ToString(provider) + " " + r1c2.ToString(provider) + " " + r1c3.ToString(provider) + " " +
r1c4.ToString(provider) + "\n" + r2c1.ToString(provider) + " " + r2c2.ToString(provider) + " " +
r2c3.ToString(provider) + " " + r2c4.ToString(provider) + "\n" + r3c1.ToString(provider) + " " +
r3c2.ToString(provider) + " " + r3c3.ToString(provider) + " " + r3c4.ToString(provider) + "\n" +
r4c1.ToString(provider) + " " + r4c2.ToString(provider) + " " + r4c3.ToString(provider) + " " +
r4c4.ToString(provider);
public object Clone() => new Matrix4x4(ToArray2D());
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -496,7 +520,7 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
a.r2c1 + b.r2c1, a.r2c2 + b.r2c2, a.r2c3 + b.r2c3, a.r2c4 + b.r2c4, 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.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); a.r4c1 + b.r4c1, a.r4c2 + b.r4c2, a.r4c3 + b.r4c3, a.r4c4 + b.r4c4);
public static Matrix4x4 operator -(Matrix4x4 m) => m.Inverse(); public static Matrix4x4? operator -(Matrix4x4 m) => m.Inverse();
public static Matrix4x4 operator -(Matrix4x4 a, Matrix4x4 b) => public static Matrix4x4 operator -(Matrix4x4 a, Matrix4x4 b) =>
new(a.r1c1 - b.r1c1, a.r1c2 - b.r1c2, a.r1c3 - b.r1c3, a.r1c4 - b.r1c4, 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.r2c1 - b.r2c1, a.r2c2 - b.r2c2, a.r2c3 - b.r2c3, a.r2c4 - b.r2c4,
@ -524,15 +548,18 @@ public struct Matrix4x4 : IMatrix<Matrix4x4, Matrix3x3>
a.r2c1 / b, a.r2c2 / b, a.r2c3 / b, a.r2c4 / 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.r3c1 / b, a.r3c2 / b, a.r3c3 / b, a.r3c4 / b,
a.r4c1 / b, a.r4c2 / b, a.r4c3 / b, a.r4c4 / b); a.r4c1 / b, a.r4c2 / b, a.r4c3 / b, a.r4c4 / b);
public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b) => a * b.Inverse(); public static Matrix4x4 operator /(Matrix4x4 a, Matrix4x4 b)
{
Matrix4x4? bInv = b.Inverse();
if (bInv is null) throw new NoInverseException(b);
return a * bInv;
}
public static Float4 operator /(Matrix4x4 a, Float4 b) => (Matrix)a / b; public static Float4 operator /(Matrix4x4 a, Float4 b) => (Matrix)a / b;
public static Matrix4x4 operator ^(Matrix4x4 a, Matrix4x4 b) => // Single number multiplication public static Matrix4x4 operator ^(Matrix4x4 a, Matrix4x4 b) => // Single number multiplication
new(a.r1c1 * b.r1c1, a.r1c2 * b.r1c2, a.r1c3 * b.r1c3, a.r1c4 * b.r1c4, 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.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.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); a.r4c1 * b.r4c1, a.r4c2 * b.r4c2, a.r4c3 * b.r4c3, a.r4c4 * b.r4c4);
public static bool operator ==(Matrix4x4 a, Matrix4x4 b) => a.Equals(b);
public static bool operator !=(Matrix4x4 a, Matrix4x4 b) => !a.Equals(b);
public static explicit operator Matrix4x4(Matrix m) public static explicit operator Matrix4x4(Matrix m)
{ {

View File

@ -1,6 +1,11 @@
namespace Nerd_STF.Mathematics.Algebra; 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 Down => new(Angle.Down);
public static Vector2d Left => new(Angle.Left); 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 One => new(Angle.Zero);
public static Vector2d Zero => new(Angle.Zero, 0); public static Vector2d Zero => new(Angle.Zero, 0);
public float Magnitude
{
get => magnitude;
set => magnitude = value;
}
public Vector2d Inverse => new(-theta, magnitude); public Vector2d Inverse => new(-theta, magnitude);
public Vector2d Normalized => new(theta, 1); public Vector2d Normalized => new(theta, 1);
@ -86,7 +97,7 @@ public struct Vector2d : ICloneable, IComparable<Vector2d>, IEquatable<Vector2d>
return val; 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]; Angle[] rots = new Angle[vals.Length];
float[] mags = new float[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 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 bool Equals(Vector2d other) => theta == other.theta && magnitude == other.magnitude;
public override int GetHashCode() => theta.GetHashCode() ^ magnitude.GetHashCode(); public override int GetHashCode() => base.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString() => ToString(Angle.Type.Degrees);
public string ToString(Angle.Type outputType) => ToString((string?)null, outputType); public string ToString(Angle.Type outputType) =>
public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) => nameof(Vector2d) + " { Mag = " + magnitude + ", Rot = " + theta.ToString(outputType) + " }";
"Mag: " + magnitude.ToString(provider) + " Rot: " + theta.ToString(provider, outputType);
public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) =>
"Mag: " + magnitude.ToString(provider) + " Rot: " + theta.ToString(provider, outputType);
public object Clone() => new Vector2d(theta, magnitude);
public Float2 ToXYZ() => new Float2(Mathf.Cos(theta), Mathf.Sin(theta)) * magnitude; 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, 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, float b) => new(a.theta, a.magnitude / b);
public static Vector2d operator /(Vector2d a, Matrix b) => (Vector2d)((Matrix)a / 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.CompareTo(b) < 0; public static bool operator <(Vector2d a, Vector2d b) => a.CompareTo(b) < 0;
public static bool operator >=(Vector2d a, Vector2d b) => a == b || a > b; public static bool operator >=(Vector2d a, Vector2d b) => a == b || a > b;
@ -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(Matrix m) => ((Float2)m).ToVector();
public static explicit operator Vector2d(Vert val) => (Vector2d)val.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 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);
} }

View File

@ -1,6 +1,10 @@
namespace Nerd_STF.Mathematics.Algebra; 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 Back => new(Angle.Zero, Angle.Up);
public static Vector3d Down => new(Angle.Down, Angle.Zero); 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 One => new(Angle.Zero);
public static Vector3d Zero => new(Angle.Zero, 0); 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 Inverse => new(-yaw, -pitch, magnitude);
public Vector3d Normalized => new(yaw, pitch, 1); 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), public static Vector3d Absolute(Vector3d val) => new(Angle.Absolute(val.yaw), Angle.Absolute(val.pitch),
Mathf.Absolute(val.magnitude)); Mathf.Absolute(val.magnitude));
@ -123,38 +155,27 @@ public struct Vector3d : ICloneable, IComparable<Vector3d>, IEquatable<Vector3d>
return val; 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]; float[] mags = new float[vals.Length];
for (int i = 0; i < vals.Length; i++) for (int i = 0; i < vals.Length; i++)
{ {
yaws[i] = vals[i].yaw; yaws[i] = vals[i].yaw;
pitchs[i] = vals[i].pitch; pitches[i] = vals[i].pitch;
mags[i] = vals[i].magnitude; mags[i] = vals[i].magnitude;
} }
return (yaws, pitchs, mags); return (yaws, pitches, mags);
} }
public int CompareTo(Vector3d other) => magnitude.CompareTo(other.magnitude); 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 public bool Equals(Vector3d other) => yaw == other.yaw && pitch == other.pitch
&& magnitude == other.magnitude; && magnitude == other.magnitude;
public override int GetHashCode() => yaw.GetHashCode() ^ pitch.GetHashCode() ^ magnitude.GetHashCode(); public override int GetHashCode() => base.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString() => ToString(Angle.Type.Degrees);
public string ToString(Angle.Type outputType) => ToString((string?)null, outputType); public string ToString(Angle.Type outputType) =>
public string ToString(string? provider, Angle.Type outputType = Angle.Type.Degrees) => nameof(Vector3d) + " { Mag = " + magnitude + ", Yaw = " + yaw.ToString(outputType) +
"Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) + ", Pitch = " + pitch.ToString(outputType) + " }";
" Pitch: " + pitch.ToString(provider, outputType);
public string ToString(IFormatProvider provider, Angle.Type outputType = Angle.Type.Degrees) =>
"Mag: " + magnitude.ToString(provider) + " Yaw: " + yaw.ToString(provider, outputType) +
" Pitch: " + pitch.ToString(provider, outputType);
public object Clone() => new Vector3d(yaw, pitch, magnitude);
public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw), public Float3 ToXYZ() => new Float3(Mathf.Sin(pitch) * Mathf.Sin(yaw),
Mathf.Cos(yaw), Mathf.Cos(yaw),
@ -169,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, 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, float b) => new(a.yaw, a.pitch, a.magnitude / b);
public static Vector3d operator /(Vector3d a, Matrix b) => (Vector3d)((Matrix)a / 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.CompareTo(b) < 0; public static bool operator <(Vector3d a, Vector3d b) => a.CompareTo(b) < 0;
public static bool operator >=(Vector3d a, Vector3d b) => a == b || a > b; public static bool operator >=(Vector3d a, Vector3d b) => a == b || a > b;
@ -184,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(Matrix m) => ((Float3)m).ToVector();
public static explicit operator Vector3d(Vert val) => val.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(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);
} }

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Mathematics; 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 Down => new(270);
public static Angle Left => new(180); public static Angle Left => new(180);
@ -84,17 +86,7 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
public static float[] SplitArray(Type outputType, params Angle[] vals) public static float[] SplitArray(Type outputType, params Angle[] vals)
{ {
float[] res = new float[vals.Length]; float[] res = new float[vals.Length];
for (int i = 0; i < vals.Length; i++) for (int i = 0; i < vals.Length; i++) res[i] = vals[i].ValueFromType(outputType);
{
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)),
};
}
return res; return res;
} }
@ -106,22 +98,13 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
} }
public bool Equals(Angle other) => p_deg == other.p_deg; public bool Equals(Angle other) => p_deg == other.p_deg;
public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode(); public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString() => ToString(Type.Degrees);
public string ToString(Type outputType) => ToString((string?)null, outputType); public string ToString(Type outputType) => outputType switch
public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch
{ {
Type.Degrees => p_deg.ToString(provider) + "°", Type.Degrees => p_deg + "°",
Type.Gradians => Gradians.ToString(provider) + "grad", Type.Gradians => Gradians + "grad",
Type.Normalized => Normalized.ToString(provider) + "%", Type.Normalized => Normalized + "%",
Type.Radians => Radians.ToString(provider) + "rad", Type.Radians => Radians + "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",
_ => throw new ArgumentException("Unknown type.", nameof(outputType)), _ => throw new ArgumentException("Unknown type.", nameof(outputType)),
}; };
@ -133,7 +116,7 @@ public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
Type.Gradians => Gradians, Type.Gradians => Gradians,
Type.Normalized => Normalized, Type.Normalized => Normalized,
Type.Radians => Radians, 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); public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg);
@ -148,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 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 public enum Type
{ {
Degrees, Degrees,

View File

@ -1,6 +1,12 @@
namespace Nerd_STF.Mathematics; 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 Down => new(0, -1);
public static Float2 Left => new(-1, 0); 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 float x, y;
public Float2(float all) : this(all, all) { } 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) public Float2(float x, float y)
{ {
this.x = x; this.x = x;
this.y = y; 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] public float this[int index]
{ {
get => index switch 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) => public static Float2 Absolute(Float2 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
public static Float2 Average(params Float2[] vals) => Sum(vals) / vals.Length; 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)); new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y));
public static Float2 Clamp(Float2 val, Float2 min, Float2 max) => public static Float2 Clamp(Float2 val, Float2 min, Float2 max) =>
new(Mathf.Clamp(val.x, min.x, max.x), 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; return x + y;
} }
public static Float2 Floor(Float2 val) => public static Int2 Floor(Float2 val) =>
new(Mathf.Floor(val.x), Mathf.Floor(val.y)); new(Mathf.Floor(val.x), Mathf.Floor(val.y));
public static Float2 Lerp(Float2 a, Float2 b, float t, bool clamp = true) => 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)); 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; if (vals.Length < 1) return Zero;
Float2 val = vals[0]; 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; return val;
} }
public static Float2 Min(params Float2[] vals) public static Float2 Min(params Float2[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Float2 val = vals[0]; 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; return val;
} }
public static Float2 Product(params Float2[] vals) 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; foreach (Float2 f in vals) val *= f;
return val; return val;
} }
public static Float2 Round(Float2 val) => public static Int2 Round(Float2 val) =>
new(Mathf.Round(val.x), Mathf.Round(val.y)); new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y));
public static Float2 Subtract(Float2 num, params Float2[] vals) => num - Sum(vals); public static Float2 Subtract(Float2 num, params Float2[] vals) => num - Sum(vals);
public static Float2 Sum(params Float2[] vals) public static Float2 Sum(params Float2[] vals)
{ {
@ -135,21 +162,11 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
return (Xs, Ys); 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 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 bool Equals(Float2 other) => x == other.x && y == other.y;
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); public override int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -168,6 +185,15 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
public Vector2d ToVector() => new(Mathf.ArcTan(y / x), Magnitude); 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 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 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);
@ -178,11 +204,17 @@ public struct Float2 : ICloneable, IComparable<Float2>, IEquatable<Float2>, IGro
public static Float2 operator /(Float2 a, Float2 b) => new(a.x / b.x, a.y / b.y); public static Float2 operator /(Float2 a, 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, float b) => new(a.x / b, a.y / b);
public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b); public static Float2 operator /(Float2 a, Matrix b) => (Float2)((Matrix)a / b);
public static bool operator ==(Float2 a, Float2 b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Float2 a, Float2 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Float2 a, Float2 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Float2 a, Float2 b) => a == b || a < b;
public static implicit operator Float2(Complex val) => new(val.u, val.i); public static implicit operator Float2(Complex val) => new(val.u, val.i);
@ -197,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 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<float> fill) => new(fill);
public static implicit operator Float2(Fill<int> 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);
} }

View File

@ -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 Back => new(0, 0, -1);
public static Float3 Down => new(0, -1, 0); 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) => public static Float3 Absolute(Float3 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); 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 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)); new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z));
public static Float3 Clamp(Float3 val, Float3 min, Float3 max) => public static Float3 Clamp(Float3 val, Float3 min, Float3 max) =>
new(Mathf.Clamp(val.x, min.x, max.x), 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; 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)); 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) => 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)); 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; if (vals.Length < 1) return Zero;
Float3 val = vals[0]; 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; return val;
} }
public static Float3 Min(params Float3[] vals) public static Float3 Min(params Float3[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Float3 val = vals[0]; 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; return val;
} }
public static Float3 Product(params Float3[] vals) 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; foreach (Float3 d in vals) val *= d;
return val; return val;
} }
public static Float3 Round(Float3 val) => public static Int3 Round(Float3 val) =>
new(Mathf.Round(val.x), Mathf.Round(val.y), Mathf.Round(val.z)); 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 Subtract(Float3 num, params Float3[] vals) => num - Sum(vals);
public static Float3 Sum(params Float3[] 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); 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 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 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 int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -197,6 +217,17 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
return new(yaw, pitch, mag); return new(yaw, pitch, mag);
} }
private bool PrintMembers(StringBuilder builder)
{
builder.Append("x = ");
builder.Append(x);
builder.Append(", y = ");
builder.Append(y);
builder.Append(", z = ");
builder.Append(z);
return true;
}
public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z); public static Float3 operator +(Float3 a, Float3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
public static Float3 operator -(Float3 d) => new(-d.x, -d.y, -d.z); public static Float3 operator -(Float3 d) => new(-d.x, -d.y, -d.z);
public static Float3 operator -(Float3 a, Float3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); public static Float3 operator -(Float3 a, Float3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
@ -207,11 +238,17 @@ 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, 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, float b) => new(a.x / b, a.y / b, a.z / b);
public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b); public static Float3 operator /(Float3 a, Matrix b) => (Float3)((Matrix)a / b);
public static bool operator ==(Float3 a, Float3 b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Float3 a, Float3 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Float3 a, Float3 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Float3 a, Float3 b) => a == b || a < b;
public static implicit operator Float3(Complex val) => new(val.u, val.i, 0); public static implicit operator Float3(Complex val) => new(val.u, val.i, 0);
@ -230,4 +267,6 @@ public struct Float3 : ICloneable, IComparable<Float3>, IEquatable<Float3>, IGro
public static explicit operator Float3(HSVAByte val) => (Float3)val.ToHSVA(); 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<float> fill) => new(fill);
public static implicit operator Float3(Fill<int> 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);
} }

View File

@ -1,6 +1,13 @@
namespace Nerd_STF.Mathematics; 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 Back => new(0, 0, -1, 0);
public static Float4 Down => new(0, -1, 0, 0); public static Float4 Down => 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) => public static Float4 Absolute(Float4 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); 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 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)); 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) => public static Float4 Clamp(Float4 val, Float4 min, Float4 max) =>
new(Mathf.Clamp(val.x, min.x, max.x), 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; 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)); 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) => 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), 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; if (vals.Length < 1) return Zero;
Float4 val = vals[0]; 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; return val;
} }
public static Float4 Min(params Float4[] vals) public static Float4 Min(params Float4[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Float4 val = vals[0]; 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; return val;
} }
public static Float4 Round(Float4 val) => public static Int4 Round(Float4 val) =>
new(Mathf.Round(val.x), Mathf.Round(val.y), Mathf.Round(val.z), Mathf.Round(val.w)); new(Mathf.RoundInt(val.x), Mathf.RoundInt(val.y), Mathf.RoundInt(val.z),
Mathf.RoundInt(val.w));
public static Float4 Product(params Float4[] vals) public static Float4 Product(params Float4[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
@ -177,23 +207,11 @@ public struct Float4 : ICloneable, IComparable<Float4>, IEquatable<Float4>, IGro
return (Xs, Ys, Zs, Ws); 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 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 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 int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> 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 }; 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 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 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); 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, 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, float b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
public static Float4 operator /(Float4 a, Matrix b) => (Float4)((Matrix)a / b); public static Float4 operator /(Float4 a, Matrix b) => (Float4)((Matrix)a / b);
public static bool operator ==(Float4 a, Float4 b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Float4 a, Float4 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Float4 a, Float4 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Float4 a, Float4 b) => a == b || a < b;
public static implicit operator Float4(Complex val) => new(val.u, val.i, 0, 0); public static implicit operator Float4(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(HSVAByte val) => (Float4)val.ToHSVA();
public static implicit operator Float4(Fill<float> fill) => new(fill); 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(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);
} }

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Mathematics.Geometry; 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); public static Box2D Unit => new(Vert.Zero, Float2.One);
@ -10,7 +12,7 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
set set
{ {
Vert diff = center - value; Vert diff = center - value;
size = (Float2)diff.position * 2; size = (Float2)diff.position * 2f;
} }
} }
public Vert MinVert public Vert MinVert
@ -19,7 +21,7 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
set set
{ {
Vert diff = center + value; Vert diff = center + value;
size = (Float2)diff.position * 2; size = (Float2)diff.position * 2f;
} }
} }
@ -60,16 +62,8 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
(Vert[] verts, Float2[] sizes) = SplitArray(vals); (Vert[] verts, Float2[] sizes) = SplitArray(vals);
return new(Vert.Median(verts), Float2.Median(sizes)); return new(Vert.Median(verts), Float2.Median(sizes));
} }
public static Box2D Max(params Box2D[] vals) public static Box2D Round(Box2D val) => new(Vert.Round(val.center), Float2.Round(val.size));
{
(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 (Vert[] centers, Float2[] sizes) SplitArray(params Box2D[] vals) public static (Vert[] centers, Float2[] sizes) SplitArray(params Box2D[] vals)
{ {
Vert[] centers = new Vert[vals.Length]; Vert[] centers = new Vert[vals.Length];
@ -84,18 +78,12 @@ public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
return (centers, sizes); 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); if (other is null) return false;
return Equals((Box2D)obj); return center == other.center && size == other.size;
} }
public bool Equals(Box2D other) => center == other.center && size == other.size; public override int GetHashCode() => base.GetHashCode();
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 bool Contains(Vert vert) 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; 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, Vert b) => new(a.center + b, a.size);
public static Box2D operator +(Box2D a, Float2 b) => new(a.center, a.size + b); 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, 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, 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 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 implicit operator Box2D(Fill<float> fill) => new(fill);
public static explicit operator Box2D(Box3D box) => new(box.center, (Float2)box.size); public static explicit operator Box2D(Box3D box) => new(box.center, (Float2)box.size);

View File

@ -1,6 +1,8 @@
namespace Nerd_STF.Mathematics.Geometry; 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); public static Box3D Unit => new(Vert.Zero, Float3.One);
@ -51,10 +53,12 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
(Vert[] centers, Float3[] sizes) = SplitArray(vals); (Vert[] centers, Float3[] sizes) = SplitArray(vals);
return new(Vert.Average(centers), Float3.Average(sizes)); 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) => 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)); 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) => 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)); new(Vert.Lerp(a.center, b.center, t, clamp), Float3.Lerp(a.size, b.size, t, clamp));
public static Box3D Median(params Box3D[] vals) public static Box3D Median(params Box3D[] vals)
@ -62,16 +66,8 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
(Vert[] verts, Float3[] sizes) = SplitArray(vals); (Vert[] verts, Float3[] sizes) = SplitArray(vals);
return new(Vert.Median(verts), Float3.Median(sizes)); return new(Vert.Median(verts), Float3.Median(sizes));
} }
public static Box3D Max(params Box3D[] vals) public static Box3D Round(Box3D val) => new(Vert.Ceiling(val.center), (Float3)Float3.Ceiling(val.size));
{
(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 (Vert[] centers, Float3[] sizes) SplitArray(params Box3D[] vals) public static (Vert[] centers, Float3[] sizes) SplitArray(params Box3D[] vals)
{ {
Vert[] centers = new Vert[vals.Length]; Vert[] centers = new Vert[vals.Length];
@ -86,25 +82,27 @@ public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
return (centers, sizes); 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); if (other is null) return false;
return Equals((Box3D)obj); return center == other.center && size == other.size;
} }
public bool Equals(Box3D other) => center == other.center && size == other.size; public override int GetHashCode() => base.GetHashCode();
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 bool Contains(Vert vert) public bool Contains(Vert vert)
{ {
Float3 diff = Float3.Absolute(center - vert); Float3 diff = Float3.Absolute(center - vert);
return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z; 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, Vert b) => new(a.center + b, a.size);
public static Box3D operator +(Box3D a, Float3 b) => new(a.center, a.size + b); public static Box3D operator +(Box3D a, Float3 b) => new(a.center, a.size + b);
@ -115,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, 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, 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 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(Fill<float> fill) => new(fill);
public static implicit operator Box3D(Box2D box) => new(box); public static implicit operator Box3D(Box2D box) => new(box);

View File

@ -1,7 +0,0 @@
namespace Nerd_STF.Mathematics.Geometry;
public interface ISubdividable<T>
{
public T Subdivide();
public T Subdivide(int iterations);
}

View File

@ -1,19 +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 static Triangle[] TriangulateAll<T>(params T[] triangulatables) where T : ITriangulatable
{
List<Triangle> res = new();
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
return res.ToArray();
}
public Triangle[] Triangulate();
}

View File

@ -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>, namespace Nerd_STF.Mathematics.Geometry;
IGroup<Vert>, ISubdividable<Line[]>
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 Back => new(Vert.Zero, Vert.Back);
public static Line Down => new(Vert.Zero, Vert.Down); 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 Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b));
public static Line Average(params Line[] vals) 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); (Vert[] starts, Vert[] ends) = SplitArray(vals);
return new(Vert.Median(starts), Vert.Median(ends)); return new(Vert.Median(starts), Vert.Median(ends));
} }
public static Line Max(params Line[] vals) public static Line Round(Line val) => new(Vert.Round(val.a), Vert.Round(val.b));
{
(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 (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines) 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); 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); if (other is null) return false;
return Equals((Line)obj); return a == other.a && b == other.b;
} }
public bool Equals(Line other) => a == other.a && b == other.b; public override int GetHashCode() => base.GetHashCode();
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 object Clone() => new Line(a, b); [Obsolete("This method is a bit ambiguous. You should instead compare " +
nameof(Length) + "s directly.")]
public int CompareTo(Line line) => Length.CompareTo(line.Length); public int CompareTo(Line? line)
{
if (line is null) return -1;
return Length.CompareTo(line.Length);
}
public bool Contains(Vert vert) 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, public List<float> ToFloatList() => new() { a.position.x, a.position.y, a.position.z,
b.position.x, b.position.y, b.position.z }; b.position.x, b.position.y, b.position.z };
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, 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, Vert b) => new(a.a + b, a.b + b);
public static Line operator -(Line l) => new(-l.a, -l.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, 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, 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 Line operator /(Line a, float b) => new(a.a / b, a.b / b);
public static bool operator ==(Line a, Line b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Line a, Line b) => !a.Equals(b); nameof(Length) + "s directly.")]
public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Line a, Line b) => a < b || a == b;
public static implicit operator Line(Fill<Vert> fill) => new(fill); 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<Int3> fill) => new(fill);
public static implicit operator Line(Fill<float> 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(Fill<int> fill) => new(fill);
public static implicit operator Line((Vert start, Vert end) val) => new(val.start, val.end);
} }

View File

@ -1,7 +1,7 @@
namespace Nerd_STF.Mathematics.Geometry; namespace Nerd_STF.Mathematics.Geometry;
[Obsolete("This struct is a garbage fire. This will be completely redesigned in v2.4.0")] [Obsolete("This struct is a garbage fire. This will be completely redesigned in v2.5.0")]
public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdividable<Polygon>, ITriangulatable public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivide<Polygon>, ITriangulate
{ {
public Line[] Lines public Line[] Lines
{ {
@ -83,8 +83,8 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
while (true) while (true)
{ {
Line? v = fill(i); Line? v = fill(i);
if (!v.HasValue) break; if (v is null) break;
lines.Add(v.Value); lines.Add(v);
} }
this = new(lines.ToArray()); this = new(lines.ToArray());
} }
@ -190,24 +190,6 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
Line[][] lines = new Line[2][] { a.Lines, b.Lines }; Line[][] lines = new Line[2][] { a.Lines, b.Lines };
Line[] res = new Line[a.Lines.Length]; 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); 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); return new(res);
} }
public static Polygon Median(params Polygon[] vals) public static Polygon Median(params Polygon[] vals)
@ -226,24 +208,6 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
res[i] = Line.Median(row); 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); return new(res);
} }
@ -266,19 +230,12 @@ public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdivid
return Lines == other.Lines; return Lines == other.Lines;
} }
public override int GetHashCode() => Lines.GetHashCode(); public override int GetHashCode() => Lines.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString()
public string ToString(string? provider) {
{ string s = "";
string s = ""; for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i] + " ";
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " "; return s;
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 object Clone() => new Polygon(Lines); public object Clone() => new Polygon(Lines);
@ -375,7 +332,8 @@ 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) if (closest.Value.posB > closest.Value.posA)
closest = (closest.Value.posB, closest.Value.posA, closest.Value.line); closest = (closest.Value.posB, closest.Value.posA, closest.Value.line);

View File

@ -1,6 +1,9 @@
namespace Nerd_STF.Mathematics.Geometry; 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 public Vert A
{ {
@ -179,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) => public static Quadrilateral Absolute(Quadrilateral val) =>
new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D)); new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C), Vert.Absolute(val.D));
@ -212,6 +237,8 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals); (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs), Vert.Min(Ds)); 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) public static (Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) SplitVertArray(params Quadrilateral[] quads)
{ {
@ -265,20 +292,12 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
} }
public static List<float> ToFloatListAll(params Quadrilateral[] quads) => new(ToFloatArrayAll(quads)); 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); if (other is null) return false;
return Equals((Quadrilateral)obj); 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() => base.GetHashCode();
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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<Vert> GetEnumerator() public IEnumerator<Vert> GetEnumerator()
@ -309,6 +328,19 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
public Triangle[] Triangulate() => new Line(A, C).Length > new Line(B, D).Length ? 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) }; 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, 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); 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, Vert b) => new(a.A + b, a.B + b, a.C + b, a.D + b);
@ -324,8 +356,6 @@ public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert
a.C / b.C, a.D / b.D); 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, 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 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<Vert> fill) => new(fill);
public static implicit operator Quadrilateral(Fill<Float3> fill) => new(fill); public static implicit operator Quadrilateral(Fill<Float3> fill) => new(fill);
@ -333,4 +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<Line> fill) => new(fill);
public static implicit operator Quadrilateral(Fill<float> 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 implicit operator Quadrilateral(Fill<int> fill) => new(fill);
public static implicit operator Quadrilateral((Vert a, Vert b, Vert c, Vert d) val) =>
new(val.a, val.b, val.c, val.d);
} }

View File

@ -1,7 +1,9 @@
namespace Nerd_STF.Mathematics.Geometry; namespace Nerd_STF.Mathematics.Geometry;
public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, IComparable<float>, IContainer<Vert>, public record class Sphere : IAverage<Sphere>, ICeiling<Sphere>, IClamp<Sphere>, IClosestTo<Vert>,
IEquatable<Sphere>, IEquatable<float> 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); 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); (Vert[] centers, float[] radii) = SplitArray(vals);
return new(Vert.Min(centers), Mathf.Min(radii)); 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) public static (Vert[] centers, float[] radii) SplitArray(params Sphere[] spheres)
{ {
@ -67,32 +70,38 @@ public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, ICompara
return (centers, radii); return (centers, radii);
} }
public override bool Equals([NotNullWhen(true)] object? 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.")]
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);
}
public bool Equals(float other) => Volume == other; public bool Equals(float other) => Volume == other;
public bool Equals(Sphere other) => center == other.center && radius == other.radius; public virtual bool Equals(Sphere? other)
public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode(); {
public override string ToString() => ToString((string?)null); if (other is null) return false;
public string ToString(string? provider) => "Center: " + center.ToString(provider) return center == other.center && radius == other.radius;
+ " Radius: " + radius.ToString(provider); }
public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider) public override int GetHashCode() => base.GetHashCode();
+ " Radius: " + radius.ToString(provider);
public object Clone() => new Sphere(center, radius); public int CompareTo(Sphere? other)
{
public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume); 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 int CompareTo(float volume) => Volume.CompareTo(volume);
public bool Contains(Vert vert) => (center - vert).Magnitude <= radius; public bool Contains(Vert vert) => (center - vert).Magnitude <= radius;
public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + center; 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, Sphere b) => new(a.center + b.center, a.radius + b.radius);
public static Sphere operator +(Sphere a, Vert b) => new(a.center + b, a.radius); public static Sphere operator +(Sphere a, Vert b) => new(a.center + b, a.radius);
public static Sphere operator +(Sphere a, float b) => new(a.center, a.radius + b); public static Sphere operator +(Sphere a, float b) => new(a.center, a.radius + b);
@ -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, 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, 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 Sphere operator /(Sphere a, float b) => new(a.center * b, a.radius * 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. " +
public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b); "This method will be removed in Nerd_STF 2.5.0.")]
public static bool operator ==(Sphere a, float b) => a.Equals(b); 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); 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; 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; 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; 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; 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; 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; 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; 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 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);
} }

View File

@ -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 public Vert A
{ {
@ -142,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) => public static Triangle Absolute(Triangle val) =>
new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C)); new(Vert.Absolute(val.A), Vert.Absolute(val.B), Vert.Absolute(val.C));
@ -173,6 +199,8 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals); (Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs)); 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) public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris)
{ {
@ -217,20 +245,12 @@ public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
} }
public static List<float> ToFloatListAll(params Triangle[] tris) => new(ToFloatArrayAll(tris)); 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); if (other is null) return false;
return Equals((Triangle)obj); 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() => base.GetHashCode();
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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<Vert> GetEnumerator() public IEnumerator<Vert> GetEnumerator()
@ -254,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, public List<float> ToFloatList() => new() { A.position.x, A.position.y, A.position.z,
B.position.x, B.position.y, B.position.z, B.position.x, B.position.y, B.position.z,
C.position.x, C.position.y, C.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, 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, 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); public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C);
@ -265,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, 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, 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 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<Vert> fill) => new(fill);
public static implicit operator Triangle(Fill<Float3> fill) => new(fill); public static implicit operator Triangle(Fill<Float3> fill) => new(fill);
@ -274,4 +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<Line> fill) => new(fill);
public static implicit operator Triangle(Fill<float> 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 implicit operator Triangle(Fill<int> fill) => new(fill);
public static implicit operator Triangle((Vert a, Vert b, Vert c) val) =>
new(val.a, val.b, val.c);
} }

View File

@ -50,6 +50,8 @@ public struct Vert : ICloneable, IEquatable<Vert>, IGroup<float>
Float3.Max(ToFloat3Array(vals)); Float3.Max(ToFloat3Array(vals));
public static Vert Min(params Vert[] vals) => public static Vert Min(params Vert[] vals) =>
Float3.Min(ToFloat3Array(vals)); Float3.Min(ToFloat3Array(vals));
public static Vert Round(Vert val) =>
Float3.Round(val);
public static Float3[] ToFloat3Array(params Vert[] vals) 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 bool Equals(Vert other) => position == other.position;
public override int GetHashCode() => position.GetHashCode(); public override int GetHashCode() => position.GetHashCode();
public override string ToString() => ToString((string?)null); public override string ToString() => position.ToString();
public string ToString(string? provider) => position.ToString(provider);
public string ToString(IFormatProvider provider) => position.ToString(provider);
public object Clone() => new Vert(position); public object Clone() => new Vert(position);

View File

@ -1,6 +1,10 @@
namespace Nerd_STF.Mathematics; 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 Down => new(0, -1);
public static Int2 Left => new(-1, 0); 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) => public static Int2 Absolute(Int2 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y)); 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; if (vals.Length < 1) return Zero;
Int2 val = vals[0]; 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; return val;
} }
public static Int2 Min(params Int2[] vals) public static Int2 Min(params Int2[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Int2 val = vals[0]; 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; return val;
} }
public static Int2 Product(params Int2[] vals) public static Int2 Product(params Int2[] vals)
@ -128,21 +154,11 @@ public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int
return (Xs, Ys); 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 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 bool Equals(Int2 other) => x == other.x && y == other.y;
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode(); public override int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<int> 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(); 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 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 i) => new(-i.x, -i.y);
public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y); public static Int2 operator -(Int2 a, Int2 b) => new(a.x - b.x, a.y - b.y);
@ -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 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); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Int2 a, Int2 b) => a == b || a < b;
public static explicit operator Int2(Complex val) => new((int)val.u, (int)val.i); public static explicit operator Int2(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(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 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(Fill<int> fill) => new(fill);
public static implicit operator Int2((int x, int y) val) => new(val.x, val.y);
} }

View File

@ -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 Back => new(0, 0, -1);
public static Int3 Down => new(0, -1, 0); 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) => public static Int3 Absolute(Int3 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z)); 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; if (vals.Length < 1) return Zero;
Int3 val = vals[0]; 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; return val;
} }
public static Int3 Min(params Int3[] vals) public static Int3 Min(params Int3[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Int3 val = vals[0]; 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; return val;
} }
public static Int3 Product(params Int3[] vals) 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); 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 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 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 int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<int> 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(); 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 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 i) => new(-i.x, -i.y, -i.z);
public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z); public static Int3 operator -(Int3 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
@ -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 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); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Int3 a, Int3 b) => a == b || a < b;
public static explicit operator Int3(Complex val) => new((int)val.u, (int)val.i, 0); public static explicit operator Int3(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(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 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(Fill<int> fill) => new(fill);
public static implicit operator Int3((int x, int y, int z) vals) =>
new(vals.x, vals.y, vals.z);
} }

View File

@ -1,8 +1,14 @@
namespace Nerd_STF.Mathematics; 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); 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 Deep => new(0, 0, 0, -1);
public static Int4 Down => new(0, -1, 0, 0); public static Int4 Down => new(0, -1, 0, 0);
[Obsolete("Field has been replaced by " + nameof(HighW) + ", because it has a better name. " + [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) => public static Int4 Absolute(Int4 val) =>
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w)); 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; if (vals.Length < 1) return Zero;
Int4 val = vals[0]; 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; return val;
} }
public static Int4 Min(params Int4[] vals) public static Int4 Min(params Int4[] vals)
{ {
if (vals.Length < 1) return Zero; if (vals.Length < 1) return Zero;
Int4 val = vals[0]; 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; return val;
} }
public static Int4 Product(params Int4[] vals) 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); 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 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 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 int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<int> 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 }; 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 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 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); 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 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); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Int4 a, Int4 b) => a == b || a < b;
public static explicit operator Int4(Complex val) => new((int)val.u, (int)val.i, 0, 0); public static explicit operator Int4(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 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(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(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);
} }

View File

@ -105,8 +105,7 @@ public static class Mathf
public static int[] Factors(int val) public static int[] Factors(int val)
{ {
List<int> factors = new(); List<int> factors = new() { 1 };
factors.Add(1);
for (int i = 2; i < val; i++) if (val % i == 0) factors.Add(i); for (int i = 2; i < val; i++) if (val % i == 0) factors.Add(i);
factors.Add(val); factors.Add(val);
return factors.ToArray(); return factors.ToArray();
@ -144,14 +143,14 @@ public static class Mathf
if (clamp) v = Clamp(v, Min(a, b), Max(a, b)); if (clamp) v = Clamp(v, Min(a, b), Max(a, b));
return v; 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) public static Equation MakeEquation(Dictionary<float, float> vals) => delegate (float x)
{ {
if (vals.Count < 1) throw new UndefinedException(); if (vals.Count < 1) throw new UndefinedException();
if (vals.Count == 1) return vals.Values.First(); 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; float? min, max;
if (x < (min = vals.Keys.Min())) if (x < (min = vals.Keys.Min()))
@ -212,9 +211,9 @@ public static class Mathf
foreach (int i in vals) val = i > val ? i : val; foreach (int i in vals) val = i > val ? i : val;
return 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]; T val = vals[0];
foreach (T t in vals) val = t.CompareTo(val) > 0 ? t : val; foreach (T t in vals) val = t.CompareTo(val) > 0 ? t : val;
return val; return val;
@ -254,9 +253,9 @@ public static class Mathf
foreach (int i in vals) val = i < val ? i : val; foreach (int i in vals) val = i < val ? i : val;
return 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]; T val = vals[0];
foreach (T t in vals) val = t.CompareTo(val) < 0 ? t : val; foreach (T t in vals) val = t.CompareTo(val) < 0 ? t : val;
return val; return val;
@ -327,8 +326,7 @@ public static class Mathf
if (pow == 1) return num; if (pow == 1) return num;
if (pow < 1) return 0; if (pow < 1) return 0;
int val = 1; int val = 1;
int abs = Absolute(pow); for (int i = 0; i < pow; i++) val = val * num % mod;
for (int i = 0; i < abs; i++) val = val * num % mod;
return val; return val;
} }

View File

@ -1,6 +1,10 @@
namespace Nerd_STF.Mathematics.NumberSystems; 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 Down => new(0, -1);
public static Complex Left => new(-1, 0); 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 float Magnitude => Mathf.Sqrt(u * u + i * i);
public Complex Normalized => this * Mathf.InverseSqrt(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 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<float> fill) : this(fill(0), fill(1)) { }
public Complex(Fill<int> 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 Absolute(Complex val) => Float2.Absolute(val);
public static Complex Average(params Complex[] vals) 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 Angle GetAngle() => Mathf.ArcTan(i / u);
public int CompareTo(Complex other) => Magnitude.CompareTo(other.Magnitude); 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 bool Equals(Complex other) => u == other.u && i == other.i;
public override int GetHashCode() => u.GetHashCode() ^ i.GetHashCode(); public override int GetHashCode() => base.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);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<float> GetEnumerator() public IEnumerator<float> GetEnumerator()
@ -161,6 +171,15 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
public Vector2d ToVector() => ((Float2)this).ToVector(); 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 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 c) => new(-c.u, -c.i);
public static Complex operator -(Complex a, Complex b) => new(a.u - b.u, a.i - b.i); public static Complex operator -(Complex a, Complex b) => new(a.u - b.u, a.i - b.i);
@ -171,11 +190,17 @@ public struct Complex : ICloneable, IComparable<Complex>, IEquatable<Complex>, I
public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b); public static Complex operator /(Complex a, float b) => new(a.u / b, a.i / b);
public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b); public static Complex operator /(Complex a, Matrix b) => (Complex)((Matrix)a / b);
public static Complex operator ~(Complex v) => v.Conjugate; public static Complex operator ~(Complex v) => v.Conjugate;
public static bool operator ==(Complex a, Complex b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Complex a, Complex b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Complex a, Complex b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Complex a, Complex b) => a == b || a < b;
public static explicit operator Complex(Quaternion val) => new(val.u, val.i); public static explicit operator Complex(Quaternion val) => new(val.u, val.i);
@ -190,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 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<float> fill) => new(fill);
public static implicit operator Complex(Fill<int> 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);
} }

View File

@ -1,12 +1,23 @@
namespace Nerd_STF.Mathematics.NumberSystems; 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 Back => new(0, 0, -1, 0);
public static Quaternion Down => new(0, -1, 0, 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 Far => new(0, 0, 0, 1);
public static Quaternion Forward => new(0, 0, 1, 0); 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 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 Near => new(0, 0, 0, -1);
public static Quaternion Right => new(1, 0, 0, 0); public static Quaternion Right => new(1, 0, 0, 0);
public static Quaternion Up => new(0, 1, 0, 0); public static Quaternion Up => new(0, 1, 0, 0);
@ -30,19 +41,15 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
} }
} }
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 all) : this(all, all, all, all) { }
public Quaternion(float i, float j, float k) : this(0, i, j, k) { } 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(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, 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<float> fill) : this(fill(0), fill(1), fill(2)) { }
public Quaternion(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { } public Quaternion(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
@ -80,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 Absolute(Quaternion val) => Float4.Absolute(val);
public static Quaternion Average(params Quaternion[] vals) public static Quaternion Average(params Quaternion[] vals)
@ -187,24 +216,8 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
} }
public int CompareTo(Quaternion other) => Magnitude.CompareTo(other.Magnitude); 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 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 int GetHashCode() => base.GetHashCode();
public override string ToString() => ToString((string?)null);
public string ToString(string? provider) => u.ToString(provider)
+ (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"
+ (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j"
+ (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k";
public string ToString(IFormatProvider provider) => u.ToString(provider)
+ (i >= 0 ? " + " : " - ") + Mathf.Absolute(i).ToString(provider) + "i"
+ (j >= 0 ? " + " : " - ") + Mathf.Absolute(j).ToString(provider) + "j"
+ (k >= 0 ? " + " : " - ") + Mathf.Absolute(k).ToString(provider) + "k";
public object Clone() => new Quaternion(u, i, j, k);
public Angle GetAngle() => Mathf.ArcCos(u) * 2; public Angle GetAngle() => Mathf.ArcCos(u) * 2;
public Float3 GetAxis() => IJK.Normalized; public Float3 GetAxis() => IJK.Normalized;
@ -275,8 +288,23 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
} }
public List<float> ToList() => new() { u, i, j, k }; 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 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 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) public static Quaternion operator *(Quaternion x, Quaternion y)
{ {
@ -295,11 +323,17 @@ public struct Quaternion : ICloneable, IComparable<Quaternion>, IEquatable<Quate
public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b); public static Quaternion operator /(Quaternion a, Matrix b) => (Quaternion)((Matrix)a / b);
public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b); public static Quaternion operator /(Quaternion a, Float3 b) => a / new Quaternion(b);
public static Quaternion operator ~(Quaternion v) => v.Conjugate; public static Quaternion operator ~(Quaternion v) => v.Conjugate;
public static bool operator ==(Quaternion a, Quaternion b) => a.Equals(b); [Obsolete("This operator is a bit ambiguous. You should instead compare " +
public static bool operator !=(Quaternion a, Quaternion b) => !a.Equals(b); nameof(Magnitude) + "s directly.")]
public static bool operator >(Quaternion a, Quaternion b) => a.CompareTo(b) > 0; 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; 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; 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 bool operator <=(Quaternion a, Quaternion b) => a == b || a < b;
public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0); public static implicit operator Quaternion(Complex val) => new(val.u, val.i, 0, 0);
@ -314,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(Vert val) => new(val);
public static implicit operator Quaternion(Fill<float> fill) => new(fill); 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(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);
} }

View File

@ -33,7 +33,7 @@ public static class Constants
public const float Sqrt3 = 1.7320508076f; public const float Sqrt3 = 1.7320508076f;
public const float Sqrt5 = 2.2360679775f; public const float Sqrt5 = 2.2360679775f;
public const float Sqrt10 = 3.16227766017f; 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 Cos0Deg = 1;
public const float Cos30Deg = Sqrt3 / 2; public const float Cos30Deg = Sqrt3 / 2;
@ -85,7 +85,7 @@ public static class Constants
public const float ConnectiveConstant = 1.847759065f; public const float ConnectiveConstant = 1.847759065f;
public const float DeVicciTesseractConstant = 1.0074347568f; public const float DeVicciTesseractConstant = 1.0074347568f;
public const float EmbreeTrefethenConstant = 0.70258f; 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 ErdosBorweinConstant = 1.6066951524f;
public const float ErdosTenenbaumFordConstant = 0.8607133205f; public const float ErdosTenenbaumFordConstant = 0.8607133205f;
public const float FeigenbaumConstant1 = 4.6692016091f; 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 LandauConstant = (0.5f + 0.54326f) / 2;
public const float LandauThirdConstant = (0.5f + 0.7853f) / 2; public const float LandauThirdConstant = (0.5f + 0.7853f) / 2;
public const float LandauRamanujanConstant = 0.7642236535f; 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 LemniscateConstant = 2.6220575542f;
public const float LevyConstant1 = Pi * Pi / (12 * Ln2); public const float LevyConstant1 = Pi * Pi / (12 * Ln2);
public const float LevyConstant2 = 3.2758229187f; public const float LevyConstant2 = 3.2758229187f;
@ -141,8 +141,8 @@ public static class Constants
public const float FirstNielsenRamanujanConstant = Pi * Pi / 12; public const float FirstNielsenRamanujanConstant = Pi * Pi / 12;
public const float SecondDuBoisRaymondConstant = (E * E - 7) / 2; public const float SecondDuBoisRaymondConstant = (E * E - 7) / 2;
public const float SecondFavardConstant = 1.2337005501f; public const float SecondFavardConstant = 1.2337005501f;
public const float SecondHermiteConstant = 2 / Sqrt3; public const float SecondHermiteConstant = 2 * Sqrt3 / 9;
public const float UniversalHyperbolicConstant = 2.2955871493f; public const float UniversalParabolicConstant = 2.2955871493f;
public const float DottieNumber = 0.7390851332f; public const float DottieNumber = 0.7390851332f;
public const float FractalDimensionOfTheApollonianPackingOfCircles = 1.305688f; public const float FractalDimensionOfTheApollonianPackingOfCircles = 1.305688f;
@ -152,5 +152,5 @@ public static class Constants
public const float PlasticNumber = 1.3247179572f; public const float PlasticNumber = 1.3247179572f;
public const float LaplaceLimit = 0.6627434193f; public const float LaplaceLimit = 0.6627434193f;
public const float LogarithmicCapacityOfTheUnitDisk = 0.5901702995f; public const float LogarithmicCapacityOfTheUnitDisk = 0.5901702995f;
public const float RegularPaperfoldingSequence = 0.8507361882f; public const float RegularPaperfoldingConstant = 0.8507361882f;
} }

View 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.

View File

@ -1,18 +1,22 @@
global using System; global using Nerd_STF;
global using Nerd_STF.Graphics;
global using Nerd_STF.Graphics.Abstract;
global using Nerd_STF.Exceptions;
global using Nerd_STF.Extensions;
global using Nerd_STF.Mathematics;
global using Nerd_STF.Mathematics.Abstract;
global using Nerd_STF.Mathematics.Algebra;
global using Nerd_STF.Mathematics.Geometry;
global using Nerd_STF.Mathematics.NumberSystems;
global using Nerd_STF.Mathematics.Samples;
global using System;
global using System.Collections; global using System.Collections;
global using System.Collections.Generic; global using System.Collections.Generic;
global using System.Diagnostics.CodeAnalysis; global using System.Diagnostics.CodeAnalysis;
global using System.IO; global using System.IO;
global using System.Linq; global using System.Linq;
global using System.Net.Http; global using System.Net.Http;
global using System.Runtime.Serialization;
global using System.Text;
global using System.Threading; global using System.Threading;
global using System.Threading.Tasks; global using System.Threading.Tasks;
global using Nerd_STF;
global using Nerd_STF.Graphics;
global using Nerd_STF.Exceptions;
global using Nerd_STF.Extensions;
global using Nerd_STF.Mathematics;
global using Nerd_STF.Mathematics.Algebra;
global using Nerd_STF.Mathematics.Geometry;
global using Nerd_STF.Mathematics.NumberSystems;
global using Nerd_STF.Mathematics.Samples;

21
Nerd_STF/Nerd_STF.cs Normal file
View File

@ -0,0 +1,21 @@
namespace Nerd_STF;
public static class Nerd_STF
{
public static readonly string[] Contributors =
{
MainDeveloper
};
public static readonly Dictionary<string, string> PersonalLinks = new()
{
{ "email", "mailto:kyle@thatonenerd.net" },
{ "website", "https://thatonenerd.net/" }
};
public static readonly Dictionary<string, string> LibraryLinks = new()
{
{ "github", "https://github.com/That-One-Nerd/Nerd_STF" },
{ "nuget", "https://www.nuget.org/packages/Nerd_STF/" }
};
public const string MainDeveloper = "That_One_Nerd";
public const string Version = "2.3.2";
}

View File

@ -1,59 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<RootNamespace>Nerd_STF</RootNamespace> <RootNamespace>Nerd_STF</RootNamespace>
<AssemblyName>Nerd_STF</AssemblyName> <AssemblyName>Nerd_STF</AssemblyName>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>That_One_Nerd</Authors> <Authors>That_One_Nerd</Authors>
<Description>Nerd_STF is a C# library that runs on .Net 6.0, and contains added structures and classes I feel would help the default C# library package.</Description> <Description>Nerd_STF is a general-purpose .NET library.</Description>
<Copyright>Copyright (c) 2022 That_One_Nerd</Copyright> <Copyright>Copyright (c) 2022 That_One_Nerd</Copyright>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/That-One-Nerd/Nerd_STF</RepositoryUrl> <RepositoryUrl>https://github.com/That-One-Nerd/Nerd_STF</RepositoryUrl>
<AssemblyVersion>2.3.1</AssemblyVersion> <AssemblyVersion>2.3.2</AssemblyVersion>
<PackageTags>c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers</PackageTags> <PackageTags>c#;csharp;c sharp;math;mathematics;mathametics;maths;color;rgb;rgba;cmyk;cmyka;hsv;hsva;calculus;linear algebra;linalg;linearalgebra;matrix;matrix2x2;matrix 2x2;matrix3x3;matrix 3x3;matrix4x4;matrix 4x4;matrix multiplication;vector;vector2d;vector3d;vector2;vector3;float2;float3;float4;int2;int3;int4;angle;geometry;vert;line;polygon;triangle;quadrilateral;sphere;circle;number system;numbersystem;complex numbers;complex;2d numbers;2dnumbers;quaternions;4d numbers;4dnumbers</PackageTags>
<Version>2.3.1</Version> <Version>2.3.2</Version>
<Product>Nerd_STF</Product> <Product>Nerd_STF</Product>
<PackageId>Nerd_STF</PackageId> <PackageId>Nerd_STF</PackageId>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIcon>Logo Square.png</PackageIcon> <PackageIcon>Logo Square.png</PackageIcon>
<PackageReleaseNotes> <PackageReleaseNotes>A bunch of stuff has changed, hasn't it?
# Nerd_STF v2.3.1
***Everything has been tested and most things work!*** This update was originally intended to be a support update. But among other problems, I don't want to maintain 3 slightly different versions of Nerd_STF at the same time. So I'm going to put the support update on hold for now. I won't delete my progress on it (I got about a quarter of the way done with support for .NET Standard 2.0. It's a big undertaking), I won't promise any completion date either.
**WARNING:** Instead, this update ended up being a quality-of-life update. I already finished this part of the update before I decided to cancel the support update. This update now has lots of support for the new .NET 7 features. I'm now using a bunch of static abstract interfaces. I also added range indexing to almost all of the types available. The color byte types now have int fields instead of byte fields because ints are much more common. The values are automatically clamped between 0 and 255 just in case. Basically all types are records now because records are really nice. Lastly, some stuff has been marked as deprecated and to be removed in a future release because they already, exist, are kind of useless, and/or are misleading. Most of the deprecated stuff will be removed in either 2.4.0 or 2.5.0.
All of the matrix classes have had all of their constructors' row and column variables swapped. You'll have to switch all your variables around.
Sorry for the inconvenience :(.
The `v2.3.1.x` updates go through every single field and method in Nerd_STF to make sure it works correctly. Also, just want to note that despite the Vert`struct not being marked as deprecated, it will still be removed in 2.5.0. I didn't mark it because that would have created a bunch of warnings in my library. And I don't like warnings.
You see, up until now I haven't actually tested literally anything at all. Partly because I didn't have the tools to and partly because I was lazy. But now, it's guarenteed to work in most cases (unless I like don't pick up some bug, you know).
Hi everyone! Everything has been checked now and most stuff works! Not everything, like the triangle and quadrilateral area stuff, but for the most part, it's all cool and good. One final note, I've changed the description of the library and I've changed a bunch of the assembly and compilation settings.
I've just now remembered how bad the Polygon struct was. It's getting remade. The v2.4.0 update will be mostly geometry focused, so that'll be the best time to figure out how to fix this stuff. The new Polygon struct will be much better, trust me. Anyway, that's it for this update. The longest delay was just getting this project to other versions of .NET. Stay tuned for v2.4.0, the Equations and Numbers update!</PackageReleaseNotes>
But all the matrix structs work like charm now! I'm honestly suprised they worked as well as they did before (especially the dynamic matrix). They can now be relied on.
Next up is the documentation update. Stay tuned!
(This may be another update with beta parts, but I'm not sure yet. We'll see).
*P.S. (NuGet only message): I didn't know I had the room to put the whole changelog here. I'll do that from now on.*
</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl> <PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>
<GenerateDocumentationFile>False</GenerateDocumentationFile> <GenerateDocumentationFile>False</GenerateDocumentationFile>
<SignAssembly>False</SignAssembly> <SignAssembly>False</SignAssembly>
<PackAsTool>False</PackAsTool> <PackAsTool>False</PackAsTool>
<Title>Nerd_STF</Title>
<IncludeSymbols>True</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<EnforceCodeStyleInBuild>False</EnforceCodeStyleInBuild>
<AssemblyOriginatorKeyFile>C:\Users\kyley\Desktop\Misc Items\Private Keys\SNA\Nerd_STF.snk</AssemblyOriginatorKeyFile>
<DelaySign>False</DelaySign>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors> <TreatWarningsAsErrors>False</TreatWarningsAsErrors>
<WarningLevel>9999</WarningLevel>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<TreatWarningsAsErrors>True</TreatWarningsAsErrors> <TreatWarningsAsErrors>True</TreatWarningsAsErrors>
<WarningLevel>9999</WarningLevel>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

Some files were not shown because too many files have changed in this diff Show More