Category : EmTeX is a TeX/LaTeX document editor
Archive   : PICTEX.ZIP
Filename : PICTEX.TEX
% 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
% ** 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
\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
% ** [
% ** \betweenarrows {TEXT} [orientation & shift] from XFROM YFROM to XTO YTO
% ** \arrow
% ** [
% ** 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.
% ** 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 [
% ** to XEND YEND
% ** \setbars [
% ** [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y]
% ** [endlabels ([E_ORIENTATION_x,E_ORIENTATION_y]
% ** \putbar [
% ** 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 [
% ** [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y]
% ** [endlabels ([E_ORIENTATION_x,E_ORIENTATION_y]
% ** 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 [
% ** and XCOORD2 YCOORD2
% ** \shaderectangleson
% ** \shaderectanglesoff
% ** \frame [
% ** \rectangle
%
%
% ** \putrectangle [
% ** 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
% ** 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 [
% ** 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
% ** 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
% ** 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
% ** \setdots
% ** \setdotsnear
% ** \setdashes
% ** \setdashesnear
% ** \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
% ** 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
% ** 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
% ** 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
% ** 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 [
% ** to XCOORD2 YCOORD2
% ** Internal commands:
% ** \!puthline [
% ** Set by dashpat to either: \!putsolidhline or \!putdashedhline
% ** \!putvline [
% ** Either: \!putsolidvline or \!putdashedvline
% ** \putrule [
% ** 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 [
% ** 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
% ** 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 [
% ** 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 [
% ** 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
% ** \setcoordinatesystem units
% ** \put {OBJECT} [ORIENTATION]
% ** \multiput {OJBECT} [ORIENTATION]
% ** XCOORD YCOORD
% ** *NUMBER_OF_TIMES DXCOORD DYCOORD /
% ** \accountingon
% ** \accountingoff
% ** \stack [ORIENTATION]
% ** \lines [ORIENTATION] {LINES}
% ** \Lines [ORIENTATION] {LINES}
% ** \setdimensionmode
% ** \setcoordinatemode
% ** \Xdistance
% ** \Ydistance
% ** Internal commands:
% ** \!setputobject{OBJECT}{[ORIENTATION]
% ** \!dimenput{OBJECT}[ORIENTATION]
% ** \!setdimenmode
% ** \!setcoordmode
% ** \!ifdimenmode
% ** \!ifcoordmode
% ** \beginpicture
% ** \endpicture
% ** \endpicturesave
% ** \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
% ** point at XREF YREF
% ** Each of `units
% ** 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]
% ** `[XY]' and `
% ** 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}
% ** 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]
% ** 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]
% ** \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
% ** 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
% ** 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\!ymidpt{\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 ] [point at XSHADE YSHADE]
% ** \setshadesymbol [
% **
% ** Internal commands:
% ** \!startvshade (xS,ybS,ytS)
% ** \!starthshade (yS,xlS,xrS)
% ** \!lshade [
% ** ** 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 [
% ** ** 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 ] [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 [
% **
% ** 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
% ** [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
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/