// Catmull-Rom & Uniform B-Spline Curve Interpolation Engine.

///|
pub fn evaluate_catmull_rom(
  p0 : Vec2,
  p1 : Vec2,
  p2 : Vec2,
  p3 : Vec2,
  t : Double,
) -> Vec2 {
  let t2 = t * t
  let t3 = t2 * t

  let f0 = -0.5 * t3 + t2 - 0.5 * t
  let f1 = 1.5 * t3 - 2.5 * t2 + 1.0
  let f2 = -1.5 * t3 + 2.0 * t2 + 0.5 * t
  let f3 = 0.5 * t3 - 0.5 * t2

  let x = p0.x * f0 + p1.x * f1 + p2.x * f2 + p3.x * f3
  let y = p0.y * f0 + p1.y * f1 + p2.y * f2 + p3.y * f3

  Vec2::new(x, y)
}

///|
pub fn evaluate_b_spline(
  p0 : Vec2,
  p1 : Vec2,
  p2 : Vec2,
  p3 : Vec2,
  t : Double,
) -> Vec2 {
  let t2 = t * t
  let t3 = t2 * t

  let f0 = (1.0 - t) * (1.0 - t) * (1.0 - t) / 6.0
  let f1 = (3.0 * t3 - 6.0 * t2 + 4.0) / 6.0
  let f2 = (-3.0 * t3 + 3.0 * t2 + 3.0 * t + 1.0) / 6.0
  let f3 = t3 / 6.0

  let x = p0.x * f0 + p1.x * f1 + p2.x * f2 + p3.x * f3
  let y = p0.y * f0 + p1.y * f1 + p2.y * f2 + p3.y * f3

  Vec2::new(x, y)
}

///|
pub fn interpolate_catmull_rom_spline(
  points : Array[Vec2],
  segments_per_span : Int,
) -> Array[Vec2] {
  let n = points.length()
  if n < 4 {
    points
  } else {
    let result : Array[Vec2] = []
    let step = 1.0 / segments_per_span.to_double()

    for i = 0; i < n - 3; i = i + 1 {
      let p0 = points[i]
      let p1 = points[i + 1]
      let p2 = points[i + 2]
      let p3 = points[i + 3]

      for j = 0; j < segments_per_span; j = j + 1 {
        let t = j.to_double() * step
        result.push(evaluate_catmull_rom(p0, p1, p2, p3, t))
      }
    }

    result.push(points[n - 2])
    result
  }
}