# Getting a custom Bézier curve function to work

In general, the $nth$-degree Bézier curve is defined as: $$\vec{C}(u)=\sum_{i=0}^{n} B_{i,n}(u) \vec{P_i} \qquad 0\leq u\leq1$$

where $B_{i,n}(u)$ is the classical Bernstein polynomial, $$B_{i,n}(u)=\frac{n!}{i!(n-i)!}u^i(1-u)^{n-i}$$

$\vec{P_i}$ is the control point.

I have written a function to plot these curves:

Trial 1

bezierPlot1[n_, pts : {{_, _} ..}, opts : OptionsPattern[Plot]]:=
ParametricPlot[
Total@Table[
BernsteinBasis[n, i, u] # & /@ pts, {i, 0, n}], {u, 0, 1}]

pts = {{0, 0}, {2, 4}, {4, 5}, {6, 0}};
bezierPlot1[3,pts]


It failed; that is, no graphics appeared.

Trial 2

I replaced the built-in function BernsteinBasis with $\frac{n!}{i! (n - i)!} u^i(1 - u)^{n - i}$

 bezierPlot2[n_, pts : {{_, _} ..}, u_, opts : OptionsPattern[Plot]] :=
ParametricPlot[
Total@Table[
n!/(i! (n - i)!) u^i (1 - u)^(n - i) # & /@ pts, {i, 0, n}] /.
u -> x, {x, 0, 1}]

bezierPlot2[3, pts, u]


It failed

Lastly, I know that Mathematica has the built-in function BezierCurve:

Graphics[{BezierCurve[pts], Green, Line[pts], Red, Point[pts]}]


So my question is, how do I make my bezierPlot work normally?

f[n_, j_, u_] := PiecewiseExpand[BernsteinBasis[n, j, u]]
cv[pt_, n_, u_] := (f[n, #, u] & /@ Range[0, n]).pt


Test:

pts = {{0, 0}, {2, 4}, {4, 5}, {6, 0}};
ParametricPlot[cv[pts, Length@pts - 1, v], {v, 0, 1},
Epilog -> {Red, PointSize[0.02], Point[pts], Green, Line[pts]},
PlotRange -> {0, 6}]


Or

DynamicModule[{p = {{0, 0}, {2, 4}, {4, 5}, {6, 0}}},
LocatorPane[Dynamic[p], Dynamic@
ParametricPlot[cv[p, Length@p - 1, v], {v, 0, 1},
Epilog -> {Red, PointSize[0.02], Point[p], Green, Line[p]},
PlotRange -> {0, 6}], Appearance -> None]]


To plot:

bezplot[pt_, opts : OptionsPattern[Plot]] :=
ParametricPlot[cv[pt, Length@pt - 1, x], {x, 0, 1},
Epilog -> {Red, PointSize[0.02], Point[pt], Green, Line[pt]}, opts]


So,

bezplot[pts, PlotRange -> {0, 6}]


yields the first figure

• +1, Thanks very much. BTW, could you tell me why does my method cannot work. I'd like know which reason lead to the failture and I will avoid this mistake next time. :-)
– xyz
Sep 29, 2014 at 13:07
• @Tangshutao apologies for delay in replying (timezone issue)...you seem to have solved yourself with your answer Sep 30, 2014 at 8:28
• Dear ubpdqn, That's all right,it's my pleasure to learn from your solution.:-)
– xyz
Sep 30, 2014 at 9:32
• Hi, @ubpdqn, today, I discovered a difference between BezierCurve and our functions bezplot & bezierPlot, pts = {{0, 0}, {2, 4}, {4, 5}, {5, 5}, {6, 0}}; Graphics[{BezierCurve[pts], Green, Line[pts], Red, Point[pts]}] seemed give the wrong result in V8 and V9.Do you think is it a bug?
– xyz
Oct 1, 2014 at 10:28

I believe ...

bezierPlot1[n_, pts : {{_, _} ..}, opts : OptionsPattern[Plot]] :=
ParametricPlot[ Sum[BernsteinBasis[n - 1, i, u] pts[[i + 1]], {i, 0, n - 1}], {u, 0, 1}, opts]

pts = {{0, 0}, {2, 1}, {4, 3}, {6, 2}};
bezierPlot1[4, pts,  Epilog -> {Green, Line@pts, PointSize[Medium], Red, Point@pts},
PlotRange -> Evaluate[{Min @@ #, Max @@ #} & /@ Transpose@pts]]


• Dear belisarius, If I omit the n, namely, bezierPlot[pts : {{_, _} ..}, opts : OptionsPattern[Plot]] := Module[{n = Length@opts}, Show[ {ParametricPlot[ Sum[ BernsteinBasis[n - 1, i, u] pts[[i + 1]], {i, 0, n - 1}], {u, 0, 1}], Graphics[{Green, Line[pts], Red, Point[pts]}]}, opts] ] it will lost the Besier curve, Could you tell me? I alway confused when I encounter the condition.Thanks
– xyz
Sep 29, 2014 at 12:50
• n = Length@pts NOTE: pts not opts Sep 29, 2014 at 14:47
• @BobHanlon, Ok, thanks :-)
– xyz
Sep 30, 2014 at 1:52

Review

Table[BernsteinBasis[n, i, u] # & /@ pts, {i, 0, n}] was the main problem.

Revising

I use the MapIndexed to fill in the second argument in BernsteinBasis[n, i, u]

 bezierPlot[n_, pts : {{_, _} ..}, opts : OptionsPattern[Plot]] :=
ParametricPlot[
Total@MapIndexed[
BernsteinBasis[n, First@#2 - 1, u] #1 &, pts], {u, 0, 1},
Epilog -> {Red, PointSize[0.02], Point[pts], Green, Line[pts]}, opts]


Test

pts={{0, 0}, {2, 4}, {4, 5}, {6, 0}};
bezierPlot[3, pts, PlotRange -> {{0, 8}, {0, 6}}]


# Edit

bezierPlotSuper[n_, pts : {{_, _} ..}, opts : OptionsPattern[Plot]] :=
ParametricPlot[
Total@MapIndexed[
BernsteinBasis[n, First@#2 - 1, u] #1 &, pts], {u, 0, 1},
Epilog -> Join[
Text @@@ (Thread@{Table[Style[Subscript["P", i], 14], {i, 0, n}],
# + {.4, .2} & /@ pts}),
{Red, PointSize[0.01], Point[pts], Green, Line[pts]}], opts]


Test

bezierPlotSuper[3, {{2, 0}, {3, 4}, {4, 5}, {7, 8}},
PlotRange -> {{-1, 11}, {-1,11}}]