Tubes and Knots

Wrapping a tube around a curve parameterized in three dimensional space is a nice enhancement. Here are several examples.

The Code

The main idea is to find an orthonormal pair of vectors perpendicular to the curve at any point. The tube may then be easily parameterized in terms of these vectors. One easy way to find these is to take the cross product of the tangent vector with an arbitrary vector. That is the crux of the following code. Note the optional fourth argument indicating the three dimensional vector which will be crossed with the tangent vector.

TubePlot[curve_List, {var_, min_, max_}, radius_,
    crossVector_List:{1, 1, 1}, opts___] := 
    Module[{tangent, unitTangent,  normal,
        unitNormal, biNormal},
    
    tangent = D[curve, t];
    unitTangent = tangent/Sqrt[tangent.tangent];
    normal = Cross[tangent, crossVector];
    unitNormal = normal/Sqrt[normal.normal];
    biNormal = Cross[unitTangent, unitNormal];
    ParametricPlot3D[
        curve + radius Cos[s] unitNormal + radius Sin[s] biNormal //
            Evaluate,
    {var, min, max}, {s, 0, 2Pi}, opts] 
]

Another approach is to take the derivative of the unit tangent vector, normailize it, and then take the cross product of these two. This is called the Frenet reference frame of the path and is used in general relativity. While the previous approach is usually faster and more reliable, the Frenet approach sometimes leads to prettier results. Here is some code implementing the Frenet approach.


TubePlotFrenet[curve_List, {var_, min_, max_}, radius_, opts___] := 
    Module[{tangent, unitTangent, normal,
            unitNormal, biNormal},
    
    tangent = D[curve, t];
    unitTangent = tangent/Sqrt[tangent.tangent];
    normal = D[unitTangent, t];
    unitNormal = normal/Sqrt[normal.normal];
    biNormal = Cross[unitTangent, unitNormal];
    ParametricPlot3D[
      curve + radius Cos[s] unitNormal + radius Sin[s] biNormal // Evaluate,
    {var, min, max}, {s, 0, 2Pi}, opts]
]


[UNCA | Math Dept. | Mark's Home]