diff --git a/Nerd_STF/CrossSection2d.cs b/Nerd_STF/CrossSection2d.cs new file mode 100644 index 0000000..ee66887 --- /dev/null +++ b/Nerd_STF/CrossSection2d.cs @@ -0,0 +1,8 @@ +namespace Nerd_STF; + +public enum CrossSection2d +{ + XY, + YZ, + ZX +} diff --git a/Nerd_STF/Exceptions/InvalidProjectionMatrixException.cs b/Nerd_STF/Exceptions/InvalidProjectionMatrixException.cs new file mode 100644 index 0000000..b4cd567 --- /dev/null +++ b/Nerd_STF/Exceptions/InvalidProjectionMatrixException.cs @@ -0,0 +1,16 @@ +namespace Nerd_STF.Exceptions; + +[Serializable] +public class InvalidProjectionMatrixException : Nerd_STFException +{ + public Matrix? Matrix; + + public InvalidProjectionMatrixException() : base("This is not a projection matrix.") { } + public InvalidProjectionMatrixException(string message) : base(message) { } + public InvalidProjectionMatrixException(string message, Exception inner) : base(message, inner) { } + public InvalidProjectionMatrixException(Matrix? matrix) : this() => Matrix = matrix; + public InvalidProjectionMatrixException(Matrix? matrix, string message) : this(message) => Matrix = matrix; + public InvalidProjectionMatrixException(Matrix? matrix, string message, Exception inner) : this(message, inner) => + Matrix = matrix; + protected InvalidProjectionMatrixException(SerializationInfo info, StreamingContext context) : base(info, context) { } +} diff --git a/Nerd_STF/Mathematics/Algebra/Matrix.cs b/Nerd_STF/Mathematics/Algebra/Matrix.cs index f97ad07..11f705b 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix.cs @@ -157,6 +157,11 @@ public class Matrix : IMatrix } } + public static Matrix Get2dRotationMatrix(Angle rot) => + Matrix2x2.GenerateRotationMatrix(rot); + public static Matrix Get3dRotationMatrix(Angle yaw, Angle pitch, Angle roll) => + Matrix3x3.GenerateRotationMatrix(yaw, pitch, roll); + public static Matrix Absolute(Matrix val) => new(val.Size, (r, c) => Mathf.Absolute(val[r, c])); public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c])); public static Matrix Clamp(Matrix val, Matrix min, Matrix max) => diff --git a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs index 165ecf3..0735899 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix2x2.cs @@ -161,6 +161,12 @@ public record class Matrix2x2 : IStaticMatrix } } + public static Matrix2x2 GenerateRotationMatrix(Angle rot) => new(new[,] + { + { Mathf.Cos(rot), -Mathf.Sin(rot) }, + { Mathf.Sin(rot), Mathf.Cos(rot) } + }); + public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2)); public static Matrix2x2 Average(params Matrix2x2[] vals) => Sum(vals) / vals.Length; diff --git a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs index 79c4ebb..60ccc4b 100644 --- a/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs +++ b/Nerd_STF/Mathematics/Algebra/Matrix3x3.cs @@ -225,6 +225,34 @@ public record class Matrix3x3 : IStaticMatrix } } + public static Matrix3x3 GenerateRotationMatrix(Angle yaw, Angle pitch, Angle roll) + { + // Could be optimized by merging all of the matrices by hand + // but that's a huge matrix and, as said before like a gajillion + // times, this ain't the optimization update. + + Matrix3x3 yawMatrix = new(new[,] + { + { Mathf.Cos(yaw), -Mathf.Sin(yaw), 0 }, + { Mathf.Sin(yaw), Mathf.Cos(yaw), 0 }, + { 0, 0, 1 } + }); + Matrix3x3 pitchMatrix = new(new[,] + { + { Mathf.Cos(pitch), 0, Mathf.Sin(pitch) }, + { 0, 1, 0 }, + { -Mathf.Sin(pitch), 0, Mathf.Cos(pitch) } + }); + Matrix3x3 rollMatrix = new(new[,] + { + { 1, 0, 0 }, + { 0, Mathf.Cos(roll), -Mathf.Sin(roll) }, + { 0, Mathf.Sin(roll), Mathf.Cos(roll) } + }); + + return yawMatrix * pitchMatrix * rollMatrix; + } + public static Matrix3x3 Absolute(Matrix3x3 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r2c3), diff --git a/Nerd_STF/Mathematics/Algebra/ProjectionMatrix.cs b/Nerd_STF/Mathematics/Algebra/ProjectionMatrix.cs new file mode 100644 index 0000000..da9a4e2 --- /dev/null +++ b/Nerd_STF/Mathematics/Algebra/ProjectionMatrix.cs @@ -0,0 +1,74 @@ +namespace Nerd_STF.Mathematics.Algebra; + +public record class ProjectionMatrix : Matrix3x3 +{ + // TODO: i need to remove the record check from everything, add new equals comparitors + // and re-implement IsValidProjectionMatrix + + public ProjectionMatrix(float all) : this(all, all, all, all, all, all, all, all, all) { } + public ProjectionMatrix(float r1c1, float r1c2, float r1c3, float r2c1, + float r2c2, float r2c3, float r3c1, float r3c2, float r3c3) : + base(r1c1, r1c2, r1c3, r2c1, r2c2, r2c3, r3c1, r3c2, r3c3) + { + //if (!IsValidProjectionMatrix) throw new InvalidProjectionMatrixException(this); + } + public ProjectionMatrix(float[] nums) : this(nums[0], nums[1], nums[2], + nums[3], nums[4], nums[5], nums[6], nums[7], nums[8]) { } + public ProjectionMatrix(int[] nums) : this(nums[0], nums[1], nums[2], + nums[3], nums[4], nums[5], nums[6], nums[7], nums[8]) { } + public ProjectionMatrix(Fill fill) : this(fill(0), fill(1), fill(2), + fill(3), fill(4), fill(5), fill(6), fill(7), fill(8)) { } + public ProjectionMatrix(Fill fill) : this(fill(0), fill(1), fill(2), + fill(3), fill(4), fill(5), fill(6), fill(7), fill(8)) { } + public ProjectionMatrix(float[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], + nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { } + public ProjectionMatrix(int[,] nums) : this(nums[0, 0], nums[0, 1], nums[0, 2], + nums[1, 0], nums[1, 1], nums[1, 2], nums[2, 0], nums[2, 1], nums[2, 2]) { } + public ProjectionMatrix(Fill2d fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), + fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { } + public ProjectionMatrix(Fill2d fill) : this(fill(0, 0), fill(0, 1), fill(0, 2), + fill(1, 0), fill(1, 1), fill(1, 2), fill(2, 0), fill(2, 1), fill(2, 2)) { } + public ProjectionMatrix(Float3 r1, Float3 r2, Float3 r3) : this(r1.x, r1.y, r1.z, r2.x, r2.y, r2.z, r3.x, r3.y, r3.z) { } + public ProjectionMatrix(Fill fill) : this(fill(0), fill(1), fill(2)) { } + public ProjectionMatrix(Fill fill) : this((IEnumerable)fill(0), fill(1), fill(2)) { } + public ProjectionMatrix(IEnumerable r1, IEnumerable r2, IEnumerable r3) + : this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { } + public ProjectionMatrix(IEnumerable r1, IEnumerable r2, IEnumerable r3) + : this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { } + public ProjectionMatrix(Fill r1, Fill r2, Fill r3) + : this(r1(0), r1(1), r1(2), r2(0), r2(1), r2(2), r3(0), r3(1), r3(2)) { } + public ProjectionMatrix(Fill r1, Fill r2, Fill r3) + : this(r1(0), r1(1), r1(2), r2(0), r2(1), r2(2), r3(0), r3(1), r3(2)) { } + + public static ProjectionMatrix SingleViewProjection(CrossSection2d section) => new(new[,] + { + { section == CrossSection2d.XY || section == CrossSection2d.ZX ? 1 : 0, 0, 0 }, + { 0, section == CrossSection2d.XY || section == CrossSection2d.YZ ? 1 : 0, 0 }, + { 0, 0, section == CrossSection2d.YZ || section == CrossSection2d.ZX ? 1 : 0 } + }); + public static ProjectionMatrix IsometricProjection(Angle alpha, Angle beta) + { + Matrix3x3 alphaMat = new(new[,] + { + { 1, 0, 0 }, + { 0, Mathf.Cos(alpha), Mathf.Sin(alpha) }, + { 0, -Mathf.Sin(alpha), Mathf.Cos(alpha) } + }); + Matrix3x3 betaMat = new(new[,] + { + { Mathf.Cos(beta), 0, -Mathf.Sin(beta) }, + { 0, 1, 0 }, + { Mathf.Sin(beta), 0, Mathf.Cos(beta) } + }); + Matrix3x3 flatten = new(new[,] + { + { 1, 0, 0 }, + { 0, 1, 0 }, + { 0, 0, 0 } + }); + Matrix3x3 result = alphaMat * betaMat * flatten; + return new(result.ToFill2D()); + } + + public Fill Project(Fill toProject) => i => this * toProject(i); +} diff --git a/Nerd_STF/Mathematics/Algebra/Vector2d.cs b/Nerd_STF/Mathematics/Algebra/Vector2d.cs index 2720aae..e8f8cdf 100644 --- a/Nerd_STF/Mathematics/Algebra/Vector2d.cs +++ b/Nerd_STF/Mathematics/Algebra/Vector2d.cs @@ -50,7 +50,7 @@ public record struct Vector2d : IAbsolute, IAverage, return new(val.theta, mag); } public static Vector3d Cross(Vector2d a, Vector2d b, bool normalized = false) => - Float2.Cross(a.ToXYZ(), b.ToXYZ(), normalized).ToVector(); + new Float3(0, 0, Float2.Cross(a.ToXYZ(), b.ToXYZ(), normalized)).ToVector(); public static float Dot(Vector2d a, Vector2d b) => Float2.Dot(a.ToXYZ(), b.ToXYZ()); public static float Dot(params Vector2d[] vals) { diff --git a/Nerd_STF/Mathematics/Float2.cs b/Nerd_STF/Mathematics/Float2.cs index e479088..e43d253 100644 --- a/Nerd_STF/Mathematics/Float2.cs +++ b/Nerd_STF/Mathematics/Float2.cs @@ -2,7 +2,7 @@ public record struct Float2 : IAbsolute, IAverage, ICeiling, IClamp, IClampMagnitude, IComparable, - ICross, IDivide, IDot, IEquatable, + ICross, IDivide, IDot, IEquatable, IFloor, IFromTuple, IGroup, ILerp, IMathOperators, IMax, IMedian, IMin, IIndexAll, IIndexRangeAll, IPresets2d, IProduct, IRound, @@ -96,8 +96,8 @@ public record struct Float2 : IAbsolute, IAverage, ICeiling maxMag) val *= maxMag; return val; } - public static Float3 Cross(Float2 a, Float2 b, bool normalized = false) => - Float3.Cross(a, b, normalized); + public static float Cross(Float2 a, Float2 b, bool normalized = false) => + Float3.Cross(a, b, normalized).z; public static Float2 Divide(Float2 num, params Float2[] vals) => num / Product(vals); public static float Dot(Float2 a, Float2 b) => a.x * b.x + a.y * b.y; public static float Dot(params Float2[] vals) diff --git a/Nerd_STF/Mathematics/Geometry/Triangle.cs b/Nerd_STF/Mathematics/Geometry/Triangle.cs index 4b2a095..e7f2228 100644 --- a/Nerd_STF/Mathematics/Geometry/Triangle.cs +++ b/Nerd_STF/Mathematics/Geometry/Triangle.cs @@ -208,18 +208,21 @@ public class Triangle : IClosestTo, IContains, IContainsPartial< } public override int GetHashCode() => base.GetHashCode(); - public bool Contains(Float3 point) + public bool Contains(Float3 point) => Contains(point, 0.05f); + public bool Contains(Float3 point, float tolerance) { Triangle pab = (point, a, b), pbc = (point, b, c), pca = (point, c, a); - return Mathf.Absolute(Area - (pab.Area + pbc.Area + pca.Area)) < 0.05f; + return Mathf.Absolute(Area - (pab.Area + pbc.Area + pca.Area)) < tolerance; } - public bool Contains(Line line) => - Contains(line.a) && Contains(line.b); + public bool Contains(Line line) => Contains(line, 0.05f); + public bool Contains(Line line, float tolerance) => + Contains(line.a, tolerance) && Contains(line.b, tolerance); - public bool ContainsPartially(Line line) => - Contains(line.a) || Contains(line.b); + public bool ContainsPartially(Line line) => ContainsPartially(line, 0.05f); + public bool ContainsPartially(Line line, float tolerance) => + Contains(line.a, tolerance) || Contains(line.b, tolerance); public Float3[] GetAllVerts() => new[] { a, b, c }; diff --git a/Nerd_STF/Nerd_STF.csproj b/Nerd_STF/Nerd_STF.csproj index 5bb893b..4d0467b 100644 --- a/Nerd_STF/Nerd_STF.csproj +++ b/Nerd_STF/Nerd_STF.csproj @@ -66,4 +66,9 @@ Anyway, that's everything in this update. Again, pretty small, but meaningful no + + + + +