2025-05-19

hints for programming catmull-rom splines

there exist uniform, centripedal and chordal variants.

links

example implementation

# evaluate a uniform Catmull-Rom spline segment at t in [0, 1]
catmull_rom = (p0, p1, p2, p3, t) ->
  a0 = []
  a1 = []
  a2 = []
  a3 = []
  for i in [0...p1.length]
    # cubic polynomial coefficients for each dimension
    a0[i] = -0.5 * p0[i] + 1.5 * p1[i] - 1.5 * p2[i] + 0.5 * p3[i]
    a1[i] = p0[i] - 2.5 * p1[i] + 2 * p2[i] - 0.5 * p3[i]
    a2[i] = -0.5 * p0[i] + 0.5 * p2[i]
    a3[i] = p1[i]
  point = []
  for i in [0...p1.length]
    # evaluate cubic polynomial
    point[i] = ((a0[i] * t + a1[i]) * t + a2[i]) * t + a3[i]
  point

# generate interpolated path through given control points
catmull_rom_path = (points, resolution) ->
  path = []
  n = points.length
  for i in [0...n - 1]
    # duplicate endpoints as needed for interpolation at boundaries
    p0 = if i is 0 then points[0] else points[i - 1]
    p1 = points[i]
    p2 = if i + 1 < n then points[i + 1] else points[n - 1]
    p3 = if i + 2 < n then points[i + 2] else points[n - 1]
    # sample points on spline segment from p1 to p2
    for j in [0...resolution]
      t = j / resolution
      path.push catmull_rom p0, p1, p2, p3, t if i < n - 1 or j is 0
  path

example usage

example_points = [[-0.72, -0.3], [0, 0], [1, 0.8], [1.1, 0.5], [2.7, 1.2], [3.4, 0.27]]
path = catmull_rom_path example_points, 100
for p in path
  console.log "#{p[0]} #{p[1]}"