using System; using System.Numerics; namespace MoonTools.Curve { /// /// A 3-dimensional Bezier curve defined by 3 points. /// public struct QuadraticBezierCurve3D : IEquatable { /// /// The start point. /// public Vector3 P0 { get; } /// /// The control point. /// public Vector3 P1 { get; } /// /// The end point. /// 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; } /// /// Returns the curve coordinate given by t. /// /// A value between 0 and 1. public Vector3 Point(float t) => Point(P0, P1, P2, t); /// /// Returns the curve coordinate given by a normalized time value. /// /// A time value between startTime and 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); /// /// Returns the instantaneous velocity on the curve given by a normalized time value. /// /// An arbitrary value between startTime and 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. /// /// The same curve expressed as a cubic curve. public CubicBezierCurve3D AsCubic() { var (p0, p1, p2, p3) = AsCubic(this.P0, this.P1, this.P2); return new CubicBezierCurve3D(p0, p1, p2, p3); } /// /// Given quadratic control points, returns cubic control points. /// public static (Vector3, Vector3, Vector3, Vector3) AsCubic(Vector3 p0, Vector3 p1, Vector3 p2) { var cubicP0 = p0; var cubicP1 = (2f / 3f * p1) + ((1f / 3f) * p0); var cubicP2 = (2f / 3f * p1) + ((1f / 3f) * p2); var cubicP3 = p2; return (cubicP0, cubicP1, cubicP2, cubicP3); } /// /// Returns the curve coordinate given by 3 points and a time value. /// /// The start point. /// The control point. /// The end point. /// A value between 0 and 1. public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, float t) { var (cubicP0, cubicP1, cubicP2, cubicP3) = AsCubic(p0, p1, p2); return CubicBezierCurve3D.Point(cubicP0, cubicP1, cubicP2, cubicP3, t); } /// /// Returns the curve coordinate given by 3 points and a normalized time value. /// /// The start point. /// The control point. /// The end point. /// A value between startTime and endTime. /// /// public static Vector3 Point(Vector3 p0, Vector3 p1, Vector3 p2, float t, float startTime, float endTime) { var (cubicP0, cubicP1, cubicP2, cubicP3) = AsCubic(p0, p1, p2); return CubicBezierCurve3D.Point(cubicP0, cubicP1, cubicP2, cubicP3, t, startTime, endTime); } /// /// Returns the instantaneous velocity given by 3 points and a normalized time value. /// /// The start point. /// The control point. /// The end point. /// A value between 0 and 1. public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, float t) { var (cubicP0, cubicP1, cubicP2, cubicP3) = AsCubic(p0, p1, p2); return CubicBezierCurve3D.Velocity(cubicP0, cubicP1, cubicP2, cubicP3, t); } /// /// Returns the instantaneous velocity given by 3 points and a normalized time value. /// /// The start point. /// The control point. /// The end point. /// A value between startTime and endTime. /// /// public static Vector3 Velocity(Vector3 p0, Vector3 p1, Vector3 p2, float t, float startTime, float endTime) { 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); } } }