File indexing completed on 2026-04-09 07:48:51
0001
0002 """
0003 catmull_rom_spline_2.py
0004 ==========================
0005
0006 This 2nd implementation factors out the calculation of the CatMull Rom interpolation
0007 weights : as they are the same for every segment.
0008
0009 This means that the interpolation reduces to a single matrix multiply
0010 for each segment.
0011
0012 """
0013
0014 import numpy as np, matplotlib as mp
0015 SIZE = np.array([1280, 720])
0016
0017 def catmull_rom_Mu_( u, a=0.5 ):
0018 """
0019 Derivation of the interpolation basis functions:
0020
0021 * https://www.cs.cmu.edu/~fp/courses/graphics/asst5/catmullRom.pdf
0022 * ~/opticks_refs/derivation_catmullRom_spline.pdf
0023
0024 """
0025 return np.array([
0026 -a*u + 2*a*u*u -a*u*u*u,
0027 1+(a-3)*u*u+(2-a)*u*u*u,
0028 a*u+(3-2*a)*u*u+(a-2)*u*u*u,
0029 -a*u*u+a*u*u*u ])
0030
0031
0032 def catmull_rom_Mu( N=100, a=0.5 ):
0033 """
0034 :param N: number of interpolated points for each segment
0035 :param a: "tension" 0.5 is standard for Catmull-Rom
0036 :return interpolation weights: shape (N, 4)
0037
0038 Every segment (which is controlled by a group of 4 control points)
0039 needs to use the same Mu for its interpolation so invoke this once only
0040 before the loop over segments.
0041 """
0042 return catmull_rom_Mu_(np.linspace(0,1,N), a ).T
0043
0044 def circle_points(n=16):
0045 angles = np.arange(0, 2*np.pi, 2*np.pi/n)
0046 points = np.zeros( (len(angles), 3) )
0047 points[:,0] = np.cos(angles)
0048 points[:,1] = np.sin(angles)
0049 return points
0050
0051 def square_points():
0052 return np.array([ [0,0,0], [1,0,0], [0,1,0], [1,1,0] ])
0053
0054 class Plot(object):
0055 def __init__(self, points, xpp, title):
0056 fig, ax = mp.pyplot.subplots(figsize=SIZE/100.)
0057 fig.suptitle(title)
0058 ax.set_aspect('equal')
0059 ax.plot( xpp[:,0], xpp[:,1], label="xpp" )
0060 ax.scatter( points[:,0], points[:,1], label="points" )
0061 ax.legend()
0062 fig.show()
0063
0064 if __name__ == '__main__':
0065 points = circle_points(16)
0066 assert len(points) >= 4
0067 numseg = len(points)-3
0068 looped = True
0069 if looped: numseg += 3
0070
0071 N = 100
0072 Mu = catmull_rom_Mu( N, a=0.5 )
0073 print(Mu.shape)
0074
0075 xpp = np.zeros( (numseg*N,3) )
0076 for i in range(numseg):
0077
0078 p = np.take( points, np.arange(i,i+4), mode='wrap', axis=0 )
0079 xpp[i*N:(i+1)*N] = np.dot( Mu, p )
0080 pass
0081 Plot(points, xpp, "analytic/catmull_rom_spline_2.py" )
0082