Bézier Curves

Adam Rumpf, 9/8/2017

Introduction

This module defines several functions that show Bézier curves being drawn. All of the main functions produce a Manipulate environment with a slider to move the convex parameter t between 0 and 1. This slider can be animated to watch the drawing process unfold. All of the paths connecting control points are shown moving, and the Bézier curve, itself, is shown being drawn in black.

The bezier[] function accepts a direct list of control points, expressed as an array of ordered pairs of coordinates. The circlebezier[] function accepts a positive integer and produces a Bézier curve with the specified number of control points arranged in a circle. The dragbezier[] function accepts a nonnegative integer and produces a random arrangement of the specified number of control points, which may then be clicked and dragged to move them.

Code

Initialization

(* Calculates the point fraction t between points x1 and x2. *)
midpoint[x1_,x2_,t_]:={(1-t) x1[[1]]+t x2[[1]],(1-t) x1[[2]]+t x2[[2]]}
(* Given a list of points, calculates the sequence of points fraction t between each consecutive pair of points. *)
iterate[p_,t_]:=Module[{out=ConstantArray[{},Length[p]-1],i},
For[i=1,i≤Length[p]-1,i++,
out[[i]]=midpoint[p[[i]],p[[i+1]],t];
];
out
]
(* Produces graphics objects for the lines and points, for a given t. *)
linegen[in_,t_,d_:Infinity]:=Module[{p,col},
p=pointgen[in,t,d];
col=Table[Hue[N[1-(k-1)/Length[p]]],{k,1,Length[p]}];
Graphics[Join[Riffle[Table[col[[k]],{k,1,Length[p]}],Table[Line[p[[k]]],{k,1,Length[p]}]],Riffle[Table[col[[k]],{k,1,Length[p]}],Table[Point[p[[k,ell]]],{k,1,Length[p]},{ell,1,Length[p[[k]]]}]],If[Length[p[[-1]]]==1,{Black,PointSize[Medium],Point[p[[-1,1]]]},{}]]]
]
(* Finds the points of all intermediate curves, for a given t, using control points in.  d is the number of layers down to go (so d=1 means only showing the control points, which involve no animation). *)
pointgen[in_,t_,d_:Infinity]:=Module[{p={in},i=1},
While[i<Length[in]&&i<d,
i++;
p=Join[p,{iterate[p[[i-1]],t]}];
];
p
]
(* Produces a list of n points describing traced by the jth point in the ith iteration, given control points in, as t varies from 0 to 1. *)trace[in_,i_,j_,n_]:=Table[N[pointgen[in,t,i][[i,j]]],{t,0,1,1/(n-1)}]
(* Produces a graphics object to follow a list of points, using a specified color, and showing only the first ell points. *)
connect[in_,i_,j_,n_,ell_,col_:Black]:=Graphics[Join[{col},{Line[trace[in,i,j,n][[1;;ell]]]}]]
(* Produces an animation of the form described at the top. *)
bezier[p_,d_:Infinity,show_:True,n_:101]:=Manipulate[Show[If[show==True,connect[p,Length[p],1,n,Floor[(n-1)t]+1],{}],linegen[p,t,d]],{t,0,1,1/(n-1)}]
(* Generates a particular set of Bezier curves for approximating a circle. *)
circlebezier[n_,show_:True,m_:101]:=bezier[Table[{Cos[-2Pi k/n-Pi/2],Sin[-2Pi k/n-Pi/2]},{k,0,n}],Infinity,show,m]
(* Specify a number of points, and the user can drag the points around. *)dragbezier[num_,d_:Infinity,show_:True,n_:101]:=Manipulate[Show[If[show==True,connect[p,Length[p],1,n,Floor[(n-1)t]+1],{}],linegen[p,t,d],PlotRange->{{0,1},{0,1}}],{t,0,1,1/(n-1)},{{p,RandomReal[1,{num,2}]},Locator}]

Demonstration

(* Directly inputting control points *)
bezier[{{0,0},{1,1},{2,0},{3,0}}]

(* Inputting a calculated set of control points *)
bezier[Riffle[Table[{Cos[2Pi k/3],Sin[2Pi k/3]},{k,0,3}],Table[3*{Cos[2Pi k/3+Pi/3],Sin[2Pi k/3+Pi/3]},{k,0,2}]]]

(* Circle of 5 control points *)
circlebezier[5]

(* Moveable arrangement of 6 control points *)
dragbezier[6]