268 lines
6.6 KiB
C#
268 lines
6.6 KiB
C#
using OpenTK.Mathematics;
|
|
using System;
|
|
using System.Diagnostics;
|
|
|
|
namespace Dashboard
|
|
{
|
|
/// <summary>
|
|
/// A bezier curve segment.
|
|
/// </summary>
|
|
[DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")]
|
|
public struct QBezier
|
|
{
|
|
/// <summary>
|
|
/// Segment start point.
|
|
/// </summary>
|
|
public Vector2 Start;
|
|
|
|
/// <summary>
|
|
/// Start point control point.
|
|
/// </summary>
|
|
public Vector2 ControlA;
|
|
|
|
/// <summary>
|
|
/// End point control point.
|
|
/// </summary>
|
|
public Vector2 ControlB;
|
|
|
|
/// <summary>
|
|
/// Segment end point.
|
|
/// </summary>
|
|
public Vector2 End;
|
|
|
|
/// <summary>
|
|
/// An approximation of the arc length of the bezier curve, for calculating rasterization resolution.
|
|
/// </summary>
|
|
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))
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a point in the curve segment.
|
|
/// </summary>
|
|
/// <param name="t">Control parameter (between 0 and 1)</param>
|
|
/// <returns>The point on the curve.</returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the tangent on the curve.
|
|
/// </summary>
|
|
/// <param name="t">Control parameter (between 0 and 1)</param>
|
|
/// <returns>The tangent curve.</returns>
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A line segment.
|
|
/// </summary>
|
|
[DebuggerDisplay("{Start} -- {End}")]
|
|
public struct QLine
|
|
{
|
|
/// <summary>
|
|
/// Start point.
|
|
/// </summary>
|
|
public Vector2 Start;
|
|
|
|
/// <summary>
|
|
/// End point.
|
|
/// </summary>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// A rectangle.
|
|
/// </summary>
|
|
[DebuggerDisplay("({Left}, {Top}, {Right}, {Bottom})")]
|
|
public struct QRectangle
|
|
{
|
|
/// <summary>
|
|
/// Position maximum point.
|
|
/// </summary>
|
|
public Vector2 Max;
|
|
|
|
/// <summary>
|
|
/// Position minimum point.
|
|
/// </summary>
|
|
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));
|
|
}
|
|
|
|
/// <summary>
|
|
/// An ellipse.
|
|
/// </summary>
|
|
/// <remarks>It is undefined to have an ellipse with non-orthogonal axes.</remarks>
|
|
[DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")]
|
|
public struct QEllipse
|
|
{
|
|
/// <summary>
|
|
/// Ellipse center point.
|
|
/// </summary>
|
|
public Vector2 Center;
|
|
|
|
/// <summary>
|
|
/// First ellipse axis.
|
|
/// </summary>
|
|
public Vector2 AxisA;
|
|
|
|
/// <summary>
|
|
/// Second ellipse axis.
|
|
/// </summary>
|
|
public Vector2 AxisB;
|
|
}
|
|
|
|
/// <summary>
|
|
/// A triangle.
|
|
/// </summary>
|
|
[DebuggerDisplay("{A} -- {B} -- {C}")]
|
|
public struct QTriangle
|
|
{
|
|
/// <summary>
|
|
/// First vertex.
|
|
/// </summary>
|
|
public Vector2 A;
|
|
|
|
/// <summary>
|
|
/// Second vertex.
|
|
/// </summary>
|
|
public Vector2 B;
|
|
|
|
/// <summary>
|
|
/// Third vertex.
|
|
/// </summary>
|
|
public Vector2 C;
|
|
}
|
|
} |