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;
}
}