Providing a set of 2D points to BSplineFunction returns a function that requires that the input parameter to the function be between [0,1] no matter what the original domain of the points. In the 2D case that I'm interested in, what is returned from this function are two values: a value in the original units of the domain and its functional value. In other words an x and a y. I am primarily interested in finding the functional value associated with particular domain values. I have seen this before in this forum for example: Does anyone know a better approach than what follows? I have seen essentially a similar question posed before. It seems there is no direct way to provide a domain value and get its functional value. Here's a way to do it but it is slow and computationally expensive:

    (* p = 2D matrix of points*)
    (* f = Function returned by BSplineFunction *)
    (* bsp = A table of 301 returned values providing f with values from \
      [0,1] in increments of 1/300 *)
    (* tstf = A function that returns the first of the two values \
       returned by f (which is a value in the domain of the points p). *)
    (* a= A table of values between [0,1] that minimizes the squared \
       difference between the domain value I want and what is output by f. *)
    (* xy = 2D matrix containing the domain values I desire in the first \
       column and their functional values in the second column. *)

    p = {{400, 0}, {428, 0}, {477, 0}, {545, .5}, {596, 0}, {639,0}, {700,0}};
    f = BSplineFunction[p];
    bsp = Table[f[t], {t, 0, 1, 1/300}];
    tstf[t_?NumericQ] := f[t][[1]];
    a = Table[ u /. NMinimize[{(tstf[u] - k)^2, 0 <= u <= 1}, u][[2]], {k,400,700}];
    xy = Table[{k + 399, f[a[[k]]][[2]]}, {k, 1, 301}];

Here's a plot of bsp:

plot 1

Here's a plot of xy:

plot 2

They look identical but for bsp the x-values are given by f with values determined by using [0,1] stepping from 0 to 1 in equal increments of 1/300. The returned domain values are not the integer values in xy. Does anyone have a better solution than finding those [0,1] values that produce a specific domain value as I am with NMinimize?

  • 1
    $\begingroup$ What you have done is essential how it needs to be done. We could probably think of ways to speed it up a bit, but in the end you are finding a lot of roots of cubic polynomials. $\endgroup$
    – george2079
    Apr 15 '16 at 20:47

this is essentially the same, but a good bit faster, first tabulate the curve to get good starting values then use FindRoot:

tab = Table[{u, tstf[u]}, {u, 0, 1, .01}];
start = (tab[[# - 1, 1]] &@
      First@FirstPosition[tab, {u_, v_ /; v > #}]) & /@ 
   Range[400, 699];
AppendTo[start, 1];
a = Table[(u /. FindRoot[tstf[u] == k, {u, start[[k - 399]]}]),
       {k, 400,700}];
ListPlot[f /@ a]

enter image description here

verify we found all the integers:

Max[Abs[(f /@ a)[[All, 1]] - Range[400, 700]]]



Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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