# Variables substitution in a B-Spline function

I have the following identity mapping expressed by tensor-product B-spline basis functions:

pts = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1,1}, {0, 1}, {1, 1}};
k = {-1, -1, 0, 1, 1};
nBasis = Sqrt[Length[pts]];
basisU = Table[BSplineBasis[{1, k}, i, u], {i, 0, nBasis - 1}];
basisV = Table[BSplineBasis[{1, k}, i, v], {i, 0, nBasis - 1}];
tensorProductBasis = Table[basisU[[i]] basisV[[j]], {j, 1, nBasis}, {i, 1, nBasis}];
tensorProductBasis = ArrayReshape[%, {1, nBasis^2}][[1]];
map = Sum[pts[[i]] tensorProductBasis[[i]], {i, 1, nBasis^2}];


I have also NURBS representation of a circle:

pts = {{.5, 0}, {1, 0}, {1, 1}, {.5, 1}, {0, 1}, {0, 0}, {.5, 0}};
w = {1, .5, .5, 1, .5, .5, 1};
k = {0, 0, 0, 1/4, 1/2, 1/2, 3/4, 1, 1, 1};
circle = BSplineFunction[pts, SplineWeights -> w, SplineKnots -> k];


I need to substitute the identity map variables $u$ and $v$ by the first and second components of B-spline function representing a circle and get expression depending on one variable only. When I am trying to do like this:

newMap = map /. {u -> circle[t][[1]], v -> circle[t][[2]]};


I get an error:

Part::partw: "Part 2 of BSplineFunction[{{0.,1.}},<>][t] does not exist


Let me first try to rephrase the question to be sure we understand each other correctly.

You have a curve in the plane (circle in this case; cf. Fig. 1).

You deform a portion of the plane enclosing the curve (i.e., circle) with map and you would like to see what the curve looks like afterwards. (I took a map different from identity to demonstrate the difference in Fig. 2.)

Now to the answer. The first possibility (trying to minimize changes in the code) is just to change the definition of newMap as follows.

newMap[t_] := Module[{}, u = circle[t][[1]]; v = circle[t][[2]]; map]


This way we locally change the values of u and v to be what we need them to.

However, I am not very happy with this solution -- your map is a hard-wired to be a function of variables u and v. If you change u or v elsewhere in your notebook, you can destroy your result (as an example, set u to .7 and observe the whole thing crumble).

What I would propose instead is to rework your code to use built-in function BSplineFunction.

pts = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1,1}, {0, 1}, {1, 1}};
k = {-1, -1, 0, 1, 1};
nBasis = Sqrt[Length[pts]];
(* We need a two-dimensional array of control points: *)
CPs = Table[pts[[(i - 1)*nBasis + j]], {i, 1, nBasis}, {j, 1, nBasis}];
map = BSplineFunction[CPs, SplineDegree -> 1, SplineKnots -> k]


Now keeping your definition of circle, all you need to add is the definition of newMap.

newMap[t_]:=map[circle[t][[1]],circle[t][[2]]]


Of course, whether this is a good solution depends on what you are going to do with it later on. Good luck!

The solution is that you should have also used the NURBS representation for constructing the circle as well, since you already did it for the map. Let me first show a better way to build your mapping:

pts = {{-1, -1}, {0, -1}, {1, -1}, {-1, 0}, {0, 0}, {1, 0}, {-1, 1}, {0, 1}, {1, 1}};
k = {-1, -1, 0, 1, 1};
nBasis = Sqrt[Length[pts]];
basisU = Table[BSplineBasis[{1, k}, i, u], {i, 0, nBasis - 1}];
basisV = Table[BSplineBasis[{1, k}, i, v], {i, 0, nBasis - 1}];
map[u_, v_] = Flatten[Outer[Times, basisV, basisU]].pts;


Do something similar for the circle:

cpts = {{1/2, 0}, {1, 0}, {1, 1}, {1/2, 1}, {0, 1}, {0, 0}, {1/2, 0}};
cw = {1, 1/2, 1/2, 1, 1/2, 1/2, 1};
ck = {0, 0, 0, 1/4, 1/2, 1/2, 3/4, 1, 1, 1};
basisT = Table[BSplineBasis[{2, ck}, i - 1, t], {i, Length[cpts]}];
circ[t_] = (cw basisT).cpts/(cw.basisT);


Then, evaluate

ParametricPlot[map @@ circ[t], {t, 0, 1}]


and you should get the same figure as the one in grbl's answer. The differentiation you mentioned in a comment is expediently done as well:

ParametricPlot[D[map @@ circ[t], t] // Evaluate, {t, 0, 1}]


I have no idea what you are doing. The BSplineFunction needs to be evaluated a point. You could try

ClearAll[newMap]
newMap[t_] := map /. {u -> (circle[t] )[[1]], v -> (circle[t] )[[2]]};
ParametricPlot[newMap[t], {t, 0, 1}]


• Then I need to separate $x$- and $y$-components of the newMap, differentiate them w.r.t. $t$ and calculate the values of derivatives at a particular point. When I define functions derX[t_] := (newMap'[t])[[1]] and derY[t_] := (newMap'[t])[[2]] and try to calculate their values at a particular parameter value (e.g. derX[0.5] and derY[0.5]), I get unreasonable results. – S. S. Dec 3 '16 at 19:30