7

I have this clumsy code to plot the height of a bouncing ball over time. Is there a possibility for optimization? Perhaps writing the functions directly with the tikz math library? Also at the moment negative time input can't be handled. And how can macros with more then one input argument call lua code?

\documentclass[tikz]{standalone}
\usepackage{fontspec}
\usepackage{pgfplots}
\usepackage{luatextra}

\begin{luacode}
  function height(h0, idx)
    return h0*(3/4)^(math.abs(idx))
  end
  function time(h0, idx)
    t = math.sqrt(2*height(h0, 0)/9.81)
    for i=1,idx,1 do
      t = t+2*math.sqrt(2*height(h0, i)/9.81)
    end
    return t
  end 
  function offset(h0, idx)
    o = 0
    if idx > 0 then
      o = time(h0, idx-1)+(time(h0, idx)-time(h0, idx-1))/2
    end
    return o
  end
\end{luacode}

\makeatletter
\pgfmathdeclarefunction{luaheight}{1}{%
  \begingroup
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=sci}%
    \pgfmathparse{#1}%
    \edef\pgfmathresult{\directlua{tex.print("" .. height(10,\pgfmathresult))}}%
    \pgfmathsmuggle\pgfmathresult%
  \endgroup
}%
\pgfmathdeclarefunction{luatime}{1}{%
  \begingroup
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=sci}%
    \pgfmathparse{#1}%
    \edef\pgfmathresult{\directlua{tex.print("" .. time(10,\pgfmathresult))}}%
    \pgfmathsmuggle\pgfmathresult%
  \endgroup
}%
\pgfmathdeclarefunction{luaoffset}{1}{%
  \begingroup
    \pgfkeys{/pgf/fpu,/pgf/fpu/output format=sci}%
    \pgfmathparse{#1}%
    \edef\pgfmathresult{\directlua{tex.print("" .. offset(10,\pgfmathresult))}}%
    \pgfmathsmuggle\pgfmathresult%
  \endgroup
}%
\makeatother

\begin{document}
\begin{tikzpicture}
\begin{axis}
  \addplot[domain=0:luatime(0)] {luaheight(0)-9.81/2*x^2};
  \foreach \p in {1,...,5} {
    \addplot[domain=luatime(\p-1):luatime(\p)] {luaheight(\p)-9.81/2*(x-luaoffset(\p))^2}; 
  }    
\end{axis}
\end{tikzpicture}
\end{document}

And it looks like this:

enter image description here

Reza
  • 1,798

2 Answers2

9

After some math (keyword is geometric series) I found an analytical solution to calculate the time passed. Now there is a neat solution, but it's way slower then the first one.

\documentclass[tikz]{standalone}
\usepackage{fontspec}
\usepackage{pgfplots}
\usepackage{luatextra}
\begin{document}
\begin{tikzpicture}[
  declare function={
    bounce(\hz,\idx) = \hz*(3/4)^\idx;
    duration(\hz,\idx) = sqrt(2*\hz/9.81)*(1+sqrt(3)*(1-sqrt(3/4)^\idx)/(1-sqrt(3/4)));
    offset(\hz,\idx) = duration(\hz,\idx-1)+(duration(\hz,\idx)-duration(\hz,\idx-1))/2;
    flight(\hz,\idx,\t) = bounce(\hz,\idx)-9.81/2*(\t-offset(\hz,\idx))^2;
  }
]
  \begin{axis}[
      xmin=0, xmax=20,
      ymin=0, ymax=12,
      thick,
      axis lines=left,
      xtick={14.047},
      %xtick={{duration(10,8)}},
      xticklabels={$t_c$},
      yticklabels={},
      xlabel={Zeit},
      ylabel={Höhe},
      tick style=transparent,
  ]
    \addplot[red,domain=0:{duration(10,0)}] {bounce(10,0)-9.81/2*\x^2};
    \addplot[dashed,gray]coordinates {({duration(10,8)},0) ({duration(10,8)},12)};
    \foreach \p in {9,...,20} {
      \addplot[domain={duration(10,\p-1)}:{duration(10,\p)}] {flight(10,\p,\x)}; 
    }
    \foreach \p in {1,...,8} {
      \addplot[red,domain={duration(10,\p-1)}:{duration(10,\p)}] {flight(10,\p,\x)}; 
    }
    \addplot[red]coordinates{({duration(10,8)},0) (20,0)};
  \end{axis}
\end{tikzpicture}
\end{document}

It looks like this:

enter image description here

Why can't I call a declared function in the xtick?

Reza
  • 1,798
  • I found the problem with xtick, æpgfmath is not expandable: http://tex.stackexchange.com/questions/20265/pgfmath-expansion-call-a-command-from-within-a-pgfmath-environment the solution is to use a macro and call it before setting the xtick with the result. – Reza Feb 02 '14 at 08:53
5

With PSTricks just for fun. The remaining trivial parts are intentionally left for the sake of simplicity.

\documentclass[pstricks,border=12pt]{standalone}
\SpecialCoor
\psset{linecolor=red}
\begin{document}
    \begin{pspicture}(11,10)
        \foreach \i in {0,...,10}{\parabola(\i,0)(!\i\space .5 add  10 .65 \i\space exp mul)}
    \end{pspicture}
\end{document}

enter image description here