using System;
using Microsoft.Xna.Framework;
namespace ProjectZ.InGame.Things
{
class CubicBezier
{
private Vector2 _firstPoint;
private Vector2 _secondPoint;
private readonly int _dataCount;
public float[] Data;
public CubicBezier(int dataCount, Vector2 firstPoint, Vector2 secondPoint)
{
_dataCount = dataCount;
Data = new float[_dataCount];
SetData(firstPoint, secondPoint);
}
public void SetData(Vector2 firstPoint, Vector2 secondPoint)
{
_firstPoint = firstPoint;
_secondPoint = secondPoint;
FillData();
}
private void FillData()
{
var lastValue = EvaluatePosition(0);
var dataSize = 1 / (float)(Data.Length - 1);
var stepSize = 1 / (float)_dataCount / 2;
var position = stepSize;
var dataIndex = 0;
for (var i = 0; i < Data.Length; i++)
Data[i] = 0;
Data[_dataCount - 1] = 1;
while (true)
{
var newValue = EvaluatePosition(position);
position += stepSize;
while (newValue.X >= dataIndex * dataSize)
{
var distance = newValue.X - lastValue.X;
var indexDistance = dataIndex * dataSize - lastValue.X;
var percentage = indexDistance / distance;
Data[dataIndex] = Vector2.Lerp(lastValue, newValue, percentage).Y;
dataIndex++;
}
lastValue = newValue;
if (position >= 1 || dataIndex >= Data.Length - 1)
break;
}
}
///
/// Get the interpolated y value from the given x value.
///
/// The value on the x axis where we want to get the y value.
///
public float EvaluateX(float x)
{
x = MathHelper.Clamp(x, 0, 1);
// interpolate between two points to get the value at "time"
var index = (int)(x * (_dataCount - 1));
var dataSize = 1 / (_dataCount - 1.0f);
var percentage = (x % dataSize) / dataSize;
var value = Data[index] * (1 - percentage);
if (index < _dataCount - 1)
value += Data[index + 1] * percentage;
return value;
}
public Vector2 EvaluatePosition(float time)
{
time = MathHelper.Clamp(time, 0, 1);
var point = // (float)Math.Pow(1 - time, 3) * Vector2.Zero +
(float)(3 * Math.Pow(1 - time, 2) * time) * _firstPoint +
((3 * (1 - time) * time * time) * _secondPoint) +
(float)Math.Pow(time, 3) * Vector2.One;
return point;
}
}
}