Introduction to Bessel Curve:
Besser curve is a parameterized spline curve used by Besser when he used electronic computer to design automobile parts.
General parametric equation:
It is easy to see from the formula that the number of points required for the NTH order Bessel curve is n+1. The formula is a parametric equation, not y=f(x) in the general sense, but y=f(t),x =f(t).
Bezier curve is used to draw curves, the third order Bessel curve, for example, he has four control points, the first point and the last point is the start and end points of the curve, the curve will be through the two points, while the second and the third is the control of curve shape, more directly, by changing the position of the second and third points, The slope of the curve will be affected. To see the effect, you can open the Chrome debug panel and set the Transition property and observe the timing function.
The slope is the velocity of a displacement – time curve, but in web animation displacement can be changed to any property (see earlier animation arguments).
That actually uses JS to realize a third-order Bezier curve, no external call is to find a time x -> any other attribute y mapping.
In this case, we know x, and now we need to solve for y. Using the transition-timing function of CSS as a reference, we can set the starting point and the ending point to (0,0) and (1,1). Naturally the range of the two control points should also be between 0 and 1.
First, the Bessel curve is expanded into a general form:
Start and end points are simplified:
OK, the theory is complete and can be put into practice.
Suppose we get the time value x at a certain moment, then the parameter TTT can be obtained by the parametric equation B(t)=xB(t) =x, B(t)=x, and then the final result y can be obtained by substituting the TTT into y=B(t), y=B(t), y=B(t).
So, in the final analysis, the first thing is to solve the equation, the root of multiple functions is not easy, here concrete implementation, we can refer to chromium bezier curve implementation, to solve this problem, the specific way is, first through 8 Times of Newton iteration, if found, directly return the result, if not, Start a binary search.
The principle of Newton’s iteration, in short, is to make a tangent line at any point on a curve, and then make a line perpendicular to the X-axis at the intersection point of the tangent line and the X-axis, assuming that the line and the curve intersect at another point, and then make a tangent line at that point… As you repeat this process, the tangent line will get closer and closer to the roots of the curve.
Basic derivation: Suppose I have a curve y=f(x),y =f(x),y =f(x),y =f(x), and take the tangent line of x0,y0x_0,y_0x0,y0, then, Point of slope to f (1) (x0) f ^ {} (1) (x_0) f (1) (x0) by curve equation y = kx + by + by = = kx kx + b generation into the above parameters is b = f (x0) – f (1) (x0) x0 = f (x_0) – b F ^ {} (1) (x_0) x_0b = f (x0) – f (1) (x0) x0 reason tangent equation for g (x) = f (x0) – f (1) (x0) (x0 – x) g (x) = f (x_0) – F ^ {} (1) (x_0) (x_0 – x), g (x) = f (x0) – f (1) (x0) (x0 – x); Get the tangent with the x axis intersection point for the x1 = x0 – f (x0) f (1) (x0) x_1 = x_0 – \ frac {f (x_0)} {f ^ {} (1) (x_0)} x1 = x0 – f (1) (x0) f (x0) this is an iteration. X1 is the first approximate root, and in subsequent iterations, if the approximate root is within an acceptable range of error from the real root, we can treat this root as the real root.
As for the dichotomy rule, it’s easy to say that the two intervals are close to each other based on the current results. Code:
type coordinate = {
x: number.y: number
}
export class cubicBezier{
p1: coordinate
p2: coordinate
precision = 1e-5;
constructor(x1,y1,x2,y2){
this.p1 = {
x:x1,
y:y1
};
this.p2 = {
x:x2,
y:y2
};
}
getX(t:number){
let x1 = this.p1.x,x2=this.p2.x;
return 3*x1*t*Math.pow(1-t,2) + 3* x2*Math.pow(t,2) * (1-t) + Math.pow(t,3)}getY(t:number){
let y1 = this.p1.y,y2=this.p2.y;
return 3*y1*t*Math.pow(1-t,2) + 3*y2*Math.pow(t,2) * (1-t) + Math.pow(t,3)}// https://github.com/amfe/amfe-cubicbezier/blob/master/src/index.js
solveCurveX(x:number){
var t2 = x;
var derivative;
var x2;
var p1x = this.p1.x, p2x = this.p2.x;
var ax = 3 * p1x - 3 * p2x + 1;
var bx = 3 * p2x - 6 * p1x;;
var cx = 3 * p1x;;
function sampleCurveDerivativeX(t:number){
// `ax t^3 + bx t^2 + cx t' expanded using Horner 's rule.
return (3 * ax * t + 2 * bx) * t + cx;
}
// https://trac.webkit.org/browser/trunk/Source/WebCore/platform/animation
// First try a few iterations of Newton's method -- normally very fast.
// http://en.wikipedia.org/wiki/Newton's_method
for (let i = 0; i < 8; i++) {
// f(t)-x=0
x2 = this.getX(t2) - x;
if (Math.abs(x2) < this.precision) {
return t2;
}
derivative = sampleCurveDerivativeX(t2);
// == 0, failure
if (Math.abs(derivative) < this.precision) {
break;
}
// xn = x(n-1) - f(xn)/ f'(xn)
// Suppose g(x) = f(t) -x
// g'(x) = f'(t)
//所以 f'(t) == g'(t)
// derivative == g'(t)
t2 -= x2 / derivative;
}
// Fall back to the bisection method for reliability.
// bisection
// http://en.wikipedia.org/wiki/Bisection_method
var t1 = 1;
var t0 = 0;
t2 = x;
while (t1 > t0) {
x2 = this.getX(t2) - x;
if (Math.abs(x2) < this.precision) {
return t2;
}
if (x2 > 0) {
t1 = t2;
} else {
t0 = t2;
}
t2 = (t1 + t0) / 2;
}
// Failure
return t2;
}
solve(x:number){
return this.getY( this.solveCurveX(x) )
}
}
Copy the code