dclowd9901 - 4 months ago 24

Javascript Question

I've found about a 1000 answers to this question, but none of them I can use, because I'm using 4 control points with my curves.

That said, I stumbled on this guy here:

`double BezierArcLength(point2d p1, point2d p2, point2d p3, point2d p4)`

{

point2d k1, k2, k3, k4;

k1 = -p1 + 3*(p2 - p3) + p4;

k2 = 3*(p1 + p3) - 6*p2;

k3 = 3*(p2 - p1);

k4 = p1;

q1 = 9.0*(sqr(k1.x) + sqr(k1.y));

q2 = 12.0*(k1.x*k2.x + k1.y*k2.y);

q3 = 3.0*(k1.x*k3.x + k1.y*k3.y) + 4.0*(sqr(k2.x) + sqr(k2.y));

q4 = 4.0*(k2.x*k3.x + k2.y*k3.y);

q5 = sqr(k3.x) + sqr(k3.y);

double result = Simpson(balf, 0, 1, 1024, 0.001);

return result;

}

It looks like it'd be the perfect solution, but that beginning part is utterly confusing to me:

`k1 = -p1 + 3*(p2 - p3) + p4;`

k2 = 3*(p1 + p3) - 6*p2;

k3 = 3*(p2 - p1);

k4 = p1;

How on earth am I supposed to do operations like add, subtract and multiply on 2-dimensional objects (I presume point2d is an object structure like

`{x: 0, y: 0}`

FWIW, I'm using this equation to normalize an entity's speed when traversing the curve in a game. If you know a better way of doing this altogether, I'm all ears.

Answer

**Here’s how to traverse your cubic bezier curve at uniform speed**

There isn't one simple formula for getting even length segments along a cubic bezier curve (meaning even arc-length segments). What's involved is calculating many points along the curve and then using interpolation to “nudge” each point into being roughly equidistant.

I can get you nearly there without your having to get a PH.D in Mathematics.

Start by using the common formula to calculate x/y points on the curve from t=0 to t=1 where t=0 represents the startpoint of the curve and t=1 represents the endpoint of the curve. This is the common formula:

```
// calc the x/y point at t interval
// t=0 at startPt, t=1 at endPt
var x=CubicN(t,startPt.x,controlPt1.x,controlPt2.x,endPt.x);
var y=CubicN(t,startPt.y,controlPt1.y,controlPt2.y,endPt.y);
// cubic helper formula at t interval
function CubicN(t, a,b,c,d) {
var t2 = t * t;
var t3 = t2 * t;
return a + (-a * 3 + t * (3 * a - a * t)) * t
+ (3 * b + t * (-6 * b + b * 3 * t)) * t
+ (c * 3 - c * 3 * t) * t2
+ d * t3;
}
```

If you calculate enough intervals, say 100 intervals (t += .01 each loop) then you will get a very good approximation of the curve.

That means if you connect the 100 points with lines, the result would look very much like a cubic bezier curve.

But you're not done!

**The series of x/y points calculated above are not uniform in arc-distance from each other.**

Some neighboring points are close together and some neighboring points are farther apart.

To calculate evenly distributed points:

- Connect all the points with lines (creating a polyline).
- Calculate the total distance (T) of that polyline.
- Divide (T) by the number of uniform segments you desire, getting the uniform segment length (SL)
- Finally, walk the polyline from start to end, calculating each point that is (SL) distance from the previous point.

Result: you can use these equidistant points to traverse your curve.

Additional Refinement: This should result in a visually smooth movement along your Bezier path. But if you desire even more smoothness, just calculate more than 100 points--more points == more smoothness.