This notebook is part of https://github.com/AudioSceneDescriptionFormat/splines, see also http://splines.readthedocs.io/.

# Derivation of Uniform Catmull-Rom Splines

tangent vectors:

\begin{equation}
\boldsymbol{\dot{x}}_i = \frac{\boldsymbol{x}_{i+1} - \boldsymbol{x}_{i-1}}{2}
\end{equation}


```python
%matplotlib inline
import sympy as sp
sp.init_printing()
```


```python
from utility import NamedExpression, NamedMatrix
```

Reminder: [Hermite splines](hermite-uniform.ipynb) use the start and end positions as well as the tangent vectors at start and end:


```python
control_values_H = sp.Matrix(sp.symbols('xbm:2 xdotbm:2'))
control_values_H
```

Catmull-Rom splines use 4 positions instead:
The start and end positions of the current segment ($\boldsymbol{x}_0$ and $\boldsymbol{x}_1$) plus the start position of the previous segment ($\boldsymbol{x}_{-1}$) and the end position of the following segment ($\boldsymbol{x}_2$).

TODO: figure? more explanations ...


```python
x_1, x0, x1, x2 = sp.symbols('xbm_-1 xbm:3')
```


```python
control_values_CR = sp.Matrix([x_1, x0, x1, x2])
control_values_CR
```


```python
xd0 = NamedExpression('xdotbm0', (x1 - x_1) / 2)
xd0
```


```python
xd1 = NamedExpression('xdotbm1', (x2 - x0) / 2)
xd1
```

So let's look for a way to transform Catmull-Rom control values to Hermite control values.
Since we already have $M_\text{H}$ from [the notebook about uniform Hermite splines](hermite-uniform.ipynb), we can use it to get $M_\text{CR}$:


```python
M_H = NamedMatrix(r'{M_\text{H}}', sp.Matrix([[2, -2, 1, 1], [-3, 3, -2, -1], [0, 0, 1, 0], [1, 0, 0, 0]]))
M_H
```


```python
M_CRtoH = NamedMatrix(r'{M_{\text{CR$\to$H}}}', 4, 4)
```


```python
M_CR = NamedMatrix(r'{M_\text{CR}}', M_H.name * M_CRtoH.name)
M_CR
```


```python
sp.Eq(control_values_H, M_CRtoH.name * control_values_CR)
```

If we substitute the above definitions of $\boldsymbol{\dot{x}}_0$ and $\boldsymbol{\dot{x}}_1$, we can directly read off the matrix elements:


```python
M_CRtoH.expr = sp.Matrix([[expr.coeff(cv) for cv in control_values_CR]
                          for expr in control_values_H.subs([xd0.args, xd1.args])])
M_CRtoH
```


```python
M_CRtoH.pull_out(sp.S.Half)
```


```python
print(_.expr)
```


```python
M_HtoCR = NamedMatrix(r'{M_{\text{H$\to$CR}}}', M_CRtoH.I.expr)
M_HtoCR
```


```python
print(_.expr)
```


```python
M_CR = M_CR.subs([M_H, M_CRtoH]).doit()
M_CR
```


```python
M_CR.pull_out(sp.S.Half)
```


```python
print(_.expr)
```

And for completeness' sake, its inverse:


```python
M_CR.I
```


```python
print(_.expr)
```


```python
t = sp.symbols('t')
```


```python
b_CR = NamedMatrix(r'{b_\text{CR}}', sp.Matrix([t**3, t**2, t, 1]).T * M_CR.expr)
b_CR.T
```


```python
sp.plot(*b_CR.expr, (t, 0, 1));
```

TODO: plot some example curves

6df3e6854f62b8efc45bed172ed211532fd1cf81
ipynb
Jupyter Notebook
doc/catmull-rom-uniform.ipynb
mgeier/splines
f54b09479d98bf13f00a183fd9d664b5783e3864
MIT
doc/catmull-rom-uniform.ipynb
mgeier/splines
f54b09479d98bf13f00a183fd9d664b5783e3864
MIT
doc/catmull-rom-uniform.ipynb
mgeier/splines
f54b09479d98bf13f00a183fd9d664b5783e3864
MIT
Qwen/Qwen-72B
1. YES
2. YES