![]() | 1 | initial version |
Create a list of the control points:
LP=[vector([var("x_{}".format(u), domain="real"),
var("y_{}".format(u),domain="real")])
for u in (0..3)]
LP
[(x_0, y_0), (x_1, y_1), (x_2, y_2), (x_3, y_3)]
Utility function to express the Bernstein polynomials:
var("t")
Bn(p,j,t)=binomial(p,j)*t^j*(1-t)^(p-j)
Bn
(p, j, t) |--> t^j*(-t + 1)^(-j + p)*binomial(p, j)
We use it to get the parametric equation of the Bezier curve:
Bz=sum(map(lambda u,v:u*v, [Bn(3,w,t) for w in (0..3)], LP))
list(Bz)
[-(t - 1)^3*x_0 + 3*(t - 1)^2*t*x_1 - 3*(t - 1)*t^2*x_2 + t^3*x_3,
-(t - 1)^3*y_0 + 3*(t - 1)^2*t*y_1 - 3*(t - 1)*t^2*y_2 + t^3*y_3]
and its derivative:
dBz=Bz.diff(t)
list(dBz)
(-3*(t - 1)^2*x_0 + 3*(t - 1)^2*x_1 + 6*(t - 1)*t*x_1 - 6*(t - 1)*t*x_2 - 3*t^2*x_2 + 3*t^2*x_3,
-3*(t - 1)^2*y_0 + 3*(t - 1)^2*y_1 + 6*(t - 1)*t*y_1 - 6*(t - 1)*t*y_2 - 3*t^2*y_2 + 3*t^2*y_3)
Let d0 and d1 be the slopes of the function at begin and end points, and use them to define the equations constraining the equality of slopes:
var("d0, d1")
dB0=dBz(t=0)
E0=d0==dB0[1]/dB0[0]
dB1=dBz(t=1)
E1=d1==dB1[1]/dB1[0]
[E0,E1]
(d0, d1)
[d0 == (y_0 - y_1)/(x_0 - x_1), d1 == (y_2 - y_3)/(x_2 - x_3)]
These equations, along with the (implicit) equality of points (satisfied by keeping (x0,y0) and (x3,y3) as such), define the set of Bezier curves satisfying our constraints:
Sol=solve([E0, E1], [x_1, x_2, y_1, y_2])
print("len(Sol)={}".format(len(Sol)))
Sol[0]
len(Sol)=1
[x_1 == r8,
x_2 == r7,
y_1 == d0*r8 - d0*x_0 + y_0,
y_2 == d1*r7 - d1*x_3 + y_3]
This means that any Bezier curve:
starting at P0=(x0,y0),
ending at P3=(x3,y3),
having P1 somewhere on the line passing at P0 with slope d0, and
having P2 somewhere on the line passing at P3 with slope d1
is a curve approximating (in some undefined sense) our original function and satisfying our constraints.
In fact, we have a double infinity of solutions. Choosing x1 and x2 can (should) therefore be done to satisfy further constraints, for example minimizing the mean square distance between the original function and the Bezier curve, and possibly other constraints (e. g. keeping the relation between x and t monotonic on [x0 x3]↦[0 1], i. e. no loop or cusp in the curve...).
One can also note that these Bezier curves cannot have a linear mapping of t to x (one can check that this implies P0=P1=P2).
HTH,