using System; using System.Numerics; using MoonTools.Curve.Extensions; namespace MoonTools.Curve { /// <summary> /// A 2-dimensional Bezier curve defined by 4 points. /// </summary> public struct CubicBezierCurve2D : IEquatable<CubicBezierCurve2D> { /// <summary> /// The start point. /// </summary> public Vector2 P0 { get; } /// <summary> /// The first control point. /// </summary> public Vector2 P1 { get; } /// <summary> /// The second control point. /// </summary> public Vector2 P2 { get; } /// <summary> /// The end point. /// </summary> public Vector2 P3 { get; } /// <summary> /// A representation of a 2D cubic Bezier curve. /// </summary> /// <param name="p0">The start point.</param> /// <param name="p1">The first control point.</param> /// <param name="p2">The second control point.</param> /// <param name="p3">The end point.</param> public CubicBezierCurve2D(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3) { P0 = p0; P1 = p1; P2 = p2; P3 = p3; } /// <summary> /// Returns the curve coordinate given by t. /// </summary> /// <param name="t">A value between 0 and 1.</param> public Vector2 Point(float t) => Point(P0, P1, P2, P3, t); /// <summary> /// Returns the curve coordinate given by a normalized time value. /// </summary> /// <param name="t">A value between startTime and endTime.</param> /// <param name="startTime"></param> /// <param name="endTime"></param> public Vector2 Point(float t, float startTime, float endTime) => Point(P0, P1, P2, P3, t, startTime, endTime); /// <summary> /// Returns the instantaneous velocity on the curve given by t. /// </summary> /// <param name="t">A value between 0 and 1.</param> public Vector2 Velocity(float t) => Velocity(P0, P1, P2, P3, t); /// <summary> /// Returns the instantaneous velocity on the curve given by a normalized time value. /// </summary> /// <param name="t">A value between startTime and endTime.</param> /// <param name="startTime"></param> /// <param name="endTime"></param> public Vector2 Velocity(float t, float startTime, float endTime) => Velocity(P0, P1, P2, P3, TimeHelper.Normalized(t, startTime, endTime)); /// <summary> /// Returns the curve coordinate given by 4 points and a time value. /// </summary> /// <param name="p0">The start point.</param> /// <param name="p1">The first control point.</param> /// <param name="p2">The second control point.</param> /// <param name="p3">The end point.</param> /// <param name="t">A value between 0 and 1.</param> public static Vector2 Point(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t) { return CubicBezierCurve3D.Point( new Vector3(p0.X, p0.Y, 0), new Vector3(p1.X, p1.Y, 0), new Vector3(p2.X, p2.Y, 0), new Vector3(p3.X, p3.Y, 0), t ).XY(); } /// <summary> /// Returns the curve coordinate given by 4 points and a normalized time value. /// </summary> /// <param name="p0">The start point.</param> /// <param name="p1">The first control point.</param> /// <param name="p2">The second control point.</param> /// <param name="p3">The end point.</param> /// <param name="t">A value between startTime and endTime.</param> /// <param name="startTime"></param> /// <param name="endTime"></param> public static Vector2 Point(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t, float startTime, float endTime) { return Point(p0, p1, p2, p3, TimeHelper.Normalized(t, startTime, endTime)); } /// <summary> /// Returns the instantaneous velocity given by 4 points and a time value. /// </summary> /// <param name="p0">The start point.</param> /// <param name="p1">The first control point.</param> /// <param name="p2">The second control point.</param> /// <param name="p3">The end point.</param> /// <param name="t">A value between 0 and 1.</param> public static Vector2 Velocity(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t) { return CubicBezierCurve3D.Velocity( new Vector3(p0.X, p0.Y, 0), new Vector3(p1.X, p1.Y, 0), new Vector3(p2.X, p2.Y, 0), new Vector3(p3.X, p3.Y, 0), t ).XY(); } /// <summary> /// Returns the instantaneous velocity given by 4 points and a normalized time value. /// </summary> /// <param name="p0">The start point.</param> /// <param name="p1">The first control point.</param> /// <param name="p2">The second control point.</param> /// <param name="p3">The end point.</param> /// <param name="t">A value between minT and maxT.</param> /// <param name="minT">The starting time value.</param> /// <param name="maxT">The ending time value.</param> 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); } } }