Quadrangle Interpolation#
This doesn’t seem to be a very popular type of spline. We are mainly mentioning it because it is the starting point for interpolating rotations with Spherical Quadrangle Interpolation (Squad).
[1]:
import sympy as sp
sp.init_printing(order='grevlex')
As usual, we import some helpers from utility.py and helper.py:
[2]:
from utility import NamedExpression, NamedMatrix
from helper import plot_basis
Let’s start – as we have done before – by looking at the fifth segment of a spline, between \(\boldsymbol{x}_4\) and \(\boldsymbol{x}_5\). It will be referred to as \(\boldsymbol{p}_4(t)\), where \(0 \le t \le 1\).
[3]:
x4, x5 = sp.symbols('xbm4:6')
Boehm [Boe82] mentions (on page 203) so-called quadrangle points:
[4]:
x4bar = sp.symbols('xbarbm4^(+)')
x5bar = sp.symbols('xbarbm5^(-)')
x4bar, x5bar
[4]:
[5]:
t = sp.symbols('t')
[6]:
def lerp(one, two, t):
"""Linear intERPolation.
The parameter *t* is expected to be between 0 and 1.
"""
return (1 - t) * one + t * two
Boehm [Boe82] also mentions (on page 210) a peculiar algorithm to construct the spline segment. In a first step, a linear interpolation between the start and end point is done, as well as a linear interpolation between the two quadrangle points. The two resulting points are then interpolated again in a second step. However, the last interpolation does not happen along a straight line, but along a parabola defined by the expression \(2t(1-t)\):
This leads to a cubic polynomial. The following steps are very similar to what we did for cubic Bézier curves.
Basis Polynomials#
[8]:
Basis Matrix#
[10]:
[10]:
[11]:
M_Q.I
[11]:
Tangent Vectors#
[12]:
pd4 = p4.diff(t)
[13]:
xd4 = pd4.evaluated_at(t, 0)
xd4
[13]:
[14]:
xd5 = pd4.evaluated_at(t, 1)
xd5
[14]:
This can be generalized to:
\begin{align*} \boldsymbol{\dot{x}}^{(+)}_{i} &= 2 \boldsymbol{\bar{x}}^{(+)}_{i} - 3 \boldsymbol{x}_{i} + \boldsymbol{x}_{i+1}\\ \boldsymbol{\dot{x}}^{(-)}_{i} &= - \left(2 \boldsymbol{\bar{x}}^{(-)}_{i} - 3 \boldsymbol{x}_{i} + \boldsymbol{x}_{i-1}\right) \end{align*}
Quadrangle to Hermite Control Values#
[15]:
[15]:
[16]:
M_QtoH.I.pull_out(sp.S.One / 2)
[16]:
Quadrangle to Bézier Control Points#
Since we already know the tangent vectors, it is easy to find the Bézier control points, as we have already shown in the notebook about uniform Hermite splines.
[17]:
x4tilde = NamedExpression('xtildebm4^(+)', x4 + xd4.expr / 3)
x4tilde
[17]:
[18]:
x5tilde = NamedExpression('xtildebm5^(-)', x5 - xd5.expr / 3)
x5tilde
[18]:
[19]:
[19]:
[20]:
M_QtoB.I.pull_out(sp.S.One / 2)
[20]:
The inverse matrix can be used for converting from Bézier control points to quadrangle points:
[21]:
[21]:
We can generalize the equations for the outgoing and incoming quadrangle points:
\begin{align*} \boldsymbol{\bar{x}}_i^{(+)} &= \frac{3}{2} \boldsymbol{\tilde{x}}_i^{(+)} - \frac{1}{2} \boldsymbol{x}_{i+1}\\ \boldsymbol{\bar{x}}_i^{(-)} &= \frac{3}{2} \boldsymbol{\tilde{x}}_i^{(-)} - \frac{1}{2} \boldsymbol{x}_{i-1} \end{align*}
The two equations are also shown by Boehm [Boe82] on page 203.
Non-Uniform Parameterization#
Just like cubic Bézier splines, the shape of a segment (i.e. the image) is fully defined by its four control points. Re-scaling the parameter does not change the shape, but it changes the speed and therefore the tangent vectors.
[22]:
t4, t5 = sp.symbols('t4:6')
[24]:
pd4nu = p4nu.diff(t)
[25]:
pd4nu.evaluated_at(t, t4)
[25]:
[26]:
pd4nu.evaluated_at(t, t5)
[26]:
This can be generalized to:
\begin{align*} \boldsymbol{\dot{x}}^{(+)}_{i,\text{non-uniform}} &= \frac{2 \boldsymbol{\bar{x}}^{(+)}_{i} - 3 \boldsymbol{x}_{i} + \boldsymbol{x}_{i+1} }{ \Delta_i }\\ \boldsymbol{\dot{x}}^{(-)}_{i,\text{non-uniform}} &= -\frac{2 \boldsymbol{\bar{x}}^{(-)}_{i} - 3 \boldsymbol{x}_{i} + \boldsymbol{x}_{i-1} }{ \Delta_{i-1} } \end{align*}