%% This is the package dsptricks
%%
%% (c) Paolo Prandoni <paolo.prandoni _at_ epfl.ch>
%%
%% This program can be redistributed and/or modified under the terms
%% of the LaTeX Project Public License Distributed from CTAN archives
%% in directory macros/latex/base/lppl.txt.
%%
%% DESCRIPTION:
%%   `dsptricks' is a LaTeX package based on PSTricks to plot discrete- and continuous-time
%%       signals, pole-zero plots and DSP block diagrams. The package has been developed 
%%       while writing the textbook "Signal Processing for Communication" by P. Prandoni
%%       and M. Vetterli, freely available at www.sp4comm.org
%%
%% v1.0, July 2014
%%
\RequirePackage{pstricks}
\RequirePackage{pstricks-add}
\RequirePackage{pst-xkey}
\RequirePackage{calc}
\RequirePackage{fp}
\RequirePackage{ifthen}
%
\ProvidesPackage{dsptricks}[2014/07/24 package for signal processing graphics]

% turn off FP messages
\FPmessagesfalse

\makeatletter

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Sizes and units:
%%
%% default values for plot size
%%
\newlength{\dspWidth}\setlength{\dspWidth}{0.7\textwidth}
\newlength{\dspHeight}\setlength{\dspHeight}{0.43\dspWidth}
\def\dspAxisColor{black}
%
%% Actual size (this is the size of the chart's frame, labels are extra)
\newlength{\dspW}
\newlength{\dspH}
%% Basic Unit is a function of plot size
\newlength{\dspBU}
%% Derived units:
\newlength{\dspLineWidth}
\newlength{\dspStemWidth}
\newlength{\dspDotSize}
\newlength{\dspTickLen}
\newlength{\dspXTickGap}
\newlength{\dspYTickGap}
\newlength{\dspTickLineWidth}
\newlength{\dspFrameLineWidth}
%% psTricks units
\newlength{\dspUnitX}
\newlength{\dspUnitY}
\newlength{\dspTmpLen}
%% booleans
\newif\ifXTicks
\newif\ifDoXTicks
\newif\ifYTicks
\newif\ifDoYTicks
\newif\ifXLabel
\newif\ifYLabel
\newif\ifXAxisExp
\newif\ifYAxisExp
\newif\ifXAxisFreq
\newif\ifXInside

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% dspPlot environment:
%%
%% \begin{dspPlot}[OPTIONS]{xMin, xMax}{yMin, yMAx}
%%
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Keys for data plots :
%%
\define@key{dspDP}{width}{\setlength{\dspW}{#1}}
\define@key{dspDP}{height}{\setlength{\dspH}{#1}}
\define@key{dspDP}{xlabel}{\def\dspXLabel{#1}\XLabeltrue}
\define@key{dspDP}{ylabel}{\def\dspYLabel{#1}\YLabeltrue}
\define@key{dspDP}{rlabel}{\def\dspYLabelR{#1}\YLabeltrue} % right-side y-axis label
\define@key{dspDP}{sidegap}{\def\sg{#1}}
\define@choicekey*+{dspDP}{xtype}[\ll\ln]{time,freq}[time]{%
  \ifcase\ln\relax
    \XAxisFreqfalse
  \or
    \XAxisFreqtrue
  \fi}{}
\define@choicekey*+{dspDP}{xticks}[\ll\ln]{auto,none,custom}[auto]{%
  \DoXTickstrue\XTickstrue\def\incX{-1}\def\piFrac{2}
  \ifcase\ln\relax
    \relax
  \or
    \DoXTicksfalse\XTicksfalse
  \or
    \DoXTicksfalse
  \fi}{%
  \DoXTickstrue\XTickstrue
  \def\incX{#1}\def\piFrac{#1}}
\define@choicekey*+{dspDP}{yticks}[\ll\ln]{auto,none,custom}[auto]{%
  \DoYTickstrue\YTickstrue\def\incY{-1}
  \ifcase\ln\relax
    \relax
  \or
    \DoYTicksfalse\YTicksfalse
  \or
    \DoYTicksfalse
  \fi}{%
  \DoYTickstrue\YTickstrue
  \def\incY{#1}}
\newif\ifXTicksOut
\define@key{dspDP}{xout}{\XTicksOuttrue}
\define@key{dspDP}{inticks}{\XInsidetrue}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% dspPlot environment
%%
\newenvironment{dspPlot}[3][]{%
% default values
  \def\dspXlabel{}\XLabelfalse%
  \def\dspYLabel{}\def\dspYLabelR{}\YLabelfalse%
  \XAxisFreqfalse%
  \XTicksOutfalse%
  \setlength{\dspW}{\dspWidth}\setlength{\dspH}{\dspHeight}%

  \presetkeys{dspDP}{xticks=auto,yticks=auto}{}%
  \presetkeys{dspDP}{sidegap=-1}{}%
  \setkeys{dspDP}{#1}%
%%
%% set up
  \ifXAxisFreq\def\sg{0} \fi%
  \dspSetDims#2,#3,\sg\relax%
  \dspSetupAxes
%%
%% special x-axis for frequency plots
  \ifXAxisFreq\FPset\incX{1}%
    \ifXAxisExp%
      % x-axis is not on bottom; skip last values
      \FPupn\stX{\dspMinX{} \piFrac{} * 1 + 0 trunc}%
      \FPupn\tlimX{\stX{} \dspMaxX{} \piFrac{} * - 0 trunc}%
    \else%
      \FPupn\stX{\dspMinX{} \piFrac{} * 0 trunc}%
      \FPupn\tlimX{\stX{} \dspMaxX{} \piFrac{} * - 1 + 0 trunc}\relax\fi%
    %
    \ifXTicksOut% undo above if ticks explicitly out
      \FPupn\stX{\dspMinX{} \piFrac{} * 0 trunc}%
      \FPupn\tlimX{\stX{} \dspMaxX{} \piFrac{} * - 1 + 0 trunc}\relax\fi
    %
    \def\thisTickX##1{%
      \FPupn\u{\piFrac{} ##1 /}%
      \psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](\u,\haY)(\u,\tickEndX)}
    \def\thisTickLabelX##1##2{%
      \FPupn\u{\piFrac{} ##1 /}%
      \rput*[B]{{0}}(\u,\tickTxtX){{\simplifyPiFrac{##1}{\piFrac}}}}%
  \else
    \def\thisTickX{\dspTickX}\def\thisTickLabelX{\dspTickLabelX}\relax\fi
%%
%% start the plot
  \begin{pspicture}(\LX,\BY)(\RX,\TY)
    %\showpointstrue
    %\psframe[dimen=middle,linewidth=1pt,linecolor=red](\LX,\BY)(\RX,\TY)%
    \ifXAxisExp\psline[linewidth=\dspFrameLineWidth,linecolor=\dspAxisColor](\dspMinX,0)(\dspMaxX,0)\fi
    \dspPlotFrame
%%
%% draw ticks selectively according to user options
    \ifDoXTicks\multido{\n=\stX+\incX}{\tlimX}{\thisTickX{\n}}\fi
    \ifDoYTicks\multido{\n=\stY+\incY}{\tlimY}{\dspTickY{\n}}\fi
}{%
%% tick labels
    \psset{xunit=\dspUnitX,yunit=\dspUnitY} %user may have changed those
    \ifDoXTicks\multido{\n=\stX+\incX}{\tlimX}{\thisTickLabelX{\n}{$\n$}}\fi
    \ifDoYTicks\multido{\n=\stY+\incY}{\tlimY}{\dspTickLabelY{\n}{$\n$}}\fi
    \dspLabels
\end{pspicture}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Custom ticks
%%
%% \dspCustomTicks[axis={x|y}]{value label ...}
%%
%% if using macros for values, enclose them in curly braces:
%% \def\a{1 }
%% \dspCustomTicks{{\a} 1}
%%
\define@choicekey*{dspCT}{axis}[\ll\ln]{x,y,ry}[x]{%
  \def\dspCA{\ln}}
\define@key{dspCT}{color}{\def\tickColor{#1}}
\newcommand{\dspCustomTicks}[2][]{%
  \presetkeys{dspCT}{axis=x,color=black}{}%
  \setkeys{dspCT}{#1}%
  \ifcase\dspCA\relax%
    \def\dspMkTk##1##2{\dspTickX{##1}{\dspTickLabelX{##1}{##2}}}%
  \or
    \def\dspMkTk##1##2{\dspTickY{##1}{\dspTickLabelY{##1}{##2}}}%
  \or
    \def\dspMkTk##1##2{{\dspTickLabelYR{##1}{##2}}}%
  \fi
  \def\dspMakeTicks##1 ##2 ##3\relax{%
    \ifx&##3&
      \dspMkTk{##1}{##2} %
    \else
     \dspMkTk{##1}{##2} \relax %
      \dspMakeTicks##3\relax%
    \fi}%
    \dspMakeTicks#2 \relax}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Draw legend
%%
%% \dspLegend(x,y){color label color label ...}
%%
\def\dspLegend(#1,#2)#3{%
  \rput[lt](#1,#2){\fbox{%
    \begin{tabular}{ll}
      \@dsplegend#3 \@empty
    \end{tabular}}}}
\def\@dsplegend#1 #2 #3{%
   {\color{#1}\rule[0.5ex]{2em}{2pt}} & #2\\ \space  % fbox here to have a visual test
   \ifx #3\@empty\else
    \expandafter\@dsplegend
   \fi
   #3}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Redraw frame around plot
%%
\newcommand{\dspPlotFrame}{
  \psframe[dimen=middle,linewidth=\dspFrameLineWidth,linecolor=black]%
    (\dspMinX,\dspMinY)(\dspMaxX,\dspMaxY)}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Environment to clip plots to within the frame box. Do not leave
%%  spaces in the environment's body otherwise graph will shift
%%
\newenvironment{dspClip}{%
  \psclip{\psframe[dimen=middle,linestyle=none](\dspMinX,\dspMinY)(\dspMaxX,\dspMaxY)}}{%
  \endpsclip}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plotting discrete-time signals in the  dspPlot environment:
%%
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Keys for plotting functions (these are set together with pstricks keys
%%  so they must use the [psset] prefix and be declared)
%%
%%   xmin=N,
%%   xmax=N       range for the plotted signal
%%
\define@key[psset]{dspData}{xmin}{\def\dspXmin{#1}}
\define@key[psset]{dspData}{xmax}{\def\dspXmax{#1}}
\pst@addfams{dspData}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot discrete-time points
%%
%% \dspTaps[OPTIONS]{x1 y1 x2 y2 ...}
%%
\newcommand{\dspTaps}[2][]{%
  \listplot[plotstyle=LineToXAxis, linestyle=solid,%
    showpoints=true, dotstyle=*, linewidth=\dspStemWidth,%
    dotsize=\dspDotSize, #1]{\expandafter\m@keList#2 \relax}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot discrete-time points starting at a given abscissa
%% Data in this case is only ordinates
%%
%% \dspTapsAt{x0}{y0 y1 y2,...}
%%
\newcommand{\dspTapsAt}[3][]{%
  % use postscript to iterate over space-separated list and create indices
  \listplot[plotstyle=LineToXAxis, linestyle=solid,%
      showpoints=true, dotstyle=*, linewidth=\dspStemWidth,%
      dotsize=\dspDotSize, #1]{%
  #2
  [#3] {    % n []
            % n a0
    1 index % n a0 n
    1 add
  } forall
  pop
}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot discrete-time signal from a data file
%%
%% \dspTapsFile[OPTIONS]{FILE}
%%
\newcommand{\dspTapsFile}[2][]{%
  \readdata{\data}{#2}%
  \listplot[plotstyle=LineToXAxis, linestyle=solid,%
            showpoints=true, dotstyle=*,%
            linewidth=\dspStemWidth, dotsize=\dspDotSize,%
            #1]{\data}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot discrete-time signal
%%
%% \dspSignal[OPTIONS]{PS code}
%%
\newcommand{\dspSignal}[2][]{%
  \presetkeys[psset]{dspData}{xmin=\dspMinActX, xmax=\dspMaxActX}{}%
  \setkeys*[psset]{dspData}{#1}%
  \FPupn\mn{{\dspXmin} 0 trunc clip }%
  \FPupn\mx{{\dspXmax} 0 trunc clip }%
  \FPupn\ntaps{\mn{} \mx{} - 1 + 0 trunc clip}%
  \psplot[plotstyle=LineToXAxis, linestyle=solid,%
          showpoints=true, dotstyle=*,%
          linewidth=\dspStemWidth, dotsize=\dspDotSize,%
          plotpoints=\ntaps, #1]%
          {\mn}{\mx}{#2}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot discrete-time signal with postscript initialization options
%%
%\dspSignalOpt[OPTIONS]{PS init code}{PS code}
%%
\newcommand{\dspSignalOpt}[3][]{%
  \presetkeys[psset]{dspData}{xmin=\dspMinActX, xmax=\dspMaxActX}{}%
  \setkeys*[psset]{dspData}{#1}%
  \FPupn\ntaps{\dspXmin{} \dspXmax{} - 1 + 0 trunc}%
  \psplot[plotstyle=LineToXAxis, linestyle=solid,%
          showpoints=true, dotstyle=*,%
          linewidth=\dspStemWidth, dotsize=\dspDotSize,%
          plotpoints=\ntaps, #1]%
          {\dspXmin}{\dspXmax}[{#2}]{#3}}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plotting continuous-time signals in the  dspPlot environment:
%%
%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot smooth function
%%
%% \dspFunc[OPTIONS]{PS code}
%%
\newcommand{\dspFunc}[2][]{%
  \presetkeys[psset]{dspData}{xmin=\dspMinActX, xmax=\dspMaxActX}{}%
  \setkeys*[psset]{dspData}{#1}%
  \psplot[linewidth=\dspLineWidth, plotpoints=\dspPSPoints,%
    linejoin=1,#1]{\dspXmin}{\dspXmax}{#2}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot smooth function with postscript initialization options
%%
%% \dspFuncOpt[OPTIONS]{PS init code}{PS code}
%%
\newcommand{\dspFuncOpt}[3][]{%
  \presetkeys[psset]{dspData}{xmin=\dspMinActX, xmax=\dspMaxActX}{}%
  \setkeys*[psset]{dspData}{#1}%
  \psplot[linewidth=\dspLineWidth, plotpoints=\dspPSPoints,%
    linejoin=1,#1]{\dspXmin}{\dspXmax}[{#2}]{#3}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot smooth function from a set of points
%%
%% \dspFuncData[OPTIONS]{x1 y1 x2 y2 ...}
%%
\newcommand{\dspFuncData}[2][]{%
  \listplot[linewidth=\dspLineWidth,linejoin=1,plotstyle=line,#1]{\expandafter\m@keList#2 \relax}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot smooth function from a set of points starting at a given point
%% Data in this case is only ordinates
%%
%% \dspFuncDataAt[OPTIONS]{x1}{y1 y2 ...}
%%
\newcommand{\dspFuncDataAt}[3][]{%
  \listplot[linewidth=\dspLineWidth,linejoin=1,plotstyle=line,#1]{%
  #2
  [#3] {    % n []
            % n a0
    1 index % n a0 n
    1 add
  } forall
  pop
}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot smooth function from a data file
%% file must contain a list of space-separated abscissa and ordinate pairs
%%
%% \dspFuncFile[OPTIONS]{FILE}
%%
\newcommand{\dspFuncFile}[2][]{%
  \readdata{\data}{#2}%
  \listplot[linewidth=\dspLineWidth,linejoin=1,plotstyle=line,#1]{\data}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% Plot Dirac deltas
%%
%% \dspDiracs[OPTIONS]{x1 y1 x2 y2 ...}
%%
\newcommand{\dspDiracs}[2][]{%
  \def\dirac##1##2{\psline[linestyle=solid,linewidth=\dspLineWidth,#1]{->}(! ##1 0)(! ##1 ##2)}
  \doOnPairs{dirac}{#2}}




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Periodize function over the [-1, 1] interval
%
\newcommand{\dspPeriod}[1]{ #1 sub #1 2 mul div dup floor sub #1 2 mul mul #1 sub }
\newcommand{\dspPeriodize}{ \dspPeriod{1} }
\newcommand{\dspMainPeriod}[1][]{%
  \psframe[linecolor=lightgray,linewidth=0.4pt,#1](-1,\dspMinY)(1,\dspMaxY)}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Plot text
% \dspText(x,y){text}
\newcommand{\dspText}[2]{%
  \rput*[B]{0}#1{#2}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Pole-Zero Plots
%
% Specialized options:
%
%   circle=["true" | "false"]  draw unit circle
%   clabel="text"  set a label at circle unit
%   roc
%
\define@key{dspPZ}{width}{\setlength{\dspW}{#1}\setlength{\dspH}{#1}}
\define@key{dspPZ}{height}{\setlength{\dspH}{#1}}
\define@key{dspPZ}{circle}{\def\dspCircle{#1}}
\define@key{dspPZ}{clabel}{\def\dspCircleLabel{#1}}
\define@choicekey*+{dspPZ}{xticks}[\ll\ln]{auto,none}[auto]{%
  \DoXTickstrue\def\incX{-1}
  \ifcase\ln\relax
    \relax
  \or
    \DoXTicksfalse
  \fi}{%
  \DoXTickstrue
  \def\incX{#1}}
\define@choicekey*+{dspPZ}{yticks}[\ll\ln]{auto,none}[auto]{%
  \DoYTickstrue\def\incY{-1}
  \ifcase\ln\relax
    \relax
  \or
    \DoYTicksfalse
  \fi}{%
  \DoYTickstrue
  \def\incY{#1}}
\newif\ifComplexLabels
\define@choicekey*{dspPZ}{cunits}[\ll\ln]{true,false}[true]{%
  \ifcase\ln\relax
    \ComplexLabelstrue
  \or
    \ComplexLabelsfalse
  \fi}
\define@key{dspPZ}{roc}{\def\PZCROC{#1}}
\define@key{dspPZ}{antiroc}{\def\PZAROC{#1}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\newenvironment{dspPZPlot}[2][]{%
  \setlength{\dspW}{\dspHeight}\setlength{\dspH}{\dspHeight}%
  \ComplexLabelstrue%
  \presetkeys{dspPZ}{xticks=auto,yticks=auto,circle=1,clabel={ },roc=-1,antiroc=-1}{}%
  \setkeys{dspPZ}{#1}%
%
  %% set up
  \dspSetDims{-#2},{#2},{-#2},{#2},0\relax%
  \dspSetupAxes%
%
  \gdef\dspTickX##1{\psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](##1,-\tickEndX)(##1,\tickEndX)}%
  \gdef\dspTickY##1{\psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](-\tickEndY,##1)(\tickEndY,##1)}%
  \gdef\dspTickLabelY##1##2{\uput{{2\dspYTickGap}}[0]{{0}}(\tickEndY,##1){{##2}}}%
  \gdef\dspTickLabelX##1##2{\rput[B]{{0}}(##1,\tickTxtX){{##2}}}%
%
  %% start the plot
  \begin{pspicture}(\LX,\BY)(\RX,\TY)
    \FPifpos\PZCROC%
      \pscustom[fillstyle=vlines,hatchcolor=lightgray,linecolor=lightgray,linewidth=0]{%
      \psarc(0,0){\PZCROC\dspUnitX}{0}{360}%
      \psline[linecolor=\dspAxisColor](\dspMaxX,0)(\dspMaxX,\dspMinY)(\dspMinX,\dspMinY)%
        (\dspMinX,\dspMaxY)(\dspMaxX,\dspMaxY)(\dspMaxX,0)}
      \pscircle[linecolor=lightgray,dimen=middle]{\PZCROC\dspUnitX}\relax\fi
    \FPifpos\PZAROC%
      \pscircle[fillstyle=vlines,hatchcolor=lightgray,linecolor=lightgray,dimen=middle]{\PZAROC\dspUnitX}\relax\fi
%%
    \psline[linewidth=\dspFrameLineWidth,linecolor=\dspAxisColor](\dspMinX,0)(\dspMaxX,0)%
    \psline[linewidth=\dspFrameLineWidth,linecolor=\dspAxisColor](0,\dspMinY,0)(0,\dspMaxY)%
    \dspPlotFrame%
    \FPifgt\dspCircle{0}%
      \FPmul\r\dspCircle{\strip@pt\dspUnitX}%
      \pscircle[linewidth=\dspFrameLineWidth,dimen=middle](0,0){{\r}pt}%
      \ifx\@empty\dspCircleLabel%
        \def\dspCircleLabel{\dspCircle}\relax\fi
      \FPupn\r{0.6 \dspTSX{} mul \dspCircle{} add}%
      \rput[b]{0}(\r,\tickTxtX){\dspCircleLabel}\relax\fi
%
    % draw ticks selectively according to user options
    % but here skip zero and intersections with the circle (if any)
    \FPupn\r{\tlimX{} 1 sub 2 div clip}%
    \def\xt{%
      \multido{\n=\stX+\incX}{\r}{\FPifeq\n{-\dspCircle}\relax\else\dspTickX{\n}\fi}%
      \multido{\n=\incX+\incX}{\r}{\FPifeq\n\dspCircle\relax\else\dspTickX{\n}\fi}%
      \multido{\n=\stX+\incX}{\r}{\FPifeq\n{-\dspCircle}\relax\else\dspTickLabelX{\n}{$\n$}\fi}%
      \multido{\n=\incX+\incX}{\r}{\FPifeq\n\dspCircle\relax\else\dspTickLabelX{\n}{$\n$}\fi}}%
    \def\yt{%
      \multido{\n=\stY+\incY}{\r}{\FPifeq\n{-\dspCircle}\relax\else\dspTickY{\n}\fi}%
      \multido{\n=\incY+\incY}{\r}{\FPifeq\n\dspCircle\relax\else\dspTickY{\n}\fi}%
      \multido{\n=\stY+\incY}{\r}{\FPifeq\n{-\dspCircle}\relax\else\dspTickLabelY{\n}{$\n$}\fi}%
      \multido{\n=\incY+\incY}{\r}{\FPifeq\n\dspCircle\relax\else\dspTickLabelY{\n}{$\n$}\fi}}%
    \ifDoXTicks\xt\fi
    \ifDoYTicks\yt\fi
    \ifComplexLabels%
      \rput[mr]{0}(\dspMaxX,1em){Re~}%
      \FPupn\r{\dspMaxY{} 0.6 \dspTSY{} mul sub}%
      \rput[t]{0}(-1.2em,\r){Im~}\relax\fi
}{%
  \end{pspicture}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Keyvals for poles and zeros
%
\newif\ifPZPole
\define@choicekey*[psset]{dspPZP}{type}[\ll\ln]{zero,pole}[zero]{%
  \ifcase\ln\relax
    \PZPolefalse
  \or
    \PZPoletrue
  \fi}
\newif\ifPZLabel
\define@choicekey*+[psset]{dspPZP}{label}[\ll\ln]{auto,none}[auto]{%
  \def\PZLabel{}\relax%
  \ifcase\ln\relax
    \PZLabeltrue
  \or
    \PZLabelfalse
  \fi}{%
  \PZLabeltrue
  \def\PZLabel{#1}}
\define@key[psset]{dspPZP}{lpos}{\def\PZLP{#1}}
\pst@addfams{dspPZP}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Plot pole-zero point
%
% \dspPZPoint[OPTIONS]{RE,IM}
%
%     RE, IM    coordinates
%
%   Options:
%
%     type = ["pole" | "zero"]    circle or cross (default: pole)
%     label=["false" | TEXT ]     the point's label (default: false)
%     lpos = ANGLE            label position (default: 45)
%
\newcommand{\dspPZ}[2][]{%
  \presetkeys[psset]{dspPZP}{type=pole,label=auto}{}%
  \setkeys*[psset]{dspPZP}{#1}%
  \ifPZPole
    \psdot[dotstyle=+,dotsize=1.4ex,dotscale=1.5,dotangle=45, #1](\twoArgSplit#2) \else
    \psdot[dotstyle=*,dotsize=1.4ex,#1](\twoArgSplit#2) \fi
  \ifx\@empty\PZLabel \def\PZLabel{$(\twoArgSplit#2)$} \fi
  % tricky bug in pstricks so we can't use presetkeys for angle... Could not understand
  \ifdefined\PZLP \relax \else \def\PZLP{45} \fi
  \ifPZLabel \uput[\PZLP]{0}(\twoArgSplit#2){\PZLabel} \fi}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


\define@key{dspCP}{width}{\setlength{\dspCPW}{#1}\setlength{\dspCPH}{#1}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% dspCP environment
%
% \begin{dspCP}[OPTIONS]{MAX}
%
%
\newlength{\dspCPW}\newlength{\dspCPH}
\newenvironment{dspCP}[3][]{%
%% scale dimensions so that axes have equal units
  \setlength{\dspCPW}{0.37\textwidth}\setlength{\dspCPH}{\dspCPW}
  \setlength{\dspW}{\dspCPW}\setlength{\dspH}{\dspCPH}
  \setkeys*{dspCP}{#1}%
  \dspSetDims#2,#3,0\relax%
  \FPupn\g{\dspRngY{} {\strip@pt\dspCPW} / \dspRngX{} * 0 trunc}%
  \setlength{\dspCPH}{1pt*\g}%
%%
  \begin{dspPlot}[#1,sidegap=0,inticks=true,width=\dspCPW,height=\dspCPH]{#2}{#3}%
    \ifYAxisExp\psline[linewidth=\dspFrameLineWidth,linecolor=\dspAxisColor](0,\dspMinY)(0,\dspMaxY)\fi
}{%
%% redo ticks and axes since images may overlap a little
    \dspPlotFrame
    \ifDoXTicks\multido{\n=\stX+\incX}{\tlimX}{\dspTickX{\n}}\fi
    \ifDoYTicks\multido{\n=\stY+\incY}{\tlimY}{\dspTickY{\n}}\fi
  \end{dspPlot}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Plot Dirac deltas
%
% \dspPoints[OPTIONS]{x1 y1 x2 y2 ...}
%
\newcommand{\dspPoints}[2][]{%
  \listplot[plotstyle=dots,%
    showpoints=true, dotstyle=*,%
    dotsize=\dspDotSize, #1]{\m@keList#2 \relax}}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Plot Dirac delta with value
%
% \dspDiracs[OPTIONS]{x, y}{text}
%
\newcommand{\dspPointValue}[3][]{%
  \psdot[dotstyle=*, dotsize=\dspDotSize, #1](\twoArgSplit#2)%
  \uput[45]{0}(\twoArgSplit#2){#3}}

\newcommand{\dspPointValueSC}[3][]{%
  \SpecialCoor
  \psdot[dotstyle=*, dotsize=\dspDotSize, #1](#2)%
  \uput[45]{0}(\twoArgSplit#2){#3}
  \NormalCoor}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Plot image from file
\newcommand{\dspImageFile}[1]{%
  \FPupn\u{2 \dspRngX{} 1.01 * / \dspMinX{} + }\FPupn\v{2 \dspRngY{} 1.01 * / \dspMinY{} + }%
  \setlength{\dspCPW}{1.01\dspW}\setlength{\dspCPH}{1.01\dspH}%
  \rput(\u,\v){\includegraphics[width=\dspCPW,height=\dspCPH]{#1}}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Quick image plot, with frame but no additional space around it
\newcommand{\dspShowImage}[2][0.37\textwidth]{%
  \psset{xunit=#1,yunit=#1}%
  \begin{pspicture}(0,0)(0,1)%
    \includegraphics[width=#1,height=#1]{#2}%
    \psframe[dimen=middle,linewidth=1.1pt](-0.01,0)(-.99,.99)
  \end{pspicture}}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%% Some geometrical primitives
%
\newif\ifPointToOrg
\define@choicekey*[psset]{dspPZP}{toorg}[\ll\ln]{true,false}[false]{%
  \ifcase\ln\relax
    \PointToOrgtrue
  \or
    \PointToOrgfalse
  \fi}

% [opts]{x,y}{label}
\newcommand{\dspCPPoint}[3][]{%
  \setkeys*[psset]{dspPZP}{#1}%
  \psdot[dotstyle=*, dotsize=\dspDotSize, #1](#2)%
  \uput[45]{0}(#2){#3}%
  \ifPointToOrg\psline[linewidth=\dspTickLineWidth, #1](0,0)(#2)\fi}

% [opts]{x,y in special coor}{label}
\newcommand{\dspCPPointSC}[3][]{%
  \setkeys*[psset]{dspPZP}{#1}%
  \SpecialCoor%
  \psdot[dotstyle=*, dotsize=\dspDotSize, #1](#2)%
  \uput[45]{0}(#2){#3}%
  \ifPointToOrg\psline[linewidth=\dspTickLineWidth, #1](! 0 0 )(#2)\fi%
  \NormalCoor}

% [opts]{x,y}{r}
\newcommand{\dspCPCircle}[3][]{%
  \pscircle[#1](#2){#3\dspUnitX}}

% [opts]{r}{a}{label}
\newcommand{\dspCPCirclePoint}[4][]{%
  \setkeys*[psset]{dspPZP}{#1}%
  \SpecialCoor%
  \def\pcorps{! #3 cos #2 mul #3 sin #2 mul}%
  \FPupn\q{#2 1.1 * 2 trunc}%
  \uput*{\q\dspUnitX}[#3]{0}(0,0){#4}%
  \psdot[dotstyle=*, dotsize=\dspDotSize, #1](\pcorps)%
  \ifPointToOrg\psline[linewidth=\dspTickLineWidth, #1](! 0 0 )(\pcorps)\fi%
  \NormalCoor}

% [opts] {r}{a}{b}{label}
\newcommand{\dspCPArc}[5][]{%
  \FPupn\p{#3 #4 + 0.5 * 2 trunc}%
  \FPupn\q{#2 1.1 * 2 trunc}%
  \uput*{\q\dspUnitX}[\p]{0}(0,0){#5}%
  \psarc[linewidth=2\dspTickLineWidth, #1]{->}{#2\dspUnitX}{#3}{#4}}
\newcommand{\dspCPArcn}[5][]{%
  \FPupn\p{#3 #4 + 0.5 * 2 trunc}%
  \FPupn\q{#2 1.1 * 2 trunc}%
  \uput*{\q\dspUnitX}[\p]{0}(0,0){#5}%
  \psarcn[linewidth=2\dspTickLineWidth, #1]{->}{#2\dspUnitX}{#3}{#4}}



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Helpers
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This is called at each plot setup with xmin, xmax, ymin, ymax and sidegap
%%  and sets all lengths
\def\dspSetDims#1,#2,#3,#4,#5\relax{%
  \def\sideGap{#5}%
  % default sidegap: 5% of range
  \FPifneg\sideGap\FPupn\sideGap{#1 #2 - 0.05 * 0.5 + 2 trunc}\fi%
  \FPifgt\sideGap{1}\FPtrunc\sideGap\sideGap{0}\fi%
%%
%% active range for the independent variable
  \def\dspMinActX{#1}%
  \def\dspMaxActX{#2}%
%% axes range (including sidegap)
  \FPupn\dspMinX{\sideGap{} #1 - clip}%
  \FPupn\dspMaxX{\sideGap{} #2 + clip}%
  \FPupn\dspRngX{#1 #2 - \sideGap{} 2 * + clip}%
  \FPupn\dspMinY{#3 0 + clip}%
  \FPupn\dspMaxY{#4 0 + clip}%
  \FPupn\dspRngY{#3 #4 - clip}%
%%
% if y-range is across zero we'll need to draw the x-axis
  \FPmul\u\dspMinY\dspMaxY%
  \FPifneg\u\XAxisExptrue\else\XAxisExpfalse\fi%
%% same for x (but usually we never draw the y axis)
  \FPmul\u\dspMinX\dspMaxX%
  \FPifneg\u\YAxisExptrue\else\YAxisExpfalse\fi%
%%
%% pstricks units: we scale the units so that coordinates are "real" coords on the axes
  \FPupn\tmp{\dspRngX{} {\strip@pt\dspW} / }
  \setlength{\dspUnitX}{\tmp pt}%
  \FPupn\tmp{\dspRngY{} {\strip@pt\dspH} / }%
  \setlength{\dspUnitY}{\tmp pt}%
%%
%% basic unit based on the size of the image: ~1pt for a 10x5 cm box
  \FPupn\g{2 {\strip@pt\dspW} {\strip@pt\dspH} * root 0.005 * 0 round 1 max}%
  \setlength{\dspBU}{1pt*\g}%
%% derived sizes: lines and fonts
  \setlength{\dspLineWidth}{1.8\dspBU}%
  \setlength{\dspDotSize}{5\dspBU}%
  \setlength{\dspStemWidth}{1.4\dspBU}%
  \fontsize{9\dspBU}{10\dspBU}\selectfont%
%  %% ticks on axes
  \setlength{\dspTickLen}{4\dspBU}%
  \setlength{\dspTickLineWidth}{0.4\dspBU}%
  \setlength{\dspXTickGap}{6\dspBU}\addtolength{\dspXTickGap}{2ex}%
  \setlength{\dspYTickGap}{2\dspBU}%
  \setlength{\dspFrameLineWidth}{2.2\dspTickLineWidth}%
%%
%% height of a line of text in psticks units
  \setlength{\dspTmpLen}{1em}%
  \FPupn\dspTSX{{\strip@pt\dspUnitX} {\strip@pt\dspTmpLen} / }%
  \FPupn\dspTSY{{\strip@pt\dspUnitY} {\strip@pt\dspTmpLen} / }%
%%
%% find the coordinates of the plot's bounding box, including labels
  \ifYLabel%
    \FPupn\LX{\dspTSX{} 4 * \dspMinX{} -}%
    \FPupn\RX{\dspTSX{} 4 * \dspMaxX{} +}%
  \else%
    \FPupn\LX{\dspTSX{} 2 * \dspMinX{} -}%
    \FPupn\RX{\dspTSX{} 2 * \dspMaxX{} +}%
  \fi
  \FPupn\TY{\dspTSY{} \dspMaxY{} +}%
  \def\outTicks{%
    \ifXTicks\FPupn\BY{\dspTSY{} 2.5 * \dspMinY{} -}\else\FPupn\BY{\dspTSY{} \dspMinY{} -}\fi%
   \ifXLabel\FPupn\BY{\dspTSY{} 1.5 * \BY{} -}\else\relax\fi }%
  \ifXAxisExp % ticks are inside
    \ifXLabel\FPupn\BY{\dspTSY{} 2.5 * \dspMinY{} -}\else\FPupn\BY{\dspTSY{} \dspMinY{} -}\fi%
  \else% ticks are outside
    \outTicks \fi%
  % did we select explicit outside ticks?
  \ifXTicksOut\outTicks \fi%
%%
%% x-axis resolution for plotting functions: ~60 values/cm
  \FPupn\dspPSPoints{{\strip@pt\dspW} 2 * 0 trunc}%
%%
  \psset{xunit=\dspUnitX, yunit=\dspUnitY}%
  \psset{linewidth=\dspLineWidth}%www
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Draw axis labels (if required) under x axis and to left and right of y axes
%%
\def\dspLabels{%
  % horizontal label
  \ifXTicksOut\XAxisExpfalse\fi%
  \ifXLabel%
    \FPupn\mid{\dspMinX{} \dspMaxX{} + 0.5 mul}%
    \ifXAxisExp%
      \FPupn\pos{\dspTSY{} 2 * \dspMinY{} -}%
    \else%
      \ifXTicks%
        \FPupn\pos{\dspTSY{} 3 * \dspMinY{} -}%
      \else%
        \FPupn\pos{\dspTSY{} 2 * \dspMinY{} -}%
      \fi%
    \fi%
    \rput[b]{0}(\mid,\pos){\dspXLabel}%
  \fi%
%
  \FPupn\mid{\dspMinY{} \dspMaxY{} + 0.5 mul}%
  \ifYTicks%
    \FPupn\pos{\dspTSX{} 3.4 * \dspMinX{} -}%
  \else%
    \FPupn\pos{\dspTSX{} 1 * \dspMinX{} -}%
  \fi%
  \rput[b]{90}(\pos,\mid){\dspYLabel}
%%
  \FPupn\pos{\dspTSX{} 3 * \dspMaxX{} +}%
  \rput[b]{-90}(\pos,\mid){\dspYLabelR}}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% This sets axes ticks (spacing and number) and prepares macros
%%  for plotting ticks and tick labels
\def\dspSetupAxes{%
%% tick increments; if incX/Y is zero, compute suitable value
  \FPifgt\incX{0}\FPupn\incX{\incX{} 2 trunc}%
    \else\FPupn\incX{\dspMinActX{} \dspMaxActX{} - 1 + 6 swap / 0 trunc 1 max}\relax\fi%
  \FPifgt\incY{0}\FPupn\incY{\incY{} 2 trunc}%
    \else\FPupn\incY{\dspMinY{} \dspMaxY{} - 1 + 6 swap / 0 trunc 1 max}\relax\fi%
%%
%% now find starting point and increment for ticks (and number of ticks)
%% start with y-axis:
  \ifXAxisExp% is y=0 explicit or does it coincide with the lower edge?
    \def\haY{0}%
    % make sure ticks hit zero; add small epsilons to avoid ticks at the limits
    \FPupn\stY{\incY{} \dspMinY{} / 0.001 + 0 trunc \incY{} * 2 trunc}%
    \FPupn\tlimY{\stY{} \dspMaxY{} - 0.001 - \incY{} swap / abs 1 + 0 trunc}%
  \else%
    \def\haY{\dspMinY}%
    \FPupn\tlimY{\incY{} \dspRngY{} / abs 1 + 0 trunc}%
    \FPupn\stY{\dspMinY{} 2 trunc}% \incY{} 1 \tlimY{} - * \dspRngY{} - 0.5 * \dspMinY{} + 2 trunc}%
  \fi%
  % x-ticks outside of the box anyway?
  \ifXTicksOut\def\haY{\dspMinY}\relax\fi%
  % round off to integer if possible:
  \FPupn\v{\stY{} 0 trunc \stY{} - abs \incY{} 0 trunc \incY{} - abs + clip}%
  \FPifeq\v{0}\FPtrunc\stY\stY{0}\FPtrunc\incY\incY{0}\relax\fi%
%
%% now x-axis:
  \ifYAxisExp% we almost never draw the y-axis but need to see if x-axis spans zero
    % make sure ticks hit zero; add small epsilons to avoid ticks at the limits
    \FPupn\stX{\incX{} \dspMinX{} / 0 trunc \incX{} * 2 trunc}%
    \FPupn\tlimX{\incX{} \stX{} \dspMaxX{} - / abs 1 +  0 trunc}%
  \else%
    \FPupn\tlimX{\incX{} \dspRngX{} / abs 1 + 0 trunc}%
    \FPupn\stX{\dspMinX{} 2 trunc}% \FPupn\stX{\incX{} 1 \tlimX{} - * \dspRngX{} - 0.5 * \dspMinX{} + 2 trunc}%
  \fi%
  \FPupn\v{\stX{} 0 trunc \stX{} - abs \incX{} 0 trunc \incX{} - abs +}%
  \FPifzero\v\FPtrunc\stX\stX{0}\FPtrunc\incX\incX{0}\relax\fi%
%%
%% macros for drawing x-ticks
  \ifXInside%
    \FPupn\tickEndX{{\strip@pt\dspUnitY} {\strip@pt\dspTickLen} /}%
    \FPupn\tickTxtX{{\strip@pt\dspUnitY} {\strip@pt\dspXTickGap} 0.9 * / \dspMinY{} -}% tick label pos in PS units
    \FPupn\tickXB{\tickEndX{} \dspMinY{} +}%
    \FPupn\tickXT{\tickEndX{} \dspMaxY{} -}%
    \gdef\dspTickX##1{%
      \psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](##1,\dspMinY)(##1,\tickXB)%
      \psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](##1,\dspMaxY)(##1,\tickXT)}%
  %  \gdef\dspTickLabelX##1##2{\uput{{2\dspYTickGap}}[180]{{0}}(\dspMinX,##1){{##2}}}%
    \gdef\dspTickLabelX##1##2{\rput*[B]{{0}}(##1,\tickTxtX){{##2}}}%
  \else%
    \FPupn\tickEndX{{\strip@pt\dspUnitY} {\strip@pt\dspTickLen} / \haY{} -}% tick len in PS units
    \FPupn\tickTxtX{{\strip@pt\dspUnitY} {\strip@pt\dspXTickGap} / \haY{} -}% tick label pos in PS units
    \gdef\dspTickX##1{\psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](##1,\haY)(##1,\tickEndX)}%
    \gdef\dspTickLabelX##1##2{\rput*[B]{{0}}(##1,\tickTxtX){{##2}}}%
  \fi%
%% macros for drawing y-ticks
  \FPupn\tickEndY{{\strip@pt\dspUnitX} {\strip@pt\dspTickLen} /}%
  \FPupn\tickXB{\tickEndY{} \dspMinX{} +}%
  \FPupn\tickXT{\tickEndY{} \dspMaxX{} -}%
  \gdef\dspTickY##1{%
    \psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](\dspMinX,##1)(\tickXB,##1)%
    \psline[linewidth=\dspTickLineWidth,linecolor=\dspAxisColor](\dspMaxX,##1)(\tickXT,##1)}%
  \gdef\dspTickLabelY##1##2{\uput{{2\dspYTickGap}}[180]{{0}}(\dspMinX,##1){{##2}}}%
  \gdef\dspTickLabelYR##1##2{\uput{{2\dspYTickGap}}[0]{{0}}(\dspMaxX,##1){{##2}}}%
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% simplify fractions of pi
\newcount\dspNum \newcount\dspDen
\def\simplifyPiFrac#1#2{%
  \ifnum#1=0 $0$\else % zero is zero
    \dspNum=#1 \dspDen=#2 %
    \divide\dspNum by\dspDen \multiply\dspNum by\dspDen % see if frac is simply an integer
    \ifnum\dspNum=#1 \divide\dspNum by\dspDen \ifnum\dspNum=1 $\pi$\else \ifnum\dspNum=-1 $-\pi$\else $\number\dspNum\pi$\fi\fi\else%
      \dspNum=#1 %
      \ifnum\dspNum<0 \multiply\dspNum by-1 \def\s{-}\else\def\s{}\fi % normalize sign
      \divide\dspDen by\dspNum \multiply\dspDen by\dspNum % see if frac is of type 1/x
      \ifnum\dspDen=#2 \divide\dspDen by\dspNum $\s\pi / \number\dspDen$\else %
      \dspNum=#1\dspDen=#2 %
      \removeFactor{10}\removeFactor{9}\removeFactor{8}% remove some common factors
      \removeFactor{7}\removeFactor{6}\removeFactor{5}%
      \removeFactor{4}\removeFactor{3}\removeFactor{2}%
      $\number\dspNum \pi / \number\dspDen$\fi%
    \fi %
  \fi}

%% simplify a fraction (not the full Euclid, but it's ok for our purposes)
\newcount\dspTerm \newcount\dspFact
\def\removeFactor#1{\dspFact=#1 \dspTerm=\dspNum%
  \divide\dspTerm by\dspFact \multiply\dspTerm by\dspFact %
  \ifnum\dspTerm=\dspNum %
    \dspTerm=\dspDen %
    \divide\dspTerm by\dspFact \multiply\dspTerm by\dspFact %
    \ifnum\dspTerm=\dspDen %
      \divide\dspNum by\dspFact \divide\dspDen by\dspFact %
    \fi %
  \fi}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% space-separated lists must have at least two pairs of elements.
% Duplicate singletons
%
\def\m@keList#1 #2 #3\relax{%
  \ifx&#3&
    #1 #2 #1 #2
  \else
    #1 #2 #3
  \fi
}

\def\twoArgSplit#1,#2{#1, #2}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% prepend the ordinal index to each element of a space-separated list
%
\def\m@keIndexedList#1#2{%
  \count0=#1%
  \expandafter\m@kixl\trim #2 |}
\def\m@kixl#1 {%
  \ifx#1|%
    \let\next=\relax%
  \else{\number\count0} \ #1\ \advance\count0 by1\let\next=\m@kixl\fi%
\next}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% perform an action on all consecutive pairs in a space-separated list
%
\def\doOnPairs#1#2{%
  \def\action{#1}%
  \expandafter\p@rseB\trim #2 |}
\def\p@rseB#1 #2 #3{%
 \csname \action\endcsname{#1}{#2}%
  \ifx#3|%
    \let\next=\@gobble%
  \else%
    \let\next=\p@rseB\fi%
  \next #3}
\def\@gobble#1{}


\def\trim#1{%
  \romannumeral-`\.\expandafter\noexpand#1%
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% PsTricks overrides
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Lollipop line style, by Denis.Girou at idris.fr %%%%%%%%%%%%%%%%%%%%%%%%
%%
\let\beginplot@LineToXAxis\beginplot@line
\def\endplot@LineToXAxis{\psLineToXAxis@ii}
\let\beginqp@LineToXAxis\beginqp@line
\let\doqp@LineToXAxis\doqp@line
\let\endqp@LineToXAxis\endqp@line
\let\testqp@LineToXAxis\testqp@line
%
\def\psLineToXAxis@ii{%
\addto@pscode{\pst@cp \psline@iii \tx@LineToXAxis}%
\end@OpenObj}
%
\def\tx@LineToXAxis{LineToXAxis }
%
% Adapted from Line
\pst@def{LineToXAxis}<{%
NArray
n 0 eq not
  { n 1 eq { 0 0 /n 2 def } if
    ArrowA
    /n n 2 sub def
    CP 2 copy moveto pop 0 Lineto
    n { 2 copy moveto pop 0 Lineto } repeat
    CP
    4 2 roll
    ArrowB
    2 copy moveto pop 0
    L
    pop pop } if}>


\makeatother
\endinput

