Files
2026-02-21 16:45:37 +08:00

177 lines
4.9 KiB
C#

using System;
using System.Collections.Generic;
using UnityEngine;
namespace PhysicsTools
{
public class Bezier
{
private Vector3[] knots;
private Vector3[] firstControlPts;
private Vector3[] secondControlPts;
private int lastIndex = 1;
private float lengthCovered;
private float indexedLength;
private float totalLength;
public Bezier(List<PosOri> points)
{
Vector3[] array = new Vector3[points.Count];
for (int i = 0; i < points.Count; i++)
{
array[i] = points[i].pos;
}
init(array);
}
public Bezier(Vector3[] points)
{
init(points);
}
private void init(Vector3[] points)
{
knots = new Vector3[points.Length];
for (int i = 0; i < points.Length; i++)
{
knots[i] = points[i];
if (i != 0)
{
totalLength += (knots[i] - knots[i - 1]).magnitude;
}
}
GetCurveControlPoints(knots, out firstControlPts, out secondControlPts);
indexedLength = (knots[1] - knots[0]).magnitude;
}
public float TotalLength()
{
return totalLength;
}
public PosOri getNext(float deltaLen)
{
return new PosOri(getNextPos(deltaLen), Quaternion.identity);
}
public Vector3 getNextPos(float deltaLen)
{
bool flag = false;
float num = indexedLength;
float num2 = indexedLength;
while (!flag)
{
num = indexedLength;
num2 = indexedLength - (knots[lastIndex] - knots[lastIndex - 1]).magnitude;
if (lengthCovered + deltaLen > num)
{
lastIndex++;
if (lastIndex == knots.Length)
{
flag = true;
deltaLen = num - lengthCovered;
lastIndex = knots.Length - 1;
}
else
{
indexedLength += (knots[lastIndex] - knots[lastIndex - 1]).magnitude;
}
continue;
}
break;
}
float num3 = (lengthCovered + deltaLen - num2) / (num - num2);
Vector3 result = (float)Math.Pow(1f - num3, 3.0) * knots[lastIndex - 1] + 3f * (float)Math.Pow(1f - num3, 2.0) * num3 * firstControlPts[lastIndex - 1] + 3f * (1f - num3) * num3 * num3 * secondControlPts[lastIndex - 1] + num3 * num3 * num3 * knots[lastIndex];
lengthCovered += deltaLen;
return result;
}
private void GetCurveControlPoints(Vector3[] knots, out Vector3[] firstControlPoints, out Vector3[] secondControlPoints)
{
if (knots == null)
{
throw new ArgumentNullException("knots");
}
int num = knots.Length - 1;
if (num < 1)
{
throw new ArgumentException("At least two knot points required", "knots");
}
if (num == 1)
{
firstControlPoints = new Vector3[1];
firstControlPoints[0].x = (2f * knots[0].x + knots[1].x) / 3f;
firstControlPoints[0].y = (2f * knots[0].y + knots[1].y) / 3f;
firstControlPoints[0].z = (2f * knots[0].z + knots[1].z) / 3f;
secondControlPoints = new Vector3[1];
secondControlPoints[0].x = 2f * firstControlPoints[0].x - knots[0].x;
secondControlPoints[0].y = 2f * firstControlPoints[0].y - knots[0].y;
secondControlPoints[0].z = 2f * firstControlPoints[0].z - knots[0].z;
return;
}
float[] array = new float[num];
for (int i = 1; i < num - 1; i++)
{
array[i] = 4f * knots[i].x + 2f * knots[i + 1].x;
}
array[0] = knots[0].x + 2f * knots[1].x;
array[num - 1] = (8f * knots[num - 1].x + knots[num].x) / 2f;
float[] firstControlPoints2 = GetFirstControlPoints(array);
for (int j = 1; j < num - 1; j++)
{
array[j] = 4f * knots[j].y + 2f * knots[j + 1].y;
}
array[0] = knots[0].y + 2f * knots[1].y;
array[num - 1] = (8f * knots[num - 1].y + knots[num].y) / 2f;
float[] firstControlPoints3 = GetFirstControlPoints(array);
for (int k = 1; k < num - 1; k++)
{
array[k] = 4f * knots[k].z + 2f * knots[k + 1].z;
}
array[0] = knots[0].z + 2f * knots[1].z;
array[num - 1] = (8f * knots[num - 1].z + knots[num].z) / 2f;
float[] firstControlPoints4 = GetFirstControlPoints(array);
firstControlPoints = new Vector3[num];
secondControlPoints = new Vector3[num];
for (int l = 0; l < num; l++)
{
firstControlPoints[l] = new Vector3(firstControlPoints2[l], firstControlPoints3[l], firstControlPoints4[l]);
if (l < num - 1)
{
secondControlPoints[l] = new Vector3(2f * knots[l + 1].x - firstControlPoints2[l + 1], 2f * knots[l + 1].y - firstControlPoints3[l + 1], 2f * knots[l + 1].z - firstControlPoints4[l + 1]);
}
else
{
secondControlPoints[l] = new Vector3((knots[num].x + firstControlPoints2[num - 1]) / 2f, (knots[num].y + firstControlPoints3[num - 1]) / 2f, (knots[num].z + firstControlPoints4[num - 1]) / 2f);
}
}
}
private float[] GetFirstControlPoints(float[] rhs)
{
int num = rhs.Length;
float[] array = new float[num];
float[] array2 = new float[num];
float num2 = 2f;
array[0] = rhs[0] / num2;
for (int i = 1; i < num; i++)
{
array2[i] = 1f / num2;
num2 = ((i >= num - 1) ? 3.5f : 4f) - array2[i];
array[i] = (rhs[i] - array[i - 1]) / num2;
}
for (int j = 1; j < num; j++)
{
array[num - j - 1] -= array2[num - j] * array[num - j];
}
return array;
}
}
}