diff --git a/Curve/CubicBezierCurve2D.cs b/Curve/CubicBezierCurve2D.cs index 9f3f710..9360a9c 100644 --- a/Curve/CubicBezierCurve2D.cs +++ b/Curve/CubicBezierCurve2D.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; using MoonTools.Core.Curve.Extensions; @@ -6,45 +7,48 @@ namespace MoonTools.Core.Curve /// /// A 2-dimensional Bezier curve defined by 4 points. /// - public struct CubicBezierCurve2D + public struct CubicBezierCurve2D : IEquatable { /// /// The start point. /// - public Vector2 p0; + public Vector2 P0 { get; } /// /// The first control point. /// - public Vector2 p1; + public Vector2 P1 { get; } /// /// The second control point. /// - public Vector2 p2; + public Vector2 P2 { get; } /// /// The end point. /// - public Vector2 p3; + public Vector2 P3 { get; } + /// + /// A representation of a 2D cubic Bezier curve. + /// /// The start point. /// The first control point. /// The second control point. /// The end point. public CubicBezierCurve2D(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) { - this.p0 = p0; - this.p1 = p1; - this.p2 = p2; - this.p3 = p3; + P0 = p0; + P1 = p1; + P2 = p2; + P3 = p3; } /// /// Returns the curve coordinate given by t. /// /// A value between 0 and 1. - public Vector2 Point(float t) => Point(p0, p1, p2, p3, t); + public Vector2 Point(float t) => Point(P0, P1, P2, P3, t); /// /// Returns the curve coordinate given by a normalized time value. @@ -52,13 +56,13 @@ namespace MoonTools.Core.Curve /// A value between startTime and endTime. /// /// - public Vector2 Point(float t, float startTime, float endTime) => Point(p0, p1, p2, p3, t, startTime, endTime); + public Vector2 Point(float t, float startTime, float endTime) => Point(P0, P1, P2, P3, t, startTime, endTime); /// /// Returns the instantaneous velocity on the curve given by t. /// /// A value between 0 and 1. - public Vector2 Velocity(float t) => Velocity(p0, p1, p2, p3, t); + public Vector2 Velocity(float t) => Velocity(P0, P1, P2, P3, t); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. @@ -66,7 +70,7 @@ namespace MoonTools.Core.Curve /// A value between startTime and endTime. /// /// - public Vector2 Velocity(float t, float startTime, float endTime) => Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, startTime, endTime)); + public Vector2 Velocity(float t, float startTime, float endTime) => Velocity(P0, P1, P2, P3, TimeHelper.Normalized(t, startTime, endTime)); /// /// Returns the curve coordinate given by 4 points and a time value. @@ -128,12 +132,40 @@ namespace MoonTools.Core.Curve /// The first control point. /// The second control point. /// The end point. - /// A value between startTime and endTime. - /// - /// + /// A value between minT and maxT. + /// The starting time value. + /// The ending time value. public static Vector2 Velocity(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t, float minT, float maxT) { return Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, minT, maxT)); } + + public override bool Equals(object obj) + { + return obj is CubicBezierCurve2D d && Equals(d); + } + + public bool Equals(CubicBezierCurve2D other) + { + return P0.Equals(other.P0) && + P1.Equals(other.P1) && + P2.Equals(other.P2) && + P3.Equals(other.P3); + } + + public override int GetHashCode() + { + return HashCode.Combine(P0, P1, P2, P3); + } + + public static bool operator ==(CubicBezierCurve2D left, CubicBezierCurve2D right) + { + return left.Equals(right); + } + + public static bool operator !=(CubicBezierCurve2D left, CubicBezierCurve2D right) + { + return !(left == right); + } } } \ No newline at end of file diff --git a/Curve/CubicBezierCurve3D.cs b/Curve/CubicBezierCurve3D.cs index 4bc27af..cc3b328 100644 --- a/Curve/CubicBezierCurve3D.cs +++ b/Curve/CubicBezierCurve3D.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; namespace MoonTools.Core.Curve @@ -5,45 +6,48 @@ namespace MoonTools.Core.Curve /// /// A 3-dimensional Bezier curve defined by 4 points. /// - public struct CubicBezierCurve3D + public struct CubicBezierCurve3D : IEquatable { /// /// The start point. /// - public Vector3 p0; + public Vector3 P0 { get; } /// /// The first control point. /// - public Vector3 p1; + public Vector3 P1 { get; } /// /// The second control point. /// - public Vector3 p2; + public Vector3 P2 { get; } /// /// The end point. /// - public Vector3 p3; + public Vector3 P3 { get; } + /// + /// A representation of a 3D cubic Bezier curve. + /// /// The start point. /// The first control point. /// The second control point. /// The end point. public CubicBezierCurve3D(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { - this.p0 = p0; - this.p1 = p1; - this.p2 = p2; - this.p3 = p3; + P0 = p0; + P1 = p1; + P2 = p2; + P3 = p3; } /// /// Returns the curve coordinate given by t. /// /// A value between 0 and 1. - public Vector3 Point(float t) => Point(p0, p1, p2, p3, t); + public Vector3 Point(float t) => Point(P0, P1, P2, P3, t); /// /// Returns the curve coordinate given by a normalized time value. @@ -51,13 +55,13 @@ namespace MoonTools.Core.Curve /// /// /// - public Vector3 Point(float t, float startTime, float endTime) => Point(p0, p1, p2, p3, t, startTime, endTime); + public Vector3 Point(float t, float startTime, float endTime) => Point(P0, P1, P2, P3, t, startTime, endTime); /// /// Returns the instantaneous velocity on the curve given by t. /// /// A value between 0 and 1. - public Vector3 Velocity(float t) => Velocity(p0, p1, p2, p3, t); + public Vector3 Velocity(float t) => Velocity(P0, P1, P2, P3, t); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. @@ -65,7 +69,7 @@ namespace MoonTools.Core.Curve /// A value between 0 and 1. /// /// - public Vector3 Velocity(float t, float startTime, float endTime) => Velocity(p0, p1, p2, p3, t, startTime, endTime); + public Vector3 Velocity(float t, float startTime, float endTime) => Velocity(P0, P1, P2, P3, t, startTime, endTime); /// /// Returns the curve coordinate given by 4 points and a time value. @@ -79,10 +83,10 @@ namespace MoonTools.Core.Curve { ArgumentChecker.CheckT(t); - return (1f - t) * (1f - t) * (1f - t) * p0 + - 3f * (1f - t) * (1f - t) * t * p1 + - 3f * (1f - t) * t * t * p2 + - t * t * t * p3; + return ((1f - t) * (1f - t) * (1f - t) * p0) + + (3f * (1f - t) * (1f - t) * t * p1) + + (3f * (1f - t) * t * t * p2) + + (t * t * t * p3); } /// @@ -113,9 +117,9 @@ namespace MoonTools.Core.Curve { ArgumentChecker.CheckT(t); - return 3f * (1f - t) * (1f - t) * (p1 - p0) + - 6f * (1f - t) * t * (p2 - p1) + - 3f * t * t * (p3 - p2); + return (3f * (1f - t) * (1f - t) * (p1 - p0)) + + (6f * (1f - t) * t * (p2 - p1)) + + (3f * t * t * (p3 - p2)); } /// @@ -128,11 +132,38 @@ namespace MoonTools.Core.Curve /// A value between startTime and endTime. /// /// - /// public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float startTime, float endTime) { ArgumentChecker.CheckT(t, startTime, endTime); return Velocity(p0, p1, p2, p3, TimeHelper.Normalized(t, startTime, endTime)); } + + public override bool Equals(object obj) + { + return obj is CubicBezierCurve3D d && Equals(d); + } + + public bool Equals(CubicBezierCurve3D other) + { + return P0.Equals(other.P0) && + P1.Equals(other.P1) && + P2.Equals(other.P2) && + P3.Equals(other.P3); + } + + public override int GetHashCode() + { + return HashCode.Combine(P0, P1, P2, P3); + } + + public static bool operator ==(CubicBezierCurve3D left, CubicBezierCurve3D right) + { + return left.Equals(right); + } + + public static bool operator !=(CubicBezierCurve3D left, CubicBezierCurve3D right) + { + return !(left == right); + } } } \ No newline at end of file diff --git a/Curve/Curve.csproj b/Curve/Curve.csproj index 1481de9..e21c213 100644 --- a/Curve/Curve.csproj +++ b/Curve/Curve.csproj @@ -1,4 +1,4 @@ - + 1.0.1 netstandard2.1 @@ -14,4 +14,10 @@ LGPL-3.0-only https://github.com/MoonsideGames/MoonTools.Core.Curve + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + \ No newline at end of file diff --git a/Curve/QuadraticBezierCurve2D.cs b/Curve/QuadraticBezierCurve2D.cs index 42aff34..9816dcf 100644 --- a/Curve/QuadraticBezierCurve2D.cs +++ b/Curve/QuadraticBezierCurve2D.cs @@ -1,43 +1,47 @@ -using System.Numerics; using MoonTools.Core.Curve.Extensions; +using System; +using System.Numerics; namespace MoonTools.Core.Curve { /// /// A 2-dimensional Bezier curve defined by 3 points. /// - public struct QuadraticBezierCurve2D + public struct QuadraticBezierCurve2D : IEquatable { /// /// The start point. /// - public Vector2 p0; + public Vector2 P0 { get; } /// /// The control point. /// - public Vector2 p1; + public Vector2 P1 { get; } /// /// The end point. /// - public Vector2 p2; + public Vector2 P2 { get; } + /// + /// A representation of a 2D quadratic Bezier curve. + /// /// The start point. /// The control point. /// The end point. public QuadraticBezierCurve2D(Vector2 p0, Vector2 p1, Vector2 p2) { - this.p0 = p0; - this.p1 = p1; - this.p2 = p2; + P0 = p0; + P1 = p1; + P2 = p2; } /// /// Returns the curve coordinate given by t. /// /// A value between 0 and 1. - public Vector2 Point(float t) => Point(p0, p1, p2, t); + public Vector2 Point(float t) => Point(P0, P1, P2, t); /// /// Returns the curve coordinate given by a normalized time value. @@ -45,13 +49,13 @@ namespace MoonTools.Core.Curve /// A time value between startTime and endTime. /// /// - public Vector2 Point(float t, float startTime, float endTime) => Point(p0, p1, p2, t, startTime, endTime); + public Vector2 Point(float t, float startTime, float endTime) => Point(P0, P1, P2, t, startTime, endTime); /// /// Returns the instantaneous velocity on the curve given by t. /// /// A value between 0 and 1. - public Vector2 Velocity(float t) => Velocity(p0, p1, p2, t); + public Vector2 Velocity(float t) => Velocity(P0, P1, P2, t); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. @@ -59,14 +63,14 @@ namespace MoonTools.Core.Curve /// A value between startTime and endTime. /// /// - public Vector2 Velocity(float t, float startTime, float endTime) => Velocity(p0, p1, p2, t, startTime, endTime); + public Vector2 Velocity(float t, float startTime, float endTime) => Velocity(P0, P1, P2, t, startTime, endTime); /// /// Performs degree elevation on the curve to turn it into a Cubic Bezier curve. /// public CubicBezierCurve2D AsCubic() { - var (p0, p1, p2, p3) = AsCubic(this.p0, this.p1, this.p2); + var (p0, p1, p2, p3) = AsCubic(this.P0, this.P1, this.P2); return new CubicBezierCurve2D(p0, p1, p2, p3); } @@ -144,5 +148,32 @@ namespace MoonTools.Core.Curve { return Velocity(p0, p1, p2, TimeHelper.Normalized(t, startTime, endTime)); } + + public override bool Equals(object obj) + { + return obj is QuadraticBezierCurve2D d && Equals(d); + } + + public bool Equals(QuadraticBezierCurve2D other) + { + return P0.Equals(other.P0) && + P1.Equals(other.P1) && + P2.Equals(other.P2); + } + + public override int GetHashCode() + { + return HashCode.Combine(P0, P1, P2); + } + + public static bool operator ==(QuadraticBezierCurve2D left, QuadraticBezierCurve2D right) + { + return left.Equals(right); + } + + public static bool operator !=(QuadraticBezierCurve2D left, QuadraticBezierCurve2D right) + { + return !(left == right); + } } } \ No newline at end of file diff --git a/Curve/QuadraticBezierCurve3D.cs b/Curve/QuadraticBezierCurve3D.cs index 98b85aa..d95c538 100644 --- a/Curve/QuadraticBezierCurve3D.cs +++ b/Curve/QuadraticBezierCurve3D.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; namespace MoonTools.Core.Curve @@ -5,38 +6,41 @@ namespace MoonTools.Core.Curve /// /// A 3-dimensional Bezier curve defined by 3 points. /// - public struct QuadraticBezierCurve3D + public struct QuadraticBezierCurve3D : IEquatable { /// /// The start point. /// - public Vector3 p0; + public Vector3 P0 { get; } /// /// The control point. /// - public Vector3 p1; + public Vector3 P1 { get; } /// /// The end point. /// - public Vector3 p2; + public Vector3 P2 { get; } + /// + /// A representation of a 3D quadratic Bezier curve. + /// /// The start point. /// The control point. /// The end point. public QuadraticBezierCurve3D(Vector3 p0, Vector3 p1, Vector3 p2) { - this.p0 = p0; - this.p1 = p1; - this.p2 = p2; + this.P0 = p0; + this.P1 = p1; + this.P2 = p2; } /// /// Returns the curve coordinate given by t. /// /// A value between 0 and 1. - public Vector3 Point(float t) => Point(p0, p1, p2, t); + public Vector3 Point(float t) => Point(P0, P1, P2, t); /// /// Returns the curve coordinate given by a normalized time value. @@ -44,13 +48,13 @@ namespace MoonTools.Core.Curve /// A time value between startTime and endTime. /// /// - public Vector3 Point(float t, float startTime, float endTime) => Point(p0, p1, p2, t, startTime, endTime); + public Vector3 Point(float t, float startTime, float endTime) => Point(P0, P1, P2, t, startTime, endTime); /// /// Returns the instantaneous velocity on the curve given by t. /// /// A value between 0 and 1. - public Vector3 Velocity(float t) => Velocity(p0, p1, p2, t); + public Vector3 Velocity(float t) => Velocity(P0, P1, P2, t); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. @@ -58,7 +62,7 @@ namespace MoonTools.Core.Curve /// An arbitrary value between startTime and endTime. /// /// - public Vector3 Velocity(float t, float startTime, float endTime) => Velocity(p0, p1, p2, t, startTime, endTime); + public Vector3 Velocity(float t, float startTime, float endTime) => Velocity(P0, P1, P2, t, startTime, endTime); /// /// Performs degree elevation on the curve to turn it into a Cubic Bezier curve. @@ -66,7 +70,7 @@ namespace MoonTools.Core.Curve /// The same curve expressed as a cubic curve. public CubicBezierCurve3D AsCubic() { - var (p0, p1, p2, p3) = AsCubic(this.p0, this.p1, this.p2); + var (p0, p1, p2, p3) = AsCubic(this.P0, this.P1, this.P2); return new CubicBezierCurve3D(p0, p1, p2, p3); } @@ -138,5 +142,32 @@ namespace MoonTools.Core.Curve var (cubicP0, cubicP1, cubicP2, cubicP3) = AsCubic(p0, p1, p2); return CubicBezierCurve3D.Velocity(cubicP0, cubicP1, cubicP2, cubicP3, t, startTime, endTime); } + + public override bool Equals(object obj) + { + return obj is QuadraticBezierCurve3D d && Equals(d); + } + + public bool Equals(QuadraticBezierCurve3D other) + { + return P0.Equals(other.P0) && + P1.Equals(other.P1) && + P2.Equals(other.P2); + } + + public override int GetHashCode() + { + return HashCode.Combine(P0, P1, P2); + } + + public static bool operator ==(QuadraticBezierCurve3D left, QuadraticBezierCurve3D right) + { + return left.Equals(right); + } + + public static bool operator !=(QuadraticBezierCurve3D left, QuadraticBezierCurve3D right) + { + return !(left == right); + } } } \ No newline at end of file diff --git a/Curve/TimeHelper.cs b/Curve/TimeHelper.cs index a0f6757..13d5404 100644 --- a/Curve/TimeHelper.cs +++ b/Curve/TimeHelper.cs @@ -2,6 +2,6 @@ namespace MoonTools.Core.Curve { public static class TimeHelper { - public static float Normalized(float t, float minT, float maxT) => ((t - minT)) / (maxT - minT); + public static float Normalized(float t, float minT, float maxT) => (t - minT) / (maxT - minT); } } \ No newline at end of file diff --git a/Test/CubicBezierCurve2D.cs b/Test/CubicBezierCurve2D.cs index 9c7a38e..5724f58 100644 --- a/Test/CubicBezierCurve2D.cs +++ b/Test/CubicBezierCurve2D.cs @@ -144,5 +144,45 @@ namespace Tests myCurve.Invoking(x => x.Velocity(15, 2, 5)).Should().Throw(); } + + [Test] + public void Equals() + { + var myCurve = new CubicBezierCurve2D( + new Vector2(-4, -4), + new Vector2(-2, 4), + new Vector2(2, -4), + new Vector2(4, 4) + ); + + var otherCurve = new CubicBezierCurve2D( + new Vector2(-4, -4), + new Vector2(-2, 4), + new Vector2(2, -4), + new Vector2(4, 4) + ); + + (myCurve == otherCurve).Should().BeTrue(); + } + + [Test] + public void NotEquals() + { + var myCurve = new CubicBezierCurve2D( + new Vector2(-9, -4), + new Vector2(-2, 4), + new Vector2(2, -4), + new Vector2(4, 4) + ); + + var otherCurve = new CubicBezierCurve2D( + new Vector2(-4, -4), + new Vector2(-2, 4), + new Vector2(2, -4), + new Vector2(4, 4) + ); + + (myCurve != otherCurve).Should().BeTrue(); + } } } \ No newline at end of file diff --git a/Test/CubicBezierCurve3D.cs b/Test/CubicBezierCurve3D.cs index 2033def..5971d79 100644 --- a/Test/CubicBezierCurve3D.cs +++ b/Test/CubicBezierCurve3D.cs @@ -91,11 +91,11 @@ namespace Tests new Vector3(4, 4, 0) ); - myCurve.Point(0f).Should().BeEquivalentTo(myCurve.p0); + myCurve.Point(0f).Should().BeEquivalentTo(myCurve.P0); myCurve.Point(0.5f).Should().BeEquivalentTo(new Vector3(0, 0, 0.75f)); myCurve.Point(0.25f).Should().BeEquivalentTo(new Vector3(-2.1875f, -0.5f, -0.84375f)); myCurve.Point(0.75f).Should().BeEquivalentTo(new Vector3(2.1875f, 0.5f, 1.21875f)); - myCurve.Point(1f).Should().BeEquivalentTo(myCurve.p3); + myCurve.Point(1f).Should().BeEquivalentTo(myCurve.P3); myCurve.Invoking(x => x.Point(1.5f)).Should().Throw(); } @@ -110,11 +110,11 @@ namespace Tests new Vector3(4, 4, 0) ); - myCurve.Point(15, 15, 17).Should().BeEquivalentTo(myCurve.p0); + myCurve.Point(15, 15, 17).Should().BeEquivalentTo(myCurve.P0); myCurve.Point(3, 2, 4).Should().BeEquivalentTo(new Vector3(0, 0, 0.75f)); myCurve.Point(2, 1, 5).Should().BeEquivalentTo(new Vector3(-2.1875f, -0.5f, -0.84375f)); myCurve.Point(11, 2, 14).Should().BeEquivalentTo(new Vector3(2.1875f, 0.5f, 1.21875f)); - myCurve.Point(1, -8, 1).Should().BeEquivalentTo(myCurve.p3); + myCurve.Point(1, -8, 1).Should().BeEquivalentTo(myCurve.P3); myCurve.Invoking(x => x.Point(15, 2, 5)).Should().Throw(); } @@ -152,5 +152,45 @@ namespace Tests myCurve.Invoking(x => x.Velocity(15, 2, 5)).Should().Throw(); } + + [Test] + public void Equals() + { + var myCurve = new CubicBezierCurve3D( + new Vector3(-4, -4, -3), + new Vector3(-2, 4, 0), + new Vector3(2, -4, 3), + new Vector3(4, 4, 0) + ); + + var otherCurve = new CubicBezierCurve3D( + new Vector3(-4, -4, -3), + new Vector3(-2, 4, 0), + new Vector3(2, -4, 3), + new Vector3(4, 4, 0) + ); + + (myCurve == otherCurve).Should().BeTrue(); + } + + [Test] + public void NotEquals() + { + var myCurve = new CubicBezierCurve3D( + new Vector3(-1, -4, -3), + new Vector3(-2, 4, 0), + new Vector3(2, -4, 3), + new Vector3(4, 4, 0) + ); + + var otherCurve = new CubicBezierCurve3D( + new Vector3(-4, -4, -3), + new Vector3(-2, 4, 0), + new Vector3(2, -4, 3), + new Vector3(4, 4, 0) + ); + + (myCurve != otherCurve).Should().BeTrue(); + } } } \ No newline at end of file diff --git a/Test/QuadraticBezierCurve2D.cs b/Test/QuadraticBezierCurve2D.cs index 6487de2..3b14d04 100644 --- a/Test/QuadraticBezierCurve2D.cs +++ b/Test/QuadraticBezierCurve2D.cs @@ -151,5 +151,33 @@ namespace Tests myCurve.Point(0.75f).Should().BeEquivalentTo(myCubicCurve.Point(0.75f)); myCurve.Point(1f).Should().BeEquivalentTo(myCubicCurve.Point(1f)); } + + [Test] + public void Equals() + { + var p0 = new Vector2(-4, -4); + var p1 = new Vector2(2, -4); + var p2 = new Vector2(4, 4); + + var myCurve = new QuadraticBezierCurve2D(p0, p1, p2); + + var otherCurve = new QuadraticBezierCurve2D(p0, p1, p2); + + (myCurve == otherCurve).Should().BeTrue(); + } + + [Test] + public void NotEquals() + { + var p0 = new Vector2(-4, -4); + var p1 = new Vector2(2, -4); + var p2 = new Vector2(4, 4); + + var myCurve = new QuadraticBezierCurve2D(p0, p1, p2); + + var otherCurve = new QuadraticBezierCurve2D(new Vector2(0, 1), p1, p2); + + (myCurve != otherCurve).Should().BeTrue(); + } } } \ No newline at end of file diff --git a/Test/QuadraticBezierCurve3D.cs b/Test/QuadraticBezierCurve3D.cs index 2fec1a7..0d2109f 100644 --- a/Test/QuadraticBezierCurve3D.cs +++ b/Test/QuadraticBezierCurve3D.cs @@ -151,5 +151,31 @@ namespace Tests myCurve.Point(0.75f).Should().BeEquivalentTo(myCubicCurve.Point(0.75f)); myCurve.Point(1f).Should().BeEquivalentTo(myCubicCurve.Point(1f)); } + + [Test] + public void Equals() + { + var p0 = new Vector3(-4, -4, -3); + var p1 = new Vector3(2, -4, 3); + var p2 = new Vector3(4, 4, 0); + + var myCurve = new QuadraticBezierCurve3D(p0, p1, p2); + var otherCurve = new QuadraticBezierCurve3D(p0, p1, p2); + + (myCurve == otherCurve).Should().BeTrue(); + } + + [Test] + public void NotEquals() + { + var p0 = new Vector3(-4, -4, -3); + var p1 = new Vector3(2, -4, 3); + var p2 = new Vector3(4, 4, 0); + + var myCurve = new QuadraticBezierCurve3D(p0, p1, p2); + var otherCurve = new QuadraticBezierCurve3D(new Vector3(0, -4, -3), p1, p2); + + (myCurve != otherCurve).Should().BeTrue(); + } } } \ No newline at end of file