# Generating orthogonal axes on a spline

I use a Catmull-Rom spline, each section built from a set of cubic functions p = x(t), y(t), z(t).

I was looking at Frenet Formulas but it's not working as desired... . Generating T = (x'(t),y'(t),z'(t)) is easy, using B = (x''(t),y''(t),z''(t)) isn't doing what I expect... T and B are not orthogonal.

Looking at it more closely I'm not convinced this is what should happen. Am I misunderstanding the math, or misunderstanding what F-S is for?

As a concrete example let's say:

x(t) = 2t^3 + t^2 - 3t + 6
y(t) = t^3 - 2t^2 + 4t
z(t) = -3t^3 + 4t^2 + 2t - 9


Where 0<=t<=1.

-
You're supposed to normalize your derivatives first (because your spline is not unit-speed parametrized); and then shift the vectors forming the Frenet frame to the actual point on the curve. – J. M. Jan 30 '12 at 14:13
@J.M. - that sounds good but is a bit over my head; could someone elaborate on that in a full answer? Is normalizing over t a required step for this to work, or an extra step that should be done simply for better spline behavior? – Mr. Boy Jan 30 '12 at 14:23
Actually, you really should be looking at this section of the wiki entry you linked to; they are doing precisely the normalization that I was alluding to. You are familiar with the concept of a vector norm, yes? – J. M. Jan 30 '12 at 14:32
@J.M. do you simply mean normalizing a single vector to unit length? If so then yes... but when you take a cross-product this would change only the magnitude of the result, not its direction; hence my confusion. I'll add a specific example to my question. – Mr. Boy Jan 30 '12 at 14:58
Right; you do that normalization to the derivatives of each piece of your spline. For the first derivative, normalizing nets you the tangent vector; for the second derivative, normalizing yields the binormal vector. Cross the two, and you have the normal vector. Since these vectors start from the origin, a shift's necessary. – J. M. Jan 30 '12 at 15:04

Alright, I'll work on two of the vectors; I'll leave the third one to you.

You have the vector-valued function

$$\mathbf c(t)=\begin{pmatrix}2t^3 + t^2 - 3t + 6\\t^3 - 2t^2 + 4t\\-3t^3 + 4t^2 + 2t - 9\end{pmatrix}$$

The first two derivatives are easily done:

$$\mathbf c^\prime(t)=\begin{pmatrix}6t^2+2t-3\\3t^2-4t+4\\-9t^2+8t+2\end{pmatrix}$$

$$\mathbf c^{\prime\prime}(t)=\begin{pmatrix}12t+2\\6t-4\\8-18t\end{pmatrix}$$

To get the tangent vector, we first get the norm of $\mathbf c^\prime(t)$:

\begin{align*} \|\mathbf c^\prime(t)\|&=\sqrt{(6t^2+2t-3)^2+(3t^2-4t+4)^2+(-9t^2+8t+2)^2}\\ &=\sqrt{126t^4-144t^3+36t^2-12t+29} \end{align*}

and that is the thing we divide $\mathbf c^\prime(t)$ with:

$$\mathbf T(t)=\frac{\mathbf c^\prime(t)}{\|\mathbf c^\prime(t)\|}=\frac1{\sqrt{126t^4-144t^3+36t^2-12t+29}}\begin{pmatrix}6t^2+2t-3\\3t^2-4t+4\\-9t^2+8t+2\end{pmatrix}$$

To get the binormal vector, we first cross $\mathbf c^\prime(t)$ and $\mathbf c^{\prime\prime}(t)$:

$$\mathbf c^\prime(t)\times \mathbf c^{\prime\prime}(t)=\begin{pmatrix}12t^2-84t+40\\66t^2-30t+28\\30t^2-66t+4\end{pmatrix}$$

normalize that result,

\begin{align*} \|\mathbf c^\prime(t)\times \mathbf c^{\prime\prime}(t)\|&=\sqrt{(12t^2-84t+40)^2+(66t^2-30t+28)^2+(30t^2-66t+4)^2}\\ &=24(225t^4-414t^3+717t^2-372t+100) \end{align*}

and assembling the binormal vector's a snap:

$$\mathbf B(t)=\frac{\mathbf c^\prime(t)\times \mathbf c^{\prime\prime}(t)}{\|\mathbf c^\prime(t)\times \mathbf c^{\prime\prime}(t)\|}=\frac1{\sqrt{24(225t^4-414t^3+717t^2-372t+100)}}\begin{pmatrix}12t^2-84t+40\\66t^2-30t+28\\30t^2-66t+4\end{pmatrix}$$

Computing the normal vector, I leave to you. But, here's a nice bonus you might appreciate:

-
Very cool thanks. My confusion turned out to be that I was thinking of normalizing the result at a given value of t, rather than normalizing the equation itself. – Mr. Boy Jan 30 '12 at 17:21

The reason your formula for $\mathbf{b}$ (shouldn't it be $\mathbf{n}$, anyway?) doesn't work is, that your curve is not parameterized by arc-length. The formula

$\mathbf{n}(s)=\frac{\mathbf{x}\verb|"|(s)}{\|\mathbf{x}\verb|"|(s)\|}$

only holds for an arc-length parameterization (notice the $s$ usually used for the arc-length parameter), in which also $\mathbf{t}(s)=\mathbf{x}'(s)$ is already of unit length.

This doesn't work for a general parameter $t$. You are right in that normalizing the operands doesn't change the direction of a cross product. But whereas for $\mathbf{t}(t)=\frac{\mathbf{x}'(t)}{\|\mathbf{x}'(t)\|}$ it just comes down to normalization, $\mathbf{x}\verb|"|(t)$ points into a completely different direction than $\mathbf{x}\verb|"|(s)$, making $\frac{\mathbf{x}\verb|"|(t)}{\|\mathbf{x}\verb|"|(t)\|}$ a completely different vector than $\mathbf{n}$. This is because we need not just derive $\mathbf{x}'(t)$, but $\frac{\mathbf{x}'(t)}{\|\mathbf{x}'(t)\|}$.

So for a general parameter $t$, the formulas are actually given by:

$\mathbf{t}(t)=\frac{\mathbf{x}'(t)}{\|\mathbf{x}'(t)\|}$

$\mathbf{n}(t)=\frac{\mathbf{x}'(t)\times(\mathbf{x}\verb|"|(t)\times\mathbf{x}'(t))}{\|\mathbf{x}'(t)\times(\mathbf{x}\verb|"|(t)\times\mathbf{x}'(t))\|} = \mathbf{b}(t)\times\mathbf{t}(t)$

$\mathbf{b}(t)=\frac{\mathbf{x}'(t)\times\mathbf{x}\verb|"|(t)}{\|\mathbf{x}'(t)\times\mathbf{x}\verb|"|(t)\|} = \mathbf{t}(t)\times\mathbf{n}(t)$

Making it practically easiest to just compute $\mathbf{t}$ and $\mathbf{b}$ and compute $\mathbf{n}$ by crossing these (keep an eye on the order of operands, though, as you know $\times$ is not commutative).

And additionally you have to keep in mind, that a Catmull-Rom spline is generally only $C^1$ at the interpolated points (where two splines connect), which means its second derivative $\mathbf{x}\verb|"|$ (and thus its Frenet-frame) doesn't need to be continuous at these points (though it's of course continuous inside the individual splines, as they're cubi splines). But I don't know if that is a problem for you.

-
Good catch about x" being non-continuous. I'm not sure if it's an issue yest, is there a quick fix like dropping in a different piecewise function or does it get complicated? – Mr. Boy Jan 30 '12 at 22:02
@John Don't know. It never was a problem for me. If I ever need C2 continuity on the whole curve, I just take a cubic B-Spline. Otherwise you just have to be sure to restrict the relevant interval to a single spline in every computation that needs a continuous 2nd derivative (e.g. Newton-based minimization or examination of curvature development). – Christian Rau Jan 30 '12 at 23:35