This page was generated from doc/euclidean/polynomials.ipynb. Interactive online version: Binder badge.

Parametric Polynomial Curves#

The building blocks for polynomial splines are of course polynomials.

But first things first, let’s import SymPy and a few helper functions from helper.py:

[1]:
import sympy as sp
sp.init_printing(order='grevlex')
from helper import plot_basis, plot_sympy, grid_lines, plot_spline_2d

We are mostly interested in univariate splines, i.e. curves with one free parameter, which are built using polynomials with a single parameter. Here we are calling this parameter \(t\). You can think about it as time (e.g. in seconds), but it doesn’t have to represent time.

[2]:
t = sp.symbols('t')

Polynomials typically consist of multiple terms. Each term contains a basis function, which itself contains one or more integer powers of \(t\). The highest power of all terms is called the degree of the polynomial.

The arguably simplest set of basis functions is the monomial basis, a.k.a. power basis, which simply consists of all powers of \(t\) up to the given degree:

[3]:
b_monomial = sp.Matrix([t**3, t**2, t, 1]).T
b_monomial
[3]:
$\displaystyle \left[\begin{matrix}t^{3} & t^{2} & t & 1\end{matrix}\right]$

In this example we are creating polynomials of degree 3, which are also called cubic polynomials.

The ordering of the basis functions is purely a matter of convention, here we are sorting them in order of descending powers.

These basis functions are multiplied by (constant) coefficients. We are writing the coefficients with bold symbols, because apart from simple scalars (for one-dimensional functions), these symbols can also represent vectors in two- or three-dimensional space (and even higher-dimensional spaces).

[4]:
$\displaystyle \left[\begin{matrix}\boldsymbol{d}\\\boldsymbol{c}\\\boldsymbol{b}\\\boldsymbol{a}\end{matrix}\right]$

We can create a polynomial by multiplying the basis functions with the coefficients and then adding all terms:

[5]:
b_monomial.dot(coefficients)
[5]:
$\displaystyle \boldsymbol{d} t^{3} + \boldsymbol{c} t^{2} + \boldsymbol{b} t + \boldsymbol{a}$

This is a cubic polynomial in its canonical form (because it uses monomial basis functions).

Let’s take a closer look at those basis functions:

[6]:
plot_basis(*b_monomial)
../_images/euclidean_polynomials_16_0.svg

It doesn’t look like much, but every conceivable cubic polynomial can be expressed as exactly one linear combination of those basis functions (i.e. using one specific list of coefficients).

An example polynomial that’s not in canonical form …

[7]:
example_polynomial = (2 * t - 1)**3 + (t + 1)**2 - 6 * t + 1
example_polynomial
[7]:
$\displaystyle \left(2 t - 1\right)^{3} + \left(t + 1\right)^{2} - 6 t + 1$
[8]:
plot_sympy(example_polynomial, (t, 0, 1))
grid_lines([0, 1], [0, 0.5, 1])
../_images/euclidean_polynomials_19_0.svg

… can simply be re-written with monomial basis functions:

[9]:
example_polynomial.expand()
[9]:
$\displaystyle 8 t^{3} - 11 t^{2} + 2 t + 1$

Any polynomial can be rewritten using any set of basis functions (as long as the degree of the basis function set matches the degree of the polynomial).

In later sections we will see more basis functions, for example those that are used for Hermite, Bézier and Catmull–Rom splines. In those sections we will also see how to convert between different bases by means of matrix multiplication.

In the previous example, we used scalar coefficients to create a one-dimensional polynomial. We can use two-dimensional coefficients to create two-dimensional polynomial curves. Let’s create a little class to try this:

[10]:
import numpy as np

class CubicPolynomial:

    grid = 0, 1

    def __init__(self, d, c, b, a):
        self.coeffs = d, c, b, a

    def evaluate(self, t):
        t = np.expand_dims(t, -1)
        return t**[3, 2, 1, 0] @ self.coeffs

Note

The @ operator is used here to do NumPy’s matrix multiplication.

[11]:
poly_2d = CubicPolynomial([-1.5, 5], [1.5, -8.5], [1, 4], [3, 2])

Since this class has the same interface as the splines that will be discussed in later sections, we can use a spline helper function for plotting:

[12]:
plot_spline_2d(poly_2d, dots_per_second=30, chords=False)
../_images/euclidean_polynomials_29_0.svg

This class can also be used with three and more dimensions. The class splines.Monomial can be used to try this with arbitrary polynomial degree.