Partial commit: Some projection matrix stuff.

This commit is contained in:
That_One_Nerd 2023-09-05 04:59:52 -04:00
parent d58ad7c94f
commit 8b4e61ce82
10 changed files with 155 additions and 10 deletions

View File

@ -0,0 +1,8 @@
namespace Nerd_STF;
public enum CrossSection2d
{
XY,
YZ,
ZX
}

View File

@ -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) { }
}

View File

@ -157,6 +157,11 @@ public class Matrix : IMatrix<Matrix, Matrix>
} }
} }
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 Absolute(Matrix val) => new(val.Size, (r, c) => Mathf.Absolute(val[r, c]));
public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c])); public static Matrix Ceiling(Matrix val) => new(val.Size, (r, c) => Mathf.Ceiling(val[r, c]));
public static Matrix Clamp(Matrix val, Matrix min, Matrix max) => public static Matrix Clamp(Matrix val, Matrix min, Matrix max) =>

View File

@ -161,6 +161,12 @@ public record class Matrix2x2 : IStaticMatrix<Matrix2x2>
} }
} }
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), public static Matrix2x2 Absolute(Matrix2x2 val) => new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2),
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2)); Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2));
public static Matrix2x2 Average(params Matrix2x2[] vals) => Sum(vals) / vals.Length; public static Matrix2x2 Average(params Matrix2x2[] vals) => Sum(vals) / vals.Length;

View File

@ -225,6 +225,34 @@ public record class Matrix3x3 : IStaticMatrix<Matrix3x3>
} }
} }
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) => public static Matrix3x3 Absolute(Matrix3x3 val) =>
new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3), new(Mathf.Absolute(val.r1c1), Mathf.Absolute(val.r1c2), Mathf.Absolute(val.r1c3),
Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r2c3), Mathf.Absolute(val.r2c1), Mathf.Absolute(val.r2c2), Mathf.Absolute(val.r2c3),

View File

@ -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<float> fill) : this(fill(0), fill(1), fill(2),
fill(3), fill(4), fill(5), fill(6), fill(7), fill(8)) { }
public ProjectionMatrix(Fill<int> 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<float> 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<int> 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<Float3> fill) : this(fill(0), fill(1), fill(2)) { }
public ProjectionMatrix(Fill<Int3> fill) : this((IEnumerable<int>)fill(0), fill(1), fill(2)) { }
public ProjectionMatrix(IEnumerable<float> r1, IEnumerable<float> r2, IEnumerable<float> r3)
: this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { }
public ProjectionMatrix(IEnumerable<int> r1, IEnumerable<int> r2, IEnumerable<int> r3)
: this(r1.ToFill(), r2.ToFill(), r3.ToFill()) { }
public ProjectionMatrix(Fill<float> r1, Fill<float> r2, Fill<float> r3)
: this(r1(0), r1(1), r1(2), r2(0), r2(1), r2(2), r3(0), r3(1), r3(2)) { }
public ProjectionMatrix(Fill<int> r1, Fill<int> r2, Fill<int> 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<Float3> Project(Fill<Float3> toProject) => i => this * toProject(i);
}

View File

@ -50,7 +50,7 @@ public record struct Vector2d : IAbsolute<Vector2d>, IAverage<Vector2d>,
return new(val.theta, mag); return new(val.theta, mag);
} }
public static Vector3d Cross(Vector2d a, Vector2d b, bool normalized = false) => 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(Vector2d a, Vector2d b) => Float2.Dot(a.ToXYZ(), b.ToXYZ());
public static float Dot(params Vector2d[] vals) public static float Dot(params Vector2d[] vals)
{ {

View File

@ -2,7 +2,7 @@
public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Float2, Int2>, public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Float2, Int2>,
IClamp<Float2>, IClampMagnitude<Float2, float>, IComparable<Float2>, IClamp<Float2>, IClampMagnitude<Float2, float>, IComparable<Float2>,
ICross<Float2, Float3>, IDivide<Float2>, IDot<Float2, float>, IEquatable<Float2>, ICross<Float2, float>, IDivide<Float2>, IDot<Float2, float>, IEquatable<Float2>,
IFloor<Float2, Int2>, IFromTuple<Float2, (float x, float y)>, IGroup<float>, IFloor<Float2, Int2>, IFromTuple<Float2, (float x, float y)>, IGroup<float>,
ILerp<Float2, float>, IMathOperators<Float2>, IMax<Float2>, IMedian<Float2>, IMin<Float2>, ILerp<Float2, float>, IMathOperators<Float2>, IMax<Float2>, IMedian<Float2>, IMin<Float2>,
IIndexAll<float>, IIndexRangeAll<float>, IPresets2d<Float2>, IProduct<Float2>, IRound<Float2, Int2>, IIndexAll<float>, IIndexRangeAll<float>, IPresets2d<Float2>, IProduct<Float2>, IRound<Float2, Int2>,
@ -96,8 +96,8 @@ public record struct Float2 : IAbsolute<Float2>, IAverage<Float2>, ICeiling<Floa
else if (mag > maxMag) val *= maxMag; else if (mag > maxMag) val *= maxMag;
return val; return val;
} }
public static Float3 Cross(Float2 a, Float2 b, bool normalized = false) => public static float Cross(Float2 a, Float2 b, bool normalized = false) =>
Float3.Cross(a, b, normalized); Float3.Cross(a, b, normalized).z;
public static Float2 Divide(Float2 num, params Float2[] vals) => num / Product(vals); 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(Float2 a, Float2 b) => a.x * b.x + a.y * b.y;
public static float Dot(params Float2[] vals) public static float Dot(params Float2[] vals)

View File

@ -208,18 +208,21 @@ public class Triangle : IClosestTo<Float3>, IContains<Float3>, IContainsPartial<
} }
public override int GetHashCode() => base.GetHashCode(); 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), Triangle pab = (point, a, b),
pbc = (point, b, c), pbc = (point, b, c),
pca = (point, c, a); 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) => public bool Contains(Line line) => Contains(line, 0.05f);
Contains(line.a) && Contains(line.b); public bool Contains(Line line, float tolerance) =>
Contains(line.a, tolerance) && Contains(line.b, tolerance);
public bool ContainsPartially(Line line) => public bool ContainsPartially(Line line) => ContainsPartially(line, 0.05f);
Contains(line.a) || Contains(line.b); public bool ContainsPartially(Line line, float tolerance) =>
Contains(line.a, tolerance) || Contains(line.b, tolerance);
public Float3[] GetAllVerts() => new[] { a, b, c }; public Float3[] GetAllVerts() => new[] { a, b, c };

View File

@ -66,4 +66,9 @@ Anyway, that's everything in this update. Again, pretty small, but meaningful no
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="Emgu.CV" Version="4.7.0.5276" />
<PackageReference Include="Emgu.CV.runtime.windows" Version="4.7.0.5276" />
</ItemGroup>
</Project> </Project>