Lots of nice changes. Made angle, more interfaces, working on fraction.

This commit is contained in:
That-One-Nerd 2024-10-31 12:52:21 -04:00
parent 467b5903cc
commit 0704b8eec7
30 changed files with 544 additions and 97 deletions

View File

@ -1,6 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
namespace Nerd_STF.Mathematics.Abstract namespace Nerd_STF.Abstract
{ {
public interface ICombinationIndexer<TItem> public interface ICombinationIndexer<TItem>
{ {

View File

@ -1,14 +1,14 @@
#if CS11_OR_GREATER #if CS11_OR_GREATER
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Nerd_STF.Mathematics.Abstract namespace Nerd_STF.Abstract
{ {
public interface IFromTuple<TSelf, TTuple> public interface IFromTuple<TSelf, TTuple>
where TSelf : IFromTuple<TSelf, TTuple> where TSelf : IFromTuple<TSelf, TTuple>
where TTuple : struct, ITuple where TTuple : struct, ITuple
{ {
public static abstract implicit operator TSelf(TTuple tuple); static abstract implicit operator TSelf(TTuple tuple);
public static abstract implicit operator TTuple(TSelf tuple); static abstract implicit operator TTuple(TSelf tuple);
} }
} }
#endif #endif

View File

@ -0,0 +1,10 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Abstract
{
public interface IInterpolable<TSelf>
where TSelf : IInterpolable<TSelf>
{
static abstract TSelf Lerp(TSelf a, TSelf b, double t, bool clamp = true);
}
}
#endif

View File

@ -0,0 +1,10 @@
using System;
namespace Nerd_STF.Abstract
{
public interface IModifiable<TSelf>
where TSelf : IModifiable<TSelf>
{
void Modify(Action<TSelf> action);
}
}

View File

@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Numerics;
namespace Nerd_STF.Abstract
{
public interface INumberGroup<TSelf, TItem> : ICombinationIndexer<TItem>,
IEnumerable<TItem>,
IEquatable<TSelf>,
IModifiable<TSelf>
#if CS11_OR_GREATER
,IInterpolable<TSelf>,
ISimpleMathOperations<TSelf>,
IVectorOperations<TSelf>
#endif
where TSelf : INumberGroup<TSelf, TItem>
#if CS11_OR_GREATER
where TItem : INumber<TItem>
#endif
{
TItem this[int index] { get; set; }
TItem[] ToArray();
List<TItem> ToList();
}
}

View File

@ -0,0 +1,10 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Abstract
{
public interface IPresets1d<TSelf> where TSelf : IPresets1d<TSelf>
{
static abstract TSelf One { get; }
static abstract TSelf Zero { get; }
}
}
#endif

View File

@ -0,0 +1,13 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Abstract
{
public interface IPresets2d<TSelf> : IPresets1d<TSelf>
where TSelf : IPresets2d<TSelf>
{
static abstract TSelf Down { get; }
static abstract TSelf Left { get; }
static abstract TSelf Right { get; }
static abstract TSelf Up { get; }
}
}
#endif

View File

@ -0,0 +1,11 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Abstract
{
public interface IPresets3d<TSelf> : IPresets2d<TSelf>
where TSelf : IPresets3d<TSelf>
{
static abstract TSelf Backward { get; }
static abstract TSelf Forward { get; }
}
}
#endif

View File

@ -1,11 +1,11 @@
#if CS11_OR_GREATER #if CS11_OR_GREATER
namespace Nerd_STF.Mathematics.Abstract namespace Nerd_STF.Abstract
{ {
public interface IPresets4d<TSelf> : IPresets3d<TSelf> public interface IPresets4d<TSelf> : IPresets3d<TSelf>
where TSelf : IPresets4d<TSelf> where TSelf : IPresets4d<TSelf>
{ {
public static abstract TSelf LowW { get; } static abstract TSelf LowW { get; }
public static abstract TSelf HighW { get; } static abstract TSelf HighW { get; }
} }
} }
#endif #endif

View File

@ -0,0 +1,19 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Abstract
{
public interface IRoundable<TSelf> : IRoundable<TSelf, TSelf>
where TSelf : IRoundable<TSelf> { }
public interface IRoundable<TSelf, TOut>
where TSelf : IRoundable<TSelf, TOut>
{
static abstract TOut Ceiling(TSelf val);
static abstract TOut Floor(TSelf val);
static abstract TOut Round(TSelf val);
static abstract void Ceiling(ref TSelf val);
static abstract void Floor(ref TSelf val);
static abstract void Round(ref TSelf val);
}
}
#endif

View File

@ -0,0 +1,17 @@
#if CS11_OR_GREATER
using System.Collections.Generic;
using System.Numerics;
namespace Nerd_STF.Abstract
{
public interface ISimpleMathOperations<TSelf> : IAdditionOperators<TSelf, TSelf, TSelf>,
ISubtractionOperators<TSelf, TSelf, TSelf>,
IMultiplyOperators<TSelf, TSelf, TSelf>,
IDivisionOperators<TSelf, TSelf, TSelf>
where TSelf : ISimpleMathOperations<TSelf>
{
static abstract TSelf Product(IEnumerable<TSelf> vals);
static abstract TSelf Sum(IEnumerable<TSelf> vals);
}
}
#endif

View File

@ -2,13 +2,13 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace Nerd_STF.Mathematics.Abstract namespace Nerd_STF.Abstract
{ {
public interface ISplittable<TSelf, TTuple> public interface ISplittable<TSelf, TTuple>
where TSelf : ISplittable<TSelf, TTuple> where TSelf : ISplittable<TSelf, TTuple>
where TTuple : struct, ITuple where TTuple : struct, ITuple
{ {
public static abstract TTuple SplitArray(IEnumerable<TSelf> values); static abstract TTuple SplitArray(IEnumerable<TSelf> values);
} }
} }
#endif #endif

View File

@ -0,0 +1,17 @@
#if CS11_OR_GREATER
using System.Collections.Generic;
namespace Nerd_STF.Abstract
{
public interface IVectorOperations<TSelf> : ISimpleMathOperations<TSelf>
where TSelf : IVectorOperations<TSelf>
{
double Magnitude { get; }
static abstract TSelf ClampMagnitude(TSelf val, double minMag, double maxMag);
static abstract void ClampMagnitude(ref TSelf val, double minMag, double maxMag);
static abstract double Dot(TSelf a, TSelf b);
static abstract double Dot(IEnumerable<TSelf> vals);
}
}
#endif

View File

@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
namespace Nerd_STF.Mathematics.Abstract
{
public interface INumberGroup<TSelf, TItem> : ICombinationIndexer<TItem>,
IEnumerable<TItem>,
IEquatable<TSelf>
where TSelf : INumberGroup<TSelf, TItem>
{
TItem this[int index] { get; set; }
TItem[] ToArray();
List<TItem> ToList();
}
}

View File

@ -1,10 +0,0 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Mathematics.Abstract
{
public interface IPresets1d<TSelf> where TSelf : IPresets1d<TSelf>
{
public static abstract TSelf One { get; }
public static abstract TSelf Zero { get; }
}
}
#endif

View File

@ -1,13 +0,0 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Mathematics.Abstract
{
public interface IPresets2d<TSelf> : IPresets1d<TSelf>
where TSelf : IPresets2d<TSelf>
{
public static abstract TSelf Down { get; }
public static abstract TSelf Left { get; }
public static abstract TSelf Right { get; }
public static abstract TSelf Up { get; }
}
}
#endif

View File

@ -1,11 +0,0 @@
#if CS11_OR_GREATER
namespace Nerd_STF.Mathematics.Abstract
{
public interface IPresets3d<TSelf> : IPresets2d<TSelf>
where TSelf : IPresets3d<TSelf>
{
public static abstract TSelf Backward { get; }
public static abstract TSelf Forward { get; }
}
}
#endif

View File

@ -0,0 +1,253 @@
using Nerd_STF.Abstract;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Nerd_STF.Mathematics
{
public struct Angle : IComparable<Angle>,
IEquatable<Angle>,
IModifiable<Angle>
#if CS11_OR_GREATER
,IPresets2d<Angle>,
IFromTuple<Angle, (double, Angle.Unit)>
#endif
{
public static Angle Down => new Angle(0.75);
public static Angle Left => new Angle(0.5);
public static Angle Right => new Angle(0);
public static Angle Up => new Angle(0.25);
public static Angle Full => new Angle(1);
public static Angle Half => new Angle(0.5);
public static Angle Quarter => new Angle(0.25);
public static Angle Zero => new Angle(0);
#if CS11_OR_GREATER
static Angle IPresets1d<Angle>.One => new Angle(1, Unit.Degrees);
#endif
public double Degrees
{
get => revTheta * 360;
set => revTheta = value / 360;
}
public double Gradians
{
get => revTheta * 400;
set => revTheta = value / 400;
}
public double Radians
{
get => revTheta * Constants.Tau;
set => revTheta = value / Constants.Tau;
}
public double Revolutions
{
get => revTheta;
set => revTheta = value;
}
public Angle Complimentary => new Angle(0.25 - MathE.AbsoluteMod(revTheta, 1));
public Angle Supplimentary => new Angle(0.5 - MathE.AbsoluteMod(revTheta, 1));
public Angle Normalized => new Angle(MathE.AbsoluteMod(revTheta, 1));
public Angle Reflected => new Angle(MathE.AbsoluteMod(-revTheta, 1));
private double revTheta;
public Angle(double theta, Unit unit)
{
switch (unit)
{
case Unit.Revolutions: revTheta = theta; break;
case Unit.Degrees: revTheta = theta / 360; break;
case Unit.Radians: revTheta = theta / Constants.Tau; break;
case Unit.Gradians: revTheta = theta / 400; break;
default: throw new ArgumentException($"Unknown angle unit \"{unit}.\"", nameof(unit));
}
}
private Angle(double revTheta)
{
this.revTheta = revTheta;
}
public double this[Unit unit]
{
get
{
switch (unit)
{
case Unit.Revolutions: return revTheta;
case Unit.Degrees: return revTheta * 360;
case Unit.Radians: return revTheta * Constants.Tau;
case Unit.Gradians: return revTheta * 400;
default: throw new ArgumentException($"Unknown angle unit \"{unit}.\"", nameof(unit));
}
}
set
{
switch (unit)
{
case Unit.Revolutions: revTheta = value; break;
case Unit.Degrees: revTheta = value / 360; break;
case Unit.Radians: revTheta = value / Constants.Tau; break;
case Unit.Gradians: revTheta = value / 400; break;
default: throw new ArgumentException($"Unknown angle unit \"{unit}.\"", nameof(unit));
}
}
}
public static Angle Average(IEnumerable<Angle> angles)
{
Angle sum = Zero;
int count = 0;
foreach (Angle ang in angles)
{
sum += ang;
count++;
}
return sum;
}
public static Angle Clamp(Angle value, Angle min, Angle max) =>
new Angle(MathE.Clamp(value.revTheta, min.revTheta, max.revTheta));
public static void Clamp(ref Angle value, Angle min, Angle max) =>
MathE.Clamp(ref value.revTheta, min.revTheta, max.revTheta);
public static Angle Max(IEnumerable<Angle> values) => Max(false, values);
public static Angle Max(bool normalize, IEnumerable<Angle> values)
{
bool any = false;
Angle best = Zero;
double bestNormalized = 0;
foreach (Angle ang in values)
{
if (!any)
{
best = ang;
if (normalize) bestNormalized = MathE.AbsoluteMod(ang.revTheta, 1);
any = true;
}
else if (normalize)
{
double angNormalized = MathE.AbsoluteMod(ang.revTheta, 1);
if (angNormalized > bestNormalized)
{
best = ang;
bestNormalized = angNormalized;
}
}
else if (ang.revTheta > best.revTheta) best = ang;
}
return best;
}
public static Angle Min(IEnumerable<Angle> values) => Min(false, values);
public static Angle Min(bool normalize, IEnumerable<Angle> values)
{
bool any = false;
Angle best = Zero;
double bestNormalized = 0;
foreach (Angle ang in values)
{
if (!any)
{
best = ang;
if (normalize) bestNormalized = MathE.AbsoluteMod(ang.revTheta, 1);
any = true;
}
else if (normalize)
{
double angNormalized = MathE.AbsoluteMod(ang.revTheta, 1);
if (angNormalized < bestNormalized)
{
best = ang;
bestNormalized = angNormalized;
}
}
else if (ang.revTheta < best.revTheta) best = ang;
}
return best;
}
public static Angle Sum(IEnumerable<Angle> angles)
{
Angle sum = Zero;
foreach (Angle ang in angles) sum += ang;
return sum;
}
public static double[] SplitArray(Unit unit, IEnumerable<Angle> values)
{
int count = values.Count();
double[] angles = new double[count];
int index = 0;
foreach (Angle val in values)
{
angles[index] = val[unit];
index++;
}
return angles;
}
public void Modify(Action<Angle> action) => action(this);
public int CompareTo(Angle other) => revTheta.CompareTo(other.revTheta);
public bool Equals(Angle other) => revTheta == other.revTheta;
#if CS8_OR_GREATER
public override bool Equals(object? other)
#else
public override bool Equals(object other)
#endif
{
if (other is null) return false;
else if (other is Angle otherAng) return Equals(otherAng);
else return false;
}
public override int GetHashCode() => revTheta.GetHashCode();
public override string ToString() => ToString(Unit.Degrees, null);
public string ToString(Unit unit) => ToString(unit, null);
#if CS8_OR_GREATER
public string ToString(string? format) =>
#else
public string ToString(string format) =>
#endif
ToString(Unit.Degrees, format);
#if CS8_OR_GREATER
public string ToString(Unit unit, string? format)
#else
public string ToString(Unit unit, string format)
#endif
{
switch (unit)
{
case Unit.Revolutions: return $"{revTheta.ToString(format)} rev";
case Unit.Degrees: return $"{(revTheta * 360).ToString(format)} deg";
case Unit.Radians: return $"{(revTheta * Constants.Tau).ToString(format)} rad";
case Unit.Gradians: return $"{(revTheta * 400).ToString(format)} grad";
default: throw new ArgumentException($"Unknown angle unit \"{unit}.\"", nameof(unit));
}
}
public static Angle operator +(Angle a, Angle b) => new Angle(a.revTheta + b.revTheta);
public static Angle operator -(Angle a) => new Angle(-a.revTheta);
public static Angle operator -(Angle a, Angle b) => new Angle(a.revTheta - b.revTheta);
public static Angle operator *(Angle a, double b) => new Angle(a.revTheta * b);
public static Angle operator /(Angle a, double b) => new Angle(a.revTheta / b);
public static bool operator ==(Angle a, Angle b) => a.Equals(b);
public static bool operator !=(Angle a, Angle b) => !a.Equals(b);
public static bool operator >(Angle a, Angle b) => a.CompareTo(b) > 0;
public static bool operator <(Angle a, Angle b) => a.CompareTo(b) < 0;
public static bool operator >=(Angle a, Angle b) => a.CompareTo(b) >= 0;
public static bool operator <=(Angle a, Angle b) => a.CompareTo(b) <= 0;
public static implicit operator Angle((double, Unit) tuple) => new Angle(tuple.Item1, tuple.Item2);
#if CS11_OR_GREATER
static implicit IFromTuple<Angle, (double, Unit)>.operator ValueTuple<double, Unit>(Angle angle) => (angle.revTheta, Unit.Revolutions);
#endif
public enum Unit
{
Revolutions,
Degrees,
Radians,
Gradians
}
}
}

View File

@ -23,5 +23,17 @@ namespace Nerd_STF.Mathematics.Equations
double Integrate(double lower, double upper); double Integrate(double lower, double upper);
// TODO: Solve // TODO: Solve
#if CS8_OR_GREATER
static IEquation operator +(IEquation a, IEquation b) => a.Add(b);
static IEquation operator +(IEquation a, double b) => a.Add(b);
static IEquation operator -(IEquation a) => a.Negate();
static IEquation operator -(IEquation a, IEquation b) => a.Subtract(b);
static IEquation operator -(IEquation a, double b) => a.Subtract(b);
static IEquation operator *(IEquation a, IEquation b) => a.Multiply(b);
static IEquation operator *(IEquation a, double b) => a.Multiply(b);
static IEquation operator /(IEquation a, IEquation b) => a.Divide(b);
static IEquation operator /(IEquation a, double b) => a.Divide(b);
#endif
} }
} }

View File

@ -79,6 +79,8 @@ namespace Nerd_STF.Mathematics.Equations
public IEquation Add(IEquation other) public IEquation Add(IEquation other)
{ {
if (other is Polynomial otherPoly) return Add(otherPoly); if (other is Polynomial otherPoly) return Add(otherPoly);
else if (other is Quadratic otherQuad) return Add((Polynomial)otherQuad);
else if (other is Linear otherLinear) return Add((Polynomial)otherLinear);
else return new Equation((double x) => Get(x) + other.Get(x)); else return new Equation((double x) => Get(x) + other.Get(x));
} }
public Polynomial Add(double constant) public Polynomial Add(double constant)

View File

@ -183,6 +183,7 @@ namespace Nerd_STF.Mathematics.Equations
public static Polynomial operator *(Quadratic a, double b) => a.Multiply(b); public static Polynomial operator *(Quadratic a, double b) => a.Multiply(b);
public static IEquation operator /(Quadratic a, IEquation b) => a.Divide(b); public static IEquation operator /(Quadratic a, IEquation b) => a.Divide(b);
public static Quadratic operator /(Quadratic a, double b) => a.Divide(b); public static Quadratic operator /(Quadratic a, double b) => a.Divide(b);
public static bool operator ==(Quadratic a, Quadratic b) => a.Equals(b); public static bool operator ==(Quadratic a, Quadratic b) => a.Equals(b);
public static bool operator ==(Quadratic a, Polynomial b) => a.Equals(b); public static bool operator ==(Quadratic a, Polynomial b) => a.Equals(b);
public static bool operator !=(Quadratic a, Quadratic b) => !a.Equals(b); public static bool operator !=(Quadratic a, Quadratic b) => !a.Equals(b);

View File

@ -1,9 +1,8 @@
using Nerd_STF.Exceptions; using Nerd_STF.Abstract;
using Nerd_STF.Mathematics.Abstract; using Nerd_STF.Exceptions;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
@ -13,6 +12,7 @@ namespace Nerd_STF.Mathematics
#if CS11_OR_GREATER #if CS11_OR_GREATER
,IFromTuple<Float2, (double, double)>, ,IFromTuple<Float2, (double, double)>,
IPresets2d<Float2>, IPresets2d<Float2>,
IRoundable<Float2, Int2>,
ISplittable<Float2, (double[] Xs, double[] Ys)> ISplittable<Float2, (double[] Xs, double[] Ys)>
#endif #endif
{ {
@ -236,6 +236,8 @@ namespace Nerd_STF.Mathematics
y = this.y; y = this.y;
} }
public void Modify(Action<Float2> action) => action(this);
public bool Equals(Float2 other) => x == other.x && y == other.y; public bool Equals(Float2 other) => x == other.x && y == other.y;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -1,5 +1,5 @@
using Nerd_STF.Exceptions; using Nerd_STF.Abstract;
using Nerd_STF.Mathematics.Abstract; using Nerd_STF.Exceptions;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -11,6 +11,7 @@ namespace Nerd_STF.Mathematics
#if CS11_OR_GREATER #if CS11_OR_GREATER
,IFromTuple<Float3, (double, double, double)>, ,IFromTuple<Float3, (double, double, double)>,
IPresets2d<Float3>, IPresets2d<Float3>,
IRoundable<Float3, Int3>,
ISplittable<Float3, (double[] Xs, double[] Ys, double[] Zs)> ISplittable<Float3, (double[] Xs, double[] Ys, double[] Zs)>
#endif #endif
{ {
@ -261,6 +262,8 @@ namespace Nerd_STF.Mathematics
z = this.z; z = this.z;
} }
public void Modify(Action<Float3> action) => action(this);
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;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -2,8 +2,8 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Nerd_STF.Abstract;
using Nerd_STF.Exceptions; using Nerd_STF.Exceptions;
using Nerd_STF.Mathematics.Abstract;
namespace Nerd_STF.Mathematics namespace Nerd_STF.Mathematics
{ {
@ -11,6 +11,7 @@ namespace Nerd_STF.Mathematics
#if CS11_OR_GREATER #if CS11_OR_GREATER
,IFromTuple<Float4, (double, double, double, double)>, ,IFromTuple<Float4, (double, double, double, double)>,
IPresets4d<Float4>, IPresets4d<Float4>,
IRoundable<Float4, Int4>,
ISplittable<Float4, (double[] Ws, double[] Xs, double[] Ys, double[] Zs)> ISplittable<Float4, (double[] Ws, double[] Xs, double[] Ys, double[] Zs)>
#endif #endif
{ {
@ -281,6 +282,8 @@ namespace Nerd_STF.Mathematics
z = this.z; z = this.z;
} }
public void Modify(Action<Float4> action) => action(this);
public bool Equals(Float4 other) => w == other.w && x == other.x && y == other.y && z == other.z; public bool Equals(Float4 other) => w == other.w && x == other.x && y == other.y && z == other.z;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -1,5 +1,5 @@
using Nerd_STF.Exceptions; using Nerd_STF.Abstract;
using Nerd_STF.Mathematics.Abstract; using Nerd_STF.Exceptions;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -120,27 +120,27 @@ namespace Nerd_STF.Mathematics
MathE.Clamp(ref value.x, min.x, max.x); MathE.Clamp(ref value.x, min.x, max.x);
MathE.Clamp(ref value.y, min.y, max.y); MathE.Clamp(ref value.y, min.y, max.y);
} }
public static Int2 ClampMagnitude(Int2 value, int minMag, int maxMag) public static Int2 ClampMagnitude(Int2 value, double minMag, double maxMag)
{ {
Int2 copy = value; Int2 copy = value;
ClampMagnitude(ref copy, minMag, maxMag); ClampMagnitude(ref copy, minMag, maxMag);
return copy; return copy;
} }
public static void ClampMagnitude(ref Int2 value, int minMag, int maxMag) public static void ClampMagnitude(ref Int2 value, double minMag, double maxMag)
{ {
if (minMag > maxMag) throw new ClampOrderMismatchException(nameof(minMag), nameof(maxMag)); if (minMag > maxMag) throw new ClampOrderMismatchException(nameof(minMag), nameof(maxMag));
double mag = value.Magnitude; double mag = value.Magnitude;
if (mag < minMag) if (mag < minMag)
{ {
double factor = minMag / mag; double factor = minMag / mag;
value.x = (int)(value.x * factor); value.x = MathE.Ceiling(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Ceiling(value.y * factor);
} }
else if (mag > maxMag) else if (mag > maxMag)
{ {
double factor = maxMag / mag; double factor = maxMag / mag;
value.x = (int)(value.x * factor); value.x = MathE.Floor(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Floor(value.y * factor);
} }
} }
public static Int3 Cross(Int2 a, Int2 b) => Int3.Cross(a, b); public static Int3 Cross(Int2 a, Int2 b) => Int3.Cross(a, b);
@ -155,6 +155,10 @@ namespace Nerd_STF.Mathematics
} }
return x + y; return x + y;
} }
#if CS11_OR_GREATER
static double IVectorOperations<Int2>.Dot(Int2 a, Int2 b) => Dot(a, b);
static double IVectorOperations<Int2>.Dot(IEnumerable<Int2> vals) => Dot(vals);
#endif
public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) => public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) =>
new Int2(MathE.Lerp(a.x, b.x, t, clamp), new Int2(MathE.Lerp(a.x, b.x, t, clamp),
MathE.Lerp(a.y, b.y, t, clamp)); MathE.Lerp(a.y, b.y, t, clamp));
@ -203,6 +207,8 @@ namespace Nerd_STF.Mathematics
y = this.y; y = this.y;
} }
public void Modify(Action<Int2> action) => action(this);
public bool Equals(Int2 other) => x == other.x && y == other.y; public bool Equals(Int2 other) => x == other.x && y == other.y;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -1,5 +1,5 @@
using Nerd_STF.Exceptions; using Nerd_STF.Abstract;
using Nerd_STF.Mathematics.Abstract; using Nerd_STF.Exceptions;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -129,13 +129,13 @@ namespace Nerd_STF.Mathematics
MathE.Clamp(ref value.y, min.y, max.y); MathE.Clamp(ref value.y, min.y, max.y);
MathE.Clamp(ref value.z, min.z, max.z); MathE.Clamp(ref value.z, min.z, max.z);
} }
public static Int3 ClampMagnitude(Int3 value, int minMag, int maxMag) public static Int3 ClampMagnitude(Int3 value, double minMag, double maxMag)
{ {
Int3 copy = value; Int3 copy = value;
ClampMagnitude(ref copy, minMag, maxMag); ClampMagnitude(ref copy, minMag, maxMag);
return copy; return copy;
} }
public static void ClampMagnitude(ref Int3 value, int minMag, int maxMag) public static void ClampMagnitude(ref Int3 value, double minMag, double maxMag)
{ {
if (minMag > maxMag) throw new ClampOrderMismatchException(nameof(minMag), nameof(maxMag)); if (minMag > maxMag) throw new ClampOrderMismatchException(nameof(minMag), nameof(maxMag));
double mag = value.Magnitude; double mag = value.Magnitude;
@ -143,16 +143,16 @@ namespace Nerd_STF.Mathematics
if (mag < minMag) if (mag < minMag)
{ {
double factor = minMag / mag; double factor = minMag / mag;
value.x = (int)(value.x * factor); value.x = MathE.Ceiling(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Ceiling(value.y * factor);
value.z = (int)(value.z * factor); value.z = MathE.Ceiling(value.z * factor);
} }
else if (mag > maxMag) else if (mag > maxMag)
{ {
double factor = maxMag / mag; double factor = maxMag / mag;
value.x = (int)(value.x * factor); value.x = MathE.Floor(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Floor(value.y * factor);
value.z = (int)(value.z * factor); value.z = MathE.Floor(value.z * factor);
} }
} }
public static Int3 Cross(Int3 a, Int3 b) => public static Int3 Cross(Int3 a, Int3 b) =>
@ -171,6 +171,10 @@ namespace Nerd_STF.Mathematics
} }
return x + y + z; return x + y + z;
} }
#if CS11_OR_GREATER
static double IVectorOperations<Int3>.Dot(Int3 a, Int3 b) => Dot(a, b);
static double IVectorOperations<Int3>.Dot(IEnumerable<Int3> vals) => Dot(vals);
#endif
public static Int3 Lerp(Int3 a, Int3 b, double t, bool clamp = true) => public static Int3 Lerp(Int3 a, Int3 b, double t, bool clamp = true) =>
new Int3(MathE.Lerp(a.x, b.x, t, clamp), new Int3(MathE.Lerp(a.x, b.x, t, clamp),
MathE.Lerp(a.y, b.y, t, clamp), MathE.Lerp(a.y, b.y, t, clamp),
@ -223,6 +227,8 @@ namespace Nerd_STF.Mathematics
z = this.z; z = this.z;
} }
public void Modify(Action<Int3> action) => action(this);
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;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -1,9 +1,9 @@
using System; using Nerd_STF.Abstract;
using Nerd_STF.Exceptions;
using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Nerd_STF.Exceptions;
using Nerd_STF.Mathematics.Abstract;
namespace Nerd_STF.Mathematics namespace Nerd_STF.Mathematics
{ {
@ -152,18 +152,18 @@ namespace Nerd_STF.Mathematics
if (mag < minMag) if (mag < minMag)
{ {
double factor = minMag / mag; double factor = minMag / mag;
value.w = (int)(value.w * factor); value.w = MathE.Ceiling(value.w * factor);
value.x = (int)(value.x * factor); value.x = MathE.Ceiling(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Ceiling(value.y * factor);
value.z = (int)(value.z * factor); value.z = MathE.Ceiling(value.z * factor);
} }
else if (mag > maxMag) else if (mag > maxMag)
{ {
double factor = maxMag / mag; double factor = maxMag / mag;
value.w = (int)(value.w * factor); value.w = MathE.Floor(value.w * factor);
value.x = (int)(value.x * factor); value.x = MathE.Floor(value.x * factor);
value.y = (int)(value.y * factor); value.y = MathE.Floor(value.y * factor);
value.z = (int)(value.z * factor); value.z = MathE.Floor(value.z * factor);
} }
} }
public static int Dot(Int4 a, Int4 b) => a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z; public static int Dot(Int4 a, Int4 b) => a.w * b.w + a.x * b.x + a.y * b.y + a.z * b.z;
@ -179,6 +179,10 @@ namespace Nerd_STF.Mathematics
} }
return w + x + y + z; return w + x + y + z;
} }
#if CS11_OR_GREATER
static double IVectorOperations<Int4>.Dot(Int4 a, Int4 b) => Dot(a, b);
static double IVectorOperations<Int4>.Dot(IEnumerable<Int4> vals) => Dot(vals);
#endif
public static Int4 Lerp(Int4 a, Int4 b, double t, bool clamp = true) => public static Int4 Lerp(Int4 a, Int4 b, double t, bool clamp = true) =>
new Int4(MathE.Lerp(a.w, b.w, t, clamp), new Int4(MathE.Lerp(a.w, b.w, t, clamp),
MathE.Lerp(a.x, b.x, t, clamp), MathE.Lerp(a.x, b.x, t, clamp),
@ -235,6 +239,8 @@ namespace Nerd_STF.Mathematics
z = this.z; z = this.z;
} }
public void Modify(Action<Int4> action) => action(this);
public bool Equals(Int4 other) => w == other.w && x == other.x && y == other.y && z == other.z; public bool Equals(Int4 other) => w == other.w && x == other.x && y == other.y && z == other.z;
#if CS8_OR_GREATER #if CS8_OR_GREATER
public override bool Equals(object? obj) public override bool Equals(object? obj)

View File

@ -435,7 +435,7 @@ namespace Nerd_STF.Mathematics
} }
else if (val > best) best = val; else if (val > best) best = val;
} }
return any ? best : 0; return best;
} }
public static double Max(IEnumerable<double> values) public static double Max(IEnumerable<double> values)
{ {
@ -488,7 +488,7 @@ namespace Nerd_STF.Mathematics
} }
else if (val < best) best = val; else if (val < best) best = val;
} }
return any ? best : 0; return best;
} }
public static double Min(IEnumerable<double> values) public static double Min(IEnumerable<double> values)
{ {

View File

@ -0,0 +1,70 @@
using System.Numerics;
namespace Nerd_STF.Mathematics.Numbers
{
public struct Fraction
{
public static Fraction One => new Fraction(1, 1);
public static Fraction Zero => new Fraction(0, 1);
public int numerator;
public int denominator;
public Fraction(int numerator, int denominator)
{
this.numerator = numerator;
this.denominator = denominator;
}
public static Fraction Approximate(double number, int iterations = 32)
{
// Forget what this algorithm is called. When I remember, I'll put its
// Wikipedia page here.
if (number == 0) return Zero;
else if (number == 1) return One;
else if (number < 0)
{
Fraction result = Approximate(-number, iterations);
result.numerator = -result.numerator;
return result;
}
else if (number > 1)
{
int whole = (int)number;
Fraction result = Approximate(number % 1, iterations);
result.numerator += whole * result.denominator;
return result;
}
int minNum = 0, maxNum = 1, newNum = minNum + maxNum,
minDen = 1, maxDen = 1, newDen = minDen + maxDen;
double newVal = (double)newNum / newDen;
for (int i = 0; i < iterations; i++)
{
if (number == newVal) break;
else if (number > newVal)
{
minNum = newNum;
minDen = newDen;
}
else // if (number < newVal)
{
maxNum = newNum;
maxDen = newDen;
}
newNum = minNum + maxNum;
newDen = minDen + maxDen;
newVal = (double)newNum / newDen;
}
return new Fraction(newNum, newDen);
}
public double GetValue() => (double)numerator / denominator;
public override string ToString() => $"{numerator} / {denominator}";
public static implicit operator double(Fraction frac) => frac.GetValue();
public static explicit operator Fraction(double num) => Approximate(num);
}
}

View File

@ -7,7 +7,7 @@
<DebugType>embedded</DebugType> <DebugType>embedded</DebugType>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild> <GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>Nerd_STF</Title> <Title>Nerd_STF</Title>
<Version>3.0.0-beta1</Version> <Version>3.0.0-beta2</Version>
<Authors>That_One_Nerd</Authors> <Authors>That_One_Nerd</Authors>
<Description>A general-purpose mathematics library for C#.</Description> <Description>A general-purpose mathematics library for C#.</Description>
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl> <PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>