% TeXdraw macros

% $Id: texdraw.tex 2.7 2019/04/18 TeXdraw-v2r3 $

%   Copyright (C) 1991-2019  Peter Kabal

% This work is licensed under the Creative Commons Attribution (CC-BY)
% License, any version. To view the licenses, visit
% creativecommons.org/licenses/by or send a letter to
% Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.

%  Peter Kabal
%  Department of Electrical & Computer Engineering
%  McGill University

%  peter dot kabal at mcgill dot ca
%  http://www-mmsp.ece.mcgill.ca/MMSP/Documents/Software/

\def\setRevDate $#1 #2 #3${#2}
\def\TeXdrawId{\setRevDate $Date: 2019/04/18 14:10:45 $ TeXdraw V2R3}

% ===============================================================

% The TeXdraw macros allow PostScript line drawings and such to be
% generated from within TeX and LaTeX.
% (1) TeXdraw allows TeX text (either horizontal or rotated) to be
%     superimposed on the figure.
% (2) TeXdraw implements a \bsegment-\esegment environment which allows
%     parameter changes and coordinate changes to be kept local.  In
%     effect these segments are self-contained relocatable procedures.
% (3) TeX's macro facility can be used to modularize drawing units and
%     produce more complex entities from simple elements.
% (4) The drawing can be positioned on the page like any other TeX box.

% TeXdraw coordinate units have positive X to the right and positive Y up.
% The drawing units can be selected (initially inches).  In addition, two
% scaling parameters - unit scale and segment scale - are available.  Their
% effects are multiplicative.

% Segments allow for relocatable drawing units.  Inside each segment the
% coordinates are relative to the initial point, which becomes (0 0).
% Scaling is local to segments.  Each segment inherits the unit scale
% scaling from outside the segment, but any changes apply to that segment
% and inferior segments.  The segment scale factor is reset to unity on
% entry to each segment.

% The coordinates given as command arguments are used to determine
% the size of the drawing.  The width of the plot line, sizes of
% arrowheads, arcs or text do not affect the size of the drawing.

% TeXdraw writes PostScript commands to an intermediate file.  After the
% drawing is finished, the PostScript file is included in the document as a
% PostSript include file.

%  This file is divided into 4 parts,
%  - TeXdraw user interface
%  - Utility definitions
%  - Low level definitions
%  - PostScript file macros


\chardef\catamp=\the\catcode`\@
\catcode`\@=11

% ===============================================================
% ===== TeXdraw user interface ==================================
\long                              % \centertexdraw needs to be very \long
\def\centertexdraw #1{\hbox to \hsize{\hss
                                     \btexdraw #1\etexdraw
                                     \hss}}

% ====== Begin TeXdraw
% Inside the texdraw box:
%   The \vbox should be of zero size; none of the TeXdraw drawing commands
%   generate text, the TeXdraw text commands generate zero size boxes.

\def\btexdraw {\x@pix=0             \y@pix=0
              \x@segoffpix=\x@pix  \y@segoffpix=\y@pix
              \let\p@sfile=\p@sundef
% Set the default values (define outside of the group so that \etexdraw can
% see the scaling parameters)
              \t@exdrawdef
              \setbox\t@xdbox=\vbox\bgroup\offinterlineskip
                  \global\d@bs=0           % pending segments
                  \global\p@osinitfalse
                  \s@avemove \x@pix \y@pix % capture the initial position
                  \m@pendingfalse
                  \global\p@osinitfalse    % capture the next move
                  \p@athfalse
                  \the\everytexdraw}

% ====== End TeXdraw
% Write out a trailer, close the file, bring in the PostScript code as
% a \special include file.  The \special is offset on the page to be at
% (llx,ury) in PostScript coordinates.

% The drawing is placed in a \vbox of appropriate size (zero depth).  The
% temporary PostScript file is superimposed with offsets such that the
% lower lefthand corner of the drawing is aligned with the lower lefthand of
% the box.
\def\etexdraw {\p@sclose         % close the PostScript file
              \egroup           % ends the \vbox \bgroup
              \vbox {\offinterlineskip
                     \pixtobp \xminpix \l@lxbp  \pixtobp \yminpix \l@lybp
                     \pixtobp \xmaxpix \u@rxbp  \pixtobp \ymaxpix \u@rybp
                     \ifx\p@sfile\p@sundef
                       \hbox{\t@xdempty
                        [{\l@lxbp},{\l@lybp}][{\u@rxbp},{\u@rybp}]}%
                     \else
                       \hbox{\t@xdinclude
                        [{\l@lxbp},{\l@lybp}][{\u@rxbp},{\u@rybp}]{\p@sfile}}%
                     \fi
                     \t@xdtext}%
}
% Superimpose TeX text. The position is temporarily offset to a position
% corresponding to (0 0) to place the TeX text.
\def\t@xdtext {
 \ifdim \wd\t@xdbox>0pt
   \t@xderror {TeXdraw box non-zero size, possible extraneous text}%
 \fi
 \pixtodim \xminpix \t@xpos  \pixtodim \yminpix \t@ypos
 \kern \t@ypos
 \hbox {\kern -\t@xpos
        \box\t@xdbox        % TeX text
        \kern \t@xpos}%
 \kern -\t@ypos\relax
}

% ===== Drawing scaling
% The units in any segment may be scaled arbitrarily.  A unit scale is
% local to a segment but affects enclosed segments unless specifically
% overridden in that segment.  In addition there is a segment scale.  The
% overall scale is the product of the two scaling factors.
%
% Scaling is handled entirely on the TeX side, the PostScript side gets
% absolute pixel coordinates.

% Drawing units, e.g. "in" or "cm"
\def\drawdim #1 {\def\d@dim{#1\relax}}

% \u@nitsc - unit scale
% \s@egsc  - segment scale
% \d@sc    - drawing scale, product of the unit scale and segment scale

% Note that successive application of relative scale factors can lead
% to poor accuracy of the final scale factor.  Each scale factor is
% represented to about 5 decimal digits after the decimal point.
\def\setunitscale #1 {\edef\u@nitsc{#1}%
                     \realmult \u@nitsc \s@egsc \d@sc}
\def\relunitscale #1 {\realmult {#1}\u@nitsc \u@nitsc
                     \realmult \u@nitsc \s@egsc \d@sc}
\def\setsegscale #1 {\edef\s@egsc {#1}%
                    \realmult \u@nitsc \s@egsc \d@sc}
\def\relsegscale #1 {\realmult {#1}\s@egsc \s@egsc
                    \realmult \u@nitsc \s@egsc \d@sc}

% ===== Drawing segments
% The position is restored after a segment.
% Segments use TeX grouping on the TeX side and gsave/grestore on the
% PostScript side to keep changes local.  On the TeX side segments have
% (0 0) as the initial point, while the PostScript side sees no scale
% changes or translations.
\def\bsegment {\ifp@ath
                \f@lushbs
                \f@lushmove
              \fi
              \begingroup
                \x@segoffpix=\x@pix
                \y@segoffpix=\y@pix
                \setsegscale 1
                \global\advance \d@bs by 1\relax}
\def\esegment {\endgroup
              \ifnum \d@bs=0
                \writetx {es}%
              \else
                \global\advance \d@bs by -1
              \fi}

% Save a position
% Save each coordinate as the macro "*name".  The macro is defined to
% be the pixel coordinate value.
\def\savecurrpos (#1 #2){\getsympos (#1 #2)\a@rgx\a@rgy
                        \s@etcsn \a@rgx {\the\x@pix}%
                        \s@etcsn \a@rgy {\the\y@pix}}
\def\savepos (#1 #2)(#3 #4){\getpos (#1 #2)\a@rgx\a@rgy
                           \coordtopix \a@rgx \t@pixa
                           \advance \t@pixa by \x@segoffpix
                           \coordtopix \a@rgy \t@pixb
                           \advance \t@pixb by \y@segoffpix
                           \getsympos (#3 #4)\a@rgx\a@rgy
                           \s@etcsn \a@rgx {\the\t@pixa}%
                           \s@etcsn \a@rgy {\the\t@pixb}}

% ===== Line parameters
% The following parameters apply to subsequent lines.  Each of these
% commands invokes a stroke to draw the previous line segments,
% establishes the current point and then changes the line parameter.
% The parameters are kept local by the PostScript gsave/grestore
% mechanism.  We use \writetx here, instead of \writeps, since we
% do not want to flush any moves.
\def\linewd #1 {\coordtopix {#1}\t@pixa
               \f@lushbs
               \writetx {\the\t@pixa\space sl}}
\def\setgray #1 {\f@lushbs
                \writetx {#1 sg}}
\def\lpatt (#1){\listtopix (#1)\p@ixlist
               \f@lushbs
               \writetx {[\p@ixlist] sd}}

% ===== Line drawing
% PostScript uses the concept of a path consisting of line segments.
% In this interface to PostScript, paths are continuous across the
% beginning of segments.  Paths terminate at the end of a segment with
% an implicit move.  In addition, paths are both terminated and started
% with a move.  There is a current point at all times, starting with
% initial position (0,0).
\def\lvec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                 \s@etpospix \a@rgx \a@rgy
                 \writeps {\the\x@pix\space \the\y@pix\space lv}}
\def\rlvec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                  \r@elpospix \a@rgx \a@rgy
                  \writeps {\the\x@pix\space \the\y@pix\space lv}}
\def\move (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                 \s@etpospix \a@rgx \a@rgy
                 \s@avemove \x@pix \y@pix}
\def\rmove (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                  \r@elpospix \a@rgx \a@rgy
                  \s@avemove \x@pix \y@pix}

% ===== Circles, ellipses and arcs
% Note that arcs do not update the size of the drawing.
% \lcir, stroked circle
%   r:#1 -  radius
% \fcir, filled circle
%   f:#1 - fill gray level, 0 is black, 1 is white
%   r:#2 - radius
% \ellip, stroked ellipse
%   rx:#1 - x radius
%   ry:#2 - y radius
% \fellip, filled ellipse
%   f:#1 - fill gray level, 0 is black, 1 is white
%   rx:#1 - x radius
%   ry:#2 - y radius
% \larc, stroked counterclockwise arc, with the present position being
%        the center of the arc.  Only the arc is drawn (not the line
%        joining the center to the beginning of the arc)
%   r:#1  - radius
%   sd:#2 - start angle (degrees)
%   ed:#3 - end angle (degrees)
\def\lcir r:#1 {\coordtopix {#1}\t@pixa
               \writeps {\the\t@pixa\space cr}%
               \r@elupd \t@pixa \t@pixa
               \r@elupd {-\t@pixa}{-\t@pixa}}
\def\fcir f:#1 r:#2 {\coordtopix {#2}\t@pixa
                    \writeps {\the\t@pixa\space #1 fc}%
                    \r@elupd \t@pixa \t@pixa
                    \r@elupd {-\t@pixa}{-\t@pixa}}
\def\lellip rx:#1 ry:#2 {\coordtopix {#1}\t@pixa
                    \coordtopix {#2}\t@pixb
                    \writeps {\the\t@pixa\space \the\t@pixb\space el}%
                    \r@elupd \t@pixa \t@pixb
                    \r@elupd {-\t@pixa}{-\t@pixb}}
\def\fellip f:#1 rx:#2 ry:#3 {\coordtopix {#2}\t@pixa
                    \coordtopix {#3}\t@pixb
                    \writeps {\the\t@pixa\space \the\t@pixb\space #1 fe}%
                    \r@elupd \t@pixa \t@pixb
                    \r@elupd {-\t@pixa}{-\t@pixb}}
\def\larc r:#1 sd:#2 ed:#3 {\coordtopix {#1}\t@pixa
                           \writeps {\the\t@pixa\space #2 #3 ar}}

% ===== Fill commands
% The form here completes a path with a closepath, applies the fill,
% starts a newpath and moves to the current point.  The gray level has
% 0 as black and 1 as white.  The current path is terminated.

\def\ifill f:#1 {\writeps {#1 fl}}     % Fill only
\def\lfill f:#1 {\writeps {#1 fp}}     % Stroke and fill

% ===== Text
% TeX text superimposed on the drawing
%  \htext (x y){text} or \htext {text}
%  \vtext (x y){text} or \vtext {text}
%  \rtext td:angle (x y){text} or \rtext td:angle {text}
%  \textref h:#1 v:#2

% The TeX text (or whatever) is placed in an \hbox.  The box is rotated
% for vertical text.  The text is placed on the drawing at the specified
% location (coordinates specified) or the current location (coordinates
% not specified).  The text reference point is placed at that location.
% For the purposes of determining the drawing size, the text box is of
% zero size.

% Horizontal text
% Check if the argument starts with a left parenthesis
\def\htext #1{\def\testit {#1}%
             \ifx \testit\l@paren
               \let\t@cmd=\h@move
             \else
               \let\t@cmd=\h@text
             \fi
             \t@cmd {#1}}

% Rotated text
\def\rtext td:#1 #2{\def\testit {#2}%
                   \ifx \testit\l@paren
                     \let\t@cmd=\r@move
                   \else
                     \let\t@cmd=\r@text
                   \fi
                   \t@cmd td:#1 {#2}}

% Vertical text
\def\vtext {\rtext td:90 }

% Text reference point
%  h:#1  text horizontal reference point - L, C or R
%  v:#2  text vertical reference point - T, C or B
\def\textref h:#1 v:#2 {\ifx #1R%
                         \edef\l@stuff {\hss}\edef\r@stuff {}%
                       \else
                         \ifx #1C%
                           \edef\l@stuff {\hss}\edef\r@stuff {\hss}%
                         \else  % default L
                           \edef\l@stuff {}\edef\r@stuff {\hss}%
                         \fi
                       \fi
                       \ifx #2T%
                         \edef\t@stuff {}\edef\b@stuff {\vss}%
                       \else
                         \ifx #2C%
                           \edef\t@stuff {\vss}\edef\b@stuff {\vss}%
                         \else  % default B
                           \edef\t@stuff {\vss}\edef\b@stuff {}%
                         \fi
                       \fi}

% ===== Arrow vectors
\def\avec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                 \s@etpospix \a@rgx \a@rgy
                 \writeps {\the\x@pix\space \the\y@pix\space (\a@type) %
                           \the\a@lenpix\space \the\a@widpix\space av}}

\def\ravec (#1 #2){\getpos (#1 #2)\a@rgx\a@rgy
                  \r@elpospix \a@rgx \a@rgy
                  \writeps {\the\x@pix\space \the\y@pix\space (\a@type) %
                            \the\a@lenpix\space \the\a@widpix\space av}}

% Arrowhead size
%  l:#1 - length of the arrowhead
%  w:#2 - width of the base of the arrowhead
\def\arrowheadsize l:#1 w:#2 {\coordtopix{#1}\a@lenpix
                             \coordtopix{#2}\a@widpix}
% Arrowhead type
%  t:#1 - arrowhead type, F  filled triangle (using current gray level)
%                         T  empty closed triangle
%                         W  white filled triangle
%                         V  Vee shape, at the end of the vector
%                         H  (or other character) Vee shape, vector stops
%                            short of the Vee
\def\arrowheadtype t:#1 {\edef\a@type{#1}}

% ===== Bezier curve
% The initial point is assumed to be the current point.  Only the last
% coordinate affects the size of the plot.
\def\clvec (#1 #2)(#3 #4)(#5 #6)%
          {\getpos (#1 #2)\a@rgx\a@rgy
           \coordtopix \a@rgx\t@pixa
           \advance \t@pixa by \x@segoffpix
           \coordtopix \a@rgy\t@pixb
           \advance \t@pixb by \y@segoffpix
           \getpos (#3 #4)\a@rgx\a@rgy
           \coordtopix \a@rgx\t@pixc
           \advance \t@pixc by \x@segoffpix
           \coordtopix \a@rgy\t@pixd
           \advance \t@pixd by \y@segoffpix
           \getpos (#5 #6)\a@rgx\a@rgy
           \s@etpospix \a@rgx \a@rgy
           \writeps {\the\t@pixa\space \the\t@pixb\space
                     \the\t@pixc\space \the\t@pixd\space
                     \the\x@pix\space \the\y@pix\space cv}}

% ===== Draw the bounding box
\def\drawbb {\bsegment
              \drawdim bp
              \linewd 0.24       % line width 1/300 inch = 0.24 bp
              \setunitscale {\p@sfactor}
              \writeps {\the\xminpix\space \the\yminpix\space mv}%
              \writeps {\the\xminpix\space \the\ymaxpix\space lv}%
              \writeps {\the\xmaxpix\space \the\ymaxpix\space lv}%
              \writeps {\the\xmaxpix\space \the\yminpix\space lv}%
              \writeps {\the\xminpix\space \the\yminpix\space lv}%
            \esegment}


% ===============================================================
% ===== Utility macros used by TeXdraw ==========================

% ===== Decode coordinates
% Get coordinates
% This macro is used to get two arguments separated by a blank, with
% possible leading and trailing blanks.  Symbolic coordinates are
% converted to user coordinates.
%  (#1 #2) - coordinates
%  #3 - macro name to receive the x-coordinate value
%  #4 - macro name to receive the y-coordinate value
\def\getpos (#1 #2)#3#4{\g@etargxy #1 #2 {} \\#3#4%
                       \c@heckast #3%
                       \ifa@st
                         \g@etsympix #3\t@pixa
                         \advance \t@pixa by -\x@segoffpix
                         \pixtocoord \t@pixa #3%
                       \fi
                       \c@heckast #4%
                       \ifa@st
                         \g@etsympix #4\t@pixa
                         \advance \t@pixa by -\y@segoffpix
                         \pixtocoord \t@pixa #4%
                       \fi}

% Get symbolic coordinate names
%  (#1 #2) - symbolic coordinates
%  #3 - macro name to receive the symbolic x coordinate name
%  #4 - macro name to receive the symbolic y coordinate name
\def\getsympos (#1 #2)#3#4{\g@etargxy #1 #2 {} \\#3#4%
                    \c@heckast #3%
                    \ifa@st \else
                      \t@xderror {TeXdraw: invalid symbolic coordinate}%
                    \fi
                    \c@heckast #4%
                    \ifa@st \else
                      \t@xderror {TeXdraw: invalid symbolic coordinate}%
                    \fi}

% ===== Convert a list of values to pixel values
%  (#1) - blank separated list of values in user coordinates
%  #2 - macro name to receive the blank separated list of pixel values
\def\listtopix (#1)#2{\def #2{}%
                     \edef\l@ist {#1 }%    % append a blank to the string
                     \m@oretrue
                     \loop
                       \expandafter\g@etitem \l@ist \\\a@rgx\l@ist
                       \a@pppix \a@rgx #2%
                       \ifx \l@ist\empty
                         \m@orefalse
                       \fi
                     \ifm@ore
                     \repeat}

% ===== Real multiplication
% This function uses the property that a box dimension may be scaled by
% a real value.  The values are converted to dimensions in units of pt.
% This choice gives us a reasonable dynamic range.  The final step is to
% clean off the "pt" on the resulting dimension.  Note that these are fixed
% point operations with each operand represented to an accuracy of about 5
% decimal places.

% Note we must use magnified points not "true" points, since the answer is
% expressed in magnified points.  The result will be calculated in the same
% manner no matter what the magnification is.
%  #1 and #2 are multiplicands
%  #3 macro name to capture the real result
\def\realmult #1#2#3{\dimen0=#1pt
                    \dimen2=#2\dimen0
                    \edef #3{\expandafter\c@lean\the\dimen2}}

% ===== Divide integers, real result
%  #1 integer numerator value
%  #2 integer denominator (divisor) value
%  #3 macro name to capture the real result
\def\intdiv #1#2#3{\t@counta=#1
                  \t@countb=#2
%  Limitations: #1 must be negatable, i.e. it must not be the largest
%                  magnitude negative number
%               #2 must be able to be multiplied by 2 without overflow
%  Calculate a*65536/b  where the factor 65536 converts from pt to sp.
%  This operation can also be interpretated as an extended precision
%  numerator divided by the denominator.  The scheme used is basically a
%  long division, except that it is bootstrapped by an integer divide.
%  The computations are carried out with positive numerator and
%  denominator, with the appropriate restoration of sign at the end.
%    \t@counta == remainder, r, initially set to a
%    \t@countb == denominator, b
%    \t@countc == quotient, q
%    \t@countd == +1, a and b have the same sign
%                 -1, a and b have opposite signs
%    \t@counte == temporary register
                  \ifnum \t@countb<0
                     \t@counta=-\t@counta
                     \t@countb=-\t@countb
                  \fi
                  \t@countd=1                    % record the sign
                  \ifnum \t@counta<0
                     \t@counta=-\t@counta
                     \t@countd=-1
                  \fi
%                                                 % q=a/b, r=a-q*b
                  \t@countc=\t@counta  \divide \t@countc by \t@countb
                  \t@counte=\t@countc  \multiply \t@counte by \t@countb
                  \advance \t@counta by -\t@counte
                  \t@counte=-1
                  \loop
                    \advance \t@counte by 1
                  \ifnum \t@counte<16                  % loop 16 times
                      \multiply \t@countc by 2           % q=2q
                      \multiply \t@counta by 2           % r=2r
                      \ifnum \t@counta<\t@countb \else   % if ( r >= b )
                        \advance \t@countc by 1          %   q=q+1
                        \advance \t@counta by -\t@countb %   r=r-b
                      \fi
                  \repeat
                  \divide \t@countb by 2         % rounding
                  \ifnum \t@counta<\t@countb     % if ( r >= b/2 ) q=q+1
                    \advance \t@countc by 1
                  \fi
                  \ifnum \t@countd<0             % restore the sign
                    \t@countc=-\t@countc
                  \fi
                  \dimen0=\t@countc sp           % express as a dimension
                  \edef #3{\expandafter\c@lean\the\dimen0}}

% ===============================================================
% ===== Internal TeXdraw macros =================================

% ===== Macros for converting between dimensions and units
% Convert drawing units (coordinate value, scaled by the unit scale and
% segment scale) to pixels.  We use rounding to get more accurate results.
%  #1 dimension in drawing units
%  #2 count in pixels (returned into a count)
\def\coordtopix #1#2{\dimen0=#1\d@dim
                    \dimen2=\d@sc\dimen0
                    \t@counta=\dimen2          % scaled dimension in sp
                    \t@countb=\s@ppix
                    \divide \t@countb by 2
                    \ifnum \t@counta<0         % rounding
                      \advance \t@counta by -\t@countb
                    \else
                      \advance \t@counta by \t@countb
                    \fi
                    \divide \t@counta by \s@ppix
                    #2=\t@counta}

% Convert from absolute pixels to relative scaled coordinates
%  #1 - input integer pixel value
%  #2 - macro name to receive the character string corresponding to the
%       floating point coordinate value
\def\pixtocoord #1#2{\t@counta=#1%
                    \multiply \t@counta by \s@ppix
                    \dimen0=\d@sc\d@dim
                    \t@countb=\dimen0
                    \intdiv \t@counta \t@countb #2}

% Convert pixels to TeX dimensions.
%  #1 - input integer pixel value
%  #2 - returned dimension (returned into a dimension register)
\def\pixtodim #1#2{\t@countb=#1%
                  \multiply \t@countb by \s@ppix
                  #2=\t@countb sp\relax}

% Convert pixels to (integer) bp units
%  #1 - input pixel value
%  #2 - integer value, returned as a macro definition
\def\pixtobp #1#2{\dimen0=\p@sfactor pt
                 \t@counta=\dimen0
                 \multiply \t@counta by #1%
                 \ifnum \t@counta < 0             % rounding
                   \advance \t@counta by -32768
                 \else
                   \advance \t@counta by 32768
                 \fi
                 \divide \t@counta by 65536
                 \edef #2{\the\t@counta}}

% ===== Allocations for registers and counts
% == Temporary count registers
\newcount\t@counta    \newcount\t@countb   % Use at lowest levels
\newcount\t@countc    \newcount\t@countd
\newcount\t@counte
\newcount\t@pixa      \newcount\t@pixb     % Use for pixel values
\newcount\t@pixc      \newcount\t@pixd

% == Temporary dimension registers
\newdimen\t@xpos      \newdimen\t@ypos

% == Position and parameter registers
% The minimum and maximum extent in the X and Y direction in pixel units
% (updated globally to reach outside segments)
\newcount\xminpix      \newcount\xmaxpix
\newcount\yminpix      \newcount\ymaxpix

% == Arrowhead parameters
\newcount\a@lenpix     \newcount\a@widpix

% == Absolute pixel positions
\newcount\x@pix        \newcount\y@pix
\newcount\x@segoffpix  \newcount\y@segoffpix
\newcount\x@savepix    \newcount\y@savepix

% == Conversion factor
\newcount\s@ppix       % sp/pixel

% == Pending segments count
\newcount\d@bs

% == Counter to form unique file names
\newcount\t@xdnum
\global\t@xdnum=0

% == TeXdraw box
\newbox\t@xdbox

% == Output stream number for the PostScript file
\newwrite\drawfile

% == \newif
\newif\ifm@pending
\newif\ifp@ath
\newif\ifa@st
\newif\ifm@ore
\newif \ift@extonly
\newif\ifp@osinit

% == \newtoks
\newtoks\everytexdraw

% ===== Character definitions
\def\l@paren{(}
\def\a@st{*}

% ===== Special character macros
% Need to be able to insert "%", "{" and "}" characters into the
% PostScript file.
% Define macros which have these characters with category "other".
% We will assume that these characters have the standard meanings -
% after all, we use comments and braces in this code.
\catcode`\%=12
 \def\p@b {%!}  \def\p@p {%%}
\catcode`\%=14
\catcode`\{=12  \catcode`\}=12  \catcode`\u=1 \catcode`\v=2
 \def\l@br u{v  \def\r@br u}v
\catcode `\{=1  \catcode`\}=2   \catcode`\u=11 \catcode`\v=11

% ===== Pixel conversion factors
% The position is kept as an integer value (count).  It is set to a
% resolution corresponding to 300 units/inch.  We refer to them as pixels,
% but in fact the resolution is just that: movements are quantized to lie
% on a grid with that resolution.

% Using pixel units which correspond to the actual resolution of the device
% has advantages in that all horizontal and vertical lines then will be
% drawn with the same line thickness.  In addition the coordinates are
% then integer values (no decimal point or leading zeros) which leads
% to a more compact PostScript file.

% The following macro sets the conversion from PostScript units (bp) to the
% integer units (pixels).  The file inclusion \special environment in the
% PostScript driver restores the context to default PostScript values
% (bp or 72/in and origin in the lower lefthand corner).  A scaling value
% of 0.24 converts to 300/inch.  Note that the PostScript commands written
% to the temporary PostScript file do not depend on the TeX magnification
% in effect.  Magnification should be handled by the dvi to PostScript
% driver at the time that the file is included in the output.

% Calculate the conversion factors
% Let s@ppix = sp/pixel = u / p, where u = sp/unit and p = pix/unit (both
% integer values).
% We calculate s@ppix as
%         s@ppix = [ (u+0.5p)/p ]
% We also calculate the PostScript scale factor bp/pixel
% Let b = sp/bp.  We want p@sfactor = s@ppix/b.  For 300 pixels/inch, this
% gives p@sfactor=0.24.  Using rounding
%         p@sfactor = [ (s@ppix+0.5b)/b ] .
% To carry out the arithmetic, we will operate in sp units (integers) and
% generate the answer in pt units (multiplying by sp/pt).  This result will
% expressed as a character string representing a real number after the "pt"
% designator is stripped off.

{\catcode`\p=12 \catcode`\t=12
\gdef\c@lean #1pt{#1}}

\def\sppix#1/#2 {\dimen0=1#2 \s@ppix=\dimen0
                \t@counta=#1%
                \divide \t@counta by 2
                \advance \s@ppix by \t@counta
                \divide \s@ppix by #1%             % \s@ppix available
                \t@counta=\s@ppix
                \multiply \t@counta by 65536       % 1 pt = 65536 sp
                \advance \t@counta by 32891        % 0.5 bp = 32890.88 sp
                \divide \t@counta by 65782         % 1 bp = 65781.76 sp
                \dimen0=\t@counta sp
                \edef\p@sfactor {\expandafter\c@lean\the\dimen0}}

% ===== Low level coordinate decoding macros
% Get two values, separated by a blank
% Invoke as \g@etargxy <stuff> {} \\\ma\mb
\def\g@etargxy #1 #2 #3 #4\\#5#6{\def #5{#1}%
                          \ifx #5\empty
                            \g@etargxy #2 #3 #4 \\#5#6%  leading blank
                          \else
                            \def #6{#2}%
                            \def\a@rg {#3}%
                            \ifx \a@rg\empty \else
                              \t@xderror {TeXdraw: invalid coordinate}%
                            \fi
                          \fi}

% Check for a leading asterisk
% Sets \a@stfalse or \a@sttrue, test with \ifa@st
\def\c@heckast #1{\expandafter
                 \c@heckastll #1\\}
\def\c@heckastll #1#2\\{\def\testit {#1}%
                       \ifx \testit\a@st
                         \a@sttrue
                       \else
                         \a@stfalse
                       \fi}

% Decode a symbolic coordinate
% Pixel value returned to a count
\def\g@etsympix #1#2{\expandafter
              \ifx \csname #1\endcsname \relax
                \t@xderror {TeXdraw: undefined symbolic coordinate}%
              \fi
              #2=\csname #1\endcsname}

% Set a macro named #1 to have value #2
\def\s@etcsn #1#2{\expandafter
                 \xdef\csname#1\endcsname {#2}}

% ===== Low level list decoding macros
% Pick off the first item -> #3, rest of string -> #4
\def\g@etitem #1 #2\\#3#4{\edef #4{#2}\edef #3{#1}}
\def\a@pppix #1#2{\edef\a@rg {#1}%
                 \ifx \a@rg\empty \else
                   \coordtopix {#1}\t@pixa
                   \ifx #2\empty
                     \edef #2{\the\t@pixa}%
                   \else
                     \edef #2{#2 \the\t@pixa}%
                   \fi
                 \fi}

% ===== Macros for updating the position
% Calculate the position in pixels and update the maximum excursions
\def\s@etpospix #1#2{\coordtopix {#1}\x@pix
                    \advance \x@pix by \x@segoffpix
                    \coordtopix {#2}\y@pix
                    \advance \y@pix by \y@segoffpix
                    \u@pdateminmax \x@pix \y@pix}

\def\r@elpospix #1#2{\coordtopix {#1}\t@pixa
                    \advance \x@pix by \t@pixa
                    \coordtopix {#2}\t@pixa
                    \advance \y@pix by \t@pixa
                    \u@pdateminmax \x@pix \y@pix}

\def\r@elupd #1#2{\t@counta=\x@pix
                 \advance\t@counta by #1%
                 \t@countb=\y@pix
                 \advance\t@countb by #2%
                 \u@pdateminmax \t@counta \t@countb}

\def\u@pdateminmax #1#2{\ifnum #1>\xmaxpix
                         \global\xmaxpix=#1%
                       \fi
                       \ifnum #1<\xminpix
                         \global\xminpix=#1%
                       \fi
                       \ifnum #2>\ymaxpix
                         \global\ymaxpix=#2%
                       \fi
                       \ifnum #2<\yminpix
                         \global\yminpix=#2%
                       \fi}

% =====  Save moves / flush moves
% A TeXdraw segment which generates only TeX text uses only move, begin
% segment and end segment commands.  The goal is to avoid writing out
% empty segments for such cases.  To this end, moves are held back and
% only written out if necessary to set the position or terminate a path.
% Also in this way, a TeXdraw drawing which generates only TeX text will
% not generate a PostScript file.

% Two flags are used.  Both flags are local to a segment.
% - move pending:  Set when a move has been invoked but the move command
%   has not been written out to the PostScript file.
% - path in progress:  Set when a PostScript path has been started but the
%   path has not been terminated and stroked.
% (1) Moves are kept back.  Using TeX's groups, a local flag and local
%     position registers are used to keep track of whether the latest
%     move applicable to a given segment has been written out or not.  In
%     effect there is a stack of pending moves, one for each level of
%     segment nesting.
% (2) At the beginning of a segment, if a PS path is in progress and a
%     a move is pending, the move is written out, terminating the path
%     and stroking the path.  This is done to ensure that the path is
%     stroked before lines and/or fills are executed in the segment.
% (3) At the beginning of a segment, if a PS path is not in progress,
%     any pending moves are kept back.  Effectively, the move will be
%     transferred into the segment.  It will be written out only when
%     the position needs to be updated for some other command.  Such
%     moves which are transferred into segments may have to be repeated
%     outside the segment.  The move pending flag will be restored to
%     the value outside the segment on exit from the segment.
% (4) A begin segment command is not written out, but instead a global
%     segment backlog counter is incremented.  The backlog of begin
%     segment commands is written out when a drawing command is
%     encountered.
% The effect of the above on the TeXdraw commands is as follows.
% (a) move:
%     - set the current position
%     - record the position of the saved move
%     - set the move pending flag
% (b) begin segment:
%     - if a path is in progress
%         - if a move is pending
%           - if there is a backlog of segments
%             - write out enough begin segments to clear the backlog
%           - write out the pending move
%           - reset the move pending flag (local to the containing segment,
%             but affects inferior segments)
%           - reset the path in progress flag
%     - increment the segment backlog counter
%     - begin a group
% (c) end segment:
%     - end a group
%     - if there is no backlog of segments
%       - write an end segment command
%     - if there is a backlog of segments
%       - decrement the backlog counter, thereby omitting an empty
%         empty segment.
%     - the move pending flag and path in progress flag are automatically
%       restored on leaving the TeX group
% (d) text:
%     - create a text box
% (e) line parameters:
%     - if there is a backlog of segments
%        - write out enough begin segments to clear the backlog
%     - clear the path in progress flag
%     - write the PS command changing the line parameter
% (f) other drawing commands:
%     - update the current position
%     - if there is a backlog of segments
%        - write out enough begin segments to clear the backlog
%     - if there is a pending move
%        - write out the pending move
%        - reset the move pending flag (local to this segment, but affects
%          inferior segments)
%     - set the path in progress flag
%     - write the drawing command
% Notes:
% (1) The es PS command strokes the path at the end of a segment to
%     ensure that the correct line parameters are used for the segment.
%     The path before the corresponding bs command is restored and
%     continued.
% (2) The \f@lushbs and \f@lushmove commands must be invoked before each
%     drawing command written to the PS file.  The macro \writeps includes
%     these operations.

% Another awkward business has to do with initialization.  We want a
% default (0 0) initial position so that the user can draw vectors
% immediately.  However, if the user specifies another move before
% beginning to draw, that position should be the initial position.  The
% importance of this initial position is that the determination of the
% maximum excursion must take this value into account.  We handle the
% initialization in the \s@avemove and \f@lushmove macros.  The macro
% \ifp@osinit indicates whether the next move should be captured as the
% initial values for \xminpix, \yminpix, \xmaxpix, and \ymaxpix.  However,
% if a \f@lushmove is invoked, then we assume that the appropriate initial
% values have already been set.  The "mv" command in PostScript is defined
% to stroke the current path (if any) and move to the pixel coordinates
% specified.

% Note that \m@pendingtrue and \m@pendingfalse define the flag locally.
% In addition, \x@savepix and \y@savepix are local variables.  We make
% use of the fact that the values of the flag and positions propagate
% down to inferior segments but not up to superior segments.  This
% behaviour Is consistent with the gsave/grestore operation on the
% PostScript side.
\def\s@avemove #1#2{\x@savepix=#1\y@savepix=#2%
                   \m@pendingtrue
                   \ifp@osinit \else
                     \global\p@osinittrue
                     \global\xminpix=\x@savepix \global\yminpix=\y@savepix
                     \global\xmaxpix=\x@savepix \global\ymaxpix=\y@savepix
                   \fi}

\def\f@lushmove {\global\p@osinittrue
                \ifm@pending
                  \writetx {\the\x@savepix\space \the\y@savepix\space mv}%
                  \m@pendingfalse
                  \p@athfalse
                \fi}

% =====  Flush begin segment
% \f@lushbs flushes any saved up \bsegments.  Some of these may be
% redundant, but we cannot know without looking ahead beyond the
% \esegment.
\def\f@lushbs {\loop
                \ifnum \d@bs>0
                  \writetx {bs}%
                  \global\advance \d@bs by -1
              \repeat}

% ===== Internal text macros
% Horizontal text, use only 3 levels of box nesting here
\def\h@move #1#2 #3)#4{\move (#2 #3)%
                      \h@text {#4}}
\def\h@text #1{\pixtodim \x@pix \t@xpos
              \pixtodim \y@pix \t@ypos
              \vbox to 0pt{\normalbaselines
                           \t@stuff
                           \kern -\t@ypos
                           \hbox to 0pt{\l@stuff
                                        \kern \t@xpos
                                        \hbox {#1}%
                                        \kern -\t@xpos
                                        \r@stuff}%
                           \kern \t@ypos
                           \b@stuff\relax}}

% Rotated text
% Uses 5 levels of box nesting here (so that the text reference point
% is that <before> rotation).  This was done so that the reference point
% definition makes sense with arbitrary angle rotation.  The text is
% rotated with respect to the text reference point.  The result is zero
% sized.  These macros generate in-line PostScript.
% #1 - rotation angle in degrees
% #2 - text to be rotated
\def\r@move td:#1 #2#3 #4)#5{\move (#3 #4)%
                            \r@text td:#1 {#5}}
\def\r@text td:#1 #2{\vbox to 0pt{\pixtodim \x@pix \t@xpos
                                 \pixtodim \y@pix \t@ypos
                                 \kern -\t@ypos
                                 \hbox to 0pt{\kern \t@xpos
                                              \rottxt {#1}{\z@sb {#2}}%
                                              \hss}%
                                 \vss}}
\def\z@sb #1{\vbox to 0pt{\normalbaselines
                         \t@stuff
                         \hbox to 0pt{\l@stuff \hbox {#1}\r@stuff}%
                         \b@stuff}}

% ===== Rotate text, in-line PostScript code
\ifx \rotatebox\@undefined
 \def\rottxt #1#2{\bgroup
                    \special {ps: gsave currentpoint currentpoint translate
                              #1\space neg rotate
                             neg exch neg exch translate}%
                    #2%
                    \special {ps: currentpoint grestore moveto}%
                  \egroup}
\else
 \let\rottxt=\rotatebox
\fi

% ===== Error message
% If not defined, use the plain TeX errmessage macro
\ifx \t@xderror\@undefined
 \let\t@xderror=\errmessage
\fi

% ===== Default values
% These are reset each time TeXdraw is invoked
\def\t@exdrawdef {\sppix 300/in            % 300 pixels/inch
                 \drawdim in              % drawing units are inches
                 \edef\u@nitsc {1}%       % unit scale 1 (has to be set
                                          % before invoking \setsegscale)
                 \setsegscale 1           % segment scale 1
                 \arrowheadsize l:0.16 w:0.08
                 \arrowheadtype t:T
                 \textref h:L v:B }


% ===============================================================
% ===== PostScript file macros ==================================

% ===== Include the TeXdraw graphics
% The drawing in a box of appropriate size will be placed such that its
% lower left hand corner will be at the current TeX position.
\ifx \includegraphics\@undefined
 \def\t@xdinclude [#1,#2][#3,#4]#5{%
   \begingroup                           % keep definitions local
     \message {<#5>}%
     \leavevmode
     \t@counta=-#1%                      % integer bounding box coordinates
     \t@countb=-#2%
     \setbox0=\hbox{%
       \special {PSfile="#5"\space
                 hoffset=\the\t@counta\space voffset=\the\t@countb}}%
     \t@ypos=#4 bp%
       \advance \t@ypos by -#2 bp%
     \t@xpos=#3 bp%
       \advance \t@xpos by -#1 bp%
     \dp0=0pt \ht0=\t@ypos \wd0=\t@xpos
     \box0%
   \endgroup}
\else
 \let\t@xdinclude=\includegraphics
\fi

% Leave space without including a PS file
\def\t@xdempty [#1,#2][#3,#4]{%
 \begingroup
   \leavevmode
   \setbox0=\hbox{}%
   \t@ypos=#4 bp%
     \advance \t@ypos by -#2 bp%
   \t@xpos=#3 bp%
     \advance \t@xpos by -#1 bp%
   \dp0=0pt \ht0=\t@ypos \wd0=\t@xpos
   \box0%
 \endgroup}

% ===== Write to the PostScript file
% Macro to write PostScript commands to the temporary PostScript file
% To decrease the size of the PostScript file, moves are kept back to
% allow redundant multiple moves to be removed.  In addition empty gsave/
% grestore pairs are not written.  The PostScript file is not opened if
% TeXdraw has not generated any PostScript commands, i.e. it has produced
% only TeX text.
% \writeps : flushes the pending move to make sure things are positioned
%            correctly and flushes pending begin segments before calling
%            \writetx to write to the PostScript file
% \writetx : writes directly to the PostScript file.  This version is used
%            only for those commands which just change line parameters
%            without drawing.  This routine opens the file and writes the
%            PS file header the first time it is called.
% \p@swr :   lowest level direct write to the PostScript file
\def\writeps #1{\f@lushbs
               \f@lushmove
               \p@athtrue
               \writetx {#1}}
\def\writetx #1{\p@sopen
               \ifx\p@sfile\p@sundef \else
                 \p@swr {#1}%
               \fi}
\def\p@swr #1{\immediate\write\drawfile {#1}}

% ===== Open/Close a PostScript file
% Open a PostScript file, write the definitions used by TeXdraw.
\xdef\p@sundef{UnDeFiNeD}
\def\p@sopen {%
 \ifx\p@sfile\p@sundef
   \p@sopenI
 \fi
}
% The code has a hook to avoid generating the PS file under certain
% circumstances.  The amsmath package sometimes sets an expression twice,
% once to measure it and again to actually typeset it.  In the first case,
% \ifmeasuring@ is set to true.  For that setting, the PS file is not
% generated.
\def\p@sopenI {%
 \ifx\ifmeasuring@\iftrue \else  % \ifmeasuring@ undefined or false
   \global\advance \t@xdnum by 1
   \ifnum \t@xdnum<10
     \xdef \p@sfile{\jobname.ps\the\t@xdnum}%
   \else
     \xdef \p@sfile{\jobname.p\the\t@xdnum}%
   \fi
   \t@xdopen \p@sfile
 \fi
}

\def\p@sclose {
 \ifx\p@sfile\p@sundef \else
   \t@xdclose
 \fi
}
\def\t@xdopen #1{%
 \immediate\openout\drawfile=#1%
 \p@swr {\p@b PS-Adobe-3.0 EPSF-3.0}%
 \p@swr {\p@p BoundingBox: (atend)}%
 \p@swr {\p@p Title: TeXdraw drawing: #1}%
 \p@swr {\p@p Pages: 1}%
 \p@swr {\p@p Creator: \TeXdrawId}%
 \p@swr {\p@p CreationDate: \the\year/\the\month/\the\day}%
 \p@swr {50 dict begin}%
 \p@swr {/mv {stroke moveto} def}%
 \p@swr {/lv {lineto} def}%
 \p@swr {/st {currentpoint stroke moveto} def}%
 \p@swr {/sl {st setlinewidth} def}%
 \p@swr {/sd {st 0 setdash} def}%
 \p@swr {/sg {st setgray} def}%
 \p@swr {/bs {gsave} def /es {stroke grestore} def}%
 \p@swr {/fl \l@br gsave setgray fill grestore}%
 \p@swr    { currentpoint newpath moveto\r@br\space def}%
 \p@swr {/fp {gsave setgray fill grestore st} def}%
 \p@swr {/cv {curveto} def}%
 \p@swr {/cr \l@br gsave currentpoint newpath 3 -1 roll 0 360 arc}%
 \p@swr    { stroke grestore\r@br\space def}%
 \p@swr {/fc \l@br gsave setgray currentpoint newpath}%
 \p@swr    { 3 -1 roll 0 360 arc fill grestore\r@br\space def}%
 \p@swr {/ar {gsave currentpoint newpath 5 2 roll arc stroke grestore} def}%
 \p@swr {/el \l@br gsave /svm matrix currentmatrix def}%
 \p@swr    { currentpoint translate scale newpath 0 0 1 0 360 arc}%
 \p@swr    { svm setmatrix stroke grestore\r@br\space def}%
 \p@swr {/fe \l@br gsave setgray currentpoint translate scale newpath}%
 \p@swr    { 0 0 1 0 360 arc fill grestore\r@br\space def}%
 \p@swr {/av \l@br /hhwid exch 2 div def /hlen exch def}%
 \p@swr    { /ah exch def /tipy exch def /tipx exch def}%
 \p@swr    { currentpoint /taily exch def /tailx exch def}%
 \p@swr    { /dx tipx tailx sub def /dy tipy taily sub def}%
 \p@swr    { /alen dx dx mul dy dy mul add sqrt def}%
 \p@swr    { /blen alen hlen sub def}%
 \p@swr    { gsave tailx taily translate dy dx atan rotate}%
 \p@swr    { (V) ah ne {blen 0 gt {blen 0 lineto} if} {alen 0 lineto} ifelse}%
 \p@swr    { stroke blen hhwid neg moveto alen 0 lineto blen hhwid lineto}%
 \p@swr    { (T) ah eq {closepath} if}%
 \p@swr    { (W) ah eq {gsave 1 setgray fill grestore closepath} if}%
 \p@swr    { (F) ah eq {fill} {stroke} ifelse}%
 \p@swr    { grestore tipx tipy moveto\r@br\space def}%
 \p@swr {\p@sfactor\space \p@sfactor\space scale}%
 \p@swr {1 setlinecap 1 setlinejoin}%
 \p@swr {3 setlinewidth [] 0 setdash}%
 \p@swr {0 0 moveto}%
}

% Notes:
% - mv (move to) This command includes a stroke before the moveto.  The
%      stroke terminates a path and the move begins another path.
% - bs (begin segment) encloses a segment in a gsave/grestore to keep
%      changes to line parameters local.
% - es (end segment) does a "stroke grestore" to make sure lines inside
%      the segment use the line parameters local to that segment
% - ar (arc) The path is generated and stroked inside a gsave/grestore,
%      leaving the current path intact.
% - cr (circle) The path is generated and stroked inside a gsave/grestore,
%      leaving the current path intact.
% - fc (filled circle) The path is generated and filled inside a gsave/
%      grestore, keeping the fill level local to the circle.  The current
%      path is left intact.
% - el (ellipse) The path is generated and stroked inside a gsave/grestore,
%      leaving the current path intact.  The elliptical path is defined
%      with different x and y scaling, then stroked with default scaling
%      to give a constant line thickness.
% - fe (filled ellipse) The path is generated and filled inside a gsave/
%      grestore, leaving the current path intact.
% - fl (fill) The current path is closed and filled inside a gsave/restore,
%      keeping the fill level local.  A newpath terminates the path.
% - fp (fill path) The current path is closed and then filled inside a
%      gsave/grestore.  Finally the closed path is stroked, implicitly
%      terminating the path.
% - av (arrow vector) The arrow vector is drawn inside a gsave/grestore.
%      The line width and type are those currently in effect.  After the
%      grestore, the current path is continued with a move to the tip of
%      the vector.

% ===== Close the PostScript file
% Write a trailer with the BoundingBox, close the file.  Note that the
% BoundingBox may be larger than the commands in the PostScript file
% indicate.  This is due to the fact that multiple move commands in
% a row are collapsed into a single move.  The BoundingBox information
% includes the effect of the moves which were expunged.
\def\t@xdclose {%
 \bgroup
   \p@swr {stroke end showpage}%
   \p@swr {\p@p Trailer:}%
   \pixtobp \xminpix \l@lxbp  \pixtobp \yminpix \l@lybp
   \pixtobp \xmaxpix \u@rxbp  \pixtobp \ymaxpix \u@rybp
   \p@swr {\p@p BoundingBox: \l@lxbp\space \l@lybp\space
                             \u@rxbp\space \u@rybp}%
   \p@swr {\p@p EOF}%
 \egroup
 \immediate\closeout\drawfile
}

% ===============================================================
\catcode`\@=\catamp