4

I'm trying to visualize the construction of B-Spline functions by showing step by step how the curve is created. This involves painting curves similar to these: B-Spline plots

The function that creates the curve, which is defined recursive: Function formula

I tried to define t0 to t5 as a list \def\tvalues{{53,125,172,248,286,338,415}} and creating N_i^1(t) as a function that i can call:

\pgfmathdeclarefunction{bsplinebase}{}{\pgfmathparse{(and(#1>=\tvalues[#2], #1<\tvalues[#2+1]))}

which didn't work out so well. The problem seemed to be the list access, so i tried to rebuild this like described here:

\pgfmathdeclarefunction{bsplinebase}{2}{
\begingroup
\pgfmathparse{#2} 
\edef\arrayvalue{\pgfmathresult}
\pgfmathparse{\tvalues[\arrayvalue]}
\edef\lowvalue{\pgfmathresult}
\pgfmathparse{#2+1} 
\edef\brrayvalue{\pgfmathresult}
\pgfmathparse{\tvalues[\brrayvalue]}
\edef\highvalue{\pgfmathresult}
\pgfmathparse{(and(#1>=\lowvalue, #1<\highvalue))}%
\endgroup
}

Test draw:

\pgfplotsset{ymax=1, ymin=0, xmin=0, xmax=500}
\begin{tikzpicture}[samples=1000,scale=0.5]
\begin{axis}[xlabel=$x$,ylabel=$y$] 
  \addplot [mark=none] {bsplinebase(x, 3)}; 
  \addplot [mark=none] {bsplinebase(x, 4)}; 
\end{axis}
\end{tikzpicture}

Either way, I just got File ended while scanning use of \pgfflt@readlowlevelfloat. every time.
I'm out if ideas. How do I achieve a visualization similar to the one above with a given set of t-values and to be displayed N_i^k ?


(Image Sources: lecture material computer graphics of my university)


EDIT: I modified my solution according to Christian's answer, and it works for the base function. Next step is getting the recursive call working. So I did this:

\def\tvalues{{53,125,172,248,286,338,415}}

% N_i^1(t), param 1: t, param 2: i  
\pgfmathdeclarefunction{bsplinebase}{2}{\pgfmathparse{and(#1>=\tvalues[#2], #1<\tvalues[#2+1])}}

% N_i^k(t), param 1: t, param 2: i, param 3: k with k > 1
\pgfmathdeclarefunction{bsplinehigh}{3}{ %
    \pgfmathparse{ %
        ((#1-\tvalues[#2])/(\tvalues[#2+#3-1]-\tvalues[#2]))*bspline(#1,#2,#3-1)+((\tvalues[#2+#3]-#1)/(\tvalues[#2+#3]-\tvalues[#2+1]))*bspline(#1,#2+1,#3-1)%
    }
}
% N_i^k(t), param 1: t, param 2: i, param 3: k
\pgfmathdeclarefunction{bspline}{3}{\pgfmathparse{ifthenelse(#3 <= 1, bsplinebase(#1, #2), bsplinehigh(#1, #2, #3))}}

the call is basically the same (\addplot [mark=none] {bspline(x, 3, 1)}; and again for x, 4, 1), so it should only use the bsplinebase function since the third parameter should get the ifthenelse to use the first choice which is bsplinebase, and not bsplinehigh.
I also tried replacing the bsplinehigh-logic with a constant, in this case it successfully builds the pdf, but there isn't a plot and not even an axis.

The first error displayed is Package PGF Math Error: You've asked me to divide '-247.0' by '0.0', but I ca{53,125,172,248,286,338,415}[3+1]))*bspline(1,3+1,1-1)'). \addplot [mark=none] {bspline(x,3,1)}; which already seems broken. Also, he shouldn't even get in a situation where he HAS TO divide, as mentioned above.

Why doesn't this work? It should be completly the same like before, but the ifthenelse doesn't work as intended. My only guess is, that the else-case gets evaluated even though it isn't used, but I'm not sure if this is really true. And if it is, I need a way to prevent this.
EDIT: This question hints that it could be as I guessed.


Reading the answer for the above mentioned question, I tried to fix the evaluation problem like this:

\def\tvalues{{53,125,172,248,286,338,415}}

% N_i^1(t), param 1: t, param 2: i  
\pgfmathdeclarefunction{bsplinebase}{2}{\pgfmathparse{and(#1>=\tvalues[#2], #1<\tvalues[#2+1])}}

% N_i^k(t), param 1: t, param 2: i, param 3: k with k > 1
\pgfmathdeclarefunction{bsplinehigh}{3}{%
    \pgfmathparse{%
        (((#1-\tvalues[#2])/(\tvalues[#2+#3-1]-\tvalues[#2]))*bspline(#1,#2,#3-1)+((\tvalues[#2+#3]-#1)/(\tvalues[#2+#3]-\tvalues[#2+1]))*bspline(#1,#2+1,#3-1))%
    }
}
% N_i^k(t), param 1: t, param 2: i, param 3: k
\pgfmathdeclarefunction{bspline}{3}{%
    \ifnum#3<2\pgfmathparse{bsplinebase(#1,#2)}\else\pgfmathparse{bsplinehigh(#1,#2,#3)}\fi%
}

This works for my basespline case again, so now I added \addplot [mark=none] {bspline(x,0,2)};. Aaaaand, the next problem:
Missing = inserted for \ifnum. \addplot [mark=none] {bspline(x,0,2)};
I have no clue what's the problem.

EDIT: This question has the same problem, and now we're getting close!

4

The primary difficulty appears to be a weakness of the floating point unit in TeX -- it appears to be unable to handle the array syntax. Deactivating it by means of use fpu=false works.

Note that you code contains no domain argument -- your x argument is sampled with the default domain -5:5.

Adding both + some style changes (that I forgot to remove while experimenting with the code snippets) results in

\documentclass{standalone}

\usepackage{pgfplots}

\pgfplotsset{compat=1.13}

\begin{document}
\def\tvalues{{53,125,172,248,286,338,415}}
\pgfmathdeclarefunction{bsplinebase}{2}{\pgfmathparse{and(#1>=\tvalues[#2], #1<\tvalues[#2+1])}}

\begin{tikzpicture}[samples=1000]
\begin{axis}[
    use fpu=false,
    xlabel=$x$,ylabel=$y$,
    ymax=2, ymin=0, xmin=0, xmax=500,
    domain=0:500,
    ] 
  \addplot [mark=none] {bsplinebase(x, 3)}; 
  \addplot [mark=none] {bsplinebase(x, 4)}; 
\end{axis}
\end{tikzpicture}
\end{document}

enter image description here

  • thx, I'll try this out as soon as i can – TheFlow0360 Apr 29 '16 at 15:01
  • ehat does the compat=1.13? It#s not working for me, he says unknown choice in key... – TheFlow0360 Apr 30 '16 at 16:53
  • I tried to implement the changes, but ran into another problem - updated the question – TheFlow0360 Apr 30 '16 at 17:23
1

With Christian's help and a lot of searching around I managed to get it working!

The definition:

\def\tvalues{{53,125,172,248,286,338,415}}

% N_i^1(t), param 1: t, param 2: i  
\pgfmathdeclarefunction{bsplinebase}{2}{\pgfmathparse{and(#1>=\tvalues[#2], #1<\tvalues[#2+1])}}

% N_i^k(t), param 1: t, param 2: i, param 3: k with k > 1
\pgfmathdeclarefunction{bsplinehigh}{3}{%
    \pgfmathparse{%
        (((#1-\tvalues[#2])/(\tvalues[#2+#3-1]-\tvalues[#2]))*bspline(#1,#2,#3-1)+((\tvalues[#2+#3]-#1)/(\tvalues[#2+#3]-\tvalues[#2+1]))*bspline(#1,#2+1,#3-1))%
    }
}
% N_i^k(t), param 1: t, param 2: i, param 3: k
\pgfmathdeclarefunction{bspline}{3}{%
    \pgfmathparse{#3>1 ? 0 : 1}%
    \ifnum\pgfmathresult=1\pgfmathparse{bsplinebase(#1,#2)}\else\pgfmathparse{bsplinehigh(#1,#2,#3)}\fi%
}

And the call:

\pgfplotsset{ymax=2, ymin=0, xmin=1,xmax=500}
\begin{tikzpicture}[samples=1000]
\begin{axis}[
    use fpu=false,
    xlabel=$x$,ylabel=$y$,
    ymax=2, ymin=0, xmin=1, xmax=500,
    domain=1:500,
    ] 
    \addplot [mark=none] {bspline(x,3,1)}; 
    \addplot [mark=none] {bspline(x,4,1)};
    \addplot [mark=none] {bspline(x,0,2)};  
    \addplot [mark=none] {bspline(x,4,2)};
    \addplot [mark=none] {bspline(x,1,3)};  
\end{axis}
\end{tikzpicture}

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.