Rides/TrackRides/TrackOrientation.cs
using System.Text.Json.Serialization;

namespace HC3.Rides;

#nullable enable

/// <summary>
/// Describes the z-axis rotation (yaw) of a piece of track.
/// </summary>
public enum TrackHeading : sbyte
{
	Forward = 0,
	ForwardLeft = 1,
	Left = 2,
	BackwardLeft = 3,
	Backward = 4,
	BackwardRight = 5,
	Right = 6,
	ForwardRight = 7
}

/// <summary>
/// Describes the y-axis rotation (pitch) of a piece of track.
/// </summary>
public enum TrackIncline : sbyte
{
	VerticalDown = -3,
	SteepDown = -2,
	ShallowDown = -1,
	None = 0,
	ShallowUp = 1,
	SteepUp = 2,
	VerticalUp = 3
}

/// <summary>
/// Describes the x-axis rotation (roll) of a piece of track.
/// </summary>
public enum TrackBanking : sbyte
{
	VerticalLeft = -3,
	SteepLeft = -2,
	ShallowLeft = -1,
	None = 0,
	ShallowRight = 1,
	SteepRight = 2,
	VerticalRight = 3
}

/// <summary>
/// Describes the rotation of a piece of track.
/// </summary>
/// <param name="Heading">Track yaw.</param>
/// <param name="Incline">Track pitch.</param>
/// <param name="Banking">Track roll.</param>
public readonly record struct TrackOrientation(
	TrackHeading Heading = default,
	TrackIncline Incline = default,
	TrackBanking Banking = default,
	bool Inverted = false )
{
	public const int HeadingIncrementDegrees = 45;
	public const int BankingIncrementDegrees = 30;
	public const float ShallowInclineDegrees = 26.57f; // atan(0.5)
	public const float SteepInclineDegrees = 63.43f; // atan(2)

	[JsonIgnore]
	public TrackOrientation Inverse => new( Heading.Inverse(), Incline.Inverse(), Banking.Inverse(), Inverted );

	public static implicit operator Rotation( TrackOrientation orientation )
	{
		return new Angles( orientation.Incline.Pitch(), orientation.Heading.Yaw(), orientation.Banking.Roll() + (orientation.Inverted ? 180f : 0f) );
	}
}