9
$\begingroup$

I have some control points and I could just plot the Bezier curve, but I also need to have the function! How can I get the exact function of the plotted Bezier curve?

$\endgroup$

3 Answers 3

12
$\begingroup$

In the documentation for BezierCurve, under Properties & Relations, it is written that a Bezier curve can be constructed from a sum of Bernstein polynomials. They give the following example:

pts = {{0, -1}, {1, 1}, {2, -1}, {3, 1}};
Graphics[BezierCurve[pts, SplineDegree -> 3], Frame -> True]

Mathematica graphics

f[t_] := Sum[pts[[i + 1]] BernsteinBasis[3, i, t], {i, 0, 3}]
ParametricPlot[f[t], {t, 0, 1}, Frame -> True, Axes -> False]

Mathematica graphics

You can read about this relationship on MathWorld.

$\endgroup$
0
2
$\begingroup$

In fact, you can just write f = BezierFunction[pts]. See BezierFunction.

$\endgroup$
2
  • $\begingroup$ Please note that BezierCurve is different from BezierFunction, and by default produces different result: (1), (2). $\endgroup$ Commented Aug 6, 2022 at 16:39
  • $\begingroup$ Get parametric polynomial expression for x and y with PiecewiseExpand g[t_] = f[t] // PiecewiseExpand // Simplify[#, 0 <= t <= 1] & yields {3 t, (-1 + 2 t)^3} . ParametricPlot[g[t], {t, 0, 1}, Frame -> True, Axes -> False, GridLines -> Automatic] Get y as a function of x Solve[Thread[{x, y} == {3 t, (-1 + 2 t)^3}], y, {t}] yields {{y -> 1/27 (-3 + 2 x)^3}} $\endgroup$
    – Akku14
    Commented Aug 7, 2022 at 4:23
2
$\begingroup$

I've made a function that can convert any BezierCurve of any degree into a set of curves, each parameterized from 0 to 1. First, convert the BezierCurve points to a new set of points:

compositeBezierPoints[bezierCurvePoints_, degree_Integer] :=
Select[
  Partition[bezierCurvePoints, UpTo[degree + 1], 1][[1 ;; -1 ;; degree]],
  Length[#] > 1 &]

compositeBezierPoints[bezierCurvePoints_, 1] :=
Select[
  Partition[bezierCurvePoints, UpTo[2], 1],
  Length[#] > 1 &]

If you input the points of the BezierCurve, and the degree (Automatic is degree 3), then compositeBezierPoints breaks up the points into a new set of points expected by BezierFunction. You would map BezierFunction over this list to get a list of functions that are each parameterized from 0 to 1. Here's a Manipulate showing the equivalence for a range of degrees:

pts = Table[{i, RandomReal[{-10, 10}]}, {i, 15}];
Manipulate[
  Show[
    Graphics[{Red, Point[pts]}], 
    ParametricPlot[
      Evaluate[Through[(BezierFunction /@ compositeBezier[pts, d])[t]]],
      {t, 0, 1}], 
    Graphics[{Black, Dashed, BezierCurve[pts, SplineDegree -> d]}]],
  {d, 1, 6, 1}]

You can re-parameterize the composite parts into a Piecewise function that itself runs from 0 to 1. I use BezierSymbolicFunction (found somewhere on MSE) to get the arc lengths in order to scale the segments:

BezierSymbolicFunction[pts_?MatrixQ] :=
Function[Evaluate[Sum[pts[[i+1]] BernsteinBasis[Length[pts]-1, i, #], {i, 0, Length[pts]-1}]]]

makeBezierPiecewise[bezierCurvePoints_, degree_Integer] :=
Module[{symbolicSegments, bezierSegments, lengths, ends},
  symbolicSegments = BezierSymbolicFunction /@ compositeBezier[bezierCurvePoints, degree];
  bezierSegments = BezierFunction /@ compositeBezier[bezierCurvePoints, degree];
  lengths = ArcLength[#[t], {t, 0, 1}]& /@ symbolicSegments;
  ends = Prepend[Accumulate[lengths/Total[lengths]], 0.];
  Function[Evaluate[
    Piecewise[
      Table[
        {
          bezierSegments[[i]][(#-ends[[i]])/(ends[[i+1]] - ends[[i]])],
          ends[[i]] < # <= ends[[i+1]]},
        {i, 1, Length[ends]-1}]]]]]
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.