177 lines
4.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|