using OpenTK.Mathematics; using System; using System.Diagnostics; namespace Dashboard { /// /// A bezier curve segment. /// [DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")] public struct QBezier { /// /// Segment start point. /// public Vector2 Start; /// /// Start point control point. /// public Vector2 ControlA; /// /// End point control point. /// public Vector2 ControlB; /// /// Segment end point. /// public Vector2 End; /// /// An approximation of the arc length of the bezier curve, for calculating rasterization resolution. /// public float RasterizationArc => 0.5f * (End - Start).Length + 0.5f * ((ControlA - Start).Length + (ControlB - ControlA).Length + (End - ControlB).Length); public QBezier(Vector2 start, Vector2 controlA, Vector2 controlB, Vector2 end) { Start = start; ControlA = controlA; ControlB = controlB; End = end; } public QBezier( float startX, float startY, float controlAx, float controlAy, float controlBx, float controlBy, float endX, float endY) : this( new Vector2(startX, startY), new Vector2(controlAx, controlAy), new Vector2(controlBx, controlBy), new Vector2(endX, endY)) { } /// /// Get a point in the curve segment. /// /// Control parameter (between 0 and 1) /// The point on the curve. public Vector2 GetBezierPoint(float t) { float T = 1 - t; return T * T * T * Start + 3 * T * T * t * ControlA + 3 * T * t * t * ControlB + t * t * t * End; } /// /// Get the tangent on the curve. /// /// Control parameter (between 0 and 1) /// The tangent curve. public Vector2 GetBezierTangent(float t) { float T = 1 - t; return ( 3 * T * T * (ControlA - Start) + 6 * T * t * (ControlB - ControlA) + 3 * t * t * (End - ControlB) ).Normalized(); } internal Vector2 GetBezierNormal(float t) { Vector2 tangent = GetBezierTangent(t); return new Vector2(-tangent.Y, tangent.X); } } /// /// A line segment. /// [DebuggerDisplay("{Start} -- {End}")] public struct QLine { /// /// Start point. /// public Vector2 Start; /// /// End point. /// public Vector2 End; public QLine(Vector2 start, Vector2 end) { Start = start; End = end; } public QLine(float startX, float startY, float endX, float endY) { Start.X = startX; Start.Y = startY; End.X = endX; End.Y = endY; } public Vector2 Normal() { Vector2 tangent = Tangent(); return new Vector2(-tangent.Y, tangent.X); } public Vector2 Tangent() { return (End - Start).Normalized(); } } /// /// A rectangle. /// [DebuggerDisplay("({Left}, {Top}, {Right}, {Bottom})")] public struct QRectangle { /// /// Position maximum point. /// public Vector2 Max; /// /// Position minimum point. /// public Vector2 Min; public float Left { get => Min.X; set => Min.X = value; } public float Right { get => Max.X; set => Max.X = value; } public float Top { get => Min.Y; set => Min.Y = value; } public float Bottom { get => Max.Y; set => Max.Y = value; } public Vector2 Size { get => Max - Min; set => Max = Min + value; } public QRectangle(Vector2 max, Vector2 min) { Max = max; Min = min; } public QRectangle(float r, float b, float l, float t) { Max = new Vector2(r, b); Min = new Vector2(l, t); } public bool Contains(Vector2 point) { return point.X > Left && point.X < Right && point.Y > Bottom && point.Y < Top; } internal void Translate(in Vector2 offset) { Min += offset; Max += offset; } public static QRectangle Intersect(in QRectangle a, in QRectangle b) => new QRectangle( Math.Max(a.Right, b.Right), Math.Max(a.Bottom, b.Bottom) , Math.Min(a.Left, b.Left), Math.Min(a.Top, b.Top)); } /// /// An ellipse. /// /// It is undefined to have an ellipse with non-orthogonal axes. [DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")] public struct QEllipse { /// /// Ellipse center point. /// public Vector2 Center; /// /// First ellipse axis. /// public Vector2 AxisA; /// /// Second ellipse axis. /// public Vector2 AxisB; } /// /// A triangle. /// [DebuggerDisplay("{A} -- {B} -- {C}")] public struct QTriangle { /// /// First vertex. /// public Vector2 A; /// /// Second vertex. /// public Vector2 B; /// /// Third vertex. /// public Vector2 C; } }