Spline interpolation in Swift

Just so that the next person can avoid having to do the wikipedia-math-formula-to-Swift conversion, here’s a simple Catmull-Rom interpolation method for linear y=x data. I’m using it to create simple ski jump hill profiles for a possibly upcoming game, it’s so easy to describe a hill profile by just giving it control points and let the interpolator do the math. This will work just fine for any time-based keyframe data, too.

Notes: you need to give 4 different points of data – if you give duplicates, the formula will turn the return value into a NaN for obvious reasons.

I’m using a simple 2d point data to feed the thing.

class Point {
    var x : Float = 0.0
    var y : Float = 0.0
}

// t: relative position between p1 and p2, in 0 .. 1 range
//     i left it as a relative value so that this can easily
//     be turned into a general-purpose 2d curve interpolator
// p0, p1, p2, p3: the four points
func CatmullRom(t: Float, _ p0: Point, _ p1: Point, _ p2: Point, _ p3: Point) -> Float
{
    let alpha : Float = 0.5
    let t0 : Float = 0.0
    let t1 = t0 + alpha * (sqrtf(powf(p1.x - p0.x, 2.0) + powf(p1.y - p0.y, 2.0)))
    let t2 = t1 + alpha * (sqrtf(powf(p2.x - p1.x, 2.0) + powf(p2.y - p1.y, 2.0)))
    let t3 = t2 + alpha * (sqrtf(powf(p3.x - p2.x, 2.0) + powf(p3.y - p2.y, 2.0)))
    let tt = t * (t2 - t1) + t1
   
    let a1 = (t1 - tt) / (t1 - t0) * p0.y + (tt - t0) / (t1 - t0) * p1.y
    let a2 = (t2 - tt) / (t2 - t1) * p1.y + (tt - t1) / (t2 - t1) * p2.y
    let a3 = (t3 - tt) / (t3 - t2) * p2.y + (tt - t2) / (t3 - t2) * p3.y
   
    let b1 = (t2 - tt) / (t2 - t0) * a1 + (tt - t0) / (t2 - t0) * a2
    let b2 = (t3 - tt) / (t3 - t1) * a2 + (tt - t1) / (t3 - t1) * a3
   
    let c = (t2 - tt) / (t2 - t1) * b1 + (tt - t1) / (t2 - t1 ) * b2
   
    return c
}

Source for the formula and picture:
https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline

Leave a Reply


*