Is there a way to decompose a BSplineFunction output into two functions x[t], y[t] parametrizing the curve BSplineFunction[{{x1, y1}, {x2, y2}, ...}][t] in a form which allows easy calculation of derivatives of arbitrary order of x[t] and y[t] and of composite functions which use x[t] or y[t] like

f[t] = y''[t]/Sqrt[x'[t]^2+y'[t]^2]
f''[0.5]

etc. ?

Edit: I would also like to do this avoiding SetDelayed as much as it's possible.

up vote 8 down vote accepted

When manipulating B-splines in this manner, it is often convenient to fall back on the definitions. Luckily, since Mathematica supplies the function BSplineBasis[], using the definitions are easy:

pts = {{0, 0}, {1, 1}, {2, -1}, {3, 0}, {4, -2}, {5, 1}};

n = 3; (* B-spline degree *)
m = Length[pts];
(* clamped uniform knots for B-spline *)
knots = {ConstantArray[0, n + 1], Range[m - n - 1]/(m - n), ConstantArray[1, n + 1]}
        // Flatten;

{xu, yu} = Transpose[pts];
bs = BSplineFunction[pts, SplineDegree -> n];

(* B-spline component functions *)
f[t_] = xu.Table[BSplineBasis[{n, knots}, i - 1, t], {i, Length[pts]}];
g[t_] = yu.Table[BSplineBasis[{n, knots}, i - 1, t], {i, Length[pts]}];

Compare:

{ParametricPlot[bs[t], {t, 0, 1}, Axes -> None, Frame -> True,
                Epilog -> {Directive[AbsolutePointSize[5], Red], Point[pts]}], 
 ParametricPlot[{f[t], g[t]}, {t, 0, 1}, Axes -> None, Frame -> True,
                Epilog -> {Directive[AbsolutePointSize[5], Red], Point[pts]}]}

Spot the difference!

One can now plot the component functions as needed:

Plot[{f[t], g[t]}, {t, 0, 1}, Axes -> None, Frame -> True]

B-spline components

or use derivatives:

With[{t = 1/3}, g''[t]/Sqrt[f'[t]^2 + g'[t]^2]]
   48/Sqrt[41]
  • This is great, thank you so much! – level1807 Oct 27 '13 at 16:39

What about trying something like the following!

pts = {{1, 1}, {2, 3}, {3, -1}, {4, 1}, {5, 0}};
f = BSplineFunction[pts];
x[t_?NumericQ] := Module[{val}, val = f[t]; First@val];
y[t_?NumericQ] := Module[{val}, val = f[t]; Last@val];

Check it!

Plot[{x[t], y[t]}, {t, 0, 1}, Frame -> True]

enter image description here

Now the value you are looking for.

nf[t_?NumericQ] := y''[t]/Sqrt[x'[t]^2 + y'[t]^2];
nf''[0.5]

-758.244

BR

  • Wow, that's a simple and awesome idea! SetDelayed did half of the job, but Module is obviously the winner. Thanks! – level1807 Feb 7 '13 at 14:07
  • Though is there a way to do this without SetDelayed? I intend to use these functions in NDSolve inside Manipulate, thus SetDelayed is not welcome. x[t] by its nature is a known value, so why does it need to be SetDelayed? – level1807 Feb 7 '13 at 14:18

A BSplineBasis cannot be used as the weights can not be defined. Extracting the coordinates of a BSplineFunction is easy. Taking the derivatives is also easy, and extracting the coordinates of the derivatives is also easy, BUT the obtained values are wrong. Hence Plot[{extracted coordinates of the 1st derivative of the BSplineFunction, real coordinates of the function] gives a different result. Given a conic in a triangle {P0,P1,P2}, and the weight wi

f.e. the NURB is f2=BsplineFunction[{P0,P1,P2},2,{000,111},{1,wi,1}]

and f1[t_] = (P0*(1-t)*(1-t)+P1*wi*2*t*(1-t)+P2*tt)/ ((1-t)(1-t)+wi*2*t*(1-t)+t*t). We must have f2[t]==f1[t] for 0<= t <= 1. But when we plot the coordinates of derivatives the they are different ! Problem: if you want to convert a 3rd degree NURB (with non-uniform weights) to a 2nd degree NURB with knots {0,0,0,1/5, 1/5, 2/5, 2/5, 3/5, 3/5, 4/5, 4/5, 1, 1, 1} then you can not do it with Mathematica, because you need the 1st, 2nd and even the 3rd derivatives, because you need to calculate the inflection points, the best intermediate weights .

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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