Skip to content

Commit

Permalink
Updated math angle
Browse files Browse the repository at this point in the history
  • Loading branch information
Tornado-Technology committed Jul 12, 2024
1 parent 51b54c6 commit 761496b
Show file tree
Hide file tree
Showing 11 changed files with 215 additions and 17 deletions.
112 changes: 108 additions & 4 deletions Hypercube.Shared.Math/Angle.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,120 @@
using System.Runtime.CompilerServices;
using Hypercube.Shared.Math.Extensions;
using Hypercube.Shared.Math.Vector;

namespace Hypercube.Shared.Math;

public readonly struct Angle(double theta)
public readonly struct Angle : IEquatable<Angle>, IEquatable<double>
{
public static readonly Angle Zero = new(0);

public readonly double Theta;

public double Degrees
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Theta * HyperMath.RadiansToDegrees;
}

public Vector2 Vector
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => new((float)System.Math.Cos(Theta), (float)System.Math.Sin(Theta));
}

public Angle(double theta)
{
Theta = theta;
}

public Angle(Vector2 vector2)
{
vector2 = vector2.Normalized;
Theta = System.Math.Atan2(vector2.X, vector2.Y);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Angle other)
{
return Theta.AboutEquals(other.Theta);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(double other)
{
return Theta.AboutEquals(other);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj)
{
return (obj is double theta && Equals(theta)) ||
(obj is Angle angle && Equals(angle));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return Theta.GetHashCode();
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override string ToString()
{
return $"{Degrees} deg";
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Angle a, double b)
{
return a.Equals(b);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Angle a, double b)
{
return !a.Equals(b);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Angle a, Angle b)
{
return a.Equals(b);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Angle a, Angle b)
{
return !a.Equals(b);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator double(Angle angle)
{
return angle.Theta;
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Angle(double radians)
{
return new Angle(radians);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Angle(float radians)
{
return new Angle(radians);
}

public readonly double Theta = theta;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Angle FromDegrees(double degrees)
{
return new Angle(degrees * HyperMath.DegreesToRadians);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator float(Angle angle)
public static Angle FromDegrees(float degrees)
{
return (float)angle.Theta;
return new Angle(degrees * HyperMath.DegreesToRadians);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@

public static class FloatingPointEqualsExtension
{
public static bool AboutEquals(this double a, double b)
public static bool AboutEquals(this double a, double b, double tolerance = 1E-15d)
{
var epsilon = System.Math.Max(System.Math.Abs(a), System.Math.Abs(b)) * 1E-15d;
return System.Math.Abs(a - b) <= epsilon;
}

public static bool AboutEquals(this float a, float b)
public static bool AboutEquals(this float a, float b, float tolerance = 1E-15f)
{
var epsilon = System.Math.Max(System.Math.Abs(a), System.Math.Abs(b)) * 1E-15f;
var epsilon = System.Math.Max(System.Math.Abs(a), System.Math.Abs(b)) * tolerance ;
return System.Math.Abs(a - b) <= epsilon;
}
}
14 changes: 11 additions & 3 deletions Hypercube.Shared.Math/HyperMath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

public static class HyperMath
{
// ReSharper disable once InconsistentNaming
public const float PI = MathF.PI;
public const float PiOver2 = PI / 2;
public const double PI = System.Math.PI;

public const double PIOver2 = PI / 2;
public const double PIOver4 = PI / 4;
public const double PIOver6 = PI / 6;

public const double TwoPI = 2 * PI;
public const double ThreePiOver2 = 3 * PI / 2;

public const double RadiansToDegrees = 180 / PI;
public const double DegreesToRadians = PI / 180;
}
16 changes: 16 additions & 0 deletions Hypercube.Shared.Math/HyperMathF.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Hypercube.Shared.Math;

public static class HyperMathF
{
public const float PI = MathF.PI;

public const float PIOver2 = PI / 2;
public const float PIOver4 = PI / 4;
public const float PIOver6 = PI / 6;

public const float TwoPI = 2 * PI;
public const float ThreePiOver2 = 3 * PI / 2;

public const float RadiansToDegrees = 180 / PI;
public const float DegreesToRadians = PI / 180;
}
4 changes: 2 additions & 2 deletions Hypercube.Shared.Math/Quaternion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -215,15 +215,15 @@ public static Vector3 ToEuler(Quaternion quaternion)
// Singularity at north pole
return new Vector3(
0,
HyperMath.PiOver2,
HyperMathF.PIOver2,
2f * MathF.Atan2(quaternion.X, quaternion.W)
);

if (singularityTest < -SingularityThreshold * unit)
// Singularity at south pole
return new Vector3(
0,
-HyperMath.PiOver2,
-HyperMathF.PIOver2,
-2f * MathF.Atan2(quaternion.X, quaternion.W)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ public partial struct Transform2
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Transform3(Transform2 transform2)
{
return new Transform3(transform2.Position, new Quaternion(Vector3.UnitZ * transform2.Rotation), transform2.Scale);
return new Transform3(transform2.Position, new Quaternion(Vector3.UnitZ * (float)transform2.Rotation), transform2.Scale);
}
}
2 changes: 1 addition & 1 deletion Hypercube.Shared.Math/Transform/Transform2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ public Transform2 SetScale(Vector2 scale)
private void UpdateMatrix()
{
Matrix = Matrix4X4.CreateTranslation(Position) *
Matrix4X4.CreateRotationZ(Rotation) *
Matrix4X4.CreateRotationZ((float)Rotation) *
Matrix4X4.CreateScale(Scale);
}
}
10 changes: 9 additions & 1 deletion Hypercube.Shared.Math/Vector/Vector2.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Hypercube.Shared.Math.Extensions;

namespace Hypercube.Shared.Math.Vector;

Expand Down Expand Up @@ -33,6 +34,12 @@ public float Length
get => MathF.Sqrt(LengthSquared);
}

public Vector2 Normalized
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this / Length;
}

public Vector2(float x, float y)
{
X = x;
Expand Down Expand Up @@ -62,7 +69,8 @@ public Vector2 WithY(float value)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Vector2 other)
{
return X.Equals(other.X) && Y.Equals(other.Y);
return X.AboutEquals(other.X) &&
Y.AboutEquals(other.Y);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand Down
6 changes: 6 additions & 0 deletions Hypercube.Shared.Math/Vector/Vector2Int.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@ public float Length
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => MathF.Sqrt(LengthSquared);
}

public Vector2Int Normalized
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this / Length;
}

public Vector2Int(int x, int y)
{
Expand Down
53 changes: 53 additions & 0 deletions Hypercube.UnitTests/Math/AngleTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
using Hypercube.Shared.Math;
using Hypercube.Shared.Math.Vector;

namespace Hypercube.UnitTests.Math;

public static class AngleTest
{
[Test]
public static void Degrees()
{
Assert.Multiple(() =>
{
Assert.That(new Angle(HyperMath.PI).Degrees, Is.EqualTo(180d).Within(0.01d));
Assert.That(new Angle(HyperMath.PIOver2).Degrees, Is.EqualTo(90d).Within(0.01d));
Assert.That(new Angle(HyperMath.PIOver4).Degrees, Is.EqualTo(45d).Within(0.01d));
Assert.That(new Angle(HyperMath.PIOver6).Degrees, Is.EqualTo(30d).Within(0.01d));
Assert.That(Angle.FromDegrees(180d), Is.EqualTo(new Angle(HyperMath.PI)));
Assert.That(Angle.FromDegrees(90d), Is.EqualTo(new Angle(HyperMath.PIOver2)));
Assert.That(Angle.FromDegrees(45d), Is.EqualTo(new Angle(HyperMath.PIOver4)));
Assert.That(Angle.FromDegrees(30d), Is.EqualTo(new Angle(HyperMath.PIOver6)));
});
Assert.Pass($"{nameof(Angle)} degrees passed");
}

[Test]
public static void Vector()
{
Assert.Multiple(() =>
{
Assert.That(Angle.Zero.GetRoundVector(), Is.EqualTo(Vector2.UnitX));
Assert.That(new Angle(HyperMath.PI).GetRoundVector(), Is.EqualTo(-Vector2.UnitX));
Assert.That(new Angle(-HyperMath.PI).GetRoundVector(), Is.EqualTo(-Vector2.UnitX));
Assert.That(new Angle(HyperMath.PIOver2).GetRoundVector(), Is.EqualTo(Vector2.UnitY));
Assert.That(new Angle(HyperMath.ThreePiOver2).GetRoundVector(), Is.EqualTo(-Vector2.UnitY));
Assert.That(new Angle(-HyperMath.PIOver2).GetRoundVector(), Is.EqualTo(-Vector2.UnitY));
Assert.That(new Angle(HyperMath.PIOver4).GetRoundVector(), Is.EqualTo(Vector2.One.Normalized));
Assert.That(new Angle(HyperMath.ThreePiOver2 - HyperMath.PIOver4).GetRoundVector(), Is.EqualTo(-Vector2.One.Normalized));
});

Assert.Pass($"{nameof(Angle)} vector passed");
}

private static Vector2 GetRoundVector(this Angle angle)
{
var vector = angle.Vector;
var x = MathF.Abs(vector.X) < 1e-15f ? 0 : vector.X;
var y = MathF.Abs(vector.Y) < 1e-15f ? 0 : vector.Y;
return new Vector2(x, y);
}
}
7 changes: 5 additions & 2 deletions Hypercube.UnitTests/Math/FloatingPointTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ public class FloatingPointTest
[Test]
public void Equals()
{
Assert.That((0.1d + 0.2d).AboutEquals(0.3d));
Assert.That((0.1f + 0.2f).AboutEquals(0.3f));
Assert.Multiple(() =>
{
Assert.That((0.1d + 0.2d).AboutEquals(0.3d));
Assert.That((0.1f + 0.2f).AboutEquals(0.3f));
});

Assert.Pass($"{nameof(FloatingPointEqualsExtension)} passed");
}
Expand Down

0 comments on commit 761496b

Please sign in to comment.