#region --- License ---
/* Licensed under the MIT/X11 license.
* Copyright (c) 2006-2008 the OpenTK Team.
* This notice may not be removed from any source distribution.
* See license.txt for licensing detailed licensing details.
*
* Contributions by Georg W�chter.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text;
namespace OpenTK
{
///
/// Represents a bezier curve with as many points as you want.
///
[Serializable]
public struct BezierCurve
{
#region Fields
private List points;
///
/// The parallel value.
///
/// This value defines whether the curve should be calculated as a
/// parallel curve to the original bezier curve. A value of 0.0f represents
/// the original curve, 5.0f i.e. stands for a curve that has always a distance
/// of 5.0f to the orignal curve at any point.
public float Parallel;
#endregion
#region Properties
///
/// Gets the points of this curve.
///
/// The first point and the last points represent the anchor points.
public IList Points
{
get
{
return points;
}
}
#endregion
#region Constructors
///
/// Constructs a new .
///
/// The points.
public BezierCurve(IEnumerable points)
{
if (points == null)
throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures.");
this.points = new List(points);
this.Parallel = 0.0f;
}
///
/// Constructs a new .
///
/// The points.
public BezierCurve(params Vector2[] points)
{
if (points == null)
throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures.");
this.points = new List(points);
this.Parallel = 0.0f;
}
///
/// Constructs a new .
///
/// The parallel value.
/// The points.
public BezierCurve(float parallel, params Vector2[] points)
{
if (points == null)
throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures.");
this.Parallel = parallel;
this.points = new List(points);
}
///
/// Constructs a new .
///
/// The parallel value.
/// The points.
public BezierCurve(float parallel, IEnumerable points)
{
if (points == null)
throw new ArgumentNullException("points", "Must point to a valid list of Vector2 structures.");
this.Parallel = parallel;
this.points = new List(points);
}
#endregion
#region Functions
///
/// Calculates the point with the specified t.
///
/// The t value, between 0.0f and 1.0f.
/// Resulting point.
public Vector2 CalculatePoint(float t)
{
return BezierCurve.CalculatePoint(points, t, Parallel);
}
///
/// Calculates the length of this bezier curve.
///
/// The precision.
/// Length of curve.
/// The precision gets better as the
/// value gets smaller.
public float CalculateLength(float precision)
{
return BezierCurve.CalculateLength(points, precision, Parallel);
}
#region Static methods
///
/// Calculates the length of the specified bezier curve.
///
/// The points.
/// The precision value.
/// The precision gets better as the
/// value gets smaller.
public static float CalculateLength(IList points, float precision)
{
return BezierCurve.CalculateLength(points, precision, 0.0f);
}
///
/// Calculates the length of the specified bezier curve.
///
/// The points.
/// The precision value.
/// The parallel value.
/// Length of curve.
/// The precision gets better as the
/// value gets smaller.
/// The parameter defines whether the curve should be calculated as a
/// parallel curve to the original bezier curve. A value of 0.0f represents
/// the original curve, 5.0f represents a curve that has always a distance
/// of 5.0f to the orignal curve.
public static float CalculateLength(IList points, float precision, float parallel)
{
float length = 0.0f;
Vector2 old = BezierCurve.CalculatePoint(points, 0.0f, parallel);
for (float i = precision; i < (1.0f + precision); i += precision)
{
Vector2 n = CalculatePoint(points, i, parallel);
length += (n - old).Length;
old = n;
}
return length;
}
///
/// Calculates the point on the given bezier curve with the specified t parameter.
///
/// The points.
/// The t parameter, a value between 0.0f and 1.0f.
/// Resulting point.
public static Vector2 CalculatePoint(IList points, float t)
{
return BezierCurve.CalculatePoint(points, t, 0.0f);
}
///
/// Calculates the point on the given bezier curve with the specified t parameter.
///
/// The points.
/// The t parameter, a value between 0.0f and 1.0f.
/// The parallel value.
/// Resulting point.
/// The parameter defines whether the curve should be calculated as a
/// parallel curve to the original bezier curve. A value of 0.0f represents
/// the original curve, 5.0f represents a curve that has always a distance
/// of 5.0f to the orignal curve.
public static Vector2 CalculatePoint(IList points, float t, float parallel)
{
Vector2 r = new Vector2();
double c = 1.0d - (double)t;
float temp;
int i = 0;
foreach (Vector2 pt in points)
{
temp = (float)MathHelper.BinomialCoefficient(points.Count - 1, i) * (float)(System.Math.Pow(t, i) *
System.Math.Pow(c, (points.Count - 1) - i));
r.X += temp * pt.X;
r.Y += temp * pt.Y;
i++;
}
if (parallel == 0.0f)
return r;
Vector2 perpendicular = new Vector2();
if (t != 0.0f)
perpendicular = r - BezierCurve.CalculatePointOfDerivative(points, t);
else
perpendicular = points[1] - points[0];
return r + Vector2.Normalize(perpendicular).PerpendicularRight * parallel;
}
///
/// Calculates the point with the specified t of the derivative of the given bezier function.
///
/// The points.
/// The t parameter, value between 0.0f and 1.0f.
/// Resulting point.
private static Vector2 CalculatePointOfDerivative(IList points, float t)
{
Vector2 r = new Vector2();
double c = 1.0d - (double)t;
float temp;
int i = 0;
foreach (Vector2 pt in points)
{
temp = (float)MathHelper.BinomialCoefficient(points.Count - 2, i) * (float)(System.Math.Pow(t, i) *
System.Math.Pow(c, (points.Count - 2) - i));
r.X += temp * pt.X;
r.Y += temp * pt.Y;
i++;
}
return r;
}
#endregion
#endregion
}
}