Bézier curves in Julia with animations

I think many heard about Bézier curves but maybe some of you didn’t and I heard about it but wasn’t really sure what they are and how they work.
During my Geometric Modelling and Animations course in university we had some lectures on it and I did some coding for homeworks and also to understand a bit more about it. During the last days I published my animations on Twitter and asked whether you’re interested in a post. There was quite a bit feedback on that so here it is!

Let us start with a basic Bézier curve:

simple Bézier curve

Before I show you what Bézier curves are we should probably have a short look what a basic curve is. A curve can be described by a parameterized description as:

\[
\mathbf{b}(t) = (x(t),y(t))^T \quad t_1 \leq t \leq t_2\]

whereas \(\mathbf{b}\) is a vector and \(x, y\) are polynomial functions like

\[
x(t) = a_0 + a_1t + a_2t^2 + \dots + a_nt^n\]

Now the idea is to compute the values on the curve from \(t_1 = 0\) to \(t_2 = 1\) using a different basis not simply \(t^0, \dots, t^n\).
For Bézier curves this basis are defined as:

\[
B_{i}^{n}(t) :=\left( \begin{array}{c}{n} \\ {i}\end{array}\right) t^{i}(1-t)^{n-i}, \quad 0 \leq i \leq n\]

and is called Bernstein basis.

Which looks a bit random for now but they have some interesting properties:

  • \(B_{0}^{n}(t)+B_{1}^{n}(t)+\cdots+B_{n}^{n}(t)=1\)
  • $B_0^n(0) = 1, B_n^n(1)=1

which means when we write down the complete formula to compute \(\mathbf{b}(t)\):

\[
\mathbf{b}(t) = \sum_{i=0}^n B_i^n \mathbf{b}_i\]

where \(\mathbf{b}_i\) are our control points. Now the second property just means that \(\mathbf{b}(0) = \mathbf{b}_0\) and \(\mathbf{b}(0) = \mathbf{b}_n\)

I think it would be nice to actually see the basis functions:

Bernstein basis

Now we can combine it with our control points to obtain:

Bézier using Bernstein basis

Besides the change in color you probably don’t see a difference to the first plot even though that was plotted differently.

I know some of you are here for code so I’ll show you the bernstein code:

using Plots
# for the LaTeX labels in the legend
using LaTeXStrings 

function compute_bernstein(i,n; steps=100)
    return [binomial(n,i)*t^i*(1-t)^(n-i) for t in LinRange(0,1,steps)]
end

function compute_bernstein_poly(px,py; steps=100)
    n = length(px)-1
    bernsteins = [compute_bernstein(i,n) for i=0:n]
    x_vals = [sum(px[k]*bernsteins[k][t] for k=1:n+1) for t=1:steps]
    y_vals = [sum(py[k]*bernsteins[k][t] for k=1:n+1) for t=1:steps]
    return x_vals, y_vals
end

function plot_with_bernstein(px,py; steps=100, subplot=1)
    x_vals, y_vals = compute_bernstein_poly(px,py; steps=steps)
    plot!(x_vals, y_vals, color=:blue, label="",subplot=subplot)
end

function main()
    px = [0, 3, 7]
    py = [2, 9, 3]

    plot(;size=(700,500), axisratio=:equal, legendfont=font(13))
    plot!(px, py, linetype=:scatter, label="control points")
    plot_with_bernstein(px,py)
    png("using_bernstein")
end

Pretty basic so far. Now combining the two and animate:

Bernstein gif

Actually I’m not too sure about how to interpret the colored animating part on the lower plot with the different bernstein polynomials but I think it looks interesting and I never saw that before. The three dots red, green and blue some up to the black in both ways.

Anyway I think the interesting things are still missing. First of all we only have 3 control points at…