using System; using System.Numerics; namespace MoonTools.Curve { /// /// A 3-dimensional Bezier curve defined by 4 points. /// public struct CubicBezierCurve3D : IEquatable, ICurve3D { /// /// The start point. /// public Vector3 P0 { get; } /// /// The first control point. /// public Vector3 P1 { get; } /// /// The second control point. /// public Vector3 P2 { get; } /// /// The end point. /// 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) { 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); /// /// Returns the curve coordinate given by a normalized time value. /// /// /// /// 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); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. /// /// A value between 0 and 1. /// /// 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. /// /// The start point. /// The first control point. /// The second control point. /// The end point. /// A value between 0 and 1. public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) { 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); } /// /// Returns the curve coordinate given by 4 points and a normalized time value. /// /// The start point. /// The first control point. /// The second control point. /// The end point. /// A value between startTime and endTime. /// /// public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t, float startTime, float endTime) { ArgumentChecker.CheckT(t, startTime, endTime); return Point(p0, p1, p2, p3, TimeHelper.Normalized(t, startTime, endTime)); } /// /// Returns the instantaneous velocity given by 4 points and a time value. /// /// The start point. /// The first control point. /// The second control point. /// The end point. /// A value between 0 and 1. public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) { ArgumentChecker.CheckT(t); return (3f * (1f - t) * (1f - t) * (p1 - p0)) + (6f * (1f - t) * t * (p2 - p1)) + (3f * t * t * (p3 - p2)); } /// /// Returns the instantaneous velocity given by 4 points and a normalized time value. /// /// The start point. /// The first control point. /// The second control point. /// The end point. /// 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); } } }