13

To plot a BezierCurve in Mathematica, I need control points. But, I do not know the control points; I only know the points through which the Bézier curve passes. Take a simple example:

A Bézier curve goes through the 4 points (0,0), (2,1), (4,3) and (6,1). Find the two control points.

How would I go about finding the two control points in this example? The solution of this simple example will give me a clue on how to solve the general case.

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574
Bob Ueland
  • 1,059
  • 6
  • 16
  • Why do you insist on BezierCurve instead of Interpolation? – Szabolcs Sep 05 '16 at 10:53
  • What is your code? Because BezierCurve[pts] doesn't go through these four points. – Feyre Sep 05 '16 at 11:06
  • 1
    Because what I really want to do is to draw a Bezier curve containing hundred of points. I know the points that the curve passes through but in order to plot it I need the control points instead. If I can do it for a simple case of 4 points I will figure out how to do it for hundred of points. – Bob Ueland Sep 05 '16 at 11:06

2 Answers2

12

Here is my approach:

pts = {{0, 0}, {2, 1}, {4, 3}, {6, 1}};
paras = FoldList[Plus, 0, Normalize[(Norm /@ Differences[pts]), Total]] // N
mat = Outer[BernsteinBasis[3, #1, #2] &, Range[0, 3], paras] // Transpose;
ctrlpts = LinearSolve[mat, pts]
(* {{0., 0.}, {2.71043, -0.262717}, {3.94236, 6.32778}, {6., 1.}} *)

Graphics[{BezierCurve[ctrlpts], PointSize[Medium], Red, Point[pts]}]

Bézier

Comparison with Interpolation[]

To show that the results of the Bézier curve interpolant and the built-in Interpolation[] are vastly different, I will use the following data:

pts1 = {{-1, 0}, {2, 1}, {4, 4}, {6, -3}};
mat1 = Outer[BernsteinBasis[3, #1, #2] &, Range[0, 3], 
             FoldList[Plus, 0.0, 
                      Normalize[(Norm /@ Differences[pts1]), Total]]] // Transpose;

f = Interpolation[pts1]; Show[Plot[f[x], {x, -1, 6}], Graphics[{BezierCurve[LinearSolve[mat1, pts1]], PointSize[Medium], Red, Point[pts1]}], PlotRange -> {Automatic, {-3, 6}}]

comparison

xyz
  • 605
  • 4
  • 38
  • 117
  • Is the slight difference with Interpolation[] expected? – Feyre Sep 05 '16 at 11:13
  • Well that's what I plotted too, I just wondered if that was expected to happen. – Feyre Sep 05 '16 at 11:17
  • 5
    @Feyre Of course, they use the different algorithms(basis function). I think the Interpolation[] uses the classical Largrange interpolation strategy, while for the Bezier curve, it uses the Bernstein basis. – xyz Sep 05 '16 at 11:20
  • 1
    I'm sure you could find an example where the Interpolation result is vastly different. It might be worthwhile to show the comparison in the answer. – george2079 Sep 05 '16 at 12:25
  • 1
    The difference is only because you used chord length instead of the abscissas in setting up the linear system for the control points. – J. M.'s missing motivation Sep 03 '17 at 05:40
  • 1
    @J.M. is right : the visual difference between the 2 curves disappears when one replace FoldList[balh blah blah ...] by Rescale[First /@ pts1] in the code above. Nevertheless it is possible that the curves are mathematically different, for example because the default method used by Interpolation is "Hermite" instead of "Spline". – andre314 Apr 01 '18 at 22:18
  • @andre, in this specific case, the equivalence is clear, because there is a unique cubic polynomial that passes through four points. Thus, there should be a mapping between the Bézier version and the Interpolation[] version. For more than four points, what you have said is generally correct. – J. M.'s missing motivation Sep 28 '18 at 08:27
5

There's no need to resort to chord length parametrization as was done in the other answer for this simple interpolation problem.

pts = {{0, 0}, {2, 1}, {4, 3}, {6, 1}};
{xt, yt} = Transpose[pts];
cp = LinearSolve[Outer[BernsteinBasis[3, #2, #1] &, Rescale[xt], Range[0, 3]], yt]
   {0, -7/6, 20/3, 1}

Graphics[{{Directive[AbsoluteThickness[2], ColorData[97, 1]], 
           BezierCurve[Transpose[{xt, cp}]]},
          {Directive[AbsolutePointSize[6], ColorData[97, 2]], Point[pts]}}]

interpolating Bézier curve

An explanation for the following two results is left as an exercise for the interested reader:

if = Interpolation[pts];
Plot[if[x], {x, 0, 6}, 
     Epilog -> {Directive[AbsoluteThickness[2], ColorData[97, 2]],
                BezierCurve[Transpose[{xt, cp}]]}, 
     PlotStyle -> AbsoluteThickness[6]]

BezierCurve vs. InterpolatingFunction

Plot[if[x] - cp.BernsteinBasis[3, Range[0, 3], Rescale[x, MinMax[xt]]],
     {x, 0, 6}, Evaluated -> True, PlotRange -> All]

difference

J. M.'s missing motivation
  • 124,525
  • 11
  • 401
  • 574