Search code examples
pythonscipy

B-Spline through 3 points in 3D space


I have three points in 3D and I'd like to a find a smooth curve (e.g., a spline) that goes through all points. With 4 points or more, I can use SciPy's B-splines:

import numpy as np
from scipy.interpolate import splev, splprep
import matplotlib.pyplot as plt


dim = 3
# doesn't work for 3 points
num_points = 4
X = np.random.rand(dim, num_points)

tck, u = splprep(X, s=0)
new_points = splev(np.linspace(0, 1, 100), tck)

# plot
ax = plt.figure().add_subplot(projection="3d")
ax.scatter(*X)
ax.plot(*new_points)
plt.show()

enter image description here

Why doesn't this work for three points? What could I do instead?


Solution

  • You can use cubic spline:

    import numpy as np
    from scipy.interpolate import CubicSpline
    import matplotlib.pyplot as plt
    
    
    X = np.array([[0, 1, 2], [0, 1, 0], [0, 1, 2]])
    t = np.linspace(0, 1, X.shape[1])
    sx, sy, sz = CubicSpline(t, X[0]), CubicSpline(t, X[1]), CubicSpline(t, X[2])
    
    nt = np.linspace(0, 1, 100)
    nsx, nsy, nsz = sx(nt), sy(nt), sz(nt)
    
    fig = plt.figure()
    ax = fig.add_subplot(projection='3d')
    ax.scatter(X[0], X[1], X[2], color='r')
    ax.plot(nsx, nsy, nsz)
    plt.show()
    
    

    Prints

    enter image description here


    You can also reduce the k to 2 (the degree of spline to a quadratic equation):

    import numpy as np
    from scipy.interpolate import splev, splprep
    import matplotlib.pyplot as plt
    
    dim = 3
    num_points = 3
    X = np.random.rand(dim, num_points)
    
    tck, u = splprep(X, s=0, k=2)
    new_points = splev(np.linspace(0, 1, 100), tck)
    
    fig = plt.figure()
    ax = fig.add_subplot(projection="3d")
    ax.scatter(*X, color='r')
    ax.plot(*new_points)
    plt.show()
    
    

    enter image description here