Discovering Bezier Curves

Discovering Bezier Curves

Recently there has been a staggeringly good video about bezier curves, and its something that I never really understood (because I had never looked at them), and yet also found it was something I've always been in love with - growing up I've done a lot of 'maths pictures' and peg-board type thing where you make curves from bits of string, and Bezier curves are basically this - using straight lines to make curves.

Freya HolmΓ©r's v=original video.

So I wanted to understand them, and my first attempts were - well, curvy, but not at all Bezier. It took me a while to realise that these curves were not 'right' - they didn't (in the second picture below) have the correct cross over. In effect I had built something that curved but didn't have the controlability that a bezier did.

Not Bezier Curves

I was also struggling to understand that if these were Quadratic Beziers, what a five point one would look like. So I went back to the maths book and read up a bit more.

The second batch worked exactly right: and the methodology looked sound:

Bezier Curves!

In particular, for the same set of entry points, the third one has the loop that I was expecting, but every curve is more distinct, which means changes in the input coordinates have a larger effect on the shape, allowing the curves to be controllable.

The great thing was, that my code now works for any number of input points on a curve, which means I could do 2, 3, 4, 5 or more point curves and it works - basically you find the intermediate points, and then if theres still more then 1 point, you find the intermediate point between those - I admit I wrote it using recursive functions (which I normally would remove the recursive code but still allow it to recurse through the points), but it allows me to demonstrate these:

5 point Beziers
6 point beziers

It should be noted that I'm using 10 line segments rather then working out every pixel - and as you add more nodes, the curves get sharper and with more artefacts. Or so I thought - I mean, yes, it has more artifacts, where an artifact is defined as a pixel where there shouldn't be one - or a missing pixel where there should, but actually the 6 point beziers were a lot more complex then I had imagined.

Taking the second curve, and showing for a different number of line segments:

Increasing line segments

My first instinct was that more segments would mean smoother curves - and it does, but it also means that some of the details which were originally being lost were now coming onto display. What I hadn't appreciated is that with a bezier curve, every point affects the entire curve - not just the locals either side of it. And by that I don't mean every point on a bunch of bezier joined together - but every point between the start and end points of this calculation. What has happened here, by adding more points is not just a tight loop (seen at the point), appearing above 20, but also a wave form appearing on the curve which becomes apparently around 50 segments.

In effect, these wavy patterns seen in the higher numbers are not artifacts - but the actual curve. The true artefacts are seen in the lower numbers where the curve is smoother.

I begin to ask myself whether or not these are fractal. And now, the dawning that I will now have to a) work out if they are* and b) if it's actually been seen by anyone else before.

So, before I do the actual maths, lets make some observations to better refine this thoughts:

  • The idea that adding more line segments to it makes it look fractal in the same way that measuring the length of the British Isles is fractal - reducing the line length leads to longer answers. Each time I increase the number of segments, the line gets longer (unlike for instance, measuring a straight line, where chopping it up into smaller lines, the total length is the same). This would suggest its fractal, and that was my initial thought.
  • Arguably, this is not similar to something like the Cantor Set - where adding more length to the line increases the length by a fraction. You can't "extend" i.e. double or halve the length of this curve - you could add more points in, but theres no logical way of knowing where to add it. Following that thought, Its possible that if the points are positioned on a calculation, then adding more points (rather then adding more segments), could lead to some curves being fractal.
  • With that thought carried further, there are almost certainly some curves which are not fractal, however, they may not be linear... if you put all the points on a straight line, you will end up with a line - but the acceleration of the line may not be the same as a straight line (i.e. the differential of the line would not be a point). Does the density of points change on this straight line? Is this now just a curved space-time problem?
  • Whilst it also looks chaotic, I don't believe it is chaos - whilst it might seem unpredictable especially when drawn using this recursive/iterative approach - (to find one point you find the previous points etc), by studying the maths, you can get an accurate formula for the curve. This has two side interpretations: Because theres an accurate formula, you can then differentiate it, which suggests it is not fractal. I use the word suggests strongly. Most fractals are 'nowhere differentiable'. The second interpretation is that it is not chaotic, because you can go to any point on the curve by plugging the numbers in, and not calculating from the start. - My initial thought was that it was chaotic, in that chaotic systems are usually highly sensitive to their input parameters, and this passes that 'test', in that any change to any of the points will change every point on the curve. However I'm not sure that it radically changes the outcome - a slight change to any point will only slightly change every point on the curve, so its sensitive, but not 'highly' sensitive (and indeed, not chaotic as explained above).

What is left now is to do the maths to work out the formulas. I think it also requires some thinking about how the 'test' for fracticality works - the line can't be doubled in length*, but then neither can the Mandlebrot set (which exists entirely inside a small square).

[Update] After some thinking, the line isn't just stretched between the two points - it goes on indefinitely. Its just the scaling factor can be below 0 or above 1. What does that look like? This is why this is a blog post - not a paper presenting an argument but a diary of discovery of the curves.

Exploring the curve further out

Here, with a slight alteration to the code, a curve has been drawn further out - showing theres another local minimum and then it starts increasing again. Even for this simpler layout (no crossing of points etc), theres distinct waves showing up on in the +ve direction. Note the curve has to go through the start and end points (where t =0 or 1) by its very definition.

Some of these glitches are artefacts from the drawing process, but some are very clear changes in direction of the curve.

[Update 2]

It's almost certain that there is a defect in my original rendering code. Overnight I rewrote the code to use proper mathsβ„’, and when using the formula to work out coordinates rather then the geometric calculations, a lot of these micro-waves disappear. In fact when you look at the formula for the curve, there shouldn't be any high frequency curves in there.

Curve laid over the top of the other.

In this picture, we can see clearly that the formula based approach gives a very smooth line. At this point I wonder if that the geometric approach has a rounding error somewhere in the middle.

The original approach was this:

  • Work out the coordinates along each of the line segments
  • Then work out the next level of coordinates along the line that connect those coordinates to.
  • if theres still more then 1 line at this layer, repeat until only one layer.

The formula approach uses the same theory to generate a formula- using sympy, an equation for the position along a line is entered. Then using this, and the initial set of points, a formula is generated for each line in the first set, and so on, but without resolving it for any particular fraction. At the end the entire formula is simplified, meaning we can now print off the formula for the above curve:


Note I used complex numbers here to allow the maths to be easier, instead of having a formula for x and a formula for y.

Because the first version involves working out multiple intermediate points, any issues with those (e.g. integer rounding) would cause larger effects in the output - where the second works them out as theoretical points, and then just simplifies the maths reducing any calculation error to only one final step.