Dashboard/Quik/QuikGeometry.cs

370 lines
9.0 KiB
C#

using System;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
namespace Quik
{
/// <summary>
/// A 2 dimensional Vector.
/// </summary>
[DebuggerDisplay("({X}, {Y})")]
public struct QuikVec2
{
public float X;
public float Y;
public float Magnitude => MathF.Sqrt(X * X + Y * Y);
public QuikVec2(float x, float y)
{
X = x;
Y = y;
}
public QuikVec2 Normalize() => this * (1.0f / Magnitude);
public float Atan2() => MathF.Atan2(Y, X);
public static QuikVec2 operator +(QuikVec2 a, QuikVec2 b)
{
return new QuikVec2()
{
X = a.X + b.X,
Y = a.Y + b.Y
};
}
public static QuikVec2 operator -(QuikVec2 a)
{
return new QuikVec2()
{
X = -a.X,
Y = -a.Y
};
}
public static QuikVec2 operator -(QuikVec2 a, QuikVec2 b)
{
return new QuikVec2()
{
X = a.X - b.X,
Y = a.Y - b.Y
};
}
public static QuikVec2 operator *(float a, QuikVec2 b)
{
return new QuikVec2()
{
X = a * b.X,
Y = a * b.Y
};
}
public static QuikVec2 operator *(QuikVec2 a, float b) => b * a;
public static bool operator ==(QuikVec2 a, QuikVec2 b) => a.X == b.X && a.Y == b.Y;
public static bool operator !=(QuikVec2 a, QuikVec2 b) => a.X != b.X || a.Y != b.Y;
public override bool Equals(object obj)
{
if (obj is QuikVec2)
{
return (QuikVec2) obj == this;
}
else
{
return false;
}
}
public override int GetHashCode()
{
return 63671 * X.GetHashCode() ^ 81083 * Y.GetHashCode();
}
public static float Dot(QuikVec2 a, QuikVec2 b)
{
return a.X * b.X + a.Y * b.Y;
}
}
/// <summary>
/// A RGBA color value.
/// </summary>
[DebuggerDisplay("({R}, {G}, {B}, {A})")]
public struct QuikColor
{
/// <summary>
/// Red channel.
/// </summary>
public byte R;
/// <summary>
/// Green channel.
/// </summary>
public byte G;
/// <summary>
/// Blue channel.
/// </summary>
public byte B;
/// <summary>
/// Alpha channel.
/// </summary>
public byte A;
public QuikColor(byte r, byte g, byte b, byte a)
{
R = r;
G = g;
B = b;
A = a;
}
public QuikColor(byte r, byte g, byte b) : this(r, g, b, 1) { }
public QuikColor(uint hexCode)
{
R = (byte)((hexCode >> 24) & 0xFF);
G = (byte)((hexCode >> 16) & 0xFF);
B = (byte)((hexCode >> 8 ) & 0xFF);
A = (byte)((hexCode >> 0 ) & 0xFF);
}
public QuikColor(int hexCode) : this((uint)hexCode) { }
}
/// <summary>
/// A bezier curve segment.
/// </summary>
[DebuggerDisplay("{Start} -- {ControlA} -- {ControlB} -- {End}")]
public struct QuikBezier
{
/// <summary>
/// Segment start point.
/// </summary>
public QuikVec2 Start;
/// <summary>
/// Start point control point.
/// </summary>
public QuikVec2 ControlA;
/// <summary>
/// End point control point.
/// </summary>
public QuikVec2 ControlB;
/// <summary>
/// Segment end point.
/// </summary>
public QuikVec2 End;
/// <summary>
/// An approximation of the arc length of the bezier curve, for calculating rasterization resolution.
/// </summary>
public float RasterizationArc =>
0.5f * (End - Start).Magnitude +
0.5f * ((ControlA - Start).Magnitude + (ControlB - ControlA).Magnitude + (End - ControlB).Magnitude);
public QuikBezier(QuikVec2 start, QuikVec2 controlA, QuikVec2 controlB, QuikVec2 end)
{
Start = start;
ControlA = controlA;
ControlB = controlB;
End = end;
}
public QuikBezier(
float startX,
float startY,
float controlAx,
float controlAy,
float controlBx,
float controlBy,
float endX,
float endY)
: this(
new QuikVec2(startX, startY),
new QuikVec2(controlAx, controlAy),
new QuikVec2(controlBx, controlBy),
new QuikVec2(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 QuikVec2 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 QuikVec2 GetBezierTangent(float t)
{
float T = 1 - t;
return
3 * T * T * (ControlA - Start) +
6 * T * t * (ControlB - ControlA) +
3 * t * t * (End - ControlB);
}
}
/// <summary>
/// A line segment.
/// </summary>
[DebuggerDisplay("{Start} -- {End}")]
public struct QuikLine
{
/// <summary>
/// Start point.
/// </summary>
public QuikVec2 Start;
/// <summary>
/// End point.
/// </summary>
public QuikVec2 End;
public QuikLine(QuikVec2 start, QuikVec2 end)
{
Start = start;
End = end;
}
public QuikLine(float startX, float startY, float endX, float endY)
{
Start.X = startX;
Start.Y = startY;
End.X = endX;
End.Y = endY;
}
}
/// <summary>
/// A rectangle.
/// </summary>
[DebuggerDisplay("({Right}, {Top}, {Left}, {Bottom})")]
public struct QuikRectangle
{
/// <summary>
/// Rectangle maximum point.
/// </summary>
public QuikVec2 Max;
/// <summary>
/// Rectangle minimum point.
/// </summary>
public QuikVec2 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 => Max.Y;
set => Max.Y = value;
}
public float Bottom
{
get => Min.Y;
set => Min.Y = value;
}
public QuikVec2 Size
{
get => Max - Min;
set => Max = Min + value;
}
public QuikRectangle(QuikVec2 max, QuikVec2 min)
{
Max = max;
Min = min;
}
public QuikRectangle(float r, float t, float l, float b)
{
Max = new QuikVec2() {X = r, Y = t};
Min = new QuikVec2() {X = l, Y = b};
}
public bool Contains(QuikVec2 point)
{
return
point.X > Left && point.X < Right &&
point.Y > Bottom && point.Y < Top;
}
internal void Translate(in QuikVec2 offset)
{
Min += offset;
Max += offset;
}
}
/// <summary>
/// An ellipse.
/// </summary>
/// <remarks>It is undefined to have an ellipse with non-orthogonal axes.</remarks>
[DebuggerDisplay("{Center} ellipse {AxisA}; {AxisB}")]
public struct QuikEllipse
{
/// <summary>
/// Ellipse center point.
/// </summary>
public QuikVec2 Center;
/// <summary>
/// First ellipse axis.
/// </summary>
public QuikVec2 AxisA;
/// <summary>
/// Second ellipse axis.
/// </summary>
public QuikVec2 AxisB;
}
/// <summary>
/// A triangle.
/// </summary>
[DebuggerDisplay("{A} -- {B} -- {C}")]
public struct QuikTriangle
{
/// <summary>
/// First vertex.
/// </summary>
public QuikVec2 A;
/// <summary>
/// Second vertex.
/// </summary>
public QuikVec2 B;
/// <summary>
/// Third vertex.
/// </summary>
public QuikVec2 C;
}
}