BSplineFunction derivatives wrong if using weights?
Yes, there seems to be a bug in there.
You still may use BSplineFunction
if you are OK with numerical results:
<< NumericalCalculus`
d = 2;
kV = {0, 0, 0, 1, 1, 1}; P = {{0, 0}, {0, 1}, {1, 1}}; W = {1, 1/Sqrt[2], 1};
x[t_] := BSplineFunction[P[[All, 1]], SplineWeights -> W, SplineDegree -> d, SplineKnots -> kV][t] /; 0 < t < 1
x[r_] := 0 /; r <= 0
x[r_] := 1 /; r >= 1
Plot[{x[t], ND[x[u], u, t, Scale -> .0001]}, {t, 0, 1}, Evaluated -> True]
One does not need a solution as drastic as george's for this case; after all, BSplineBasis[]
is a built-in function. You can thus easily fall back on the definition of a NURBS curve:
x[t_] = (P[[All, 1]].(W Table[BSplineBasis[{d, kV}, j - 1, t], {j, Length[P]}]))/
(W.Table[BSplineBasis[{d, kV}, j - 1, t], {j, Length[P]}]);
y[t_] = (P[[All, 2]].(W Table[BSplineBasis[{d, kV}, j - 1, t], {j, Length[P]}]))/
(W.Table[BSplineBasis[{d, kV}, j - 1, t], {j, Length[P]}]);
Plot[{x'[t], y'[t]}, {t, 0, 1}, Frame -> True,
PlotStyle -> {RGBColor[7/19, 37/73, 22/31], RGBColor[59/67, 11/18, 1/7]}]
This also has the advantage of giving exact results if the input and the starting data (knots, weights, and control points) are all exact.
The definition of B-Spline curve
$$\vec{C}(u)=\sum _{i=0}^n N_{i,p}(u) \vec{P}_i \text{ }\qquad (0\leq u\leq 1)$$
where, $\vec{P}_i$ is the control point, and the $N_ {i, p} (u)$ are the $p$-th - degree B-spline basis functions defined on the non-periodic(and non-uniform) knot vector $U$.
$$U=\{\underbrace {0,\cdots ,0}_{p+1},u_{p+1},\cdots u_{m-p-1},\underbrace {1,\cdots,1}_{p+1}\}$$
For the non-rational B-spline curve of degree $p$, its derivative is a $p-1$ degree non-rational curve. where, the new control points and knot vector are $Q_i$ and $U'$, respectively. $$\vec Q_i=p \frac{\vec P_{i+1}-\vec P_i}{u_{i+p+1}-u_{i+1}}$$
$$U'=\{\underbrace {0,\cdots ,0}_{p},u_{p+1},\cdots u_{m-p-1},\underbrace {1,\cdots,1}_{p}\}$$
I think the built-in f = BSplineFunction[2D/3D-points vector]; f'
just returns a non-rational curve.
However, for the rational B-spline curve: $$\vec{C}^w(u)=\frac{\sum_{i=0}^n N_{i,p}(u)w_i\vec{P}_i}{\sum_{i=0}^n N_{i,p}(u)w_i}=\frac{\vec{A}(u)}{w(u)}$$
where, $\vec P_i=\{x_i, y_i\}$(2D curve) or $\vec P_i=\{x_i, y_i,z_i\}$(3D curve). Then
$$\left[\vec{C}^w(u)\right]'=\left[\frac{\vec A(u)}{w(u)}\right]'=\frac{\vec A'(u)w(u)-\vec A(u)w'(u)}{w^2(u)}$$
The derivative of built-in BSplineFunction[]
for curve case is right when the weights
is vector that contains same value. Namely, the curve is non-rational.
Here, ptsW = wi {xi, yi, zi}
BSplineDer[pts_, wgts_, {deg_, knots_}][u_?NumericQ] :=
Module[{ptsW, A, w, Au, wu, AuDer, wuDer},
ptsW = pts wgts;
A = BSplineFunction[ptsW, SplineDegree -> deg, SplineKnots -> knots];
w = BSplineFunction[wgts, SplineDegree -> deg, SplineKnots -> knots];
(*calculate the A(u) and w(u)*)
Au = A[u];
wu = w[u];
(*calculate the derivative of A(u) and w(u)*)
AuDer = A'[u];
wuDer = w'[u];
(*using the NURBS curve derivative formula*)
(wu AuDer - wuDer Au)/wu^2
]
TEST
pts = {{1, 1}, {2, 3}, {3, -1}, {4, 1}, {5, 0}};
wgts = {1, 2, 3, 4, 5};
knots = {0, 0, 0, 0, 0.5, 1, 1, 1, 1};
f = BSplineFunction[pts, SplineDegree -> 3, SplineWeights -> {1, 2, 3, 4, 5}]
Show[
{ParametricPlot[f[t], {t, 0, 1}],
Graphics[
{Red, Dashed, Arrowheads[0.03],
Table[Arrow[{f[t], f[t] + BSplineDer[pts, wgts, {3, knots}][t]/7}], {t, 0, 1, 0.1}]}],
ListPlot[f /@ Range[0, 1, 0.1],
PlotStyle -> Directive[Black, PointSize[Medium]]]},
PlotRange -> All, Axes -> False
]
Using gdir's data to test BSplineDer[]
BSplineDer[Pts, w, {5, U}][160]
f = BSplineFunction[Pts, SplineDegree -> p, SplineKnots -> U, SplineWeights -> w]
Needs["NumericalCalculus`"]
ND[f[u], u, 160]