Utils/MathLD.cs
using System;
using System.Runtime.CompilerServices;

namespace Skateboard.Utils;

public static class MathLD
{
	public struct NearestPoint
	{
		public Vector3 Point;

		public Vector3 Direction;

		public float Fraction;

		public bool Outside;
	}

	public static float CalcShortestRot( float from, float to )
	{
		float max = 180f;
		if ( from < 0f )
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			from += max;
		}
		if ( to < 0f )
		{
			RuntimeHelpers.EnsureSufficientExecutionStack();
			to += max;
		}
		if ( from == to || (from == 0f && to == max) || (from == max && to == 0f) )
		{
			return 0f;
		}
		float left = 360f - from + to;
		float right = from - to;
		if ( from < to )
		{
			if ( to > 0f )
			{
				RuntimeHelpers.EnsureSufficientExecutionStack();
				left = to - from;
				RuntimeHelpers.EnsureSufficientExecutionStack();
				right = max - to + from;
			}
			else
			{
				RuntimeHelpers.EnsureSufficientExecutionStack();
				left = max - to + from;
				RuntimeHelpers.EnsureSufficientExecutionStack();
				right = to - from;
			}
		}
		if ( !(left <= right) )
		{
			return right * -1f;
		}
		return left;
	}

	public static Rotation FromToRotation( Vector3 fromDirection, Vector3 toDirection )
	{
		Vector3 axis = Vector3.Cross( fromDirection, toDirection );
		float angle = Vector3.GetAngle( fromDirection, toDirection );
		if ( angle >= 179.9196f )
		{
			Vector3 a = Vector3.Cross( fromDirection, Vector3.Right );
			RuntimeHelpers.EnsureSufficientExecutionStack();
			axis = Vector3.Cross( a, fromDirection );
			if ( axis.LengthSquared < 1E-06f )
			{
				axis = Vector3.Up;
			}
		}
		return AngleAxis( angle, axis.Normal );
	}

	public static Rotation AngleAxis( float aAngle, Vector3 aAxis )
	{
		RuntimeHelpers.EnsureSufficientExecutionStack();
		aAxis = aAxis.Normal;
		float rad = aAngle * ((float)Math.PI / 180f) * 0.5f;
		RuntimeHelpers.EnsureSufficientExecutionStack();
		aAxis *= (float)Math.Sin( rad );
		return new Rotation( aAxis.x, aAxis.y, aAxis.z, (float)Math.Cos( rad ) );
	}

	public static NearestPoint NearestPointOnLine( Vector3 point, Vector3 lineStart, Vector3 lineEnd, float threshold = 0f )
	{
		Vector3 lineDirection = (lineEnd - lineStart).Normal;
		float d = Vector3.Dot( point - lineStart, lineDirection );
		float len = Vector3.DistanceBetween( lineStart, lineEnd );
		bool outside = false;
		if ( d < threshold || d > len - threshold )
		{
			outside = true;
		}
		RuntimeHelpers.EnsureSufficientExecutionStack();
		d = Math.Min( len, Math.Max( 0f, d ) );
		NearestPoint result = default( NearestPoint );
		result.Point = lineStart + lineDirection * d;
		result.Direction = lineDirection;
		result.Fraction = d / len;
		result.Outside = outside;
		return result;
	}
}