using System; using System.Collections.Generic; using System.Linq; using UnityEngine; namespace Moonlit.Core { public class CubicSpline { private class TriDiagonalMatrix { public readonly float[] A; public readonly float[] B; public readonly float[] C; public TriDiagonalMatrix(int n) { A = new float[n]; B = new float[n]; C = new float[n]; } public float[] Solve(float[] d) { int num = A.Length; if (d.Length != num) { throw new ArgumentException("The input d is not the same size as this matrix."); } float[] array = new float[num]; array[0] = C[0] / B[0]; for (int i = 1; i < num; i++) { array[i] = C[i] / (B[i] - array[i - 1] * A[i]); } float[] array2 = new float[num]; array2[0] = d[0] / B[0]; for (int j = 1; j < num; j++) { array2[j] = (d[j] - array2[j - 1] * A[j]) / (B[j] - array[j - 1] * A[j]); } float[] array3 = new float[num]; array3[num - 1] = array2[num - 1]; for (int num2 = num - 2; num2 >= 0; num2--) { array3[num2] = array2[num2] - array[num2] * array3[num2 + 1]; } return array3; } } private float[] _A; private float[] _B; private float[] _XOrig; private float[] _YOrig; private int _LastIndex; public static void Interpolate(float[] x, float[] y, int points, out float[] xs, out float[] ys) { int num = x.Length; float[] array = new float[num]; array[0] = 0f; float num2 = 0f; for (int i = 1; i < num; i++) { float num3 = x[i] - x[i - 1]; float num4 = y[i] - y[i - 1]; float num5 = (float)Math.Sqrt(num3 * num3 + num4 * num4); num2 = (array[i] = num2 + num5); } float num6 = num2 / (float)(points - 1); float[] array2 = new float[points]; array2[0] = 0f; for (int j = 1; j < points; j++) { array2[j] = array2[j - 1] + num6; } CubicSpline cubicSpline = new CubicSpline(); xs = cubicSpline.FitAndEval(array, x, array2); CubicSpline cubicSpline2 = new CubicSpline(); ys = cubicSpline2.FitAndEval(array, y, array2); } public static List Interpolate(List input, int points) { List list = new List(points); float[] x = input.Select((Vector2 p) => p.x).ToArray(); float[] y = input.Select((Vector2 p) => p.y).ToArray(); Interpolate(x, y, points, out var xs, out var ys); for (int num = 0; num < points; num++) { list.Add(new Vector2(xs[num], ys[num])); } return list; } public static List Interpolate(List input, Func getter, Action setter, int points) where T : class, new() { List list = new List(points); float[] x = input.Select((T p) => getter(p).x).ToArray(); float[] y = input.Select((T p) => getter(p).y).ToArray(); Interpolate(x, y, points, out var xs, out var ys); for (int num = 0; num < points; num++) { T val = new T(); setter(val, new Vector2(xs[num], ys[num])); list.Add(val); } return list; } private float[] FitAndEval(float[] x, float[] y, float[] xs, float startSlope = float.NaN, float endSlope = float.NaN) { Fit(x, y, startSlope, endSlope); return Eval(xs); } private void Fit(float[] x, float[] y, float startSlope = float.NaN, float endSlope = float.NaN) { if (float.IsInfinity(startSlope) || float.IsInfinity(endSlope)) { throw new Exception("startSlope and endSlope cannot be infinity."); } _XOrig = x; _YOrig = y; int num = x.Length; float[] array = new float[num]; TriDiagonalMatrix triDiagonalMatrix = new TriDiagonalMatrix(num); if (float.IsNaN(startSlope)) { float num2 = x[1] - x[0]; triDiagonalMatrix.C[0] = 1f / num2; triDiagonalMatrix.B[0] = 2f * triDiagonalMatrix.C[0]; array[0] = 3f * (y[1] - y[0]) / (num2 * num2); } else { triDiagonalMatrix.B[0] = 1f; array[0] = startSlope; } for (int i = 1; i < num - 1; i++) { float num2 = x[i] - x[i - 1]; float num3 = x[i + 1] - x[i]; triDiagonalMatrix.A[i] = 1f / num2; triDiagonalMatrix.C[i] = 1f / num3; triDiagonalMatrix.B[i] = 2f * (triDiagonalMatrix.A[i] + triDiagonalMatrix.C[i]); float num4 = y[i] - y[i - 1]; float num5 = y[i + 1] - y[i]; array[i] = 3f * (num4 / (num2 * num2) + num5 / (num3 * num3)); } if (float.IsNaN(endSlope)) { float num2 = x[num - 1] - x[num - 2]; float num4 = y[num - 1] - y[num - 2]; triDiagonalMatrix.A[num - 1] = 1f / num2; triDiagonalMatrix.B[num - 1] = 2f * triDiagonalMatrix.A[num - 1]; array[num - 1] = 3f * (num4 / (num2 * num2)); } else { triDiagonalMatrix.B[num - 1] = 1f; array[num - 1] = endSlope; } float[] array2 = triDiagonalMatrix.Solve(array); _A = new float[num - 1]; _B = new float[num - 1]; for (int j = 1; j < num; j++) { float num2 = x[j] - x[j - 1]; float num4 = y[j] - y[j - 1]; _A[j - 1] = array2[j - 1] * num2 - num4; _B[j - 1] = (0f - array2[j]) * num2 + num4; } } private float[] Eval(float[] x) { int num = x.Length; float[] array = new float[num]; _LastIndex = 0; for (int i = 0; i < num; i++) { int nextXIndex = GetNextXIndex(x[i]); array[i] = EvalSpline(x[i], nextXIndex); } return array; } private int GetNextXIndex(float x) { if (x < _XOrig[_LastIndex]) { throw new ArgumentException("The X values to evaluate must be sorted."); } while (_LastIndex < _XOrig.Length - 2 && x > _XOrig[_LastIndex + 1]) { _LastIndex++; } return _LastIndex; } private float EvalSpline(float x, int j) { float num = _XOrig[j + 1] - _XOrig[j]; float num2 = (x - _XOrig[j]) / num; return (1f - num2) * _YOrig[j] + num2 * _YOrig[j + 1] + num2 * (1f - num2) * (_A[j] * (1f - num2) + _B[j] * num2); } } }