Chaikin's Algorithm In SwiftUI

Chaikin's Algorithm In SwiftUI

Many of you are probably familiar with Bézier curves and how they create smooth paths and designs, but did you know there's a simpler way to get a similar results?

I came across this blog post yesterday that introduced me to Chaikin's Algorithm, , and after spending an afternoon experimenting with it, I knew I had to write about it.

What is Chaikin's Algorithm?

Chaikin's Algorithm is a simple method to smooth out a rough polygonal line into a nice, smooth curve. It works by repeatedly adding new points along each line segment, at 25% and 75% of the way between the original points, and then connecting these new points. Every time you do this, the line gets smoother and smoother.

Let's apply the algorithm to this starting set of points:

Next, we'll add new points at 25% and 75% of the way along each line segment.

We'll look at how we calculate these points in a minute, but for now we'll just estimate it.

Now, let's combine just the new points together:

You'll see that by effectively cutting off the corners, we've achieved a more curved appearance.

Let's do it one more time.

We'll start again by adding new points along each of the new line segments:

New points added in black.

And then connect them:

We can see that in just 2 iterations we've transformed our initial jagged line into a much more pleasant curve.

Calculating Control Points

To calculate the control points at 25% and 75% along a line segment, we need to use linear interpolation (a.k.a. lerp). It sounds fancy, but it's simply a way of finding a point that is some percentage of the way between two other points.


If you're already familiar with this concept, feel free to skip to the next section. Or, if you're interested in exploring the relationship between different interpolation approaches and how they relate to animations in iOS (UIKit & SwiftUI), check out my earlier blog post:

Exploring Animation Curves
Between my recent SwiftUI projects and YouTube content, animations have become a crucial part of my work. So, I’ve been down a bit of an animation rabbit hole lately... We’ll start with the basics - from linear animations to easing curves - and then we’ll dive into creating custom animations

We'll start by looking at the linear interpolation formula and then we'll look at an example:

L(t) = (1 − t) ⋅ P0​ + t ⋅ P1​

  • L(t) is the interpolated point.
  • t is the interpolation parameter which ranges from 0 to 1.
    • When t = 0, L(t) = P0.
    • When t = 1, L(t) = P1.
  • P0 is the starting point.
  • P1 is the ending point.

So, if we wanted to figure out a point that was 25% of the way between P0 and P1, we'd just have to evaluate this expression:

L(t) = (1 - 0.25) * P0 + 0.25 * P1

L(t) = (0.75 * P0) + (0.25 * P1)

In practice, we'll use this formula to calculate a new control point's X and Y coordinates individually.

Implementing Chaikin's Algorithm

Now that we know how the algorithm and linear interpolation work, let's create an interactive version of it in SwiftUI.

Here's the main algorithm's implementation:

func chaikinAlgorithm(points: [CGPoint], iterations: Int) -> [CGPoint] {
    // We want to preserve the starting and ending points, so let's save them.
    guard points.count > 2, let startingPoint = points.first, let endingPoint = points.last else { return points }

    var currentPoints = points

    // We know the more iterations we do, the smoother the curve.
    for _ in 0..<iterations {
        var newPoints: [CGPoint] = [startingPoint]

        for i in 0..<currentPoints.count - 1 {
            // Gets adjacent points
            let p0 = currentPoints[i]
            let p1 = currentPoints[i + 1]

            // Calculates the position of the new control points
            // via linear interpolation
            let q = CGPoint(x: 0.75 * p0.x + 0.25 * p1.x, y: 0.75 * p0.y + 0.25 * p1.y)
            let r = CGPoint(x: 0.25 * p0.x + 0.75 * p1.x, y: 0.25 * p0.y + 0.75 * p1.y)

            newPoints.append(q)
            newPoints.append(r)
        }

        newPoints.append(endingPoint)
        currentPoints = newPoints
    }

    return currentPoints
}

To render the points and curve in SwiftUI, we can use Path:

var body: some View {
    ZStack {
        // Draw the points where the user taps
        ForEach(points, id: \.self) { point in
            Circle()
                .fill(Color.blue)
                .frame(width: 10, height: 10)
                .position(point)
        }

        // Draw the smoothed curve
        Path { path in
            guard !smoothedPoints.isEmpty else { return }
            path.move(to: smoothedPoints.first!)
            for point in smoothedPoints.dropFirst() {
                path.addLine(to: point)
            }
        }
        .stroke(Color.red, lineWidth: 2)
    }
    .background(Color.white)
    .onTapGesture(coordinateSpace: .global) { location in
        points.append(location)
        
        // Perform Chaikin's Algo every time we add a new point
        smoothedPoints = chaikinAlgorithm(points: points, iterations: 3)
    }
    .edgesIgnoringSafeArea(.all)
}

Putting everything together, we can now define any line and generate a curve that matches it's shape.

1 Iteration

0:00
/0:08

3 Iterations

0:00
/0:08

5 Iterations

0:00
/0:06

You can find the full source code here.

Chaikin's Algorithm vs. Bézier Curves

Both Chaikin's Algorithm and Bézier curves are essential tools for creating smooth curves from a set of control points. They are widely used in graphic design, animation, and UI/UX design to generate appealing shapes and paths. One key similarity is that both methods can be applied iteratively to increase the smoothness of the resulting curve. With Chaikin's Algorithm, each iteration adds new points and refines the curve, while Bézier curves can be subdivided further to achieve a similar effect.

However, there are significant differences between the two. Bézier curves are mathematically more complex, requiring polynomial equations and manipulation of control points to define the curve. In contrast, Chaikin's Algorithm is straightforward, using simple linear interpolation between points. Bézier curves are defined by a specific set of control points that directly influence the shape of the curve. Moving a control point will change the entire curve's shape. Chaikin's Algorithm, however, generates new points along the line segments, gradually smoothing the path without direct manipulation of the original control points.

In terms of applications, Bézier curves are widely used in vector graphic design, font design, and path animation due to their precision and control. On the other hand, Chaikin's Algorithm is more commonly used for quick and easy curve smoothing, particularly in applications where simplicity and efficiency are more critical than precise control over the curve's shape. In summary, while both Chaikin's Algorithm and Bézier curves are powerful tools for creating smooth curves, they cater to different needs and levels of complexity. Chaikin's Algorithm is ideal for quick, easy smoothing, while Bézier curves offer greater control and precision for more complex designs.


If you're interested in more articles about iOS Development & Swift, check out my YouTube channel or follow me on Twitter.

And, if you're an indie iOS developer, make sure to check out my newsletter! Each issue features a new indie developer, so feel free to submit your iOS apps.

Ace The iOS Interview
The best investment for landing your dream iOS jobHey there! My name is Aryaman Sharda and I started making iOS apps way back in 2015. Since then, I’ve worked for a variety of companies like Porsche, Turo, and Scoop Technologies just to name a few. Over the years, I’ve mentored junior engineers, bui…
Indie Watch
Indie Watch is an exclusive weekly hand-curated newsletter showcasing the best iOS, macOS, watchOS, and tvOS apps from developers worldwide.
Universal Link & Apple App Site Association Testing Tool
Easily verify and test Universal GetUniversal.link is a free tool for verifying and testing Apple App Site Association (AASA) files. Ensure your Universal Links are configured correctly with easy link creation, real-time testing, and team collaboration features. Save the website as a bookmark for quick access on devices and simulators. Simplify your AASA file troubleshooting today!

Subscribe to Digital Bunker

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Subscribe