Version 2.1.1
This commit is contained in:
parent
4be41701cd
commit
97c189c296
86
Changelog.md
86
Changelog.md
@ -1,82 +1,12 @@
|
|||||||
# Nerd_STF v2.1.0
|
# Nerd_STF v2.1.1
|
||||||
|
|
||||||
|
This update doesn't add any new features, simply a code simplification, using some of the .net 6 tools, such as global usings and file-scoped namespace declarations.
|
||||||
|
|
||||||
```
|
```
|
||||||
* Nerd_STF
|
* Nerd_STF
|
||||||
+ Exceptions
|
= Removed unused or unrequired usings in all files.
|
||||||
+ Nerd_STFException
|
= Replaced all namespace declarations with file-scoped declarations.
|
||||||
+ DifferingVertCountException
|
* Miscellaneous
|
||||||
+ DisconnectedLinesException
|
* GlobalUsings
|
||||||
+ Miscellaneous
|
+ global using System.Diagnostics.CodeAnalysis
|
||||||
+ `GlobalUsings.cs`
|
|
||||||
+ IClosest<T>
|
|
||||||
+ IContainer<T>
|
|
||||||
* Logger
|
|
||||||
* DefaultLogHandler(LogMessage)
|
|
||||||
= Replaced a `throw new Exception` with a `throw new ArgumentException`
|
|
||||||
* Mathematics
|
|
||||||
+ Angle
|
|
||||||
+ Calculus
|
|
||||||
+ delegate double Equation(double)
|
|
||||||
* Double2
|
|
||||||
= Made `CompareTo(Double2)` better
|
|
||||||
* Double3
|
|
||||||
= Made `CompareTo(Double3)` better
|
|
||||||
* Double4
|
|
||||||
= Made `CompareTo(Double4)` better
|
|
||||||
* Int2
|
|
||||||
+ operator &(Int2, Int2)
|
|
||||||
+ operator |(Int2, Int2)
|
|
||||||
+ operator ^(Int2, Int2)
|
|
||||||
= Made `CompareTo(Int2)` better
|
|
||||||
* Int3
|
|
||||||
+ operator &(Int3, Int3)
|
|
||||||
+ operator |(Int3, Int3)
|
|
||||||
+ operator ^(Int3, Int3)
|
|
||||||
= Made `CompareTo(Int3)` better
|
|
||||||
* Int4
|
|
||||||
+ operator &(Int4, Int4)
|
|
||||||
+ operator |(Int4, Int4)
|
|
||||||
+ operator ^(Int4, Int4)
|
|
||||||
= Made `CompareTo(Int4)` better
|
|
||||||
* Mathf
|
|
||||||
+ Average(Equation, double, double, double)
|
|
||||||
+ GetValues(Equation)
|
|
||||||
+ MakeEquation(Dictionary<double, double>)
|
|
||||||
+ Max(Equation, double, double, double)
|
|
||||||
+ Min(Equation, double, double, double)
|
|
||||||
= Swapped the names of "RadToDeg" and "DegToRad"
|
|
||||||
* Geometry
|
|
||||||
+ Box2D
|
|
||||||
+ Box3D
|
|
||||||
+ Polygon
|
|
||||||
+ Quadrilateral
|
|
||||||
+ Sphere
|
|
||||||
+ ISubdividable
|
|
||||||
* ITriangulatable
|
|
||||||
+ Triangle[] TriangulateAll(params ITriangulatable[])
|
|
||||||
* Line
|
|
||||||
+ : IComparable<Line>
|
|
||||||
+ : IContainer<Vert>
|
|
||||||
+ : IClosest<Vert>
|
|
||||||
+ : ISubdividable<Line[]>
|
|
||||||
+ ClosestTo(Vert)
|
|
||||||
+ ClosestTo(Vert, double)
|
|
||||||
+ CompareTo(Line)
|
|
||||||
+ Contains(Vert)
|
|
||||||
+ Subdivide()
|
|
||||||
+ operator -(Line)
|
|
||||||
+ operator >(Line)
|
|
||||||
+ operator <(Line)
|
|
||||||
+ operator >=(Line)
|
|
||||||
+ operator <=(Line)
|
|
||||||
= Renamed all instances of "start" to "a"
|
|
||||||
= Renamed all instances of "end" to "b"
|
|
||||||
* Triangle
|
|
||||||
+ operator -(Triangle)
|
|
||||||
+ ToDoubleArrayAll(params Triangle[])
|
|
||||||
= Replaced the variable assignings in the Triangle to not re-assign the lines.
|
|
||||||
= Now uses custom exception in line constructor
|
|
||||||
= Renamed "L1" to "AB"
|
|
||||||
= Renamed "L2" to "BC"
|
|
||||||
= Renamed "L3" to "CA"
|
|
||||||
```
|
```
|
||||||
|
|||||||
@ -1,30 +1,28 @@
|
|||||||
using System.Runtime.Serialization;
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
namespace Nerd_STF.Exceptions
|
namespace Nerd_STF.Exceptions;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class DifferingVertCountException : Nerd_STFException
|
||||||
{
|
{
|
||||||
|
public string? ParamName;
|
||||||
|
public Polygon[]? Polygons;
|
||||||
|
|
||||||
[Serializable]
|
public DifferingVertCountException() : base("Not all polygons have the same vert count.") { }
|
||||||
public class DifferingVertCountException : Nerd_STFException
|
public DifferingVertCountException(Exception inner) : base("Not all polygons have the same vert count.", inner) { }
|
||||||
|
public DifferingVertCountException(string paramName) : this() => ParamName = paramName;
|
||||||
|
public DifferingVertCountException(string paramName, Exception inner) : this(inner) => ParamName = paramName;
|
||||||
|
public DifferingVertCountException(params Polygon[] polys) : this() => Polygons = polys;
|
||||||
|
public DifferingVertCountException(Polygon[] polys, Exception inner) : this(inner) => Polygons = polys;
|
||||||
|
public DifferingVertCountException(string paramName, Polygon[] polys) : this()
|
||||||
{
|
{
|
||||||
public string? ParamName;
|
ParamName = paramName;
|
||||||
public Polygon[]? Polygons;
|
Polygons = polys;
|
||||||
|
|
||||||
public DifferingVertCountException() : base("Not all polygons have the same vert count.") { }
|
|
||||||
public DifferingVertCountException(Exception inner) : base("Not all polygons have the same vert count.", inner) { }
|
|
||||||
public DifferingVertCountException(string paramName) : this() => ParamName = paramName;
|
|
||||||
public DifferingVertCountException(string paramName, Exception inner) : this(inner) => ParamName = paramName;
|
|
||||||
public DifferingVertCountException(params Polygon[] polys) : this() => Polygons = polys;
|
|
||||||
public DifferingVertCountException(Polygon[] polys, Exception inner) : this(inner) => Polygons = polys;
|
|
||||||
public DifferingVertCountException(string paramName, Polygon[] polys) : this()
|
|
||||||
{
|
|
||||||
ParamName = paramName;
|
|
||||||
Polygons = polys;
|
|
||||||
}
|
|
||||||
public DifferingVertCountException(string paramName, Polygon[] polys, Exception inner) : this(inner)
|
|
||||||
{
|
|
||||||
ParamName = paramName;
|
|
||||||
Polygons = polys;
|
|
||||||
}
|
|
||||||
protected DifferingVertCountException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
|
||||||
}
|
}
|
||||||
|
public DifferingVertCountException(string paramName, Polygon[] polys, Exception inner) : this(inner)
|
||||||
|
{
|
||||||
|
ParamName = paramName;
|
||||||
|
Polygons = polys;
|
||||||
|
}
|
||||||
|
protected DifferingVertCountException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,28 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
using System.Runtime.Serialization;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Exceptions
|
namespace Nerd_STF.Exceptions;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class DisconnectedLinesException : Nerd_STFException
|
||||||
{
|
{
|
||||||
[Serializable]
|
public string? ParamName;
|
||||||
public class DisconnectedLinesException : Nerd_STFException
|
public Line[]? Lines;
|
||||||
{
|
|
||||||
public string? ParamName;
|
|
||||||
public Line[]? Lines;
|
|
||||||
|
|
||||||
public DisconnectedLinesException() : base("Lines are not connected.") { }
|
public DisconnectedLinesException() : base("Lines are not connected.") { }
|
||||||
public DisconnectedLinesException(Exception inner) : base("Lines are not connected.", inner) { }
|
public DisconnectedLinesException(Exception inner) : base("Lines are not connected.", inner) { }
|
||||||
public DisconnectedLinesException(string paramName) : this() => ParamName = paramName;
|
public DisconnectedLinesException(string paramName) : this() => ParamName = paramName;
|
||||||
public DisconnectedLinesException(string paramName, Exception inner) : this(inner) => ParamName = paramName;
|
public DisconnectedLinesException(string paramName, Exception inner) : this(inner) => ParamName = paramName;
|
||||||
public DisconnectedLinesException(params Line[] lines) : this() => Lines = lines;
|
public DisconnectedLinesException(params Line[] lines) : this() => Lines = lines;
|
||||||
public DisconnectedLinesException(Line[] lines, Exception inner) : this(inner) => Lines = lines;
|
public DisconnectedLinesException(Line[] lines, Exception inner) : this(inner) => Lines = lines;
|
||||||
public DisconnectedLinesException(string paramName, Line[] lines) : this()
|
public DisconnectedLinesException(string paramName, Line[] lines) : this()
|
||||||
{
|
{
|
||||||
ParamName = paramName;
|
ParamName = paramName;
|
||||||
Lines = lines;
|
Lines = lines;
|
||||||
}
|
}
|
||||||
public DisconnectedLinesException(string paramName, Line[] lines, Exception inner) : this(inner)
|
public DisconnectedLinesException(string paramName, Line[] lines, Exception inner) : this(inner)
|
||||||
{
|
{
|
||||||
ParamName = paramName;
|
ParamName = paramName;
|
||||||
Lines = lines;
|
Lines = lines;
|
||||||
}
|
}
|
||||||
protected DisconnectedLinesException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
protected DisconnectedLinesException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,12 @@
|
|||||||
using System;
|
using System.Runtime.Serialization;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Exceptions
|
namespace Nerd_STF.Exceptions;
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
public class Nerd_STFException : Exception
|
||||||
{
|
{
|
||||||
[Serializable]
|
public Nerd_STFException() { }
|
||||||
public class Nerd_STFException : Exception
|
public Nerd_STFException(string message) : base(message) { }
|
||||||
{
|
public Nerd_STFException(string message, Exception inner) : base(message, inner) { }
|
||||||
public Nerd_STFException() { }
|
protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
||||||
public Nerd_STFException(string message) : base(message) { }
|
|
||||||
public Nerd_STFException(string message, Exception inner) : base(message, inner) { }
|
|
||||||
protected Nerd_STFException(SerializationInfo info, StreamingContext context) : base(info, context) { }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
namespace Nerd_STF
|
namespace Nerd_STF;
|
||||||
{
|
|
||||||
public delegate T Fill<T>(int index);
|
public delegate T Fill<T>(int index);
|
||||||
}
|
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
using System;
|
namespace Nerd_STF;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF
|
public interface IClosest<T> where T : IEquatable<T>
|
||||||
{
|
{
|
||||||
public interface IClosest<T> where T : IEquatable<T>
|
public T ClosestTo(T item);
|
||||||
{
|
|
||||||
public T ClosestTo(T item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
using System;
|
namespace Nerd_STF;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF
|
public interface IContainer<T> where T : IEquatable<T>
|
||||||
{
|
{
|
||||||
public interface IContainer<T> where T : IEquatable<T>
|
public bool Contains(T item);
|
||||||
{
|
|
||||||
public bool Contains(T item);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
using System;
|
namespace Nerd_STF;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF
|
public interface IEncapsulator<T, TE> : IContainer<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
||||||
{
|
{
|
||||||
public interface IEncapsulator<T, TE> : IContainer<TE> where T : IEquatable<T> where TE : IEquatable<TE>
|
public T Encapsulate(TE val);
|
||||||
{
|
|
||||||
public T Encapsulate(TE val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
namespace Nerd_STF
|
namespace Nerd_STF;
|
||||||
|
|
||||||
|
public interface IGroup<T> : IEnumerable<T>
|
||||||
{
|
{
|
||||||
public interface IGroup<T> : IEnumerable<T>
|
public T[] ToArray();
|
||||||
{
|
public List<T> ToList();
|
||||||
public T[] ToArray();
|
|
||||||
public List<T> ToList();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,25 +1,18 @@
|
|||||||
using System;
|
namespace Nerd_STF;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF
|
public struct LogMessage
|
||||||
{
|
{
|
||||||
public struct LogMessage
|
public string Message;
|
||||||
|
public LogSeverity Severity;
|
||||||
|
public DateTime Timestamp;
|
||||||
|
|
||||||
|
public LogMessage() : this("", LogSeverity.Information, null) { }
|
||||||
|
public LogMessage(string msg, LogSeverity severity, DateTime? time = null)
|
||||||
{
|
{
|
||||||
public string Message;
|
Message = msg;
|
||||||
public LogSeverity Severity;
|
Severity = severity;
|
||||||
public DateTime Timestamp;
|
Timestamp = time ?? DateTime.Now;
|
||||||
|
|
||||||
public LogMessage() : this("", LogSeverity.Information, null) { }
|
|
||||||
public LogMessage(string msg, LogSeverity severity, DateTime? time = null)
|
|
||||||
{
|
|
||||||
Message = msg;
|
|
||||||
Severity = severity;
|
|
||||||
Timestamp = time ?? DateTime.Now;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString() => Timestamp + " " + Severity.ToString().ToUpper() + ": " + Message;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override string ToString() => Timestamp + " " + Severity.ToString().ToUpper() + ": " + Message;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
namespace Nerd_STF
|
namespace Nerd_STF;
|
||||||
|
|
||||||
|
public enum LogSeverity
|
||||||
{
|
{
|
||||||
public enum LogSeverity
|
Debug = 1,
|
||||||
{
|
Information = 2,
|
||||||
Debug = 1,
|
Warning = 4,
|
||||||
Information = 2,
|
Error = 8,
|
||||||
Warning = 4,
|
Fatal = 16,
|
||||||
Error = 8,
|
|
||||||
Fatal = 16,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,72 +1,71 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Nerd_STF
|
namespace Nerd_STF;
|
||||||
|
|
||||||
|
public class Logger
|
||||||
{
|
{
|
||||||
public class Logger
|
public event Action<LogMessage> OnMessageRecieved = DefaultLogHandler;
|
||||||
|
|
||||||
|
public LogMessage[] Cache => msgs.ToArray();
|
||||||
|
public int CacheSize = 64;
|
||||||
|
public List<LogSeverity> IncludeSeverities = new()
|
||||||
{
|
{
|
||||||
public event Action<LogMessage> OnMessageRecieved = DefaultLogHandler;
|
LogSeverity.Warning,
|
||||||
|
LogSeverity.Error,
|
||||||
|
LogSeverity.Fatal,
|
||||||
|
};
|
||||||
|
public Stream? LogStream;
|
||||||
|
public int WriteSize;
|
||||||
|
|
||||||
public LogMessage[] Cache => msgs.ToArray();
|
private readonly List<LogMessage> msgs;
|
||||||
public int CacheSize = 64;
|
private readonly List<string> writeCache;
|
||||||
public List<LogSeverity> IncludeSeverities = new()
|
|
||||||
|
public Logger(Stream? logStream = null, int cacheSize = 64, int writeSize = 1)
|
||||||
|
{
|
||||||
|
CacheSize = cacheSize;
|
||||||
|
LogStream = logStream;
|
||||||
|
WriteSize = writeSize;
|
||||||
|
|
||||||
|
msgs = new(CacheSize);
|
||||||
|
writeCache = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Send(LogMessage msg)
|
||||||
|
{
|
||||||
|
if (!IncludeSeverities.Contains(msg.Severity)) return;
|
||||||
|
|
||||||
|
msgs.Insert(0, msg);
|
||||||
|
writeCache.Add(msg.ToString());
|
||||||
|
while (msgs.Count > CacheSize) msgs.RemoveAt(CacheSize);
|
||||||
|
OnMessageRecieved(msg);
|
||||||
|
|
||||||
|
if (writeCache.Count >= WriteSize && LogStream != null)
|
||||||
{
|
{
|
||||||
LogSeverity.Warning,
|
string s = "";
|
||||||
LogSeverity.Error,
|
foreach (string cache in writeCache) s += cache + "\n" + (cache.Contains('\n') ? "\n" : "");
|
||||||
LogSeverity.Fatal,
|
LogStream.Write(Encoding.Default.GetBytes(s));
|
||||||
};
|
LogStream.Flush();
|
||||||
public Stream? LogStream;
|
writeCache.Clear();
|
||||||
public int WriteSize;
|
|
||||||
|
|
||||||
private readonly List<LogMessage> msgs;
|
|
||||||
private readonly List<string> writeCache;
|
|
||||||
|
|
||||||
public Logger(Stream? logStream = null, int cacheSize = 64, int writeSize = 1)
|
|
||||||
{
|
|
||||||
CacheSize = cacheSize;
|
|
||||||
LogStream = logStream;
|
|
||||||
WriteSize = writeSize;
|
|
||||||
|
|
||||||
msgs = new(CacheSize);
|
|
||||||
writeCache = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Send(LogMessage msg)
|
|
||||||
{
|
|
||||||
if (!IncludeSeverities.Contains(msg.Severity)) return;
|
|
||||||
|
|
||||||
msgs.Insert(0, msg);
|
|
||||||
writeCache.Add(msg.ToString());
|
|
||||||
while (msgs.Count > CacheSize) msgs.RemoveAt(CacheSize);
|
|
||||||
OnMessageRecieved(msg);
|
|
||||||
|
|
||||||
if (writeCache.Count >= WriteSize && LogStream != null)
|
|
||||||
{
|
|
||||||
string s = "";
|
|
||||||
foreach (string cache in writeCache) s += cache + "\n" + (cache.Contains('\n') ? "\n" : "");
|
|
||||||
LogStream.Write(Encoding.Default.GetBytes(s));
|
|
||||||
LogStream.Flush();
|
|
||||||
writeCache.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DefaultLogHandler(LogMessage msg)
|
|
||||||
{
|
|
||||||
ConsoleColor color = msg.Severity switch
|
|
||||||
{
|
|
||||||
LogSeverity.Debug => ConsoleColor.DarkGray,
|
|
||||||
LogSeverity.Information => ConsoleColor.White,
|
|
||||||
LogSeverity.Warning => ConsoleColor.DarkYellow,
|
|
||||||
LogSeverity.Error => ConsoleColor.Red,
|
|
||||||
LogSeverity.Fatal => ConsoleColor.DarkRed,
|
|
||||||
_ => throw new ArgumentException("Unknown log severity " + msg.Severity, nameof(msg)),
|
|
||||||
};
|
|
||||||
|
|
||||||
ConsoleColor originalCol = Console.ForegroundColor;
|
|
||||||
|
|
||||||
Console.ForegroundColor = color;
|
|
||||||
Console.WriteLine(msg.ToString());
|
|
||||||
|
|
||||||
Console.ForegroundColor = originalCol;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DefaultLogHandler(LogMessage msg)
|
||||||
|
{
|
||||||
|
ConsoleColor color = msg.Severity switch
|
||||||
|
{
|
||||||
|
LogSeverity.Debug => ConsoleColor.DarkGray,
|
||||||
|
LogSeverity.Information => ConsoleColor.White,
|
||||||
|
LogSeverity.Warning => ConsoleColor.DarkYellow,
|
||||||
|
LogSeverity.Error => ConsoleColor.Red,
|
||||||
|
LogSeverity.Fatal => ConsoleColor.DarkRed,
|
||||||
|
_ => throw new ArgumentException("Unknown log severity " + msg.Severity, nameof(msg)),
|
||||||
|
};
|
||||||
|
|
||||||
|
ConsoleColor originalCol = Console.ForegroundColor;
|
||||||
|
|
||||||
|
Console.ForegroundColor = color;
|
||||||
|
Console.WriteLine(msg.ToString());
|
||||||
|
|
||||||
|
Console.ForegroundColor = originalCol;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,124 +1,116 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
||||||
{
|
{
|
||||||
public struct Angle : ICloneable, IComparable<Angle>, IEquatable<Angle>
|
public static Angle Full => new(360);
|
||||||
{
|
public static Angle Half => new(180);
|
||||||
public static Angle Full => new(360);
|
public static Angle One => new(1);
|
||||||
public static Angle Half => new(180);
|
public static Angle Quarter => new(90);
|
||||||
public static Angle One => new(1);
|
public static Angle Zero => new(0);
|
||||||
public static Angle Quarter => new(90);
|
|
||||||
public static Angle Zero => new(0);
|
|
||||||
|
|
||||||
public double Degrees
|
public double Degrees
|
||||||
{
|
{
|
||||||
get => p_deg;
|
get => p_deg;
|
||||||
set => p_deg = value;
|
set => p_deg = value;
|
||||||
}
|
}
|
||||||
public double Gradians
|
public double Gradians
|
||||||
{
|
{
|
||||||
get => p_deg * 1.11111111111; // Reciprocal of 9/10 as a constant (10/9)
|
get => p_deg * 1.11111111111; // Reciprocal of 9/10 as a constant (10/9)
|
||||||
set => p_deg = value * 0.9;
|
set => p_deg = value * 0.9;
|
||||||
}
|
}
|
||||||
public double Radians
|
public double Radians
|
||||||
{
|
{
|
||||||
get => p_deg * Mathf.DegToRad;
|
get => p_deg * Mathf.DegToRad;
|
||||||
set => p_deg = value * Mathf.RadToDeg;
|
set => p_deg = value * Mathf.RadToDeg;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Angle Bounded => new(p_deg % 360);
|
public Angle Bounded => new(p_deg % 360);
|
||||||
|
|
||||||
private double p_deg;
|
private double p_deg;
|
||||||
|
|
||||||
public Angle(double value, Type valueType = Type.Degrees)
|
public Angle(double value, Type valueType = Type.Degrees)
|
||||||
|
{
|
||||||
|
p_deg = valueType switch
|
||||||
{
|
{
|
||||||
p_deg = valueType switch
|
Type.Degrees => value,
|
||||||
|
Type.Gradians => value * 0.9,
|
||||||
|
Type.Radians => value * Mathf.RadToDeg,
|
||||||
|
_ => throw new ArgumentException("Unknown type.", nameof(valueType)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Angle Absolute(Angle val) => new(Mathf.Absolute(val.p_deg));
|
||||||
|
public static Angle Average(params Angle[] vals) => new(Mathf.Average(ToDoubles(Type.Degrees, vals)));
|
||||||
|
public static Angle Ceiling(Angle val) => new(Mathf.Ceiling(val.p_deg));
|
||||||
|
public static Angle Clamp(Angle val, Angle min, Angle max) => new(Mathf.Clamp(val.p_deg, min.p_deg, max.p_deg));
|
||||||
|
public static Angle Floor(Angle val) => new(Mathf.Ceiling(val.p_deg));
|
||||||
|
public static Angle Lerp(Angle a, Angle b, double t, bool clamp = true) =>
|
||||||
|
new(Mathf.Lerp(a.p_deg, b.p_deg, t, clamp));
|
||||||
|
public static Angle Max(params Angle[] vals) => new(Mathf.Max(ToDoubles(Type.Degrees, vals)));
|
||||||
|
public static Angle Median(params Angle[] vals) => new(Mathf.Median(ToDoubles(Type.Degrees, vals)));
|
||||||
|
public static Angle Min(params Angle[] vals) => new(Mathf.Min(ToDoubles(Type.Degrees, vals)));
|
||||||
|
|
||||||
|
public static double[] ToDoubles(Type outputType, params Angle[] vals)
|
||||||
|
{
|
||||||
|
double[] res = new double[vals.Length];
|
||||||
|
for (int i = 0; i < vals.Length; i++)
|
||||||
|
{
|
||||||
|
res[i] = outputType switch
|
||||||
{
|
{
|
||||||
Type.Degrees => value,
|
Type.Degrees => vals[i].Degrees,
|
||||||
Type.Gradians => value * 0.9,
|
Type.Gradians => vals[i].Gradians,
|
||||||
Type.Radians => value * Mathf.RadToDeg,
|
Type.Radians => vals[i].Radians,
|
||||||
_ => throw new ArgumentException("Unknown type.", nameof(valueType)),
|
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
public static Angle Absolute(Angle val) => new(Mathf.Absolute(val.p_deg));
|
public int CompareTo(Angle other) => p_deg.CompareTo(other.p_deg);
|
||||||
public static Angle Average(params Angle[] vals) => new(Mathf.Average(ToDoubles(Type.Degrees, vals)));
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
public static Angle Ceiling(Angle val) => new(Mathf.Ceiling(val.p_deg));
|
{
|
||||||
public static Angle Clamp(Angle val, Angle min, Angle max) => new(Mathf.Clamp(val.p_deg, min.p_deg, max.p_deg));
|
if (obj == null || obj.GetType() != typeof(Angle)) return false;
|
||||||
public static Angle Floor(Angle val) => new(Mathf.Ceiling(val.p_deg));
|
return Equals((Angle)obj);
|
||||||
public static Angle Lerp(Angle a, Angle b, double t, bool clamp = true) =>
|
}
|
||||||
new(Mathf.Lerp(a.p_deg, b.p_deg, t, clamp));
|
public bool Equals(Angle other) => p_deg == other.p_deg;
|
||||||
public static Angle Max(params Angle[] vals) => new(Mathf.Max(ToDoubles(Type.Degrees, vals)));
|
public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode();
|
||||||
public static Angle Median(params Angle[] vals) => new(Mathf.Median(ToDoubles(Type.Degrees, vals)));
|
public override string ToString() => ToString((string?)null);
|
||||||
public static Angle Min(params Angle[] vals) => new(Mathf.Min(ToDoubles(Type.Degrees, vals)));
|
public string ToString(Type outputType) => ToString((string?)null, outputType);
|
||||||
|
public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch
|
||||||
|
{
|
||||||
|
Type.Degrees => p_deg.ToString(provider),
|
||||||
|
Type.Gradians => Gradians.ToString(provider),
|
||||||
|
Type.Radians => Radians.ToString(provider),
|
||||||
|
_ => 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),
|
||||||
|
Type.Radians => Radians.ToString(provider),
|
||||||
|
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
||||||
|
};
|
||||||
|
|
||||||
public static double[] ToDoubles(Type outputType, params Angle[] vals)
|
public object Clone() => new Angle(p_deg);
|
||||||
{
|
|
||||||
double[] res = new double[vals.Length];
|
|
||||||
for (int i = 0; i < vals.Length; i++)
|
|
||||||
{
|
|
||||||
res[i] = outputType switch
|
|
||||||
{
|
|
||||||
Type.Degrees => vals[i].Degrees,
|
|
||||||
Type.Gradians => vals[i].Gradians,
|
|
||||||
Type.Radians => vals[i].Radians,
|
|
||||||
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Angle other) => p_deg.CompareTo(other.p_deg);
|
public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg);
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
public static Angle operator -(Angle a) => new(-a.p_deg);
|
||||||
{
|
public static Angle operator -(Angle a, Angle b) => new(a.p_deg - b.p_deg);
|
||||||
if (obj == null || obj.GetType() != typeof(Angle)) return false;
|
public static Angle operator *(Angle a, Angle b) => new(a.p_deg * b.p_deg);
|
||||||
return Equals((Angle)obj);
|
public static Angle operator *(Angle a, double b) => new(a.p_deg * b);
|
||||||
}
|
public static Angle operator /(Angle a, Angle b) => new(a.p_deg / b.p_deg);
|
||||||
public bool Equals(Angle other) => p_deg == other.p_deg;
|
public static Angle operator /(Angle a, double b) => new(a.p_deg / b);
|
||||||
public override int GetHashCode() => Degrees.GetHashCode() ^ Gradians.GetHashCode() ^ Radians.GetHashCode();
|
public static bool operator ==(Angle a, Angle b) => a.Equals(b);
|
||||||
public override string ToString() => ToString((string?)null);
|
public static bool operator !=(Angle a, Angle b) => !a.Equals(b);
|
||||||
public string ToString(Type outputType) => ToString((string?)null, outputType);
|
public static bool operator >(Angle a, Angle b) => a.CompareTo(b) > 0;
|
||||||
public string ToString(string? provider, Type outputType = Type.Degrees) => outputType switch
|
public static bool operator <(Angle a, Angle b) => a.CompareTo(b) < 0;
|
||||||
{
|
public static bool operator >=(Angle a, Angle b) => a == b || a > b;
|
||||||
Type.Degrees => p_deg.ToString(provider),
|
public static bool operator <=(Angle a, Angle b) => a == b || a < b;
|
||||||
Type.Gradians => Gradians.ToString(provider),
|
|
||||||
Type.Radians => Radians.ToString(provider),
|
|
||||||
_ => 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),
|
|
||||||
Type.Radians => Radians.ToString(provider),
|
|
||||||
_ => throw new ArgumentException("Unknown type.", nameof(outputType)),
|
|
||||||
};
|
|
||||||
|
|
||||||
public object Clone() => new Angle(p_deg);
|
public enum Type
|
||||||
|
{
|
||||||
public static Angle operator +(Angle a, Angle b) => new(a.p_deg + b.p_deg);
|
Degrees,
|
||||||
public static Angle operator -(Angle a) => new(-a.p_deg);
|
Gradians,
|
||||||
public static Angle operator -(Angle a, Angle b) => new(a.p_deg - b.p_deg);
|
Radians,
|
||||||
public static Angle operator *(Angle a, Angle b) => new(a.p_deg * b.p_deg);
|
|
||||||
public static Angle operator *(Angle a, double b) => new(a.p_deg * b);
|
|
||||||
public static Angle operator /(Angle a, Angle b) => new(a.p_deg / b.p_deg);
|
|
||||||
public static Angle operator /(Angle a, double b) => new(a.p_deg / 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 == b || a > b;
|
|
||||||
public static bool operator <=(Angle a, Angle b) => a == b || a < b;
|
|
||||||
|
|
||||||
public enum Type
|
|
||||||
{
|
|
||||||
Degrees,
|
|
||||||
Gradians,
|
|
||||||
Radians,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,41 +1,34 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public static class Calculus
|
||||||
{
|
{
|
||||||
public static class Calculus
|
public const double DefaultStep = 0.001;
|
||||||
|
|
||||||
|
public static Equation GetDerivative(Equation equ, double min, double max, double step = DefaultStep)
|
||||||
{
|
{
|
||||||
public const double DefaultStep = 0.001;
|
Dictionary<double, double> vals = new();
|
||||||
|
for (double x = min; x <= max; x += step)
|
||||||
public static Equation GetDerivative(Equation equ, double min, double max, double step = DefaultStep)
|
|
||||||
{
|
{
|
||||||
Dictionary<double, double> vals = new();
|
double val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step;
|
||||||
for (double x = min; x <= max; x += step)
|
vals.Add(x, change);
|
||||||
{
|
|
||||||
double val1 = equ(x), val2 = equ(x + step), change = (val2 - val1) / step;
|
|
||||||
vals.Add(x, change);
|
|
||||||
}
|
|
||||||
return Mathf.MakeEquation(vals);
|
|
||||||
}
|
}
|
||||||
public static double GetDerivativeAtPoint(Equation equ, double x, double step = DefaultStep) =>
|
return Mathf.MakeEquation(vals);
|
||||||
(equ(x + DefaultStep) - equ(x)) / step;
|
}
|
||||||
|
public static double GetDerivativeAtPoint(Equation equ, double x, double step = DefaultStep) =>
|
||||||
|
(equ(x + DefaultStep) - equ(x)) / step;
|
||||||
|
|
||||||
public static double GetIntegral(Equation equ, double lowerBound, double upperBound, double step = DefaultStep)
|
public static double GetIntegral(Equation equ, double lowerBound, double upperBound, double step = DefaultStep)
|
||||||
{
|
{
|
||||||
double val = 0;
|
double val = 0;
|
||||||
for (double x = lowerBound; x <= upperBound; x += step) val += equ(x) * step;
|
for (double x = lowerBound; x <= upperBound; x += step) val += equ(x) * step;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double GradientDescent(Equation equ, double initial, double rate, double stepCount = 1000,
|
public static double GradientDescent(Equation equ, double initial, double rate, double stepCount = 1000,
|
||||||
double step = DefaultStep)
|
double step = DefaultStep)
|
||||||
{
|
{
|
||||||
double val = initial;
|
double val = initial;
|
||||||
for (int i = 0; i < stepCount; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate;
|
for (int i = 0; i < stepCount; i++) val -= GetDerivativeAtPoint(equ, val, step) * rate;
|
||||||
return val;
|
return val;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,186 +1,181 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Double2 : ICloneable, IComparable<Double2>, IEquatable<Double2>, IGroup<double>
|
||||||
{
|
{
|
||||||
public struct Double2 : ICloneable, IComparable<Double2>, IEquatable<Double2>, IGroup<double>
|
public static Double2 Down => new(0, -1);
|
||||||
|
public static Double2 Left => new(-1, 0);
|
||||||
|
public static Double2 Right => new(1, 0);
|
||||||
|
public static Double2 Up => new(0, 1);
|
||||||
|
|
||||||
|
public static Double2 One => new(1, 1);
|
||||||
|
public static Double2 Zero => new(0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y);
|
||||||
|
public Double2 Normalized => this / Magnitude;
|
||||||
|
|
||||||
|
public double x, y;
|
||||||
|
|
||||||
|
public Double2(double all) : this(all, all) { }
|
||||||
|
public Double2(double x, double y)
|
||||||
{
|
{
|
||||||
public static Double2 Down => new(0, -1);
|
this.x = x;
|
||||||
public static Double2 Left => new(-1, 0);
|
this.y = y;
|
||||||
public static Double2 Right => new(1, 0);
|
|
||||||
public static Double2 Up => new(0, 1);
|
|
||||||
|
|
||||||
public static Double2 One => new(1, 1);
|
|
||||||
public static Double2 Zero => new(0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y);
|
|
||||||
public Double2 Normalized => this / Magnitude;
|
|
||||||
|
|
||||||
public double x, y;
|
|
||||||
|
|
||||||
public Double2(double all) : this(all, all) { }
|
|
||||||
public Double2(double x, double y)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
public Double2(Fill<double> fill) : this(fill(0), fill(1)) { }
|
|
||||||
public Double2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Double2 Absolute(Double2 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
|
||||||
public static Double2 Average(params Double2[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Double2 Ceiling(Double2 val) =>
|
|
||||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y));
|
|
||||||
public static Double2 Clamp(Double2 val, Double2 min, Double2 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y));
|
|
||||||
public static Double2 ClampMagnitude(Double2 val, double minMag, double maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double3 Cross(Double2 a, Double2 b, bool normalized = false) =>
|
|
||||||
Double3.Cross(a, b, normalized);
|
|
||||||
public static Double2 Divide(Double2 num, params Double2[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double2 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static double Dot(Double2 a, Double2 b) => a.x * b.x + a.y * b.y;
|
|
||||||
public static double Dot(params Double2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double x = 1, y = 1;
|
|
||||||
foreach (Double2 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
}
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
public static Double2 Floor(Double2 val) =>
|
|
||||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y));
|
|
||||||
public static Double2 Lerp(Double2 a, Double2 b, double t, bool clamp = true) =>
|
|
||||||
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp));
|
|
||||||
public static Double2 Median(params Double2[] vals)
|
|
||||||
{
|
|
||||||
double index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Double2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Double2 Max(params Double2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double2 val = vals[0];
|
|
||||||
foreach (Double2 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double2 Min(params Double2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double2 val = vals[0];
|
|
||||||
foreach (Double2 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double2 Multiply(params Double2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double2 val = One;
|
|
||||||
foreach (Double2 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double2 Subtract(Double2 num, params Double2[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double2 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Double2 Sum(params Double2[] vals)
|
|
||||||
{
|
|
||||||
Double2 val = Zero;
|
|
||||||
foreach (Double2 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Double2 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Double2)) return false;
|
|
||||||
return Equals((Double2)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Double2 other) => x == other.x && y == other.y;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Double2(x, y);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<double> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double[] ToArray() => new[] { x, y };
|
|
||||||
public List<double> ToList() => new() { x, y };
|
|
||||||
|
|
||||||
public static Double2 operator +(Double2 a, Double2 b) => new(a.x + b.x, a.y + b.y);
|
|
||||||
public static Double2 operator -(Double2 d) => new(-d.x, -d.y);
|
|
||||||
public static Double2 operator -(Double2 a, Double2 b) => new(a.x - b.x, a.y - b.y);
|
|
||||||
public static Double2 operator *(Double2 a, Double2 b) => new(a.x * b.x, a.y * b.y);
|
|
||||||
public static Double2 operator *(Double2 a, double b) => new(a.x * b, a.y * b);
|
|
||||||
public static Double2 operator /(Double2 a, Double2 b) => new(a.x / b.x, a.y / b.y);
|
|
||||||
public static Double2 operator /(Double2 a, double b) => new(a.x / b, a.y / b);
|
|
||||||
public static bool operator ==(Double2 a, Double2 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Double2 a, Double2 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Double2 a, Double2 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Double2 a, Double2 b) => a.CompareTo(b) < 0;
|
|
||||||
public static bool operator >=(Double2 a, Double2 b) => a == b || a > b;
|
|
||||||
public static bool operator <=(Double2 a, Double2 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static explicit operator Double2(Double3 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Double2(Double4 val) => new(val.x, val.y);
|
|
||||||
public static implicit operator Double2(Int2 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Double2(Int3 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Double2(Int4 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Double2(Vert val) => new(val.position.x, val.position.y);
|
|
||||||
public static implicit operator Double2(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Double2(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Double2(Fill<double> fill) : this(fill(0), fill(1)) { }
|
||||||
|
public Double2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double2 Absolute(Double2 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
||||||
|
public static Double2 Average(params Double2[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Double2 Ceiling(Double2 val) =>
|
||||||
|
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y));
|
||||||
|
public static Double2 Clamp(Double2 val, Double2 min, Double2 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y));
|
||||||
|
public static Double2 ClampMagnitude(Double2 val, double minMag, double maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double3 Cross(Double2 a, Double2 b, bool normalized = false) =>
|
||||||
|
Double3.Cross(a, b, normalized);
|
||||||
|
public static Double2 Divide(Double2 num, params Double2[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double2 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static double Dot(Double2 a, Double2 b) => a.x * b.x + a.y * b.y;
|
||||||
|
public static double Dot(params Double2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double x = 1, y = 1;
|
||||||
|
foreach (Double2 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
}
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
public static Double2 Floor(Double2 val) =>
|
||||||
|
new(Mathf.Floor(val.x), Mathf.Floor(val.y));
|
||||||
|
public static Double2 Lerp(Double2 a, Double2 b, double t, bool clamp = true) =>
|
||||||
|
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp));
|
||||||
|
public static Double2 Median(params Double2[] vals)
|
||||||
|
{
|
||||||
|
double index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Double2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Double2 Max(params Double2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double2 val = vals[0];
|
||||||
|
foreach (Double2 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double2 Min(params Double2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double2 val = vals[0];
|
||||||
|
foreach (Double2 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double2 Multiply(params Double2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double2 val = One;
|
||||||
|
foreach (Double2 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double2 Subtract(Double2 num, params Double2[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double2 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Double2 Sum(params Double2[] vals)
|
||||||
|
{
|
||||||
|
Double2 val = Zero;
|
||||||
|
foreach (Double2 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Double2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Double2)) return false;
|
||||||
|
return Equals((Double2)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Double2 other) => x == other.x && y == other.y;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Double2(x, y);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<double> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] ToArray() => new[] { x, y };
|
||||||
|
public List<double> ToList() => new() { x, y };
|
||||||
|
|
||||||
|
public static Double2 operator +(Double2 a, Double2 b) => new(a.x + b.x, a.y + b.y);
|
||||||
|
public static Double2 operator -(Double2 d) => new(-d.x, -d.y);
|
||||||
|
public static Double2 operator -(Double2 a, Double2 b) => new(a.x - b.x, a.y - b.y);
|
||||||
|
public static Double2 operator *(Double2 a, Double2 b) => new(a.x * b.x, a.y * b.y);
|
||||||
|
public static Double2 operator *(Double2 a, double b) => new(a.x * b, a.y * b);
|
||||||
|
public static Double2 operator /(Double2 a, Double2 b) => new(a.x / b.x, a.y / b.y);
|
||||||
|
public static Double2 operator /(Double2 a, double b) => new(a.x / b, a.y / b);
|
||||||
|
public static bool operator ==(Double2 a, Double2 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Double2 a, Double2 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Double2 a, Double2 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Double2 a, Double2 b) => a.CompareTo(b) < 0;
|
||||||
|
public static bool operator >=(Double2 a, Double2 b) => a == b || a > b;
|
||||||
|
public static bool operator <=(Double2 a, Double2 b) => a == b || a < b;
|
||||||
|
|
||||||
|
public static explicit operator Double2(Double3 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Double2(Double4 val) => new(val.x, val.y);
|
||||||
|
public static implicit operator Double2(Int2 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Double2(Int3 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Double2(Int4 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Double2(Vert val) => new(val.position.x, val.position.y);
|
||||||
|
public static implicit operator Double2(Fill<double> fill) => new(fill);
|
||||||
|
public static implicit operator Double2(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,207 +1,202 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Double3 : ICloneable, IComparable<Double3>, IEquatable<Double3>, IGroup<double>
|
||||||
{
|
{
|
||||||
public struct Double3 : ICloneable, IComparable<Double3>, IEquatable<Double3>, IGroup<double>
|
public static Double3 Back => new(0, 0, -1);
|
||||||
|
public static Double3 Down => new(0, -1, 0);
|
||||||
|
public static Double3 Forward => new(0, 0, 1);
|
||||||
|
public static Double3 Left => new(-1, 0, 0);
|
||||||
|
public static Double3 Right => new(1, 0, 0);
|
||||||
|
public static Double3 Up => new(0, 1, 0);
|
||||||
|
|
||||||
|
public static Double3 One => new(1, 1, 1);
|
||||||
|
public static Double3 Zero => new(0, 0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
||||||
|
public Double3 Normalized => this / Magnitude;
|
||||||
|
|
||||||
|
public Double2 XY => new(x, y);
|
||||||
|
public Double2 XZ => new(x, z);
|
||||||
|
public Double2 YZ => new(y, z);
|
||||||
|
|
||||||
|
public double x, y, z;
|
||||||
|
|
||||||
|
public Double3(double all) : this(all, all, all) { }
|
||||||
|
public Double3(double x, double y) : this(x, y, 0) { }
|
||||||
|
public Double3(double x, double y, double z)
|
||||||
{
|
{
|
||||||
public static Double3 Back => new(0, 0, -1);
|
this.x = x;
|
||||||
public static Double3 Down => new(0, -1, 0);
|
this.y = y;
|
||||||
public static Double3 Forward => new(0, 0, 1);
|
this.z = z;
|
||||||
public static Double3 Left => new(-1, 0, 0);
|
|
||||||
public static Double3 Right => new(1, 0, 0);
|
|
||||||
public static Double3 Up => new(0, 1, 0);
|
|
||||||
|
|
||||||
public static Double3 One => new(1, 1, 1);
|
|
||||||
public static Double3 Zero => new(0, 0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
|
||||||
public Double3 Normalized => this / Magnitude;
|
|
||||||
|
|
||||||
public Double2 XY => new(x, y);
|
|
||||||
public Double2 XZ => new(x, z);
|
|
||||||
public Double2 YZ => new(y, z);
|
|
||||||
|
|
||||||
public double x, y, z;
|
|
||||||
|
|
||||||
public Double3(double all) : this(all, all, all) { }
|
|
||||||
public Double3(double x, double y) : this(x, y, 0) { }
|
|
||||||
public Double3(double x, double y, double z)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
public Double3(Fill<double> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
public Double3(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
2 => z,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
z = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Double3 Absolute(Double3 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
|
||||||
public static Double3 Average(params Double3[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Double3 Ceiling(Double3 val) =>
|
|
||||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z));
|
|
||||||
public static Double3 Clamp(Double3 val, Double3 min, Double3 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y),
|
|
||||||
Mathf.Clamp(val.z, min.z, max.z));
|
|
||||||
public static Double3 ClampMagnitude(Double3 val, double minMag, double maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double3 Cross(Double3 a, Double3 b, bool normalized = false)
|
|
||||||
{
|
|
||||||
Double3 val = new(a.y * b.z - b.y * a.z,
|
|
||||||
b.x * a.z - a.x * b.z,
|
|
||||||
a.x * b.y - b.x * a.y);
|
|
||||||
return normalized ? val.Normalized : val;
|
|
||||||
}
|
|
||||||
public static Double3 Divide(Double3 num, params Double3[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double3 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static double Dot(Double3 a, Double3 b) => a.x * b.x + a.y * b.y + a.z * b.z;
|
|
||||||
public static double Dot(params Double3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double x = 1, y = 1, z = 1;
|
|
||||||
foreach (Double3 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
z *= d.z;
|
|
||||||
}
|
|
||||||
return x + y + z;
|
|
||||||
}
|
|
||||||
public static Double3 Floor(Double3 val) =>
|
|
||||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z));
|
|
||||||
public static Double3 Lerp(Double3 a, Double3 b, double 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));
|
|
||||||
public static Double3 Median(params Double3[] vals)
|
|
||||||
{
|
|
||||||
double index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Double3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Double3 Max(params Double3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double3 val = vals[0];
|
|
||||||
foreach (Double3 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double3 Min(params Double3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double3 val = vals[0];
|
|
||||||
foreach (Double3 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double3 Multiply(params Double3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double3 val = One;
|
|
||||||
foreach (Double3 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double3 Subtract(Double3 num, params Double3[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double3 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Double3 Sum(params Double3[] vals)
|
|
||||||
{
|
|
||||||
Double3 val = Zero;
|
|
||||||
foreach (Double3 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Double3 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Double3)) return false;
|
|
||||||
return Equals((Double3)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Double3 other) => x == other.x && y == other.y && z == other.z;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Double3(x, y, z);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<double> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
yield return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double[] ToArray() => new[] { x, y, z };
|
|
||||||
public List<double> ToList() => new() { x, y, z };
|
|
||||||
|
|
||||||
public static Double3 operator +(Double3 a, Double3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
|
||||||
public static Double3 operator -(Double3 d) => new(-d.x, -d.y, -d.z);
|
|
||||||
public static Double3 operator -(Double3 a, Double3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
|
||||||
public static Double3 operator *(Double3 a, Double3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
|
||||||
public static Double3 operator *(Double3 a, double b) => new(a.x * b, a.y * b, a.z * b);
|
|
||||||
public static Double3 operator /(Double3 a, Double3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
|
||||||
public static Double3 operator /(Double3 a, double b) => new(a.x / b, a.y / b, a.z / b);
|
|
||||||
public static bool operator ==(Double3 a, Double3 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Double3 a, Double3 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Double3 a, Double3 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Double3 a, Double3 b) => a.CompareTo(b) < 0;
|
|
||||||
public static bool operator >=(Double3 a, Double3 b) => a == b || a > b;
|
|
||||||
public static bool operator <=(Double3 a, Double3 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Double3(Double2 val) => new(val.x, val.y, 0);
|
|
||||||
public static explicit operator Double3(Double4 val) => new(val.x, val.y, val.z);
|
|
||||||
public static implicit operator Double3(Int2 val) => new(val.x, val.y, 0);
|
|
||||||
public static implicit operator Double3(Int3 val) => new(val.x, val.y, val.z);
|
|
||||||
public static explicit operator Double3(Int4 val) => new(val.x, val.y, val.z);
|
|
||||||
public static implicit operator Double3(Vert val) => new(val.position.x, val.position.y, val.position.z);
|
|
||||||
public static implicit operator Double3(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Double3(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Double3(Fill<double> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
public Double3(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
2 => z,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
z = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double3 Absolute(Double3 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
||||||
|
public static Double3 Average(params Double3[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Double3 Ceiling(Double3 val) =>
|
||||||
|
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z));
|
||||||
|
public static Double3 Clamp(Double3 val, Double3 min, Double3 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y),
|
||||||
|
Mathf.Clamp(val.z, min.z, max.z));
|
||||||
|
public static Double3 ClampMagnitude(Double3 val, double minMag, double maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double3 Cross(Double3 a, Double3 b, bool normalized = false)
|
||||||
|
{
|
||||||
|
Double3 val = new(a.y * b.z - b.y * a.z,
|
||||||
|
b.x * a.z - a.x * b.z,
|
||||||
|
a.x * b.y - b.x * a.y);
|
||||||
|
return normalized ? val.Normalized : val;
|
||||||
|
}
|
||||||
|
public static Double3 Divide(Double3 num, params Double3[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double3 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static double Dot(Double3 a, Double3 b) => a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
public static double Dot(params Double3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double x = 1, y = 1, z = 1;
|
||||||
|
foreach (Double3 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
z *= d.z;
|
||||||
|
}
|
||||||
|
return x + y + z;
|
||||||
|
}
|
||||||
|
public static Double3 Floor(Double3 val) =>
|
||||||
|
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z));
|
||||||
|
public static Double3 Lerp(Double3 a, Double3 b, double 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));
|
||||||
|
public static Double3 Median(params Double3[] vals)
|
||||||
|
{
|
||||||
|
double index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Double3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Double3 Max(params Double3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double3 val = vals[0];
|
||||||
|
foreach (Double3 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double3 Min(params Double3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double3 val = vals[0];
|
||||||
|
foreach (Double3 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double3 Multiply(params Double3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double3 val = One;
|
||||||
|
foreach (Double3 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double3 Subtract(Double3 num, params Double3[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double3 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Double3 Sum(params Double3[] vals)
|
||||||
|
{
|
||||||
|
Double3 val = Zero;
|
||||||
|
foreach (Double3 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Double3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Double3)) return false;
|
||||||
|
return Equals((Double3)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Double3 other) => x == other.x && y == other.y && z == other.z;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Double3(x, y, z);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<double> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
yield return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] ToArray() => new[] { x, y, z };
|
||||||
|
public List<double> ToList() => new() { x, y, z };
|
||||||
|
|
||||||
|
public static Double3 operator +(Double3 a, Double3 b) => new(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||||
|
public static Double3 operator -(Double3 d) => new(-d.x, -d.y, -d.z);
|
||||||
|
public static Double3 operator -(Double3 a, Double3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||||
|
public static Double3 operator *(Double3 a, Double3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||||
|
public static Double3 operator *(Double3 a, double b) => new(a.x * b, a.y * b, a.z * b);
|
||||||
|
public static Double3 operator /(Double3 a, Double3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||||
|
public static Double3 operator /(Double3 a, double b) => new(a.x / b, a.y / b, a.z / b);
|
||||||
|
public static bool operator ==(Double3 a, Double3 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Double3 a, Double3 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Double3 a, Double3 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Double3 a, Double3 b) => a.CompareTo(b) < 0;
|
||||||
|
public static bool operator >=(Double3 a, Double3 b) => a == b || a > b;
|
||||||
|
public static bool operator <=(Double3 a, Double3 b) => a == b || a < b;
|
||||||
|
|
||||||
|
public static implicit operator Double3(Double2 val) => new(val.x, val.y, 0);
|
||||||
|
public static explicit operator Double3(Double4 val) => new(val.x, val.y, val.z);
|
||||||
|
public static implicit operator Double3(Int2 val) => new(val.x, val.y, 0);
|
||||||
|
public static implicit operator Double3(Int3 val) => new(val.x, val.y, val.z);
|
||||||
|
public static explicit operator Double3(Int4 val) => new(val.x, val.y, val.z);
|
||||||
|
public static implicit operator Double3(Vert val) => new(val.position.x, val.position.y, val.position.z);
|
||||||
|
public static implicit operator Double3(Fill<double> fill) => new(fill);
|
||||||
|
public static implicit operator Double3(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,223 +1,218 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Double4 : ICloneable, IComparable<Double4>, IEquatable<Double4>, IGroup<double>
|
||||||
{
|
{
|
||||||
public struct Double4 : ICloneable, IComparable<Double4>, IEquatable<Double4>, IGroup<double>
|
public static Double4 Back => new(0, 0, -1, 0);
|
||||||
|
public static Double4 Deep => new(0, 0, 0, -1);
|
||||||
|
public static Double4 Down => new(0, -1, 0, 0);
|
||||||
|
public static Double4 Far => new(0, 0, 0, 1);
|
||||||
|
public static Double4 Forward => new(0, 0, 1, 0);
|
||||||
|
public static Double4 Left => new(-1, 0, 0, 0);
|
||||||
|
public static Double4 Right => new(1, 0, 0, 0);
|
||||||
|
public static Double4 Up => new(0, 1, 0, 0);
|
||||||
|
|
||||||
|
public static Double4 One => new(1, 1, 1, 1);
|
||||||
|
public static Double4 Zero => new(0, 0, 0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
||||||
|
public Double4 Normalized => this / Magnitude;
|
||||||
|
|
||||||
|
public Double2 XY => new(x, y);
|
||||||
|
public Double2 XZ => new(x, z);
|
||||||
|
public Double2 XW => new(x, w);
|
||||||
|
public Double2 YW => new(y, w);
|
||||||
|
public Double2 YZ => new(y, z);
|
||||||
|
public Double2 ZW => new(z, w);
|
||||||
|
|
||||||
|
public Double3 XYW => new(x, y, w);
|
||||||
|
public Double3 XYZ => new(x, y, z);
|
||||||
|
public Double3 YZW => new(y, z, w);
|
||||||
|
public Double3 XZW => new(x, z, w);
|
||||||
|
|
||||||
|
public double x, y, z, w;
|
||||||
|
|
||||||
|
public Double4(double all) : this(all, all, all, all) { }
|
||||||
|
public Double4(double x, double y) : this(x, y, 0, 0) { }
|
||||||
|
public Double4(double x, double y, double z) : this(x, y, z, 0) { }
|
||||||
|
public Double4(double x, double y, double z, double w)
|
||||||
{
|
{
|
||||||
public static Double4 Back => new(0, 0, -1, 0);
|
this.x = x;
|
||||||
public static Double4 Deep => new(0, 0, 0, -1);
|
this.y = y;
|
||||||
public static Double4 Down => new(0, -1, 0, 0);
|
this.z = z;
|
||||||
public static Double4 Far => new(0, 0, 0, 1);
|
this.w = w;
|
||||||
public static Double4 Forward => new(0, 0, 1, 0);
|
|
||||||
public static Double4 Left => new(-1, 0, 0, 0);
|
|
||||||
public static Double4 Right => new(1, 0, 0, 0);
|
|
||||||
public static Double4 Up => new(0, 1, 0, 0);
|
|
||||||
|
|
||||||
public static Double4 One => new(1, 1, 1, 1);
|
|
||||||
public static Double4 Zero => new(0, 0, 0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
|
||||||
public Double4 Normalized => this / Magnitude;
|
|
||||||
|
|
||||||
public Double2 XY => new(x, y);
|
|
||||||
public Double2 XZ => new(x, z);
|
|
||||||
public Double2 XW => new(x, w);
|
|
||||||
public Double2 YW => new(y, w);
|
|
||||||
public Double2 YZ => new(y, z);
|
|
||||||
public Double2 ZW => new(z, w);
|
|
||||||
|
|
||||||
public Double3 XYW => new(x, y, w);
|
|
||||||
public Double3 XYZ => new(x, y, z);
|
|
||||||
public Double3 YZW => new(y, z, w);
|
|
||||||
public Double3 XZW => new(x, z, w);
|
|
||||||
|
|
||||||
public double x, y, z, w;
|
|
||||||
|
|
||||||
public Double4(double all) : this(all, all, all, all) { }
|
|
||||||
public Double4(double x, double y) : this(x, y, 0, 0) { }
|
|
||||||
public Double4(double x, double y, double z) : this(x, y, z, 0) { }
|
|
||||||
public Double4(double x, double y, double z, double w)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
this.w = w;
|
|
||||||
}
|
|
||||||
public Double4(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
|
||||||
public Double4(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
2 => z,
|
|
||||||
3 => w,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
z = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
w = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Double4 Absolute(Double4 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
|
||||||
public static Double4 Average(params Double4[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Double4 Ceiling(Double4 val) =>
|
|
||||||
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w));
|
|
||||||
public static Double4 Clamp(Double4 val, Double4 min, Double4 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y),
|
|
||||||
Mathf.Clamp(val.z, min.z, max.z),
|
|
||||||
Mathf.Clamp(val.w, min.w, max.w));
|
|
||||||
public static Double4 ClampMagnitude(Double4 val, double minMag, double maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double4 Divide(Double4 num, params Double4[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double4 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static double Dot(Double4 a, Double4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
|
||||||
public static double Dot(params Double4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double x = 1, y = 1, z = 1, w = 1;
|
|
||||||
foreach (Double4 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
z *= d.z;
|
|
||||||
w *= d.w;
|
|
||||||
}
|
|
||||||
return x + y + z;
|
|
||||||
}
|
|
||||||
public static Double4 Floor(Double4 val) =>
|
|
||||||
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w));
|
|
||||||
public static Double4 Lerp(Double4 a, Double4 b, double 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),
|
|
||||||
Mathf.Lerp(a.w, b.w, t, clamp));
|
|
||||||
public static Double4 Median(params Double4[] vals)
|
|
||||||
{
|
|
||||||
double index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Double4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Double4 Max(params Double4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double4 val = vals[0];
|
|
||||||
foreach (Double4 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double4 Min(params Double4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double4 val = vals[0];
|
|
||||||
foreach (Double4 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double4 Multiply(params Double4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Double4 val = One;
|
|
||||||
foreach (Double4 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Double4 Subtract(Double4 num, params Double4[] vals)
|
|
||||||
{
|
|
||||||
foreach (Double4 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Double4 Sum(params Double4[] vals)
|
|
||||||
{
|
|
||||||
Double4 val = Zero;
|
|
||||||
foreach (Double4 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Double4 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Double4)) return false;
|
|
||||||
return Equals((Double4)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Double4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
|
||||||
+ " W: " + w.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
|
||||||
+ " W: " + w.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Double4(x, y, z, w);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<double> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
yield return z;
|
|
||||||
yield return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double[] ToArray() => new[] { x, y, z, w };
|
|
||||||
public List<double> ToList() => new() { x, y, z, w };
|
|
||||||
|
|
||||||
public static Double4 operator +(Double4 a, Double4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
|
||||||
public static Double4 operator -(Double4 d) => new(-d.x, -d.y, -d.z, -d.w);
|
|
||||||
public static Double4 operator -(Double4 a, Double4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
|
||||||
public static Double4 operator *(Double4 a, Double4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
|
|
||||||
public static Double4 operator *(Double4 a, double b) => new(a.x * b, a.y * b, a.z * b, a.w * b);
|
|
||||||
public static Double4 operator /(Double4 a, Double4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
|
||||||
public static Double4 operator /(Double4 a, double b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
|
||||||
public static bool operator ==(Double4 a, Double4 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Double4 a, Double4 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Double4 a, Double4 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Double4 a, Double4 b) => a.CompareTo(b) < 0;
|
|
||||||
public static bool operator >=(Double4 a, Double4 b) => a == b || a > b;
|
|
||||||
public static bool operator <=(Double4 a, Double4 b) => a == b || a < b;
|
|
||||||
|
|
||||||
public static implicit operator Double4(Double2 val) => new(val.x, val.y, 0, 0);
|
|
||||||
public static implicit operator Double4(Double3 val) => new(val.x, val.y, val.z, 0);
|
|
||||||
public static implicit operator Double4(Int2 val) => new(val.x, val.y, 0, 0);
|
|
||||||
public static implicit operator Double4(Int3 val) => new(val.x, val.y, val.z, 0);
|
|
||||||
public static implicit operator Double4(Int4 val) => new(val.x, val.y, val.z, val.w);
|
|
||||||
public static implicit operator Double4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0);
|
|
||||||
public static implicit operator Double4(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Double4(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Double4(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
|
public Double4(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
2 => z,
|
||||||
|
3 => w,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
z = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
w = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double4 Absolute(Double4 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
||||||
|
public static Double4 Average(params Double4[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Double4 Ceiling(Double4 val) =>
|
||||||
|
new(Mathf.Ceiling(val.x), Mathf.Ceiling(val.y), Mathf.Ceiling(val.z), Mathf.Ceiling(val.w));
|
||||||
|
public static Double4 Clamp(Double4 val, Double4 min, Double4 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y),
|
||||||
|
Mathf.Clamp(val.z, min.z, max.z),
|
||||||
|
Mathf.Clamp(val.w, min.w, max.w));
|
||||||
|
public static Double4 ClampMagnitude(Double4 val, double minMag, double maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double4 Divide(Double4 num, params Double4[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double4 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static double Dot(Double4 a, Double4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||||
|
public static double Dot(params Double4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double x = 1, y = 1, z = 1, w = 1;
|
||||||
|
foreach (Double4 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
z *= d.z;
|
||||||
|
w *= d.w;
|
||||||
|
}
|
||||||
|
return x + y + z;
|
||||||
|
}
|
||||||
|
public static Double4 Floor(Double4 val) =>
|
||||||
|
new(Mathf.Floor(val.x), Mathf.Floor(val.y), Mathf.Floor(val.z), Mathf.Floor(val.w));
|
||||||
|
public static Double4 Lerp(Double4 a, Double4 b, double 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),
|
||||||
|
Mathf.Lerp(a.w, b.w, t, clamp));
|
||||||
|
public static Double4 Median(params Double4[] vals)
|
||||||
|
{
|
||||||
|
double index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Double4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Double4 Max(params Double4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double4 val = vals[0];
|
||||||
|
foreach (Double4 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double4 Min(params Double4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double4 val = vals[0];
|
||||||
|
foreach (Double4 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double4 Multiply(params Double4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Double4 val = One;
|
||||||
|
foreach (Double4 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Double4 Subtract(Double4 num, params Double4[] vals)
|
||||||
|
{
|
||||||
|
foreach (Double4 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Double4 Sum(params Double4[] vals)
|
||||||
|
{
|
||||||
|
Double4 val = Zero;
|
||||||
|
foreach (Double4 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Double4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Double4)) return false;
|
||||||
|
return Equals((Double4)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Double4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||||
|
+ " W: " + w.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||||
|
+ " W: " + w.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Double4(x, y, z, w);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<double> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
yield return z;
|
||||||
|
yield return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double[] ToArray() => new[] { x, y, z, w };
|
||||||
|
public List<double> ToList() => new() { x, y, z, w };
|
||||||
|
|
||||||
|
public static Double4 operator +(Double4 a, Double4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||||
|
public static Double4 operator -(Double4 d) => new(-d.x, -d.y, -d.z, -d.w);
|
||||||
|
public static Double4 operator -(Double4 a, Double4 b) => new(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
|
||||||
|
public static Double4 operator *(Double4 a, Double4 b) => new(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
|
||||||
|
public static Double4 operator *(Double4 a, double b) => new(a.x * b, a.y * b, a.z * b, a.w * b);
|
||||||
|
public static Double4 operator /(Double4 a, Double4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
||||||
|
public static Double4 operator /(Double4 a, double b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
||||||
|
public static bool operator ==(Double4 a, Double4 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Double4 a, Double4 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Double4 a, Double4 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Double4 a, Double4 b) => a.CompareTo(b) < 0;
|
||||||
|
public static bool operator >=(Double4 a, Double4 b) => a == b || a > b;
|
||||||
|
public static bool operator <=(Double4 a, Double4 b) => a == b || a < b;
|
||||||
|
|
||||||
|
public static implicit operator Double4(Double2 val) => new(val.x, val.y, 0, 0);
|
||||||
|
public static implicit operator Double4(Double3 val) => new(val.x, val.y, val.z, 0);
|
||||||
|
public static implicit operator Double4(Int2 val) => new(val.x, val.y, 0, 0);
|
||||||
|
public static implicit operator Double4(Int3 val) => new(val.x, val.y, val.z, 0);
|
||||||
|
public static implicit operator Double4(Int4 val) => new(val.x, val.y, val.z, val.w);
|
||||||
|
public static implicit operator Double4(Vert val) => new(val.position.x, val.position.y, val.position.z, 0);
|
||||||
|
public static implicit operator Double4(Fill<double> fill) => new(fill);
|
||||||
|
public static implicit operator Double4(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,3 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public delegate double Equation(double x);
|
||||||
{
|
|
||||||
public delegate double Equation(double x);
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,130 +1,122 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
||||||
{
|
{
|
||||||
public struct Box2D : ICloneable, IContainer<Vert>, IEquatable<Box2D>
|
public static Box2D Unit => new(Vert.Zero, Double2.One);
|
||||||
|
|
||||||
|
public Vert MaxVert
|
||||||
{
|
{
|
||||||
public static Box2D Unit => new(Vert.Zero, Double2.One);
|
get => center + (size / 2);
|
||||||
|
set
|
||||||
public Vert MaxVert
|
|
||||||
{
|
{
|
||||||
get => center + (size / 2);
|
Vert diff = center - value;
|
||||||
set
|
size = (Double2)diff.position * 2;
|
||||||
{
|
|
||||||
Vert diff = center - value;
|
|
||||||
size = (Double2)diff.position * 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public Vert MinVert
|
|
||||||
{
|
|
||||||
get => center - (size / 2);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Vert diff = center + value;
|
|
||||||
size = (Double2)diff.position * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double Area => size.x * size.y;
|
|
||||||
public double Perimeter => size.x * 2 + size.y * 2;
|
|
||||||
|
|
||||||
public Vert center;
|
|
||||||
public Double2 size;
|
|
||||||
|
|
||||||
public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Double2)(min - max)) { }
|
|
||||||
public Box2D(Vert center, Double2 size)
|
|
||||||
{
|
|
||||||
this.center = center;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
public Box2D(Fill<double> fill) : this(fill, new Double2(fill(3), fill(4))) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => size[index];
|
|
||||||
set => size[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Box2D Absolute(Box2D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert));
|
|
||||||
public static Box2D Average(params Box2D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, Double2[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Average(centers), Double2.Average(sizes));
|
|
||||||
}
|
|
||||||
public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Double2.Ceiling(val.size));
|
|
||||||
public static Box2D Clamp(Box2D val, Box2D min, Box2D max) =>
|
|
||||||
new(Vert.Clamp(val.center, min.center, max.center), Double2.Clamp(val.size, min.size, max.size));
|
|
||||||
public static Box2D Floor(Box2D val) => new(Vert.Floor(val.center), Double2.Floor(val.size));
|
|
||||||
public static Box2D Lerp(Box2D a, Box2D b, float t, bool clamp = true) =>
|
|
||||||
new(Vert.Lerp(a.center, b.center, t, clamp), Double2.Lerp(a.size, b.size, t, clamp));
|
|
||||||
public static Box2D Median(params Box2D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Median(verts), Double2.Median(sizes));
|
|
||||||
}
|
|
||||||
public static Box2D Max(params Box2D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Max(verts), Double2.Max(sizes));
|
|
||||||
}
|
|
||||||
public static Box2D Min(params Box2D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Min(verts), Double2.Min(sizes));
|
|
||||||
}
|
|
||||||
public static (Vert[] centers, Double2[] sizes) SplitArray(params Box2D[] vals)
|
|
||||||
{
|
|
||||||
Vert[] centers = new Vert[vals.Length];
|
|
||||||
Double2[] sizes = new Double2[vals.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < vals.Length; i++)
|
|
||||||
{
|
|
||||||
centers[i] = vals[i].center;
|
|
||||||
sizes[i] = vals[i].size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (centers, sizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Box2D)) return false;
|
|
||||||
return Equals((Box2D)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Box2D other) => center == other.center && size == other.size;
|
|
||||||
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
|
||||||
|
|
||||||
public bool Contains(Vert vert)
|
|
||||||
{
|
|
||||||
Double2 diff = Double2.Absolute((Double2)(center - vert));
|
|
||||||
return diff.x <= size.x && diff.y <= size.y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Clone() => new Box2D(center, size);
|
|
||||||
|
|
||||||
public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size);
|
|
||||||
public static Box2D operator +(Box2D a, Double2 b) => new(a.center, a.size + b);
|
|
||||||
public static Box2D operator -(Box2D b) => new(-b.MaxVert, -b.MinVert);
|
|
||||||
public static Box2D operator -(Box2D a, Vert b) => new(a.center - b, a.size);
|
|
||||||
public static Box2D operator -(Box2D a, Double2 b) => new(a.center, a.size - b);
|
|
||||||
public static Box2D operator *(Box2D a, double b) => new(a.center * b, a.size * b);
|
|
||||||
public static Box2D operator *(Box2D a, Double2 b) => new(a.center, a.size * b);
|
|
||||||
public static Box2D operator /(Box2D a, double b) => new(a.center / b, a.size / b);
|
|
||||||
public static Box2D operator /(Box2D a, Double2 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<double> fill) => new(fill);
|
|
||||||
public static explicit operator Box2D(Box3D box) => new(box.center, (Double2)box.size);
|
|
||||||
}
|
}
|
||||||
|
public Vert MinVert
|
||||||
|
{
|
||||||
|
get => center - (size / 2);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Vert diff = center + value;
|
||||||
|
size = (Double2)diff.position * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Area => size.x * size.y;
|
||||||
|
public double Perimeter => size.x * 2 + size.y * 2;
|
||||||
|
|
||||||
|
public Vert center;
|
||||||
|
public Double2 size;
|
||||||
|
|
||||||
|
public Box2D(Vert min, Vert max) : this(Vert.Average(min, max), (Double2)(min - max)) { }
|
||||||
|
public Box2D(Vert center, Double2 size)
|
||||||
|
{
|
||||||
|
this.center = center;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
public Box2D(Fill<double> fill) : this(fill, new Double2(fill(3), fill(4))) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
|
{
|
||||||
|
get => size[index];
|
||||||
|
set => size[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Box2D Absolute(Box2D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert));
|
||||||
|
public static Box2D Average(params Box2D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, Double2[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Average(centers), Double2.Average(sizes));
|
||||||
|
}
|
||||||
|
public static Box2D Ceiling(Box2D val) => new(Vert.Ceiling(val.center), Double2.Ceiling(val.size));
|
||||||
|
public static Box2D Clamp(Box2D val, Box2D min, Box2D max) =>
|
||||||
|
new(Vert.Clamp(val.center, min.center, max.center), Double2.Clamp(val.size, min.size, max.size));
|
||||||
|
public static Box2D Floor(Box2D val) => new(Vert.Floor(val.center), Double2.Floor(val.size));
|
||||||
|
public static Box2D Lerp(Box2D a, Box2D b, float t, bool clamp = true) =>
|
||||||
|
new(Vert.Lerp(a.center, b.center, t, clamp), Double2.Lerp(a.size, b.size, t, clamp));
|
||||||
|
public static Box2D Median(params Box2D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Median(verts), Double2.Median(sizes));
|
||||||
|
}
|
||||||
|
public static Box2D Max(params Box2D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Max(verts), Double2.Max(sizes));
|
||||||
|
}
|
||||||
|
public static Box2D Min(params Box2D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double2[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Min(verts), Double2.Min(sizes));
|
||||||
|
}
|
||||||
|
public static (Vert[] centers, Double2[] sizes) SplitArray(params Box2D[] vals)
|
||||||
|
{
|
||||||
|
Vert[] centers = new Vert[vals.Length];
|
||||||
|
Double2[] sizes = new Double2[vals.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < vals.Length; i++)
|
||||||
|
{
|
||||||
|
centers[i] = vals[i].center;
|
||||||
|
sizes[i] = vals[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (centers, sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Box2D)) return false;
|
||||||
|
return Equals((Box2D)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Box2D other) => center == other.center && size == other.size;
|
||||||
|
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||||
|
|
||||||
|
public bool Contains(Vert vert)
|
||||||
|
{
|
||||||
|
Double2 diff = Double2.Absolute((Double2)(center - vert));
|
||||||
|
return diff.x <= size.x && diff.y <= size.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Clone() => new Box2D(center, size);
|
||||||
|
|
||||||
|
public static Box2D operator +(Box2D a, Vert b) => new(a.center + b, a.size);
|
||||||
|
public static Box2D operator +(Box2D a, Double2 b) => new(a.center, a.size + b);
|
||||||
|
public static Box2D operator -(Box2D b) => new(-b.MaxVert, -b.MinVert);
|
||||||
|
public static Box2D operator -(Box2D a, Vert b) => new(a.center - b, a.size);
|
||||||
|
public static Box2D operator -(Box2D a, Double2 b) => new(a.center, a.size - b);
|
||||||
|
public static Box2D operator *(Box2D a, double b) => new(a.center * b, a.size * b);
|
||||||
|
public static Box2D operator *(Box2D a, Double2 b) => new(a.center, a.size * b);
|
||||||
|
public static Box2D operator /(Box2D a, double b) => new(a.center / b, a.size / b);
|
||||||
|
public static Box2D operator /(Box2D a, Double2 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<double> fill) => new(fill);
|
||||||
|
public static explicit operator Box2D(Box3D box) => new(box.center, (Double2)box.size);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,131 +1,122 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
||||||
{
|
{
|
||||||
public struct Box3D : ICloneable, IContainer<Vert>, IEquatable<Box3D>
|
public static Box3D Unit => new(Vert.Zero, Double3.One);
|
||||||
|
|
||||||
|
public Vert MaxVert
|
||||||
{
|
{
|
||||||
public static Box3D Unit => new(Vert.Zero, Double3.One);
|
get => center + (Vert)(size / 2);
|
||||||
|
set
|
||||||
public Vert MaxVert
|
|
||||||
{
|
{
|
||||||
get => center + (Vert)(size / 2);
|
Vert diff = center - value;
|
||||||
set
|
size = diff.position * 2;
|
||||||
{
|
|
||||||
Vert diff = center - value;
|
|
||||||
size = diff.position * 2;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public Vert MinVert
|
|
||||||
{
|
|
||||||
get => center - (Vert)(size / 2);
|
|
||||||
set
|
|
||||||
{
|
|
||||||
Vert diff = center + value;
|
|
||||||
size = diff.position * 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public double Area => size.x * size.y * size.z;
|
|
||||||
public double Perimeter => size.x * 2 + size.y * 2 + size.z * 2;
|
|
||||||
|
|
||||||
public Vert center;
|
|
||||||
public Double3 size;
|
|
||||||
|
|
||||||
public Box3D(Box2D box) : this(box.center, (Double3)box.size) { }
|
|
||||||
public Box3D(Vert min, Vert max) : this(Vert.Average(min, max), (Double3)(min - max)) { }
|
|
||||||
public Box3D(Vert center, Double3 size)
|
|
||||||
{
|
|
||||||
this.center = center;
|
|
||||||
this.size = size;
|
|
||||||
}
|
|
||||||
public Box3D(Fill<double> fill) : this(fill, new Double3(fill(3), fill(4), fill(5))) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => size[index];
|
|
||||||
set => size[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Box3D Absolute(Box3D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert));
|
|
||||||
public static Box3D Average(params Box3D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, Double3[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Average(centers), Double3.Average(sizes));
|
|
||||||
}
|
|
||||||
public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Double3.Ceiling(val.size));
|
|
||||||
public static Box3D Clamp(Box3D val, Box3D min, Box3D max) =>
|
|
||||||
new(Vert.Clamp(val.center, min.center, max.center), Double3.Clamp(val.size, min.size, max.size));
|
|
||||||
public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Double3.Floor(val.size));
|
|
||||||
public static Box3D Lerp(Box3D a, Box3D b, float t, bool clamp = true) =>
|
|
||||||
new(Vert.Lerp(a.center, b.center, t, clamp), Double3.Lerp(a.size, b.size, t, clamp));
|
|
||||||
public static Box3D Median(params Box3D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Median(verts), Double3.Median(sizes));
|
|
||||||
}
|
|
||||||
public static Box3D Max(params Box3D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Max(verts), Double3.Max(sizes));
|
|
||||||
}
|
|
||||||
public static Box3D Min(params Box3D[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
|
||||||
return new(Vert.Min(verts), Double3.Min(sizes));
|
|
||||||
}
|
|
||||||
public static (Vert[] centers, Double3[] sizes) SplitArray(params Box3D[] vals)
|
|
||||||
{
|
|
||||||
Vert[] centers = new Vert[vals.Length];
|
|
||||||
Double3[] sizes = new Double3[vals.Length];
|
|
||||||
|
|
||||||
for (int i = 0; i < vals.Length; i++)
|
|
||||||
{
|
|
||||||
centers[i] = vals[i].center;
|
|
||||||
sizes[i] = vals[i].size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (centers, sizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Box3D)) return false;
|
|
||||||
return Equals((Box3D)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Box3D other) => center == other.center && size == other.size;
|
|
||||||
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
|
||||||
|
|
||||||
public bool Contains(Vert vert)
|
|
||||||
{
|
|
||||||
Double3 diff = Double3.Absolute(center - vert);
|
|
||||||
return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object Clone() => new Box3D(center, size);
|
|
||||||
|
|
||||||
public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size);
|
|
||||||
public static Box3D operator +(Box3D a, Double3 b) => new(a.center, a.size + b);
|
|
||||||
public static Box3D operator -(Box3D b) => new(-b.MaxVert, -b.MinVert);
|
|
||||||
public static Box3D operator -(Box3D a, Vert b) => new(a.center - b, a.size);
|
|
||||||
public static Box3D operator -(Box3D a, Double3 b) => new(a.center, a.size - b);
|
|
||||||
public static Box3D operator *(Box3D a, double b) => new(a.center * b, a.size * b);
|
|
||||||
public static Box3D operator *(Box3D a, Double3 b) => new(a.center, a.size * b);
|
|
||||||
public static Box3D operator /(Box3D a, double b) => new(a.center / b, a.size / b);
|
|
||||||
public static Box3D operator /(Box3D a, Double3 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<double> fill) => new(fill);
|
|
||||||
public static implicit operator Box3D(Box2D box) => new(box);
|
|
||||||
}
|
}
|
||||||
|
public Vert MinVert
|
||||||
|
{
|
||||||
|
get => center - (Vert)(size / 2);
|
||||||
|
set
|
||||||
|
{
|
||||||
|
Vert diff = center + value;
|
||||||
|
size = diff.position * 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Area => size.x * size.y * size.z;
|
||||||
|
public double Perimeter => size.x * 2 + size.y * 2 + size.z * 2;
|
||||||
|
|
||||||
|
public Vert center;
|
||||||
|
public Double3 size;
|
||||||
|
|
||||||
|
public Box3D(Box2D box) : this(box.center, (Double3)box.size) { }
|
||||||
|
public Box3D(Vert min, Vert max) : this(Vert.Average(min, max), (Double3)(min - max)) { }
|
||||||
|
public Box3D(Vert center, Double3 size)
|
||||||
|
{
|
||||||
|
this.center = center;
|
||||||
|
this.size = size;
|
||||||
|
}
|
||||||
|
public Box3D(Fill<double> fill) : this(fill, new Double3(fill(3), fill(4), fill(5))) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
|
{
|
||||||
|
get => size[index];
|
||||||
|
set => size[index] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Box3D Absolute(Box3D val) => new(Vert.Absolute(val.MinVert), Vert.Absolute(val.MaxVert));
|
||||||
|
public static Box3D Average(params Box3D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, Double3[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Average(centers), Double3.Average(sizes));
|
||||||
|
}
|
||||||
|
public static Box3D Ceiling(Box3D val) => new(Vert.Ceiling(val.center), Double3.Ceiling(val.size));
|
||||||
|
public static Box3D Clamp(Box3D val, Box3D min, Box3D max) =>
|
||||||
|
new(Vert.Clamp(val.center, min.center, max.center), Double3.Clamp(val.size, min.size, max.size));
|
||||||
|
public static Box3D Floor(Box3D val) => new(Vert.Floor(val.center), Double3.Floor(val.size));
|
||||||
|
public static Box3D Lerp(Box3D a, Box3D b, float t, bool clamp = true) =>
|
||||||
|
new(Vert.Lerp(a.center, b.center, t, clamp), Double3.Lerp(a.size, b.size, t, clamp));
|
||||||
|
public static Box3D Median(params Box3D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Median(verts), Double3.Median(sizes));
|
||||||
|
}
|
||||||
|
public static Box3D Max(params Box3D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Max(verts), Double3.Max(sizes));
|
||||||
|
}
|
||||||
|
public static Box3D Min(params Box3D[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] verts, Double3[] sizes) = SplitArray(vals);
|
||||||
|
return new(Vert.Min(verts), Double3.Min(sizes));
|
||||||
|
}
|
||||||
|
public static (Vert[] centers, Double3[] sizes) SplitArray(params Box3D[] vals)
|
||||||
|
{
|
||||||
|
Vert[] centers = new Vert[vals.Length];
|
||||||
|
Double3[] sizes = new Double3[vals.Length];
|
||||||
|
|
||||||
|
for (int i = 0; i < vals.Length; i++)
|
||||||
|
{
|
||||||
|
centers[i] = vals[i].center;
|
||||||
|
sizes[i] = vals[i].size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (centers, sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Box3D)) return false;
|
||||||
|
return Equals((Box3D)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Box3D other) => center == other.center && size == other.size;
|
||||||
|
public override int GetHashCode() => center.GetHashCode() ^ size.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"Min: " + MinVert.ToString(provider) + " Max: " + MaxVert.ToString(provider);
|
||||||
|
|
||||||
|
public bool Contains(Vert vert)
|
||||||
|
{
|
||||||
|
Double3 diff = Double3.Absolute(center - vert);
|
||||||
|
return diff.x <= size.x && diff.y <= size.y && diff.z <= size.z;
|
||||||
|
}
|
||||||
|
public object Clone() => new Box3D(center, size);
|
||||||
|
|
||||||
|
public static Box3D operator +(Box3D a, Vert b) => new(a.center + b, a.size);
|
||||||
|
public static Box3D operator +(Box3D a, Double3 b) => new(a.center, a.size + b);
|
||||||
|
public static Box3D operator -(Box3D b) => new(-b.MaxVert, -b.MinVert);
|
||||||
|
public static Box3D operator -(Box3D a, Vert b) => new(a.center - b, a.size);
|
||||||
|
public static Box3D operator -(Box3D a, Double3 b) => new(a.center, a.size - b);
|
||||||
|
public static Box3D operator *(Box3D a, double b) => new(a.center * b, a.size * b);
|
||||||
|
public static Box3D operator *(Box3D a, Double3 b) => new(a.center, a.size * b);
|
||||||
|
public static Box3D operator /(Box3D a, double b) => new(a.center / b, a.size / b);
|
||||||
|
public static Box3D operator /(Box3D a, Double3 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<double> fill) => new(fill);
|
||||||
|
public static implicit operator Box3D(Box2D box) => new(box);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,7 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public interface ISubdividable<T>
|
||||||
{
|
{
|
||||||
public interface ISubdividable<T>
|
public T Subdivide();
|
||||||
{
|
public T Subdivide(int iterations);
|
||||||
public T Subdivide();
|
|
||||||
public T Subdivide(int iterations);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,20 +1,13 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public interface ITriangulatable
|
||||||
{
|
{
|
||||||
public interface ITriangulatable
|
public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables)
|
||||||
{
|
{
|
||||||
public static Triangle[] TriangulateAll(params ITriangulatable[] triangulatables)
|
List<Triangle> res = new();
|
||||||
{
|
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
|
||||||
List<Triangle> res = new();
|
return res.ToArray();
|
||||||
foreach (ITriangulatable triangulatable in triangulatables) res.AddRange(triangulatable.Triangulate());
|
|
||||||
return res.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Triangle[] Triangulate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Triangle[] Triangulate();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,202 +1,193 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<Vert>, IEquatable<Line>,
|
||||||
|
IGroup<Vert>, ISubdividable<Line[]>
|
||||||
{
|
{
|
||||||
public struct Line : ICloneable, IClosest<Vert>, IComparable<Line>, IContainer<Vert>, IEquatable<Line>,
|
public static Line Back => new(Vert.Zero, Vert.Back);
|
||||||
IGroup<Vert>, ISubdividable<Line[]>
|
public static Line Down => new(Vert.Zero, Vert.Down);
|
||||||
|
public static Line Forward => new(Vert.Zero, Vert.Forward);
|
||||||
|
public static Line Left => new(Vert.Zero, Vert.Left);
|
||||||
|
public static Line Right => new(Vert.Zero, Vert.Right);
|
||||||
|
public static Line Up => new(Vert.Zero, Vert.Up);
|
||||||
|
|
||||||
|
public static Line One => new(Vert.Zero, Vert.One);
|
||||||
|
public static Line Zero => new(Vert.Zero, Vert.Zero);
|
||||||
|
|
||||||
|
public double Length => (b - a).Magnitude;
|
||||||
|
|
||||||
|
public Vert a, b;
|
||||||
|
|
||||||
|
public Line(Vert a, Vert b)
|
||||||
{
|
{
|
||||||
public static Line Back => new(Vert.Zero, Vert.Back);
|
this.a = a;
|
||||||
public static Line Down => new(Vert.Zero, Vert.Down);
|
this.b = b;
|
||||||
public static Line Forward => new(Vert.Zero, Vert.Forward);
|
|
||||||
public static Line Left => new(Vert.Zero, Vert.Left);
|
|
||||||
public static Line Right => new(Vert.Zero, Vert.Right);
|
|
||||||
public static Line Up => new(Vert.Zero, Vert.Up);
|
|
||||||
|
|
||||||
public static Line One => new(Vert.Zero, Vert.One);
|
|
||||||
public static Line Zero => new(Vert.Zero, Vert.Zero);
|
|
||||||
|
|
||||||
public double Length => (b - a).Magnitude;
|
|
||||||
|
|
||||||
public Vert a, b;
|
|
||||||
|
|
||||||
public Line(Vert a, Vert b)
|
|
||||||
{
|
|
||||||
this.a = a;
|
|
||||||
this.b = b;
|
|
||||||
}
|
|
||||||
public Line(double x1, double y1, double x2, double y2) : this(new(x1, y1), new(x2, y2)) { }
|
|
||||||
public Line(double x1, double y1, double z1, double x2, double y2, double z2)
|
|
||||||
: this(new(x1, y1, z1), new(x2, y2, z2)) { }
|
|
||||||
public Line(Fill<Vert> fill) : this(fill(0), fill(1)) { }
|
|
||||||
public Line(Fill<Double3> fill) : this(new(fill(0)), new(fill(1))) { }
|
|
||||||
public Line(Fill<Int3> fill) : this(new(fill(0)), new(fill(1))) { }
|
|
||||||
public Line(Fill<double> fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { }
|
|
||||||
public Line(Fill<int> fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { }
|
|
||||||
|
|
||||||
public Vert this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => a,
|
|
||||||
1 => b,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
a = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
b = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b));
|
|
||||||
public static Line Average(params Line[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
|
||||||
return new(Vert.Average(starts), Vert.Average(ends));
|
|
||||||
}
|
|
||||||
public static Line Ceiling(Line val) => new(Vert.Ceiling(val.a), Vert.Ceiling(val.b));
|
|
||||||
public static Line Clamp(Line val, Line min, Line max) =>
|
|
||||||
new(Vert.Clamp(val.a, min.a, max.a), Vert.Clamp(val.b, min.b, max.b));
|
|
||||||
public static Line Floor(Line val) => new(Vert.Floor(val.a), Vert.Floor(val.b));
|
|
||||||
public static Line Lerp(Line a, Line b, double t, bool clamp = true) =>
|
|
||||||
new(Vert.Lerp(a.a, b.a, t, clamp), Vert.Lerp(a.b, b.b, t, clamp));
|
|
||||||
public static Line Median(params Line[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
|
||||||
return new(Vert.Median(starts), Vert.Median(ends));
|
|
||||||
}
|
|
||||||
public static Line Max(params Line[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
|
||||||
return new(Vert.Max(starts), Vert.Max(ends));
|
|
||||||
}
|
|
||||||
public static Line Min(params Line[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
|
||||||
return new(Vert.Min(starts), Vert.Min(ends));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines)
|
|
||||||
{
|
|
||||||
Vert[] starts = new Vert[lines.Length], ends = new Vert[lines.Length];
|
|
||||||
for (int i = 0; i < lines.Length; i++)
|
|
||||||
{
|
|
||||||
starts[i] = lines[i].a;
|
|
||||||
ends[i] = lines[i].b;
|
|
||||||
}
|
|
||||||
return (starts, ends);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Line)) return false;
|
|
||||||
return Equals((Line)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Line other) => a == other.a && b == other.b;
|
|
||||||
public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Line(a, b);
|
|
||||||
|
|
||||||
public int CompareTo(Line line) => Length.CompareTo(line.Length);
|
|
||||||
|
|
||||||
public bool Contains(Vert vert)
|
|
||||||
{
|
|
||||||
Double3 diffA = a - vert, diffB = a - b;
|
|
||||||
double lerpVal = diffA.Magnitude / diffB.Magnitude;
|
|
||||||
return Vert.Lerp(a, b, lerpVal) == vert;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vert ClosestTo(Vert vert) => ClosestTo(vert, Calculus.DefaultStep);
|
|
||||||
public Vert ClosestTo(Vert vert, double step)
|
|
||||||
{
|
|
||||||
Vert closestA = a, closestB = b;
|
|
||||||
for (double t = 0; t <= 1; t += step)
|
|
||||||
{
|
|
||||||
Vert valA = Vert.Lerp(a, b, t);
|
|
||||||
Vert valB = Vert.Lerp(b, a, t);
|
|
||||||
closestA = (valA - vert).Magnitude < (closestA - vert).Magnitude ? valA : closestA;
|
|
||||||
closestB = (valB - vert).Magnitude < (closestB - vert).Magnitude ? valB : closestB;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (closestA - vert).Magnitude >= (closestB - vert).Magnitude ? closestA : closestB;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<Vert> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return a;
|
|
||||||
yield return b;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Line[] Subdivide()
|
|
||||||
{
|
|
||||||
Vert middle = Vert.Lerp(a, b, 0.5);
|
|
||||||
return new Line[] { new(a, middle), new(middle, b) };
|
|
||||||
}
|
|
||||||
public Line[] Subdivide(int iterations)
|
|
||||||
{
|
|
||||||
if (iterations < 1) return Array.Empty<Line>();
|
|
||||||
List<Line> lines = new(Subdivide());
|
|
||||||
for (int i = 1; i < iterations; i++)
|
|
||||||
{
|
|
||||||
List<Line> add = new();
|
|
||||||
for (int j = 0; j < lines.Count; j++) add.AddRange(lines[j].Subdivide());
|
|
||||||
lines = add;
|
|
||||||
}
|
|
||||||
return lines.ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vert[] ToArray() => new Vert[] { a, b };
|
|
||||||
public List<Vert> ToList() => new() { a, b };
|
|
||||||
|
|
||||||
public double[] ToDoubleArray() => new double[] { a.position.x, a.position.y, a.position.z,
|
|
||||||
b.position.x, b.position.y, b.position.z };
|
|
||||||
public List<double> ToDoubleList() => new() { a.position.x, a.position.y, a.position.z,
|
|
||||||
b.position.x, b.position.y, b.position.z };
|
|
||||||
|
|
||||||
public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b);
|
|
||||||
public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b);
|
|
||||||
public static Line operator -(Line l) => new(-l.a, -l.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, 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, double b) => new(a.a * b, a.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, double b) => new(a.a / b, a.b / b);
|
|
||||||
public static bool operator ==(Line a, Line b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Line a, Line b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0;
|
|
||||||
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<Double3> fill) => new(fill);
|
|
||||||
public static implicit operator Line(Fill<Int3> fill) => new(fill);
|
|
||||||
public static implicit operator Line(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Line(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Line(double x1, double y1, double x2, double y2) : this(new(x1, y1), new(x2, y2)) { }
|
||||||
|
public Line(double x1, double y1, double z1, double x2, double y2, double z2)
|
||||||
|
: this(new(x1, y1, z1), new(x2, y2, z2)) { }
|
||||||
|
public Line(Fill<Vert> fill) : this(fill(0), fill(1)) { }
|
||||||
|
public Line(Fill<Double3> fill) : this(new(fill(0)), new(fill(1))) { }
|
||||||
|
public Line(Fill<Int3> fill) : this(new(fill(0)), new(fill(1))) { }
|
||||||
|
public Line(Fill<double> fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { }
|
||||||
|
public Line(Fill<int> fill) : this(new(fill(0), fill(1), fill(2)), new(fill(3), fill(4), fill(5))) { }
|
||||||
|
|
||||||
|
public Vert this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => a,
|
||||||
|
1 => b,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
a = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
b = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Line Absolute(Line val) => new(Vert.Absolute(val.a), Vert.Absolute(val.b));
|
||||||
|
public static Line Average(params Line[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||||
|
return new(Vert.Average(starts), Vert.Average(ends));
|
||||||
|
}
|
||||||
|
public static Line Ceiling(Line val) => new(Vert.Ceiling(val.a), Vert.Ceiling(val.b));
|
||||||
|
public static Line Clamp(Line val, Line min, Line max) =>
|
||||||
|
new(Vert.Clamp(val.a, min.a, max.a), Vert.Clamp(val.b, min.b, max.b));
|
||||||
|
public static Line Floor(Line val) => new(Vert.Floor(val.a), Vert.Floor(val.b));
|
||||||
|
public static Line Lerp(Line a, Line b, double t, bool clamp = true) =>
|
||||||
|
new(Vert.Lerp(a.a, b.a, t, clamp), Vert.Lerp(a.b, b.b, t, clamp));
|
||||||
|
public static Line Median(params Line[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||||
|
return new(Vert.Median(starts), Vert.Median(ends));
|
||||||
|
}
|
||||||
|
public static Line Max(params Line[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||||
|
return new(Vert.Max(starts), Vert.Max(ends));
|
||||||
|
}
|
||||||
|
public static Line Min(params Line[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] starts, Vert[] ends) = SplitArray(vals);
|
||||||
|
return new(Vert.Min(starts), Vert.Min(ends));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (Vert[] starts, Vert[] ends) SplitArray(params Line[] lines)
|
||||||
|
{
|
||||||
|
Vert[] starts = new Vert[lines.Length], ends = new Vert[lines.Length];
|
||||||
|
for (int i = 0; i < lines.Length; i++)
|
||||||
|
{
|
||||||
|
starts[i] = lines[i].a;
|
||||||
|
ends[i] = lines[i].b;
|
||||||
|
}
|
||||||
|
return (starts, ends);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Line)) return false;
|
||||||
|
return Equals((Line)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Line other) => a == other.a && b == other.b;
|
||||||
|
public override int GetHashCode() => a.GetHashCode() ^ b.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"A: " + a.ToString(provider) + " B: " + b.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Line(a, b);
|
||||||
|
|
||||||
|
public int CompareTo(Line line) => Length.CompareTo(line.Length);
|
||||||
|
|
||||||
|
public bool Contains(Vert vert)
|
||||||
|
{
|
||||||
|
Double3 diffA = a - vert, diffB = a - b;
|
||||||
|
double lerpVal = diffA.Magnitude / diffB.Magnitude;
|
||||||
|
return Vert.Lerp(a, b, lerpVal) == vert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vert ClosestTo(Vert vert) => ClosestTo(vert, Calculus.DefaultStep);
|
||||||
|
public Vert ClosestTo(Vert vert, double step)
|
||||||
|
{
|
||||||
|
Vert closestA = a, closestB = b;
|
||||||
|
for (double t = 0; t <= 1; t += step)
|
||||||
|
{
|
||||||
|
Vert valA = Vert.Lerp(a, b, t);
|
||||||
|
Vert valB = Vert.Lerp(b, a, t);
|
||||||
|
closestA = (valA - vert).Magnitude < (closestA - vert).Magnitude ? valA : closestA;
|
||||||
|
closestB = (valB - vert).Magnitude < (closestB - vert).Magnitude ? valB : closestB;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (closestA - vert).Magnitude >= (closestB - vert).Magnitude ? closestA : closestB;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<Vert> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return a;
|
||||||
|
yield return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Line[] Subdivide()
|
||||||
|
{
|
||||||
|
Vert middle = Vert.Lerp(a, b, 0.5);
|
||||||
|
return new Line[] { new(a, middle), new(middle, b) };
|
||||||
|
}
|
||||||
|
public Line[] Subdivide(int iterations)
|
||||||
|
{
|
||||||
|
if (iterations < 1) return Array.Empty<Line>();
|
||||||
|
List<Line> lines = new(Subdivide());
|
||||||
|
for (int i = 1; i < iterations; i++)
|
||||||
|
{
|
||||||
|
List<Line> add = new();
|
||||||
|
for (int j = 0; j < lines.Count; j++) add.AddRange(lines[j].Subdivide());
|
||||||
|
lines = add;
|
||||||
|
}
|
||||||
|
return lines.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Vert[] ToArray() => new Vert[] { a, b };
|
||||||
|
public List<Vert> ToList() => new() { a, b };
|
||||||
|
|
||||||
|
public double[] ToDoubleArray() => new double[] { a.position.x, a.position.y, a.position.z,
|
||||||
|
b.position.x, b.position.y, b.position.z };
|
||||||
|
public List<double> ToDoubleList() => new() { a.position.x, a.position.y, a.position.z,
|
||||||
|
b.position.x, b.position.y, b.position.z };
|
||||||
|
|
||||||
|
public static Line operator +(Line a, Line b) => new(a.a + b.a, a.b + b.b);
|
||||||
|
public static Line operator +(Line a, Vert b) => new(a.a + b, a.b + b);
|
||||||
|
public static Line operator -(Line l) => new(-l.a, -l.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, 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, double b) => new(a.a * b, a.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, double b) => new(a.a / b, a.b / b);
|
||||||
|
public static bool operator ==(Line a, Line b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Line a, Line b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Line a, Line b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Line a, Line b) => a.CompareTo(b) < 0;
|
||||||
|
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<Double3> fill) => new(fill);
|
||||||
|
public static implicit operator Line(Fill<Int3> fill) => new(fill);
|
||||||
|
public static implicit operator Line(Fill<double> fill) => new(fill);
|
||||||
|
public static implicit operator Line(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,16 +1,8 @@
|
|||||||
using Nerd_STF.Exceptions;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdividable<Polygon>, ITriangulatable
|
||||||
{
|
{
|
||||||
public struct Polygon : ICloneable, IEquatable<Polygon>, IGroup<Vert>, ISubdividable<Polygon>, ITriangulatable
|
public Line[] Lines
|
||||||
{
|
|
||||||
public Line[] Lines
|
|
||||||
{
|
{
|
||||||
get => p_lines;
|
get => p_lines;
|
||||||
set
|
set
|
||||||
@ -19,7 +11,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_verts = GenerateVerts(value);
|
p_verts = GenerateVerts(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert[] Verts
|
public Vert[] Verts
|
||||||
{
|
{
|
||||||
get => p_verts;
|
get => p_verts;
|
||||||
set
|
set
|
||||||
@ -29,21 +21,21 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Line[] p_lines;
|
private Line[] p_lines;
|
||||||
private Vert[] p_verts;
|
private Vert[] p_verts;
|
||||||
|
|
||||||
[Obsolete("This method uses the Polygon.Triangulate() function, which has issues. It will be fixed in a " +
|
[Obsolete("This method uses the Polygon.Triangulate() function, which has issues. It will be fixed in a " +
|
||||||
"future update.")]
|
"future update.")]
|
||||||
public double Area
|
public double Area
|
||||||
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
get
|
double val = 0;
|
||||||
{
|
foreach (Triangle t in Triangulate()) val += t.Area;
|
||||||
double val = 0;
|
return val;
|
||||||
foreach (Triangle t in Triangulate()) val += t.Area;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public double Perimeter
|
}
|
||||||
|
public double Perimeter
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -53,12 +45,12 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Polygon()
|
public Polygon()
|
||||||
{
|
{
|
||||||
p_lines = Array.Empty<Line>();
|
p_lines = Array.Empty<Line>();
|
||||||
p_verts = Array.Empty<Vert>();
|
p_verts = Array.Empty<Vert>();
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Vert?> fill)
|
public Polygon(Fill<Vert?> fill)
|
||||||
{
|
{
|
||||||
List<Vert> verts = new();
|
List<Vert> verts = new();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -70,7 +62,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
this = new(verts.ToArray());
|
this = new(verts.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Double3?> fill)
|
public Polygon(Fill<Double3?> fill)
|
||||||
{
|
{
|
||||||
List<Vert> verts = new();
|
List<Vert> verts = new();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -82,7 +74,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
this = new(verts.ToArray());
|
this = new(verts.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Line?> fill)
|
public Polygon(Fill<Line?> fill)
|
||||||
{
|
{
|
||||||
List<Line> lines = new();
|
List<Line> lines = new();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
@ -94,65 +86,65 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
this = new(lines.ToArray());
|
this = new(lines.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Vert> fill, int length)
|
public Polygon(Fill<Vert> fill, int length)
|
||||||
{
|
{
|
||||||
List<Vert> verts = new();
|
List<Vert> verts = new();
|
||||||
for (int i = 0; i < length; i++) verts.Add(fill(i));
|
for (int i = 0; i < length; i++) verts.Add(fill(i));
|
||||||
this = new(verts.ToArray());
|
this = new(verts.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Double3> fill, int length)
|
public Polygon(Fill<Double3> fill, int length)
|
||||||
{
|
{
|
||||||
List<Vert> verts = new();
|
List<Vert> verts = new();
|
||||||
for (int i = 0; i < length; i++) verts.Add(fill(i));
|
for (int i = 0; i < length; i++) verts.Add(fill(i));
|
||||||
this = new(verts.ToArray());
|
this = new(verts.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(Fill<Line> fill, int length)
|
public Polygon(Fill<Line> fill, int length)
|
||||||
{
|
{
|
||||||
List<Line> lines = new();
|
List<Line> lines = new();
|
||||||
for (int i = 0; i < length; i++) lines.Add(fill(i));
|
for (int i = 0; i < length; i++) lines.Add(fill(i));
|
||||||
this = new(lines.ToArray());
|
this = new(lines.ToArray());
|
||||||
}
|
}
|
||||||
public Polygon(params Double3[] verts)
|
public Polygon(params Double3[] verts)
|
||||||
{
|
{
|
||||||
p_verts = new Vert[verts.Length];
|
p_verts = new Vert[verts.Length];
|
||||||
for (int i = 0; i < verts.Length; i++) p_verts[i] = verts[i];
|
for (int i = 0; i < verts.Length; i++) p_verts[i] = verts[i];
|
||||||
p_lines = GenerateLines(p_verts);
|
p_lines = GenerateLines(p_verts);
|
||||||
}
|
}
|
||||||
public Polygon(params Vert[] verts)
|
public Polygon(params Vert[] verts)
|
||||||
{
|
{
|
||||||
p_verts = verts;
|
p_verts = verts;
|
||||||
p_lines = GenerateLines(verts);
|
p_lines = GenerateLines(verts);
|
||||||
}
|
}
|
||||||
public Polygon(params Line[] lines)
|
public Polygon(params Line[] lines)
|
||||||
{
|
{
|
||||||
p_lines = lines;
|
p_lines = lines;
|
||||||
p_verts = GenerateVerts(lines);
|
p_verts = GenerateVerts(lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vert this[int index]
|
public Vert this[int index]
|
||||||
{
|
{
|
||||||
get => Verts[index];
|
get => Verts[index];
|
||||||
set => Verts[index] = value;
|
set => Verts[index] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Polygon CreateCircle(int vertCount)
|
public static Polygon CreateCircle(int vertCount)
|
||||||
|
{
|
||||||
|
List<Vert> parts = new();
|
||||||
|
for (int i = 0; i < vertCount; i++)
|
||||||
{
|
{
|
||||||
List<Vert> parts = new();
|
double val = Mathf.Tau * i / vertCount;
|
||||||
for (int i = 0; i < vertCount; i++)
|
parts.Add(new(Mathf.Cos(val), Mathf.Sin(val)));
|
||||||
{
|
|
||||||
double val = Mathf.Tau * i / vertCount;
|
|
||||||
parts.Add(new(Mathf.Cos(val), Mathf.Sin(val)));
|
|
||||||
}
|
|
||||||
return new(parts.ToArray());
|
|
||||||
}
|
}
|
||||||
|
return new(parts.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
public static Polygon Absolute(Polygon val)
|
public static Polygon Absolute(Polygon val)
|
||||||
{
|
{
|
||||||
Vert[] v = val.Verts;
|
Vert[] v = val.Verts;
|
||||||
for (int i = 0; i < v.Length; i++) v[i] = Vert.Absolute(v[i]);
|
for (int i = 0; i < v.Length; i++) v[i] = Vert.Absolute(v[i]);
|
||||||
return new(v);
|
return new(v);
|
||||||
}
|
}
|
||||||
public static Polygon Average(params Polygon[] vals)
|
public static Polygon Average(params Polygon[] vals)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||||
if (vals.Length < 1) return default;
|
if (vals.Length < 1) return default;
|
||||||
@ -170,13 +162,13 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
|
|
||||||
return new(res);
|
return new(res);
|
||||||
}
|
}
|
||||||
public static Polygon Ceiling(Polygon val)
|
public static Polygon Ceiling(Polygon val)
|
||||||
{
|
{
|
||||||
Vert[] v = val.Verts;
|
Vert[] v = val.Verts;
|
||||||
for (int i = 0; i < v.Length; i++) v[i] = Vert.Ceiling(v[i]);
|
for (int i = 0; i < v.Length; i++) v[i] = Vert.Ceiling(v[i]);
|
||||||
return new(v);
|
return new(v);
|
||||||
}
|
}
|
||||||
public static Polygon Clamp(Polygon val, Polygon min, Polygon max)
|
public static Polygon Clamp(Polygon val, Polygon min, Polygon max)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(val, min, max)) throw new DifferingVertCountException(val, min, max);
|
if (!CheckVerts(val, min, max)) throw new DifferingVertCountException(val, min, max);
|
||||||
Line[][] lines = new Line[3][] { val.Lines, min.Lines, max.Lines };
|
Line[][] lines = new Line[3][] { val.Lines, min.Lines, max.Lines };
|
||||||
@ -184,13 +176,13 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
for (int i = 0; i < res.Length; i++) res[i] = Line.Clamp(lines[0][i], lines[1][i], lines[2][i]);
|
for (int i = 0; i < res.Length; i++) res[i] = Line.Clamp(lines[0][i], lines[1][i], lines[2][i]);
|
||||||
return new(res);
|
return new(res);
|
||||||
}
|
}
|
||||||
public static Polygon Floor(Polygon val)
|
public static Polygon Floor(Polygon val)
|
||||||
{
|
{
|
||||||
Vert[] v = val.Verts;
|
Vert[] v = val.Verts;
|
||||||
for (int i = 0; i < v.Length; i++) v[i] = Vert.Floor(v[i]);
|
for (int i = 0; i < v.Length; i++) v[i] = Vert.Floor(v[i]);
|
||||||
return new(v);
|
return new(v);
|
||||||
}
|
}
|
||||||
public static Polygon Lerp(Polygon a, Polygon b, double t, bool clamp = true)
|
public static Polygon Lerp(Polygon a, Polygon b, double t, bool clamp = true)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
||||||
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
||||||
@ -198,7 +190,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
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);
|
return new(res);
|
||||||
}
|
}
|
||||||
public static Polygon Max(params Polygon[] vals)
|
public static Polygon Max(params Polygon[] vals)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||||
if (vals.Length < 1) return default;
|
if (vals.Length < 1) return default;
|
||||||
@ -216,7 +208,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
|
|
||||||
return new(res);
|
return new(res);
|
||||||
}
|
}
|
||||||
public static Polygon Median(params Polygon[] vals)
|
public static Polygon Median(params Polygon[] vals)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||||
if (vals.Length < 1) return default;
|
if (vals.Length < 1) return default;
|
||||||
@ -234,7 +226,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
|
|
||||||
return new(res);
|
return new(res);
|
||||||
}
|
}
|
||||||
public static Polygon Min(params Polygon[] vals)
|
public static Polygon Min(params Polygon[] vals)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
if (!CheckVerts(vals)) throw new DifferingVertCountException(nameof(vals), vals);
|
||||||
if (vals.Length < 1) return default;
|
if (vals.Length < 1) return default;
|
||||||
@ -253,48 +245,48 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
return new(res);
|
return new(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray();
|
public static double[] ToDoubleArrayAll(params Polygon[] polys) => ToDoubleListAll(polys).ToArray();
|
||||||
public static List<double> ToDoubleListAll(params Polygon[] polys)
|
public static List<double> ToDoubleListAll(params Polygon[] polys)
|
||||||
{
|
{
|
||||||
List<double> vals = new();
|
List<double> vals = new();
|
||||||
foreach (Polygon poly in polys) vals.AddRange(poly.ToDoubleArray());
|
foreach (Polygon poly in polys) vals.AddRange(poly.ToDoubleArray());
|
||||||
return vals;
|
return vals;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
{
|
{
|
||||||
if (obj == null || obj.GetType() != typeof(Polygon)) return false;
|
if (obj == null || obj.GetType() != typeof(Polygon)) return false;
|
||||||
return Equals((Polygon)obj);
|
return Equals((Polygon)obj);
|
||||||
}
|
}
|
||||||
public bool Equals(Polygon other)
|
public bool Equals(Polygon other)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(this, other)) return false;
|
if (!CheckVerts(this, other)) return false;
|
||||||
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() => ToString((string?)null);
|
||||||
public string ToString(string? provider)
|
public string ToString(string? provider)
|
||||||
{
|
{
|
||||||
string s = "";
|
string s = "";
|
||||||
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
public string ToString(IFormatProvider provider)
|
public string ToString(IFormatProvider provider)
|
||||||
{
|
{
|
||||||
string s = "";
|
string s = "";
|
||||||
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
for (int i = 0; i < Lines.Length; i++) s += "L" + i + ": " + Lines[i].ToString(provider) + " ";
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public object Clone() => new Polygon(Lines);
|
public object Clone() => new Polygon(Lines);
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
public IEnumerator<Vert> GetEnumerator() { foreach (Vert v in Verts) yield return v; }
|
public IEnumerator<Vert> GetEnumerator() { foreach (Vert v in Verts) yield return v; }
|
||||||
|
|
||||||
public Vert[] ToArray() => Verts;
|
public Vert[] ToArray() => Verts;
|
||||||
public List<Vert> ToList() => new(Verts);
|
public List<Vert> ToList() => new(Verts);
|
||||||
|
|
||||||
public double[] ToDoubleArray()
|
public double[] ToDoubleArray()
|
||||||
{
|
{
|
||||||
double[] vals = new double[Verts.Length * 3];
|
double[] vals = new double[Verts.Length * 3];
|
||||||
for (int i = 0; i < Verts.Length; i++)
|
for (int i = 0; i < Verts.Length; i++)
|
||||||
@ -306,57 +298,57 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
return vals;
|
return vals;
|
||||||
}
|
}
|
||||||
public List<double> ToDoubleList() => new(ToDoubleArray());
|
public List<double> ToDoubleList() => new(ToDoubleArray());
|
||||||
|
|
||||||
public Polygon Subdivide()
|
public Polygon Subdivide()
|
||||||
{
|
{
|
||||||
Polygon poly = new();
|
Polygon poly = new();
|
||||||
List<Line> lines = new();
|
List<Line> lines = new();
|
||||||
for (int i = 0; i < Lines.Length; i++) lines.AddRange(Lines[i].Subdivide());
|
for (int i = 0; i < Lines.Length; i++) lines.AddRange(Lines[i].Subdivide());
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
public Polygon Subdivide(int iterations)
|
public Polygon Subdivide(int iterations)
|
||||||
{
|
{
|
||||||
if (iterations < 1) return new();
|
if (iterations < 1) return new();
|
||||||
Polygon poly = this;
|
Polygon poly = this;
|
||||||
for (int i = 0; i < iterations; i++) poly = poly.Subdivide();
|
for (int i = 0; i < iterations; i++) poly = poly.Subdivide();
|
||||||
return poly;
|
return poly;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Polygon SubdivideCatmullClark(int segments)
|
public Polygon SubdivideCatmullClark(int segments)
|
||||||
|
{
|
||||||
|
// Thanks Saalty for making this accidentally.
|
||||||
|
List<Vert> newVerts = new();
|
||||||
|
for (int i = 0; i < Verts.Length; i++)
|
||||||
{
|
{
|
||||||
// Thanks Saalty for making this accidentally.
|
for (int factor = 0; factor < segments; factor++)
|
||||||
List<Vert> newVerts = new();
|
|
||||||
for (int i = 0; i < Verts.Length; i++)
|
|
||||||
{
|
{
|
||||||
for (int factor = 0; factor < segments; factor++)
|
double unit = factor / (double)(segments * 2), unit2 = unit + 0.5, lastUnit = unit * 2;
|
||||||
|
Vert p1, p2;
|
||||||
|
if (i == Verts.Length - 1)
|
||||||
{
|
{
|
||||||
double unit = factor / (double)(segments * 2), unit2 = unit + 0.5, lastUnit = unit * 2;
|
p1 = Verts[^1] + (Verts[0] - Verts[^1]) * unit2;
|
||||||
Vert p1, p2;
|
p2 = Verts[0] + (Verts[1] - Verts[0]) * unit;
|
||||||
if (i == Verts.Length - 1)
|
|
||||||
{
|
|
||||||
p1 = Verts[^1] + (Verts[0] - Verts[^1]) * unit2;
|
|
||||||
p2 = Verts[0] + (Verts[1] - Verts[0]) * unit;
|
|
||||||
}
|
|
||||||
else if (i == Verts.Length - 2)
|
|
||||||
{
|
|
||||||
p1 = Verts[^2] + (Verts[^1] - Verts[^2]) * unit2;
|
|
||||||
p2 = Verts[^1] + (Verts[0] - Verts[^1]) * unit;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p1 = Verts[i] + (Verts[i + 1] - Verts[i]) * unit2;
|
|
||||||
p2 = Verts[i + 1] + (Verts[i + 2] - Verts[i + 1]) * unit;
|
|
||||||
}
|
|
||||||
newVerts.Add(p1 + (p2 - p1) * lastUnit);
|
|
||||||
}
|
}
|
||||||
|
else if (i == Verts.Length - 2)
|
||||||
|
{
|
||||||
|
p1 = Verts[^2] + (Verts[^1] - Verts[^2]) * unit2;
|
||||||
|
p2 = Verts[^1] + (Verts[0] - Verts[^1]) * unit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p1 = Verts[i] + (Verts[i + 1] - Verts[i]) * unit2;
|
||||||
|
p2 = Verts[i + 1] + (Verts[i + 2] - Verts[i + 1]) * unit;
|
||||||
|
}
|
||||||
|
newVerts.Add(p1 + (p2 - p1) * lastUnit);
|
||||||
}
|
}
|
||||||
return new(newVerts.ToArray());
|
|
||||||
}
|
}
|
||||||
|
return new(newVerts.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("This method doesn't work very well, and will give very weird results in certain cases. " +
|
[Obsolete("This method doesn't work very well, and will give very weird results in certain cases. " +
|
||||||
"This will be fixed in a future update.")]
|
"This will be fixed in a future update.")]
|
||||||
public Triangle[] Triangulate()
|
public Triangle[] Triangulate()
|
||||||
{
|
{
|
||||||
// This may cause issues. FIXME
|
// This may cause issues. FIXME
|
||||||
// Tbh, not even sure if this works. This was a bit confusing.
|
// Tbh, not even sure if this works. This was a bit confusing.
|
||||||
@ -397,7 +389,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
return tris.ToArray();
|
return tris.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CheckVerts(params Polygon[] polys)
|
private static bool CheckVerts(params Polygon[] polys)
|
||||||
{
|
{
|
||||||
int len = -1;
|
int len = -1;
|
||||||
foreach (Polygon poly in polys)
|
foreach (Polygon poly in polys)
|
||||||
@ -411,14 +403,14 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
private static Line[] GenerateLines(Vert[] verts)
|
private static Line[] GenerateLines(Vert[] verts)
|
||||||
{
|
{
|
||||||
Line[] lines = new Line[verts.Length];
|
Line[] lines = new Line[verts.Length];
|
||||||
for (int i = 0; i < lines.Length; i++)
|
for (int i = 0; i < lines.Length; i++)
|
||||||
lines[i] = new(verts[i], verts[i == lines.Length - 1 ? 0 : i + 1]);
|
lines[i] = new(verts[i], verts[i == lines.Length - 1 ? 0 : i + 1]);
|
||||||
return lines;
|
return lines;
|
||||||
}
|
}
|
||||||
private static Vert[] GenerateVerts(Line[] lines)
|
private static Vert[] GenerateVerts(Line[] lines)
|
||||||
{
|
{
|
||||||
Vert[] verts = new Vert[lines.Length];
|
Vert[] verts = new Vert[lines.Length];
|
||||||
for (int i = 0; i < verts.Length; i++)
|
for (int i = 0; i < verts.Length; i++)
|
||||||
@ -430,90 +422,89 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
return verts;
|
return verts;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Polygon operator +(Polygon a, Polygon b)
|
public static Polygon operator +(Polygon a, Polygon b)
|
||||||
{
|
{
|
||||||
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
||||||
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] = lines[0][i] + lines[1][i];
|
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] + lines[1][i];
|
||||||
return new(res);
|
return new(res);
|
||||||
}
|
|
||||||
public static Polygon operator +(Polygon a, Vert b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] += b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator -(Polygon p)
|
|
||||||
{
|
|
||||||
Line[] lines = p.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] = -lines[i];
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator -(Polygon a, Polygon b)
|
|
||||||
{
|
|
||||||
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
|
||||||
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
|
||||||
Line[] res = new Line[a.Lines.Length];
|
|
||||||
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] - lines[1][i];
|
|
||||||
return new(res);
|
|
||||||
}
|
|
||||||
public static Polygon operator -(Polygon a, Vert b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] -= b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator *(Polygon a, Polygon b)
|
|
||||||
{
|
|
||||||
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
|
||||||
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
|
||||||
Line[] res = new Line[a.Lines.Length];
|
|
||||||
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] * lines[1][i];
|
|
||||||
return new(res);
|
|
||||||
}
|
|
||||||
public static Polygon operator *(Polygon a, Vert b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] *= b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator *(Polygon a, float b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] *= b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator /(Polygon a, Polygon b)
|
|
||||||
{
|
|
||||||
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
|
||||||
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
|
||||||
Line[] res = new Line[a.Lines.Length];
|
|
||||||
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] / lines[1][i];
|
|
||||||
return new(res);
|
|
||||||
}
|
|
||||||
public static Polygon operator /(Polygon a, Vert b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] /= b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static Polygon operator /(Polygon a, float b)
|
|
||||||
{
|
|
||||||
Line[] lines = a.Lines;
|
|
||||||
for (int i = 0; i < lines.Length; i++) lines[i] /= b;
|
|
||||||
return new(lines);
|
|
||||||
}
|
|
||||||
public static bool operator ==(Polygon a, Polygon b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Polygon a, Polygon b) => !a.Equals(b);
|
|
||||||
|
|
||||||
public static implicit operator Polygon(Fill<Vert?> fill) => new(fill);
|
|
||||||
public static implicit operator Polygon(Fill<Double3?> fill) => new(fill);
|
|
||||||
public static implicit operator Polygon(Fill<Line?> fill) => new(fill);
|
|
||||||
public static implicit operator Polygon(Vert[] verts) => new(verts);
|
|
||||||
public static implicit operator Polygon(Double3[] verts) => new(verts);
|
|
||||||
public static implicit operator Polygon(Line[] lines) => new(lines);
|
|
||||||
public static implicit operator Polygon(Triangle tri) => new(tri.AB, tri.BC, tri.CA);
|
|
||||||
public static implicit operator Polygon(Quadrilateral quad) => new(quad.AB, quad.BC, quad.CD, quad.DA);
|
|
||||||
}
|
}
|
||||||
|
public static Polygon operator +(Polygon a, Vert b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] += b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator -(Polygon p)
|
||||||
|
{
|
||||||
|
Line[] lines = p.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] = -lines[i];
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator -(Polygon a, Polygon b)
|
||||||
|
{
|
||||||
|
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
||||||
|
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
||||||
|
Line[] res = new Line[a.Lines.Length];
|
||||||
|
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] - lines[1][i];
|
||||||
|
return new(res);
|
||||||
|
}
|
||||||
|
public static Polygon operator -(Polygon a, Vert b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] -= b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator *(Polygon a, Polygon b)
|
||||||
|
{
|
||||||
|
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
||||||
|
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
||||||
|
Line[] res = new Line[a.Lines.Length];
|
||||||
|
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] * lines[1][i];
|
||||||
|
return new(res);
|
||||||
|
}
|
||||||
|
public static Polygon operator *(Polygon a, Vert b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] *= b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator *(Polygon a, float b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] *= b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator /(Polygon a, Polygon b)
|
||||||
|
{
|
||||||
|
if (!CheckVerts(a, b)) throw new DifferingVertCountException(a, b);
|
||||||
|
Line[][] lines = new Line[2][] { a.Lines, b.Lines };
|
||||||
|
Line[] res = new Line[a.Lines.Length];
|
||||||
|
for (int i = 0; i < res.Length; i++) res[i] = lines[0][i] / lines[1][i];
|
||||||
|
return new(res);
|
||||||
|
}
|
||||||
|
public static Polygon operator /(Polygon a, Vert b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] /= b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static Polygon operator /(Polygon a, float b)
|
||||||
|
{
|
||||||
|
Line[] lines = a.Lines;
|
||||||
|
for (int i = 0; i < lines.Length; i++) lines[i] /= b;
|
||||||
|
return new(lines);
|
||||||
|
}
|
||||||
|
public static bool operator ==(Polygon a, Polygon b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Polygon a, Polygon b) => !a.Equals(b);
|
||||||
|
|
||||||
|
public static implicit operator Polygon(Fill<Vert?> fill) => new(fill);
|
||||||
|
public static implicit operator Polygon(Fill<Double3?> fill) => new(fill);
|
||||||
|
public static implicit operator Polygon(Fill<Line?> fill) => new(fill);
|
||||||
|
public static implicit operator Polygon(Vert[] verts) => new(verts);
|
||||||
|
public static implicit operator Polygon(Double3[] verts) => new(verts);
|
||||||
|
public static implicit operator Polygon(Line[] lines) => new(lines);
|
||||||
|
public static implicit operator Polygon(Triangle tri) => new(tri.AB, tri.BC, tri.CA);
|
||||||
|
public static implicit operator Polygon(Quadrilateral quad) => new(quad.AB, quad.BC, quad.CD, quad.DA);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,8 @@
|
|||||||
using Nerd_STF.Exceptions;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert>, ITriangulatable
|
||||||
{
|
{
|
||||||
public struct Quadrilateral : ICloneable, IEquatable<Quadrilateral>, IGroup<Vert>, ITriangulatable
|
public Vert A
|
||||||
{
|
|
||||||
public Vert A
|
|
||||||
{
|
{
|
||||||
get => p_a;
|
get => p_a;
|
||||||
set
|
set
|
||||||
@ -21,7 +12,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_da.b = value;
|
p_da.b = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert B
|
public Vert B
|
||||||
{
|
{
|
||||||
get => p_b;
|
get => p_b;
|
||||||
set
|
set
|
||||||
@ -31,7 +22,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_bc.a = value;
|
p_bc.a = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert C
|
public Vert C
|
||||||
{
|
{
|
||||||
get => p_c;
|
get => p_c;
|
||||||
set
|
set
|
||||||
@ -41,7 +32,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_cd.a = value;
|
p_cd.a = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert D
|
public Vert D
|
||||||
{
|
{
|
||||||
get => p_d;
|
get => p_d;
|
||||||
set
|
set
|
||||||
@ -51,7 +42,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_da.a = value;
|
p_da.a = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line AB
|
public Line AB
|
||||||
{
|
{
|
||||||
get => p_ab;
|
get => p_ab;
|
||||||
set
|
set
|
||||||
@ -63,7 +54,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_da.b = value.a;
|
p_da.b = value.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line BC
|
public Line BC
|
||||||
{
|
{
|
||||||
get => p_bc;
|
get => p_bc;
|
||||||
set
|
set
|
||||||
@ -75,7 +66,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_ab.b = value.a;
|
p_ab.b = value.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line CD
|
public Line CD
|
||||||
{
|
{
|
||||||
get => p_cd;
|
get => p_cd;
|
||||||
set
|
set
|
||||||
@ -87,7 +78,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_bc.b = value.a;
|
p_bc.b = value.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line DA
|
public Line DA
|
||||||
{
|
{
|
||||||
get => p_da;
|
get => p_da;
|
||||||
set
|
set
|
||||||
@ -100,21 +91,21 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vert p_a, p_b, p_c, p_d;
|
private Vert p_a, p_b, p_c, p_d;
|
||||||
private Line p_ab, p_bc, p_cd, p_da;
|
private Line p_ab, p_bc, p_cd, p_da;
|
||||||
|
|
||||||
public double Area
|
public double Area
|
||||||
|
{
|
||||||
|
get
|
||||||
{
|
{
|
||||||
get
|
double val = 0;
|
||||||
{
|
foreach (Triangle t in Triangulate()) val += t.Area;
|
||||||
double val = 0;
|
return val;
|
||||||
foreach (Triangle t in Triangulate()) val += t.Area;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
public double Perimeter => AB.Length + BC.Length + CD.Length + DA.Length;
|
}
|
||||||
|
public double Perimeter => AB.Length + BC.Length + CD.Length + DA.Length;
|
||||||
|
|
||||||
public Quadrilateral(Vert a, Vert b, Vert c, Vert d)
|
public Quadrilateral(Vert a, Vert b, Vert c, Vert d)
|
||||||
{
|
{
|
||||||
p_a = a;
|
p_a = a;
|
||||||
p_b = b;
|
p_b = b;
|
||||||
@ -125,7 +116,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_cd = new(c, d);
|
p_cd = new(c, d);
|
||||||
p_da = new(d, a);
|
p_da = new(d, a);
|
||||||
}
|
}
|
||||||
public Quadrilateral(Line ab, Line bc, Line cd, Line da)
|
public Quadrilateral(Line ab, Line bc, Line cd, Line da)
|
||||||
{
|
{
|
||||||
if (ab.a != da.b || ab.b != bc.a || bc.b != cd.a || cd.b != da.a)
|
if (ab.a != da.b || ab.b != bc.a || bc.b != cd.a || cd.b != da.a)
|
||||||
throw new DisconnectedLinesException(ab, bc, cd, da);
|
throw new DisconnectedLinesException(ab, bc, cd, da);
|
||||||
@ -139,21 +130,21 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_cd = cd;
|
p_cd = cd;
|
||||||
p_da = da;
|
p_da = da;
|
||||||
}
|
}
|
||||||
public Quadrilateral(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
|
public Quadrilateral(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
|
||||||
: this(new Vert(x1, y1), new(x2, y2), new(x3, y3), new(x4, y4)) { }
|
: this(new Vert(x1, y1), new(x2, y2), new(x3, y3), new(x4, y4)) { }
|
||||||
public Quadrilateral(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3,
|
public Quadrilateral(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3,
|
||||||
double z3, double x4, double y4, double z4)
|
double z3, double x4, double y4, double z4)
|
||||||
: this(new Vert(x1, y1, z1), new(x2, y2, z2), new(x3, y3, z3), new(x4, y4, z4)) { }
|
: this(new Vert(x1, y1, z1), new(x2, y2, z2), new(x3, y3, z3), new(x4, y4, z4)) { }
|
||||||
public Quadrilateral(Fill<Double3> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
public Quadrilateral(Fill<Double3> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
public Quadrilateral(Fill<Int3> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
public Quadrilateral(Fill<Int3> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
public Quadrilateral(Fill<Vert> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
public Quadrilateral(Fill<Vert> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
public Quadrilateral(Fill<Line> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
public Quadrilateral(Fill<Line> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
public Quadrilateral(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
public Quadrilateral(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||||
fill(7), fill(8), fill(9), fill(10), fill(11)) { }
|
fill(7), fill(8), fill(9), fill(10), fill(11)) { }
|
||||||
public Quadrilateral(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
public Quadrilateral(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||||
fill(7), fill(8), fill(9), fill(10), fill(11)) { }
|
fill(7), fill(8), fill(9), fill(10), fill(11)) { }
|
||||||
|
|
||||||
public Vert this[int index]
|
public Vert this[int index]
|
||||||
{
|
{
|
||||||
get => index switch
|
get => index switch
|
||||||
{
|
{
|
||||||
@ -188,40 +179,40 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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));
|
||||||
public static Quadrilateral Average(params Quadrilateral[] vals)
|
public static Quadrilateral Average(params Quadrilateral[] vals)
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
||||||
return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs), Vert.Average(Ds));
|
return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs), Vert.Average(Ds));
|
||||||
}
|
}
|
||||||
public static Quadrilateral Ceiling(Quadrilateral val) =>
|
public static Quadrilateral Ceiling(Quadrilateral val) =>
|
||||||
new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C), Vert.Ceiling(val.D));
|
new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C), Vert.Ceiling(val.D));
|
||||||
public static Quadrilateral Clamp(Quadrilateral val, Quadrilateral min, Quadrilateral max) =>
|
public static Quadrilateral Clamp(Quadrilateral val, Quadrilateral min, Quadrilateral max) =>
|
||||||
new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C),
|
new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C),
|
||||||
Vert.Clamp(val.D, min.D, max.D));
|
Vert.Clamp(val.D, min.D, max.D));
|
||||||
public static Quadrilateral Floor(Quadrilateral val) =>
|
public static Quadrilateral Floor(Quadrilateral val) =>
|
||||||
new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C), Vert.Floor(val.D));
|
new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C), Vert.Floor(val.D));
|
||||||
public static Quadrilateral Lerp(Quadrilateral a, Quadrilateral b, double t, bool clamp = true) =>
|
public static Quadrilateral Lerp(Quadrilateral a, Quadrilateral b, double t, bool clamp = true) =>
|
||||||
new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp),
|
new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp),
|
||||||
Vert.Lerp(a.D, b.D, t, clamp));
|
Vert.Lerp(a.D, b.D, t, clamp));
|
||||||
public static Quadrilateral Max(params Quadrilateral[] vals)
|
public static Quadrilateral Max(params Quadrilateral[] vals)
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
||||||
return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs), Vert.Max(Ds));
|
return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs), Vert.Max(Ds));
|
||||||
}
|
}
|
||||||
public static Quadrilateral Median(params Quadrilateral[] vals)
|
public static Quadrilateral Median(params Quadrilateral[] vals)
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
(Vert[] As, Vert[] Bs, Vert[] Cs, Vert[] Ds) = SplitVertArray(vals);
|
||||||
return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs), Vert.Median(Ds));
|
return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs), Vert.Median(Ds));
|
||||||
}
|
}
|
||||||
public static Quadrilateral Min(params Quadrilateral[] vals)
|
public static Quadrilateral Min(params Quadrilateral[] vals)
|
||||||
{
|
{
|
||||||
(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 (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)
|
||||||
{
|
{
|
||||||
Vert[] a = new Vert[quads.Length], b = new Vert[quads.Length],
|
Vert[] a = new Vert[quads.Length], b = new Vert[quads.Length],
|
||||||
c = new Vert[quads.Length], d = new Vert[quads.Length];
|
c = new Vert[quads.Length], d = new Vert[quads.Length];
|
||||||
@ -235,7 +226,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
|
|
||||||
return (a, b, c, d);
|
return (a, b, c, d);
|
||||||
}
|
}
|
||||||
public static (Line[] ABs, Line[] BCs, Line[] CDs, Line[] DAs) SplitLineArray(params Quadrilateral[] quads)
|
public static (Line[] ABs, Line[] BCs, Line[] CDs, Line[] DAs) SplitLineArray(params Quadrilateral[] quads)
|
||||||
{
|
{
|
||||||
Line[] ab = new Line[quads.Length], bc = new Line[quads.Length],
|
Line[] ab = new Line[quads.Length], bc = new Line[quads.Length],
|
||||||
cd = new Line[quads.Length], da = new Line[quads.Length];
|
cd = new Line[quads.Length], da = new Line[quads.Length];
|
||||||
@ -250,7 +241,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
return (ab, bc, cd, da);
|
return (ab, bc, cd, da);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static double[] ToDoubleArrayAll(params Quadrilateral[] quads)
|
public static double[] ToDoubleArrayAll(params Quadrilateral[] quads)
|
||||||
{
|
{
|
||||||
double[] vals = new double[quads.Length * 12];
|
double[] vals = new double[quads.Length * 12];
|
||||||
for (int i = 0; i < quads.Length; i++)
|
for (int i = 0; i < quads.Length; i++)
|
||||||
@ -271,72 +262,71 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
return vals;
|
return vals;
|
||||||
}
|
}
|
||||||
public static List<double> ToDoubleListAll(params Quadrilateral[] quads) => new(ToDoubleArrayAll(quads));
|
public static List<double> ToDoubleListAll(params Quadrilateral[] quads) => new(ToDoubleArrayAll(quads));
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
{
|
{
|
||||||
if (obj == null || obj.GetType() != typeof(Quadrilateral)) return false;
|
if (obj == null || obj.GetType() != typeof(Quadrilateral)) return false;
|
||||||
return Equals((Quadrilateral)obj);
|
return Equals((Quadrilateral)obj);
|
||||||
}
|
}
|
||||||
public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D;
|
public bool Equals(Quadrilateral other) => A == other.A && B == other.B && C == other.C && D == other.D;
|
||||||
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode();
|
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode() ^ D.GetHashCode();
|
||||||
public override string ToString() => ToString((string?)null);
|
public override string ToString() => ToString((string?)null);
|
||||||
public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider)
|
public string ToString(string? provider) => "A: " + A.ToString(provider) + " B: " + B.ToString(provider)
|
||||||
+ " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
+ " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
||||||
public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: "
|
public string ToString(IFormatProvider provider) => "A: " + A.ToString(provider) + " B: "
|
||||||
+ B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
+ B.ToString(provider) + " C: " + C.ToString(provider) + " D: " + D.ToString(provider);
|
||||||
|
|
||||||
public object Clone() => new Quadrilateral(A, B, C, D);
|
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()
|
||||||
{
|
{
|
||||||
yield return A;
|
yield return A;
|
||||||
yield return B;
|
yield return B;
|
||||||
yield return C;
|
yield return C;
|
||||||
yield return D;
|
yield return D;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vert[] ToArray() => new Vert[] { A, B, C, D };
|
public Vert[] ToArray() => new Vert[] { A, B, C, D };
|
||||||
public List<Vert> ToList() => new() { A, B, C, D };
|
public List<Vert> ToList() => new() { A, B, C, D };
|
||||||
|
|
||||||
public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z,
|
public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z,
|
||||||
B.position.x, B.position.y, B.position.z,
|
|
||||||
C.position.x, C.position.y, C.position.z,
|
|
||||||
D.position.x, D.position.y, D.position.z };
|
|
||||||
public List<double> ToDoubleList() => 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,
|
||||||
D.position.x, D.position.y, D.position.z };
|
D.position.x, D.position.y, D.position.z };
|
||||||
|
public List<double> ToDoubleList() => new() { A.position.x, A.position.y, A.position.z,
|
||||||
|
B.position.x, B.position.y, B.position.z,
|
||||||
|
C.position.x, C.position.y, C.position.z,
|
||||||
|
D.position.x, D.position.y, D.position.z };
|
||||||
|
|
||||||
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) };
|
||||||
|
|
||||||
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);
|
||||||
public static Quadrilateral operator -(Quadrilateral q) => new(-q.A, -q.B, -q.C, -q.D);
|
public static Quadrilateral operator -(Quadrilateral q) => new(-q.A, -q.B, -q.C, -q.D);
|
||||||
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);
|
||||||
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);
|
||||||
public static Quadrilateral operator *(Quadrilateral a, double b) => new(a.A * b, a.B * b, a.C * b, a.D * b);
|
public static Quadrilateral operator *(Quadrilateral a, double b) => new(a.A * b, a.B * b, a.C * b, a.D * b);
|
||||||
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);
|
||||||
public static Quadrilateral operator /(Quadrilateral a, double b) => new(a.A / b, a.B / b, a.C / b, a.D / b);
|
public static Quadrilateral operator /(Quadrilateral a, double 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 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<Double3> fill) => new(fill);
|
public static implicit operator Quadrilateral(Fill<Double3> fill) => new(fill);
|
||||||
public static implicit operator Quadrilateral(Fill<Int3> fill) => new(fill);
|
public static implicit operator Quadrilateral(Fill<Int3> fill) => new(fill);
|
||||||
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<double> fill) => new(fill);
|
public static implicit operator Quadrilateral(Fill<double> 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 explicit operator Quadrilateral(Polygon poly) => new(poly.Lines[0], poly.Lines[1],
|
public static explicit operator Quadrilateral(Polygon poly) => new(poly.Lines[0], poly.Lines[1],
|
||||||
poly.Lines[2], poly.Lines[3]);
|
poly.Lines[2], poly.Lines[3]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,126 +1,118 @@
|
|||||||
using System;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, IComparable<double>, IContainer<Vert>,
|
||||||
|
IEquatable<Sphere>, IEquatable<double>
|
||||||
{
|
{
|
||||||
public struct Sphere : ICloneable, IClosest<Vert>, IComparable<Sphere>, IComparable<double>, IContainer<Vert>,
|
public static Sphere Unit => new(Vert.Zero, 1);
|
||||||
IEquatable<Sphere>, IEquatable<double>
|
|
||||||
|
public Vert center;
|
||||||
|
public double radius;
|
||||||
|
|
||||||
|
public double SurfaceArea => 4 * Mathf.Pi * radius * radius;
|
||||||
|
public double Volume => 4 / 3 * (Mathf.Pi * radius * radius * radius);
|
||||||
|
|
||||||
|
public static Sphere FromDiameter(Vert a, Vert b) => new(Vert.Average(a, b), (a - b).Magnitude / 2);
|
||||||
|
public static Sphere FromRadius(Vert center, Vert radius) => new(center, (center - radius).Magnitude);
|
||||||
|
|
||||||
|
public Sphere(Vert center, double radius)
|
||||||
{
|
{
|
||||||
public static Sphere Unit => new(Vert.Zero, 1);
|
this.center = center;
|
||||||
|
this.radius = radius;
|
||||||
public Vert center;
|
|
||||||
public double radius;
|
|
||||||
|
|
||||||
public double SurfaceArea => 4 * Mathf.Pi * radius * radius;
|
|
||||||
public double Volume => 4 / 3 * (Mathf.Pi * radius * radius * radius);
|
|
||||||
|
|
||||||
public static Sphere FromDiameter(Vert a, Vert b) => new(Vert.Average(a, b), (a - b).Magnitude / 2);
|
|
||||||
public static Sphere FromRadius(Vert center, Vert radius) => new(center, (center - radius).Magnitude);
|
|
||||||
|
|
||||||
public Sphere(Vert center, double radius)
|
|
||||||
{
|
|
||||||
this.center = center;
|
|
||||||
this.radius = radius;
|
|
||||||
}
|
|
||||||
public Sphere(double cX, double cY, double radius) : this(new Vert(cX, cY), radius) { }
|
|
||||||
public Sphere(double cX, double cY, double cZ, double radius) : this(new Vert(cX, cY, cZ), radius) { }
|
|
||||||
public Sphere(Fill<double> fill, double radius) : this(new Vert(fill), radius) { }
|
|
||||||
public Sphere(Fill<double> fill) : this(new Vert(fill), fill(3)) { }
|
|
||||||
public Sphere(Fill<int> fill, double radius) : this(new Vert(fill), radius) { }
|
|
||||||
public Sphere(Fill<int> fill) : this(new Vert(fill), fill(3)) { }
|
|
||||||
public Sphere(Fill<Vert> fill, double radius) : this(fill(0), radius) { }
|
|
||||||
public Sphere(Fill<Vert> fillA, Fill<double> fillB) : this(fillA(0), fillB(0)) { }
|
|
||||||
|
|
||||||
public static Sphere Average(params Sphere[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, double[] radii) = SplitArray(vals);
|
|
||||||
return new(Vert.Average(centers), Mathf.Average(radii));
|
|
||||||
}
|
|
||||||
public static Sphere Ceiling(Sphere val) => new(Vert.Ceiling(val.center), Mathf.Ceiling(val.radius));
|
|
||||||
public static Sphere Clamp(Sphere val, Sphere min, Sphere max) =>
|
|
||||||
new(Vert.Clamp(val.center, min.center, max.center), Mathf.Clamp(val.radius, min.radius, max.radius));
|
|
||||||
public static Sphere Floor(Sphere val) => new(Vert.Floor(val.center), Mathf.Floor(val.radius));
|
|
||||||
public static Sphere Lerp(Sphere a, Sphere b, double t, bool clamp = true) =>
|
|
||||||
new(Vert.Lerp(a.center, b.center, t, clamp), Mathf.Lerp(a.radius, b.radius, t, clamp));
|
|
||||||
public static Sphere Max(params Sphere[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, double[] radii) = SplitArray(vals);
|
|
||||||
return new(Vert.Max(centers), Mathf.Max(radii));
|
|
||||||
}
|
|
||||||
public static Sphere Median(params Sphere[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, double[] radii) = SplitArray(vals);
|
|
||||||
return new(Vert.Median(centers), Mathf.Median(radii));
|
|
||||||
}
|
|
||||||
public static Sphere Min(params Sphere[] vals)
|
|
||||||
{
|
|
||||||
(Vert[] centers, double[] radii) = SplitArray(vals);
|
|
||||||
return new(Vert.Min(centers), Mathf.Min(radii));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static (Vert[] centers, double[] radii) SplitArray(params Sphere[] spheres)
|
|
||||||
{
|
|
||||||
Vert[] centers = new Vert[spheres.Length];
|
|
||||||
double[] radii = new double[spheres.Length];
|
|
||||||
for (int i = 0; i < spheres.Length; i++)
|
|
||||||
{
|
|
||||||
centers[i] = spheres[i].center;
|
|
||||||
radii[i] = spheres[i].radius;
|
|
||||||
}
|
|
||||||
return (centers, radii);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null) return false;
|
|
||||||
Type type = obj.GetType();
|
|
||||||
if (type == typeof(Sphere)) return Equals((Sphere)obj);
|
|
||||||
if (type == typeof(double)) return Equals((double)obj);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
public bool Equals(double other) => Volume == other;
|
|
||||||
public bool Equals(Sphere other) => center == other.center && radius == other.radius;
|
|
||||||
public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) => "Center: " + center.ToString(provider)
|
|
||||||
+ " Radius: " + radius.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider)
|
|
||||||
+ " Radius: " + radius.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Sphere(center, radius);
|
|
||||||
|
|
||||||
public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume);
|
|
||||||
public int CompareTo(double volume) => Volume.CompareTo(volume);
|
|
||||||
|
|
||||||
public bool Contains(Vert vert) => (center - vert).Magnitude <= radius;
|
|
||||||
|
|
||||||
public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + vert;
|
|
||||||
|
|
||||||
public 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, double b) => new(a.center, 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, Vert b) => new(a.center + b, a.radius);
|
|
||||||
public static Sphere operator -(Sphere a, double b) => new(a.center, 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, double 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, double b) => new(a.center * b, a.radius * b);
|
|
||||||
public static bool operator ==(Sphere a, Sphere b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b);
|
|
||||||
public static bool operator ==(Sphere a, double b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Sphere a, double b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0;
|
|
||||||
public static bool operator >(Sphere a, double b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Sphere a, double b) => a.CompareTo(b) < 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;
|
|
||||||
public static bool operator >=(Sphere a, double b) => a > b || a == b;
|
|
||||||
public static bool operator <=(Sphere a, double b) => a < b || a == b;
|
|
||||||
}
|
}
|
||||||
|
public Sphere(double cX, double cY, double radius) : this(new Vert(cX, cY), radius) { }
|
||||||
|
public Sphere(double cX, double cY, double cZ, double radius) : this(new Vert(cX, cY, cZ), radius) { }
|
||||||
|
public Sphere(Fill<double> fill, double radius) : this(new Vert(fill), radius) { }
|
||||||
|
public Sphere(Fill<double> fill) : this(new Vert(fill), fill(3)) { }
|
||||||
|
public Sphere(Fill<int> fill, double radius) : this(new Vert(fill), radius) { }
|
||||||
|
public Sphere(Fill<int> fill) : this(new Vert(fill), fill(3)) { }
|
||||||
|
public Sphere(Fill<Vert> fill, double radius) : this(fill(0), radius) { }
|
||||||
|
public Sphere(Fill<Vert> fillA, Fill<double> fillB) : this(fillA(0), fillB(0)) { }
|
||||||
|
|
||||||
|
public static Sphere Average(params Sphere[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, double[] radii) = SplitArray(vals);
|
||||||
|
return new(Vert.Average(centers), Mathf.Average(radii));
|
||||||
|
}
|
||||||
|
public static Sphere Ceiling(Sphere val) => new(Vert.Ceiling(val.center), Mathf.Ceiling(val.radius));
|
||||||
|
public static Sphere Clamp(Sphere val, Sphere min, Sphere max) =>
|
||||||
|
new(Vert.Clamp(val.center, min.center, max.center), Mathf.Clamp(val.radius, min.radius, max.radius));
|
||||||
|
public static Sphere Floor(Sphere val) => new(Vert.Floor(val.center), Mathf.Floor(val.radius));
|
||||||
|
public static Sphere Lerp(Sphere a, Sphere b, double t, bool clamp = true) =>
|
||||||
|
new(Vert.Lerp(a.center, b.center, t, clamp), Mathf.Lerp(a.radius, b.radius, t, clamp));
|
||||||
|
public static Sphere Max(params Sphere[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, double[] radii) = SplitArray(vals);
|
||||||
|
return new(Vert.Max(centers), Mathf.Max(radii));
|
||||||
|
}
|
||||||
|
public static Sphere Median(params Sphere[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, double[] radii) = SplitArray(vals);
|
||||||
|
return new(Vert.Median(centers), Mathf.Median(radii));
|
||||||
|
}
|
||||||
|
public static Sphere Min(params Sphere[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] centers, double[] radii) = SplitArray(vals);
|
||||||
|
return new(Vert.Min(centers), Mathf.Min(radii));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (Vert[] centers, double[] radii) SplitArray(params Sphere[] spheres)
|
||||||
|
{
|
||||||
|
Vert[] centers = new Vert[spheres.Length];
|
||||||
|
double[] radii = new double[spheres.Length];
|
||||||
|
for (int i = 0; i < spheres.Length; i++)
|
||||||
|
{
|
||||||
|
centers[i] = spheres[i].center;
|
||||||
|
radii[i] = spheres[i].radius;
|
||||||
|
}
|
||||||
|
return (centers, radii);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null) return false;
|
||||||
|
Type type = obj.GetType();
|
||||||
|
if (type == typeof(Sphere)) return Equals((Sphere)obj);
|
||||||
|
if (type == typeof(double)) return Equals((double)obj);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
public bool Equals(double other) => Volume == other;
|
||||||
|
public bool Equals(Sphere other) => center == other.center && radius == other.radius;
|
||||||
|
public override int GetHashCode() => center.GetHashCode() ^ radius.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) => "Center: " + center.ToString(provider)
|
||||||
|
+ " Radius: " + radius.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) => "Center: " + center.ToString(provider)
|
||||||
|
+ " Radius: " + radius.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Sphere(center, radius);
|
||||||
|
|
||||||
|
public int CompareTo(Sphere sphere) => Volume.CompareTo(sphere.Volume);
|
||||||
|
public int CompareTo(double volume) => Volume.CompareTo(volume);
|
||||||
|
|
||||||
|
public bool Contains(Vert vert) => (center - vert).Magnitude <= radius;
|
||||||
|
|
||||||
|
public Vert ClosestTo(Vert vert) => Contains(vert) ? vert : ((vert - center).Normalized * radius) + vert;
|
||||||
|
|
||||||
|
public 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, double b) => new(a.center, 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, Vert b) => new(a.center + b, a.radius);
|
||||||
|
public static Sphere operator -(Sphere a, double b) => new(a.center, 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, double 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, double b) => new(a.center * b, a.radius * b);
|
||||||
|
public static bool operator ==(Sphere a, Sphere b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Sphere a, Sphere b) => !a.Equals(b);
|
||||||
|
public static bool operator ==(Sphere a, double b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Sphere a, double b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Sphere a, Sphere b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Sphere a, Sphere b) => a.CompareTo(b) < 0;
|
||||||
|
public static bool operator >(Sphere a, double b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Sphere a, double b) => a.CompareTo(b) < 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;
|
||||||
|
public static bool operator >=(Sphere a, double b) => a > b || a == b;
|
||||||
|
public static bool operator <=(Sphere a, double b) => a < b || a == b;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,12 +1,8 @@
|
|||||||
using Nerd_STF.Exceptions;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
||||||
{
|
{
|
||||||
public struct Triangle : ICloneable, IEquatable<Triangle>, IGroup<Vert>
|
public Vert A
|
||||||
{
|
|
||||||
public Vert A
|
|
||||||
{
|
{
|
||||||
get => p_a;
|
get => p_a;
|
||||||
set
|
set
|
||||||
@ -16,7 +12,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_ca.b = value;
|
p_ca.b = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert B
|
public Vert B
|
||||||
{
|
{
|
||||||
get => p_b;
|
get => p_b;
|
||||||
set
|
set
|
||||||
@ -26,7 +22,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_bc.a = value;
|
p_bc.a = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Vert C
|
public Vert C
|
||||||
{
|
{
|
||||||
get => p_c;
|
get => p_c;
|
||||||
set
|
set
|
||||||
@ -36,7 +32,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_ca.a = value;
|
p_ca.a = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line AB
|
public Line AB
|
||||||
{
|
{
|
||||||
get => p_ab;
|
get => p_ab;
|
||||||
set
|
set
|
||||||
@ -48,7 +44,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_ca.b = value.a;
|
p_ca.b = value.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line BC
|
public Line BC
|
||||||
{
|
{
|
||||||
get => p_bc;
|
get => p_bc;
|
||||||
set
|
set
|
||||||
@ -60,7 +56,7 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
p_ab.b = value.a;
|
p_ab.b = value.a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public Line CA
|
public Line CA
|
||||||
{
|
{
|
||||||
get => p_ca;
|
get => p_ca;
|
||||||
set
|
set
|
||||||
@ -73,208 +69,202 @@ namespace Nerd_STF.Mathematics.Geometry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Vert p_a, p_b, p_c;
|
private Vert p_a, p_b, p_c;
|
||||||
private Line p_ab, p_bc, p_ca;
|
private Line p_ab, p_bc, p_ca;
|
||||||
|
|
||||||
public double Area => Mathf.Absolute((A.position.x * B.position.y) + (B.position.x * C.position.y) + (C.position.x * A.position.y) -
|
public double Area => Mathf.Absolute((A.position.x * B.position.y) + (B.position.x * C.position.y) + (C.position.x * A.position.y) -
|
||||||
((B.position.x * A.position.y) + (C.position.x * B.position.y) + (A.position.x * C.position.y))) * 0.5;
|
((B.position.x * A.position.y) + (C.position.x * B.position.y) + (A.position.x * C.position.y))) * 0.5;
|
||||||
public double Perimeter => AB.Length + BC.Length + CA.Length;
|
public double Perimeter => AB.Length + BC.Length + CA.Length;
|
||||||
|
|
||||||
public Triangle(Vert a, Vert b, Vert c)
|
public Triangle(Vert a, Vert b, Vert c)
|
||||||
|
{
|
||||||
|
p_a = a;
|
||||||
|
p_b = b;
|
||||||
|
p_c = c;
|
||||||
|
p_ab = new(a, b);
|
||||||
|
p_bc = new(b, c);
|
||||||
|
p_ca = new(c, a);
|
||||||
|
}
|
||||||
|
public Triangle(Line ab, Line bc, Line ca)
|
||||||
|
{
|
||||||
|
if (ab.a != ca.b || ab.b != bc.a || bc.b != ca.a)
|
||||||
|
throw new DisconnectedLinesException(ab, bc, ca);
|
||||||
|
|
||||||
|
p_a = ab.a;
|
||||||
|
p_b = bc.a;
|
||||||
|
p_c = ca.a;
|
||||||
|
p_ab = ab;
|
||||||
|
p_bc = bc;
|
||||||
|
p_ca = ca;
|
||||||
|
}
|
||||||
|
public Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
|
||||||
|
: this(new Vert(x1, y1), new Vert(x2, y2), new Vert(x3, y3)) { }
|
||||||
|
public Triangle(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3,
|
||||||
|
double z3) : this(new Vert(x1, y1, z1), new Vert(x2, y2, z2), new Vert(x3, y3, z3)) { }
|
||||||
|
public Triangle(Fill<Double3> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
public Triangle(Fill<Int3> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
public Triangle(Fill<Vert> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
public Triangle(Fill<Line> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
public Triangle(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||||
|
fill(7), fill(8)) { }
|
||||||
|
public Triangle(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
||||||
|
fill(7), fill(8)) { }
|
||||||
|
|
||||||
|
public Vert this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
{
|
{
|
||||||
p_a = a;
|
0 => A,
|
||||||
p_b = b;
|
1 => B,
|
||||||
p_c = c;
|
2 => C,
|
||||||
p_ab = new(a, b);
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
p_bc = new(b, c);
|
};
|
||||||
p_ca = new(c, a);
|
set
|
||||||
}
|
|
||||||
public Triangle(Line ab, Line bc, Line ca)
|
|
||||||
{
|
{
|
||||||
if (ab.a != ca.b || ab.b != bc.a || bc.b != ca.a)
|
switch (index)
|
||||||
throw new DisconnectedLinesException(ab, bc, ca);
|
|
||||||
|
|
||||||
p_a = ab.a;
|
|
||||||
p_b = bc.a;
|
|
||||||
p_c = ca.a;
|
|
||||||
p_ab = ab;
|
|
||||||
p_bc = bc;
|
|
||||||
p_ca = ca;
|
|
||||||
}
|
|
||||||
public Triangle(double x1, double y1, double x2, double y2, double x3, double y3)
|
|
||||||
: this(new Vert(x1, y1), new Vert(x2, y2), new Vert(x3, y3)) { }
|
|
||||||
public Triangle(double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3,
|
|
||||||
double z3) : this(new Vert(x1, y1, z1), new Vert(x2, y2, z2), new Vert(x3, y3, z3)) { }
|
|
||||||
public Triangle(Fill<Double3> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
public Triangle(Fill<Int3> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
public Triangle(Fill<Vert> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
public Triangle(Fill<Line> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
public Triangle(Fill<double> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
|
||||||
fill(7), fill(8))
|
|
||||||
{ }
|
|
||||||
public Triangle(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3), fill(4), fill(5), fill(6),
|
|
||||||
fill(7), fill(8))
|
|
||||||
{ }
|
|
||||||
|
|
||||||
public Vert this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
{
|
||||||
0 => A,
|
case 0:
|
||||||
1 => B,
|
A = value;
|
||||||
2 => C,
|
break;
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
A = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
B = value;
|
B = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
C = value;
|
C = value;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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));
|
||||||
public static Triangle Average(params Triangle[] vals)
|
public static Triangle Average(params Triangle[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
||||||
|
return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs));
|
||||||
|
}
|
||||||
|
public static Triangle Ceiling(Triangle val) =>
|
||||||
|
new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C));
|
||||||
|
public static Triangle Clamp(Triangle val, Triangle min, Triangle max) =>
|
||||||
|
new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C));
|
||||||
|
public static Triangle Floor(Triangle val) =>
|
||||||
|
new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C));
|
||||||
|
public static Triangle Lerp(Triangle a, Triangle b, double t, bool clamp = true) =>
|
||||||
|
new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp));
|
||||||
|
public static Triangle Max(params Triangle[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
||||||
|
return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs));
|
||||||
|
}
|
||||||
|
public static Triangle Median(params Triangle[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
||||||
|
return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs));
|
||||||
|
}
|
||||||
|
public static Triangle Min(params Triangle[] vals)
|
||||||
|
{
|
||||||
|
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
||||||
|
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris)
|
||||||
|
{
|
||||||
|
Vert[] a = new Vert[tris.Length], b = new Vert[tris.Length], c = new Vert[tris.Length];
|
||||||
|
for (int i = 0; i < tris.Length; i++)
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
a[i] = tris[i].A;
|
||||||
return new(Vert.Average(As), Vert.Average(Bs), Vert.Average(Cs));
|
b[i] = tris[i].B;
|
||||||
|
c[i] = tris[i].C;
|
||||||
}
|
}
|
||||||
public static Triangle Ceiling(Triangle val) =>
|
return (a, b, c);
|
||||||
new(Vert.Ceiling(val.A), Vert.Ceiling(val.B), Vert.Ceiling(val.C));
|
}
|
||||||
public static Triangle Clamp(Triangle val, Triangle min, Triangle max) =>
|
public static (Line[] ABs, Line[] BCs, Line[] CAs) SplitLineArray(params Triangle[] tris)
|
||||||
new(Vert.Clamp(val.A, min.A, max.A), Vert.Clamp(val.B, min.B, max.B), Vert.Clamp(val.C, min.C, max.C));
|
{
|
||||||
public static Triangle Floor(Triangle val) =>
|
Line[] ab = new Line[tris.Length], bc = new Line[tris.Length], ca = new Line[tris.Length];
|
||||||
new(Vert.Floor(val.A), Vert.Floor(val.B), Vert.Floor(val.C));
|
for (int i = 0; i < tris.Length; i++)
|
||||||
public static Triangle Lerp(Triangle a, Triangle b, double t, bool clamp = true) =>
|
|
||||||
new(Vert.Lerp(a.A, b.A, t, clamp), Vert.Lerp(a.B, b.B, t, clamp), Vert.Lerp(a.C, b.C, t, clamp));
|
|
||||||
public static Triangle Max(params Triangle[] vals)
|
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
ab[i] = tris[i].AB;
|
||||||
return new(Vert.Max(As), Vert.Max(Bs), Vert.Max(Cs));
|
bc[i] = tris[i].BC;
|
||||||
|
ca[i] = tris[i].CA;
|
||||||
}
|
}
|
||||||
public static Triangle Median(params Triangle[] vals)
|
return (ab, bc, ca);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double[] ToDoubleArrayAll(params Triangle[] tris)
|
||||||
|
{
|
||||||
|
double[] vals = new double[tris.Length * 9];
|
||||||
|
for (int i = 0; i < tris.Length; i++)
|
||||||
{
|
{
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
int pos = i * 9;
|
||||||
return new(Vert.Median(As), Vert.Median(Bs), Vert.Median(Cs));
|
vals[pos + 0] = tris[i].A.position.x;
|
||||||
}
|
vals[pos + 1] = tris[i].A.position.y;
|
||||||
public static Triangle Min(params Triangle[] vals)
|
vals[pos + 2] = tris[i].A.position.z;
|
||||||
{
|
vals[pos + 3] = tris[i].B.position.x;
|
||||||
(Vert[] As, Vert[] Bs, Vert[] Cs) = SplitVertArray(vals);
|
vals[pos + 4] = tris[i].B.position.y;
|
||||||
return new(Vert.Min(As), Vert.Min(Bs), Vert.Min(Cs));
|
vals[pos + 5] = tris[i].B.position.z;
|
||||||
|
vals[pos + 6] = tris[i].C.position.x;
|
||||||
|
vals[pos + 7] = tris[i].C.position.y;
|
||||||
|
vals[pos + 8] = tris[i].C.position.z;
|
||||||
}
|
}
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
public static List<double> ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris));
|
||||||
|
|
||||||
public static (Vert[] As, Vert[] Bs, Vert[] Cs) SplitVertArray(params Triangle[] tris)
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
{
|
{
|
||||||
Vert[] a = new Vert[tris.Length], b = new Vert[tris.Length], c = new Vert[tris.Length];
|
if (obj == null || obj.GetType() != typeof(Triangle)) return false;
|
||||||
for (int i = 0; i < tris.Length; i++)
|
return Equals((Triangle)obj);
|
||||||
{
|
}
|
||||||
a[i] = tris[i].A;
|
public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C;
|
||||||
b[i] = tris[i].B;
|
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode();
|
||||||
c[i] = tris[i].C;
|
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);
|
||||||
|
|
||||||
return (a, b, c);
|
public object Clone() => new Triangle(A, B, C);
|
||||||
}
|
|
||||||
public static (Line[] ABs, Line[] BCs, Line[] CAs) SplitLineArray(params Triangle[] tris)
|
|
||||||
{
|
|
||||||
Line[] ab = new Line[tris.Length], bc = new Line[tris.Length], ca = new Line[tris.Length];
|
|
||||||
for (int i = 0; i < tris.Length; i++)
|
|
||||||
{
|
|
||||||
ab[i] = tris[i].AB;
|
|
||||||
bc[i] = tris[i].BC;
|
|
||||||
ca[i] = tris[i].CA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ab, bc, ca);
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
}
|
public IEnumerator<Vert> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return A;
|
||||||
|
yield return B;
|
||||||
|
yield return C;
|
||||||
|
}
|
||||||
|
|
||||||
public static double[] ToDoubleArrayAll(params Triangle[] tris)
|
public Vert[] ToArray() => new Vert[] { A, B, C };
|
||||||
{
|
public List<Vert> ToList() => new() { A, B, C };
|
||||||
double[] vals = new double[tris.Length * 9];
|
|
||||||
for (int i = 0; i < tris.Length; i++)
|
|
||||||
{
|
|
||||||
int pos = i * 9;
|
|
||||||
vals[pos + 0] = tris[i].A.position.x;
|
|
||||||
vals[pos + 1] = tris[i].A.position.y;
|
|
||||||
vals[pos + 2] = tris[i].A.position.z;
|
|
||||||
vals[pos + 3] = tris[i].B.position.x;
|
|
||||||
vals[pos + 4] = tris[i].B.position.y;
|
|
||||||
vals[pos + 5] = tris[i].B.position.z;
|
|
||||||
vals[pos + 6] = tris[i].C.position.x;
|
|
||||||
vals[pos + 7] = tris[i].C.position.y;
|
|
||||||
vals[pos + 8] = tris[i].C.position.z;
|
|
||||||
}
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
public static List<double> ToDoubleListAll(params Triangle[] tris) => new(ToDoubleArrayAll(tris));
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z,
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Triangle)) return false;
|
|
||||||
return Equals((Triangle)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Triangle other) => A == other.A && B == other.B && C == other.C;
|
|
||||||
public override int GetHashCode() => A.GetHashCode() ^ B.GetHashCode() ^ C.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"A: " + A.ToString(provider) + " B: " + B.ToString(provider) + " C: " + C.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Triangle(A, B, C);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<Vert> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return A;
|
|
||||||
yield return B;
|
|
||||||
yield return C;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vert[] ToArray() => new Vert[] { A, B, C };
|
|
||||||
public List<Vert> ToList() => new() { A, B, C };
|
|
||||||
|
|
||||||
public double[] ToDoubleArray() => new double[] { A.position.x, A.position.y, A.position.z,
|
|
||||||
B.position.x, B.position.y, B.position.z,
|
|
||||||
C.position.x, C.position.y, C.position.z };
|
|
||||||
public List<double> ToDoubleList() => 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 };
|
||||||
|
public List<double> ToDoubleList() => new() { A.position.x, A.position.y, A.position.z,
|
||||||
|
B.position.x, B.position.y, B.position.z,
|
||||||
|
C.position.x, C.position.y, C.position.z };
|
||||||
|
public static Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C);
|
||||||
|
public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b);
|
||||||
|
public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C);
|
||||||
|
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, 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, double b) => new(a.A * b, a.B * b, a.C * b);
|
||||||
|
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, double 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 Triangle operator +(Triangle a, Triangle b) => new(a.A + b.A, a.B + b.B, a.C + b.C);
|
public static implicit operator Triangle(Fill<Vert> fill) => new(fill);
|
||||||
public static Triangle operator +(Triangle a, Vert b) => new(a.A + b, a.B + b, a.C + b);
|
public static implicit operator Triangle(Fill<Double3> fill) => new(fill);
|
||||||
public static Triangle operator -(Triangle t) => new(-t.A, -t.B, -t.C);
|
public static implicit operator Triangle(Fill<Int3> fill) => new(fill);
|
||||||
public static Triangle operator -(Triangle a, Triangle b) => new(a.A - b.A, a.B - b.B, a.C - b.C);
|
public static implicit operator Triangle(Fill<Line> fill) => new(fill);
|
||||||
public static Triangle operator -(Triangle a, Vert b) => new(a.A - b, a.B - b, a.C - b);
|
public static implicit operator Triangle(Fill<double> fill) => new(fill);
|
||||||
public static Triangle operator *(Triangle a, Triangle b) => new(a.A * b.A, a.B * b.B, a.C * b.C);
|
public static implicit operator Triangle(Fill<int> fill) => new(fill);
|
||||||
public static Triangle operator *(Triangle a, Vert b) => new(a.A * b, a.B * b, a.C * b);
|
public static explicit operator Triangle(Polygon poly) => new(poly.Lines[0], poly.Lines[1], poly.Lines[2]);
|
||||||
public static Triangle operator *(Triangle a, double b) => new(a.A * b, a.B * b, a.C * b);
|
|
||||||
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, double 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<Double3> fill) => new(fill);
|
|
||||||
public static implicit operator Triangle(Fill<Int3> fill) => new(fill);
|
|
||||||
public static implicit operator Triangle(Fill<Line> fill) => new(fill);
|
|
||||||
public static implicit operator Triangle(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Triangle(Fill<int> fill) => new(fill);
|
|
||||||
public static explicit operator Triangle(Polygon poly) => new(poly.Lines[0], poly.Lines[1], poly.Lines[2]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,102 +1,98 @@
|
|||||||
using System.Collections;
|
namespace Nerd_STF.Mathematics.Geometry;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics.Geometry
|
public struct Vert : ICloneable, IEquatable<Vert>, IGroup<double>
|
||||||
{
|
{
|
||||||
public struct Vert : ICloneable, IEquatable<Vert>, IGroup<double>
|
public static Vert Back => new(0, 0, -1);
|
||||||
|
public static Vert Down => new(0, -1, 0);
|
||||||
|
public static Vert Forward => new(0, 0, 1);
|
||||||
|
public static Vert Left => new(-1, 0, 0);
|
||||||
|
public static Vert Right => new(1, 0, 0);
|
||||||
|
public static Vert Up => new(0, 1, 0);
|
||||||
|
|
||||||
|
public static Vert One => new(1, 1, 1);
|
||||||
|
public static Vert Zero => new(0, 0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => position.Magnitude;
|
||||||
|
public Vert Normalized => new(this / Magnitude);
|
||||||
|
|
||||||
|
public Double3 position;
|
||||||
|
|
||||||
|
public Vert(Double2 pos) : this(pos.x, pos.y, 0) { }
|
||||||
|
public Vert(Double3 pos) => position = pos;
|
||||||
|
public Vert(double x, double y) : this(new Double2(x, y)) { }
|
||||||
|
public Vert(double x, double y, double z) : this(new Double3(x, y, z)) { }
|
||||||
|
public Vert(Fill<double> fill) : this(new Double3(fill)) { }
|
||||||
|
public Vert(Fill<int> fill) : this(new Double3(fill)) { }
|
||||||
|
|
||||||
|
public double this[int index]
|
||||||
{
|
{
|
||||||
public static Vert Back => new(0, 0, -1);
|
get => position[index];
|
||||||
public static Vert Down => new(0, -1, 0);
|
set => position[index] = value;
|
||||||
public static Vert Forward => new(0, 0, 1);
|
|
||||||
public static Vert Left => new(-1, 0, 0);
|
|
||||||
public static Vert Right => new(1, 0, 0);
|
|
||||||
public static Vert Up => new(0, 1, 0);
|
|
||||||
|
|
||||||
public static Vert One => new(1, 1, 1);
|
|
||||||
public static Vert Zero => new(0, 0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => position.Magnitude;
|
|
||||||
public Vert Normalized => new(this / Magnitude);
|
|
||||||
|
|
||||||
public Double3 position;
|
|
||||||
|
|
||||||
public Vert(Double2 pos) : this(pos.x, pos.y, 0) { }
|
|
||||||
public Vert(Double3 pos) => position = pos;
|
|
||||||
public Vert(double x, double y) : this(new Double2(x, y)) { }
|
|
||||||
public Vert(double x, double y, double z) : this(new Double3(x, y, z)) { }
|
|
||||||
public Vert(Fill<double> fill) : this(new Double3(fill)) { }
|
|
||||||
public Vert(Fill<int> fill) : this(new Double3(fill)) { }
|
|
||||||
|
|
||||||
public double this[int index]
|
|
||||||
{
|
|
||||||
get => position[index];
|
|
||||||
set => position[index] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Vert Absolute(Vert val) => new(Double3.Absolute(val.position));
|
|
||||||
public static Vert Average(params Vert[] vals) => Double3.Average(ToDouble3Array(vals));
|
|
||||||
public static Vert Ceiling(Vert val) => new(Double3.Ceiling(val.position));
|
|
||||||
public static Vert Clamp(Vert val, Vert min, Vert max) =>
|
|
||||||
new(Double3.Clamp(val.position, min.position, max.position));
|
|
||||||
public static Vert ClampMagnitude(Vert val, double minMag, double maxMag) =>
|
|
||||||
new(Double3.ClampMagnitude(val.position, minMag, maxMag));
|
|
||||||
public static Vert Cross(Vert a, Vert b, bool normalized = false) =>
|
|
||||||
new(Double3.Cross(a.position, b.position, normalized));
|
|
||||||
public static double Dot(Vert a, Vert b) => Double3.Dot(a.position, b.position);
|
|
||||||
public static double Dot(params Vert[] vals) => Double3.Dot(ToDouble3Array(vals));
|
|
||||||
public static Vert Floor(Vert val) => new(Double3.Floor(val.position));
|
|
||||||
public static Vert Lerp(Vert a, Vert b, double t, bool clamp = true) =>
|
|
||||||
new(Double3.Lerp(a.position, b.position, t, clamp));
|
|
||||||
public static Vert Median(params Vert[] vals) =>
|
|
||||||
Double3.Median(ToDouble3Array(vals));
|
|
||||||
public static Vert Max(params Vert[] vals) =>
|
|
||||||
Double3.Max(ToDouble3Array(vals));
|
|
||||||
public static Vert Min(params Vert[] vals) =>
|
|
||||||
Double3.Min(ToDouble3Array(vals));
|
|
||||||
public static Double3[] ToDouble3Array(params Vert[] vals)
|
|
||||||
{
|
|
||||||
Double3[] doubles = new Double3[vals.Length];
|
|
||||||
for (int i = 0; i < vals.Length; i++) doubles[i] = vals[i].position;
|
|
||||||
return doubles;
|
|
||||||
}
|
|
||||||
public static List<Double3> ToDouble3List(params Vert[] vals) => ToDouble3Array(vals).ToList();
|
|
||||||
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Vert)) return false;
|
|
||||||
return Equals((Vert)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Vert other) => position == other.position;
|
|
||||||
public override int GetHashCode() => position.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) => position.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) => position.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Vert(position);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<double> GetEnumerator() => position.GetEnumerator();
|
|
||||||
|
|
||||||
public double[] ToArray() => position.ToArray();
|
|
||||||
public List<double> ToList() => position.ToList();
|
|
||||||
|
|
||||||
public static Vert operator +(Vert a, Vert b) => new(a.position + b.position);
|
|
||||||
public static Vert operator -(Vert d) => new(-d.position);
|
|
||||||
public static Vert operator -(Vert a, Vert b) => new(a.position - b.position);
|
|
||||||
public static Vert operator *(Vert a, Vert b) => new(a.position * b.position);
|
|
||||||
public static Vert operator *(Vert a, double b) => new(a.position * b);
|
|
||||||
public static Vert operator /(Vert a, Vert b) => new(a.position / b.position);
|
|
||||||
public static Vert operator /(Vert a, double b) => new(a.position / b);
|
|
||||||
public static bool operator ==(Vert a, Vert b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Vert a, Vert b) => !a.Equals(b);
|
|
||||||
|
|
||||||
public static implicit operator Vert(Double2 val) => new(val);
|
|
||||||
public static implicit operator Vert(Double3 val) => new(val);
|
|
||||||
public static explicit operator Vert(Double4 val) => new(val.XYZ);
|
|
||||||
public static implicit operator Vert(Int2 val) => new(val);
|
|
||||||
public static implicit operator Vert(Int3 val) => new(val);
|
|
||||||
public static explicit operator Vert(Int4 val) => new(val.XYZ);
|
|
||||||
public static implicit operator Vert(Fill<double> fill) => new(fill);
|
|
||||||
public static implicit operator Vert(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Vert Absolute(Vert val) => new(Double3.Absolute(val.position));
|
||||||
|
public static Vert Average(params Vert[] vals) => Double3.Average(ToDouble3Array(vals));
|
||||||
|
public static Vert Ceiling(Vert val) => new(Double3.Ceiling(val.position));
|
||||||
|
public static Vert Clamp(Vert val, Vert min, Vert max) =>
|
||||||
|
new(Double3.Clamp(val.position, min.position, max.position));
|
||||||
|
public static Vert ClampMagnitude(Vert val, double minMag, double maxMag) =>
|
||||||
|
new(Double3.ClampMagnitude(val.position, minMag, maxMag));
|
||||||
|
public static Vert Cross(Vert a, Vert b, bool normalized = false) =>
|
||||||
|
new(Double3.Cross(a.position, b.position, normalized));
|
||||||
|
public static double Dot(Vert a, Vert b) => Double3.Dot(a.position, b.position);
|
||||||
|
public static double Dot(params Vert[] vals) => Double3.Dot(ToDouble3Array(vals));
|
||||||
|
public static Vert Floor(Vert val) => new(Double3.Floor(val.position));
|
||||||
|
public static Vert Lerp(Vert a, Vert b, double t, bool clamp = true) =>
|
||||||
|
new(Double3.Lerp(a.position, b.position, t, clamp));
|
||||||
|
public static Vert Median(params Vert[] vals) =>
|
||||||
|
Double3.Median(ToDouble3Array(vals));
|
||||||
|
public static Vert Max(params Vert[] vals) =>
|
||||||
|
Double3.Max(ToDouble3Array(vals));
|
||||||
|
public static Vert Min(params Vert[] vals) =>
|
||||||
|
Double3.Min(ToDouble3Array(vals));
|
||||||
|
public static Double3[] ToDouble3Array(params Vert[] vals)
|
||||||
|
{
|
||||||
|
Double3[] doubles = new Double3[vals.Length];
|
||||||
|
for (int i = 0; i < vals.Length; i++) doubles[i] = vals[i].position;
|
||||||
|
return doubles;
|
||||||
|
}
|
||||||
|
public static List<Double3> ToDouble3List(params Vert[] vals) => ToDouble3Array(vals).ToList();
|
||||||
|
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Vert)) return false;
|
||||||
|
return Equals((Vert)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Vert other) => position == other.position;
|
||||||
|
public override int GetHashCode() => position.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) => position.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) => position.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Vert(position);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<double> GetEnumerator() => position.GetEnumerator();
|
||||||
|
|
||||||
|
public double[] ToArray() => position.ToArray();
|
||||||
|
public List<double> ToList() => position.ToList();
|
||||||
|
|
||||||
|
public static Vert operator +(Vert a, Vert b) => new(a.position + b.position);
|
||||||
|
public static Vert operator -(Vert d) => new(-d.position);
|
||||||
|
public static Vert operator -(Vert a, Vert b) => new(a.position - b.position);
|
||||||
|
public static Vert operator *(Vert a, Vert b) => new(a.position * b.position);
|
||||||
|
public static Vert operator *(Vert a, double b) => new(a.position * b);
|
||||||
|
public static Vert operator /(Vert a, Vert b) => new(a.position / b.position);
|
||||||
|
public static Vert operator /(Vert a, double b) => new(a.position / b);
|
||||||
|
public static bool operator ==(Vert a, Vert b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Vert a, Vert b) => !a.Equals(b);
|
||||||
|
|
||||||
|
public static implicit operator Vert(Double2 val) => new(val);
|
||||||
|
public static implicit operator Vert(Double3 val) => new(val);
|
||||||
|
public static explicit operator Vert(Double4 val) => new(val.XYZ);
|
||||||
|
public static implicit operator Vert(Int2 val) => new(val);
|
||||||
|
public static implicit operator Vert(Int3 val) => new(val);
|
||||||
|
public static explicit operator Vert(Int4 val) => new(val.XYZ);
|
||||||
|
public static implicit operator Vert(Fill<double> fill) => new(fill);
|
||||||
|
public static implicit operator Vert(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,183 +1,178 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int>
|
||||||
{
|
{
|
||||||
public struct Int2 : ICloneable, IComparable<Int2>, IEquatable<Int2>, IGroup<int>
|
public static Int2 Down => new(0, -1);
|
||||||
|
public static Int2 Left => new(-1, 0);
|
||||||
|
public static Int2 Right => new(1, 0);
|
||||||
|
public static Int2 Up => new(0, 1);
|
||||||
|
|
||||||
|
public static Int2 One => new(1, 1);
|
||||||
|
public static Int2 Zero => new(0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y);
|
||||||
|
public Int2 Normalized => (Int2)((Double2)this / Magnitude);
|
||||||
|
|
||||||
|
public int x, y;
|
||||||
|
|
||||||
|
public Int2(int all) : this(all, all) { }
|
||||||
|
public Int2(int x, int y)
|
||||||
{
|
{
|
||||||
public static Int2 Down => new(0, -1);
|
this.x = x;
|
||||||
public static Int2 Left => new(-1, 0);
|
this.y = y;
|
||||||
public static Int2 Right => new(1, 0);
|
|
||||||
public static Int2 Up => new(0, 1);
|
|
||||||
|
|
||||||
public static Int2 One => new(1, 1);
|
|
||||||
public static Int2 Zero => new(0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y);
|
|
||||||
public Int2 Normalized => (Int2)((Double2)this / Magnitude);
|
|
||||||
|
|
||||||
public int x, y;
|
|
||||||
|
|
||||||
public Int2(int all) : this(all, all) { }
|
|
||||||
public Int2(int x, int y)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
}
|
|
||||||
public Int2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
|
||||||
|
|
||||||
public int this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Int2 Absolute(Int2 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
|
||||||
public static Int2 Average(params Int2[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Int2 Clamp(Int2 val, Int2 min, Int2 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y));
|
|
||||||
public static Int2 ClampMagnitude(Int2 val, int minMag, int maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int3 Cross(Int2 a, Int2 b, bool normalized = false) =>
|
|
||||||
Int3.Cross(a, b, normalized);
|
|
||||||
public static Int2 Divide(Int2 num, params Int2[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int2 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static int Dot(Int2 a, Int2 b) => a.x * b.x + a.y * b.y;
|
|
||||||
public static int Dot(params Int2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int x = 1, y = 1;
|
|
||||||
foreach (Int2 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
}
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) =>
|
|
||||||
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp));
|
|
||||||
public static Int2 Median(params Int2[] vals)
|
|
||||||
{
|
|
||||||
int index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Int2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Int2 Max(params Int2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int2 val = vals[0];
|
|
||||||
foreach (Int2 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int2 Min(params Int2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int2 val = vals[0];
|
|
||||||
foreach (Int2 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int2 Multiply(params Int2[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int2 val = One;
|
|
||||||
foreach (Int2 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int2 Subtract(Int2 num, params Int2[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int2 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Int2 Sum(params Int2[] vals)
|
|
||||||
{
|
|
||||||
Int2 val = Zero;
|
|
||||||
foreach (Int2 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Int2)) return false;
|
|
||||||
return Equals((Int2)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Int2(x, y);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<int> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] ToArray() => new[] { x, y };
|
|
||||||
public List<int> ToList() => new() { x, 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 a, Int2 b) => new(a.x - b.x, a.y - b.y);
|
|
||||||
public static Int2 operator *(Int2 a, Int2 b) => new(a.x * b.x, a.y * b.y);
|
|
||||||
public static Int2 operator *(Int2 a, int b) => new(a.x * b, a.y * b);
|
|
||||||
public static Int2 operator /(Int2 a, Int2 b) => new(a.x / b.x, a.y / b.y);
|
|
||||||
public static Int2 operator /(Int2 a, int b) => new(a.x / b, a.y / b);
|
|
||||||
public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y);
|
|
||||||
public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y);
|
|
||||||
public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y);
|
|
||||||
public static bool operator ==(Int2 a, Int2 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0;
|
|
||||||
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(Double2 val) => new((int)val.x, (int)val.y);
|
|
||||||
public static explicit operator Int2(Double3 val) => new((int)val.x, (int)val.y);
|
|
||||||
public static explicit operator Int2(Double4 val) => new((int)val.x, (int)val.y);
|
|
||||||
public static explicit operator Int2(Int3 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Int2(Int4 val) => new(val.x, val.y);
|
|
||||||
public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y);
|
|
||||||
public static implicit operator Int2(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Int2(Fill<int> fill) : this(fill(0), fill(1)) { }
|
||||||
|
|
||||||
|
public int this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int2 Absolute(Int2 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y));
|
||||||
|
public static Int2 Average(params Int2[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Int2 Clamp(Int2 val, Int2 min, Int2 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y));
|
||||||
|
public static Int2 ClampMagnitude(Int2 val, int minMag, int maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int3 Cross(Int2 a, Int2 b, bool normalized = false) =>
|
||||||
|
Int3.Cross(a, b, normalized);
|
||||||
|
public static Int2 Divide(Int2 num, params Int2[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int2 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static int Dot(Int2 a, Int2 b) => a.x * b.x + a.y * b.y;
|
||||||
|
public static int Dot(params Int2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int x = 1, y = 1;
|
||||||
|
foreach (Int2 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
}
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
public static Int2 Lerp(Int2 a, Int2 b, double t, bool clamp = true) =>
|
||||||
|
new(Mathf.Lerp(a.x, b.x, t, clamp), Mathf.Lerp(a.y, b.y, t, clamp));
|
||||||
|
public static Int2 Median(params Int2[] vals)
|
||||||
|
{
|
||||||
|
int index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Int2 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Int2 Max(params Int2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int2 val = vals[0];
|
||||||
|
foreach (Int2 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int2 Min(params Int2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int2 val = vals[0];
|
||||||
|
foreach (Int2 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int2 Multiply(params Int2[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int2 val = One;
|
||||||
|
foreach (Int2 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int2 Subtract(Int2 num, params Int2[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int2 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Int2 Sum(params Int2[] vals)
|
||||||
|
{
|
||||||
|
Int2 val = Zero;
|
||||||
|
foreach (Int2 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Int2 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Int2)) return false;
|
||||||
|
return Equals((Int2)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Int2 other) => x == other.x && y == other.y;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Int2(x, y);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<int> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] ToArray() => new[] { x, y };
|
||||||
|
public List<int> ToList() => new() { x, 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 a, Int2 b) => new(a.x - b.x, a.y - b.y);
|
||||||
|
public static Int2 operator *(Int2 a, Int2 b) => new(a.x * b.x, a.y * b.y);
|
||||||
|
public static Int2 operator *(Int2 a, int b) => new(a.x * b, a.y * b);
|
||||||
|
public static Int2 operator /(Int2 a, Int2 b) => new(a.x / b.x, a.y / b.y);
|
||||||
|
public static Int2 operator /(Int2 a, int b) => new(a.x / b, a.y / b);
|
||||||
|
public static Int2 operator &(Int2 a, Int2 b) => new(a.x & b.x, a.y & b.y);
|
||||||
|
public static Int2 operator |(Int2 a, Int2 b) => new(a.x | b.x, a.y | b.y);
|
||||||
|
public static Int2 operator ^(Int2 a, Int2 b) => new(a.x ^ b.x, a.y ^ b.y);
|
||||||
|
public static bool operator ==(Int2 a, Int2 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Int2 a, Int2 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Int2 a, Int2 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Int2 a, Int2 b) => a.CompareTo(b) < 0;
|
||||||
|
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(Double2 val) => new((int)val.x, (int)val.y);
|
||||||
|
public static explicit operator Int2(Double3 val) => new((int)val.x, (int)val.y);
|
||||||
|
public static explicit operator Int2(Double4 val) => new((int)val.x, (int)val.y);
|
||||||
|
public static explicit operator Int2(Int3 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Int2(Int4 val) => new(val.x, val.y);
|
||||||
|
public static explicit operator Int2(Vert val) => new((int)val.position.x, (int)val.position.y);
|
||||||
|
public static implicit operator Int2(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,205 +1,197 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int>
|
||||||
{
|
{
|
||||||
public struct Int3 : ICloneable, IComparable<Int3>, IEquatable<Int3>, IGroup<int>
|
public static Int3 Back => new(0, 0, -1);
|
||||||
|
public static Int3 Down => new(0, -1, 0);
|
||||||
|
public static Int3 Forward => new(0, 0, 1);
|
||||||
|
public static Int3 Left => new(-1, 0, 0);
|
||||||
|
public static Int3 Right => new(1, 0, 0);
|
||||||
|
public static Int3 Up => new(0, 1, 0);
|
||||||
|
|
||||||
|
public static Int3 One => new(1, 1, 1);
|
||||||
|
public static Int3 Zero => new(0, 0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
||||||
|
public Int3 Normalized => (Int3)((Double3)this / Magnitude);
|
||||||
|
|
||||||
|
public Int2 XY => new(x, y);
|
||||||
|
public Int2 XZ => new(x, z);
|
||||||
|
public Int2 YZ => new(y, z);
|
||||||
|
|
||||||
|
public int x, y, z;
|
||||||
|
|
||||||
|
public Int3(int all) : this(all, all, all) { }
|
||||||
|
public Int3(int x, int y) : this(x, y, 0) { }
|
||||||
|
public Int3(int x, int y, int z)
|
||||||
{
|
{
|
||||||
public static Int3 Back => new(0, 0, -1);
|
this.x = x;
|
||||||
public static Int3 Down => new(0, -1, 0);
|
this.y = y;
|
||||||
public static Int3 Forward => new(0, 0, 1);
|
this.z = z;
|
||||||
public static Int3 Left => new(-1, 0, 0);
|
|
||||||
public static Int3 Right => new(1, 0, 0);
|
|
||||||
public static Int3 Up => new(0, 1, 0);
|
|
||||||
|
|
||||||
public static Int3 One => new(1, 1, 1);
|
|
||||||
public static Int3 Zero => new(0, 0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z);
|
|
||||||
public Int3 Normalized => (Int3)((Double3)this / Magnitude);
|
|
||||||
|
|
||||||
public Int2 XY => new(x, y);
|
|
||||||
public Int2 XZ => new(x, z);
|
|
||||||
public Int2 YZ => new(y, z);
|
|
||||||
|
|
||||||
public int x, y, z;
|
|
||||||
|
|
||||||
public Int3(int all) : this(all, all, all) { }
|
|
||||||
public Int3(int x, int y) : this(x, y, 0) { }
|
|
||||||
public Int3(int x, int y, int z)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
public Int3(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
|
|
||||||
|
|
||||||
public int this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
2 => z,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
z = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Int3 Absolute(Int3 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
|
||||||
public static Int3 Average(params Int3[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Int3 Clamp(Int3 val, Int3 min, Int3 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y),
|
|
||||||
Mathf.Clamp(val.z, min.z, max.z));
|
|
||||||
public static Int3 ClampMagnitude(Int3 val, int minMag, int maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int3 Cross(Int3 a, Int3 b, bool normalized = false)
|
|
||||||
{
|
|
||||||
Int3 val = new(a.y * b.z - b.y * a.z,
|
|
||||||
b.x * a.z - a.x * b.z,
|
|
||||||
a.x * b.y - b.x * a.y);
|
|
||||||
return normalized ? val.Normalized : val;
|
|
||||||
}
|
|
||||||
public static Int3 Divide(Int3 num, params Int3[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int3 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static int Dot(Int3 a, Int3 b) => a.x * b.x + a.y * b.y + a.z * b.z;
|
|
||||||
public static int Dot(params Int3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int x = 1, y = 1, z = 1;
|
|
||||||
foreach (Int3 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
z *= d.z;
|
|
||||||
}
|
|
||||||
return x + y + z;
|
|
||||||
}
|
|
||||||
public static Int3 Lerp(Int3 a, Int3 b, double 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));
|
|
||||||
public static Int3 Median(params Int3[] vals)
|
|
||||||
{
|
|
||||||
int index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Int3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Int3 Max(params Int3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int3 val = vals[0];
|
|
||||||
foreach (Int3 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int3 Min(params Int3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int3 val = vals[0];
|
|
||||||
foreach (Int3 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int3 Multiply(params Int3[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int3 val = One;
|
|
||||||
foreach (Int3 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int3 Subtract(Int3 num, params Int3[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int3 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Int3 Sum(params Int3[] vals)
|
|
||||||
{
|
|
||||||
Int3 val = Zero;
|
|
||||||
foreach (Int3 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Int3)) return false;
|
|
||||||
return Equals((Int3)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Int3(x, y, z);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<int> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
yield return z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] ToArray() => new[] { x, y, z };
|
|
||||||
public List<int> ToList() => new() { x, y, 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 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
|
||||||
public static Int3 operator *(Int3 a, Int3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
|
||||||
public static Int3 operator *(Int3 a, int b) => new(a.x * b, a.y * b, a.z * b);
|
|
||||||
public static Int3 operator /(Int3 a, Int3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
|
||||||
public static Int3 operator /(Int3 a, int b) => new(a.x / b, a.y / b, a.z / b);
|
|
||||||
public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z);
|
|
||||||
public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z);
|
|
||||||
public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z);
|
|
||||||
public static bool operator ==(Int3 a, Int3 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0;
|
|
||||||
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(Double2 val) => new((int)val.x, (int)val.y, 0);
|
|
||||||
public static explicit operator Int3(Double3 val) => new((int)val.x, (int)val.y, (int)val.z);
|
|
||||||
public static explicit operator Int3(Double4 val) => new((int)val.x, (int)val.y, (int)val.z);
|
|
||||||
public static implicit operator Int3(Int2 val) => new(val.x, val.y, 0);
|
|
||||||
public static explicit operator Int3(Int4 val) => new(val.x, val.y, val.z);
|
|
||||||
public static explicit operator Int3(Vert val) => new((int)val.position.x, (int)val.position.y,
|
|
||||||
(int)val.position.z);
|
|
||||||
public static implicit operator Int3(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Int3(Fill<int> fill) : this(fill(0), fill(1), fill(2)) { }
|
||||||
|
|
||||||
|
public int this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
2 => z,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
z = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int3 Absolute(Int3 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z));
|
||||||
|
public static Int3 Average(params Int3[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Int3 Clamp(Int3 val, Int3 min, Int3 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y),
|
||||||
|
Mathf.Clamp(val.z, min.z, max.z));
|
||||||
|
public static Int3 ClampMagnitude(Int3 val, int minMag, int maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int3 Cross(Int3 a, Int3 b, bool normalized = false)
|
||||||
|
{
|
||||||
|
Int3 val = new(a.y * b.z - b.y * a.z,
|
||||||
|
b.x * a.z - a.x * b.z,
|
||||||
|
a.x * b.y - b.x * a.y);
|
||||||
|
return normalized ? val.Normalized : val;
|
||||||
|
}
|
||||||
|
public static Int3 Divide(Int3 num, params Int3[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int3 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static int Dot(Int3 a, Int3 b) => a.x * b.x + a.y * b.y + a.z * b.z;
|
||||||
|
public static int Dot(params Int3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int x = 1, y = 1, z = 1;
|
||||||
|
foreach (Int3 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
z *= d.z;
|
||||||
|
}
|
||||||
|
return x + y + z;
|
||||||
|
}
|
||||||
|
public static Int3 Lerp(Int3 a, Int3 b, double 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));
|
||||||
|
public static Int3 Median(params Int3[] vals)
|
||||||
|
{
|
||||||
|
int index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Int3 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Int3 Max(params Int3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int3 val = vals[0];
|
||||||
|
foreach (Int3 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int3 Min(params Int3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int3 val = vals[0];
|
||||||
|
foreach (Int3 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int3 Multiply(params Int3[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int3 val = One;
|
||||||
|
foreach (Int3 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int3 Subtract(Int3 num, params Int3[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int3 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Int3 Sum(params Int3[] vals)
|
||||||
|
{
|
||||||
|
Int3 val = Zero;
|
||||||
|
foreach (Int3 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public int CompareTo(Int3 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Int3)) return false;
|
||||||
|
return Equals((Int3)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Int3 other) => x == other.x && y == other.y && z == other.z;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider);
|
||||||
|
public object Clone() => new Int3(x, y, z);
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<int> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
yield return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] ToArray() => new[] { x, y, z };
|
||||||
|
public List<int> ToList() => new() { x, y, 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 a, Int3 b) => new(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||||
|
public static Int3 operator *(Int3 a, Int3 b) => new(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||||
|
public static Int3 operator *(Int3 a, int b) => new(a.x * b, a.y * b, a.z * b);
|
||||||
|
public static Int3 operator /(Int3 a, Int3 b) => new(a.x / b.x, a.y / b.y, a.z / b.z);
|
||||||
|
public static Int3 operator /(Int3 a, int b) => new(a.x / b, a.y / b, a.z / b);
|
||||||
|
public static Int3 operator &(Int3 a, Int3 b) => new(a.x & b.x, a.y & b.y, a.z & b.z);
|
||||||
|
public static Int3 operator |(Int3 a, Int3 b) => new(a.x | b.x, a.y | b.y, a.z | b.z);
|
||||||
|
public static Int3 operator ^(Int3 a, Int3 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z);
|
||||||
|
public static bool operator ==(Int3 a, Int3 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Int3 a, Int3 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Int3 a, Int3 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Int3 a, Int3 b) => a.CompareTo(b) < 0;
|
||||||
|
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(Double2 val) => new((int)val.x, (int)val.y, 0);
|
||||||
|
public static explicit operator Int3(Double3 val) => new((int)val.x, (int)val.y, (int)val.z);
|
||||||
|
public static explicit operator Int3(Double4 val) => new((int)val.x, (int)val.y, (int)val.z);
|
||||||
|
public static implicit operator Int3(Int2 val) => new(val.x, val.y, 0);
|
||||||
|
public static explicit operator Int3(Int4 val) => new(val.x, val.y, val.z);
|
||||||
|
public static explicit operator Int3(Vert val) => new((int)val.position.x, (int)val.position.y,
|
||||||
|
(int)val.position.z);
|
||||||
|
public static implicit operator Int3(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,221 +1,216 @@
|
|||||||
using Nerd_STF.Mathematics.Geometry;
|
namespace Nerd_STF.Mathematics;
|
||||||
using System.Collections;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
|
|
||||||
namespace Nerd_STF.Mathematics
|
public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int>
|
||||||
{
|
{
|
||||||
public struct Int4 : ICloneable, IComparable<Int4>, IEquatable<Int4>, IGroup<int>
|
public static Int4 Back => new(0, 0, -1, 0);
|
||||||
|
public static Int4 Deep => new(0, 0, 0, -1);
|
||||||
|
public static Int4 Down => new(0, -1, 0, 0);
|
||||||
|
public static Int4 Far => new(0, 0, 0, 1);
|
||||||
|
public static Int4 Forward => new(0, 0, 1, 0);
|
||||||
|
public static Int4 Left => new(-1, 0, 0, 0);
|
||||||
|
public static Int4 Right => new(1, 0, 0, 0);
|
||||||
|
public static Int4 Up => new(0, 1, 0, 0);
|
||||||
|
|
||||||
|
public static Int4 One => new(1, 1, 1, 1);
|
||||||
|
public static Int4 Zero => new(0, 0, 0, 0);
|
||||||
|
|
||||||
|
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
||||||
|
public Int4 Normalized => (Int4)((Double4)this / Magnitude);
|
||||||
|
|
||||||
|
public Int2 XY => new(x, y);
|
||||||
|
public Int2 XZ => new(x, z);
|
||||||
|
public Int2 XW => new(x, w);
|
||||||
|
public Int2 YW => new(y, w);
|
||||||
|
public Int2 YZ => new(y, z);
|
||||||
|
public Int2 ZW => new(z, w);
|
||||||
|
|
||||||
|
public Int3 XYW => new(x, y, w);
|
||||||
|
public Int3 XYZ => new(x, y, z);
|
||||||
|
public Int3 YZW => new(y, z, w);
|
||||||
|
public Int3 XZW => new(x, z, w);
|
||||||
|
|
||||||
|
public int x, y, z, w;
|
||||||
|
|
||||||
|
public Int4(int all) : this(all, all, all, all) { }
|
||||||
|
public Int4(int x, int y) : this(x, y, 0, 0) { }
|
||||||
|
public Int4(int x, int y, int z) : this(x, y, z, 0) { }
|
||||||
|
public Int4(int x, int y, int z, int w)
|
||||||
{
|
{
|
||||||
public static Int4 Back => new(0, 0, -1, 0);
|
this.x = x;
|
||||||
public static Int4 Deep => new(0, 0, 0, -1);
|
this.y = y;
|
||||||
public static Int4 Down => new(0, -1, 0, 0);
|
this.z = z;
|
||||||
public static Int4 Far => new(0, 0, 0, 1);
|
this.w = w;
|
||||||
public static Int4 Forward => new(0, 0, 1, 0);
|
|
||||||
public static Int4 Left => new(-1, 0, 0, 0);
|
|
||||||
public static Int4 Right => new(1, 0, 0, 0);
|
|
||||||
public static Int4 Up => new(0, 1, 0, 0);
|
|
||||||
|
|
||||||
public static Int4 One => new(1, 1, 1, 1);
|
|
||||||
public static Int4 Zero => new(0, 0, 0, 0);
|
|
||||||
|
|
||||||
public double Magnitude => Mathf.Sqrt(x * x + y * y + z * z + w * w);
|
|
||||||
public Int4 Normalized => (Int4)((Double4)this / Magnitude);
|
|
||||||
|
|
||||||
public Int2 XY => new(x, y);
|
|
||||||
public Int2 XZ => new(x, z);
|
|
||||||
public Int2 XW => new(x, w);
|
|
||||||
public Int2 YW => new(y, w);
|
|
||||||
public Int2 YZ => new(y, z);
|
|
||||||
public Int2 ZW => new(z, w);
|
|
||||||
|
|
||||||
public Int3 XYW => new(x, y, w);
|
|
||||||
public Int3 XYZ => new(x, y, z);
|
|
||||||
public Int3 YZW => new(y, z, w);
|
|
||||||
public Int3 XZW => new(x, z, w);
|
|
||||||
|
|
||||||
public int x, y, z, w;
|
|
||||||
|
|
||||||
public Int4(int all) : this(all, all, all, all) { }
|
|
||||||
public Int4(int x, int y) : this(x, y, 0, 0) { }
|
|
||||||
public Int4(int x, int y, int z) : this(x, y, z, 0) { }
|
|
||||||
public Int4(int x, int y, int z, int w)
|
|
||||||
{
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
this.w = w;
|
|
||||||
}
|
|
||||||
public Int4(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
|
||||||
|
|
||||||
public int this[int index]
|
|
||||||
{
|
|
||||||
get => index switch
|
|
||||||
{
|
|
||||||
0 => x,
|
|
||||||
1 => y,
|
|
||||||
2 => z,
|
|
||||||
3 => w,
|
|
||||||
_ => throw new IndexOutOfRangeException(nameof(index)),
|
|
||||||
};
|
|
||||||
set
|
|
||||||
{
|
|
||||||
switch (index)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
x = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
y = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
z = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
w = value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: throw new IndexOutOfRangeException(nameof(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Int4 Absolute(Int4 val) =>
|
|
||||||
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
|
||||||
public static Int4 Average(params Int4[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static Int4 Clamp(Int4 val, Int4 min, Int4 max) =>
|
|
||||||
new(Mathf.Clamp(val.x, min.x, max.x),
|
|
||||||
Mathf.Clamp(val.y, min.y, max.y),
|
|
||||||
Mathf.Clamp(val.z, min.z, max.z),
|
|
||||||
Mathf.Clamp(val.w, min.w, max.w));
|
|
||||||
public static Int4 ClampMagnitude(Int4 val, int minMag, int maxMag)
|
|
||||||
{
|
|
||||||
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
|
||||||
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
|
||||||
double mag = val.Magnitude;
|
|
||||||
if (mag >= minMag && mag <= maxMag) return val;
|
|
||||||
val = val.Normalized;
|
|
||||||
if (mag < minMag) val *= minMag;
|
|
||||||
else if (mag > maxMag) val *= maxMag;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int4 Divide(Int4 num, params Int4[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int4 d in vals) num /= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static int Dot(Int4 a, Int4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
|
||||||
public static int Dot(params Int4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int x = 1, y = 1, z = 1, w = 1;
|
|
||||||
foreach (Int4 d in vals)
|
|
||||||
{
|
|
||||||
x *= d.x;
|
|
||||||
y *= d.y;
|
|
||||||
z *= d.z;
|
|
||||||
w *= d.w;
|
|
||||||
}
|
|
||||||
return x + y + z;
|
|
||||||
}
|
|
||||||
public static Int4 Lerp(Int4 a, Int4 b, double 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),
|
|
||||||
Mathf.Lerp(a.w, b.w, t, clamp));
|
|
||||||
public static Int4 Median(params Int4[] vals)
|
|
||||||
{
|
|
||||||
int index = Mathf.Average(0, vals.Length - 1);
|
|
||||||
Int4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static Int4 Max(params Int4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int4 val = vals[0];
|
|
||||||
foreach (Int4 d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int4 Min(params Int4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int4 val = vals[0];
|
|
||||||
foreach (Int4 d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int4 Multiply(params Int4[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return Zero;
|
|
||||||
Int4 val = One;
|
|
||||||
foreach (Int4 d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static Int4 Subtract(Int4 num, params Int4[] vals)
|
|
||||||
{
|
|
||||||
foreach (Int4 d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static Int4 Sum(params Int4[] vals)
|
|
||||||
{
|
|
||||||
Int4 val = Zero;
|
|
||||||
foreach (Int4 d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude);
|
|
||||||
public override bool Equals([NotNullWhen(true)] object? obj)
|
|
||||||
{
|
|
||||||
if (obj == null || obj.GetType() != typeof(Int4)) return false;
|
|
||||||
return Equals((Int4)obj);
|
|
||||||
}
|
|
||||||
public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
|
||||||
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
|
||||||
public override string ToString() => ToString((string?)null);
|
|
||||||
public string ToString(string? provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
|
||||||
+ " W: " + w.ToString(provider);
|
|
||||||
public string ToString(IFormatProvider provider) =>
|
|
||||||
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
|
||||||
+ " W: " + w.ToString(provider);
|
|
||||||
|
|
||||||
public object Clone() => new Int4(x, y, z, w);
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
|
||||||
public IEnumerator<int> GetEnumerator()
|
|
||||||
{
|
|
||||||
yield return x;
|
|
||||||
yield return y;
|
|
||||||
yield return z;
|
|
||||||
yield return w;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int[] ToArray() => new[] { x, y, z, w };
|
|
||||||
public List<int> ToList() => new() { x, y, z, w };
|
|
||||||
|
|
||||||
public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
|
||||||
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);
|
|
||||||
public static Int4 operator *(Int4 a, int b) => new(a.x * b, a.y * b, a.z * b, a.w * b);
|
|
||||||
public static Int4 operator /(Int4 a, Int4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
|
||||||
public static Int4 operator /(Int4 a, int b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
|
||||||
public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
|
|
||||||
public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
|
|
||||||
public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
|
||||||
public static bool operator ==(Int4 a, Int4 b) => a.Equals(b);
|
|
||||||
public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b);
|
|
||||||
public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0;
|
|
||||||
public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0;
|
|
||||||
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(Double2 val) => new((int)val.x, (int)val.y, 0, 0);
|
|
||||||
public static explicit operator Int4(Double3 val) => new((int)val.x, (int)val.y, (int)val.z, 0);
|
|
||||||
public static explicit operator Int4(Double4 val) => new((int)val.x, (int)val.y, (int)val.z, (int)val.w);
|
|
||||||
public static implicit operator Int4(Int2 val) => new(val.x, val.y, 0, 0);
|
|
||||||
public static implicit operator Int4(Int3 val) => new(val.x, val.y, val.z, 0);
|
|
||||||
public static explicit operator Int4(Vert val) => new((int)val.position.x, (int)val.position.y,
|
|
||||||
(int)val.position.z, 0);
|
|
||||||
public static implicit operator Int4(Fill<int> fill) => new(fill);
|
|
||||||
}
|
}
|
||||||
|
public Int4(Fill<int> fill) : this(fill(0), fill(1), fill(2), fill(3)) { }
|
||||||
|
|
||||||
|
public int this[int index]
|
||||||
|
{
|
||||||
|
get => index switch
|
||||||
|
{
|
||||||
|
0 => x,
|
||||||
|
1 => y,
|
||||||
|
2 => z,
|
||||||
|
3 => w,
|
||||||
|
_ => throw new IndexOutOfRangeException(nameof(index)),
|
||||||
|
};
|
||||||
|
set
|
||||||
|
{
|
||||||
|
switch (index)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
x = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
y = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
z = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
w = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Int4 Absolute(Int4 val) =>
|
||||||
|
new(Mathf.Absolute(val.x), Mathf.Absolute(val.y), Mathf.Absolute(val.z), Mathf.Absolute(val.w));
|
||||||
|
public static Int4 Average(params Int4[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static Int4 Clamp(Int4 val, Int4 min, Int4 max) =>
|
||||||
|
new(Mathf.Clamp(val.x, min.x, max.x),
|
||||||
|
Mathf.Clamp(val.y, min.y, max.y),
|
||||||
|
Mathf.Clamp(val.z, min.z, max.z),
|
||||||
|
Mathf.Clamp(val.w, min.w, max.w));
|
||||||
|
public static Int4 ClampMagnitude(Int4 val, int minMag, int maxMag)
|
||||||
|
{
|
||||||
|
if (maxMag < minMag) throw new ArgumentOutOfRangeException(nameof(maxMag),
|
||||||
|
nameof(maxMag) + " must be greater than or equal to " + nameof(minMag));
|
||||||
|
double mag = val.Magnitude;
|
||||||
|
if (mag >= minMag && mag <= maxMag) return val;
|
||||||
|
val = val.Normalized;
|
||||||
|
if (mag < minMag) val *= minMag;
|
||||||
|
else if (mag > maxMag) val *= maxMag;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int4 Divide(Int4 num, params Int4[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int4 d in vals) num /= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static int Dot(Int4 a, Int4 b) => a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
|
||||||
|
public static int Dot(params Int4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int x = 1, y = 1, z = 1, w = 1;
|
||||||
|
foreach (Int4 d in vals)
|
||||||
|
{
|
||||||
|
x *= d.x;
|
||||||
|
y *= d.y;
|
||||||
|
z *= d.z;
|
||||||
|
w *= d.w;
|
||||||
|
}
|
||||||
|
return x + y + z;
|
||||||
|
}
|
||||||
|
public static Int4 Lerp(Int4 a, Int4 b, double 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),
|
||||||
|
Mathf.Lerp(a.w, b.w, t, clamp));
|
||||||
|
public static Int4 Median(params Int4[] vals)
|
||||||
|
{
|
||||||
|
int index = Mathf.Average(0, vals.Length - 1);
|
||||||
|
Int4 valA = vals[Mathf.Floor(index)], valB = vals[Mathf.Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static Int4 Max(params Int4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int4 val = vals[0];
|
||||||
|
foreach (Int4 d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int4 Min(params Int4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int4 val = vals[0];
|
||||||
|
foreach (Int4 d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int4 Multiply(params Int4[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return Zero;
|
||||||
|
Int4 val = One;
|
||||||
|
foreach (Int4 d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static Int4 Subtract(Int4 num, params Int4[] vals)
|
||||||
|
{
|
||||||
|
foreach (Int4 d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static Int4 Sum(params Int4[] vals)
|
||||||
|
{
|
||||||
|
Int4 val = Zero;
|
||||||
|
foreach (Int4 d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int CompareTo(Int4 other) => Magnitude.CompareTo(other.Magnitude);
|
||||||
|
public override bool Equals([NotNullWhen(true)] object? obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != typeof(Int4)) return false;
|
||||||
|
return Equals((Int4)obj);
|
||||||
|
}
|
||||||
|
public bool Equals(Int4 other) => x == other.x && y == other.y && z == other.z && w == other.w;
|
||||||
|
public override int GetHashCode() => x.GetHashCode() ^ y.GetHashCode() ^ z.GetHashCode() ^ w.GetHashCode();
|
||||||
|
public override string ToString() => ToString((string?)null);
|
||||||
|
public string ToString(string? provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||||
|
+ " W: " + w.ToString(provider);
|
||||||
|
public string ToString(IFormatProvider provider) =>
|
||||||
|
"X: " + x.ToString(provider) + " Y: " + y.ToString(provider) + " Z: " + z.ToString(provider)
|
||||||
|
+ " W: " + w.ToString(provider);
|
||||||
|
|
||||||
|
public object Clone() => new Int4(x, y, z, w);
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
public IEnumerator<int> GetEnumerator()
|
||||||
|
{
|
||||||
|
yield return x;
|
||||||
|
yield return y;
|
||||||
|
yield return z;
|
||||||
|
yield return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] ToArray() => new[] { x, y, z, w };
|
||||||
|
public List<int> ToList() => new() { x, y, z, w };
|
||||||
|
|
||||||
|
public static Int4 operator +(Int4 a, Int4 b) => new(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
|
||||||
|
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);
|
||||||
|
public static Int4 operator *(Int4 a, int b) => new(a.x * b, a.y * b, a.z * b, a.w * b);
|
||||||
|
public static Int4 operator /(Int4 a, Int4 b) => new(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
|
||||||
|
public static Int4 operator /(Int4 a, int b) => new(a.x / b, a.y / b, a.z / b, a.w / b);
|
||||||
|
public static Int4 operator &(Int4 a, Int4 b) => new(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
|
||||||
|
public static Int4 operator |(Int4 a, Int4 b) => new(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
|
||||||
|
public static Int4 operator ^(Int4 a, Int4 b) => new(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
|
||||||
|
public static bool operator ==(Int4 a, Int4 b) => a.Equals(b);
|
||||||
|
public static bool operator !=(Int4 a, Int4 b) => !a.Equals(b);
|
||||||
|
public static bool operator >(Int4 a, Int4 b) => a.CompareTo(b) > 0;
|
||||||
|
public static bool operator <(Int4 a, Int4 b) => a.CompareTo(b) < 0;
|
||||||
|
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(Double2 val) => new((int)val.x, (int)val.y, 0, 0);
|
||||||
|
public static explicit operator Int4(Double3 val) => new((int)val.x, (int)val.y, (int)val.z, 0);
|
||||||
|
public static explicit operator Int4(Double4 val) => new((int)val.x, (int)val.y, (int)val.z, (int)val.w);
|
||||||
|
public static implicit operator Int4(Int2 val) => new(val.x, val.y, 0, 0);
|
||||||
|
public static implicit operator Int4(Int3 val) => new(val.x, val.y, val.z, 0);
|
||||||
|
public static explicit operator Int4(Vert val) => new((int)val.position.x, (int)val.position.y,
|
||||||
|
(int)val.position.z, 0);
|
||||||
|
public static implicit operator Int4(Fill<int> fill) => new(fill);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,253 +1,252 @@
|
|||||||
namespace Nerd_STF.Mathematics
|
namespace Nerd_STF.Mathematics;
|
||||||
|
|
||||||
|
public static class Mathf
|
||||||
{
|
{
|
||||||
public static class Mathf
|
public const double RadToDeg = 0.0174532925199; // Pi / 180
|
||||||
|
public const double E = 2.71828182846;
|
||||||
|
public const double GoldenRatio = 1.61803398875; // (1 + Sqrt(5)) / 2
|
||||||
|
public const double HalfPi = 1.57079632679; // Pi / 2
|
||||||
|
public const double Pi = 3.14159265359;
|
||||||
|
public const double DegToRad = 57.2957795131; // 180 / Pi
|
||||||
|
public const double Tau = 6.28318530718; // 2 * Pi
|
||||||
|
|
||||||
|
public static double Absolute(double val) => val < 0 ? -val : val;
|
||||||
|
public static int Absolute(int val) => val < 0 ? -val : val;
|
||||||
|
|
||||||
|
public static double ArcCos(double value) => -ArcSin(value) + HalfPi;
|
||||||
|
|
||||||
|
public static double ArcCot(double value) => ArcCos(value / Sqrt(1 + value * value));
|
||||||
|
|
||||||
|
public static double ArcCsc(double value) => ArcSin(1 / value);
|
||||||
|
|
||||||
|
public static double ArcSec(double value) => ArcCos(1 / value);
|
||||||
|
|
||||||
|
// Maybe one day I'll have a polynomial for this, but the RMSE for an order 10 polynomial is only 0.00876.
|
||||||
|
public static double ArcSin(double value) => Math.Asin(value);
|
||||||
|
|
||||||
|
public static double ArcTan(double value) => ArcSin(value / Sqrt(1 + value * value));
|
||||||
|
|
||||||
|
public static double Average(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
||||||
{
|
{
|
||||||
public const double RadToDeg = 0.0174532925199; // Pi / 180
|
List<double> vals = new();
|
||||||
public const double E = 2.71828182846;
|
for (double x = min; x <= max; x += step) vals.Add(equ(x));
|
||||||
public const double GoldenRatio = 1.61803398875; // (1 + Sqrt(5)) / 2
|
return Average(vals.ToArray());
|
||||||
public const double HalfPi = 1.57079632679; // Pi / 2
|
|
||||||
public const double Pi = 3.14159265359;
|
|
||||||
public const double DegToRad = 57.2957795131; // 180 / Pi
|
|
||||||
public const double Tau = 6.28318530718; // 2 * Pi
|
|
||||||
|
|
||||||
public static double Absolute(double val) => val < 0 ? -val : val;
|
|
||||||
public static int Absolute(int val) => val < 0 ? -val : val;
|
|
||||||
|
|
||||||
public static double ArcCos(double value) => -ArcSin(value) + HalfPi;
|
|
||||||
|
|
||||||
public static double ArcCot(double value) => ArcCos(value / Sqrt(1 + value * value));
|
|
||||||
|
|
||||||
public static double ArcCsc(double value) => ArcSin(1 / value);
|
|
||||||
|
|
||||||
public static double ArcSec(double value) => ArcCos(1 / value);
|
|
||||||
|
|
||||||
// Maybe one day I'll have a polynomial for this, but the RMSE for an order 10 polynomial is only 0.00876.
|
|
||||||
public static double ArcSin(double value) => Math.Asin(value);
|
|
||||||
|
|
||||||
public static double ArcTan(double value) => ArcSin(value / Sqrt(1 + value * value));
|
|
||||||
|
|
||||||
public static double Average(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
|
||||||
{
|
|
||||||
List<double> vals = new();
|
|
||||||
for (double x = min; x <= max; x += step) vals.Add(equ(x));
|
|
||||||
return Average(vals.ToArray());
|
|
||||||
}
|
|
||||||
public static double Average(params double[] vals) => Sum(vals) / vals.Length;
|
|
||||||
public static int Average(params int[] vals) => Sum(vals) / vals.Length;
|
|
||||||
|
|
||||||
public static int Ceiling(double val) => (int)(val + (1 - (val % 1)));
|
|
||||||
|
|
||||||
public static double Clamp(double val, double min, double max)
|
|
||||||
{
|
|
||||||
if (max < min) throw new ArgumentOutOfRangeException(nameof(max),
|
|
||||||
nameof(max) + " must be greater than or equal to " + nameof(min));
|
|
||||||
val = val < min ? min : val;
|
|
||||||
val = val > max ? max : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Clamp(int val, int min, int max)
|
|
||||||
{
|
|
||||||
if (max < min) throw new ArgumentOutOfRangeException(nameof(max),
|
|
||||||
nameof(max) + " must be greater than or equal to " + nameof(min));
|
|
||||||
val = val < min ? min : val;
|
|
||||||
val = val > max ? max : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Cos(double radians) => Sin(radians + HalfPi);
|
|
||||||
|
|
||||||
public static double Cot(double radians) => Cos(radians) / Sin(radians);
|
|
||||||
|
|
||||||
public static double Csc(double radians) => 1 / Sin(radians);
|
|
||||||
|
|
||||||
public static double Divide(double val, params double[] dividends)
|
|
||||||
{
|
|
||||||
foreach (double d in dividends) val /= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Divide(int val, params int[] dividends)
|
|
||||||
{
|
|
||||||
foreach (int i in dividends) val /= i;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Factorial(int amount)
|
|
||||||
{
|
|
||||||
if (amount < 0) return 0;
|
|
||||||
int val = 1;
|
|
||||||
for (int i = 2; i <= amount; i++) val *= i;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Floor(double val) => (int)(val - (val % 1));
|
|
||||||
|
|
||||||
public static Dictionary<double, double> GetValues(Equation equ, double min, double max,
|
|
||||||
double step = Calculus.DefaultStep)
|
|
||||||
{
|
|
||||||
Dictionary<double, double> vals = new();
|
|
||||||
for (double x = min; x <= max; x += step) vals.Add(x, equ(x));
|
|
||||||
return vals;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Lerp(double a, double b, double t, bool clamp = true)
|
|
||||||
{
|
|
||||||
double v = a + t * (b - a);
|
|
||||||
if (clamp) v = Clamp(v, a, b);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
public static int Lerp(int a, int b, double value, bool clamp = true) => Floor(Lerp(a, b, value, clamp));
|
|
||||||
|
|
||||||
public static Equation MakeEquation(Dictionary<double, double> vals) => (x) =>
|
|
||||||
{
|
|
||||||
double min = -1, max = -1;
|
|
||||||
foreach (KeyValuePair<double, double> val in vals)
|
|
||||||
{
|
|
||||||
if (val.Key <= x) min = val.Key;
|
|
||||||
if (val.Key >= x) max = val.Key;
|
|
||||||
|
|
||||||
if (min != -1 && max != -1) break;
|
|
||||||
}
|
|
||||||
double per = x % (max - min);
|
|
||||||
return Lerp(min, max, per);
|
|
||||||
};
|
|
||||||
|
|
||||||
public static double Max(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
|
||||||
{
|
|
||||||
double Y = equ(min);
|
|
||||||
for (double x = min; x <= max; x += step)
|
|
||||||
{
|
|
||||||
double val = equ(x);
|
|
||||||
Y = val > Y ? val : Y;
|
|
||||||
}
|
|
||||||
return Y;
|
|
||||||
}
|
|
||||||
public static double Max(params double[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double val = vals[0];
|
|
||||||
foreach (double d in vals) val = d > val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Max(params int[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int val = vals[0];
|
|
||||||
foreach (int i in vals) val = i > val ? i : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Median(params double[] vals)
|
|
||||||
{
|
|
||||||
double index = Average(0, vals.Length - 1);
|
|
||||||
double valA = vals[Floor(index)], valB = vals[Ceiling(index)];
|
|
||||||
return Average(valA, valB);
|
|
||||||
}
|
|
||||||
public static int Median(params int[] vals) => vals[Floor(Average(0, vals.Length - 1))];
|
|
||||||
|
|
||||||
public static double Min(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
|
||||||
{
|
|
||||||
double Y = equ(min);
|
|
||||||
for (double x = min; x <= max; x += step)
|
|
||||||
{
|
|
||||||
double val = equ(x);
|
|
||||||
Y = val < Y ? val : Y;
|
|
||||||
}
|
|
||||||
return Y;
|
|
||||||
}
|
|
||||||
public static double Min(params double[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double val = vals[0];
|
|
||||||
foreach (double d in vals) val = d < val ? d : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Min(params int[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int val = vals[0];
|
|
||||||
foreach (int i in vals) val = i < val ? i : val;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Multiply(params double[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
double val = 1;
|
|
||||||
foreach (double d in vals) val *= d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Multiply(params int[] vals)
|
|
||||||
{
|
|
||||||
if (vals.Length < 1) return 0;
|
|
||||||
int val = 1;
|
|
||||||
foreach (int i in vals) val *= i;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Power(double num, double pow) => Math.Pow(num, pow);
|
|
||||||
public static int Power(int num, int pow)
|
|
||||||
{
|
|
||||||
if (pow < 0) return 0;
|
|
||||||
int val = 1;
|
|
||||||
for (int i = 0; i < Absolute(pow); i++) val *= num;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Root(double value, double index) => Math.Exp(index * Math.Log(value));
|
|
||||||
|
|
||||||
public static double Round(double num) => num % 1 >= 0.5 ? Ceiling(num) : Floor(num);
|
|
||||||
public static double Round(double num, double nearest) => nearest * Round(num / nearest);
|
|
||||||
public static int RoundInt(double num) => (int)Round(num);
|
|
||||||
|
|
||||||
public static double Sec(double radians) => 1 / Cos(radians);
|
|
||||||
|
|
||||||
public static double Sin(double radians)
|
|
||||||
{
|
|
||||||
// Really close polynomial to sin(x) (when modded by 2pi). RMSE of 0.000003833
|
|
||||||
const double a = 0.000013028,
|
|
||||||
b = 0.999677,
|
|
||||||
c = 0.00174164,
|
|
||||||
d = -0.170587,
|
|
||||||
e = 0.0046494,
|
|
||||||
f = 0.00508955,
|
|
||||||
g = 0.00140205,
|
|
||||||
h = -0.000577413,
|
|
||||||
i = 0.0000613134,
|
|
||||||
j = -0.00000216852;
|
|
||||||
double x = radians % Tau;
|
|
||||||
|
|
||||||
return
|
|
||||||
a + (b * x) + (c * x * x) + (d * x * x * x) + (e * x * x * x * x) + (f * x * x * x * x * x)
|
|
||||||
+ (g * x * x * x * x * x * x) + (h * x * x * x * x * x * x * x) + (i * x * x * x * x * x * x * x * x)
|
|
||||||
+ (j * x * x * x * x * x * x * x * x * x);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Sqrt(double value) => Root(value, 2);
|
|
||||||
|
|
||||||
public static double Subtract(double num, params double[] vals)
|
|
||||||
{
|
|
||||||
foreach (double d in vals) num -= d;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
public static int Subtract(int num, params int[] vals)
|
|
||||||
{
|
|
||||||
foreach (int i in vals) num -= i;
|
|
||||||
return num;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Sum(params double[] vals)
|
|
||||||
{
|
|
||||||
double val = 0;
|
|
||||||
foreach (double d in vals) val += d;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
public static int Sum(params int[] vals)
|
|
||||||
{
|
|
||||||
int val = 0;
|
|
||||||
foreach (int i in vals) val += i;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static double Tan(double radians) => Sin(radians) / Cos(radians);
|
|
||||||
}
|
}
|
||||||
|
public static double Average(params double[] vals) => Sum(vals) / vals.Length;
|
||||||
|
public static int Average(params int[] vals) => Sum(vals) / vals.Length;
|
||||||
|
|
||||||
|
public static int Ceiling(double val) => (int)(val + (1 - (val % 1)));
|
||||||
|
|
||||||
|
public static double Clamp(double val, double min, double max)
|
||||||
|
{
|
||||||
|
if (max < min) throw new ArgumentOutOfRangeException(nameof(max),
|
||||||
|
nameof(max) + " must be greater than or equal to " + nameof(min));
|
||||||
|
val = val < min ? min : val;
|
||||||
|
val = val > max ? max : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Clamp(int val, int min, int max)
|
||||||
|
{
|
||||||
|
if (max < min) throw new ArgumentOutOfRangeException(nameof(max),
|
||||||
|
nameof(max) + " must be greater than or equal to " + nameof(min));
|
||||||
|
val = val < min ? min : val;
|
||||||
|
val = val > max ? max : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Cos(double radians) => Sin(radians + HalfPi);
|
||||||
|
|
||||||
|
public static double Cot(double radians) => Cos(radians) / Sin(radians);
|
||||||
|
|
||||||
|
public static double Csc(double radians) => 1 / Sin(radians);
|
||||||
|
|
||||||
|
public static double Divide(double val, params double[] dividends)
|
||||||
|
{
|
||||||
|
foreach (double d in dividends) val /= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Divide(int val, params int[] dividends)
|
||||||
|
{
|
||||||
|
foreach (int i in dividends) val /= i;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Factorial(int amount)
|
||||||
|
{
|
||||||
|
if (amount < 0) return 0;
|
||||||
|
int val = 1;
|
||||||
|
for (int i = 2; i <= amount; i++) val *= i;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int Floor(double val) => (int)(val - (val % 1));
|
||||||
|
|
||||||
|
public static Dictionary<double, double> GetValues(Equation equ, double min, double max,
|
||||||
|
double step = Calculus.DefaultStep)
|
||||||
|
{
|
||||||
|
Dictionary<double, double> vals = new();
|
||||||
|
for (double x = min; x <= max; x += step) vals.Add(x, equ(x));
|
||||||
|
return vals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Lerp(double a, double b, double t, bool clamp = true)
|
||||||
|
{
|
||||||
|
double v = a + t * (b - a);
|
||||||
|
if (clamp) v = Clamp(v, a, b);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
public static int Lerp(int a, int b, double value, bool clamp = true) => Floor(Lerp(a, b, value, clamp));
|
||||||
|
|
||||||
|
public static Equation MakeEquation(Dictionary<double, double> vals) => (x) =>
|
||||||
|
{
|
||||||
|
double min = -1, max = -1;
|
||||||
|
foreach (KeyValuePair<double, double> val in vals)
|
||||||
|
{
|
||||||
|
if (val.Key <= x) min = val.Key;
|
||||||
|
if (val.Key >= x) max = val.Key;
|
||||||
|
|
||||||
|
if (min != -1 && max != -1) break;
|
||||||
|
}
|
||||||
|
double per = x % (max - min);
|
||||||
|
return Lerp(min, max, per);
|
||||||
|
};
|
||||||
|
|
||||||
|
public static double Max(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
||||||
|
{
|
||||||
|
double Y = equ(min);
|
||||||
|
for (double x = min; x <= max; x += step)
|
||||||
|
{
|
||||||
|
double val = equ(x);
|
||||||
|
Y = val > Y ? val : Y;
|
||||||
|
}
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
public static double Max(params double[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double val = vals[0];
|
||||||
|
foreach (double d in vals) val = d > val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Max(params int[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int val = vals[0];
|
||||||
|
foreach (int i in vals) val = i > val ? i : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Median(params double[] vals)
|
||||||
|
{
|
||||||
|
double index = Average(0, vals.Length - 1);
|
||||||
|
double valA = vals[Floor(index)], valB = vals[Ceiling(index)];
|
||||||
|
return Average(valA, valB);
|
||||||
|
}
|
||||||
|
public static int Median(params int[] vals) => vals[Floor(Average(0, vals.Length - 1))];
|
||||||
|
|
||||||
|
public static double Min(Equation equ, double min, double max, double step = Calculus.DefaultStep)
|
||||||
|
{
|
||||||
|
double Y = equ(min);
|
||||||
|
for (double x = min; x <= max; x += step)
|
||||||
|
{
|
||||||
|
double val = equ(x);
|
||||||
|
Y = val < Y ? val : Y;
|
||||||
|
}
|
||||||
|
return Y;
|
||||||
|
}
|
||||||
|
public static double Min(params double[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double val = vals[0];
|
||||||
|
foreach (double d in vals) val = d < val ? d : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Min(params int[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int val = vals[0];
|
||||||
|
foreach (int i in vals) val = i < val ? i : val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Multiply(params double[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
double val = 1;
|
||||||
|
foreach (double d in vals) val *= d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Multiply(params int[] vals)
|
||||||
|
{
|
||||||
|
if (vals.Length < 1) return 0;
|
||||||
|
int val = 1;
|
||||||
|
foreach (int i in vals) val *= i;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Power(double num, double pow) => Math.Pow(num, pow);
|
||||||
|
public static int Power(int num, int pow)
|
||||||
|
{
|
||||||
|
if (pow < 0) return 0;
|
||||||
|
int val = 1;
|
||||||
|
for (int i = 0; i < Absolute(pow); i++) val *= num;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Root(double value, double index) => Math.Exp(index * Math.Log(value));
|
||||||
|
|
||||||
|
public static double Round(double num) => num % 1 >= 0.5 ? Ceiling(num) : Floor(num);
|
||||||
|
public static double Round(double num, double nearest) => nearest * Round(num / nearest);
|
||||||
|
public static int RoundInt(double num) => (int)Round(num);
|
||||||
|
|
||||||
|
public static double Sec(double radians) => 1 / Cos(radians);
|
||||||
|
|
||||||
|
public static double Sin(double radians)
|
||||||
|
{
|
||||||
|
// Really close polynomial to sin(x) (when modded by 2pi). RMSE of 0.000003833
|
||||||
|
const double a = 0.000013028,
|
||||||
|
b = 0.999677,
|
||||||
|
c = 0.00174164,
|
||||||
|
d = -0.170587,
|
||||||
|
e = 0.0046494,
|
||||||
|
f = 0.00508955,
|
||||||
|
g = 0.00140205,
|
||||||
|
h = -0.000577413,
|
||||||
|
i = 0.0000613134,
|
||||||
|
j = -0.00000216852;
|
||||||
|
double x = radians % Tau;
|
||||||
|
|
||||||
|
return
|
||||||
|
a + (b * x) + (c * x * x) + (d * x * x * x) + (e * x * x * x * x) + (f * x * x * x * x * x)
|
||||||
|
+ (g * x * x * x * x * x * x) + (h * x * x * x * x * x * x * x) + (i * x * x * x * x * x * x * x * x)
|
||||||
|
+ (j * x * x * x * x * x * x * x * x * x);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Sqrt(double value) => Root(value, 2);
|
||||||
|
|
||||||
|
public static double Subtract(double num, params double[] vals)
|
||||||
|
{
|
||||||
|
foreach (double d in vals) num -= d;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
public static int Subtract(int num, params int[] vals)
|
||||||
|
{
|
||||||
|
foreach (int i in vals) num -= i;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Sum(params double[] vals)
|
||||||
|
{
|
||||||
|
double val = 0;
|
||||||
|
foreach (double d in vals) val += d;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
public static int Sum(params int[] vals)
|
||||||
|
{
|
||||||
|
int val = 0;
|
||||||
|
foreach (int i in vals) val += i;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double Tan(double radians) => Sin(radians) / Cos(radians);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
global using System;
|
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.IO;
|
global using System.IO;
|
||||||
global using System.Linq;
|
global using System.Linq;
|
||||||
global using System.Net.Http;
|
global using System.Net.Http;
|
||||||
|
|||||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user