Curve Length Calculus with Functional JS

Riky Perdana
4 min readMay 27, 2023

--

Photo by Benjamín Gremler on Unsplash

You’re on a holiday trip to the peak this weekend, instead of riding on linear road you found that the road to the top is winding sideways, oscillating that way to make your trip less climbing. If you look from way up in the sky, you’d realize that the curve follows certain pattern that resembles sine function. With calculus, you’d be familiar with derivation and integration of a function to find its slope and area. But what if you want to stretch out that curve and measure the length from certain point to another? Surely there’s a formula for that:

Equation 1: Curve Length formula with derivative and integration method

That formula surely will make your work easier since you only need to find the 1) derivative, 2) simplify it, 3) integrate it and 4) plug the numbers in to get the result. But some of the time derivating and inegrating a function is not as easily as you think would be. There’s another trick through exhaustion — principally similar to Riemann Sum— which can be used to find the curve length.

Figure 1: Any curve is representable as sum of infinitesimal hypotenuses

You know that Pythagoras prompt a theorem that the square of hypotenuse of a triangle is equal to the sum of the other two sides squared. If you slice a curve to certain number you’d realize that each slice of that curve is just the hypotenuse of a triangle. So you can take advantage of this perception to think of that any curve is just a summation of many hypotenuses. With infinitesimal quantity of hypotenuse you’d get the closest approximation to the real lengh of that curve. That method is representable in this equation:

Formula 2: Curve Length formula with Exhaustion Method

So to apply that algorithm to functional JS code, we ought to do this:

  1. Set a large number of slices between the desired start and end
  2. Treat each sliced curve as the hypotenuse of a triangle that has width and height according to given function
  3. Sum all hypotenuses and present the result

Through experimentation, trial and errors, here’s the code I came up with:

let withAs = (obj, cb) => cb(obj),
makeArray = n => [...Array(n).keys()],
sum = arr => arr.reduce((r, i) => r + i),
sub = arr => arr.reduce((r, i) => r - i),

curveLength = obj => withAs(
(obj.end - obj.start) / obj.slices,
width => sum(
makeArray(obj.slices)
.map(i => Math.pow(sum([
Math.pow(width, 2),
Math.pow(sub([
obj.func(width * (i + 1)),
obj.func(width * i),
]), 2)
]), 1/2))
)
)

withAs is a callback function to pass object around inside a function. makeArray is a function to create an array in certain length. Both sum and sub are self-explanatory, they are used for reducing an array of numbers to single number. curveLength is a function whence given an object with specified properties, shall return an approximate value close to the actual curve length of given function. Now lets test with a linear function y = x with x ranged from 2 to 3:

curveLength({
start: 2, end: 3, slices: 100,
func: x => x
}) // get 1.4142 or root of 2

As we expected, the function call yields 1.4142 which is roughly equal to the root of 2. And now back to our curiosity of finding the actual length of a winding road that follows the y = sin(2x) function from 0 to 5:

Figure 2: The winding road of sin (no pun intended)
curveLength({
start: 0, end: 5, slices: 100,
func: x => Math.sin(2 * x)
}) // got 8.5190

According to curveLength function, the actual length should be close to 8.52 point of distance, which is reasonable since the straight road — which supposedly shorter — is 5 point of distance. If you need some additional explanation of how this function works, here’s the documentation:

// How it works
curveLength = obj => withAs(
// make so many slices
(obj.end - obj.start) / obj.slices,
width => sum(
makeArray(obj.slices)
// find hypotenuse of each triangle
.map(i => Math.pow(sum([ // square of c is sum of ..
Math.pow(width, 2), // square of a and
Math.pow(sub([ // square of b
obj.func(width * (i + 1)),
obj.func(width * i), // height of triangle
]), 2)
]), 1/2))
) // sum every hypotenuse
)

I hope it helps you in some ways.

--

--

No responses yet