I've made a function like what @yu-sung-chang was suggesting.
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}]]]]]
SplineDegree
which is explicitly mentioned in the docs forBezierFunction
is then completely misleading because it suggests that the function works just likeBezierCurve
. So my guess is that they did mean to make these two functions work the same way, but forgot to partition the argument lis ofBezierFunction
according to theSplineDegree
when it's explicitly given. $\endgroup$