georgwaechter's picture

Structure for Bezier curves

Hello,

in my private math library i have structures for calculating bezier curves. I think this could be useful for OpenTK too, or? Within my personal projekt i use these structures to calculate and draw bezier curves with OpenGL.

I have one structure for quadric bezier curves, one structure for cubic bezier curves and one struct for bezier curves with any count of anchor points.

georg


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture

Nice, thanks :)

2) Makes sense. I'd suggest a pattern like this, though:

private List<Vector2> points = new List<Vector2>();
 
/// <summary>Gets the points of this curve.</summary>
/// <remarks>The first point and the last points represent the anchor points.</remarks>
public IList<Vector2> Points
{
    get { return (IList<Vector2>)points; }
}

The main reason is that this helps keep the internal state consistent. If the user was able to say curve.Points = null, you'd have to guard against null references every time you used the property.

This still allows you to add and remove points:

Vector2 point = new Vector2();
BezierCurve curve = new BezierCurve();
curve.Points.Add(point);    // works
curve.Points.Clear();
curve.Points = null;        // error

What do you think?

georgwaechter's picture

In reality i anyway should check for null in all functions, because a line like
private List<Vector2> points = new List<Vector2>();
is not allowed within structures. An alternative would be to switch to a class ...

1) using IEnumerable now implies, that we have to copy the specified list always ... but thats no real problem

the Fiddler's picture

No need, just make sure points are always initialized in the constructor.

1) True. I think it's good design to always copy though, because it avoids nasty surprises:

List<Vector2> points = new List<Vector2>();
points.Add(new Vector2());
points.Add(new Vector2());
 
BezierCurve curve = new BezierCurve(points);
points.Clear();
Console.WriteLine(curve.Points.Length.ToString());
// If the constructor does not copy, curve.Points.Length is now 0.
// An outside change has influenced the internals of BezierCurve,
// which is dangerous. No such problems if the constructor always copies.
georgwaechter's picture

Ok i made all changes. But there is yet the theoretical chance of null-reference-exceptions, because anybody could call the default ctor of the struct, that initializes all fields to 0 or null.

BezierCurve b = new BezierCurve();
b.Points.Add(new Vector2()); // exception

For that reason i added a setter for the property Points:

set { if (value != null) points = value; }

Additionally i made a few performance optimizations within the loops to reduce redundant calculations.

Here is the patch: http://trackplanner.de/files/BezierPatch.patch

the Fiddler's picture

Thanks, I've applied it to my working copy and it looks good, I'll play with it a bit and commit it.

iliak's picture

Just a little precision about the order of the control points :

/// <summary>
/// Draws a Bezier curve
/// </summary>
/// <param name="point1">Starting point</param>
/// <param name="point2">ending point</param>
/// <param name="control1">First control point</param>
/// <param name="control2">Second control point</param>
public void BezierCurveTo(Point point1, Point point2, Point control1, Point control2)
{
	Vector2[] points = new Vector2[]
	{
		new Vector2(point1.X, point1.Y),
		new Vector2(control1.X, control1.Y),
		new Vector2(control2.X, control2.Y),
		new Vector2(point2.X, point2.Y),
	};
	BezierCurve curve = new BezierCurve(points);
 
	int resolution = 50; // The number of points in the bezier curve
	Vector2 pos = Vector2.One;
	for (int p = 0; p <= resolution; p++)
	{
		pos = curve.CalculatePoint((float)p / (float)resolution);
		GL.Vertex2(pos.X, pos.Y);
	}
}

Like in OpenGL, it would be a nice addon to have the following "targets" : Normal, Texture, Color