Bézier curves seem both very simple, when using vector graphics applications, and a bit mysterious, when writing graphics code. Turns out they aren't really that complex. The Mathematics required is school level and the intuition is even simpler. This article explains Bézier curves with demos and code. And proposes a way of parameterising them which makes sense for algorithmic use.
A (quadratic) Bézier curve can be specified by 3 points. The start, end and a single control point. Like below. Click and drag to play around with the curve.
Okay so what is really going on. Well mathemetically it is just:
Clear? Well, go from t of 0 to 1 and it is the average of two parts for each t. The first part is going along the line between the first point and the control point. The second part is going (in the opposite direction) along the line from the control point to the second point. And we weight the average by the t value.
If you haven't done enough mathematics that might be a little abstract. But this animated, interactive diagram below should make it clearer.
See how the curve is drawn by going along the lines in opposite directions? (You can drag the points about to see how it changes the curve.)
The cubic version has an extra control point. Play around with it below:
Okay what is going on here? Well it is 'just' as if we have points on the lines between start and end and control points and a line between those points, and(!) a point on that line sliding across to draw the curve. Simple, right? Play around with the below demo to see what is going on.
Here is where I think we have a problem. It is fine to go from direct manipulation to code. But consider the other way round. Play around with the interactive demo. Look at the code. Look back at the image. Could you really naturally and intuitively go from the code (SVG) to an idea in your head of what it would look like?
<path d="M 40 40 Q 320 440 600 40" stroke="black" fill="transparent" />
The SVG code above is actually relatively clear as far as these things go. It is both concise and declarative. Move to x,y; quadratic beizer with control point and destination. Consider the HTML Canvas equivalent:
const c=document.getElementById("canvas"); const ctx=c.getContext("2d"); ctx.beginPath(); ctx.moveTo(20,20); ctx.quadraticCurveTo(20,100,200,20); ctx.stroke();
Yuck. Let's do better.
A Better Approach?
The below is proposal for a progressively complex API for drawing curves. One that makes more intuitive sense from an algorithmic perspective. We keep direct control over the start and end points, then provide parameters to control the curve in an intuitive way.
One curve parameter
You can still position the start and end points by dragging. This is pretty intuitive. But now you have one extra control mechanism: a single parameter controlling the size of the curve. Everything is entirely symmetric. And notice how as you adjust the start and end points the curve maintains the same shape. This makes it much easier to reason about and achieve desired outcomes from code.
Two curve parameters
Let's expose the full power of quadratic curves. But again everything should be relative to the start and end points. A natural way to accomplish this is by allowing the adjustment of the size of curve and angle of control.
Three curve parameters
Let's go up to three parameters. For the next thing to control let's adjust the bulbousness with a single additional parameter.
Four curve parameters
Let's go up to four. What about twisting the bulbousness line?