MathUtil

This is a helper class for various math operations.

REQUIREMENTS:

HOW TO USE:

  • First download the extensions library and put it inside TOZ/Plugins/Extensions folder, if you havent done already.
  • Save the below code as MathUtil.cs and put it inside TOZ/Plugins/Utilities folder.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace TOZ {

	public static class MathUtil {

		public const double PI = 3.1415926535897932385;
		public const double SQRT_2 = 1.4142135623730950488;
		public const double SQRT_3 = 1.7320508075688772935;
		public const double DEG_TO_RAD = PI / 180.0;
		public const double RAD_TO_DEG = 1.0 / DEG_TO_RAD;

		//Swap two values
		public static void Swap<T>(ref T a, ref T b) {
			T c = a;
			a = b;
			b = c;
		}

		//Convert double to integer32 range
		public static double MakeInt32Range(double s) {
			if (s >= 1073741824.0) {
				return (2.0 * Math.IEEERemainder(s, 1073741824.0)) - 1073741824.0;
			}
			else if (s <= -1073741824.0) {
				return (2.0 * Math.IEEERemainder(s, 1073741824.0)) + 1073741824.0;
			}
			else {
				return s;
			}
		}

		//Clamp a value
		public static int ClampUp(int value, int upperBound) {
			return (value < upperBound) ? value : upperBound;
		}

		public static float ClampUp(float value, float upperBound) {
			return (value < upperBound) ? value : upperBound;
		}

		public static double ClampUp(double value, double upperBound) {
			return (value < upperBound) ? value : upperBound;
		}

		//Clamp a value
		public static int ClampDown(int value, int lowerBound) {
			return (value > lowerBound) ? value : lowerBound;
		}

		public static float ClampDown(float value, float lowerBound) {
			return (value > lowerBound) ? value : lowerBound;
		}

		public static double ClampDown(double value, double lowerBound) {
			return (value > lowerBound) ? value : lowerBound;
		}

		//Clamp a value between defined borders
		public static int Clamp(int value, int lowerBound, int upperBound) {
			return (value > lowerBound) ? ((value < upperBound) ? value : upperBound) : lowerBound;
		}

		public static float Clamp(float value, float lowerBound, float upperBound) {
			return (value > lowerBound) ? ((value < upperBound) ? value : upperBound) : lowerBound;
		}

		public static double Clamp(double value, double lowerBound, double upperBound) {
			return (value > lowerBound) ? ((value < upperBound) ? value : upperBound) : lowerBound;
		}

		//Cubic S-Curve value
		public static float SCurve3(float s) {
			return (s * s * (3.0f - 2.0f * s));
		}

		public static double SCurve3(double s) {
			return (s * s * (3.0 - 2.0 * s));
		}

		//Quintic S-Curve value
		public static float SCurve5(float s) {
			float s3 = s * s * s;
			float s4 = s3 * s;
			float s5 = s4 * s;
			return (6.0f * s5) - (15.0f * s4) + (10.0f * s3);
		}

		public static double SCurve5(double s) {
			double s3 = s * s * s;
			double s4 = s3 * s;
			double s5 = s4 * s;
			return (6.0 * s5) - (15.0 * s4) + (10.0 * s3);
		}

		//Saturate value
		public static float Saturate(float value) {
			return Mathf.Max(0.0f, Mathf.Min(1.0f, value));
		}

		public static double Saturate(double value) {
			return Math.Max(0.0, Math.Min(1.0, value));
		}

		//Smoothstep value
		public static float Smoothstep(float a, float b, float t) {
			float v = Saturate((t - a) / (b - a));
			return SCurve3(v);
		}

		public static double Smoothstep(double a, double b, double t) {
			double v = Saturate((t - a) / (b - a));
			return SCurve3(v);
		}

		//Grade value
		public static float Grade(float start, float end, float lowerBound, float upperBound, float t) {
			return Mathf.Lerp(start, end, Smoothstep(lowerBound, upperBound, t));
		}

		public static double Grade(double start, double end, double lowerBound, double upperBound, double t) {
			return InterpolationUtil.Linear(start, end, Smoothstep(lowerBound, upperBound, t));
		}

		public static Vector2 Grade(Vector2 start, Vector2 end, float lowerBound, float upperBound, float t) {
			return Vector2.Lerp(start, end, Smoothstep(lowerBound, upperBound, t));
		}

		public static Vector3 Grade(Vector3 start, Vector3 end, float lowerBound, float upperBound, float t) {
			return Vector3.Lerp(start, end, Smoothstep(lowerBound, upperBound, t));
		}

		public static Color Grade(Color start, Color end, float lowerBound, float upperBound, float t) {
			return Color.Lerp(start, end, Smoothstep(lowerBound, upperBound, t));
		}

		//Sign of value, different from Mathf as 0 returns 0
		public static int Sign(float v) {
			return (v < 0f) ? -1 : (v > 0f) ? 1 : 0;
		}

		public static int Sign(double v) {
			return (v < 0.0) ? -1 : (v > 0.0) ? 1 : 0;
		}

		//Polar to cartesian and vice versa
		public static Vector3 PolarToCartesian(float lat, float lon) {
			Vector3 direction = -Vector3.forward;
			Quaternion rotation = Quaternion.Euler(lat, -lon, 0f);
			return rotation * direction;
		}

		public static Vector2 CartesianToPolar(Vector3 pos) {
			float length = new Vector2(pos.x, pos.z).magnitude;
			Vector2 result = Vector3.zero;
			result.y = Mathf.Atan2(pos.x, -pos.z);
			result.x = Mathf.Atan2(pos.y, length);
			result *= Mathf.Rad2Deg;
			if(Sign(pos.x) < 0f) {
				result.y = 360f + result.y;
			}
			return result;
		}

		//Latitude and Longitude to XYZ on a unit sphere
		public static void LatLonToXYZ(float lat, float lon, ref float x, ref float y, ref float z) {
			float r = Mathf.Cos(Mathf.Deg2Rad * lat);
			x = r * Mathf.Cos(Mathf.Deg2Rad * lon);
			y = Mathf.Sin(Mathf.Deg2Rad * lat);
			z = r * Mathf.Sin(Mathf.Deg2Rad * lon);
		}

		public static void LatLonToXYZ(double lat, double lon, ref double x, ref double y, ref double z) {
			double r = Math.Cos(DEG_TO_RAD * lat);
			x = r * Math.Cos(DEG_TO_RAD * lon);
			y = Math.Sin(DEG_TO_RAD * lat);
			z = r * Math.Sin(DEG_TO_RAD * lon);
		}
	}

}