Lots of nice changes. Made angle, more interfaces, working on fraction.
This commit is contained in:
parent
467b5903cc
commit
0704b8eec7
@ -1,6 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract
|
||||
namespace Nerd_STF.Abstract
|
||||
{
|
||||
public interface ICombinationIndexer<TItem>
|
||||
{
|
||||
@ -1,14 +1,14 @@
|
||||
#if CS11_OR_GREATER
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract
|
||||
namespace Nerd_STF.Abstract
|
||||
{
|
||||
public interface IFromTuple<TSelf, TTuple>
|
||||
where TSelf : IFromTuple<TSelf, TTuple>
|
||||
where TTuple : struct, ITuple
|
||||
{
|
||||
public static abstract implicit operator TSelf(TTuple tuple);
|
||||
public static abstract implicit operator TTuple(TSelf tuple);
|
||||
static abstract implicit operator TSelf(TTuple tuple);
|
||||
static abstract implicit operator TTuple(TSelf tuple);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
10
Nerd_STF/Abstract/IInterpolable.cs
Normal file
10
Nerd_STF/Abstract/IInterpolable.cs
Normal 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
|
||||
10
Nerd_STF/Abstract/IModifiable.cs
Normal file
10
Nerd_STF/Abstract/IModifiable.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Nerd_STF.Abstract
|
||||
{
|
||||
public interface IModifiable<TSelf>
|
||||
where TSelf : IModifiable<TSelf>
|
||||
{
|
||||
void Modify(Action<TSelf> action);
|
||||
}
|
||||
}
|
||||
26
Nerd_STF/Abstract/INumberGroup.cs
Normal file
26
Nerd_STF/Abstract/INumberGroup.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
10
Nerd_STF/Abstract/IPresets1d.cs
Normal file
10
Nerd_STF/Abstract/IPresets1d.cs
Normal 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
|
||||
13
Nerd_STF/Abstract/IPresets2d.cs
Normal file
13
Nerd_STF/Abstract/IPresets2d.cs
Normal 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
|
||||
11
Nerd_STF/Abstract/IPresets3d.cs
Normal file
11
Nerd_STF/Abstract/IPresets3d.cs
Normal 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
|
||||
@ -1,11 +1,11 @@
|
||||
#if CS11_OR_GREATER
|
||||
namespace Nerd_STF.Mathematics.Abstract
|
||||
namespace Nerd_STF.Abstract
|
||||
{
|
||||
public interface IPresets4d<TSelf> : IPresets3d<TSelf>
|
||||
where TSelf : IPresets4d<TSelf>
|
||||
{
|
||||
public static abstract TSelf LowW { get; }
|
||||
public static abstract TSelf HighW { get; }
|
||||
static abstract TSelf LowW { get; }
|
||||
static abstract TSelf HighW { get; }
|
||||
}
|
||||
}
|
||||
#endif
|
||||
19
Nerd_STF/Abstract/IRoundable.cs
Normal file
19
Nerd_STF/Abstract/IRoundable.cs
Normal 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
|
||||
17
Nerd_STF/Abstract/ISimpleMathOperations.cs
Normal file
17
Nerd_STF/Abstract/ISimpleMathOperations.cs
Normal 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
|
||||
@ -2,13 +2,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Nerd_STF.Mathematics.Abstract
|
||||
namespace Nerd_STF.Abstract
|
||||
{
|
||||
public interface ISplittable<TSelf, TTuple>
|
||||
where TSelf : ISplittable<TSelf, TTuple>
|
||||
where TTuple : struct, ITuple
|
||||
{
|
||||
public static abstract TTuple SplitArray(IEnumerable<TSelf> values);
|
||||
static abstract TTuple SplitArray(IEnumerable<TSelf> values);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
17
Nerd_STF/Abstract/IVectorOperations.cs
Normal file
17
Nerd_STF/Abstract/IVectorOperations.cs
Normal 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
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
253
Nerd_STF/Mathematics/Angle.cs
Normal file
253
Nerd_STF/Mathematics/Angle.cs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -23,5 +23,17 @@ namespace Nerd_STF.Mathematics.Equations
|
||||
double Integrate(double lower, double upper);
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,6 +79,8 @@ namespace Nerd_STF.Mathematics.Equations
|
||||
public IEquation Add(IEquation other)
|
||||
{
|
||||
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));
|
||||
}
|
||||
public Polynomial Add(double constant)
|
||||
|
||||
@ -183,6 +183,7 @@ namespace Nerd_STF.Mathematics.Equations
|
||||
public static Polynomial operator *(Quadratic a, double b) => a.Multiply(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 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, Quadratic b) => !a.Equals(b);
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
|
||||
@ -13,6 +12,7 @@ namespace Nerd_STF.Mathematics
|
||||
#if CS11_OR_GREATER
|
||||
,IFromTuple<Float2, (double, double)>,
|
||||
IPresets2d<Float2>,
|
||||
IRoundable<Float2, Int2>,
|
||||
ISplittable<Float2, (double[] Xs, double[] Ys)>
|
||||
#endif
|
||||
{
|
||||
@ -236,6 +236,8 @@ namespace Nerd_STF.Mathematics
|
||||
y = this.y;
|
||||
}
|
||||
|
||||
public void Modify(Action<Float2> action) => action(this);
|
||||
|
||||
public bool Equals(Float2 other) => x == other.x && y == other.y;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@ -11,6 +11,7 @@ namespace Nerd_STF.Mathematics
|
||||
#if CS11_OR_GREATER
|
||||
,IFromTuple<Float3, (double, double, double)>,
|
||||
IPresets2d<Float3>,
|
||||
IRoundable<Float3, Int3>,
|
||||
ISplittable<Float3, (double[] Xs, double[] Ys, double[] Zs)>
|
||||
#endif
|
||||
{
|
||||
@ -261,6 +262,8 @@ namespace Nerd_STF.Mathematics
|
||||
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;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -2,8 +2,8 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
namespace Nerd_STF.Mathematics
|
||||
{
|
||||
@ -11,6 +11,7 @@ namespace Nerd_STF.Mathematics
|
||||
#if CS11_OR_GREATER
|
||||
,IFromTuple<Float4, (double, double, double, double)>,
|
||||
IPresets4d<Float4>,
|
||||
IRoundable<Float4, Int4>,
|
||||
ISplittable<Float4, (double[] Ws, double[] Xs, double[] Ys, double[] Zs)>
|
||||
#endif
|
||||
{
|
||||
@ -281,6 +282,8 @@ namespace Nerd_STF.Mathematics
|
||||
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;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
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.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;
|
||||
ClampMagnitude(ref copy, minMag, maxMag);
|
||||
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));
|
||||
double mag = value.Magnitude;
|
||||
if (mag < minMag)
|
||||
{
|
||||
double factor = minMag / mag;
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.x = MathE.Ceiling(value.x * factor);
|
||||
value.y = MathE.Ceiling(value.y * factor);
|
||||
}
|
||||
else if (mag > maxMag)
|
||||
{
|
||||
double factor = maxMag / mag;
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.x = MathE.Floor(value.x * factor);
|
||||
value.y = MathE.Floor(value.y * factor);
|
||||
}
|
||||
}
|
||||
public static Int3 Cross(Int2 a, Int2 b) => Int3.Cross(a, b);
|
||||
@ -155,6 +155,10 @@ namespace Nerd_STF.Mathematics
|
||||
}
|
||||
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) =>
|
||||
new Int2(MathE.Lerp(a.x, b.x, t, clamp),
|
||||
MathE.Lerp(a.y, b.y, t, clamp));
|
||||
@ -203,6 +207,8 @@ namespace Nerd_STF.Mathematics
|
||||
y = this.y;
|
||||
}
|
||||
|
||||
public void Modify(Action<Int2> action) => action(this);
|
||||
|
||||
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
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.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;
|
||||
ClampMagnitude(ref copy, minMag, maxMag);
|
||||
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));
|
||||
double mag = value.Magnitude;
|
||||
@ -143,16 +143,16 @@ namespace Nerd_STF.Mathematics
|
||||
if (mag < minMag)
|
||||
{
|
||||
double factor = minMag / mag;
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.z = (int)(value.z * factor);
|
||||
value.x = MathE.Ceiling(value.x * factor);
|
||||
value.y = MathE.Ceiling(value.y * factor);
|
||||
value.z = MathE.Ceiling(value.z * factor);
|
||||
}
|
||||
else if (mag > maxMag)
|
||||
{
|
||||
double factor = maxMag / mag;
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.z = (int)(value.z * factor);
|
||||
value.x = MathE.Floor(value.x * factor);
|
||||
value.y = MathE.Floor(value.y * factor);
|
||||
value.z = MathE.Floor(value.z * factor);
|
||||
}
|
||||
}
|
||||
public static Int3 Cross(Int3 a, Int3 b) =>
|
||||
@ -171,6 +171,10 @@ namespace Nerd_STF.Mathematics
|
||||
}
|
||||
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) =>
|
||||
new Int3(MathE.Lerp(a.x, b.x, t, clamp),
|
||||
MathE.Lerp(a.y, b.y, t, clamp),
|
||||
@ -223,6 +227,8 @@ namespace Nerd_STF.Mathematics
|
||||
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;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using Nerd_STF.Abstract;
|
||||
using Nerd_STF.Exceptions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nerd_STF.Exceptions;
|
||||
using Nerd_STF.Mathematics.Abstract;
|
||||
|
||||
namespace Nerd_STF.Mathematics
|
||||
{
|
||||
@ -152,18 +152,18 @@ namespace Nerd_STF.Mathematics
|
||||
if (mag < minMag)
|
||||
{
|
||||
double factor = minMag / mag;
|
||||
value.w = (int)(value.w * factor);
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.z = (int)(value.z * factor);
|
||||
value.w = MathE.Ceiling(value.w * factor);
|
||||
value.x = MathE.Ceiling(value.x * factor);
|
||||
value.y = MathE.Ceiling(value.y * factor);
|
||||
value.z = MathE.Ceiling(value.z * factor);
|
||||
}
|
||||
else if (mag > maxMag)
|
||||
{
|
||||
double factor = maxMag / mag;
|
||||
value.w = (int)(value.w * factor);
|
||||
value.x = (int)(value.x * factor);
|
||||
value.y = (int)(value.y * factor);
|
||||
value.z = (int)(value.z * factor);
|
||||
value.w = MathE.Floor(value.w * factor);
|
||||
value.x = MathE.Floor(value.x * factor);
|
||||
value.y = MathE.Floor(value.y * 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;
|
||||
@ -179,6 +179,10 @@ namespace Nerd_STF.Mathematics
|
||||
}
|
||||
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) =>
|
||||
new Int4(MathE.Lerp(a.w, b.w, t, clamp),
|
||||
MathE.Lerp(a.x, b.x, t, clamp),
|
||||
@ -235,6 +239,8 @@ namespace Nerd_STF.Mathematics
|
||||
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;
|
||||
#if CS8_OR_GREATER
|
||||
public override bool Equals(object? obj)
|
||||
|
||||
@ -435,7 +435,7 @@ namespace Nerd_STF.Mathematics
|
||||
}
|
||||
else if (val > best) best = val;
|
||||
}
|
||||
return any ? best : 0;
|
||||
return best;
|
||||
}
|
||||
public static double Max(IEnumerable<double> values)
|
||||
{
|
||||
@ -488,7 +488,7 @@ namespace Nerd_STF.Mathematics
|
||||
}
|
||||
else if (val < best) best = val;
|
||||
}
|
||||
return any ? best : 0;
|
||||
return best;
|
||||
}
|
||||
public static double Min(IEnumerable<double> values)
|
||||
{
|
||||
|
||||
70
Nerd_STF/Mathematics/Numbers/Fraction.cs
Normal file
70
Nerd_STF/Mathematics/Numbers/Fraction.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,7 @@
|
||||
<DebugType>embedded</DebugType>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Title>Nerd_STF</Title>
|
||||
<Version>3.0.0-beta1</Version>
|
||||
<Version>3.0.0-beta2</Version>
|
||||
<Authors>That_One_Nerd</Authors>
|
||||
<Description>A general-purpose mathematics library for C#.</Description>
|
||||
<PackageProjectUrl>https://github.com/That-One-Nerd/Nerd_STF</PackageProjectUrl>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user