Topological Recursion Relations by Localization
Eric Edward Katz
pictex.tex
% This is PiCTeX, Version 1.1   9/21/87
 
% CAVEAT: The PiCTeX manual often has a more lucid explanation
%   of any given topic than you will find in the internal documentation
%   of the macros.
 
% PiCTeX's commands can be classified into two groups: (1) public (or
%   external), and (2) private (or internal). The public macros are
%   discussed at length in the manual. The only discussion of the private
%   macros is the internal documentation. The private macros all have
%   names beginning with an exclamation point (!) of category code 11. 
%   Since in normal usage "!" has category code 12, these macros can't
%   be accessed or modified by the general user.
 
% The macros are organized into thematically related groups. For example,
%   the macros dealing with dots & dashes are all in the DASHPATTERN group.
%   The table below shows which macros are in which groups. The table
%   covers all public macros, and many (but not all) of PiCTeX's upper level
%   private macros. Following the table, the various groups are listed
%   in the order in which they appear in the table.
 
% *********************** TABLE OF GROUPS OF MACROS **********************
 
% HACKS:  Utility macros
%    \PiC
%    \PiCTeX
%    \placevalueinpts 
%    \!!loop 
%    \!cfor
%    \!copylist
%    \!ecfor
%    \!etfor
%    \!getnext
%    \!getnextvalueof
%    \!ifempty
%    \!ifnextchar
%    \!leftappend
%    \!listaddon 
%    \!loop
%    \!lop
%    \!mlap
%    \!not
%    \!removept
%    \!rightappend
%    \!tfor 
%    \!vmlap
%    \!wlet
 
% ALLOCATION:  Allocates registers
 
% AREAS: Deals with plot areas 
%    \axis
%    \grid 
%    \invisibleaxes
%    \normalgraphs 
%    \plotheading 
%    \setplotarea
%    \visibleaxes
 
% ARROWS:  Draws arrows
%    \arrow
%    \betweenarrows
 
% BARS:  Draws bars
%    \putbar 
%    \setbars
 
% BOXES:  Draws rectangles
%    \frame
%    \putrectangle 
%    \rectangle
%    \shaderectangleson
%    \shaderectanglesoff
 
% CURVES:  Upper level plot commands
%    \hshade 
%    \plot 
%    \sethistograms
%    \setlinear
%    \setquadratic
%    \vshade
 
% DASHPATTERNS:  Sets up dash patterns
%    \findlength 
%    \setdashes 
%    \setdashesnear
%    \setdashpattern
%    \setdots 
%    \setdotsnear 
%    \setsolid
%    \!dashingoff
%    \!dashingon
 
% DIVISION:  Does long division of dimension registers
%    \Divide 
%    \!divide
 
% ELLIPSES:  Draws ellipses and circles
%    \circulararc 
%    \ellipticalarc 
 
% RULES:  Draws rules, i.e., horizontal & vertical lines
%    \putrule 
%    \!putdashedhline
%    \!putdashedvline
%    \!puthline 
%    \!putsolidhline  
%    \!putsolidvline  
%    \!putvline
 
% LINEAR ARC:  Draws straight lines -- solid and dashed
%    \inboundscheckoff
%    \inboundscheckon
%    \!advancedashing 
%    \!drawlinearsegment
%    \!initinboundscheck
%    \!linearsolid
%    \!lineardashed
%    \!ljoin
%    \!plotifinbounds     
%    \!start 
 
% LOGTEN:  Log_10 function
%    \!logten
 
% PICTURES:  Basic setups for PiCtures; \put commands
%    \accountingoff
%    \accountingon
%    \beginpicture
%    \endpicture    
%    \endpicturesave 
%    \lines
%    \multiput
%    \put 
%    \setcoordinatemode
%    \setcoordinatesystem
%    \setdimensionmode
%    \stack 
%    \Lines
%    \Xdistance
%    \Ydistance
%    \!dimenput
%    \!ifcoordmode
%    \!ifdimenmode
%    \!setcoordmode
%    \!setdimenmode
%    \!setputobject
   
% PLOTTING:  Things to do with plotting
%    \dontsavelinesandcurves
%    \replot
%    \savelinesandcurves 
%    \setplotsymbol
%    \writesavefile 
%    \!plot
 
% PYTHAGORAS:  Euclidean distance function
%    \placehypotenuse 
%    \!Pythag
 
% QUADRATIC ARC:  Draws a quadratic arc
%    \!qjoin 
 
% ROTATIONS:  Handles rotations
%    \startrotation 
%    \stoprotation
%    \!rotateaboutpivot
%    \!rotateonly
 
% SHADING:  Handles shading
%    \setshadegrid 
%    \setshadesymbol
%    \!lshade
%    \!qshade
%    \!starthshade
%    \!startvshade  
 
% TICKS:  Draws ticks on graphs
%    \gridlines
%    \loggedticks
%    \nogridlines
%    \ticksin
%    \ticksout
%    \unloggesticks
 
% ***************** END OF TABLE OF GROUPS OF MACROS ********************


\catcode`!=11 %  ***** THIS MUST NEVER BE OMITTED
% *******************************
% *** HACKS  (Utility macros) ***
% *******************************
 
% ** User commands
% **   \PiC{P\kern-.12em\lower.5ex\hbox{I}\kern-.075emC}
% **   \PiCTeX{\PiC\kern-.11em\TeX}
% **   \placevalueinpts of <DIMENSION REGISTER> in {CONTROL SEQUENCE}
  
% ** Internal commands
% **   \!ifnextchar{CHARACTER}{TRUE ACTION}{FALSE ACTION}
% **   \!tfor NAME := LIST \do {BODY}
% **   \!etfor NAME:= LIST \do {BODY}
% **   \!cfor NAME := LIST \do {BODY}
% **   \!ecfor NAME:= LIST \do {BODY}
% **   \!ifempty{MACRO}{TRUE ACTION}{FALSE ACTION}
% **   \!getnext\\ITEMfrom\LIST
% **   \!getnextvalueof\DIMEN\from\LIST
% **   \!copylist\LISTMACRO_A\to\LISTMACRO_B
% **   \!wlet\CONTROL_SEQUENCE_A=\CONTROL_SEQUENCE_B
% **   \!listaddon ITEM LIST
% **   \!rightappendITEM\withCS\to\LISTMACRO
% **   \!leftappendITEM\withCS\to\LISTMACRO
% **   \!lop\LISTMACRO\to\ITEM
% **   \!loop ... repeat
% **   \!!loop ... repeat
% **   \!removept{DIMENSION REGISTER}{CONTROL SEQUENCE}
% **   \!mlap{...}  
% **   \!vmlap{...}
% **   \!not{TEK if-CONDITION}

% ** First, here are the the PiCTeX logo, and the syllable PiC:
\def\PiC{P\kern-.12em\lower.5ex\hbox{I}\kern-.075emC}
\def\PiCTeX{\PiC\kern-.11em\TeX}

% ** The following macro expands to parameter #2 or parameter #3 according to
% ** whether the next non-blank character following the macro is or is not #1. 
% ** Blanks following the macro are gobbled.
\def\!ifnextchar#1#2#3{%
  \let\!testchar=#1%
  \def\!first{#2}%
  \def\!second{#3}%
  \futurelet\!nextchar\!testnext}
\def\!testnext{%
  \ifx \!nextchar \!spacetoken 
    \let\!next=\!skipspacetestagain
  \else
    \ifx \!nextchar \!testchar
      \let\!next=\!first
    \else 
      \let\!next=\!second 
    \fi 
  \fi
  \!next}
\def\\{\!skipspacetestagain} 
  \expandafter\def\\ {\futurelet\!nextchar\!testnext} 
\def\\{\let\!spacetoken= } \\  %  ** set \spacetoken to a space token
 
 
% ** Borrow the "tfor" macro from Latex:
% **   \!tfor NAME := LIST \do {BODY}
% **   if, before expansion, LIST = T1 ... Tn,  where each  Ti  is a token
% **   or  {...},  then executes  BODY  n  times, with  NAME = Ti  on the
% **   i-th iteration.  Works for  n=0.
\def\!tfor#1:=#2\do#3{%
  \edef\!fortemp{#2}%
  \ifx\!fortemp\!empty 
    \else
    \!tforloop#2\!nil\!nil\!!#1{#3}%
  \fi}
\def\!tforloop#1#2\!!#3#4{%
  \def#3{#1}%
  \ifx #3\!nnil
    \let\!nextwhile=\!fornoop
  \else
    #4\relax
    \let\!nextwhile=\!tforloop
  \fi 
  \!nextwhile#2\!!#3{#4}}
 
 
% **   \!etfor NAME:= LIST\do {BODY}
% **   This is like \!cfor, but LIST is any balanced token list whose complete
% **     expansion has the form  T1 ... Tn
\def\!etfor#1:=#2\do#3{%
  \def\!!tfor{\!tfor#1:=}%
  \edef\!!!tfor{#2}%
  \expandafter\!!tfor\!!!tfor\do{#3}}
 
 
% **   modify the Latex \tfor (token-for) loop to a \cfor (comma-for) loop.
% **   \!cfor NAME := LIST \do {BODY}
% **     if, before expansion, LIST = a1,a2,...an, then executes  BODY n times,
% **     with  NAME = ai  on the i-th iteration.  Works for  n=0.
\def\!cfor#1:=#2\do#3{%
  \edef\!fortemp{#2}%
  \ifx\!fortemp\!empty 
  \else
    \!cforloop#2,\!nil,\!nil\!!#1{#3}%
  \fi}
\def\!cforloop#1,#2\!!#3#4{%
  \def#3{#1}%
  \ifx #3\!nnil
    \let\!nextwhile=\!fornoop 
  \else
    #4\relax
    \let\!nextwhile=\!cforloop
  \fi
  \!nextwhile#2\!!#3{#4}}
 
 
% **   \!ecfor NAME:= LIST\do {BODY}
% **   This is like \!cfor, but LIST is any balanced token list whose complete
% **     expansion has the form  a1,a2,...,an.
\def\!ecfor#1:=#2\do#3{%
  \def\!!cfor{\!cfor#1:=}%
  \edef\!!!cfor{#2}%
  \expandafter\!!cfor\!!!cfor\do{#3}}
 
 
\def\!empty{}
\def\!nnil{\!nil}
\def\!fornoop#1\!!#2#3{}
 
 
% **  \!ifempty{ARG}{TRUE ACTION}{FALSE ACTION}
\def\!ifempty#1#2#3{%
  \edef\!emptyarg{#1}%
  \ifx\!emptyarg\!empty
    #2%
  \else
    #3%
  \fi}
 
% **  \!getnext\\ITEMfrom\LIST
% **    \LIST has the form \\{item1}\\{item2}\\{item3}...\\{itemk}
% **    This routine sets \ITEM to item1, and cycles \LIST to
% **    \\{item2}\\{item3}...\\{itemk}\\{item1}
\def\!getnext#1\from#2{%
  \expandafter\!gnext#2\!#1#2}%
\def\!gnext\\#1#2\!#3#4{%
  \def#3{#1}%
  \def#4{#2\\{#1}}%
  \ignorespaces}
 
 
% ** \!getnextvalueof\DIMEN\from\LIST
% **   Similar to !getnext.  
% **   \LIST has the form \\{dimen1}\\{dimen2}\\{dimen3} ... 
% **   \DIMEN is a dimension register
% **   Works also for counts
%
\def\!getnextvalueof#1\from#2{%
  \expandafter\!gnextv#2\!#1#2}%
\def\!gnextv\\#1#2\!#3#4{%
  #3=#1%
  \def#4{#2\\{#1}}%
  \ignorespaces}
 
 
% ** \!copylist\LISTMACROA\to\LISTMACROB
% **   makes the replacement text of LISTMACRO B identical to that of
% **   list macro A.
\def\!copylist#1\to#2{%
  \expandafter\!!copylist#1\!#2}
\def\!!copylist#1\!#2{%
  \def#2{#1}\ignorespaces}
 
 
% **  \!wlet\CSA=\CSB
% **  lets control sequence \CSB = control sequence \CSA, and writes a
% **    message to that effect in the log file using plain TEK's \wlog
\def\!wlet#1=#2{%
  \let#1=#2 
  \wlog{\string#1=\string#2}}
 
% ** \!listaddon ITEM LIST
% ** LIST <-- LIST \\ ITEM
\def\!listaddon#1#2{%
  \expandafter\!!listaddon#2\!{#1}#2}
\def\!!listaddon#1\!#2#3{%
  \def#3{#1\\#2}}
 
% **  \!rightappendITEM\to\LISTMACRO
% **    \LISTMACRO --> \LISTMACRO\\{ITEM}
%\def\!rightappend#1\to#2{\expandafter\!!rightappend#2\!{#1}#2}
%\def\!!rightappend#1\!#2#3{\def#3{#1\\{#2}}}
 
 
% **  \!rightappendITEM\withCS\to\LISTMACRO
% **    \LISTMACRO --> \LISTMACRO||CS||{ITEM}
\def\!rightappend#1\withCS#2\to#3{\expandafter\!!rightappend#3\!#2{#1}#3}
\def\!!rightappend#1\!#2#3#4{\def#4{#1#2{#3}}}
 
 
% **  \!leftappendITEM\withCS\to\LISTMACRO
% **    \LISTMACRO --> CS||{ITEM}||\LISTMACRO
\def\!leftappend#1\withCS#2\to#3{\expandafter\!!leftappend#3\!#2{#1}#3}
\def\!!leftappend#1\!#2#3#4{\def#4{#2{#3}#1}}
 
 
% **  \!lop\LISTMACRO\to\ITEM
% **    \\{item1}\\{item2}\\{item3} ... --> \\{item2}\\{item3} ...
% **    item1 --> \ITEM
\def\!lop#1\to#2{\expandafter\!!lop#1\!#1#2}
\def\!!lop\\#1#2\!#3#4{\def#4{#1}\def#3{#2}}
 
 
% **  \!placeNUMBER\of\LISTMACRO\in\ITEM
% **    the NUMBERth item of \LISTMACRO --> replacement text of \ITEM
%\def\!place#1\of#2\in#3{\def#3{\outofrange}%
%{\count0=#1\def\\##1{\advance\count0-1 \ifnum\count0=0 \gdef#3{##1}\fi}#2}}
 
 
% **  Following code converts a commalist to a list macro, with all items 
% **    fully expanded.
%\!ecfor\item:=\commalist\do{\expandafter\!rightappend\item\to\list}
 
 
% ** \!loop ... repeat
% ** This is exactly like TEX's \loop ... repeat.  It can be used in nesting
% ** two loops, without puting the inner one inside a group.
\def\!loop#1\repeat{\def\!body{#1}\!iterate}
\def\!iterate{\!body\let\!next=\!iterate\else\let\!next=\relax\fi\!next}
 
% ** \!!loop ... repeat
% ** This is exactly like TEX's \loop ... repeat.  It can be used in nesting
% ** two loops, without puting the inner one inside a group.
\def\!!loop#1\repeat{\def\!!body{#1}\!!iterate}
\def\!!iterate{\!!body\let\!!next=\!!iterate\else\let\!!next=\relax\fi\!!next}
%  (\multiput uses \!!loop)
 
% ** \!removept{DIMENREG}{\CS}
% ** Defines the control sequence CS to be the value (in points) in the
% ** dimension register DIMENREG (but without the "pt" TEK usually adds)
% ** E.g., after  \dimen0=12.3pt \!removept\dimen0\A, \A expands to 12.3
\def\!removept#1#2{\edef#2{\expandafter\!!removePT\the#1}}
{\catcode`p=12 \catcode`t=12 \gdef\!!removePT#1pt{#1}}

% ** \pladevalueinpts of <DIMENSION REGISTER> in {CONTROL SEQUENCE}
\def\placevalueinpts of <#1> in #2 {%
  \!removept{#1}{#2}}
 
% ** \!mlap{...}  \!vmlap{...}
% ** Center  ...  in a box of width 0.
\def\!mlap#1{\hbox to 0pt{\hss#1\hss}}
\def\!vmlap#1{\vbox to 0pt{\vss#1\vss}}
 
% ** \!not{TEK if-CONDITION}
% ** By a TEK if-CONDITION is meant something like 
% **     \ifnum\N<0,   or   \ifdim\A>\B
% ** \!not produces an if-condition which is false if the original condition
% ** is true, and true if the original condition is false.
\def\!not#1{%
  #1\relax
    \!switchfalse
  \else
    \!switchtrue
  \fi
  \if!switch
  \ignorespaces}
 

% *******************
% *** ALLOCATIONS ***
% *******************

% This section allocates all the registers PiCTeX uses. Following
% each allocation is a string of the form  ....N.D...L......... ;
% the various letters show which sections of PiCTeX make explicit
% reference to that register, according to the following code:
 
%   H Hacks
%   A Areas
%   W arroWs
%   B Bars
%   X boXes
%   C Curves
%   D Dashpattterns
%   V diVision
%   E Ellipses
%   U rUles
%   L Linear arc
%   G loGten
%   P Pictures
%   O plOtting
%   Y pYthagoras
%   Q Quadratic arc
%   R Rotations
%   S Shading
%   T Ticks

% Turn off messages from TeX's allocation macros
\let\!!!wlog=\wlog              % "\wlog" is defined in plain TeX
\def\wlog#1{}    

\newdimen\headingtoplotskip     %.A.................
\newdimen\linethickness         %.A..X....U........T
\newdimen\longticklength        %.A................T
\newdimen\plotsymbolspacing     %......D...L....Q...
\newdimen\shortticklength       %.A................T
\newdimen\stackleading          %.A..........P......
\newdimen\tickstovaluesleading  %.A................T
\newdimen\totalarclength        %......D...L....Q...
\newdimen\valuestolabelleading  %.A.................

\newbox\!boxA                   %.AW...............T
\newbox\!boxB                   %..W................
\newbox\!picbox                 %............P......
\newbox\!plotsymbol             %..........L..O.....
\newbox\!putobject              %............PO...S.
\newbox\!shadesymbol            %.................S.

\newcount\!countA               %.A....D..UL....Q.ST
\newcount\!countB               %......D..U.....Q.ST
\newcount\!countC               %...............Q..T
\newcount\!countD               %...................
\newcount\!countE               %.............O....T
\newcount\!countF               %.............O....T
\newcount\!countG               %..................T
\newcount\!fiftypt              %.........U.........
\newcount\!intervalno           %..........L....Q...
\newcount\!npoints              %..........L........
\newcount\!nsegments            %.........U.........
\newcount\!ntemp                %............P......
\newcount\!parity               %.................S.
\newcount\!scalefactor          %..................T
\newcount\!tfs                  %.......V...........
\newcount\!tickcase             %..................T

\newdimen\!Xleft                %............P......
\newdimen\!Xright               %............P......
\newdimen\!Xsave                %.A................T
\newdimen\!Ybot                 %............P......
\newdimen\!Ysave                %.A................T
\newdimen\!Ytop                 %............P......
\newdimen\!angle                %........E..........
\newdimen\!arclength            %..W......UL....Q...
\newdimen\!areabloc             %.A........L........
\newdimen\!arealloc             %.A........L........
\newdimen\!arearloc             %.A........L........
\newdimen\!areatloc             %.A........L........
\newdimen\!bshrinkage           %.................S.
\newdimen\!checkbot             %..........L........
\newdimen\!checkleft            %..........L........
\newdimen\!checkright           %..........L........
\newdimen\!checktop             %..........L........
\newdimen\!dimenA               %.AW.X.DVEUL..OYQRST
\newdimen\!dimenB               %....X.DVEU...O.QRS.
\newdimen\!dimenC               %..W.X.DVEU......RS.
\newdimen\!dimenD               %..W.X.DVEU....Y.RS.
\newdimen\!dimenE               %..W........G..YQ.S.
\newdimen\!dimenF               %...........G..YQ.S.
\newdimen\!dimenG               %...........G..YQ.S.
\newdimen\!dimenH               %...........G..Y..S.
\newdimen\!dimenI               %...BX.........Y....
\newdimen\!distacross           %..........L....Q...
\newdimen\!downlength           %..........L........
\newdimen\!dp                   %.A..X.......P....S.
\newdimen\!dshade               %.................S.
\newdimen\!dxpos                %..W......U..P....S.
\newdimen\!dxprime              %...............Q...
\newdimen\!dypos                %..WB.....U..P......
\newdimen\!dyprime              %...............Q...
\newdimen\!ht                   %.A..X.......P....S.
\newdimen\!leaderlength         %......D..U.........
\newdimen\!lshrinkage           %.................S.
\newdimen\!midarclength         %...............Q...
\newdimen\!offset               %.A................T
\newdimen\!plotheadingoffset    %.A.................
\newdimen\!plotsymbolxshift     %..........L..O.....
\newdimen\!plotsymbolyshift     %..........L..O.....
\newdimen\!plotxorigin          %..........L..O.....
\newdimen\!plotyorigin          %..........L..O.....
\newdimen\!rootten              %...........G.......
\newdimen\!rshrinkage           %.................S.
\newdimen\!shadesymbolxshift    %.................S.
\newdimen\!shadesymbolyshift    %.................S.
\newdimen\!tenAa                %...........G.......
\newdimen\!tenAc                %...........G.......
\newdimen\!tenAe                %...........G.......
\newdimen\!tshrinkage           %.................S.
\newdimen\!uplength             %..........L........
\newdimen\!wd                   %....X.......P....S.
\newdimen\!wmax                 %...............Q...
\newdimen\!wmin                 %...............Q...
\newdimen\!xB                   %...............Q...
\newdimen\!xC                   %...............Q...
\newdimen\!xE                   %..W.....E.L....Q.S.
\newdimen\!xM                   %..W.....E......Q.S.
\newdimen\!xS                   %..W.....E.L....Q.S.
\newdimen\!xaxislength          %.A................T
\newdimen\!xdiff                %..........L........
\newdimen\!xleft                %............P......
\newdimen\!xloc                 %..WB.....U.......S.
\newdimen\!xorigin              %.A........L.P....S.
\newdimen\!xpivot               %................R..

\newdimen\!xpos                 %..........L.P..Q.ST
\newdimen\!xprime               %...............Q...
\newdimen\!xright               %............P......
\newdimen\!xshade               %.................S.
\newdimen\!xshift               %..W.........PO...S.
\newdimen\!xtemp                %............P......
\newdimen\!xunit                %.AWBX...EUL.P..QRS.
\newdimen\!xxE                  %........E..........
\newdimen\!xxM                  %........E..........
\newdimen\!xxS                  %........E..........
\newdimen\!xxloc                %..WB....EU.........
\newdimen\!yB                   %...............Q...
\newdimen\!yC                   %...............Q...
\newdimen\!yE                   %..W.....E.L....Q...
\newdimen\!yM                   %..W.....E......Q...
\newdimen\!yS                   %..W.....E.L....Q...
\newdimen\!yaxislength          %.A................T
\newdimen\!ybot                 %............P......
\newdimen\!ydiff                %..........L........
\newdimen\!yloc                 %..WB.....U.......S.
\newdimen\!yorigin              %.A........L.P....S.
\newdimen\!ypivot               %................R..
\newdimen\!ypos                 %..........L.P..Q.ST
\newdimen\!yprime               %...............Q...
\newdimen\!yshade               %.................S.
\newdimen\!yshift               %..W.........PO...S.
\newdimen\!ytemp                %............P......
\newdimen\!ytop                 %............P......
\newdimen\!yunit                %.AWBX...EUL.P..QRS.
\newdimen\!yyE                  %........E..........
\newdimen\!yyM                  %........E..........
\newdimen\!yyS                  %........E..........
\newdimen\!yyloc                %..WB....EU.........
\newdimen\!zpt                  %.AWBX.DVEULGP.YQ.ST

\newif\if!axisvisible           %.A.................
\newif\if!gridlinestoo          %..................T
\newif\if!keepPO                %...................
\newif\if!placeaxislabel        %.A.................
\newif\if!switch                %H..................
\newif\if!xswitch               %.A................T

\newtoks\!axisLaBeL             %.A.................
\newtoks\!keywordtoks           %.A.................

\newwrite\!replotfile           %.............O.....

\newhelp\!keywordhelp{The keyword mentioned in the error message in unknown. 
Replace NEW KEYWORD in the indicated response by the keyword that 
should have been specified.}    %.A.................

% The following commands assign alternate names to some of the 
% above registers.  "\!wlet"  is defined in  Hacks.
\!wlet\!!origin=\!xM                   %.A................T
\!wlet\!!unit=\!uplength               %.A................T
\!wlet\!Lresiduallength=\!dimenG       %.........U.........
\!wlet\!Rresiduallength=\!dimenF       %.........U.........
\!wlet\!axisLength=\!distacross        %.A................T
\!wlet\!axisend=\!ydiff                %.A................T
\!wlet\!axisstart=\!xdiff              %.A................T
\!wlet\!axisxlevel=\!arclength         %.A................T
\!wlet\!axisylevel=\!downlength        %.A................T
\!wlet\!beta=\!dimenE                  %...............Q...
\!wlet\!gamma=\!dimenF                 %...............Q...
\!wlet\!shadexorigin=\!plotxorigin     %.................S.
\!wlet\!shadeyorigin=\!plotyorigin     %.................S.
\!wlet\!ticklength=\!xS                %..................T
\!wlet\!ticklocation=\!xE              %..................T
\!wlet\!ticklocationincr=\!yE          %..................T
\!wlet\!tickwidth=\!yS                 %..................T
\!wlet\!totalleaderlength=\!dimenE     %.........U.........
\!wlet\!xone=\!xprime                  %....X..............
\!wlet\!xtwo=\!dxprime                 %....X..............
\!wlet\!ySsave=\!yM                    %...................
\!wlet\!ybB=\!yB                       %.................S.
\!wlet\!ybC=\!yC                       %.................S.
\!wlet\!ybE=\!yE                       %.................S.
\!wlet\!ybM=\!yM                       %.................S.
\!wlet\!ybS=\!yS                       %.................S.
\!wlet\!ybpos=\!yyloc                  %.................S.
\!wlet\!yone=\!yprime                  %....X..............
\!wlet\!ytB=\!xB                       %.................S.
\!wlet\!ytC=\!xC                       %.................S.
\!wlet\!ytE=\!downlength               %.................S.
\!wlet\!ytM=\!arclength                %.................S.
\!wlet\!ytS=\!distacross               %.................S.
\!wlet\!ytpos=\!xxloc                  %.................S.
\!wlet\!ytwo=\!dyprime                 %....X..............


% Initial values for registers
\!zpt=0pt                              % static
\!xunit=1pt
\!yunit=1pt
\!arearloc=\!xunit
\!areatloc=\!yunit
\!dshade=5pt
\!leaderlength=24in
\!tfs=256                              % static
\!wmax=5.3pt                           % static
\!wmin=2.7pt                           % static
\!xaxislength=\!xunit
\!xpivot=\!zpt
\!yaxislength=\!yunit 
\!ypivot=\!zpt
\plotsymbolspacing=.4pt
  \!dimenA=50pt \!fiftypt=\!dimenA     % static

\!rootten=3.162278pt                   % static
\!tenAa=8.690286pt                     % static  (A5)
\!tenAc=2.773839pt                     % static  (A3)
\!tenAe=2.543275pt                     % static  (A1)

% Initial values for control sequences
\def\!cosrotationangle{1}      %................R..
\def\!sinrotationangle{0}      %................R..
\def\!xpivotcoord{0}           %................R..
\def\!xref{0}                  %............P......
\def\!xshadesave{0}            %.................S.
\def\!ypivotcoord{0}           %................R..
\def\!yref{0}                  %............P......
\def\!yshadesave{0}            %.................S.
\def\!zero{0}                  %..................T

% Reset TeX to report allocations
\let\wlog=\!!!wlog
%  *************************************
%  ***  AREAS: Deals with plot areas ***
%  *************************************
%
%  ** User commands
%  **   \setplotarea x from LEFT XCOORD to RIGTH XCOORD, y from BOTTOM YCOORD
%  **      to TOP YCOORD
%  **   \axis BOTTOM-LEFT-TOP-RIGHT  [SHIFTEDTO xy=COORD] [VISIBLE-INVISIBLE]
%  **      [LABEL {label}] [TICKS] /
%  **   \visibleaxes
%  **   \invisibleaxes
%  **   \plotheading {HEADING}
%  **   \grid {# of columns} {# of rows}
%  **   \normalgraphs 
  
%  **  \normalgraphs
%  **    Sets defaults for graph setup. See Subsection 3.4 of manual.
\def\normalgraphs{%
  \longticklength=.4\baselineskip
  \shortticklength=.25\baselineskip
  \tickstovaluesleading=.25\baselineskip
  \valuestolabelleading=.8\baselineskip
  \linethickness=.4pt
  \stackleading=.17\baselineskip
  \headingtoplotskip=1.5\baselineskip
  \visibleaxes
  \ticksout
  \nogridlines
  \unloggedticks}
%
% **  \setplotarea x from LEFT XCOORD to RIGTH XCOORD, y from BOTTOM YCOORD
% **    to TOP YCOORD
% **  Reserves space in PICBOX for a rectangular box with the indicated
% **   coordinates.  Must be specified before calls to  \axis, 
% **   \grid, \plotheading.
% **  See Subsection 3.1 of the manual.
\def\setplotarea x from #1 to #2, y from #3 to #4 {%
  \!arealloc=\!M{#1}\!xunit \advance \!arealloc -\!xorigin
  \!areabloc=\!M{#3}\!yunit \advance \!areabloc -\!yorigin
  \!arearloc=\!M{#2}\!xunit \advance \!arearloc -\!xorigin
  \!areatloc=\!M{#4}\!yunit \advance \!areatloc -\!yorigin
  \!initinboundscheck
  \!xaxislength=\!arearloc  \advance\!xaxislength -\!arealloc
  \!yaxislength=\!areatloc  \advance\!yaxislength -\!areabloc
  \!plotheadingoffset=\!zpt
  \!dimenput {{\setbox0=\hbox{}\wd0=\!xaxislength\ht0=\!yaxislength\box0}}
     [bl] (\!arealloc,\!areabloc)}
%
% ** \visibleaxes, \invisibleaxes 
% ** Switches for setting visibility of subsequent axes.
% ** See Subsection 3.2 of the manual.
\def\visibleaxes{%
  \def\!axisvisibility{\!axisvisibletrue}}
\def\invisibleaxes{%
  \def\!axisvisibility{\!axisvisiblefalse}}
%
% ** The next few macros enable the user to fix up an erroneous keyword
% **   in the \axis command.
%  \newhelp is in ALLOCATIONS
%  \newhelp\!keywordhelp{The keyword mentioned in the error message in unknown. 
%  Replace NEW KEYWORD in the indicated response by the keyword that 
%  should have been specified.}

\def\!fixkeyword#1{%
  \errhelp=\!keywordhelp
  \errmessage{Unrecognized keyword `#1': \the\!keywordtoks{NEW KEYWORD}'}}

%  \newtoks\!keywordtoks    In ALLOCATIONS.
\!keywordtoks={enter `i\fixkeyword}

\def\fixkeyword#1{%
  \!nextkeyword#1 }

% ** \axis BOTTOM-LEFT-TOP-RIGHT  [SHIFTEDTO xy=COORD] [VISIBLE-INVISIBLE]
% **   [LABEL {label}] [TICKS] /
% ** Exactly one of the keywords BOTTOM, LEFT, TOP, RIGHT must be
% ** specified. Axis is drawn along the indicated edge of the current
% ** plot area, shifted if the SHIFTEDTO option is used, visible or
% ** invisible according the selected option, with an optional LABEL,
% ** and optional TICKS (see ticks.tex for the options avialabel with
% ** TICKS). The TICKS option must be the last one specified. The \axis
% ** MUST be terminated with a / followed by a space.
% ** See Subsection 3.2 of the manual for more information.

% ** The various options of the \axis command are processed by the
% ** \!nextkeyword macro defined below. For example, 
% ** `\!nextkeyword shiftedto ' expands to `\!axisshiftedto'.
\def\axis {%
  \def\!nextkeyword##1 {%
    \expandafter\ifx\csname !axis##1\endcsname \relax
      \def\!next{\!fixkeyword{##1}}%
    \else
      \def\!next{\csname !axis##1\endcsname}%
    \fi
    \!next}%
  \!offset=\!zpt
  \!axisvisibility
  \!placeaxislabelfalse
  \!nextkeyword}

% ** This and the various macros that follow handle the keyword
% ** specifications on the \axis command
% ** See Subsection 3.2 of the manual.
\def\!axisbottom{%
  \!axisylevel=\!areabloc
  \def\!tickxsign{0}%
  \def\!tickysign{-}%
  \def\!axissetup{\!axisxsetup}%
  \def\!axislabeltbrl{t}%
  \!nextkeyword}

\def\!axistop{%
  \!axisylevel=\!areatloc
  \def\!tickxsign{0}%
  \def\!tickysign{+}%
  \def\!axissetup{\!axisxsetup}%
  \def\!axislabeltbrl{b}%
  \!nextkeyword}

\def\!axisleft{%
  \!axisxlevel=\!arealloc
  \def\!tickxsign{-}%
  \def\!tickysign{0}%
  \def\!axissetup{\!axisysetup}%
  \def\!axislabeltbrl{r}%
  \!nextkeyword}

\def\!axisright{%
  \!axisxlevel=\!arearloc
  \def\!tickxsign{+}%
  \def\!tickysign{0}%
  \def\!axissetup{\!axisysetup}%
  \def\!axislabeltbrl{l}%
  \!nextkeyword}

\def\!axisshiftedto#1=#2 {%
  \if 0\!tickxsign
    \!axisylevel=\!M{#2}\!yunit
    \advance\!axisylevel -\!yorigin
  \else
    \!axisxlevel=\!M{#2}\!xunit
    \advance\!axisxlevel -\!xorigin
  \fi
  \!nextkeyword}

\def\!axisvisible{%
  \!axisvisibletrue  
  \!nextkeyword}

\def\!axisinvisible{%
  \!axisvisiblefalse
  \!nextkeyword}

\def\!axislabel#1 {%
  \!axisLaBeL={#1}%
  \!placeaxislabeltrue
  \!nextkeyword}

\expandafter\def\csname !axis/\endcsname{%
  \!axissetup % This could done already by "ticks"; if so, now \relax
  \if!placeaxislabel
    \!placeaxislabel
  \fi
  \if +\!tickysign %                 ** (A "top" axis)
    \!dimenA=\!axisylevel
    \advance\!dimenA \!offset %      ** dimA = top of the axis structure
    \advance\!dimenA -\!areatloc %   ** dimA = excess over the plot area
    \ifdim \!dimenA>\!plotheadingoffset
      \!plotheadingoffset=\!dimenA % ** Greatest excess over the plot area
    \fi
  \fi}

% ** \grid {c} {r} 
% ** Partitions the plot area into c columns and r rows; see Subsection 3.3
% ** of the manual.
% ** (Other grid patterns can be drawn with the TICKS option of the \axis 
% ** command.
\def\grid #1 #2 {%
  \!countA=#1\advance\!countA 1
  \axis bottom invisible ticks length <\!zpt> andacross quantity {\!countA} /
  \!countA=#2\advance\!countA 1
  \axis left   invisible ticks length <\!zpt> andacross quantity {\!countA} / }

% ** \plotheading{HEADING}
% ** Places HEADING centered above the top of the plotarea (and above
% ** any top axis ticks marks, tick labels, and axis label); see
% ** Subsection 3.3 of the manual.
\def\plotheading#1 {%
  \advance\!plotheadingoffset \headingtoplotskip
  \!dimenput {#1} [B] <.5\!xaxislength,\!plotheadingoffset>
    (\!arealloc,\!areatloc)}

% ** From here on, the routines are internal.
\def\!axisxsetup{%
  \!axisxlevel=\!arealloc
  \!axisstart=\!arealloc
  \!axisend=\!arearloc
  \!axisLength=\!xaxislength
  \!!origin=\!xorigin
  \!!unit=\!xunit
  \!xswitchtrue
  \if!axisvisible 
    \!makeaxis
  \fi}

\def\!axisysetup{%
  \!axisylevel=\!areabloc
  \!axisstart=\!areabloc
  \!axisend=\!areatloc
  \!axisLength=\!yaxislength
  \!!origin=\!yorigin
  \!!unit=\!yunit
  \!xswitchfalse
  \if!axisvisible
    \!makeaxis
  \fi}

\def\!makeaxis{%
  \setbox\!boxA=\hbox{% (Make a pseudo-y[x] tick for an x[y]-axis)
    \beginpicture
      \!setdimenmode
      \setcoordinatesystem point at {\!zpt} {\!zpt}   
      \putrule from {\!zpt} {\!zpt} to
        {\!tickysign\!tickysign\!axisLength} 
        {\!tickxsign\!tickxsign\!axisLength}
    \endpicturesave <\!Xsave,\!Ysave>}%
    \wd\!boxA=\!zpt
    \!placetick\!axisstart}

\def\!placeaxislabel{%
  \advance\!offset \valuestolabelleading
  \if!xswitch
    \!dimenput {\the\!axisLaBeL} [\!axislabeltbrl]
      <.5\!axisLength,\!tickysign\!offset> (\!axisxlevel,\!axisylevel)
    \advance\!offset \!dp  % ** advance offset by the "tallness"
    \advance\!offset \!ht  % ** of the label
  \else
    \!dimenput {\the\!axisLaBeL} [\!axislabeltbrl]
      <\!tickxsign\!offset,.5\!axisLength> (\!axisxlevel,\!axisylevel)
  \fi
  \!axisLaBeL={}}


% *******************************
% *** ARROWS  (Draws arrows)  ***
% *******************************
%
% ** User commands
% **  \arrow <ARROW HEAD LENGTH> [MID FRACTION, BASE FRACTION]
% **    [<XSHIFT,YSHIFT>] from XFROM YFROM to XTO YTO
% **  \betweenarrows {TEXT} [orientation & shift] from XFROM YFROM to XTO YTO

% ** \arrow <ARROW HEAD LENGTH> [MID FRACTION, BASE FRACTION]
% **    [<XSHIFT,YSHIFT>] from XFROM YFROM to XTO YTO
% ** Draws an arrow from (XFROM,YFROM) to (XTO,YTO).  The arrow head
% ** is constructed two quadratic arcs, which extend back a distance
% ** ARROW HEAD LENGTH (a dimension) on both sides of the arrow shaft.
% ** All the way back the arcs are a distance BASE FRACTION*ARROW HEAD
% ** LENGTH apart, while half-way back they are a distance MID FRACTION*
% ** ARROW HEAD LENGTH apart. <XSHIFT,YSHIFT> is optional, and has
% ** its usual interpreation. See Subsection 5.4 of the manual.

\def\arrow <#1> [#2,#3]{%
  \!ifnextchar<{\!arrow{#1}{#2}{#3}}{\!arrow{#1}{#2}{#3}<\!zpt,\!zpt> }}

\def\!arrow#1#2#3<#4,#5> from #6 #7 to #8 #9 {%
%
% ** convert to dimensions
  \!xloc=\!M{#8}\!xunit   
  \!yloc=\!M{#9}\!yunit
  \!dxpos=\!xloc  \!dimenA=\!M{#6}\!xunit  \advance \!dxpos -\!dimenA
  \!dypos=\!yloc  \!dimenA=\!M{#7}\!yunit  \advance \!dypos -\!dimenA
  \let\!MAH=\!M%                         ** save current c/d mode
  \!setdimenmode%                        ** go into dimension mode
%
  \!xshift=#4\relax  \!yshift=#5\relax%  ** pick up shift
  \!reverserotateonly\!xshift\!yshift%   ** back rotate shift
  \advance\!xshift\!xloc  \advance\!yshift\!yloc
%
% **  draw shaft of arrow
  \!xS=-\!dxpos  \advance\!xS\!xshift
  \!yS=-\!dypos  \advance\!yS\!yshift
  \!start (\!xS,\!yS)
  \!ljoin (\!xshift,\!yshift)
%
% ** find 32*cosine and 32*sine of angle of rotation
  \!Pythag\!dxpos\!dypos\!arclength
  \!divide\!dxpos\!arclength\!dxpos  
  \!dxpos=32\!dxpos  \!removept\!dxpos\!!cos
  \!divide\!dypos\!arclength\!dypos  
  \!dypos=32\!dypos  \!removept\!dypos\!!sin
% 
% ** construct arrowhead
  \!halfhead{#1}{#2}{#3}%                ** draw half of arrow head
  \!halfhead{#1}{-#2}{-#3}%              ** draw other half
%
  \let\!M=\!MAH%                         ** restore old c/d mode
  \ignorespaces}
%
% ** draw half of arrow head
  \def\!halfhead#1#2#3{%
    \!dimenC=-#1%                
    \divide \!dimenC 2 %                 ** half way back
    \!dimenD=#2\!dimenC%                 ** half the mid width
    \!rotate(\!dimenC,\!dimenD)by(\!!cos,\!!sin)to(\!xM,\!yM)
    \!dimenC=-#1%                        ** all the way back
    \!dimenD=#3\!dimenC
    \!dimenD=.5\!dimenD%                 ** half the full width
    \!rotate(\!dimenC,\!dimenD)by(\!!cos,\!!sin)to(\!xE,\!yE)
    \!start (\!xshift,\!yshift)
    \advance\!xM\!xshift  \advance\!yM\!yshift
    \advance\!xE\!xshift  \advance\!yE\!yshift
    \!qjoin (\!xM,\!yM) (\!xE,\!yE) 
    \ignorespaces}


% ** \betweenarrows {TEXT} [orientation & shift] from XFROM YFROM to XTO YTO
% **   Makes things like <--- text --->, using arrow heads from TeX's fonts.
% **   See Subsection 5.4 of the manual.
\def\betweenarrows #1#2 from #3 #4 to #5 #6 {%
  \!xloc=\!M{#3}\!xunit  \!xxloc=\!M{#5}\!xunit%   
  \!yloc=\!M{#4}\!yunit  \!yyloc=\!M{#6}\!yunit%           
  \!dxpos=\!xxloc  \advance\!dxpos by -\!xloc
  \!dypos=\!yyloc  \advance\!dypos by -\!yloc
  \advance\!xloc .5\!dxpos
  \advance\!yloc .5\!dypos
%
  \let\!MBA=\!M%           ** save current coord\dimen mode
  \!setdimenmode%          ** express locations in dimens
  \ifdim\!dypos=\!zpt
    \ifdim\!dxpos<\!zpt \!dxpos=-\!dxpos \fi
    \put {\!lrarrows{\!dxpos}{#1}}#2{} at {\!xloc} {\!yloc}
  \else
    \ifdim\!dxpos=\!zpt
      \ifdim\!dypos<\!zpt \!dypos=-\!zpt \fi
      \put {\!udarrows{\!dypos}{#1}}#2{} at {\!xloc} {\!yloc}
    \fi
  \fi
  \let\!M=\!MBA%           ** restore previous c/d mode
  \ignorespaces}

% ** Subroutine for left-right between arrows 
\def\!lrarrows#1#2{% #1=width, #2=text
  {\setbox\!boxA=\hbox{$\mkern-2mu\mathord-\mkern-2mu$}%
   \setbox\!boxB=\hbox{$\leftarrow$}\!dimenE=\ht\!boxB
   \setbox\!boxB=\hbox{}\ht\!boxB=2\!dimenE
   \hbox to #1{$\mathord\leftarrow\mkern-6mu
     \cleaders\copy\!boxA\hfil
     \mkern-6mu\mathord-$%
     \kern.4em $\vcenter{\box\!boxB}$$\vcenter{\hbox{#2}}$\kern.4em
     $\mathord-\mkern-6mu
     \cleaders\copy\!boxA\hfil
     \mkern-6mu\mathord\rightarrow$}}}

% ** Subroutine for up-down between arrows 
\def\!udarrows#1#2{% #1=width, #2=text
  {\setbox\!boxB=\hbox{#2}%
   \setbox\!boxA=\hbox to \wd\!boxB{\hss$\vert$\hss}%
   \!dimenE=\ht\!boxA \advance\!dimenE \dp\!boxA \divide\!dimenE 2
   \vbox to #1{\offinterlineskip
      \vskip .05556\!dimenE
      \hbox to \wd\!boxB{\hss$\mkern.4mu\uparrow$\hss}\vskip-\!dimenE
      \cleaders\copy\!boxA\vfil
      \vskip-\!dimenE\copy\!boxA
      \vskip\!dimenE\copy\!boxB\vskip.4em
      \copy\!boxA\vskip-\!dimenE
      \cleaders\copy\!boxA\vfil
      \vskip-\!dimenE \hbox to \wd\!boxB{\hss$\mkern.4mu\downarrow$\hss}
      \vskip .05556\!dimenE}}}


% ***************************
% *** BARS  (Draws bars)  ***
% ***************************
%
% ** User commands:
% ** \putbar [<XSHIFT,YSHIFT>] breadth <BREADTH> from XSTART YSTART
% **   to XEND YEND
% ** \setbars [<XSHIFT,YSHIFT>] breadth <BREADTH> baseline at XY = COORD
% **   [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y] <B_XSHIFT,B_YSHIFT>)]
% **   [endlabels  ([E_ORIENTATION_x,E_ORIENTATION_y] <E_XSHIFT,E_YSHIFT>)]


% ** \putbar [<XSHIFT,YSHIFT>] breadth <BREADTH> from XSTART YSTART
% **   to XEND YEND
% ** Either XSTART=XEND or YSTART=YEND. Draws a rectangle between
% **   (XSTART,YSTART) & (XEND,YEND). The "depth" of the rectangle
% **   is determined by those two plot positions; its other
% **   dimension "breadth" is specified by the dimension BREADTH.
% ** See Subsection 4.2 of the manual.
\def\putbar#1breadth <#2> from #3 #4 to #5 #6 {%
  \!xloc=\!M{#3}\!xunit  \!xxloc=\!M{#5}\!xunit%   
  \!yloc=\!M{#4}\!yunit  \!yyloc=\!M{#6}\!yunit%           
  \!dypos=\!yyloc  \advance\!dypos by -\!yloc
  \!dimenI=#2  
% 
  \ifdim \!dimenI=\!zpt %            ** If 0 breadth
    \putrule#1from {#3} {#4} to {#5} {#6} % ** Then draw line
  \else %                            ** Else, put in a rectangle
    \let\!MBar=\!M%                  ** save current c/d mode
    \!setdimenmode %                 ** go into dimension mode
    \divide\!dimenI 2
    \ifdim \!dypos=\!zpt             
      \advance \!yloc -\!dimenI %    ** Equal y coordinates
      \advance \!yyloc \!dimenI
    \else
      \advance \!xloc -\!dimenI %    ** Equal x coordinates
      \advance \!xxloc \!dimenI
    \fi
    \putrectangle#1corners at {\!xloc} {\!yloc} and {\!xxloc} {\!yyloc}
    \let\!M=\!MBar %                 ** restore c/d mode
  \fi
  \ignorespaces}


% ** \setbars [<XSHIFT,YSHIFT>] breadth <BREADTH> baseline at XY = COORD
% **   [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y] <B_XSHIFT,B_YSHIFT>)]
% **   [endlabels  ([E_ORIENTATION_x,E_ORIENTATION_y] <E_XSHIFT,E_YSHIFT>)]
% ** This command puts PiCTeX into the bar graph drawing mode described
% **   in Subsection 4.4 of the manual.
\def\setbars#1breadth <#2> baseline at #3 = #4 {%
  \edef\!barshift{#1}%
  \edef\!barbreadth{#2}%
  \edef\!barorientation{#3}%
  \edef\!barbaseline{#4}%
  \def\!bardobaselabel{\!bardoendlabel}%
  \def\!bardoendlabel{\!barfinish}%
  \let\!drawcurve=\!barcurve
  \!setbars}
\def\!setbars{%
  \futurelet\!nextchar\!!setbars}
\def\!!setbars{%
  \if b\!nextchar
    \def\!!!setbars{\!setbarsbget}%
  \else 
    \if e\!nextchar
      \def\!!!setbars{\!setbarseget}%
    \else
      \def\!!!setbars{\relax}%
    \fi
  \fi
  \!!!setbars}
\def\!setbarsbget baselabels (#1) {%
  \def\!barbaselabelorientation{#1}%
  \def\!bardobaselabel{\!!bardobaselabel}%
  \!setbars}
\def\!setbarseget endlabels (#1) {%
  \edef\!barendlabelorientation{#1}%
  \def\!bardoendlabel{\!!bardoendlabel}%
  \!setbars}

% ** \!barcurve
% ** Draws a bargraph with preset values of barshift, barbreadth,
% ** barorientation (x or y) and barbaseline (coordinate)
\def\!barcurve #1 #2 {%
  \if y\!barorientation
    \def\!basexarg{#1}%
    \def\!baseyarg{\!barbaseline}%
  \else
    \def\!basexarg{\!barbaseline}%
    \def\!baseyarg{#2}%
  \fi
  \expandafter\putbar\!barshift breadth <\!barbreadth> from {\!basexarg}
    {\!baseyarg} to {#1} {#2}
  \def\!endxarg{#1}%
  \def\!endyarg{#2}%
  \!bardobaselabel}

\def\!!bardobaselabel "#1" {%
  \put {#1}\!barbaselabelorientation{} at {\!basexarg} {\!baseyarg}
  \!bardoendlabel}
 
\def\!!bardoendlabel "#1" {%
  \put {#1}\!barendlabelorientation{} at {\!endxarg} {\!endyarg}
  \!barfinish}

\def\!barfinish{%
  \!ifnextchar/{\!finish}{\!barcurve}}
 

% ********************************
% *** BOXES (Draws rectangles) ***
% ********************************
%
% ** User commands:
% **   \putrectangle [<XSHIFT,YSHIFT>] corners at  XCOORD1 YCOORD1
% **     and  XCOORD2 YCOORD2 
% **   \shaderectangleson
% **   \shaderectanglesoff
% **   \frame [<SEPARATION>] {TEXT}
% **   \rectangle <WIDTH> <HEIGHT>
%
%
% **  \putrectangle [<XSHIFT,YSHIFT>] corners at XCOORD1 YCOORD1 
% **    and  XCOORD2 YCOORD2 
% **  Draws a rectangle with corners at (X1,Y1), (X2,Y1), (X1,Y2), (X2,Y2)
% **  Lines have thickness \linethickness, and overlap at the corners.
% **  The optional field  <XSHIFT,YSHIFT>  functions as with a \put command.
% **  See Subsection 4.2 of the manual.
\def\putrectangle{%
  \!ifnextchar<{\!putrectangle}{\!putrectangle<\!zpt,\!zpt> }}
\def\!putrectangle<#1,#2> corners at #3 #4 and #5 #6 {%
%
% ** get locations
  \!xone=\!M{#3}\!xunit  \!xtwo=\!M{#5}\!xunit%   
  \!yone=\!M{#4}\!yunit  \!ytwo=\!M{#6}\!yunit%           
  \ifdim \!xtwo<\!xone
    \!dimenI=\!xone  \!xone=\!xtwo  \!xtwo=\!dimenI
  \fi
  \ifdim \!ytwo<\!yone
    \!dimenI=\!yone  \!yone=\!ytwo  \!ytwo=\!dimenI
  \fi
  \!dimenI=#1\relax  \advance\!xone\!dimenI  \advance\!xtwo\!dimenI
  \!dimenI=#2\relax  \advance\!yone\!dimenI  \advance\!ytwo\!dimenI
  \let\!MRect=\!M%                  ** save current coord/dimen mode
  \!setdimenmode
%
% ** shade rectangle if appropriate
  \!shaderectangle
%
% ** draw horizontal edges
  \!dimenI=.5\linethickness
  \advance \!xone  -\!dimenI%       ** adjust x-location to overlap corners
  \advance \!xtwo   \!dimenI%       ** ditto
  \putrule from {\!xone} {\!yone} to {\!xtwo} {\!yone} 
  \putrule from {\!xone} {\!ytwo} to {\!xtwo} {\!ytwo} 
%
% ** draw vertical edges
  \advance \!xone   \!dimenI%       ** restore original x-values
  \advance \!xtwo  -\!dimenI% 
  \advance \!yone  -\!dimenI%       ** adjust y-location to overlap corners
  \advance \!ytwo   \!dimenI%       ** ditto
  \putrule from {\!xone} {\!yone} to {\!xone} {\!ytwo} 
  \putrule from {\!xtwo} {\!yone} to {\!xtwo} {\!ytwo} 
%
  \let\!M=\!MRect%                  ** restore coord/dimen mode
  \ignorespaces}
 
% ** \shaderectangleson 
% **   Subsequent rectangles will be shaded according to 
% **   the current shading pattern.  Affects \putrectangle, \putbar,
% **   \frame, \sethistograms, and \setbars. See Subsection 7.5 of the manual.
\def\shaderectangleson{%     
  \def\!shaderectangle{\!!shaderectangle}%
  \ignorespaces}
% ** \shaderectanglesoff 
% **    Suppresses  \shaderectangleson.  The default.
\def\shaderectanglesoff{%
  \def\!shaderectangle{}%
  \ignorespaces}

\shaderectanglesoff
 
% ** The following internal routine shades the current rectangle, when
% **   \!shaderectangle = \!!shaderectangle . 
\def\!!shaderectangle{%
  \!dimenA=\!xtwo  \advance \!dimenA -\!xone
  \!dimenB=\!ytwo  \advance \!dimenB -\!yone
  \ifdim \!dimenA<\!dimenB
    \!startvshade (\!xone,\!yone,\!ytwo)
    \!lshade      (\!xtwo,\!yone,\!ytwo)
  \else
    \!starthshade (\!yone,\!xone,\!xtwo)
    \!lshade      (\!ytwo,\!xone,\!xtwo)
  \fi
  \ignorespaces}
  
% ** \frame [<SEPARATION>] {TEXT}
% ** Draws a frame of thickness linethickness about the box enclosing
% **   TEXT; the frame is separated from the box by a distance of
% **   SEPARATION.  The result is an hbox with the same baseline as TEXT.
% **   If <SEPARATION> is omitted, you get the effect of <0pt>.
% ** See Subsection 4.2 of the manual.
\def\frame{%
  \!ifnextchar<{\!frame}{\!frame<\!zpt> }}
\long\def\!frame<#1> #2{%
  \beginpicture
    \setcoordinatesystem units <1pt,1pt> point at 0 0 
    \put {#2} [Bl] at 0 0 
    \!dimenA=#1\relax
    \!dimenB=\!wd \advance \!dimenB \!dimenA
    \!dimenC=\!ht \advance \!dimenC \!dimenA
    \!dimenD=\!dp \advance \!dimenD \!dimenA
    \let\!MFr=\!M
    \!setdimenmode
    \putrectangle corners at {-\!dimenA} {-\!dimenD} and {\!dimenB} {\!dimenC}
    \!setcoordmode
    \let\!M=\!MFr
  \endpicture
  \ignorespaces}
 
% ** \rectangle <WIDTH> <HEIGHT>
% ** Constructs a rectangle of width WIDTH and heigth HEIGHT. 
% ** See Subsection 4.2 of the manual.
\def\rectangle <#1> <#2> {%
  \setbox0=\hbox{}\wd0=#1\ht0=#2\frame {\box0}}


% *********************************************
% ***  CURVES  (Upper level \plot commands) ***
% *********************************************
%
% ** User commands
% **   \plot  DATA  /
% **   \plot  "FILE NAME"
% **   \setquadratic
% **   \setlinear
% **   \sethistograms
% **   \vshade  ...
% **   \hshade  ...

% \plot: multi-purpose command. Draws histograms, bar graphs, piecewise-linear
% or piecewise quadratic curves, depending on the setting of \!drawcurve.
% See Subsections 4.3-4.5, 5.1, 5.2 of the manual.
\def\plot{%
  \!ifnextchar"{\!plotfromfile}{\!drawcurve}}
\def\!plotfromfile"#1"{%
  \expandafter\!drawcurve \input #1 /}

% Command to set piecewise quadratic mode
% See Subsections 5.1, 7.3, and 7.4 of the manual.
\def\setquadratic{%
  \let\!drawcurve=\!qcurve
  \let\!!Shade=\!!qShade
  \let\!!!Shade=\!!!qShade}

% Command to set piecewise linear mode
% See Subsections 5.1, 7.3, and 7.4 of the manual.
\def\setlinear{%
  \let\!drawcurve=\!lcurve
  \let\!!Shade=\!!lShade
  \let\!!!Shade=\!!!lShade}

% Command to set histogram mode
% See Subsection 4.3 of the manual.
\def\sethistograms{%
  \let\!drawcurve=\!hcurve}

% Commands to cycle through list of coordinates in piecewise quadratic 
% interpolation mode
\def\!qcurve #1 #2 {%
  \!start (#1,#2)
  \!Qjoin}
\def\!Qjoin#1 #2 #3 #4 {%
  \!qjoin (#1,#2) (#3,#4)             % \!qjoin  is defined in QUADRATIC
  \!ifnextchar/{\!finish}{\!Qjoin}}

% Commands to cycle through list of coordinates in piecewise linear 
% interpolation mode
\def\!lcurve #1 #2 {%
  \!start (#1,#2)
  \!Ljoin}
\def\!Ljoin#1 #2 {%
  \!ljoin (#1,#2)                    % \!ljoin  is defined in LINEAR
  \!ifnextchar/{\!finish}{\!Ljoin}}

\def\!finish/{\ignorespaces}

% Command to cycle through list of coordinates in histogram mode
\def\!hcurve #1 #2 {%
  \edef\!hxS{#1}%
  \edef\!hyS{#2}%
  \!hjoin}
\def\!hjoin#1 #2 {%
  \putrectangle corners at {\!hxS} {\!hyS} and {#1} {#2}
  \edef\!hxS{#1}%
  \!ifnextchar/{\!finish}{\!hjoin}}


% \vshade: See Subsection 7.3 of the manual.
\def\vshade #1 #2 #3 {%
  \!startvshade (#1,#2,#3)
  \!Shadewhat}

% \hshade: See Subsection 7.4 of the manual.
\def\hshade #1 #2 #3 {%
  \!starthshade (#1,#2,#3)
  \!Shadewhat}

% Commands to cycle through coordinates and optional "edge effect"
% fields while shading.
\def\!Shadewhat{%
  \futurelet\!nextchar\!Shade}
\def\!Shade{%
  \if <\!nextchar
    \def\!nextShade{\!!Shade}%
  \else
    \if /\!nextchar
      \def\!nextShade{\!finish}%
    \else
      \def\!nextShade{\!!!Shade}%
    \fi
  \fi
  \!nextShade}
\def\!!lShade<#1> #2 #3 #4 {%
  \!lshade <#1> (#2,#3,#4)                 % \!lshade is defined in SHADING
  \!Shadewhat}
\def\!!!lShade#1 #2 #3 {%
  \!lshade (#1,#2,#3)
  \!Shadewhat} 
\def\!!qShade<#1> #2 #3 #4 #5 #6 #7 {%
  \!qshade <#1> (#2,#3,#4) (#5,#6,#7)      % \!qshade is defined in SHADING
  \!Shadewhat}
\def\!!!qShade#1 #2 #3 #4 #5 #6 {%
  \!qshade (#1,#2,#3) (#4,#5,#6)
  \!Shadewhat} 

% ** Set default interpolation mode
\setlinear


%  ********************************************
%  *** DASHPATTERNS (Sets up dash patterns) ***
%  ********************************************

%  **  User commands:
%  **    \setdashpattern <DIMEN1,DIMEN2,DIMEN3,...>
%  **    \setdots <INTRADOT_DISTANCE>
%  **    \setdotsnear <INTRADOT_DISTANCE> for <ARC LENGTH>
%  **    \setdashes <DASH/SKIP_DISTANCE>
%  **    \setdashesnear <DASH/SKIP_DISTANCE> for <ARC LENGTH>
%  **    \setsolid
%  **    \findlength {CURVE CMDS}
 
%  **  Internal commands:
%  **    \!dashingon
%  **    \!dashingoff
 
%  **  Dash patterns are specified by a balanced token list whose complete
%  **    expansion has the form: DIMEN1,DIMEN2,DIMEN3,DIMEN4,... ; this produces
%  **    an arc of length DIMEN1, a skip of length DIMEN2, an arc of length
%  **    DIMEN3, a skip of length DIMEN4, ... .  Any number of DIMEN values may
%  **    be given. The pattern is repeated as many times (perhaps fractional)
%  **    as necessary to draw the curve. 
%  **  A dash pattern remains in effect until it is overridden by a call to
%  **    \setdashpattern, or to \setdots, \setdotsnear ... , \setdashes, 
%  **    \setdashesnear ... , or \setsolid.
%  **  Solid lines are the default.
 
 
%  **  \def\setdashpattern <DIMEN1,DIMEN2,DIMEN3,...>
%  **  The following routine converts a balanced list of tokens whose
%  **  complete expansion has the form  DIMEN1,DIMEN2, ... , DIMENk  into 
%  **  three list macros that are used in drawing dashed rules and curves:
%  **    !Flist:   \!Rule{DIMEN1}\!Skip{DIMEN2}\!Rule{DIMEN3}\!Skip{DIMEN4} ...
%  **    !Blist:   ...\!Skip{DIMEN4}\!Rule{DIMEN3}\!Skip{DIMEN2}\!Rule{DIMEN1}
%  **    !UDlist:  \\{DIMEN1}\\{DIMEN2}\\{DIMEN3}\\{DIMEN4} ...;
%  **  calculates \!leaderlength := DIMEN1 + ... + DIMENk; and
%  **  sets the curve drawing routines to dash mode.
%  **  Those lists are used by the curve drawing routines.
%  **  Dimenj ... may be given as an explicit dimension (e.g., 5pt), or
%  **  as an expression involving a dimension register (e.g., -2.5\dimen0).
%  **  See Subsection 6.2 of the manual
\def\setdashpattern <#1>{%
  \def\!Flist{}\def\!Blist{}\def\!UDlist{}%
  \!countA=0
  \!ecfor\!item:=#1\do{%
    \!dimenA=\!item\relax
    \expandafter\!rightappend\the\!dimenA\withCS{\\}\to\!UDlist%
    \advance\!countA  1
    \ifodd\!countA
      \expandafter\!rightappend\the\!dimenA\withCS{\!Rule}\to\!Flist%
      \expandafter\!leftappend\the\!dimenA\withCS{\!Rule}\to\!Blist%
    \else 
      \expandafter\!rightappend\the\!dimenA\withCS{\!Skip}\to\!Flist%
      \expandafter\!leftappend\the\!dimenA\withCS{\!Skip}\to\!Blist%
    \fi}%
  \!leaderlength=\!zpt
  \def\!Rule##1{\advance\!leaderlength  ##1}%
  \def\!Skip##1{\advance\!leaderlength  ##1}%
  \!Flist%
  \ifdim\!leaderlength>\!zpt 
  \else
    \def\!Flist{\!Skip{24in}}\def\!Blist{\!Skip{24in}}\ignorespaces
    \def\!UDlist{\\{\!zpt}\\{24in}}\ignorespaces
    \!leaderlength=24in
  \fi
  \!dashingon}   
 
 
%  **  \!dashingon  -- puts the curve drawing routines into dash mode
%  **  \!dashingoff -- puts the curve drawing routines into solid mode
%  **  These are internal commands, invoked by \setdashpattern and \setsolid
\def\!dashingon{%
  \def\!advancedashing{\!!advancedashing}%
  \def\!drawlinearsegment{\!lineardashed}%
  \def\!puthline{\!putdashedhline}%
  \def\!putvline{\!putdashedvline}%
%  \def\!putsline{\!putdashedsline}%
  \ignorespaces}% 
\def\!dashingoff{%
  \def\!advancedashing{\relax}%
  \def\!drawlinearsegment{\!linearsolid}%
  \def\!puthline{\!putsolidhline}%
  \def\!putvline{\!putsolidvline}%
%  \def\!putsline{\!putsolidsline}%
  \ignorespaces}
 
 
%  **  \setdots <LENGTH>  --  sets up a dot/skip pattern where dot (actually
%  **    the current plotsymbol) is plunked down once for every LENGTH 
%  **    traveled along the curve.  LENGTH defaults to 5pt.
%  **    See Subsection 6.1 of the manual.
\def\setdots{%
  \!ifnextchar<{\!setdots}{\!setdots<5pt>}}
\def\!setdots<#1>{%
  \!dimenB=#1\advance\!dimenB -\plotsymbolspacing
  \ifdim\!dimenB<\!zpt
    \!dimenB=\!zpt
  \fi
\setdashpattern <\plotsymbolspacing,\!dimenB>}
 
% ** \setdotsnear <LENGTH> for <ARC LENGTH>
% ** sets up a dot pattern where the dots are approximately LENGTH apart,
% ** the total length of the pattern is ARC LENGTH, and the pattern
% ** begins and ends with a dot. See Subsection 6.3 of the manual.
\def\setdotsnear <#1> for <#2>{%
  \!dimenB=#2\relax  \advance\!dimenB -.05pt  
  \!dimenC=#1\relax  \!countA=\!dimenC 
  \!dimenD=\!dimenB  \advance\!dimenD .5\!dimenC  \!countB=\!dimenD
  \divide \!countB  \!countA
  \ifnum 1>\!countB 
    \!countB=1
  \fi
  \divide\!dimenB  \!countB
  \setdots <\!dimenB>}
 
%  **  \setdashes <LENGTH>  --  sets up a dash/skip pattern where the dash
%  **    and the skip are each of length LENGTH (the dash is formed by
%  **    plunking down the current plotsymbol over an arc of length LENGTH
%  **    and so may actually be longer than LENGTH.  LENGTH defaults to 5pt.
%  **    See Subsection 6.1 of the manual.
\def\setdashes{%
  \!ifnextchar<{\!setdashes}{\!setdashes<5pt>}}
\def\!setdashes<#1>{\setdashpattern <#1,#1>}
 
% ** \setdashesnear ...
% ** Like \setdotsnear; the pattern begins and ends with a dash.
% ** See Subsection 6.3 of the manual.
\def\setdashesnear <#1> for <#2>{%
  \!dimenB=#2\relax  
  \!dimenC=#1\relax  \!countA=\!dimenC 
  \!dimenD=\!dimenB  \advance\!dimenD .5\!dimenC  \!countB=\!dimenD
  \divide \!countB  \!countA
  \ifodd \!countB 
  \else 
    \advance \!countB  1
  \fi
  \divide\!dimenB  \!countB
  \setdashes <\!dimenB>}
 
%  **  \setsolid  --  puts the curve drawing routines in "solid line" mode,
%  **    the default mode.  See Subsection 6.1 of the manual.
\def\setsolid{%
  \def\!Flist{\!Rule{24in}}\def\!Blist{\!Rule{24in}}%  
  \def\!UDlist{\\{24in}\\{\!zpt}}%
  \!dashingoff}  
\setsolid

%  **  \findlength {CURVE CMDS}
%  **  PiCTeX executes the \start, \ljoin, and \qjoin cmds comprising
%  **  CURVE CMDS without plotting anything, but stashes the length
%  **  of the phantom curve away in \totalarclength.
%  **  See Subsection 6.3 of the manual.
\def\findlength#1{%
  \begingroup
    \setdashpattern <0pt, \maxdimen>
    \setplotsymbol ({})  
    \dontsavelinesandcurves
    #1%
  \endgroup
  \ignorespaces}



% *************************************************************
% *** DIVISION  (Does long division of dimension registers) ***
% *************************************************************
 
% ** User command:
% **   \Divide {DIVIDEND} by {DIVISOR} forming {RESULT}
  
% ** Internal command
% **   \!divide{DIVIDEND}{DIVISOR}{RESULT}
 
% **  \!divide DIVIDEND [by] DIVISOR [to get] ANSWER
% **  Divides the dimension DIVIDEND by the dimension DIVISOR, placing the 
% **  quotient in the dimension register ANSWER.  Values are understood to 
% **  be in points.  E.g.  12.5pt/1.4pt=8.92857pt.
% **  Quotient is accurate to 1/65536pt=2**[-16]pt
% **  |DIVISOR| should be < 2048pt (about 28 inches).
\def\!divide#1#2#3{%
  \!dimenB=#1%                      **  dimB  holds current remainder (r)
  \!dimenC=#2%                      **  dimC  holds divisor (d)
  \!dimenD=\!dimenB%                **  dimD  holds quotient q=r/d for this 
  \divide \!dimenD \!dimenC%        **    step, in units of scaled pts
  \!dimenA=\!dimenD%                **  dimA  eventually holds answer (a)
  \multiply\!dimenD \!dimenC%       **  r <-- r - dq
  \advance\!dimenB -\!dimenD%       **  First step complete. Have integer part
%                                   **  of a, and corresponding remainder.
  \!dimenD=\!dimenC%                **  Temporarily use dimD to hold |d|
    \ifdim\!dimenD<\!zpt \!dimenD=-\!dimenD 
  \fi
  \ifdim\!dimenD<64pt%              **  Branch on the magnitude of |d|
    \!divstep[\!tfs]\!divstep[\!tfs]%
  \else 
    \!!divide
  \fi
  #3=\!dimenA\ignorespaces}

% **  The following code handles divisors  d  with 
% **    (1)  .88in =  64pt <= d <  256pt =  3.54in
% **    (2) 3.54in = 256pt <= d < 2048pt = 28.34in
% **  Anything bigger than that may result in an overflow condition.
% **  For our purposes, we should never even see case (2).
\def\!!divide{%
  \ifdim\!dimenD<256pt
    \!divstep[64]\!divstep[32]\!divstep[32]%
  \else 
    \!divstep[8]\!divstep[8]\!divstep[8]\!divstep[8]\!divstep[8]%
    \!dimenA=2\!dimenA
  \fi}
 
 
% **  The following macro does the real long division work.
\def\!divstep[#1]{%                 **  #1 = "B"
  \!dimenB=#1\!dimenB%              **  r <-- B*r
  \!dimenD=\!dimenB%                **  dimD  holds quotient q=r/d for this 
    \divide \!dimenD by \!dimenC%   **    step, in units of scaled pts
  \!dimenA=#1\!dimenA%              **  a <-- B*a + q
    \advance\!dimenA by \!dimenD%
  \multiply\!dimenD by \!dimenC%    **  r <-- r - dq
    \advance\!dimenB by -\!dimenD}
 
% **  \Divide:  See Subsection 9.3 of the manual.
\def\Divide <#1> by <#2> forming <#3> {%
  \!divide{#1}{#2}{#3}}


% *********************************************
% *** ELLIPSES (Draws ellipses and circles) ***
% *********************************************
 
% ** User commands
% **   \ellipticalarc  axes ratio A:B  DEGREES degrees from XSTART YSTART 
% **      center at XCENTER YCENTER 
% **   \circulararc DEGREES degrees from XSTART YSTART 
% **      center at XCENTER YCENTER 
 
% ** Internal command
% **   \!sinandcos{32*ANGLE in radians}{32*SIN}{32*COS}
 
 
% **   \ellipticalarc  axes ratio A:B  DEGREES degrees from XSTART YSTART 
% **      center at XCENTER YCENTER 
% **    Draws a elliptical arc starting at the coordinate point (XSTART,YSTART).
% **    The center of the ellipse of which the arc is a segment is at 
% **      (XCENTER,YCENTER).
% **    The arc extends through an angle of DEGREES degrees (may be + or -).
% **    A:B is the ratio of the length of the xaxis to the length of
% **      the yaxis of the ellipse
% **    Sqrt{[(XSTART-XCENTER)/A]**2 + [(YSTART-YCENTER)/B]**2}
% **      must be < 512pt (about 7in).
% **    Doesn't modify the dimensions (ht, dp, wd) of the PiCture under
% **      construction.
 
% ** \circulararc  --  See Subsection 5.3 of the manual.
\def\circulararc{%
  \ellipticalarc axes ratio 1:1 }

% ** \ellipticalarc  --  See Subsection 5.3 of the manual.
\def\ellipticalarc axes ratio #1:#2 #3 degrees from #4 #5 center at #6 #7 {%
  \!angle=#3pt\relax%                    ** get angle
  \ifdim\!angle>\!zpt 
    \def\!sign{}%                        ** counterclockwise
  \else 
    \def\!sign{-}\!angle=-\!angle%       ** clockwise
  \fi
  \!xxloc=\!M{#6}\!xunit%                ** convert CENTER to dimension
  \!yyloc=\!M{#7}\!yunit     
  \!xxS=\!M{#4}\!xunit%                  ** get STARTing point on rim of ellipse
  \!yyS=\!M{#5}\!yunit
  \advance\!xxS -\!xxloc%                ** make center of ellipse (0,0)
  \advance\!yyS -\!yyloc
  \!divide\!xxS{#1pt}\!xxS %             ** scale point on ellipse to point on 
  \!divide\!yyS{#2pt}\!yyS %                 corresponding circle
%
  \let\!MC=\!M%                          ** save current c/d mode
  \!setdimenmode%                        ** go into dimension mode
%
  \!xS=#1\!xxS  \advance\!xS\!xxloc
  \!yS=#2\!yyS  \advance\!yS\!yyloc
  \!start (\!xS,\!yS)%
  \!loop\ifdim\!angle>14.9999pt%         ** draw in major portion of ellipse 
    \!rotate(\!xxS,\!yyS)by(\!cos,\!sign\!sin)to(\!xxM,\!yyM) 
    \!rotate(\!xxM,\!yyM)by(\!cos,\!sign\!sin)to(\!xxE,\!yyE)
    \!xM=#1\!xxM  \advance\!xM\!xxloc  \!yM=#2\!yyM  \advance\!yM\!yyloc
    \!xE=#1\!xxE  \advance\!xE\!xxloc  \!yE=#2\!yyE  \advance\!yE\!yyloc
    \!qjoin (\!xM,\!yM) (\!xE,\!yE)
    \!xxS=\!xxE  \!yyS=\!yyE 
    \advance \!angle -15pt
  \repeat
  \ifdim\!angle>\!zpt%                   ** complete remaining arc, if any
    \!angle=100.53096\!angle%            ** convert angle to radians, divide
    \divide \!angle 360 %                **   by 2, and multiply by 32
    \!sinandcos\!angle\!!sin\!!cos%      ** get 32*sin & 32*cos
    \!rotate(\!xxS,\!yyS)by(\!!cos,\!sign\!!sin)to(\!xxM,\!yyM) 
    \!rotate(\!xxM,\!yyM)by(\!!cos,\!sign\!!sin)to(\!xxE,\!yyE)
    \!xM=#1\!xxM  \advance\!xM\!xxloc  \!yM=#2\!yyM  \advance\!yM\!yyloc
    \!xE=#1\!xxE  \advance\!xE\!xxloc  \!yE=#2\!yyE  \advance\!yE\!yyloc
    \!qjoin (\!xM,\!yM) (\!xE,\!yE)
  \fi
%
  \let\!M=\!MC%                          ** restore c/d mode
  \ignorespaces}%                        **   if appropriate
 
 
%  ** \!rotate(XREG,YREG)by(32cos,32sin)to(XXREG,YYREG)
%  ** rotates (XREG,YREG) by angle with specfied scaled cos & sin to
%  ** (XXREG,YYREG).  Uses \!dimenA & \!dimenB as scratch registers.
\def\!rotate(#1,#2)by(#3,#4)to(#5,#6){% 
  \!dimenA=#3#1\advance \!dimenA -#4#2%   ** Rcos(x+t)=Rcosx*cost - Rsinx*sint
  \!dimenB=#3#2\advance \!dimenB  #4#1%   ** Rsin(x+t)=Rsinx*cost + Rcosx*sint
  \divide \!dimenA 32  \divide \!dimenB 32 
  #5=\!dimenA  #6=\!dimenB
  \ignorespaces}
\def\!sin{4.17684}%                       ** 32*sin(pi/24) (pi/24=7.5deg)
\def\!cos{31.72624}%                      ** 32*cos(pi/24)
 
 
%  ** \!sinandcos{32*ANGLE in radians}{\SINCS}{\COSCS}
%  **   Computes the 32*sine and 32*cosine of a small ANGLE expressed in 
%  **   radians/32 and puts these values in the replacement texts of 
%  **   \SINCS and \COSCS
\def\!sinandcos#1#2#3{%
 \!dimenD=#1%                **  angle is expressed in radians/32: 1pt = 1/32rad
 \!dimenA=\!dimenD%          **  dimA will eventually contain 32sin(angle)in pts
 \!dimenB=32pt%              **  dimB will eventually contain 32cos(angle)in pts
 \!removept\!dimenD\!value%  **  get value of 32*angle, without "pt"
 \!dimenC=\!dimenD%          **  holds 32*angle**i/i! in pts
 \!dimenC=\!value\!dimenC \divide\!dimenC by 64 %   ** now 32*angle**2/2
 \advance\!dimenB by -\!dimenC%                     ** 32-32*angle**2/2
 \!dimenC=\!value\!dimenC \divide\!dimenC by 96 %   ** now 32*angle**3/3!
 \advance\!dimenA by -\!dimenC%                     ** now 32*(angle-angle**3/6)
 \!dimenC=\!value\!dimenC \divide\!dimenC by 128 %  ** now 32*angle**4/4!
 \advance\!dimenB by \!dimenC%
 \!removept\!dimenA#2%                              ** set 32*sin(angle)
 \!removept\!dimenB#3%                              ** set 32*cos(angle)
 \ignorespaces}


% *****************************************************************
% ***  RULES  (Draws rules, i.e., horizontal & vertical lines)  ***
% *****************************************************************

% **  User command:
% **    \putrule [<XDIMEN,YDIMEN>] from  XCOORD1 YCOORD1 
% **      to  XCOORD2 YCOORD2 

% **  Internal commands:
% **    \!puthline [<XDIMEN,YDIMEN>]    (h = horizontal)
% **      Set by dashpat to either: \!putsolidhline  or \!putdashedhline
% **    \!putvline [<XDIMEN,YDIMEN>]    (v = vertical)
% **      Either:  \!putsolidvline  or  \!putdashedvline


% **  \putrule [<XDIMEN,YDIMEN>] from XCOORD1 YCOORD1
% **    to XCOORD2 YCOORD2
% **  Draws a rule -- dashed or solid depending on the current dash pattern --
% **    from (X1,Y1) to (X2,Y2).  Uses TEK's  \hrule & \vrule & \leaders  
% **    constructions to handle horizontal & vertical lines efficiently both
% **    in terms of execution time and space in the DVI file.  
% **  See Subsection 4.1 of the manual.
\def\putrule#1from #2 #3 to #4 #5 {%
  \!xloc=\!M{#2}\!xunit  \!xxloc=\!M{#4}\!xunit%   
  \!yloc=\!M{#3}\!yunit  \!yyloc=\!M{#5}\!yunit%           
  \!dxpos=\!xxloc  \advance\!dxpos by -\!xloc
  \!dypos=\!yyloc  \advance\!dypos by -\!yloc
%
  \ifdim\!dypos=\!zpt
    \def\!!Line{\!puthline{#1}}\ignorespaces
  \else
    \ifdim\!dxpos=\!zpt
      \def\!!Line{\!putvline{#1}}\ignorespaces
    \else 
       \def\!!Line{}
    \fi
  \fi
  \let\!ML=\!M%           ** save current coord\dimen mode
  \!setdimenmode%         ** express locations in dimens
  \!!Line%
  \let\!M=\!ML%           ** restore previous c/d mode
  \ignorespaces}
 
 
% **  \!putsolidhline [<XDIMEN,YDIMEN>]
% **  Place horizontal solid line
\def\!putsolidhline#1{%
  \ifdim\!dxpos>\!zpt 
    \put{\!hline\!dxpos}#1[l] at {\!xloc} {\!yloc}
  \else 
    \put{\!hline{-\!dxpos}}#1[l] at {\!xxloc} {\!yyloc}
  \fi
  \ignorespaces}
 
% **  \!putsolidvline [shifted <XDIMEN,YDIMEN>]
% **  Place vertical solid line
\def\!putsolidvline#1{%
  \ifdim\!dypos>\!zpt 
    \put{\!vline\!dypos}#1[b] at {\!xloc} {\!yloc}
  \else 
    \put{\!vline{-\!dypos}}#1[b] at {\!xxloc} {\!yyloc}
  \fi
  \ignorespaces}
 
\def\!hline#1{\hbox to #1{\leaders \hrule height\linethickness\hfill}}
\def\!vline#1{\vbox to #1{\leaders \vrule width\linethickness\vfill}}
 
 
% **  \!putdashedhline [<XDIMEN,YDIMEN>]
% **  Place dashed horizontal line
\def\!putdashedhline#1{%
  \ifdim\!dxpos>\!zpt 
    \!DLsetup\!Flist\!dxpos
    \put{\hbox to \!totalleaderlength{\!hleaders}\!hpartialpattern\!Rtrunc}
      #1[l] at {\!xloc} {\!yloc} 
  \else 
    \!DLsetup\!Blist{-\!dxpos}
    \put{\!hpartialpattern\!Ltrunc\hbox to \!totalleaderlength{\!hleaders}}
      #1[r] at {\!xloc} {\!yloc} 
  \fi
  \ignorespaces}
 
% **  \!putdashedhline [<XDIMEN,YDIMEN>]
% **  Place dashed vertical line
\def\!putdashedvline#1{%
  \!dypos=-\!dypos%            ** vertical leaders go from top to bottom
  \ifdim\!dypos>\!zpt 
    \!DLsetup\!Flist\!dypos 
    \put{\vbox{\vbox to \!totalleaderlength{\!vleaders}
      \!vpartialpattern\!Rtrunc}}#1[t] at {\!xloc} {\!yloc} 
  \else 
    \!DLsetup\!Blist{-\!dypos}
    \put{\vbox{\!vpartialpattern\!Ltrunc
      \vbox to \!totalleaderlength{\!vleaders}}}#1[b] at {\!xloc} {\!yloc} 
  \fi
  \ignorespaces}
 

% **  The rest of the macros in this section are subroutines used by 
% **  \!putdashedhline and \!putdashedvline.
\def\!DLsetup#1#2{%            ** Dashed-Line set up
  \let\!RSlist=#1%             ** set !Rule-Skip list
  \!countB=#2%                 ** convert rule length to integer (number of sps)
  \!countA=\!leaderlength%     ** ditto, leaderlength
  \divide\!countB by \!countA% ** number of complete leader units
  \!totalleaderlength=\!countB\!leaderlength
  \!Rresiduallength=#2%
  \advance \!Rresiduallength by -\!totalleaderlength%  \** excess length
  \!Lresiduallength=\!leaderlength
  \advance \!Lresiduallength by -\!Rresiduallength
  \ignorespaces}
 
\def\!hleaders{%
  \def\!Rule##1{\vrule height\linethickness width##1}%
  \def\!Skip##1{\hskip##1}%
  \leaders\hbox{\!RSlist}\hfill}
 
\def\!hpartialpattern#1{%
  \!dimenA=\!zpt \!dimenB=\!zpt 
  \def\!Rule##1{#1{##1}\vrule height\linethickness width\!dimenD}%
  \def\!Skip##1{#1{##1}\hskip\!dimenD}%
  \!RSlist}
 
\def\!vleaders{%
  \def\!Rule##1{\hrule width\linethickness height##1}%
  \def\!Skip##1{\vskip##1}%
  \leaders\vbox{\!RSlist}\vfill}
 
\def\!vpartialpattern#1{%
  \!dimenA=\!zpt \!dimenB=\!zpt 
  \def\!Rule##1{#1{##1}\hrule width\linethickness height\!dimenD}%
  \def\!Skip##1{#1{##1}\vskip\!dimenD}%
  \!RSlist}
 
\def\!Rtrunc#1{\!trunc{#1}>\!Rresiduallength}
\def\!Ltrunc#1{\!trunc{#1}<\!Lresiduallength}
 
\def\!trunc#1#2#3{%          
  \!dimenA=\!dimenB         
  \advance\!dimenB by #1%
  \!dimenD=\!dimenB  \ifdim\!dimenD#2#3\!dimenD=#3\fi
  \!dimenC=\!dimenA  \ifdim\!dimenC#2#3\!dimenC=#3\fi
  \advance \!dimenD by -\!dimenC}
 

%  ****************************************************************
%  ***  LINEAR ARC  (Draws straight lines -- solid and dashed)  ***
%  ****************************************************************
 
%  **  User commands
%  **    \inboundscheckoff
%  **    \inboundscheckon
   
%  **  Internal commands 
%  **    \!start (XCOORD,YCOORD)
%  **    \!ljoin (XCOORD,YCOORD)
%  **    \!drawlinearsegment  --  set by \dashpat to either
%  **      \!linearsolid  or  \!lineardashed
%  **    \!advancedashing     --  set by \dashpat to either
%  **       \relax  or  \!!advancedashing
%  **    \!plotifinbounds     --  set by \inboundscheck off/on to either
%  **       \!plot  or  \!!plotifinbounds
%  **    \!initinboundscheck  --  set by \inboundscheck off/on to either
%  **       \relax  or  \!!initinboundscheck
 
 
%  \plotsymbolspacing  ** distance between consecutive plot positions
%  \!xS                ** starting x
%  \!yS                ** starting y
%  \!xE                ** ending   x
%  \!yE                ** ending   y
%  \!xdiff             ** x_end - x_start
%  \!ydiff             ** y_end - y_start
%  \!distacross        ** how far along curve next point to be plotted is
%  \!arclength         ** approximate length of arc for current interval
%  \!downlength        ** remaining length for "pen" to be down    
%  \!uplength          ** length for "pen" to be down    
%  \!intervalno        ** counts segments to curve
%  \totalarclength     ** cumulative distance along curve
%  \!npoints           ** approximately  (arc length / plotsymbolspacing)
 
%  **  Calls -- \!Pythag, \!divide, \!plot
 
 
%  **  \!start (XCOORD,YCOORD)
%  **  Sets initial point for linearly (or quadratically) interpolated curve
\def\!start (#1,#2){%
  \!plotxorigin=\!xorigin  \advance \!plotxorigin by \!plotsymbolxshift
  \!plotyorigin=\!yorigin  \advance \!plotyorigin by \!plotsymbolyshift
  \!xS=\!M{#1}\!xunit \!yS=\!M{#2}\!yunit
  \!rotateaboutpivot\!xS\!yS
  \!copylist\!UDlist\to\!!UDlist% **\!UDlist has the form \\{dimen1}\\{dimen2}..
%                                 ** Routine will draw dashed line with pen
%                                 ** down for dimen1, up for dimen2, ...
  \!getnextvalueof\!downlength\from\!!UDlist
  \!distacross=\!zpt%             ** 1st point goes at start of curve
  \!intervalno=0 %                ** initialize interval counter
  \global\totalarclength=\!zpt%   ** initialize distance traveled along curve
  \ignorespaces}
 

%  **  \!ljoin (XCOORD,YCOORD) 
%  **  Draws a straight line starting at the last point specified
%  **    by the most recent \!start, \!ljoin, or \!qjoin, and
%  **    ending at (XCOORD,YCOORD).
\def\!ljoin (#1,#2){%
  \advance\!intervalno by 1
  \!xE=\!M{#1}\!xunit \!yE=\!M{#2}\!yunit
  \!rotateaboutpivot\!xE\!yE
  \!xdiff=\!xE \advance \!xdiff by -\!xS%**  xdiff = xE - xS
  \!ydiff=\!yE \advance \!ydiff by -\!yS%**  ydiff = yE - yS
  \!Pythag\!xdiff\!ydiff\!arclength%     **  arclength = sqrt(xdiff**2+ydiff**2) 
  \global\advance \totalarclength by \!arclength%
  \!drawlinearsegment%   ** set by dashpat to \!linearsolid or \!lineardashed
  \!xS=\!xE \!yS=\!yE%   ** shift ending points to starting points
  \ignorespaces}
 
 
% **  The following routine is used to draw a "solid" line between (xS,yS)
% **  and (xE,yE).  Points are spaced nearly every  \plotsymbolspacing length
% **  along the line.  
\def\!linearsolid{%
  \!npoints=\!arclength
  \!countA=\plotsymbolspacing
  \divide\!npoints by \!countA%      ** now #pts =. arclength/plotsymbolspacing
  \ifnum \!npoints<1 
    \!npoints=1 
  \fi
  \divide\!xdiff by \!npoints
  \divide\!ydiff by \!npoints
  \!xpos=\!xS \!ypos=\!yS
%
  \loop\ifnum\!npoints>-1
    \!plotifinbounds
    \advance \!xpos by \!xdiff
    \advance \!ypos by \!ydiff
    \advance \!npoints by -1
  \repeat
  \ignorespaces}
 
 
% ** The following routine is used to draw a dashed line between (xS,yS)
% ** and (xE,yE). The dash pattern continues from the previous segment.
\def\!lineardashed{%
% **
  \ifdim\!distacross>\!arclength
    \advance \!distacross by -\!arclength  %nothing to plot in this interval
%
  \else
%
    \loop\ifdim\!distacross<\!arclength
%     ** plot point, interpolating linearly in x and y
      \!divide\!distacross\!arclength\!dimenA%  ** dimA = across/arclength
      \!removept\!dimenA\!t%  ** \!t holds value in dimA, without the "pt"
      \!xpos=\!t\!xdiff \advance \!xpos by \!xS
      \!ypos=\!t\!ydiff \advance \!ypos by \!yS
      \!plotifinbounds
      \advance\!distacross by \plotsymbolspacing
      \!advancedashing
    \repeat  
%
    \advance \!distacross by -\!arclength%    ** prepare for next interval 
  \fi
  \ignorespaces}
 
 
\def\!!advancedashing{%
  \advance\!downlength by -\plotsymbolspacing
  \ifdim \!downlength>\!zpt
  \else
    \advance\!distacross by \!downlength
    \!getnextvalueof\!uplength\from\!!UDlist
    \advance\!distacross by \!uplength
    \!getnextvalueof\!downlength\from\!!UDlist
  \fi}
 
 
% ** \inboundscheckoff & \inboundscheckon: See Subsection 5.5 of the manual.
\def\inboundscheckoff{%
  \def\!plotifinbounds{\!plot(\!xpos,\!ypos)}%
  \def\!initinboundscheck{\relax}\ignorespaces}
\def\inboundscheckon{%
  \def\!plotifinbounds{\!!plotifinbounds}%
  \def\!initinboundscheck{\!!initinboundscheck}%
  \!initinboundscheck\ignorespaces} 
\inboundscheckoff
 
% ** The following code plots the current point only if it falls in the
% ** current plotarea.  It doesn't matter if the coordinate system has
% ** changed since the plotarea was set up.  However, shifts of the plot
% ** are ignored (how the plotsymbol stands relative to its plot position is
% ** unknown anyway).
\def\!!plotifinbounds{%
  \ifdim \!xpos<\!checkleft
  \else
    \ifdim \!xpos>\!checkright
    \else
      \ifdim \!ypos<\!checkbot
      \else
         \ifdim \!ypos>\!checktop
         \else
           \!plot(\!xpos,\!ypos)
         \fi 
      \fi
    \fi
  \fi}
 
 
\def\!!initinboundscheck{%
  \!checkleft=\!arealloc     \advance\!checkleft by \!xorigin
  \!checkright=\!arearloc    \advance\!checkright by \!xorigin
  \!checkbot=\!areabloc      \advance\!checkbot by \!yorigin
  \!checktop=\!areatloc      \advance\!checktop by \!yorigin}
 

% *********************************
% *** LOGTEN  (Log_10 function) ***
% *********************************
%
% ** \!logten{X}
% ** Calculates log_10 of X.  X and LOG10(X) are in fixed point notation.
% **  X must be positive; it may have an optional `+' sign; any number
% **  of digits may be specified for X.  The absolute error in LOG10(X) is
% **  less than .0001 (probably < .00006).  That's about as good as you
% **  hope for, since TEX only operates to 5 figures after the decimal
% **  point anyway.

%  \!rootten=3.162278pt       **** These are values are set in ALLOCATIONS
%  \!tenAe=2.543275pt  (=A5)
%  \!tenAc=2.773839pt  (=A3)
%  \!tenAa=8.690286pt  (=A1)

\def\!logten#1#2{%
  \expandafter\!!logten#1\!nil
  \!removept\!dimenF#2%
  \ignorespaces}

\def\!!logten#1#2\!nil{%
  \if -#1%
    \!dimenF=\!zpt
    \def\!next{\ignorespaces}%
  \else
    \if +#1%
      \def\!next{\!!logten#2\!nil}%
    \else
      \if .#1%
        \def\!next{\!!logten0.#2\!nil}%
      \else
        \def\!next{\!!!logten#1#2..\!nil}%
      \fi
    \fi
  \fi
  \!next}

\def\!!!logten#1#2.#3.#4\!nil{%
  \!dimenF=1pt %                 ** DimF holds log10 original argument
  \if 0#1%                      
    \!!logshift#3pt %            ** Argument < 1
  \else %                        ** Argument >= 1
    \!logshift#2/%               ** Shift decimal pt as many places
    \!dimenE=#1.#2#3pt %         **   as there are figures in #2
  \fi %                          ** Now dimE holds revised X want log10 of
  \ifdim \!dimenE<\!rootten%          ** Transform X to XX between sqrt(10) 
    \multiply \!dimenE 10 %           **   and 10*sqrt(10)
    \advance  \!dimenF -1pt
  \fi
  \!dimenG=\!dimenE%                  ** dimG <- (XX + 10)
    \advance\!dimenG 10pt
  \advance\!dimenE -10pt %            ** dimE <- (XX - 10)
  \multiply\!dimenE 10 %              ** dimE = 10*(XX-10)
  \!divide\!dimenE\!dimenG\!dimenE%   ** Now dimE=10t==10*(XX-10)/(XX+10)
  \!removept\!dimenE\!t%              ** !t=10t, with "pt" removed
  \!dimenG=\!t\!dimenE%               ** dimG=100t**2
  \!removept\!dimenG\!tt%             ** !tt=100t**2, with "pt" removed
  \!dimenH=\!tt\!tenAe%               ** dimH=10*a5*(10t)**2 /100
    \divide\!dimenH 100
  \advance\!dimenH \!tenAc%           ** ditto + 10*a3
  \!dimenH=\!tt\!dimenH%              ** ditto * (10t)**2 /100
    \divide\!dimenH 100   
  \advance\!dimenH \!tenAa%           ** ditto + 10*a1
  \!dimenH=\!t\!dimenH%               ** ditto * 10t / 100
    \divide\!dimenH 100 %             ** Now dimH = log10(XX) - 1
  \advance\!dimenF \!dimenH}%         ** dimF = log10(X)

\def\!logshift#1{%
  \if #1/%
    \def\!next{\ignorespaces}%
  \else
    \advance\!dimenF 1pt 
    \def\!next{\!logshift}%
  \fi 
  \!next}
 
 \def\!!logshift#1{%
   \advance\!dimenF -1pt
   \if 0#1%
     \def\!next{\!!logshift}%
   \else
     \if p#1%
       \!dimenF=1pt
       \def\!next{\!dimenE=1p}%
     \else
       \def\!next{\!dimenE=#1.}%
     \fi
   \fi
   \!next}


% ***********************************************************
% *** PICTURES (Basic setups for PiCtures; \put commands) ***
% ***********************************************************
 
% **  User Commands:
% **    \beginpicture
% **    \endpicture    
% **    \endpicturesave <XREG,YREG>
% **    \setcoordinatesystem units <XUNIT,YUNIT> point at XREF YREF
% **    \put {OBJECT} [ORIENTATION] <XSHIFT,YSHIFT> at XCOORD YCOORD
% **    \multiput {OJBECT} [ORIENTATION] <XSHIFT,YSHIFT>) at
% **      XCOORD YCOORD
% **      *NUMBER_OF_TIMES DXCOORD DYCOORD  /
% **    \accountingon
% **    \accountingoff
% **    \stack [ORIENTATION] <LEADING> {LIST OF ITEMS}
% **    \lines [ORIENTATION] {LINES}
% **    \Lines [ORIENTATION] {LINES}
% **    \setdimensionmode
% **    \setcoordinatemode
% **    \Xdistance
% **    \Ydistance
  
% **  Internal commands:
% **    \!setputobject{OBJECT}{[ORIENTATION]<XSHIFT,YSHIFT>}
% **    \!dimenput{OBJECT}[ORIENTATION]<XSHIFT,YSHIFT>(XDIMEN,YDIMEN)
% **    \!setdimenmode
% **    \!setcoordmode
% **    \!ifdimenmode
% **    \!ifcoordmode
  
 
% **  \beginpicture
% **  \endpicture
% **  \endpicturesave <XREG,YREG>
% **    \beginpicture ... \endpicture  creates an hbox.  Objects are
% **    placed in this box using the \put command and the like (see below).
% **    The location of an object is specified in terms of coordinate system(s)
% **    established by \setcoordinatesystem.  Each coordinate system (there
% **    might be just one) specifies the length of 1 horizontal unit, the length
% **    of 1 vertical unit, and the coordinates of a "reference point".  The
% **    reference points of various coordinate systems will be in the same
% **    physical location.  The macros keep track of the size of the objects
% **    and their locations. The resulting hbox is the smallest hbox which
% **    encloses all the objects, and whose TEK reference point is the point
% **    on the left edge of the box closest vertically to the PICTEX reference
% **    point. Using \endpicturesave, you can (globally) save the distance TEK's
% **    reference point is to the right (respectively, up from) PICTEX's 
% **    reference point in the dimension register \XREG (respectively \YREG). 
% **    You can then \put the picture OBJECT into a larger picture so that its
% **    reference point is at (XCOORD,YCOORD) with the command
% **      \put {picture OBJECT} [Bl] <\XREG, \YREG> at  XCOORD YCOORD 

% **  \beginpicture : See Subsection 1.1 of the manual.
\def\beginpicture{%
  \setbox\!picbox=\hbox\bgroup%
  \!xleft=\maxdimen  
  \!xright=-\maxdimen
  \!ybot=\maxdimen
  \!ytop=-\maxdimen}
 
% **  \endpicture : See Subsection 1.1 of the manual.
\def\endpicture{%
  \ifdim\!xleft=\maxdimen%  ** check if nothing was put in picbox
    \!xleft=\!zpt \!xright=\!zpt \!ybot=\!zpt \!ytop=\!zpt 
  \fi
  \global\!Xleft=\!xleft \global\!Xright=\!xright
  \global\!Ybot=\!ybot \global\!Ytop=\!ytop
  \egroup%
  \ht\!picbox=\!Ytop  \dp\!picbox=-\!Ybot
  \ifdim\!Ybot>\!zpt
  \else 
    \ifdim\!Ytop<\!zpt
      \!Ybot=\!Ytop
    \else
      \!Ybot=\!zpt
    \fi
  \fi
  \hbox{\kern-\!Xleft\lower\!Ybot\box\!picbox\kern\!Xright}}
 
% **  \endpicturesave : See Subsection 8.4 of the manual.
\def\endpicturesave <#1,#2>{%
  \endpicture \global #1=\!Xleft \global #2=\!Ybot \ignorespaces}
 
 
% **   \setcoordinatesystem units <XUNIT,YUNIT> 
% **     point at XREF YREF  
% **   Each of `units <XUNIT,YUNIT>' and `point at XREF YREF' 
% **     are optional.
% **   Unit lengths must be given in dimensions (e.g., <10pt,1in>).
% **     Default unit lengths are 1pt, 1pt, or previous unit lengths.
% **   Reference point is specified in current units (e.g., 3 5 ). 
% **     Default reference point is 0 0 , or previous reference point.
% **   Unit lengths and reference points obey TEX's scoping rules.
% **   See Subsection 1.2 of the manual.
\def\setcoordinatesystem{%
  \!ifnextchar{u}{\!getlengths }
    {\!getlengths units <\!xunit,\!yunit>}}
\def\!getlengths units <#1,#2>{%
  \!xunit=#1\relax
  \!yunit=#2\relax
  \!ifcoordmode 
    \let\!SCnext=\!SCccheckforRP
  \else
    \let\!SCnext=\!SCdcheckforRP
  \fi
  \!SCnext}
\def\!SCccheckforRP{%
  \!ifnextchar{p}{\!cgetreference }
    {\!cgetreference point at {\!xref} {\!yref} }}
\def\!cgetreference point at #1 #2 {%
  \edef\!xref{#1}\edef\!yref{#2}%
  \!xorigin=\!xref\!xunit  \!yorigin=\!yref\!yunit  
  \!initinboundscheck % ** See linear.tex
  \ignorespaces}
\def\!SCdcheckforRP{%
  \!ifnextchar{p}{\!dgetreference}%
    {\ignorespaces}}
\def\!dgetreference point at #1 #2 {%
  \!xorigin=#1\relax  \!yorigin=#2\relax
  \ignorespaces}

 
%  ** \put {OBJECT} [XY] <XDIMEN,YDIMEN> at (XCOORD,YCOORD)
%  **   `[XY]' and `<XDIMEN,YDIMEN>' are optional.
%  **   First OBJECT is placed in an hbox (the "objectbox") and then a
%  **     "reference point" is assigned to the objectbox as follows:
%  **     [1] first, the reference point is taken to be the center of the box;
%  **     [2] next, centering is overridden by the specifications
%  **           X=l -- reference point along the left edge of the objectbox
%  **           X=r -- reference point along the right edge of the objectbox
%  **           Y=b -- reference point along the bottom edge of the objectbox
%  **           Y=B -- reference point along the Baseline of the objectbox
%  **           Y=t -- reference point along the top edge of the objectbox;
%  **     [3] finally the reference point is shifted left by XDIMEN, down
%  **           by YDIMEN  (both default to 0pt).
%  **   The objectbox is placed within PICBOX with its reference point at  
%  **     (XCOORD,YCOORD). 
%  **   If OBJECT is a saved box, say  box0, you have to write
%  **     \put{\box0}...   or  \put{\copy0}...
%  **   The objectbox is void after the put.
%  **   See Subsection 2.1 of the manual.
\long\def\put#1#2 at #3 #4 {%
  \!setputobject{#1}{#2}%
  \!xpos=\!M{#3}\!xunit  \!ypos=\!M{#4}\!yunit  
  \!rotateaboutpivot\!xpos\!ypos%
  \advance\!xpos -\!xorigin  \advance\!xpos -\!xshift
  \advance\!ypos -\!yorigin  \advance\!ypos -\!yshift
  \kern\!xpos\raise\!ypos\box\!putobject\kern-\!xpos%
  \!doaccounting\ignorespaces}
 
%  **   \multiput etc.  Like  \put.  The objectbox is not voided until the
%  **     termininating /, and is placed repeatedly with:
%  **     XCOORD YCOORD -- the objectbox is put down with its reference point
%  **       at (XCOORD,YCOORD);
%  **     *N DXCOORD DYCOORD -- each of N times the current
%  **       (xcoord,ycoord) is incremented by (DXCOORD,DYCOORD), and the
%  **       objectbox is put down with its reference point at (xcoord,ycoord)
%  **       (This specification has to follow an XCOORD YCOORD pair)
%  **     See Subsection 2.2 of the manual.
\long\def\multiput #1#2 at {%
  \!setputobject{#1}{#2}%
  \!ifnextchar"{\!putfromfile}{\!multiput}}
\def\!putfromfile"#1"{%
  \expandafter\!multiput \input #1 /}
\def\!multiput{%
  \futurelet\!nextchar\!!multiput}
\def\!!multiput{%
  \if *\!nextchar
    \def\!nextput{\!alsoby}%
  \else
    \if /\!nextchar
      \def\!nextput{\!finishmultiput}%
    \else
      \def\!nextput{\!alsoat}%
    \fi
  \fi
  \!nextput}
\def\!finishmultiput/{%
  \setbox\!putobject=\hbox{}%
  \ignorespaces}
 
%  **   \!alsoat XCOORD YCOORD 
%  **     The objectbox is put down with reference point at XCOORD,YCOORD
\def\!alsoat#1 #2 {%
  \!xpos=\!M{#1}\!xunit  \!ypos=\!M{#2}\!yunit  
  \!rotateaboutpivot\!xpos\!ypos%
  \advance\!xpos -\!xorigin  \advance\!xpos -\!xshift
  \advance\!ypos -\!yorigin  \advance\!ypos -\!yshift
  \kern\!xpos\raise\!ypos\copy\!putobject\kern-\!xpos%
  \!doaccounting
  \!multiput}
 
% **   \!alsoby*N DXCOORD DYCOORD
% **     N times, the current (XCOORD,YCOORD) is advanced by (DXCOORD,DYCOORD),
% **     and the current (shifted, oriented) OBJECT is put down.
\def\!alsoby*#1 #2 #3 {%
  \!dxpos=\!M{#2}\!xunit \!dypos=\!M{#3}\!yunit 
  \!rotateonly\!dxpos\!dypos
  \!ntemp=#1%
  \!!loop\ifnum\!ntemp>0
    \advance\!xpos by \!dxpos  \advance\!ypos by \!dypos
    \kern\!xpos\raise\!ypos\copy\!putobject\kern-\!xpos%
    \advance\!ntemp by -1
  \repeat
  \!doaccounting 
  \!multiput}
 
% **  \accountingoff : Suspends PiCTeX's accounting of the aggregate
% **    size of the picture box.
% **  \accounting on : Reinstates accounting.
% **  See Subsection 8.2 of the manual.
\def\accountingon{\def\!doaccounting{\!!doaccounting}\ignorespaces}
\def\accountingoff{\def\!doaccounting{}\ignorespaces}
\accountingon
\def\!!doaccounting{%
  \!xtemp=\!xpos  
  \!ytemp=\!ypos
  \ifdim\!xtemp<\!xleft 
     \!xleft=\!xtemp 
  \fi
  \advance\!xtemp by  \!wd 
  \ifdim\!xright<\!xtemp 
    \!xright=\!xtemp
  \fi
  \advance\!ytemp by -\!dp
  \ifdim\!ytemp<\!ybot  
    \!ybot=\!ytemp
  \fi
  \advance\!ytemp by  \!dp
  \advance\!ytemp by  \!ht 
  \ifdim\!ytemp>\!ytop  
    \!ytop=\!ytemp  
  \fi}
 
\long\def\!setputobject#1#2{%
  \setbox\!putobject=\hbox{#1}%
  \!ht=\ht\!putobject  \!dp=\dp\!putobject  \!wd=\wd\!putobject
  \wd\!putobject=\!zpt
  \!xshift=.5\!wd   \!yshift=.5\!ht   \advance\!yshift by -.5\!dp
  \edef\!putorientation{#2}%
  \expandafter\!SPOreadA\!putorientation[]\!nil%
  \expandafter\!SPOreadB\!putorientation<\!zpt,\!zpt>\!nil\ignorespaces}
 
\def\!SPOreadA#1[#2]#3\!nil{\!etfor\!orientation:=#2\do\!SPOreviseshift}
 
\def\!SPOreadB#1<#2,#3>#4\!nil{\advance\!xshift by -#2\advance\!yshift by -#3}
 
\def\!SPOreviseshift{%
  \if l\!orientation 
    \!xshift=\!zpt
  \else 
    \if r\!orientation 
      \!xshift=\!wd
    \else 
      \if b\!orientation
        \!yshift=-\!dp
      \else 
        \if B\!orientation 
          \!yshift=\!zpt
        \else 
          \if t\!orientation 
            \!yshift=\!ht
          \fi 
        \fi
      \fi
    \fi
  \fi}
 
 
%  **  \!dimenput{OBJECT} <XDIMEN,YDIMEN> [XY] (XLOC,YLOC)
%  **    This is an internal put routine, similar to \put, except that
%  **    XLOC=distance right from reference point, YLOC=distance up from
%  **    reference point. XLOC and YLOC are dimensions, so this routine
%  **    is completely independent of the current coordinate system. 
%  **    This routine does NOT do ROTATIONS.
\long\def\!dimenput#1#2(#3,#4){%
  \!setputobject{#1}{#2}%
  \!xpos=#3\advance\!xpos by -\!xshift
  \!ypos=#4\advance\!ypos by -\!yshift
  \kern\!xpos\raise\!ypos\box\!putobject\kern-\!xpos%
  \!doaccounting\ignorespaces}
 
 
%  ** The following macros permit the picture drawing routines to be used 
%  ** either in the default "coordinate mode", or in "dimension mode".
%  **   In coordinate mode  \!M(1.5,\!xunit)    expands to  1.5\!xunit
%  **   In dimension  mode  \!M(1.5pt,\!xunit)  expands to  1.5pt
%  ** Dimension mode is useful in coding macros.
%  ** Any special purpose picture macro that sets dimension mode should 
%  ** reset coordinate mode before completion.
%  ** See Subsection 9.2 of the manual.
\def\!setdimenmode{%
  \let\!M=\!M!!\ignorespaces}
\def\!setcoordmode{%
  \let\!M=\!M!\ignorespaces}
\def\!ifcoordmode{%
  \ifx \!M \!M!}
\def\!ifdimenmode{%
  \ifx \!M \!M!!}
\def\!M!#1#2{#1#2} 
\def\!M!!#1#2{#1}
\!setcoordmode
\let\setdimensionmode=\!setdimenmode
\let\setcoordinatemode=\!setcoordmode

%  ** \Xdistance{XCOORD}, \Ydistance{YCOORD}  are the horizontal and
%  **   vertical distances from the origin (0,0) to the point
%  **   (XCOORD,YCOORD)  in the current coordinate system.
%  ** See Subsection 9.2 of the manual.
\def\Xdistance#1{%
  \!M{#1}\!xunit
  \ignorespaces}
\def\Ydistance#1{%
  \!M{#1}\!yunit
  \ignorespaces}

% ** The following macros -- \stack, \line, and \Lines -- are useful for
% **   annotating PiCtures. They can be used outside the \beginpicture ...
% **   \endpicture environment.

% ** \stack [POSITIONING] <LEADING> {VALUESLIST}
% ** Builds a vertical stack of the values in VALUESLIST. Values in
% ** VALUESLIST are separated by commas.  In the resulting stack, values are
% ** centered by default, and positioned flush left (right) if 
% ** POSITIONING = l (r).  Values are separated vertically by LEADING,
% ** which defaults to \stackleading.
% ** See Subsection 2.3 of the manual.
\def\stack{%
  \!ifnextchar[{\!stack}{\!stack[c]}}
\def\!stack[#1]{%
  \let\!lglue=\hfill \let\!rglue=\hfill
  \expandafter\let\csname !#1glue\endcsname=\relax
  \!ifnextchar<{\!!stack}{\!!stack<\stackleading>}}
\def\!!stack<#1>#2{%
  \vbox{\def\!valueslist{}\!ecfor\!value:=#2\do{%
    \expandafter\!rightappend\!value\withCS{\\}\to\!valueslist}%
    \!lop\!valueslist\to\!value
    \let\\=\cr\lineskiplimit=\maxdimen\lineskip=#1%
    \baselineskip=-1000pt\halign{\!lglue##\!rglue\cr \!value\!valueslist\cr}}%
  \ignorespaces}

% ** \lines [POSITIONING] {LINES}
% ** Builds a vertical array of the lines in LINES. Each line in LINES
% ** is terminated by a \cr.  In the resulting array, lines are
% ** centered by default, and positioned flush left (right) if 
% ** POSITIONING = l (r).  The lines in the array are subject to TeX's
% ** usual spacing rules: in particular the baselines are ordinarily an equal
% ** distance apart. The baseline of the array is the baseline of the
% ** the bottom line.
% ** See Subsection 2.3 of the manual.
\def\lines{%
  \!ifnextchar[{\!lines}{\!lines[c]}}
\def\!lines[#1]#2{%
  \let\!lglue=\hfill \let\!rglue=\hfill
  \expandafter\let\csname !#1glue\endcsname=\relax
  \vbox{\halign{\!lglue##\!rglue\cr #2\crcr}}%
  \ignorespaces}

% ** \Lines [POSITIONING] {LINES}
% ** Like \lines, but the baseline of the array is the baseline of the
% ** top line.  See Subsection 2.3 of the manual.
\def\Lines{%
  \!ifnextchar[{\!Lines}{\!Lines[c]}}
\def\!Lines[#1]#2{%
  \let\!lglue=\hfill \let\!rglue=\hfill
  \expandafter\let\csname !#1glue\endcsname=\relax
  \vtop{\halign{\!lglue##\!rglue\cr #2\crcr}}%
  \ignorespaces}


% *********************************************
% *** PLOTTING (Things to do with plotting) ***
% *********************************************
 
% **  User commands
% **    \setplotsymbol ({PLOTSYMBOL} [ORIENTATION] <XSHIFT,YSHIFT>)
% **    \savelinesandcurves on "FILE_NAME"
% **    \dontsavelinesandcurves
% **    \writesavefile {MESSAGE}
% **    \replot {FILE_NAME}
 
% **  Internal command
% **    \!plot(XDIMEN,YDIMEN)
 
% **  \setplotsymbol ({PLOTSYMBOL} [ ] < , >)
% **  Save PLOTSYMBOL away in an hbox for use with curve plotting routines
% **  See Subsection 5.2 of the manual.
\def\setplotsymbol(#1#2){%
  \!setputobject{#1}{#2}
  \setbox\!plotsymbol=\box\!putobject%
  \!plotsymbolxshift=\!xshift 
  \!plotsymbolyshift=\!yshift 
  \ignorespaces}
 
\setplotsymbol({\fiverm .})%       ** initialize plotsymbol
 
 
% **  \!plot is either \!!plot (when no lines and curves are being saved) or
% **                   \!!!plot (when   lines and curves are being saved)
 
% **  \!!plot(XDIMEN,YDIMEN)
% **  Places the current plotsymbol a horizontal distance=XDIMEN-xorigin 
% **    and a vertical distance=YDIMEN-yorigin from the current
% **    reference point.  
\def\!!plot(#1,#2){%
  \!dimenA=-\!plotxorigin \advance \!dimenA by #1%    ** over
  \!dimenB=-\!plotyorigin \advance \!dimenB by #2%    ** up
  \kern\!dimenA\raise\!dimenB\copy\!plotsymbol\kern-\!dimenA%
  \ignorespaces}
 
% **  \!!!plot(XDIMEN,YDIMEN)
% **  Like \!!plot, but also saves the plot location in units of 
% **    scaled point, on file `replotfile'
\def\!!!plot(#1,#2){%
  \!dimenA=-\!plotxorigin \advance \!dimenA by #1%    ** over

  \!dimenB=-\!plotyorigin \advance \!dimenB by #2%    ** up
  \kern\!dimenA\raise\!dimenB\copy\!plotsymbol\kern-\!dimenA%
  \!countE=\!dimenA
  \!countF=\!dimenB
  \immediate\write\!replotfile{\the\!countE,\the\!countF.}%
  \ignorespaces}


% ** \savelinesandcurves on "FILE_NAME"
% **   Switch to save locations used for plotting lines and curves
% **   (No advantage in saving locations for solid lines; however
% **   replotting curve locations speeds things up by a factor of about 4. 
% ** \dontsavelinesandcurves
% **   Terminates \savelinesandcurves. The default.
% ** See Subsection 5.6 of the manual.
\def\savelinesandcurves on "#1" {%
  \immediate\closeout\!replotfile
  \immediate\openout\!replotfile=#1%
  \let\!plot=\!!!plot}

\def\dontsavelinesandcurves {%
  \let\!plot=\!!plot}
\dontsavelinesandcurves

% ** \writesavefile {MESSAGE}
% ** The message is preceded by a "%", so that it won't interfere
% ** with replotting.
% ** See Subsection 5.6 of the manual.
{\catcode`\%=11\xdef\!Commentsignal{%}}
\def\writesavefile#1 {%
  \immediate\write\!replotfile{\!Commentsignal #1}%
  \ignorespaces}

% ** \replot "FILE_NAME"
% **   Replots the locations saved earlier under \savelinesandcurves
% **   on "FILE_NAME"
% ** See Subsection 5.6 of the manual.
\def\replot"#1" {%
  \expandafter\!replot\input #1 /}
\def\!replot#1,#2. {%
  \!dimenA=#1sp
  \kern\!dimenA\raise#2sp\copy\!plotsymbol\kern-\!dimenA
  \futurelet\!nextchar\!!replot}
\def\!!replot{%
  \if /\!nextchar 
    \def\!next{\!finish}%
  \else
    \def\!next{\!replot}%
  \fi
  \!next}
% **************************************************
% ***  PYTHAGORAS  (Euclidean distance function) ***
% **************************************************

% ** User command:
% **   \placehypotenuse for <dimension1> and <dimension2> in <register> 

% ** Internal command:
% **   \!Pythag{X}{Y}{Z}
% **     Input X,Y are dimensions, or dimension registers.
% **     Output Z == sqrt(X**2+Y**2) must be a dimension register.
% **     Assumes that |X|+|Y| < 2048pt (about 28in).
 
% ** Without loss of generality, suppose  x>0, y>0.  Put s = x+y,
% **   z = sqrt(x**2+y**2). Then  z = s*f,  where  f = sqrt(t**2 + (1-t)**2)
% **   = sqrt((1+tau**2)/2), where  t = x/s  and  tau = 2(t-1/2) .
 
% ** Uses the \!divide macro (which uses registers \!dimenA--\!dimenD.
% ** Uses the \!removept macro   (e.g., 123.45pt --> 123.45)
% ** Uses registers \!dimenE--\!dimenI.
\def\!Pythag#1#2#3{%
  \!dimenE=#1\relax                                     
  \ifdim\!dimenE<\!zpt 
    \!dimenE=-\!dimenE 
  \fi%                                            ** dimE = |x|
  \!dimenF=#2\relax
  \ifdim\!dimenF<\!zpt 
    \!dimenF=-\!dimenF 
  \fi%                                            ** dimF = |y|
  \advance \!dimenF by \!dimenE%                  ** dimF = s = |x|+|y|
  \ifdim\!dimenF=\!zpt 
    \!dimenG=\!zpt%                               ** dimG = z = sqrt(x**2+y**2)
  \else 
    \!divide{8\!dimenE}\!dimenF\!dimenE%          ** now dimE = 8t = (8|x|)/s
    \advance\!dimenE by -4pt%                     ** 8tau = (8t-4)*2
      \!dimenE=2\!dimenE%                         **   (tau = 2*t - 1)
    \!removept\!dimenE\!!t%                       ** 8tau, without "pt"
    \!dimenE=\!!t\!dimenE%                        ** (8tau)**2, in pts
    \advance\!dimenE by 64pt%                     ** u = [64 + (8tau)**2]/2
    \divide \!dimenE by 2%                        **   [u = (8f)**2]
    \!dimenH=7pt%                                 ** initial guess g at sqrt(u)
    \!!Pythag\!!Pythag\!!Pythag%                  ** 3 iterations give sqrt(u)
    \!removept\!dimenH\!!t%                       ** 8f=sqrt(u), without "pt"
    \!dimenG=\!!t\!dimenF%                        ** z = (8f)*s/8
    \divide\!dimenG by 8
  \fi
  #3=\!dimenG
  \ignorespaces}

\def\!!Pythag{%                                   ** Newton-Raphson for sqrt
  \!divide\!dimenE\!dimenH\!dimenI%               ** v = u/g
  \advance\!dimenH by \!dimenI%                   ** g <-- (g + u/g)/2
    \divide\!dimenH by 2}

% **  \placehypotenuse for <XI> and <ETA> in <ZETA>
% **  See Subsection 9.3 of the manual.
\def\placehypotenuse for <#1> and <#2> in <#3> {%
  \!Pythag{#1}{#2}{#3}}


% **********************************************
% *** QUADRATIC ARC  (Draws a quadratic arc) ***
% **********************************************
 
% **  Internal command
% **    \!qjoin (XCOORD1,YCOORD1) (XCOORD2,YCOORD2)
 
% **  \!qjoin (XCOORD1,YCOORD1) (XCOORD2,YCOORD2)
% **  Draws an arc starting at the (last) point specified by the most recent
% **  \!qjoin, or \!ljoin, or \!start  and passing through (X_1,Y_1), (X_2,Y_2).
% **  Uses quadratic interpolation in both  x  and  y:  
% **    x(t), 0 <= t <= 1, interpolates  x_0, x_1, x_2  at  t=0, .5, 1
% **    y(t), 0 <= t <= 1, interpolates  y_0, y_1, y_2  at  t=0, .5, 1
 
\def\!qjoin (#1,#2) (#3,#4){%
  \advance\!intervalno by 1
  \!ifcoordmode
    \edef\!xmidpt{#1}\edef\!ymidpt{#2}%
  \else
    \!dimenA=#1\relax \edef\!xmidpt{\the\!dimenA}%
    \!dimenA=#2\relax \edef\!xmidpt{\the\!dimenA}%
  \fi
  \!xM=\!M{#1}\!xunit  \!yM=\!M{#2}\!yunit   \!rotateaboutpivot\!xM\!yM
  \!xE=\!M{#3}\!xunit  \!yE=\!M{#4}\!yunit   \!rotateaboutpivot\!xE\!yE
%
% ** Find coefficients for x(t)=a_x + b_x*t + c_x*t**2
  \!dimenA=\!xM  \advance \!dimenA by -\!xS%   ** dimA = I = xM - xS
  \!dimenB=\!xE  \advance \!dimenB by -\!xM%   ** dimB = II = xE-xM
  \!xB=3\!dimenA \advance \!xB by -\!dimenB%   ** b=3I-II
  \!xC=2\!dimenB \advance \!xC by -2\!dimenA%  ** c=2(II-I)
%
% ** Find coefficients for y(t)=y_x + b_y*t + c_y*t**2
  \!dimenA=\!yM  \advance \!dimenA by -\!yS%   
  \!dimenB=\!yE  \advance \!dimenB by -\!yM%  
  \!yB=3\!dimenA \advance \!yB by -\!dimenB%  
  \!yC=2\!dimenB \advance \!yC by -2\!dimenA% 
%
% ** Use Simpson's rule to calculate arc length over [0,1/2]:
% **   arc length = 1/2[1/6 f(0) + 4/6 f(1/4) + 1/6 f(1/2)]
% ** with f(t) = sqrt(x'(t)**2 + y'(t)**2).
  \!xprime=\!xB  \!yprime=\!yB%          ** x'(t) = b + 2ct
  \!dxprime=.5\!xC  \!dyprime=.5\!yC%    ** dt=1/4 ==> dx'(t) = c/2
  \!getf \!midarclength=\!dimenA
  \!getf \advance \!midarclength by 4\!dimenA
  \!getf \advance \!midarclength by \!dimenA
  \divide \!midarclength by 12
%
% ** Get arc length over [0,1].
  \!arclength=\!dimenA
  \!getf \advance \!arclength by 4\!dimenA
  \!getf \advance \!arclength by \!dimenA
  \divide \!arclength by 12%             ** Now have arc length over [1/2,1]
  \advance \!arclength by \!midarclength
  \global\advance \totalarclength by \!arclength
%
%
% ** Check to see if there's anything to plot in this interval
  \ifdim\!distacross>\!arclength 
    \advance \!distacross by -\!arclength%   ** nothing 
%
  \else
    \!initinverseinterp%  ** initialize for inverse interpolation on arc length
    \loop\ifdim\!distacross<\!arclength%     ** loop over points on arc 
      \!inverseinterp%    ** find  t  such that arc length[0,t] = distacross,
%                         **   using inverse quadratic interpolation
%                         ** now evaluate x(t)=(c*t + b)*t + a
      \!xpos=\!t\!xC \advance\!xpos by \!xB
        \!xpos=\!t\!xpos \advance \!xpos by \!xS
%                                             ** evaluate y(t)
      \!ypos=\!t\!yC \advance\!ypos by \!yB
        \!ypos=\!t\!ypos \advance \!ypos by \!yS
      \!plotifinbounds%                       ** plot point if in bounds
      \advance\!distacross \plotsymbolspacing%** advance arc length for next pt
      \!advancedashing%                       ** see "linear"
    \repeat  
%
    \advance \!distacross by -\!arclength%    ** prepare for next interval 
  \fi
%
  \!xS=\!xE%              ** shift ending points to starting points
  \!yS=\!yE
  \ignorespaces}
 
 
% ** \!getf -- Calculates sqrt(x'(t)**2 + y'(t)**2) and advances
% **   x'(t) and y'(t)
\def\!getf{\!Pythag\!xprime\!yprime\!dimenA%
  \advance\!xprime by \!dxprime
  \advance\!yprime by \!dyprime}
 
 
% ** \!initinverseinterp -- initializes for inverse quadratic interpolation
% ** of arc length provided  1/3 < midarclength/arclength < 2/3; otherwise
% ** initializes for inverse linear interpolation.
\def\!initinverseinterp{%
  \ifdim\!arclength>\!zpt
    \!divide{8\!midarclength}\!arclength\!dimenE% ** dimE=8w=8r/s, where  r 
%                                               **  = midarclength, s=arclength
% **  Test for  w  out of range:  w<1/3  or w>2/3
    \ifdim\!dimenE<\!wmin \!setinverselinear
    \else 
      \ifdim\!dimenE>\!wmax \!setinverselinear
      \else%                                    ** w  in range: initialize
        \def\!inverseinterp{\!inversequad}\ignorespaces
%
% **     Calculate the coefficients  \!beta  and  \!gamma  of the quadratic
% **                    t = \!beta*v + \!gamma*v**2
% **     taking the values  t=0, 1/2, 1  at  v=0, w==r/s, 1  respectively:
% **        \!beta = (1/2 - w**2)/[w(1-w)] 
% **        \!gamma = 1 - beta.
%
         \!removept\!dimenE\!Ew%           **  8w, without "pt"
         \!dimenF=-\!Ew\!dimenE%           **  -(8w)**2
         \advance\!dimenF by 32pt%         **  32 - (8w)**2
         \!dimenG=8pt 
         \advance\!dimenG by -\!dimenE%    **  8 - 8w
         \!dimenG=\!Ew\!dimenG%            **  (8w)*(8-8w)
         \!divide\!dimenF\!dimenG\!beta%   **  beta = (32-(8w)**2)/(8w(8-8w))
%                                          **       = (1/2 - w**2)/(w(1-w))
         \!gamma=1pt
         \advance \!gamma by -\!beta%      **  gamma = 1-beta
      \fi%       ** end of the \ifdim\!dimenE>\!wmax
    \fi%         ** end of the \ifdim\!dimenE<\!wmin
  \fi%           ** end of the \ifdim\!arclength>\!zpt
  \ignorespaces}
 
 
% ** For 0 <= t <= 1, let AL(t) = arclength[0,t]/arclength[0,1]; note
% ** AL(0)=0, AL(1/2)=midarclength/arclength, AL(1)=1.  This routine
% ** calculates an approximation to AL^{-1}(distance across/arclength),
% ** using the assumption that AL^{-1} is quadratic.  Specifically, 
% ** it finds  t  such that
% **    AL^{-1}(v) =. t = v*(\!beta + \!gamma*v)
% ** where  \!beta  and  \!gamma  are set by \!initinv, and where
% ** v=distance across/arclength
\def\!inversequad{%
  \!divide\!distacross\!arclength\!dimenG%   ** dimG = v = distacross/arclength
  \!removept\!dimenG\!v%                     ** v, without "pt"
  \!dimenG=\!v\!gamma%                       ** gamma*v
  \advance\!dimenG by \!beta%                ** beta + gamma*v
  \!dimenG=\!v\!dimenG%                      ** t = v*(beta + gamma*v)
  \!removept\!dimenG\!t}%                    ** t, without "pt"
 
 
% ** When  w <= 1/3  or  w >= 2/3, the following routine writes (using
% ** plain TEK's \wlog command) a warning message on the user's log file,
% ** and initializes for inverse linear interpolation on arc length.
\def\!setinverselinear{%
  \def\!inverseinterp{\!inverselinear}%
  \divide\!dimenE by 8 \!removept\!dimenE\!t
  \!countC=\!intervalno \multiply \!countC 2
  \!countB=\!countC     \advance \!countB -1
  \!countA=\!countB     \advance \!countA -1
  \wlog{\the\!countB th point (\!xmidpt,\!ymidpt) being plotted 
    doesn't lie in the}%
  \wlog{ middle third of the arc between the \the\!countA th 
    and \the\!countC th points:}%
  \wlog{ [arc length \the\!countA\space to \the\!countB]/[arc length 
    \the \!countA\space to \the\!countC]=\!t.}%
  \ignorespaces}
 
% **  Inverse linear interpolation
\def\!inverselinear{% 
  \!divide\!distacross\!arclength\!dimenG
  \!removept\!dimenG\!t}


% **************************************
% **  ROTATIONS  (Handles rotations) ***
% **************************************
 
% ** User commands
% **   \startrotation [by COS_OF_ANGLE SIN_OF_ANGLE] [about XPIVOT YPIVOT]
% **   \stoprotation

% **   \startrotation [by COS_OF_ANGLE SIN_OF_ANGLE] [about XPIVOT YPIVOT]
% ** Future (XCOORD,YCOORD)'s will be rotated about (XPIVOT,YPIVOT) 
% ** by the angle with the give COS and SIN. Both fields are optional.
% ** [COS,SIN] defaults to previous value, or (1,0).
% ** (XPIVOT,YPIVOT) defaults to previous value, or (0,0)
% ** You can't change the coordinate system in the scope of a rotation.
% ** See Subsection 9.1 of the manual.
\def\startrotation{%
  \let\!rotateaboutpivot=\!!rotateaboutpivot
  \let\!rotateonly=\!!rotateonly
  \!ifnextchar{b}{\!getsincos }%
    {\!getsincos by {\!cosrotationangle} {\!sinrotationangle} }}
\def\!getsincos by #1 #2 {%
  \edef\!cosrotationangle{#1}%
  \edef\!sinrotationangle{#2}%
  \!ifcoordmode 
    \let\!ROnext=\!ccheckforpivot
  \else
    \let\!ROnext=\!dcheckforpivot
  \fi
  \!ROnext}
\def\!ccheckforpivot{%
  \!ifnextchar{a}{\!cgetpivot}%
    {\!cgetpivot about {\!xpivotcoord} {\!ypivotcoord} }}
\def\!cgetpivot about #1 #2 {%
  \edef\!xpivotcoord{#1}%
  \edef\!ypivotcoord{#2}%
  \!xpivot=#1\!xunit  \!ypivot=#2\!yunit
  \ignorespaces}
\def\!dcheckforpivot{%
  \!ifnextchar{a}{\!dgetpivot}{\ignorespaces}}
\def\!dgetpivot about #1 #2 {%
  \!xpivot=#1\relax  \!ypivot=#2\relax
  \ignorespaces}
  

% ** Following terminates rotation.
% ** See Subsection 9.1 of the manual.
\def\stoprotation{%
  \let\!rotateaboutpivot=\!!!rotateaboutpivot
  \let\!rotateonly=\!!!rotateonly
  \ignorespaces}
 
% ** !!rotateaboutpivot{XREG}{YREG}
% ** XREG <-- xpvt + cos(angle)*(XREG-xpvt) - sin(angle)*(YREG-ypvt)
% ** YREG <-- ypvt + cos(angle)*(YREG-ypvt) + sin(angle)*(XREG-xpvt)
% ** XREG,YREG are dimension registers. Can't be \!dimenA to \!dimenD
\def\!!rotateaboutpivot#1#2{%
  \!dimenA=#1\relax  \advance\!dimenA -\!xpivot
  \!dimenB=#2\relax  \advance\!dimenB -\!ypivot
  \!dimenC=\!cosrotationangle\!dimenA
    \advance \!dimenC -\!sinrotationangle\!dimenB
  \!dimenD=\!cosrotationangle\!dimenB
    \advance \!dimenD  \!sinrotationangle\!dimenA
  \advance\!dimenC \!xpivot  \advance\!dimenD \!ypivot
  #1=\!dimenC  #2=\!dimenD
  \ignorespaces}

% ** \!!rotateonly{XREG}{YREG}
% ** Like \!!rotateaboutpivot, but with a pivot of  (0,0)
\def\!!rotateonly#1#2{%
  \!dimenA=#1\relax  \!dimenB=#2\relax 
  \!dimenC=\!cosrotationangle\!dimenA
    \advance \!dimenC -\!rotsign\!sinrotationangle\!dimenB
  \!dimenD=\!cosrotationangle\!dimenB
    \advance \!dimenD  \!rotsign\!sinrotationangle\!dimenA
  #1=\!dimenC  #2=\!dimenD
  \ignorespaces}
\def\!rotsign{}
\def\!!!rotateaboutpivot#1#2{\relax}
\def\!!!rotateonly#1#2{\relax}
\stoprotation

\def\!reverserotateonly#1#2{%
  \def\!rotsign{-}%
  \!rotateonly{#1}{#2}%
  \def\!rotsign{}%
  \ignorespaces}


% **********************************
% *** SHADING  (Handles shading) ***
% **********************************

% **  User commands
% **    \setshadegrid [span <SPAN>] [point at XSHADE YSHADE] 
% **    \setshadesymbol [<LS, RS, BS, TS>] ({SHADESYMBOL}
% **      <XDIMEN,YDIMEN> [ORIENTATION])

% **  Internal commands:
% **    \!startvshade  (xS,ybS,ytS)
% **    \!starthshade  (yS,xlS,xrS)
% **    \!lshade [<LS,RS,BS,TS>]
% **       ** when shading vertically:
% **       [the region from (xS,ybS,ytS) to] (xE,ybE,ytE)
% **       ** when shading horizontally:
% **       [the region from (yS,xlS,xrS) to] (yE,xlE,xrE)
% **    \!qshade [<LS,RS,BS,TS>]
% **       ** when shading vertically:
% **       [the region from (xS,ybS,ytS) to] (xM,ybM,ytM)  (xE,ybE,ytE)
% **       ** when shading horizontally:
% **       [the region from (yS,xlS,xrS) to] (yM,xlM,xrM)  (yE,xlE,xrE)
% **    \!lattice{ANCHOR}{SPAN}{LOCATION}{INDEX}{LATTICE LOCATION}
% **    \!override{NOMINAL DIMEN}{REPLACEMENT DIMEN}{DIMEN}


% **  The shading routine can operate either in a "vertical mode" or a
% **  "horizontal mode".  In vertical mode, the region to be shaded is specified
% **  in the form
% **                 {(x,y): xl <= x <= xr  &  yb(x) <= y <= yt(x)}
% **  where  yb  and  yt  are functions of  x.  In horizontal mode, the region
% **  is specified in the form
% **                 {(x,y): yb <= y <= yt  &  xl(y) <= x <= xr(y)}.
% **  The functions  yb  and  yt  may be either both linear or both quadratic;
% **  similarly for  xl  and  xr.  A region with say, piecewise quadratic bottom
% **  and top boundaries, can be shaded by consecutive (vertical) \!qshades,
% **  proceeding from left to right.  Similarly, a region with piecewise     
% **  quadratic left and right boundaries can be shaded by consecutive
% **  (horizontal) \!qshades, proceeding from bottom to top.  More complex
% **  regions can be shaded by partitioning them into appropriate subregions,
% **  and shading those.
    
% **  Shading is accomplished by placing a user-selected shading symbol at
% **  those points of a regular grid which fall within the region to be
% **  shaded.  This region can be "shrunk" so that a largish shading symbol
% **  will not extend outside it.  Shrinking is accomplished by specifying
% **  shrinkages for the left, right, bottom, and top boundaries, in a manner
% **  discussed further below.

% **  \shades and \!joins MUST NOT be intermingled.  Finish drawing a curve
% **  before starting to shade a region, and finish shading a region before
% **  starting to draw a curve.


% **  \setshadegrid [span <SPAN>] [point at XSHADE YSHADE] 
% **  The shading symbol is placed down on the points of a grid centered
% **  at the coordinate point (XSHADE,YSHADE).  The grid points are of the
% **  form (j*SPAN,k*SPAN), with  j+k  even.  SPAN is specified
% **  as a dimension.
% **  (XSHADE,YSHADE) defaults to previous (XSHADE,YSHADE) (or (0,0) if none)
% **  SPAN defaults to previous span (or 5pt if none)
% **  See Subsection 7.2 of the manual.
\def\setshadegrid{%
  \!ifnextchar{s}{\!getspan }
    {\!getspan span <\!dshade>}}
\def\!getspan span <#1>{%
  \!dshade=#1\relax
  \!ifcoordmode 
    \let\!GRnext=\!GRccheckforAP
  \else
    \let\!GRnext=\!GRdcheckforAP
  \fi
  \!GRnext}
\def\!GRccheckforAP{%
  \!ifnextchar{p}{\!cgetanchor }
    {\!cgetanchor point at {\!xshadesave} {\!yshadesave} }}
\def\!cgetanchor point at #1 #2 {%
  \edef\!xshadesave{#1}\edef\!yshadesave{#2}%
  \!xshade=\!xshadesave\!xunit  \!yshade=\!yshadesave\!yunit
  \ignorespaces}
\def\!GRdcheckforAP{%
  \!ifnextchar{p}{\!dgetanchor}%
    {\ignorespaces}}
\def\!dgetanchor point at #1 #2 {%
  \!xshade=#1\relax  \!yshade=#2\relax
  \ignorespaces}

% **  \setshadesymbol  [<LS, RS, BS, TS>] ({SHADESYMBOL}
% **    <XDIMEN,YDIMEN> [ORIENTATION])
% **  Saves SHADESYMBOL away in an hbox for use with shading routines.
% **  A shade symbol will not be plotted if its plot position comes within
% **    distance LS of the left boundary,  RS of the right boundary,  TS of the
% **    top boundary,  BS of the bottom boundary.  These parameters have 
% **    default values that should work in most cases (see below).
% **    To override a default value, specify the replacement value
% **    in the appropriate subfield of the shrinkages field.
% **    0pt may be coded as  "z" (without the quotes).  To accept a
% **    default value, leave the field empty.  Thus
% **      [,z,,5pt]  sets  LS=default, RS=0pt, BS=default, TS=5pt .
% **    Skipping the shrinkages field accepts all the defaults.
% **  See Subsection 7.1 of the manual.
\def\setshadesymbol{%
  \!ifnextchar<{\!setshadesymbol}{\!setshadesymbol<,,,> }}

\def\!setshadesymbol <#1,#2,#3,#4> (#5#6){%
% **  set the shadesymbol
  \!setputobject{#5}{#6}%                        
  \setbox\!shadesymbol=\box\!putobject%
  \!shadesymbolxshift=\!xshift \!shadesymbolyshift=\!yshift
%
% **  set the shrinkages
  \!dimenA=\!xshift \advance\!dimenA \!smidge% ** default LS = xshift - smidge
  \!override\!dimenA{#1}\!lshrinkage%         
  \!dimenA=\!wd \advance \!dimenA -\!xshift%   ** default RS = width - xshift
    \advance\!dimenA \!smidge%                                  - smidge
    \!override\!dimenA{#2}\!rshrinkage
  \!dimenA=\!dp \advance \!dimenA \!yshift%    ** default BS = depth + yshift
    \advance\!dimenA \!smidge%                                  - smidge
    \!override\!dimenA{#3}\!bshrinkage
  \!dimenA=\!ht \advance \!dimenA -\!yshift%   ** default TS = height - yshift
    \advance\!dimenA \!smidge%                                  - smidge
    \!override\!dimenA{#4}\!tshrinkage
  \ignorespaces}
\def\!smidge{-.2pt}%

% ** \!override{NOMINAL DIMEN}{REPLACEMENT DIMEN}{DIMEN}
% ** Overrides the NOMINAL DIMEN by the REPLACEMENT DIMEN to produce DIMEN,
% ** according to the following rules:
% **   REPLACEMENT DIMEN empty: DIMEN <-- NOMINAL DIMEN
% **   REPLACEMENT DIMEN z:     DIMEN <-- 0pt
% **   otherwise:               DIMEN <-- REPLACEMENT DIMEN
% ** DIMEN must be a dimension register
\def\!override#1#2#3{%
  \edef\!!override{#2}% 
  \ifx \!!override\empty
    #3=#1\relax
  \else
    \if z\!!override
      #3=\!zpt
    \else
      \ifx \!!override\!blankz
        #3=\!zpt
      \else
        #3=#2\relax
      \fi
    \fi
  \fi
  \ignorespaces}
\def\!blankz{ z}

\setshadesymbol ({\fiverm .})%       ** initialize plotsymbol
%                                    ** \fivesy ^^B  is a small cross


% ** \!startvshade [at] (xS,ybS,ytS)
% ** Initiates vertical shading mode
\def\!startvshade#1(#2,#3,#4){%
  \let\!!xunit=\!xunit%
  \let\!!yunit=\!yunit%
  \let\!!xshade=\!xshade%
  \let\!!yshade=\!yshade%
  \def\!getshrinkages{\!vgetshrinkages}%
  \let\!setshadelocation=\!vsetshadelocation%
  \!xS=\!M{#2}\!!xunit
  \!ybS=\!M{#3}\!!yunit
  \!ytS=\!M{#4}\!!yunit
  \!shadexorigin=\!xorigin  \advance \!shadexorigin \!shadesymbolxshift
  \!shadeyorigin=\!yorigin  \advance \!shadeyorigin \!shadesymbolyshift
  \ignorespaces}
 
% ** \!starthshade [at] (yS,xlS,xrS)
% ** Initiates horizontal shading mode
\def\!starthshade#1(#2,#3,#4){%
  \let\!!xunit=\!yunit%
  \let\!!yunit=\!xunit%
  \let\!!xshade=\!yshade%
  \let\!!yshade=\!xshade%
  \def\!getshrinkages{\!hgetshrinkages}%
  \let\!setshadelocation=\!hsetshadelocation%
  \!xS=\!M{#2}\!!xunit
  \!ybS=\!M{#3}\!!yunit
  \!ytS=\!M{#4}\!!yunit
  \!shadexorigin=\!xorigin  \advance \!shadexorigin \!shadesymbolxshift
  \!shadeyorigin=\!yorigin  \advance \!shadeyorigin \!shadesymbolyshift
  \ignorespaces}


% **  \!lattice{ANCHOR}{SPAN}{LOCATION}{INDEX}{LATTICE LOCATION}
% **  Consider the lattice with points  ANCHOR + j*SPAN. This routine determines
% **  the index  k  of the smallest lattice point >= LOCATION, and sets
% **  LATTICE LOCATION = ANCHOR + k*SPAN.
% **  INDEX is assumed to be a count register, LATTICE LOCATION a dimen reg.
\def\!lattice#1#2#3#4#5{%
  \!dimenA=#1%                        ** dimA = ANCHOR
  \!dimenB=#2%                        ** dimB = SPAN  (assumed > 0pt)
  \!countB=\!dimenB%                  ** ctB  = SPAN, as a count
%
% ** Determine index of smallest lattice point >= LOCATION
  \!dimenC=#3%                        ** dimC = LOCATION
  \advance\!dimenC -\!dimenA%         ** now dimC = LOCATION-ANCHOR
  \!countA=\!dimenC%                  ** ctA = above, as a count
  \divide\!countA \!countB%           ** now ctA = desired index, if dimC <= 0
  \ifdim\!dimenC>\!zpt
    \!dimenD=\!countA\!dimenB%        ** (tentative k)*span
    \ifdim\!dimenD<\!dimenC%          ** if this is false, ctA = desired index
      \advance\!countA 1 %            ** if true, have to add 1
    \fi
  \fi
%
  \!dimenC=\!countA\!dimenB%          ** lattice location = anchor + ctA*span
    \advance\!dimenC \!dimenA
  #4=\!countA%                        ** the desired index
  #5=\!dimenC%                        ** corresponding lattice location
  \ignorespaces}


% ** \!qshade [with shrinkages] [[LS,RS,BS,TS]]
% ***** during vertical shading:
% **    [the region from (xS,ybS,ytS) to] (xM,ybM,ytM) [and] (xE,ybE,ytE)
% ** Shades the region {(x,y): xS <= x <= xE, yb(x) <= y <= yt(x)}, where 
% **   yb is the quadratic thru (xS,ybS) & (xM,ybM) & (xE,ybE)
% **   yt is the quadratic thru (xS,ytS) & (xM,ybM) & (xE,ytE)
% ** xS,ybS,ytS are either given by \!startvshade or carried over
% **   as the ending values of the immediately preceding \!qshade.
% ** For the interpretation of LS, RS, BS, & TS, see \setshadesymbol. The
% **   values set there can be overridden, for the course of this \!qshade
% **   only, in the same manner as overrides are specified for
% **   \setshadesymbol.
% ***** during horizontal shading:
% **    [the region from (yS,xlS,xrS) to] (yM,xlM,xrM) [and] (yE,xlE,xrE)
\def\!qshade#1(#2,#3,#4)#5(#6,#7,#8){%
  \!xM=\!M{#2}\!!xunit
  \!ybM=\!M{#3}\!!yunit
  \!ytM=\!M{#4}\!!yunit
  \!xE=\!M{#6}\!!xunit
  \!ybE=\!M{#7}\!!yunit
  \!ytE=\!M{#8}\!!yunit
  \!getcoeffs\!xS\!ybS\!xM\!ybM\!xE\!ybE\!ybB\!ybC%**Get coefficients B & C for
  \!getcoeffs\!xS\!ytS\!xM\!ytM\!xE\!ytE\!ytB\!ytC%**y=y0 + B(x-X0) + C(x-X0)**2
  \def\!getylimits{\!qgetylimits}%
  \!shade{#1}\ignorespaces}
 
% ** \!lshade ... (xE,ybE,ytE)
% ** This is like \!qshade, but the top and bottom boundaries are linear,
% ** rather than quadratic.
\def\!lshade#1(#2,#3,#4){%
  \!xE=\!M{#2}\!!xunit
  \!ybE=\!M{#3}\!!yunit
  \!ytE=\!M{#4}\!!yunit
  \!dimenE=\!xE  \advance \!dimenE -\!xS%   ** xE-xS
  \!dimenC=\!ytE \advance \!dimenC -\!ytS%  ** ytE-ytS
  \!divide\!dimenC\!dimenE\!ytB%            ** ytB = (ytE-ytS)/(xE-xS)
  \!dimenC=\!ybE \advance \!dimenC -\!ybS%  ** ybE-ybS
  \!divide\!dimenC\!dimenE\!ybB%            ** ybB = (ybE-ybS)/(xE-xS)
  \def\!getylimits{\!lgetylimits}%
  \!shade{#1}\ignorespaces}
 
% **  \!getcoeffs{X0}{Y0}{X1}{Y1}{X2}{Y2}{B}{C}
% **  Finds  B  and  C  such that the quadratic  y = Y0 + B(x-X0) + C(x-X0)**2
% **  passes through (X1,Y1) and (X2,Y2):  when X0=0=Y0, the formulas are:
% **                   B = S1 - X1*C,   C = (S2-S1)/X2
% **  with
% **                 S1 = Y1/X1,   S2 = (Y2-Y1)/(X2-X1).
\def\!getcoeffs#1#2#3#4#5#6#7#8{% 
  \!dimenC=#4\advance \!dimenC -#2%            ** dimC=Y1-Y0
  \!dimenE=#3\advance \!dimenE -#1%            ** dimE=X1-X0
  \!divide\!dimenC\!dimenE\!dimenF%            ** dimF=S1
  \!dimenC=#6\advance \!dimenC -#4%            ** dimC=Y2-Y1
  \!dimenH=#5\advance \!dimenH -#3%            ** dimH=X2-X1
  \!divide\!dimenC\!dimenH\!dimenG%            ** dimG=S2
  \advance\!dimenG -\!dimenF%                  ** dimG=S2-S1
  \advance \!dimenH \!dimenE%                  ** dimH=X2-X0
  \!divide\!dimenG\!dimenH#8%                  ** C=(S2-S1)/(X2-X0)
  \!removept#8\!t%                             ** C, without "pt"
  #7=-\!t\!dimenE%                             ** -C*(X1-X0)
  \advance #7\!dimenF%                         ** B=S1-C*(X1-X0)
  \ignorespaces}
 
 
\def\!shade#1{%
% ** Get LS,RS,BS,TS for this panel
  \!getshrinkages#1<,,,>\!nil% %       ** now effective LS=dimE, RS=dimF,
%                                      **   BS=dimG, TS=dimH
  \advance \!dimenE \!xS%              ** now dimE=xS+LS
  \!lattice\!!xshade\!dshade\!dimenE%  ** set parity=index of left-mst x-lattice
    \!parity\!xpos%                    **   point >= xS+LS, xpos=its location
  \!dimenF=-\!dimenF%                  ** set dimF=xE-RS
    \advance\!dimenF \!xE
%               
  \!loop\!not{\ifdim\!xpos>\!dimenF}%  ** loop over x-lattice points <= xE-RS
    \!shadecolumn%                 
    \advance\!xpos \!dshade%           ** move over to next column
    \advance\!parity 1%                ** increase index of x-point
  \repeat
%
  \!xS=\!xE%                           ** shift ending values to starting values
  \!ybS=\!ybE
  \!ytS=\!ytE
  \ignorespaces}
 
 
\def\!vgetshrinkages#1<#2,#3,#4,#5>#6\!nil{%
  \!override\!lshrinkage{#2}\!dimenE
  \!override\!rshrinkage{#3}\!dimenF
  \!override\!bshrinkage{#4}\!dimenG
  \!override\!tshrinkage{#5}\!dimenH
  \ignorespaces}
\def\!hgetshrinkages#1<#2,#3,#4,#5>#6\!nil{%
  \!override\!lshrinkage{#2}\!dimenG
  \!override\!rshrinkage{#3}\!dimenH
  \!override\!bshrinkage{#4}\!dimenE
  \!override\!tshrinkage{#5}\!dimenF
  \ignorespaces}
 
 
\def\!shadecolumn{%
  \!dxpos=\!xpos
  \advance\!dxpos -\!xS%            ** dx = x - xS
  \!removept\!dxpos\!dx%            ** ditto, without "pt"
  \!getylimits%                     ** get top and bottom y-values
  \advance\!ytpos -\!dimenH%        ** less TS
  \advance\!ybpos \!dimenG%         ** plus BS
  \!yloc=\!!yshade%                 ** get anchor point for this column
  \ifodd\!parity 
     \advance\!yloc \!dshade
  \fi
  \!lattice\!yloc{2\!dshade}\!ybpos%
    \!countA\!ypos%                 ** ypos=smallest y point for this column
  \!dimenA=-\!shadexorigin \advance \!dimenA \!xpos%      ** over
  \loop\!not{\ifdim\!ypos>\!ytpos}% ** loop over ypos <= yt(t)
    \!setshadelocation%             ** vmode: xloc=xpos, yloc=ypos 
%                                   ** hmode: xloc=ypos, yloc=xpos 
    \!rotateaboutpivot\!xloc\!yloc%
    \!dimenA=-\!shadexorigin \advance \!dimenA \!xloc%    ** over
    \!dimenB=-\!shadeyorigin \advance \!dimenB \!yloc%    ** up
    \kern\!dimenA \raise\!dimenB\copy\!shadesymbol \kern-\!dimenA
    \advance\!ypos 2\!dshade
  \repeat
  \ignorespaces}
 
\def\!qgetylimits{%
  \!dimenA=\!dx\!ytC              
  \advance\!dimenA \!ytB%         ** yt(t)=ytS + dx*(Bt + dx*Ct)
  \!ytpos=\!dx\!dimenA
  \advance\!ytpos \!ytS
  \!dimenA=\!dx\!ybC              
  \advance\!dimenA \!ybB%         ** yb(t)=ybS + dx*(Bb + dx*Cb)
  \!ybpos=\!dx\!dimenA
  \advance\!ybpos \!ybS}
 
\def\!lgetylimits{%
  \!ytpos=\!dx\!ytB%              ** yt(t)=ytS + dx*Bt
  \advance\!ytpos \!ytS
  \!ybpos=\!dx\!ybB%              ** yb(t)=ybS + dx*Bb
  \advance\!ybpos \!ybS}
 
\def\!vsetshadelocation{%         ** vmode: xloc=xpos, yloc=ypos 
  \!xloc=\!xpos
  \!yloc=\!ypos}
\def\!hsetshadelocation{%         ** hmode: xloc=ypos, yloc=xpos 
  \!xloc=\!ypos
  \!yloc=\!xpos}


% **************************************
% *** TICKS  (Draws ticks on graphs) ***
% **************************************

% ** User commands
% **   \ticksout
% **   \ticksin
% **   \gridlines
% **   \nogridlines
% **   \loggedticks
% **   \unloggesticks
% ** See Subsection 3.4 of the manual

% ** The following is an option of the \axis command
% **   ticks 
% **     [in] [out] 
% **     [long] [short] [length <LENGTH>] 
% **     [width <WIDTH>]
% **     [andacross] [butnotacross] 
% **     [logged] [unlogged] 
% **     [unlabeled] [numbered] [withvalues VALUE1 VALUE2 ... VALUEk / ]
% **     [quantity Q] [at LOC1 LOC2 ... LOCk / ] [from LOC1 to LOC2 by
% **       LOC_INCREMENT]
% ** See Subsection 3.2 of the manual for the rules.

% ** The various options of the  tick  field are processed by the
% ** \!nextkeyword  command defined below.
% ** For example, `\!nextkeyword short '  expands to  `\!ticksshort',
% ** while `\!nextkeyword withvalues' expands to `\!tickswithvalues'.

\def\!axisticks {%
  \def\!nextkeyword##1 {%
    \expandafter\ifx\csname !ticks##1\endcsname \relax
      \def\!next{\!fixkeyword{##1}}%
    \else
      \def\!next{\csname !ticks##1\endcsname}%
    \fi
    \!next}%
  \!axissetup
    \def\!axissetup{\relax}%
  \edef\!ticksinoutsign{\!ticksinoutSign}%
  \!ticklength=\longticklength
  \!tickwidth=\linethickness
  \!gridlinestatus
  \!setticktransform
  \!maketick
  \!tickcase=0
  \def\!LTlist{}%
  \!nextkeyword}

\def\ticksout{%
  \def\!ticksinoutSign{+}}
\def\ticksin{%
  \def\!ticksinoutSign{-}}
\ticksout

\def\gridlines{%
  \def\!gridlinestatus{\!gridlinestootrue}}
\def\nogridlines{%
  \def\!gridlinestatus{\!gridlinestoofalse}}
\nogridlines

\def\loggedticks{%
  \def\!setticktransform{\let\!ticktransform=\!logten}}
\def\unloggedticks{%
  \def\!setticktransform{\let\!ticktransform=\!donothing}}
\def\!donothing#1#2{\def#2{#1}}
\unloggedticks

% ** \!ticks/ : terminates read of tick options
\expandafter\def\csname !ticks/\endcsname{%
  \!not {\ifx \!LTlist\empty}
    \!placetickvalues
  \fi
  \def\!tickvalueslist{}%
  \def\!LTlist{}%
  \expandafter\csname !axis/\endcsname}

\def\!maketick{%
  \setbox\!boxA=\hbox{%
    \beginpicture
      \!setdimenmode
      \setcoordinatesystem point at {\!zpt} {\!zpt}   
      \linethickness=\!tickwidth
      \ifdim\!ticklength>\!zpt
        \putrule from {\!zpt} {\!zpt} to
          {\!ticksinoutsign\!tickxsign\!ticklength}
          {\!ticksinoutsign\!tickysign\!ticklength}
      \fi
      \if!gridlinestoo
        \putrule from {\!zpt} {\!zpt} to
          {-\!tickxsign\!xaxislength} {-\!tickysign\!yaxislength}
      \fi
    \endpicturesave <\!Xsave,\!Ysave>}%
    \wd\!boxA=\!zpt}
  
\def\!ticksin{%
  \def\!ticksinoutsign{-}%
  \!maketick
  \!nextkeyword}

\def\!ticksout{%
  \def\!ticksinoutsign{+}%
  \!maketick
  \!nextkeyword}

\def\!tickslength<#1> {%
  \!ticklength=#1\relax
  \!maketick
  \!nextkeyword}

\def\!tickslong{%
  \!tickslength<\longticklength> }

\def\!ticksshort{%
  \!tickslength<\shortticklength> }

\def\!tickswidth<#1> {%
  \!tickwidth=#1\relax
  \!maketick
  \!nextkeyword}

\def\!ticksandacross{%
  \!gridlinestootrue
  \!maketick
  \!nextkeyword}

\def\!ticksbutnotacross{%
  \!gridlinestoofalse
  \!maketick
  \!nextkeyword}

\def\!tickslogged{%
  \let\!ticktransform=\!logten
  \!nextkeyword}

\def\!ticksunlogged{%
  \let\!ticktransform=\!donothing
  \!nextkeyword}

\def\!ticksunlabeled{%
  \!tickcase=0
  \!nextkeyword}

\def\!ticksnumbered{%
  \!tickcase=1
  \!nextkeyword}

\def\!tickswithvalues#1/ {%
  \edef\!tickvalueslist{#1! /}%
  \!tickcase=2
  \!nextkeyword}

\def\!ticksquantity#1 {%
  \ifnum #1>1
    \!updatetickoffset
    \!countA=#1\relax
    \advance \!countA -1
    \!ticklocationincr=\!axisLength
      \divide \!ticklocationincr \!countA
    \!ticklocation=\!axisstart
    \loop \!not{\ifdim \!ticklocation>\!axisend}
      \!placetick\!ticklocation
      \ifcase\!tickcase
          \relax %  Case 0: no labels
        \or
          \relax %  Case 1: numbered -- not available here
        \or
          \expandafter\!gettickvaluefrom\!tickvalueslist
          \edef\!tickfield{{\the\!ticklocation}{\!value}}%
          \expandafter\!listaddon\expandafter{\!tickfield}\!LTlist%
      \fi
      \advance \!ticklocation \!ticklocationincr
    \repeat
  \fi
  \!nextkeyword}

\def\!ticksat#1 {%
  \!updatetickoffset
  \edef\!Loc{#1}%
  \if /\!Loc
    \def\next{\!nextkeyword}%
  \else
    \!ticksincommon
    \def\next{\!ticksat}%
  \fi
  \next}    
      
\def\!ticksfrom#1 to #2 by #3 {%
  \!updatetickoffset
  \edef\!arg{#3}%
  \expandafter\!separate\!arg\!nil
  \!scalefactor=1
  \expandafter\!countfigures\!arg/
  \edef\!arg{#1}%
  \!scaleup\!arg by\!scalefactor to\!countE
  \edef\!arg{#2}%
  \!scaleup\!arg by\!scalefactor to\!countF
  \edef\!arg{#3}%
  \!scaleup\!arg by\!scalefactor to\!countG
  \loop \!not{\ifnum\!countE>\!countF}
    \ifnum\!scalefactor=1
      \edef\!Loc{\the\!countE}%
    \else
      \!scaledown\!countE by\!scalefactor to\!Loc
    \fi
    \!ticksincommon
    \advance \!countE \!countG
  \repeat
  \!nextkeyword}

\def\!updatetickoffset{%
  \!dimenA=\!ticksinoutsign\!ticklength
  \ifdim \!dimenA>\!offset
    \!offset=\!dimenA
  \fi}

\def\!placetick#1{%
  \if!xswitch
    \!xpos=#1\relax
    \!ypos=\!axisylevel
  \else
    \!xpos=\!axisxlevel
    \!ypos=#1\relax
  \fi
  \advance\!xpos \!Xsave
  \advance\!ypos \!Ysave
  \kern\!xpos\raise\!ypos\copy\!boxA\kern-\!xpos
  \ignorespaces}

\def\!gettickvaluefrom#1 #2 /{%
  \edef\!value{#1}%
  \edef\!tickvalueslist{#2 /}%
  \ifx \!tickvalueslist\!endtickvaluelist
    \!tickcase=0
  \fi}
\def\!endtickvaluelist{! /}

\def\!ticksincommon{%
  \!ticktransform\!Loc\!t
  \!ticklocation=\!t\!!unit
  \advance\!ticklocation -\!!origin
  \!placetick\!ticklocation
  \ifcase\!tickcase
    \relax % Case 0: no labels
  \or %      Case 1: numbered
    \ifdim\!ticklocation<-\!!origin
      \edef\!Loc{$\!Loc$}%
    \fi
    \edef\!tickfield{{\the\!ticklocation}{\!Loc}}%
    \expandafter\!listaddon\expandafter{\!tickfield}\!LTlist%
  \or %      Case 2: labeled
    \expandafter\!gettickvaluefrom\!tickvalueslist
    \edef\!tickfield{{\the\!ticklocation}{\!value}}%
    \expandafter\!listaddon\expandafter{\!tickfield}\!LTlist%
  \fi}

\def\!separate#1\!nil{%
  \!ifnextchar{-}{\!!separate}{\!!!separate}#1\!nil}
\def\!!separate-#1\!nil{%
  \def\!sign{-}%
  \!!!!separate#1..\!nil}
\def\!!!separate#1\!nil{%
  \def\!sign{+}%
  \!!!!separate#1..\!nil}
\def\!!!!separate#1.#2.#3\!nil{%
  \def\!arg{#1}%
  \ifx\!arg\!empty
    \!countA=0
  \else
    \!countA=\!arg

  \fi
  \def\!arg{#2}%
  \ifx\!arg\!empty
    \!countB=0
  \else
    \!countB=\!arg
  \fi}
 
\def\!countfigures#1{%
  \if #1/%
    \def\!next{\ignorespaces}%
  \else
    \multiply\!scalefactor 10
    \def\!next{\!countfigures}%
  \fi
  \!next}

\def\!scaleup#1by#2to#3{%
  \expandafter\!separate#1\!nil
  \multiply\!countA #2\relax
  \advance\!countA \!countB
  \if -\!sign
    \!countA=-\!countA
  \fi
  #3=\!countA
  \ignorespaces}

\def\!scaledown#1by#2to#3{%
  \!countA=#1\relax%                          ** get original #
  \ifnum \!countA<0 %                         ** take abs value,
    \def\!sign{-}%                            **   remember sign
    \!countA=-\!countA
  \else
    \def\!sign{}%
  \fi
  \!countB=\!countA%                          ** copy |#|
  \divide\!countB #2\relax%                   ** integer part (|#|/sf)
  \!countC=\!countB%                          ** get sf * (|#|/sf)
    \multiply\!countC #2\relax
  \advance \!countA -\!countC%                ** ctA is now remainder
  \edef#3{\!sign\the\!countB.}%               ** +- integerpart.
  \!countC=\!countA %                         ** Tack on proper number
  \ifnum\!countC=0 %                          **   of zeros after .
    \!countC=1
  \fi
  \multiply\!countC 10
  \!loop \ifnum #2>\!countC
    \edef#3{#3\!zero}%
    \multiply\!countC 10
  \repeat
  \edef#3{#3\the\!countA}%                    ** Add on rest of remainder
  \ignorespaces}

\def\!placetickvalues{%
  \advance\!offset \tickstovaluesleading
  \if!xswitch
    \setbox\!boxA=\hbox{%
      \def\\##1##2{%
        \!dimenput {##2} [B] (##1,\!axisylevel)}%
      \beginpicture 
        \!LTlist
      \endpicturesave <\!Xsave,\!Ysave>}%
    \!dimenA=\!axisylevel
      \advance\!dimenA -\!Ysave
      \advance\!dimenA \!tickysign\!offset
      \if -\!tickysign
        \advance\!dimenA -\ht\!boxA
      \else
        \advance\!dimenA  \dp\!boxA
      \fi
    \advance\!offset \ht\!boxA 
      \advance\!offset \dp\!boxA
    \!dimenput {\box\!boxA} [Bl] <\!Xsave,\!Ysave> (\!zpt,\!dimenA)
  \else
    \setbox\!boxA=\hbox{%
      \def\\##1##2{%
        \!dimenput {##2} [r] (\!axisxlevel,##1)}%
      \beginpicture 
        \!LTlist
      \endpicturesave <\!Xsave,\!Ysave>}%
    \!dimenA=\!axisxlevel
      \advance\!dimenA -\!Xsave
      \advance\!dimenA \!tickxsign\!offset
      \if -\!tickxsign
        \advance\!dimenA -\wd\!boxA
      \fi
    \advance\!offset \wd\!boxA
    \!dimenput {\box\!boxA} [Bl] <\!Xsave,\!Ysave> (\!dimenA,\!zpt)
  \fi}


\normalgraphs
\catcode`!=12 %  *****  THIS MUST NEVER BE OMITTED




postpictex.tex


% This is postpictex.tex  Version 1.1  9/10/87

% To use the PiCTeX macros under LaTeX, you first need to \input the
% file prepictex.tex, then the main corpus of PiCTeX macros (pictex.tex), 
% and finally this file.  Do not \input the file latexpicobjs.tex.
 
\catcode`@=11 \catcode`!=11
  
% Save meanings of PiCTeX keywords that duplicate LaTeX keywords
\let\!pictexendpicture=\endpicture 
\let\!pictexframe=\frame
\let\!pictexlinethickness=\linethickness
\let\!pictexmultiput=\multiput
\let\!pictexput=\put

% Redefine the PiCTeX \beginpicture macro
\def\beginpicture{%
  \setbox\!picbox=\hbox\bgroup%
  \let\endpicture=\!pictexendpicture
  \let\frame=\!pictexframe
  \let\linethickness=\!pictexlinethickness
  \let\multiput=\!pictexmultiput
  \let\put=\!pictexput
  \let\input=\@@input   % \@@input is LaTeX's saved version of TeX's primitive
  \!xleft=\maxdimen  
  \!xright=-\maxdimen
  \!ybot=\maxdimen
  \!ytop=-\maxdimen}

% Reestablish LaTeX's meaning of \frame. This makes
% PiCTeX's meaning of \frame available only inside a PiCture.
\let\frame=\!latexframe

% Make PiCTeX's meaning of \frame available everywhere in the
% guise of \pictexframe
\let\pictexframe=\!pictexframe

% Now do the same for \linethickness
\let\linethickness=\!latexlinethickness
\let\pictexlinethickness=\!pictexlinethickness

% Reset LaTeX's default meaning of \\
\let\\=\@normalcr
\catcode`@=12 \catcode`!=12



\begingroup\makeatletter
% extract first six characters in \fmtname
\def\x#1#2#3#4#5#6#7\relax{\def\x{#1#2#3#4#5#6}}
\expandafter\x\fmtname xxxxxx\relax \def\y{splain}
\ifx\x\y   % LaTeX or SliTeX?
\gdef\SetFigFont#1#2#3{%
  \ifnum #1<17 \tiny\else \ifnum #1<20 \small\else
  \ifnum #1<24 \normalsize\else \ifnum #1<29 \large\else
  \ifnum #1<34 \Large\else \ifnum #1<41 \LARGE\else
     \huge\fi\fi\fi\fi\fi\fi
  \csname #3\endcsname}
\else
\gdef\SetFigFont#1#2#3{\begingroup
  \count@#1\relax \ifnum 25<\count@ \count@25 \fi
  \def\x{\endgroup\@setsize\SetFigFont{#2pt}}%
  \expandafter\x
    \csname \romannumeral\the\count@ pt\expandafter\endcsname
    \csname @\romannumeral\the\count@ pt\endcsname
  \csname #3\endcsname}
\fi
\endgroup




prepictex.tex

% This is prepictex.tex  Version 1.1  9/10/87

% To use the PiCTeX macros under LaTeX, you first need to \input this
% file, then the main corpus of PiCTeX macros (pictex.tex), and then
% the file postpictex.tex. Do not \input the file latexpicobjs.tex.

\font\fiverm=cmr5 % Harmless addition for compatibility with new LaTeX fontsel
% Added 27-Aug-1990 Don Hosek dhosek@ymir.claremont.edu
\catcode`@=11 \catcode`!=11

\@ifundefined{normalshape}{%
     \def\pdollar{{\ifdim \fontdimen\@ne\font >\z@ \sl \fi\char36}}}{%
        \def\pdollar{\text{\ifdim \fontdimen\@ne\font >\z@
              \sl \else \normalshape \fi\char36}}}
% Added 2-Oct-1990 Don Hosek at suggestion of Eberhard Mattes to allow
% use of \$ inside a PiCTeX PiCture.

% First of all, see if  \fiverm  is defined. If so do nothing;
% if not, let  \fiverm  take on meaning of LaTeX's  \fivrm.
\expandafter\ifx\csname fiverm\endcsname\relax
  \let\fiverm\fivrm
\fi
  
% Save meanings of LaTeX keywords that duplicate PiCTeX keywords
\let\!latexendpicture=\endpicture 
\let\!latexframe=\frame
\let\!latexlinethickness=\linethickness
\let\!latexmultiput=\multiput
\let\!latexput=\put
 
% Redefine the LaTeX \@picture macro
\def\@picture(#1,#2)(#3,#4){%
  \@picht #2\unitlength
  \setbox\@picbox\hbox to #1\unitlength\bgroup 
  \let\endpicture=\!latexendpicture
  \let\frame=\!latexframe
  \let\linethickness=\!latexlinethickness
  \let\multiput=\!latexmultiput
  \let\put=\!latexput
  \hskip -#3\unitlength \lower #4\unitlength \hbox\bgroup}

\catcode`@=12 \catcode`!=12

psfig.tex
% Psfig/TeX 
\def\PsfigVersion{1.9}
% dvips version
%
% All psfig/tex software, documentation, and related files
% in this distribution of psfig/tex are 
% Copyright 1987, 1988, 1991 Trevor J. Darrell
%
% Permission is granted for use and non-profit distribution of psfig/tex 
% providing that this notice is clearly maintained. The right to
% distribute any portion of psfig/tex for profit or as part of any commercial
% product is specifically reserved for the author(s) of that portion.
%
% *** Feel free to make local modifications of psfig as you wish,
% *** but DO NOT post any changed or modified versions of ``psfig''
% *** directly to the net. Send them to me and I'll try to incorporate
% *** them into future versions. If you want to take the psfig code 
% *** and make a new program (subject to the copyright above), distribute it, 
% *** (and maintain it) that's fine, just don't call it psfig.
%
% Bugs and improvements to trevor@media.mit.edu.
%
% Thanks to Greg Hager (GDH) and Ned Batchelder for their contributions
% to the original version of this project.
%
% Modified by J. Daniel Smith on 9 October 1990 to accept the
% %%BoundingBox: comment with or without a space after the colon.  Stole
% file reading code from Tom Rokicki's EPSF.TEX file (see below).
%
% More modifications by J. Daniel Smith on 29 March 1991 to allow the
% the included PostScript figure to be rotated.  The amount of
% rotation is specified by the "angle=" parameter of the \psfig command.
%
% Modified by Robert Russell on June 25, 1991 to allow users to specify
% .ps filenames which don't yet exist, provided they explicitly provide
% boundingbox information via the \psfig command. Note: This will only work
% if the "file=" parameter follows all four "bb???=" parameters in the
% command. This is due to the order in which psfig interprets these params.
%
%  3 Jul 1991	JDS	check if file already read in once
%  4 Sep 1991	JDS	fixed incorrect computation of rotated
%			bounding box
% 25 Sep 1991	GVR	expanded synopsis of \psfig
% 14 Oct 1991	JDS	\fbox code from LaTeX so \psdraft works with TeX
%			changed \typeout to \ps@typeout
% 17 Oct 1991	JDS	added \psscalefirst and \psrotatefirst
%

% From: gvr@cs.brown.edu (George V. Reilly)
%
% \psdraft	draws an outline box, but doesn't include the figure
%		in the DVI file.  Useful for previewing.
%
% \psfull	includes the figure in the DVI file (default).
%
% \psscalefirst width= or height= specifies the size of the figure
% 		before rotation.
% \psrotatefirst (default) width= or height= specifies the size of the
% 		 figure after rotation.  Asymetric figures will
% 		 appear to shrink.
%
% \psfigurepath#1	sets the path to search for the figure
%
% \psfig
% usage: \psfig{file=, figure=, height=, width=,
%			bbllx=, bblly=, bburx=, bbury=,
%			rheight=, rwidth=, clip=, angle=, silent=}
%
%	"file" is the filename.  If no path name is specified and the
%		file is not found in the current directory,
%		it will be looked for in directory \psfigurepath.
%	"figure" is a synonym for "file".
%	By default, the width and height of the figure are taken from
%		the BoundingBox of the figure.
%	If "width" is specified, the figure is scaled so that it has
%		the specified width.  Its height changes proportionately.
%	If "height" is specified, the figure is scaled so that it has
%		the specified height.  Its width changes proportionately.
%	If both "width" and "height" are specified, the figure is scaled
%		anamorphically.
%	"bbllx", "bblly", "bburx", and "bbury" control the PostScript
%		BoundingBox.  If these four values are specified
%               *before* the "file" option, the PSFIG will not try to
%               open the PostScript file.
%	"rheight" and "rwidth" are the reserved height and width
%		of the figure, i.e., how big TeX actually thinks
%		the figure is.  They default to "width" and "height".
%	The "clip" option ensures that no portion of the figure will
%		appear outside its BoundingBox.  "clip=" is a switch and
%		takes no value, but the `=' must be present.
%	The "angle" option specifies the angle of rotation (degrees, ccw).
%	The "silent" option makes \psfig work silently.
%

% check to see if macros already loaded in (maybe some other file says
% "\input psfig") ...
\ifx\undefined\psfig\else\endinput\fi

%
% from a suggestion by eijkhout@csrd.uiuc.edu to allow
% loading as a style file. Changed to avoid problems
% with amstex per suggestion by jbence@math.ucla.edu

\let\LaTeXAtSign=\@
\let\@=\relax
\edef\psfigRestoreAt{\catcode`\@=\number\catcode`@\relax}
%\edef\psfigRestoreAt{\catcode`@=\number\catcode`@\relax}
\catcode`\@=11\relax
\newwrite\@unused
\def\ps@typeout#1{{\let\protect\string\immediate\write\@unused{#1}}}
\ps@typeout{psfig/tex \PsfigVersion}

%% Here's how you define your figure path.  Should be set up with null
%% default and a user useable definition.

\def\figurepath{./}
\def\psfigurepath#1{\edef\figurepath{#1}}

%
% @psdo control structure -- similar to Latex @for.
% I redefined these with different names so that psfig can
% be used with TeX as well as LaTeX, and so that it will not 
% be vunerable to future changes in LaTeX's internal
% control structure,
%
\def\@nnil{\@nil}
\def\@empty{}
\def\@psdonoop#1\@@#2#3{}
\def\@psdo#1:=#2\do#3{\edef\@psdotmp{#2}\ifx\@psdotmp\@empty \else
    \expandafter\@psdoloop#2,\@nil,\@nil\@@#1{#3}\fi}
\def\@psdoloop#1,#2,#3\@@#4#5{\def#4{#1}\ifx #4\@nnil \else
       #5\def#4{#2}\ifx #4\@nnil \else#5\@ipsdoloop #3\@@#4{#5}\fi\fi}
\def\@ipsdoloop#1,#2\@@#3#4{\def#3{#1}\ifx #3\@nnil 
       \let\@nextwhile=\@psdonoop \else
      #4\relax\let\@nextwhile=\@ipsdoloop\fi\@nextwhile#2\@@#3{#4}}
\def\@tpsdo#1:=#2\do#3{\xdef\@psdotmp{#2}\ifx\@psdotmp\@empty \else
    \@tpsdoloop#2\@nil\@nil\@@#1{#3}\fi}
\def\@tpsdoloop#1#2\@@#3#4{\def#3{#1}\ifx #3\@nnil 
       \let\@nextwhile=\@psdonoop \else
      #4\relax\let\@nextwhile=\@tpsdoloop\fi\@nextwhile#2\@@#3{#4}}
% 
% \fbox is defined in latex.tex; so if \fbox is undefined, assume that
% we are not in LaTeX.
% Perhaps this could be done better???
\ifx\undefined\fbox
% \fbox code from modified slightly from LaTeX
\newdimen\fboxrule
\newdimen\fboxsep
\newdimen\ps@tempdima
\newbox\ps@tempboxa
\fboxsep = 3pt
\fboxrule = .4pt
\long\def\fbox#1{\leavevmode\setbox\ps@tempboxa\hbox{#1}\ps@tempdima\fboxrule
    \advance\ps@tempdima \fboxsep \advance\ps@tempdima \dp\ps@tempboxa
   \hbox{\lower \ps@tempdima\hbox
  {\vbox{\hrule height \fboxrule
          \hbox{\vrule width \fboxrule \hskip\fboxsep
          \vbox{\vskip\fboxsep \box\ps@tempboxa\vskip\fboxsep}\hskip 
                 \fboxsep\vrule width \fboxrule}
                 \hrule height \fboxrule}}}}
\fi
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% file reading stuff from epsf.tex
%   EPSF.TEX macro file:
%   Written by Tomas Rokicki of Radical Eye Software, 29 Mar 1989.
%   Revised by Don Knuth, 3 Jan 1990.
%   Revised by Tomas Rokicki to accept bounding boxes with no
%      space after the colon, 18 Jul 1990.
%   Portions modified/removed for use in PSFIG package by
%      J. Daniel Smith, 9 October 1990.
%
\newread\ps@stream
\newif\ifnot@eof       % continue looking for the bounding box?
\newif\if@noisy        % report what you're making?
\newif\if@atend        % %%BoundingBox: has (at end) specification
\newif\if@psfile       % does this look like a PostScript file?
%
% PostScript files should start with `%!'
%
{\catcode`\%=12\global\gdef\epsf@start{%!}}
\def\epsf@PS{PS}
%
\def\epsf@getbb#1{%
%
%   The first thing we need to do is to open the
%   PostScript file, if possible.
%
\openin\ps@stream=#1
\ifeof\ps@stream\ps@typeout{Error, File #1 not found}\else
%
%   Okay, we got it. Now we'll scan lines until we find one that doesn't
%   start with %. We're looking for the bounding box comment.
%
   {\not@eoftrue \chardef\other=12
    \def\do##1{\catcode`##1=\other}\dospecials \catcode`\ =10
    \loop
       \if@psfile
	  \read\ps@stream to \epsf@fileline
       \else{
	  \obeyspaces
          \read\ps@stream to \epsf@tmp\global\let\epsf@fileline\epsf@tmp}
       \fi
       \ifeof\ps@stream\not@eoffalse\else
%
%   Check the first line for `%!'.  Issue a warning message if its not
%   there, since the file might not be a PostScript file.
%
       \if@psfile\else
       \expandafter\epsf@test\epsf@fileline:. \\%
       \fi
%
%   We check to see if the first character is a % sign;
%   if so, we look further and stop only if the line begins with
%   `%%BoundingBox:' and the `(atend)' specification was not found.
%   That is, the only way to stop is when the end of file is reached,
%   or a `%%BoundingBox: llx lly urx ury' line is found.
%
          \expandafter\epsf@aux\epsf@fileline:. \\%
       \fi
   \ifnot@eof\repeat
   }\closein\ps@stream\fi}%
%
% This tests if the file we are reading looks like a PostScript file.
%
\long\def\epsf@test#1#2#3:#4\\{\def\epsf@testit{#1#2}
			\ifx\epsf@testit\epsf@start\else
\ps@typeout{Warning! File does not start with `\epsf@start'.  It may not be a PostScript file.}
			\fi
			\@psfiletrue} % don't test after 1st line
%
%   We still need to define the tricky \epsf@aux macro. This requires
%   a couple of magic constants for comparison purposes.
%
{\catcode`\%=12\global\let\epsf@percent=%\global\def\epsf@bblit{%BoundingBox}}
%
%
%   So we're ready to check for `%BoundingBox:' and to grab the
%   values if they are found.  We continue searching if `(at end)'
%   was found after the `%BoundingBox:'.
%
\long\def\epsf@aux#1#2:#3\\{\ifx#1\epsf@percent
   \def\epsf@testit{#2}\ifx\epsf@testit\epsf@bblit
	\@atendfalse
        \epsf@atend #3 . \\%
	\if@atend	
	   \if@verbose{
		\ps@typeout{psfig: found `(atend)'; continuing search}
	   }\fi
        \else
        \epsf@grab #3 . . . \\%
        \not@eoffalse
        \global\no@bbfalse
        \fi
   \fi\fi}%
%
%   Here we grab the values and stuff them in the appropriate definitions.
%
\def\epsf@grab #1 #2 #3 #4 #5\\{%
   \global\def\epsf@llx{#1}\ifx\epsf@llx\empty
      \epsf@grab #2 #3 #4 #5 .\\\else
   \global\def\epsf@lly{#2}%
   \global\def\epsf@urx{#3}\global\def\epsf@ury{#4}\fi}%
%
% Determine if the stuff following the %%BoundingBox is `(atend)'
% J. Daniel Smith.  Copied from \epsf@grab above.
%
\def\epsf@atendlit{(atend)} 
\def\epsf@atend #1 #2 #3\\{%
   \def\epsf@tmp{#1}\ifx\epsf@tmp\empty
      \epsf@atend #2 #3 .\\\else
   \ifx\epsf@tmp\epsf@atendlit\@atendtrue\fi\fi}


% End of file reading stuff from epsf.tex
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% trigonometry stuff from "trig.tex"
\chardef\psletter = 11 % won't conflict with \begin{letter} now...
\chardef\other = 12

\newif \ifdebug %%% turn me on to see TeX hard at work ...
\newif\ifc@mpute %%% don't need to compute some values
\c@mputetrue % but assume that we do

\let\then = \relax
\def\r@dian{pt }
\let\r@dians = \r@dian
\let\dimensionless@nit = \r@dian
\let\dimensionless@nits = \dimensionless@nit
\def\internal@nit{sp }
\let\internal@nits = \internal@nit
\newif\ifstillc@nverging
\def \Mess@ge #1{\ifdebug \then \message {#1} \fi}

{ %%% Things that need abnormal catcodes %%%
	\catcode `\@ = \psletter
	\gdef \nodimen {\expandafter \n@dimen \the \dimen}
	\gdef \term #1 #2 #3%
	       {\edef \t@ {\the #1}%%% freeze parameter 1 (count, by value)
		\edef \t@@ {\expandafter \n@dimen \the #2\r@dian}%
				   %%% freeze parameter 2 (dimen, by value)
		\t@rm {\t@} {\t@@} {#3}%
	       }
	\gdef \t@rm #1 #2 #3%
	       {{%
		\count 0 = 0
		\dimen 0 = 1 \dimensionless@nit
		\dimen 2 = #2\relax
		\Mess@ge {Calculating term #1 of \nodimen 2}%
		\loop
		\ifnum	\count 0 < #1
		\then	\advance \count 0 by 1
			\Mess@ge {Iteration \the \count 0 \space}%
			\Multiply \dimen 0 by {\dimen 2}%
			\Mess@ge {After multiplication, term = \nodimen 0}%
			\Divide \dimen 0 by {\count 0}%
			\Mess@ge {After division, term = \nodimen 0}%
		\repeat
		\Mess@ge {Final value for term #1 of 
				\nodimen 2 \space is \nodimen 0}%
		\xdef \Term {#3 = \nodimen 0 \r@dians}%
		\aftergroup \Term
	       }}
	\catcode `\p = \other
	\catcode `\t = \other
	\gdef \n@dimen #1pt{#1} %%% throw away the ``pt''
}

\def \Divide #1by #2{\divide #1 by #2} %%% just a synonym

\def \Multiply #1by #2%%% allows division of a dimen by a dimen
       {{%%% should really freeze parameter 2 (dimen, passed by value)
	\count 0 = #1\relax
	\count 2 = #2\relax
	\count 4 = 65536
	\Mess@ge {Before scaling, count 0 = \the \count 0 \space and
			count 2 = \the \count 2}%
	\ifnum	\count 0 > 32767 %%% do our best to avoid overflow
	\then	\divide \count 0 by 4
		\divide \count 4 by 4
	\else	\ifnum	\count 0 < -32767
		\then	\divide \count 0 by 4
			\divide \count 4 by 4
		\else
		\fi
	\fi
	\ifnum	\count 2 > 32767 %%% while retaining reasonable accuracy
	\then	\divide \count 2 by 4
		\divide \count 4 by 4
	\else	\ifnum	\count 2 < -32767
		\then	\divide \count 2 by 4
			\divide \count 4 by 4
		\else
		\fi
	\fi
	\multiply \count 0 by \count 2
	\divide \count 0 by \count 4
	\xdef \product {#1 = \the \count 0 \internal@nits}%
	\aftergroup \product
       }}

\def\r@duce{\ifdim\dimen0 > 90\r@dian \then   % sin(x+90) = sin(180-x)
		\multiply\dimen0 by -1
		\advance\dimen0 by 180\r@dian
		\r@duce
	    \else \ifdim\dimen0 < -90\r@dian \then  % sin(-x) = sin(360+x)
		\advance\dimen0 by 360\r@dian
		\r@duce
		\fi
	    \fi}

\def\Sine#1%
       {{%
	\dimen 0 = #1 \r@dian
	\r@duce
	\ifdim\dimen0 = -90\r@dian \then
	   \dimen4 = -1\r@dian
	   \c@mputefalse
	\fi
	\ifdim\dimen0 = 90\r@dian \then
	   \dimen4 = 1\r@dian
	   \c@mputefalse
	\fi
	\ifdim\dimen0 = 0\r@dian \then
	   \dimen4 = 0\r@dian
	   \c@mputefalse
	\fi
%
	\ifc@mpute \then
        	% convert degrees to radians
		\divide\dimen0 by 180
		\dimen0=3.141592654\dimen0
%
		\dimen 2 = 3.1415926535897963\r@dian %%% a well-known constant
		\divide\dimen 2 by 2 %%% we only deal with -pi/2 : pi/2
		\Mess@ge {Sin: calculating Sin of \nodimen 0}%
		\count 0 = 1 %%% see power-series expansion for sine
		\dimen 2 = 1 \r@dian %%% ditto
		\dimen 4 = 0 \r@dian %%% ditto
		\loop
			\ifnum	\dimen 2 = 0 %%% then we've done
			\then	\stillc@nvergingfalse 
			\else	\stillc@nvergingtrue
			\fi
			\ifstillc@nverging %%% then calculate next term
			\then	\term {\count 0} {\dimen 0} {\dimen 2}%
				\advance \count 0 by 2
				\count 2 = \count 0
				\divide \count 2 by 2
				\ifodd	\count 2 %%% signs alternate
				\then	\advance \dimen 4 by \dimen 2
				\else	\advance \dimen 4 by -\dimen 2
				\fi
		\repeat
	\fi		
			\xdef \sine {\nodimen 4}%
       }}

% Now the Cosine can be calculated easily by calling \Sine
\def\Cosine#1{\ifx\sine\UnDefined\edef\Savesine{\relax}\else
		             \edef\Savesine{\sine}\fi
	{\dimen0=#1\r@dian\advance\dimen0 by 90\r@dian
	 \Sine{\nodimen 0}
	 \xdef\cosine{\sine}
	 \xdef\sine{\Savesine}}}	      
% end of trig stuff
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\def\psdraft{
	\def\@psdraft{0}
	%\ps@typeout{draft level now is \@psdraft \space . }
}
\def\psfull{
	\def\@psdraft{100}
	%\ps@typeout{draft level now is \@psdraft \space . }
}

\psfull

\newif\if@scalefirst
\def\psscalefirst{\@scalefirsttrue}
\def\psrotatefirst{\@scalefirstfalse}
\psrotatefirst

\newif\if@draftbox
\def\psnodraftbox{
	\@draftboxfalse
}
\def\psdraftbox{
	\@draftboxtrue
}
\@draftboxtrue

\newif\if@prologfile
\newif\if@postlogfile
\def\pssilent{
	\@noisyfalse
}
\def\psnoisy{
	\@noisytrue
}
\psnoisy
%%% These are for the option list.
%%% A specification of the form a = b maps to calling \@p@@sa{b}
\newif\if@bbllx
\newif\if@bblly
\newif\if@bburx
\newif\if@bbury
\newif\if@height
\newif\if@width
\newif\if@rheight
\newif\if@rwidth
\newif\if@angle
\newif\if@clip
\newif\if@verbose
\def\@p@@sclip#1{\@cliptrue}


%\newif\if@decmpr
% Causes confusing error messages if the needed file is present
% but NOT in .Z format.  (LBL, M. Gelbaum, 5-18-1992)

%%% GDH 7/26/87 -- changed so that it first looks in the local directory,
%%% then in a specified global directory for the ps file.
%%% RPR 6/25/91 -- changed so that it defaults to user-supplied name if
%%% boundingbox info is specified, assuming graphic will be created by
%%% print time.
%%% TJD 10/19/91 -- added bbfile vs. file distinction, and @decmpr flag
%%% MG 5/18/92 -- Removed @decmpr flag (see comment above).

\def\@p@@sfigure#1{\def\@p@sfile{null}\def\@p@sbbfile{null}
	        \openin1=#1.bb
		\ifeof1\closein1
	        	\openin1=\figurepath#1.bb
			\ifeof1\closein1
			        \openin1=#1
				\ifeof1\closein1%
				       \openin1=\figurepath#1
					\ifeof1
					   \ps@typeout{Error, File #1 not found}
						\if@bbllx\if@bblly
				   		\if@bburx\if@bbury
			      				\def\@p@sfile{#1}%
			      				\def\@p@sbbfile{#1}%
							%\@decmprfalse
				  	   	\fi\fi\fi\fi
					\else\closein1
				    		\def\@p@sfile{\figurepath#1}%
				    		\def\@p@sbbfile{\figurepath#1}%
						%\@decmprfalse
	                       		\fi%
			 	\else\closein1%
					\def\@p@sfile{#1}
					\def\@p@sbbfile{#1}
					%\@decmprfalse
			 	\fi
			\else
				\def\@p@sfile{\figurepath#1}
				\def\@p@sbbfile{\figurepath#1.bb}
				%\@decmprtrue 
			\fi
		\else
			\def\@p@sfile{#1}
			\def\@p@sbbfile{#1.bb}
			%\@decmprtrue
		\fi}

\def\@p@@sfile#1{\@p@@sfigure{#1}}

\def\@p@@sbbllx#1{
		%\ps@typeout{bbllx is #1}
		\@bbllxtrue
		\dimen100=#1
		\edef\@p@sbbllx{\number\dimen100}
}
\def\@p@@sbblly#1{
		%\ps@typeout{bblly is #1}
		\@bbllytrue
		\dimen100=#1
		\edef\@p@sbblly{\number\dimen100}
}
\def\@p@@sbburx#1{
		%\ps@typeout{bburx is #1}
		\@bburxtrue
		\dimen100=#1
		\edef\@p@sbburx{\number\dimen100}
}
\def\@p@@sbbury#1{
		%\ps@typeout{bbury is #1}
		\@bburytrue
		\dimen100=#1
		\edef\@p@sbbury{\number\dimen100}
}
\def\@p@@sheight#1{
		\@heighttrue
		\dimen100=#1
   		\edef\@p@sheight{\number\dimen100}
		%\ps@typeout{Height is \@p@sheight}
}
\def\@p@@swidth#1{
		%\ps@typeout{Width is #1}
		\@widthtrue
		\dimen100=#1
		\edef\@p@swidth{\number\dimen100}
}
\def\@p@@srheight#1{
		%\ps@typeout{Reserved height is #1}
		\@rheighttrue
		\dimen100=#1
		\edef\@p@srheight{\number\dimen100}
}
\def\@p@@srwidth#1{
		%\ps@typeout{Reserved width is #1}
		\@rwidthtrue
		\dimen100=#1
		\edef\@p@srwidth{\number\dimen100}
}
\def\@p@@sangle#1{
		%\ps@typeout{Rotation is #1}
		\@angletrue
%		\dimen100=#1
		\edef\@p@sangle{#1} %\number\dimen100}
}
\def\@p@@ssilent#1{ 
		\@verbosefalse
}
\def\@p@@sprolog#1{\@prologfiletrue\def\@prologfileval{#1}}
\def\@p@@spostlog#1{\@postlogfiletrue\def\@postlogfileval{#1}}
\def\@cs@name#1{\csname #1\endcsname}
\def\@setparms#1=#2,{\@cs@name{@p@@s#1}{#2}}
%
% initialize the defaults (size the size of the figure)
%
\def\ps@init@parms{
		\@bbllxfalse \@bbllyfalse
		\@bburxfalse \@bburyfalse
		\@heightfalse \@widthfalse
		\@rheightfalse \@rwidthfalse
		\def\@p@sbbllx{}\def\@p@sbblly{}
		\def\@p@sbburx{}\def\@p@sbbury{}
		\def\@p@sheight{}\def\@p@swidth{}
		\def\@p@srheight{}\def\@p@srwidth{}
		\def\@p@sangle{0}
		\def\@p@sfile{} \def\@p@sbbfile{}
		\def\@p@scost{10}
		\def\@sc{}
		\@prologfilefalse
		\@postlogfilefalse
		\@clipfalse
		\if@noisy
			\@verbosetrue
		\else
			\@verbosefalse
		\fi
}
%
% Go through the options setting things up.
%
\def\parse@ps@parms#1{
	 	\@psdo\@psfiga:=#1\do
		   {\expandafter\@setparms\@psfiga,}}
%
% Compute bb height and width
%
\newif\ifno@bb
\def\bb@missing{
	\if@verbose{
		\ps@typeout{psfig: searching \@p@sbbfile \space  for bounding box}
	}\fi
	\no@bbtrue
	\epsf@getbb{\@p@sbbfile}
        \ifno@bb \else \bb@cull\epsf@llx\epsf@lly\epsf@urx\epsf@ury\fi
}	
\def\bb@cull#1#2#3#4{
	\dimen100=#1 bp\edef\@p@sbbllx{\number\dimen100}
	\dimen100=#2 bp\edef\@p@sbblly{\number\dimen100}
	\dimen100=#3 bp\edef\@p@sbburx{\number\dimen100}
	\dimen100=#4 bp\edef\@p@sbbury{\number\dimen100}
	\no@bbfalse
}
% rotate point (#1,#2) about (0,0).
% The sine and cosine of the angle are already stored in \sine and
% \cosine.  The result is placed in (\p@intvaluex, \p@intvaluey).
\newdimen\p@intvaluex
\newdimen\p@intvaluey
\def\rotate@#1#2{{\dimen0=#1 sp\dimen1=#2 sp
%            	calculate x' = x \cos\theta - y \sin\theta
		  \global\p@intvaluex=\cosine\dimen0
		  \dimen3=\sine\dimen1
		  \global\advance\p@intvaluex by -\dimen3
% 		calculate y' = x \sin\theta + y \cos\theta
		  \global\p@intvaluey=\sine\dimen0
		  \dimen3=\cosine\dimen1
		  \global\advance\p@intvaluey by \dimen3
		  }}
\def\compute@bb{
		\no@bbfalse
		\if@bbllx \else \no@bbtrue \fi
		\if@bblly \else \no@bbtrue \fi
		\if@bburx \else \no@bbtrue \fi
		\if@bbury \else \no@bbtrue \fi
		\ifno@bb \bb@missing \fi
		\ifno@bb \ps@typeout{FATAL ERROR: no bb supplied or found}
			\no-bb-error
		\fi
		%
%\ps@typeout{BB: \@p@sbbllx, \@p@sbblly, \@p@sbburx, \@p@sbbury} 
%
% store height/width of original (unrotated) bounding box
		\count203=\@p@sbburx
		\count204=\@p@sbbury
		\advance\count203 by -\@p@sbbllx
		\advance\count204 by -\@p@sbblly
		\edef\ps@bbw{\number\count203}
		\edef\ps@bbh{\number\count204}
		%\ps@typeout{ psbbh = \ps@bbh, psbbw = \ps@bbw }
		\if@angle 
			\Sine{\@p@sangle}\Cosine{\@p@sangle}
	        	{\dimen100=\maxdimen\xdef\r@p@sbbllx{\number\dimen100}
					    \xdef\r@p@sbblly{\number\dimen100}
			                    \xdef\r@p@sbburx{-\number\dimen100}
					    \xdef\r@p@sbbury{-\number\dimen100}}
%
% Need to rotate all four points and take the X-Y extremes of the new
% points as the new bounding box.
                        \def\minmaxtest{
			   \ifnum\number\p@intvaluex<\r@p@sbbllx
			      \xdef\r@p@sbbllx{\number\p@intvaluex}\fi
			   \ifnum\number\p@intvaluex>\r@p@sbburx
			      \xdef\r@p@sbburx{\number\p@intvaluex}\fi
			   \ifnum\number\p@intvaluey<\r@p@sbblly
			      \xdef\r@p@sbblly{\number\p@intvaluey}\fi
			   \ifnum\number\p@intvaluey>\r@p@sbbury
			      \xdef\r@p@sbbury{\number\p@intvaluey}\fi
			   }
%			lower left
			\rotate@{\@p@sbbllx}{\@p@sbblly}
			\minmaxtest
%			upper left
			\rotate@{\@p@sbbllx}{\@p@sbbury}
			\minmaxtest
%			lower right
			\rotate@{\@p@sbburx}{\@p@sbblly}
			\minmaxtest
%			upper right
			\rotate@{\@p@sbburx}{\@p@sbbury}
			\minmaxtest
			\edef\@p@sbbllx{\r@p@sbbllx}\edef\@p@sbblly{\r@p@sbblly}
			\edef\@p@sbburx{\r@p@sbburx}\edef\@p@sbbury{\r@p@sbbury}
%\ps@typeout{rotated BB: \r@p@sbbllx, \r@p@sbblly, \r@p@sbburx, \r@p@sbbury}
		\fi
		\count203=\@p@sbburx
		\count204=\@p@sbbury
		\advance\count203 by -\@p@sbbllx
		\advance\count204 by -\@p@sbblly
		\edef\@bbw{\number\count203}
		\edef\@bbh{\number\count204}
		%\ps@typeout{ bbh = \@bbh, bbw = \@bbw }
}
%
% \in@hundreds performs #1 * (#2 / #3) correct to the hundreds,
%	then leaves the result in @result
%
\def\in@hundreds#1#2#3{\count240=#2 \count241=#3
		     \count100=\count240	% 100 is first digit #2/#3
		     \divide\count100 by \count241
		     \count101=\count100
		     \multiply\count101 by \count241
		     \advance\count240 by -\count101
		     \multiply\count240 by 10
		     \count101=\count240	%101 is second digit of #2/#3
		     \divide\count101 by \count241
		     \count102=\count101
		     \multiply\count102 by \count241
		     \advance\count240 by -\count102
		     \multiply\count240 by 10
		     \count102=\count240	% 102 is the third digit
		     \divide\count102 by \count241
		     \count200=#1\count205=0
		     \count201=\count200
			\multiply\count201 by \count100
		 	\advance\count205 by \count201
		     \count201=\count200
			\divide\count201 by 10
			\multiply\count201 by \count101
			\advance\count205 by \count201
			%
		     \count201=\count200
			\divide\count201 by 100
			\multiply\count201 by \count102
			\advance\count205 by \count201
			%
		     \edef\@result{\number\count205}
}
\def\compute@wfromh{
		% computing : width = height * (bbw / bbh)
		\in@hundreds{\@p@sheight}{\@bbw}{\@bbh}
		%\ps@typeout{ \@p@sheight * \@bbw / \@bbh, = \@result }
		\edef\@p@swidth{\@result}
		%\ps@typeout{w from h: width is \@p@swidth}
}
\def\compute@hfromw{
		% computing : height = width * (bbh / bbw)
	        \in@hundreds{\@p@swidth}{\@bbh}{\@bbw}
		%\ps@typeout{ \@p@swidth * \@bbh / \@bbw = \@result }
		\edef\@p@sheight{\@result}
		%\ps@typeout{h from w : height is \@p@sheight}
}
\def\compute@handw{
		\if@height 
			\if@width
			\else
				\compute@wfromh
			\fi
		\else 
			\if@width
				\compute@hfromw
			\else
				\edef\@p@sheight{\@bbh}
				\edef\@p@swidth{\@bbw}
			\fi
		\fi
}
\def\compute@resv{
		\if@rheight \else \edef\@p@srheight{\@p@sheight} \fi
		\if@rwidth \else \edef\@p@srwidth{\@p@swidth} \fi
		%\ps@typeout{rheight = \@p@srheight, rwidth = \@p@srwidth}
}
%		
% Compute any missing values
\def\compute@sizes{
	\compute@bb
	\if@scalefirst\if@angle
% at this point the bounding box has been adjsuted correctly for
% rotation.  PSFIG does all of its scaling using \@bbh and \@bbw.  If
% a width= or height= was specified along with \psscalefirst, then the
% width=/height= value needs to be adjusted to match the new (rotated)
% bounding box size (specifed in \@bbw and \@bbh).
%    \ps@bbw       width=
%    -------  =  ---------- 
%    \@bbw       new width=
% so `new width=' = (width= * \@bbw) / \ps@bbw; where \ps@bbw is the
% width of the original (unrotated) bounding box.
	\if@width
	   \in@hundreds{\@p@swidth}{\@bbw}{\ps@bbw}
	   \edef\@p@swidth{\@result}
	\fi
	\if@height
	   \in@hundreds{\@p@sheight}{\@bbh}{\ps@bbh}
	   \edef\@p@sheight{\@result}
	\fi
	\fi\fi
	\compute@handw
	\compute@resv}

%
% \psfig
% usage : \psfig{file=, height=, width=, bbllx=, bblly=, bburx=, bbury=,
%			rheight=, rwidth=, clip=}
%
% "clip=" is a switch and takes no value, but the `=' must be present.
\def\psfig#1{\vbox {
	% do a zero width hard space so that a single
	% \psfig in a centering enviornment will behave nicely
	%{\setbox0=\hbox{\ }\ \hskip-\wd0}
	%
	\ps@init@parms
	\parse@ps@parms{#1}
	\compute@sizes
	%
	\ifnum\@p@scost<\@psdraft{
		%
		\special{ps::[begin] 	\@p@swidth \space \@p@sheight \space
				\@p@sbbllx \space \@p@sbblly \space
				\@p@sbburx \space \@p@sbbury \space
				startTexFig \space }
		\if@angle
			\special {ps:: \@p@sangle \space rotate \space} 
		\fi
		\if@clip{
			\if@verbose{
				\ps@typeout{(clip)}
			}\fi
			\special{ps:: doclip \space }
		}\fi
		\if@prologfile
		    \special{ps: plotfile \@prologfileval \space } \fi
%		\if@decmpr{
%			\if@verbose{
%			\ps@typeout{psfig: including \@p@sfile.Z \space }
%			}\fi
%			\special{ps: plotfile "`zcat \@p@sfile.Z" \space }
%		}\else{
			\if@verbose{
				\ps@typeout{psfig: including \@p@sfile \space }
			}\fi
			\special{ps: plotfile \@p@sfile \space }
%		}\fi
		\if@postlogfile
		    \special{ps: plotfile \@postlogfileval \space } \fi
		\special{ps::[end] endTexFig \space }
		% Create the vbox to reserve the space for the figure.
		\vbox to \@p@srheight sp{
		% 1/92 TJD Changed from "true sp" to "sp" for magnification.
			\hbox to \@p@srwidth sp{
				\hss
			}
		\vss
		}
	}\else{
		% draft figure, just reserve the space and print the
		% path name.
		\if@draftbox{		
			% Verbose draft: print file name in box
			\hbox{\frame{\vbox to \@p@srheight sp{
			\vss
			\hbox to \@p@srwidth sp{ \hss \@p@sfile \hss }
			\vss
			}}}
		}\else{
			% Non-verbose draft
			\vbox to \@p@srheight sp{
			\vss
			\hbox to \@p@srwidth sp{\hss}
			\vss
			}
		}\fi	



	}\fi
}}
\psfigRestoreAt
\let\@=\LaTeXAtSign

trr.tex
\documentclass[10 pt]{article}
\input{psfig}
\include{prepictex}
\include{pictex}
\include{postpictex}
\usepackage{amscd, amssymb, amsmath}


\newtheorem{pr}{Proposition}
\newtheorem{lm}{Lemma}
\newtheorem{tm}{Theorem}

\newcommand{\proj}{\mathbb{P}}
\newcommand{\com}{\mathbb{C}}
\newcommand{\qrat}{\mathbb{Q}}
\newcommand{\grass}{\mathbf G}
\newcommand{\barr}{\overline}
\newcommand{\rarr}{\rightarrow}
\newcommand{\oh}{{\mathcal{O}}}
\newcommand{\Q}{\mathbb{Q}}
\newcommand{\Z}{\mathbb{Z}}
\newcommand{\sy}{\mathbb{S}}
\newcommand{\G}{\mathbf{G}}

\newcommand{\eqq}{\stackrel{\sim}{=}}
\newcommand{\deli}{\bigtriangleup}
\newcommand{\sumo}{\oplus}
\newcommand{\grad}{\nabla}

\newcommand{\cs}{\com^*}
\newcommand{\cm}{\mathcal{M}}
\newcommand{\mm}{\overline{\cm}_{1,4}}
\newcommand{\mh}{\overline{\cm}_{2,3}}
\newcommand{\mgn}{\overline{\cm}_{g,n}}
\newcommand{\pd}{(\proj^1,d)}
\newcommand{\prt}{(\proj^1,2)}
\newcommand{\HCs}{H_{\cs}^*}
\newcommand{\cloc}{\com[\hbar,\frac{1}{\hbar}]}
\newcommand{\cdim}{\text{vdim}_\com}
\newcommand{\Aut}{\text{Aut}}
\newcommand{\iz}{{i_0}}
\newcommand{\ii}{{i_\infty}}
\newcommand{\elli}{\text{ell}}
\newcommand{\rat}{\text{rat}}
\newcommand{\un}{\text{un}}
\def\HC#1{H_{\cs}^#1}
\def\HAH#1{A_{#1}^{\cs}}
\def\HAC#1{A_{\cs}^{#1}}
\def\vir#1{[#1]^{vir}}
\def\fref#1{(\ref{#1})}
\def\ev#1{ev_{#1}^*}
\def\sig#1{\sigma({#1})}
\def\mc#1#2{\overline{\cm}_{#1,#2}}
\newcommand{\bpf}{\noindent {\em Proof.} }
\newcommand{\epf}{\qed \vspace{+10pt}}

\begin{document}

\title{Topological Recursion Relations by Localization}
\author{Eric Edward Katz}
\date{2 Oct 2003}
\maketitle

\pagestyle{plain}
\setcounter{section}{0}
\section{\bf{Introduction}}

Let $\mgn$ be the moduli space of stable genus $g$ curves
with $n$ marked points.
$\mgn$ has boundary strata consisting of nodal curves parametrized by
products of smaller-dimensional moduli spaces.  The fundamental classes
of these boundary strata may be linearly dependent in $A_*(\mgn)$.  
Relations among these boundary strata can be found by exploiting a
localization trick.  
Let $\pi$ be the stabilization map 
$$\pi:\mgn\pd \rarr \mgn.$$
Note that $\mgn\pd$ has a $\cs$-action induced from the $\cs$-action on
$\proj^1$.
$\mgn$ has a trivial $\cs$-action which makes $\pi$ an equivariant
map.
If we write $\HAH{*}(pt)=\com[\hbar]$ then 
$\HAH{*}(\mgn)=A_*(\mgn)[\hbar]$.


Now, given $a\in \HAC{*}(\mgn\pd)$, we may compute $\pi_*(\vir{\mgn\pd}\cap a)$ by the following
localization formula
\begin{equation}
\label{pfs}
\pi_*\left(\vir{\mgn\pd}\cap a\right)
 = \sum_F \pi_* i_{F*} \left(\frac {\vir{F} \cap i_F^*a}{e(\nu)}\right)
\end{equation}
in $\HAH{*}(\mgn) \otimes \cloc$
where the sum is over $\cs$-fixed loci $F$ in $\mgn\pd$, 
$i_F : F \rarr \mgn\pd$
and $e(\nu)$ is the equivariant Euler class of the normal bundle to $F$
in $\mgn\pd$.

Note that the left hand side of \fref{pfs} is a finite expansion in powers
of $\hbar$ and involves no negative powers of $\hbar$.  The right hand side
of \fref{pfs} involves $\frac {1}{e(\nu)}$ and so has negative powers of
$\hbar$ occuring.  This means that the coefficient of $\hbar^{-k}$ on
the right hand side must be zero.  Because the coefficient is the sum of cycle
classes pushed forward from fixed loci, we obtain relations among the 
boundary strata in $A_*(\mgn)$.

In what follows, we will apply this trick to
$$\pi:\mm\prt \rarr \mm$$
and obtain the Getzler relation in $A_*(\mm)$

The Getzler relation was first discovered by Getzler in \cite{G} by bounding
the dimension of $H_4(\mm)$ and computing its intersection matrix.  A
geometric proof of this relation was given by Pandharipande in \cite{P}.
Pandharipande's proof makes heavy use of the branch morphism and can 
probably also be cast in the more modern language of the degeneration 
methods of \cite{Li}.  This note can be thought of as an attempt to 
modify the proof of Pandharipande to use the technique of virtual
localization.

I would like to mention that the main technique of this note is used
in a number of papers of Faber and Pandharipande, most recently, implicitly 
in section 2.2.2 of \cite{FP}.

I would like to extend thanks to Ravi Vakil for valuable discussions and 
to Rahul Pandharipande for the use of his figures. 


\section{\bf Dimension Count}

The purpose of this section is to state the virtual dimensions of the 
relevant moduli spaces.  

$$\cdim \mgn = 3g-3+n$$
$$\cdim \mgn\pd = 2g-2+2d+n$$
Therefore, the virtual dimension of the fiber of the stabilization map 
$\pi$ is 
$$\cdim \mgn\pd - \cdim \mgn = (2g-2+2d+n)-(3g-3+n)=1-g+2d$$
Hence if $a\in \HAC{m}(\mgn \pd)$,
$\pi_*(\vir{\mgn\pd}\cap a) \in A_{2g-2+2d+n-m}(\mgn)$.

Since $\hbar$ is of degree $1$ in $\HAH{*}(\mgn)$, the coefficient of 
$\hbar^{-k}$ in $\pi_*(\vir{\mgn\pd}\cap a)$ is an element of
$A_{2g-2+2d+n-m-k}(\mgn)$.

\section{\bf Symmetrized Strata in $\mm$}

The Getzler relation \cite{G} is a relation among two-dimensional strata on
$\mm$.  
It is best written in terms of strata that have been symmetrized over the
placement of marked points.  We adopt Getzler's notation
for symmetrized strata, so the symbol
%\begin{figure}[strat1]
\begin{center}
  \psfig{file=strat1.eps}
\end{center}
%\end{figure}
is shorthand for

%\begin{figure}[stratsum]
\begin{center}
  \psfig{file=stratsum.eps}
\end{center}
%\end{figure}
where the line labelled $1$ is an elliptic curve, the unlabelled lines are 
rational curves and the bars represent marked points.
In other words, given a stratum $S$ in $\mm$, we consider the symmetrized
stratum 
$$\text{Sym}(S)=\frac{1}{\Aut(S)}\sum_{\sigma\in S_4}\sigma(S)$$
where $\sigma (S)$ is the action of $\sigma$ on $S$ permuting the marked
points and $\Aut(S)$ is the number of permutations that leave $S$ fixed.

Getzler's notation for the set of
$S_4$-invariant dimension 2 strata of $\mm$ is

\begin{center}
  \input{g1.pictex}
\end{center}
\vspace{+5pt}
\begin{center}
  \input{g2.pictex}
\end{center}
\vspace{+5pt}
\begin{center}
\input{g3.pictex}
\end{center}

Note tht these figures are taken from the appendix of \cite{P}.

\section{\bf The Getzler Relation}

Using the above notation, we may write Getzler's relation as

\begin{equation}
\label{getzler}
12\deli_{2,2}-4\deli_{2,3}-2\deli_{2,4}+6\deli_{3,4}+\deli_{0,3}
+\deli_{0,4}-2\deli_\beta=0.
\end{equation}

Note that this formula agrees with that in \cite{G}, not that in \cite{P}. 
The two instances differ in that in \cite{G}, the symbols $\deli$ refer
to the fundamental class of the stratum considered as a stack, i.e. the 
usual fundamental
class divided by the order of the automorphism group of the
generic point while in \cite{P},
the same symbols refer to the usual fundamental class.  We have
found it convenient to use the fundamental classes of the stack 
throughout.


The Getzler relation appear as the coefficient of $\hbar^{-2}$ in
$\pi_*(\vir{\mm\prt}\cap a)$ for a particular choice of $a\in\HAC{4}(\prt)$.

\section{\bf Group Actions and Linearizations}

The purpose of this section is to review the standard conventions for the 
group action on $\proj^1$.  See \cite{GP} for more details.  
We define a $\cs$ action on $\proj^1$ by
$$\lambda\cdot [Z_0:Z_1] = [\lambda Z_0:Z_1]$$
We identify $\com$ with $\proj^1-{[1:0]}$ and refer to $[0:1]$ as $0$
and $[1:0]$ as $\infty$.  

We will pull back point classes from $\proj^1$ by the evaluation map.  To
perform the localization computation, we need to pick equivariant extensions
of the point class.  These equivariant extensions will arise as $c_1(\oh(1))$
for appropriate choices of linearization of $\oh(1)$

If $\oh(-1)$ is the line bundle whose fiber over $[Z_0:Z_1]$ are all
complex multiples of $(Z_0,Z_1)$, we define the linearization of $\oh(-1)$
of weight $b$ to be 
$$\lambda\cdot (Z_0,Z_1) = (\lambda^{b+1} Z_0,\lambda^b Z_1)$$
If $\iz:0 \rarr \proj^1$ and $\ii:\infty \rarr \proj^1$ are the usual
inclusions then
$\iz^* \oh(-1)$ is the vector space $\com$ with the action
$$\lambda\cdot z = \lambda^{b+1} z$$
and $\ii^* \oh(-1)$ is the vector space $\com$ with the action
$$\lambda\cdot z = \lambda^b z.$$

Let $\oh(1)$ be the equivariant line-bundle on $\proj^1$ dual to the one 
defined above.
For $b=0$, $c_1(\oh(1))=\iz_*[P]$ where $P$ is Poincare-dual to the 
fundamental class of a point.  Likewise, for $b=1$, $c_1(\oh(1))=\ii_*[P]$.
Set $[0]=\ii_*[P]$ and $[\infty]=\ii_*[P]$.
Note that $\iz^*[\infty]=0$ and $\ii^*[0]=0$.

The class $a\in\HAC{4}(\mm\prt)$ will be an appropriately symmetrized version
of
$$a=\ev{1}[0]\ev{2}[0]\ev{3}[\infty]\ev{4}[\infty]$$

\section{Fixed Loci}

We will be summing over fixed loci of the $\cs$-action on $\mgn\pd$.
These loci are given by genus $g$ stable maps with $n$ marked points
whose irreducible components are as follows:
\begin{enumerate}
\item[(i)] Curves of any genus contracted to $0$
\item[(ii)] Curves of any genus contracted to $\infty$
\item[(iii)] Rational curves mapped into $\proj^1$, ramified only over $0$ and
$\infty$, called trivial components
\end{enumerate}
The marked points on the fixed loci are mapped to $0$ or $\infty$.

An example of a fixed locus in $\mm\prt$ is

%\begin{figure}[fixloc1]
\begin{center}
  \psfig{file=fixloc1.eps}
\end{center}
%\end{figure}
where the circle at top represents an elliptic curve contracted to $0$, the 
$1$'s at the side are degree $1$ trivial components, $1$ and $2$ are
marked points on the elliptic curve, and the $3$ and $4$ marked points 
on the trivial components.
\section{Evaluation of Classes on Fixed Loci}

Following \cite{K} or \cite{GP} we will compute 
$$\sum_F \pi_* i_{F*} \left( \frac {\vir{F} 
\cap i_F^*(\ev{1}[0]\ev{2}[0]\ev{3}[\infty]\ev{4}[\infty])}{e(\nu)}\right)$$
by parametrizing fixed loci by a product of moduli spaces.
For example, the above fixed locus is parametrized by $\mm$.
More formally, we define a map 
$$I:\mm \rarr \mm\prt$$
that attaches degree one trivial components to the third and fourth marked
marked points and then places the marked points $3$ and $4$ on the trivial
components.

So we note that $\vir{F}=\frac{1}{\deg(I)} I_*(\vir{\mm})$ where $\deg(I)$ is
the degree of the map $I$ considered as a map of stacks which in more 
conventional language is
the number of automorphisms of $F$ divided by the number of automorphisms
of $\mm$.  In this case, $\deg(I)$ is equal to $1$ but in more general 
situations, we may have more complicated fixed loci which are products of 
moduli spaces and whose automorphism groups are non-trivial.  See \cite{K} or
\cite{GP} for more explanation.  See also \cite{PO} for a very systematic
description of fixed locii of $\mgn\pd$.

In general, we will have a product of moduli stacks $L$ parametrizing
a fixed locus by a map $I:L\rarr F$.   This gives us the
following commutative diagram

\setlength{\unitlength}{1.5cm}
\begin{picture}(6,6)
  \put(1,3){$F$}
  \put(3,3){$\mm\prt$}
  \put(3,1){$\mm$}
  \put(1,5){$L$}
  \put(3.15,2.9){\vector(0,-1){1.6}}
  \put(1.2,3.06){\vector(1,0){1.7}}
  \put(1.1,4.9){\vector(0,-1){1.6}}
  \put(1.2,4.9){\vector(1,-1){1.75}}
  \put(1.15,4.9){\vector(1,-2){1.8}}
  \put(3.2,2){$\pi$}
  \put(1.55,3.15){$i_F$}
  \put(.9,4){$I$}
  \put(2.1,4.1){$i_L$}
  \put(1.9,2.7){$\pi_L$}
\end{picture}

\noindent
Therefore,
$$\pi_* i_{F*}\left(\frac {\vir{F} \cap i_F^*a}{e(\nu)}\right)=
\frac{1}{\deg(i_L)}\pi_{L*}\left(\frac {\vir{L} \cap i_L^*a}{I^*e(\nu)}\right).$$
Now, note that $\pi_L$ parametrizes a stratum $S$ in $\mm$.  Since we
are using fundamental classes for strata considered as stacks, 
$$\vir{S}=\frac{1}{\deg(\pi_L)} \pi_{L*}(\vir{L}).$$
In what follows, we will abuse notation and identify $\vir{S}$ with the
cycle class on $L$ which pushes forward by $\pi_{L*}$ to the legitimate
$\vir{S}$.  It follows that
$$\pi_* i_{F*}\left(\frac {\vir{F} \cap i_F^*a}{e(\nu)}\right)=
\frac{\deg(\pi_L)}{\deg(i_L)}\pi_{L*} 
\left(\vir{S}\cap\frac{i_L^*a}{I^*e(\nu)}\right).$$

Now, we notice that $i_L^*(\ev{i}[0])$ and $i_L^*(\ev{i}[\infty])$ are of
pure weight.  In fact, 
$i_L^*(\ev{1}[0]\ev{2}[0]\ev{3}[\infty]\ev{4}[\infty])=\delta_F \hbar^4$
where $\delta_F=1$ if marked points $1,2$ are mapped to $0$ and $3,4$ are
mapped to $\infty$ and $\delta_F=0$ otherwise.

Therefore, we must evaluate
\begin{equation}
\label{ssa}
\sum_{F} \delta_F \frac{\deg(\pi_L)}{\deg(i_L)}\pi_{L*}
\left(\frac {\hbar^4 \vir{S}}{I^*e(\nu)}\right).
\end{equation}

Since we are looking at the coefficient of $\hbar^{-2}$, in \fref{ssa},
we can consider the constant coefficient of
\begin{equation}
\label{ss}
\sum_{F} \delta_F \frac{\deg(\pi_L)}{\deg(i_L)}\pi_{L*}
\left(\frac {\hbar^6 \vir{S}}{I^*e(\nu)}\right).
\end{equation}

\section{Symmetrization of Marked Points}

In \fref{ss}, the cycles classes in each summand is independent of the 
labelling of marked points.
Therefore, 
\begin{eqnarray*}
\lefteqn{
\sum_{\sigma\in S_4} \sum_F \pi_* i_{F*} \frac {\vir{F} 
\cap i_F^*(\ev{\sig{1}}[0]\ev{\sig{2}}[0]
\ev{\sig{3}}[\infty]\ev{\sig{4}}[\infty])}{e(\nu)}
} \\
&=&
\sum_{\sigma\in S_4}\sum_{\sig{F}}
\delta_{\sig{F}}\frac{\deg(\pi_L)}{\deg(i_L)}\pi_{L*}
\left(\frac {\hbar^6 \vir{S}}{I^*e(\nu)}\right)
\end{eqnarray*}
where $\sigma$ acts on the right hand side by permuting marked points.

For ease of notation, we can replace fixed locii in $\mm\prt$ labelled 
with marked points by unlabelled fixed locii.  In other words, 
we consider
$$\text{Sym}(F)=\sum_{\sigma\in S_4}\sigma(F)$$
Note that our convention for symmetrized strata in $\mm\prt$ differs from
that in $\mm$ and that
$$\pi_*(\text{Sym}(F))=\Aut({\pi_*(F)})\ \text{Sym}(\pi_*F)).$$
The unlabelled locus
%\begin{figure}[sloc1]
\begin{center}
  \psfig{file=sloc1.eps}
\end{center}
%\end{figure}
represents
%\begin{figure}[unsymsum]
\begin{center}
  \psfig{file=unsymsum.eps}
\end{center}
%\end{figure}
we consider, the shorthand of
where we pick up a factor of $4$ when we pushforward by $\pi_*$.

Now, instead of summing over labelled fixed locii, we sum over their
unlabelled counterparts, i.e.
\begin{eqnarray*}
\lefteqn
{
\sum_{\sigma\in S_4}\sum_{\sig{F}}\delta_{\sig{F}}
\frac{\deg(\pi_L)}{\deg(i_L)}\pi_{L*}
\left(\frac {\hbar^6 \vir{L}}{I^*e(\nu)}\right)
} \\
& = &
\sum_{F_{\un}}
\frac{\deg(\pi_L)}{\deg(i_L)}N_{F_{\un}}Aut({\pi_*}L)
\pi_{L*}\left(\frac {\hbar^6 \vir{S}}{I^*e(\nu)}\right)
\end{eqnarray*}
where $N_{F_{\un}}$ is the number of labelled fixed with $\delta_F=1$ locii 
have $F_{\un}$ as their unlabelled counterpart.  More formally, this is
\begin{equation}
\label{nfdef}
N_{F_{\un}}
=
\sum_{\un(F)=F_{\un}}
\delta_F
\end{equation}
where $\un(F)$ denotes the unlabelled fixed locus corresponding to $F$.


For example,

%\begin{figure}[lloc]
\begin{center}
  \psfig{file=lloc.eps}
\end{center}
which are distinct fixed locii in $\mm\prt$ both have
%\begin{figure}[uloc]
\begin{center}
  \psfig{file=uloc.eps}
\end{center}
as their unlabelled counterpart.

\section{Contributing Fixed Locii}
The unlabelled fixed locii in $\mm\prt$ are

%\begin{figure}[floc1]
\begin{center}
  \psfig{file=floc1.eps}
\end{center}
\setlength{\unitlength}{.675cm}

\begin{picture}(15,.1)
  \put(-.3,1){$\prod_{1,1}$}
  \put(3,1){$\prod_{2,0}$}
  \put(6,1){$\top$}
\end{picture}
%\begin{figure}[floc2]
\begin{center}
  \psfig{file=floc2.eps}
\end{center}
%\end{figure}
\setlength{\unitlength}{.675cm}

\begin{picture}(15,.1)
  \put(-.3,1){$\bigvee_{2,0}$}
  \put(2.7,1){$\bigvee_{1,1}$}
  \put(5.4,1){$\bigvee_{0,2}$}
\end{picture}
%\begin{figure}[floc3]
\begin{center}
  \psfig{file=floc3.eps}
\end{center}
%\end{figure}
\setlength{\unitlength}{.675cm}

\begin{picture}(15,.1)
  \put(-.3,1){$O$}
\end{picture}
%\begin{figure}[floc4]
\begin{center}
  \psfig{file=floc4.eps}
\end{center}
%\end{figure}
\setlength{\unitlength}{.675cm}

\begin{picture}(15,.1)
  \put(-.3,1){$\bigwedge_{2,0}$}
  \put(2.7,1){$\bigwedge_{1,1}$}
  \put(5.4,1){$\bigwedge_{0,2}$}
\end{picture}
%\begin{figure}[floc5]
\begin{center}
  \psfig{file=floc5.eps}
\end{center}
%\end{figure}
\setlength{\unitlength}{.675cm}

\begin{picture}(15,.1)
  \put(-.3,1){$\coprod_{1,1}$}
  \put(3,1){$\coprod_{2,0}$}
  \put(6,1){$\bot$}
\end{picture}

\section{Example Computation}

Determining the contribution of each fixed locus is straight-forward but
laborious.  To give the reader an idea of the computation, we will find
the contribution of $\bigvee_{1,1}$

%\begin{figure}[fixloc3]
\begin{center}
  \psfig{file=fixloc3.eps}
\end{center}
%\end{figure}
Note that this fixed locus is paramterized by $\mc{1}{2}\times\mc{0}{4}$ where the elliptic curve is contracted to $0$ and the rational curve is contracted
to $\infty$.  This locus has $N_F=2$.
We must determine the normal bundle to this fixed locus.  This is done in
detail in \cite{K} and \cite{GP} so we will only give a very colloquial
explanation here.  We can think of the normal bundle as
being given by
\begin{equation}
\label{norm}
e(\nu)=\frac{e(\text{Node Resolutions})e(\text{Moving})}
{e(\text{Hodge})e(\text{Structure})e(\text{Automorphisms})}
\end{equation}
where Node Resolutions denote the bundle of deformations given
by resolving nodes, Moving, the bundle of deformations of the map from the 
trivial components, Hodge, the appropriate Hodge bundle, Structure, the 
bundle of equations on deforming the map that force the map to maintain its
dual graph, and Automorphisms, the bundle of automorphisms of the curve.
Here,
$$e(\text{Node Resolutions})=(-\psi_{\elli}+\hbar)
(-\psi_{\rat,1}-\hbar)(-\psi_{\rat,2}-\hbar)$$
where $\psi_\elli$ is the $\psi$-class at the node on the elliptic curve
and $\psi_{\rat,i}$ are the $\psi$-classes at the nodes on the rational
curve.
$$e(\text{Moving})=((-\hbar)(\hbar))^2$$
$$e(\text{Hodge})=\hbar-\lambda_1$$
where $\lambda_1$ is the first Hodge class on the moduli of elliptic curves.
$$e(\text{Structure})=-\hbar$$
which comes from the equation that forces the
two trivial components to meet at the collapsed rational curve.
$$e(\text{Automorphisms})=1$$
Therefore, we get
$$e(\nu)=\frac
{(\hbar+\psi_{\rat,1})(\hbar+\psi_{\rat,2})(\hbar-\psi_\elli)(\hbar^4)}
{(\hbar-\lambda_1)(-\hbar)}.
$$
On $L=\mc{1}{2}\times\mc{0}{4}$, the contribution is given by
$$\frac{\hbar^6}{e(\nu)}=-\frac{\hbar^6(\hbar-\lambda_1)\hbar}
{(\hbar+\psi_{\rat,1})(\hbar+\psi_{rat,2})(\hbar-\psi_\elli)\hbar^4}
=-\frac{\hbar(1-\frac{\lambda_1}{\hbar})}
{(1+\frac{\psi_{\rat,1}}{\hbar})(1+\frac{\psi_{\rat,2}}{\hbar})
(1-\frac{\psi_\elli}{\hbar})}.$$
The coefficient of $\hbar^0$ in the above is
\begin{equation}
\label{cont}
\lambda_1+\psi_{\rat,1}+\psi_{\rat,2}-\psi_\elli
\end{equation}
By standard string equation arguments, $\psi_{\rat,1}$ and $\psi_{rat,2}$
each force the rational curve to become a two component nodal curve with two 
special points on each components.  Therefore, $\psi_{rat,1}+\psi_{rat,2}$ 
evaluated
on the above fixed locus is
%\begin{figure}[ev1]
\begin{center}
  \psfig{file=ev1.eps}
\end{center}
%\end{figure}
where the short horizontal line is a node.  In other words, this is the
stratum parametrized by $\mc{1}{2}$ which consists of a one-pointed elliptic 
curve with contracted to $0$, a trivial component joining the elliptic
curve to a two component nodal rational curve.  Attached to one irreducible 
component of the nodal rational curve, there are two trivial component.  
Attached to the other component are two marked points mapping to $\infty$.  
And on the preimage of the trivial component disjoint from the elliptic curve
is a marked point that maps to $0$.  This pushes forward to $2\deli_{2,3}$. 
Since $\Aut(\pi_*L)=2$ and $N_{F_\un}=2$, we get a contribution of 
$8\deli_{2,3}$.


On $\mc{1}{1}$, $\psi_\elli=\lambda_1$, so on $\mc{1}{2}$,
$\psi_\elli$ and $\lambda_1$ differ only by a correction given by the
string equation.  It follows that $\psi_\elli-\lambda_1$ on $\mc{1}{2}$ is 
given by the $1$-dimensional locus where the two marked points are on a 
rational
component together.  Therefore the contribution of $\lambda_1-\psi_\elli$ is 
%\begin{figure}[ev2]
\begin{center}
  \psfig{file=ev2.eps}
\end{center}
%\end{figure}
This is parametrized by $\mc{1}{1}\times\mc{0}{4}$ and pushes foward 
to $-\deli_{3,4}$ with $\Aut(\pi_*L)=6$ and $N_{F_\un}=2$, so we get a 
contribution of $-12\deli_{3,4}$

\section{Contributions}

The result of the calculations for all the fixed locii is

\begin{eqnarray*}
\bigvee_{0,2}   & : & -4\deli_{2,4} \\
\bigvee_{1,1}   & : & -12\deli_{3,4}+8\deli_{2,3} \\
\bigvee_{2,0}   & : & 8\deli_{2,3}+8\deli_{2,4} \\
\top            & : & -\frac{8}{3}\deli_{0,2}-64\deli_{2,3}-64\deli_{2,4} \\
\prod_{2,0}     & : & 8\deli_{2,2}+20\deli_{2,3}+24\deli_{2,4}+\deli_{0,2} \\
\prod_{1,1}     & : & 16\deli_{2,2}+20\deli_{2,3}+32\deli_{2,4}+24\deli_{3,4}
+\frac{5}{3}\deli_{0,2}+2\deli_{0,3}+2\deli_{0,4} \\
\bigwedge_{0,2} & : & -4\deli_{2,4} \\
\bigwedge_{1,1} & : & -12\deli_{3,4}+8\deli_{2,3} \\ 
\bigwedge_{2,0} & : & 8\deli_{2,3}+8\deli_{2,4} \\
\bot            & : & -\frac{8}{3}\deli_{0,2}-64\deli_{2,3}-64\deli_{2,4} \\
\coprod_{2,0}   & : & 8\deli_{2,2}+20\deli_{2,3}+24\deli_{2,4}+\deli_{0,2} \\
\coprod_{1,1}   & : & 16\deli_{2,2}+20\deli_{2,3}+32\deli_{2,4}+24\deli_{3,4}
+\frac{5}{3}\deli_{0,2}+2\deli_{0,3}+2\deli_{0,4} \\
O               & : & -8\deli_b
\end{eqnarray*}

Their sum is
$$4(12\deli_{2,2}-4\deli_{2,3}-2\deli_{2,4}+6\deli_{3,4}+\deli_{0,3}
+\deli_{0,4}-2\deli_b)=0.$$
This is the Getzler relation.

\section{Conclusion}

The above method can be generalized and systematized in many directions.
An obvious question is to apply this method to derive the 
Belorousski-Pandharipande relation on $\mh$.  Another question are to 
systematize this method so that the computation can be done by a
computer or can be expressed in terms of a Feynman expansion of an
integral.  A humbler version of the above is to prove that there are 
non-trivial relations by automating the computation of the leading terms (the 
symbol) of such relations.  One also would like to study the structure 
of such relations.  It is likely that much work will be done along these 
lines by using
localization and degeneration methods in conjunction as in \cite{FP} and
\cite{GV}.

\bibliographystyle{plain}
\bibliography{trr}


\vspace{+10 pt}
\noindent
Department of Mathematics \\
Stanford University \\
eekatz@math.stanford.edu
\end{document}



\end{document}


trr.bbl
\begin{thebibliography}{1}

\bibitem{FP}
C.~Faber and R.~Pandharipande.
\newblock {R}elative maps and tautological classes.
\newblock {\em math.AG/0304485}.

\bibitem{G}
E.~Getzler.
\newblock Intersection theory on {$\overline{M}\sb {1,4}$} and elliptic
  {G}romov-{W}itten invariants.
\newblock {\em J. Amer. Math. Soc.}, 10(4):973--998, 1997.

\bibitem{GP}
T.~Graber and R.~Pandharipande.
\newblock Localization of virtual classes.
\newblock {\em Invent. Math.}, 135(2):487--518, 1999.

\bibitem{PO}
T.~Graber and R.~Vakil.
\newblock {R}elative virutal localization and vanishing of tautological classes
  on moduli spaces.
\newblock {\em math.AG/0309227}.

\bibitem{K}
M.~Kontsevich.
\newblock Enumeration of rational curves via torus actions.
\newblock In {\em The moduli space of curves (Texel Island, 1994)}, volume 129
  of {\em Progr. Math.}, pages 335--368. Birkh\"auser Boston, Boston, MA, 1995.

\bibitem{Li}
J.~Li.
\newblock A degeneration formula of {GW}-invariants.
\newblock {\em J. Differential Geom.}, 60(2):199--293, 2002.

\bibitem{GV}
A.~Okounkov and R.~Pandharipande.
\newblock {G}romov-{W}itten theory, {H}urwitz numbers, and {M}atrix models,
  {I}.
\newblock {\em math.AG/0101147}.

\bibitem{P}
R.~Pandharipande.
\newblock A geometric construction of {G}etzler's elliptic relation.
\newblock {\em Math. Ann.}, 313(4):715--729, 1999.

\end{thebibliography}
