grunwald@uiucdcsm.cs.uiuc.edu (01/18/88)
this is part 2 of 3 of the PicTeX macros
----------------------------------------------------------------------
\!makeaxis
\fi}
\def\!makeaxis{%
\setbox\!boxA=\hbox{% (Make a pseudo-y[x] tick for an x[y]-axis)
\beginpicture
\!setdimenmode
\setcoordinatesystem point at {\!zpt} {\!zpt}
\putrule from {\!zpt} {\!zpt} to
{\!tickysign\!tickysign\!axisLength}
{\!tickxsign\!tickxsign\!axisLength}
\endpicturesave <\!Xsave,\!Ysave>}%
\wd\!boxA=\!zpt
\!placetick\!axisstart}
\def\!placeaxislabel{%
\advance\!offset \valuestolabelleading
\if!xswitch
\!dimenput {\the\!axisLaBeL} [\!axislabeltbrl]
<.5\!axisLength,\!tickysign\!offset> (\!axisxlevel,\!axisylevel)
\advance\!offset \!dp % ** advance offset by the "tallness"
\advance\!offset \!ht % ** of the label
\else
\!dimenput {\the\!axisLaBeL} [\!axislabeltbrl]
<\!tickxsign\!offset,.5\!axisLength> (\!axisxlevel,\!axisylevel)
\fi
\!axisLaBeL={}}
% *******************************
% *** ARROWS (Draws arrows) ***
% *******************************
%
% ** User commands
% ** \arrow <ARROW HEAD LENGTH> [MID FRACTION, BASE FRACTION]
% ** [<XSHIFT,YSHIFT>] from XFROM YFROM to XTO YTO
% ** \betweenarrows {TEXT} [orientation & shift] from XFROM YFROM to XTO YTO
% ** \arrow <ARROW HEAD LENGTH> [MID FRACTION, BASE FRACTION]
% ** [<XSHIFT,YSHIFT>] from XFROM YFROM to XTO YTO
% ** Draws an arrow from (XFROM,YFROM) to (XTO,YTO). The arrow head
% ** is constructed two quadratic arcs, which extend back a distance
% ** ARROW HEAD LENGTH (a dimension) on both sides of the arrow shaft.
% ** All the way back the arcs are a distance BASE FRACTION*ARROW HEAD
% ** LENGTH apart, while half-way back they are a distance MID FRACTION*
% ** ARROW HEAD LENGTH apart. <XSHIFT,YSHIFT> is optional, and has
% ** its usual interpreation. See Subsection 5.4 of the manual.
\def\arrow <#1> [#2,#3]{%
\!ifnextchar<{\!arrow{#1}{#2}{#3}}{\!arrow{#1}{#2}{#3}<\!zpt,\!zpt> }}
\def\!arrow#1#2#3<#4,#5> from #6 #7 to #8 #9 {%
%
% ** convert to dimensions
\!xloc=\!M{#8}\!xunit
\!yloc=\!M{#9}\!yunit
\!dxpos=\!xloc \!dimenA=\!M{#6}\!xunit \advance \!dxpos -\!dimenA
\!dypos=\!yloc \!dimenA=\!M{#7}\!yunit \advance \!dypos -\!dimenA
\let\!MAH=\!M% ** save current c/d mode
\!setdimenmode% ** go into dimension mode
%
\!xshift=#4\relax \!yshift=#5\relax% ** pick up shift
\!reverserotateonly\!xshift\!yshift% ** back rotate shift
\advance\!xshift\!xloc \advance\!yshift\!yloc
%
% ** draw shaft of arrow
\!xS=-\!dxpos \advance\!xS\!xshift
\!yS=-\!dypos \advance\!yS\!yshift
\!start (\!xS,\!yS)
\!ljoin (\!xshift,\!yshift)
%
% ** find 32*cosine and 32*sine of angle of rotation
\!Pythag\!dxpos\!dypos\!arclength
\!divide\!dxpos\!arclength\!dxpos
\!dxpos=32\!dxpos \!removept\!dxpos\!!cos
\!divide\!dypos\!arclength\!dypos
\!dypos=32\!dypos \!removept\!dypos\!!sin
%
% ** construct arrowhead
\!halfhead{#1}{#2}{#3}% ** draw half of arrow head
\!halfhead{#1}{-#2}{-#3}% ** draw other half
%
\let\!M=\!MAH% ** restore old c/d mode
\ignorespaces}
%
% ** draw half of arrow head
\def\!halfhead#1#2#3{%
\!dimenC=-#1%
\divide \!dimenC 2 % ** half way back
\!dimenD=#2\!dimenC% ** half the mid width
\!rotate(\!dimenC,\!dimenD)by(\!!cos,\!!sin)to(\!xM,\!yM)
\!dimenC=-#1% ** all the way back
\!dimenD=#3\!dimenC
\!dimenD=.5\!dimenD% ** half the full width
\!rotate(\!dimenC,\!dimenD)by(\!!cos,\!!sin)to(\!xE,\!yE)
\!start (\!xshift,\!yshift)
\advance\!xM\!xshift \advance\!yM\!yshift
\advance\!xE\!xshift \advance\!yE\!yshift
\!qjoin (\!xM,\!yM) (\!xE,\!yE)
\ignorespaces}
% ** \betweenarrows {TEXT} [orientation & shift] from XFROM YFROM to XTO YTO
% ** Makes things like <--- text --->, using arrow heads from TeX's fonts.
% ** See Subsection 5.4 of the manual.
\def\betweenarrows #1#2 from #3 #4 to #5 #6 {%
\!xloc=\!M{#3}\!xunit \!xxloc=\!M{#5}\!xunit%
\!yloc=\!M{#4}\!yunit \!yyloc=\!M{#6}\!yunit%
\!dxpos=\!xxloc \advance\!dxpos by -\!xloc
\!dypos=\!yyloc \advance\!dypos by -\!yloc
\advance\!xloc .5\!dxpos
\advance\!yloc .5\!dypos
%
\let\!MBA=\!M% ** save current coord\dimen mode
\!setdimenmode% ** express locations in dimens
\ifdim\!dypos=\!zpt
\ifdim\!dxpos<\!zpt \!dxpos=-\!dxpos \fi
\put {\!lrarrows{\!dxpos}{#1}}#2{} at {\!xloc} {\!yloc}
\else
\ifdim\!dxpos=\!zpt
\ifdim\!dypos<\!zpt \!dypos=-\!zpt \fi
\put {\!udarrows{\!dypos}{#1}}#2{} at {\!xloc} {\!yloc}
\fi
\fi
\let\!M=\!MBA% ** restore previous c/d mode
\ignorespaces}
% ** Subroutine for left-right between arrows
\def\!lrarrows#1#2{% #1=width, #2=text
{\setbox\!boxA=\hbox{$\mkern-2mu\mathord-\mkern-2mu$}%
\setbox\!boxB=\hbox{$\leftarrow$}\!dimenE=\ht\!boxB
\setbox\!boxB=\hbox{}\ht\!boxB=2\!dimenE
\hbox to #1{$\mathord\leftarrow\mkern-6mu
\cleaders\copy\!boxA\hfil
\mkern-6mu\mathord-$%
\kern.4em $\vcenter{\box\!boxB}$$\vcenter{\hbox{#2}}$\kern.4em
$\mathord-\mkern-6mu
\cleaders\copy\!boxA\hfil
\mkern-6mu\mathord\rightarrow$}}}
% ** Subroutine for up-down between arrows
\def\!udarrows#1#2{% #1=width, #2=text
{\setbox\!boxB=\hbox{#2}%
\setbox\!boxA=\hbox to \wd\!boxB{\hss$\vert$\hss}%
\!dimenE=\ht\!boxA \advance\!dimenE \dp\!boxA \divide\!dimenE 2
\vbox to #1{\offinterlineskip
\vskip .05556\!dimenE
\hbox to \wd\!boxB{\hss$\mkern.4mu\uparrow$\hss}\vskip-\!dimenE
\cleaders\copy\!boxA\vfil
\vskip-\!dimenE\copy\!boxA
\vskip\!dimenE\copy\!boxB\vskip.4em
\copy\!boxA\vskip-\!dimenE
\cleaders\copy\!boxA\vfil
\vskip-\!dimenE \hbox to \wd\!boxB{\hss$\mkern.4mu\downarrow$\hss}
\vskip .05556\!dimenE}}}
% ***************************
% *** BARS (Draws bars) ***
% ***************************
%
% ** User commands:
% ** \putbar [<XSHIFT,YSHIFT>] breadth <BREADTH> from XSTART YSTART
% ** to XEND YEND
% ** \setbars [<XSHIFT,YSHIFT>] breadth <BREADTH> baseline at XY = COORD
% ** [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y] <B_XSHIFT,B_YSHIFT>)]
% ** [endlabels ([E_ORIENTATION_x,E_ORIENTATION_y] <E_XSHIFT,E_YSHIFT>)]
% ** \putbar [<XSHIFT,YSHIFT>] breadth <BREADTH> from XSTART YSTART
% ** to XEND YEND
% ** Either XSTART=XEND or YSTART=YEND. Draws a rectangle between
% ** (XSTART,YSTART) & (XEND,YEND). The "depth" of the rectangle
% ** is determined by those two plot positions; its other
% ** dimension "breadth" is specified by the dimension BREADTH.
% ** See Subsection 4.2 of the manual.
\def\putbar#1breadth <#2> from #3 #4 to #5 #6 {%
\!xloc=\!M{#3}\!xunit \!xxloc=\!M{#5}\!xunit%
\!yloc=\!M{#4}\!yunit \!yyloc=\!M{#6}\!yunit%
\!dypos=\!yyloc \advance\!dypos by -\!yloc
\!dimenI=#2
%
\ifdim \!dimenI=\!zpt % ** If 0 breadth
\putrule#1from {#3} {#4} to {#5} {#6} % ** Then draw line
\else % ** Else, put in a rectangle
\let\!MBar=\!M% ** save current c/d mode
\!setdimenmode % ** go into dimension mode
\divide\!dimenI 2
\ifdim \!dypos=\!zpt
\advance \!yloc -\!dimenI % ** Equal y coordinates
\advance \!yyloc \!dimenI
\else
\advance \!xloc -\!dimenI % ** Equal x coordinates
\advance \!xxloc \!dimenI
\fi
\putrectangle#1corners at {\!xloc} {\!yloc} and {\!xxloc} {\!yyloc}
\let\!M=\!MBar % ** restore c/d mode
\fi
\ignorespaces}
% ** \setbars [<XSHIFT,YSHIFT>] breadth <BREADTH> baseline at XY = COORD
% ** [baselabels ([B_ORIENTATION_x,B_ORIENTATION_y] <B_XSHIFT,B_YSHIFT>)]
% ** [endlabels ([E_ORIENTATION_x,E_ORIENTATION_y] <E_XSHIFT,E_YSHIFT>)]
% ** This command puts PiCTeX into the bar graph drawing mode described
% ** in Subsection 4.4 of the manual.
\def\setbars#1breadth <#2> baseline at #3 = #4 {%
\edef\!barshift{#1}%
\edef\!barbreadth{#2}%
\edef\!barorientation{#3}%
\edef\!barbaseline{#4}%
\def\!bardobaselabel{\!bardoendlabel}%
\def\!bardoendlabel{\!barfinish}%
\let\!drawcurve=\!barcurve
\!setbars}
\def\!setbars{%
\futurelet\!nextchar\!!setbars}
\def\!!setbars{%
\if b\!nextchar
\def\!!!setbars{\!setbarsbget}%
\else
\if e\!nextchar
\def\!!!setbars{\!setbarseget}%
\else
\def\!!!setbars{\relax}%
\fi
\fi
\!!!setbars}
\def\!setbarsbget baselabels (#1) {%
\def\!barbaselabelorientation{#1}%
\def\!bardobaselabel{\!!bardobaselabel}%
\!setbars}
\def\!setbarseget endlabels (#1) {%
\edef\!barendlabelorientation{#1}%
\def\!bardoendlabel{\!!bardoendlabel}%
\!setbars}
% ** \!barcurve
% ** Draws a bargraph with preset values of barshift, barbreadth,
% ** barorientation (x or y) and barbaseline (coordinate)
\def\!barcurve #1 #2 {%
\if y\!barorientation
\def\!basexarg{#1}%
\def\!baseyarg{\!barbaseline}%
\else
\def\!basexarg{\!barbaseline}%
\def\!baseyarg{#2}%
\fi
\expandafter\putbar\!barshift breadth <\!barbreadth> from {\!basexarg}
{\!baseyarg} to {#1} {#2}
\def\!endxarg{#1}%
\def\!endyarg{#2}%
\!bardobaselabel}
\def\!!bardobaselabel "#1" {%
\put {#1}\!barbaselabelorientation{} at {\!basexarg} {\!baseyarg}
\!bardoendlabel}
\def\!!bardoendlabel "#1" {%
\put {#1}\!barendlabelorientation{} at {\!endxarg} {\!endyarg}
\!barfinish}
\def\!barfinish{%
\!ifnextchar/{\!finish}{\!barcurve}}
% ********************************
% *** BOXES (Draws rectangles) ***
% ********************************
%
% ** User commands:
% ** \putrectangle [<XSHIFT,YSHIFT>] corners at XCOORD1 YCOORD1
% ** and XCOORD2 YCOORD2
% ** \shaderectangleson
% ** \shaderectanglesoff
% ** \frame [<SEPARATION>] {TEXT}
% ** \rectangle <WIDTH> <HEIGHT>
%
%
% ** \putrectangle [<XSHIFT,YSHIFT>] corners at XCOORD1 YCOORD1
% ** and XCOORD2 YCOORD2
% ** Draws a rectangle with corners at (X1,Y1), (X2,Y1), (X1,Y2), (X2,Y2)
% ** Lines have thickness \linethickness, and overlap at the corners.
% ** The optional field <XSHIFT,YSHIFT> functions as with a \put command.
% ** See Subsection 4.2 of the manual.
\def\putrectangle{%
\!ifnextchar<{\!putrectangle}{\!putrectangle<\!zpt,\!zpt> }}
\def\!putrectangle<#1,#2> corners at #3 #4 and #5 #6 {%
%
% ** get locations
\!xone=\!M{#3}\!xunit \!xtwo=\!M{#5}\!xunit%
\!yone=\!M{#4}\!yunit \!ytwo=\!M{#6}\!yunit%
\ifdim \!xtwo<\!xone
\!dimenI=\!xone \!xone=\!xtwo \!xtwo=\!dimenI
\fi
\ifdim \!ytwo<\!yone
\!dimenI=\!yone \!yone=\!ytwo \!ytwo=\!dimenI
\fi
\!dimenI=#1\relax \advance\!xone\!dimenI \advance\!xtwo\!dimenI
\!dimenI=#2\relax \advance\!yone\!dimenI \advance\!ytwo\!dimenI
\let\!MRect=\!M% ** save current coord/dimen mode
\!setdimenmode
%
% ** shade rectangle if appropriate
\!shaderectangle
%
% ** draw horizontal edges
\!dimenI=.5\linethickness
\advance \!xone -\!dimenI% ** adjust x-location to overlap corners
\advance \!xtwo \!dimenI% ** ditto
\putrule from {\!xone} {\!yone} to {\!xtwo} {\!yone}
\putrule from {\!xone} {\!ytwo} to {\!xtwo} {\!ytwo}
%
% ** draw vertical edges
\advance \!xone \!dimenI% ** restore original x-values
\advance \!xtwo -\!dimenI%
\advance \!yone -\!dimenI% ** adjust y-location to overlap corners
\advance \!ytwo \!dimenI% ** ditto
\putrule from {\!xone} {\!yone} to {\!xone} {\!ytwo}
\putrule from {\!xtwo} {\!yone} to {\!xtwo} {\!ytwo}
%
\let\!M=\!MRect% ** restore coord/dimen mode
\ignorespaces}
% ** \shaderectangleson
% ** Subsequent rectangles will be shaded according to
% ** the current shading pattern. Affects \putrectangle, \putbar,
% ** \frame, \sethistograms, and \setbars. See Subsection 7.5 of the manual.
\def\shaderectangleson{%
\def\!shaderectangle{\!!shaderectangle}%
\ignorespaces}
% ** \shaderectanglesoff
% ** Suppresses \shaderectangleson. The default.
\def\shaderectanglesoff{%
\def\!shaderectangle{}%
\ignorespaces}
\shaderectanglesoff
% ** The following internal routine shades the current rectangle, when
% ** \!shaderectangle = \!!shaderectangle .
\def\!!shaderectangle{%
\!dimenA=\!xtwo \advance \!dimenA -\!xone
\!dimenB=\!ytwo \advance \!dimenB -\!yone
\ifdim \!dimenA<\!dimenB
\!startvshade (\!xone,\!yone,\!ytwo)
\!lshade (\!xtwo,\!yone,\!ytwo)
\else
\!starthshade (\!yone,\!xone,\!xtwo)
\!lshade (\!ytwo,\!xone,\!xtwo)
\fi
\ignorespaces}
% ** \frame [<SEPARATION>] {TEXT}
% ** Draws a frame of thickness linethickness about the box enclosing
% ** TEXT; the frame is separated from the box by a distance of
% ** SEPARATION. The result is an hbox with the same baseline as TEXT.
% ** If <SEPARATION> is omitted, you get the effect of <0pt>.
% ** See Subsection 4.2 of the manual.
\def\frame{%
\!ifnextchar<{\!frame}{\!frame<\!zpt> }}
\long\def\!frame<#1> #2{%
\beginpicture
\setcoordinatesystem units <1pt,1pt> point at 0 0
\put {#2} [Bl] at 0 0
\!dimenA=#1\relax
\!dimenB=\!wd \advance \!dimenB \!dimenA
\!dimenC=\!ht \advance \!dimenC \!dimenA
\!dimenD=\!dp \advance \!dimenD \!dimenA
\let\!MFr=\!M
\!setdimenmode
\putrectangle corners at {-\!dimenA} {-\!dimenD} and {\!dimenB} {\!dimenC}
\!setcoordmode
\let\!M=\!MFr
\endpicture
\ignorespaces}
% ** \rectangle <WIDTH> <HEIGHT>
% ** Constructs a rectangle of width WIDTH and heigth HEIGHT.
% ** See Subsection 4.2 of the manual.
\def\rectangle <#1> <#2> {%
\setbox0=\hbox{}\wd0=#1\ht0=#2\frame {\box0}}
% *********************************************
% *** CURVES (Upper level \plot commands) ***
% *********************************************
%
% ** User commands
% ** \plot DATA /
% ** \plot "FILE NAME"
% ** \setquadratic
% ** \setlinear
% ** \sethistograms
% ** \vshade ...
% ** \hshade ...
% \plot: multi-purpose command. Draws histograms, bar graphs, piecewise-linear
% or piecewise quadratic curves, depending on the setting of \!drawcurve.
% See Subsections 4.3-4.5, 5.1, 5.2 of the manual.
\def\plot{%
\!ifnextchar"{\!plotfromfile}{\!drawcurve}}
\def\!plotfromfile"#1"{%
\expandafter\!drawcurve \input #1 /}
% Command to set piecewise quadratic mode
% See Subsections 5.1, 7.3, and 7.4 of the manual.
\def\setquadratic{%
\let\!drawcurve=\!qcurve
\let\!!Shade=\!!qShade
\let\!!!Shade=\!!!qShade}
% Command to set piecewise linear mode
% See Subsections 5.1, 7.3, and 7.4 of the manual.
\def\setlinear{%
\let\!drawcurve=\!lcurve
\let\!!Shade=\!!lShade
\let\!!!Shade=\!!!lShade}
% Command to set histogram mode
% See Subsection 4.3 of the manual.
\def\sethistograms{%
\let\!drawcurve=\!hcurve}
% Commands to cycle through list of coordinates in piecewise quadratic
% interpolation mode
\def\!qcurve #1 #2 {%
\!start (#1,#2)
\!Qjoin}
\def\!Qjoin#1 #2 #3 #4 {%
\!qjoin (#1,#2) (#3,#4) % \!qjoin is defined in QUADRATIC
\!ifnextchar/{\!finish}{\!Qjoin}}
% Commands to cycle through list of coordinates in piecewise linear
% interpolation mode
\def\!lcurve #1 #2 {%
\!start (#1,#2)
\!Ljoin}
\def\!Ljoin#1 #2 {%
\!ljoin (#1,#2) % \!ljoin is defined in LINEAR
\!ifnextchar/{\!finish}{\!Ljoin}}
\def\!finish/{\ignorespaces}
% Command to cycle through list of coordinates in histogram mode
\def\!hcurve #1 #2 {%
\edef\!hxS{#1}%
\edef\!hyS{#2}%
\!hjoin}
\def\!hjoin#1 #2 {%
\putrectangle corners at {\!hxS} {\!hyS} and {#1} {#2}
\edef\!hxS{#1}%
\!ifnextchar/{\!finish}{\!hjoin}}
% \vshade: See Subsection 7.3 of the manual.
\def\vshade #1 #2 #3 {%
\!startvshade (#1,#2,#3)
\!Shadewhat}
% \hshade: See Subsection 7.4 of the manual.
\def\hshade #1 #2 #3 {%
\!starthshade (#1,#2,#3)
\!Shadewhat}
% Commands to cycle through coordinates and optional "edge effect"
% fields while shading.
\def\!Shadewhat{%
\futurelet\!nextchar\!Shade}
\def\!Shade{%
\if <\!nextchar
\def\!nextShade{\!!Shade}%
\else
\if /\!nextchar
\def\!nextShade{\!finish}%
\else
\def\!nextShade{\!!!Shade}%
\fi
\fi
\!nextShade}
\def\!!lShade<#1> #2 #3 #4 {%
\!lshade <#1> (#2,#3,#4) % \!lshade is defined in SHADING
\!Shadewhat}
\def\!!!lShade#1 #2 #3 {%
\!lshade (#1,#2,#3)
\!Shadewhat}
\def\!!qShade<#1> #2 #3 #4 #5 #6 #7 {%
\!qshade <#1> (#2,#3,#4) (#5,#6,#7) % \!qshade is defined in SHADING
\!Shadewhat}
\def\!!!qShade#1 #2 #3 #4 #5 #6 {%
\!qshade (#1,#2,#3) (#4,#5,#6)
\!Shadewhat}
% ** Set default interpolation mode
\setlinear
% ********************************************
% *** DASHPATTERNS (Sets up dash patterns) ***
% ********************************************
% ** User commands:
% ** \setdashpattern <DIMEN1,DIMEN2,DIMEN3,...>
% ** \setdots <INTRADOT_DISTANCE>
% ** \setdotsnear <INTRADOT_DISTANCE> for <ARC LENGTH>
% ** \setdashes <DASH/SKIP_DISTANCE>
% ** \setdashesnear <DASH/SKIP_DISTANCE> for <ARC LENGTH>
% ** \setsolid
% ** \findlength {CURVE CMDS}
% ** Internal commands:
% ** \!dashingon
% ** \!dashingoff
% ** Dash patterns are specified by a balanced token list whose complete
% ** expansion has the form: DIMEN1,DIMEN2,DIMEN3,DIMEN4,... ; this produces
% ** an arc of length DIMEN1, a skip of length DIMEN2, an arc of length
% ** DIMEN3, a skip of length DIMEN4, ... . Any number of DIMEN values may
% ** be given. The pattern is repeated as many times (perhaps fractional)
% ** as necessary to draw the curve.
% ** A dash pattern remains in effect until it is overridden by a call to
% ** \setdashpattern, or to \setdots, \setdotsnear ... , \setdashes,
% ** \setdashesnear ... , or \setsolid.
% ** Solid lines are the default.
% ** \def\setdashpattern <DIMEN1,DIMEN2,DIMEN3,...>
% ** The following routine converts a balanced list of tokens whose
% ** complete expansion has the form DIMEN1,DIMEN2, ... , DIMENk into
% ** three list macros that are used in drawing dashed rules and curves:
% ** !Flist: \!Rule{DIMEN1}\!Skip{DIMEN2}\!Rule{DIMEN3}\!Skip{DIMEN4} ...
% ** !Blist: ...\!Skip{DIMEN4}\!Rule{DIMEN3}\!Skip{DIMEN2}\!Rule{DIMEN1}
% ** !UDlist: \\{DIMEN1}\\{DIMEN2}\\{DIMEN3}\\{DIMEN4} ...;
% ** calculates \!leaderlength := DIMEN1 + ... + DIMENk; and
% ** sets the curve drawing routines to dash mode.
% ** Those lists are used by the curve drawing routines.
% ** Dimenj ... may be given as an explicit dimension (e.g., 5pt), or
% ** as an expression involving a dimension register (e.g., -2.5\dimen0).
% ** See Subsection 6.2 of the manual
\def\setdashpattern <#1>{%
\def\!Flist{}\def\!Blist{}\def\!UDlist{}%
\!countA=0
\!ecfor\!item:=#1\do{%
\!dimenA=\!item\relax
\expandafter\!rightappend\the\!dimenA\withCS{\\}\to\!UDlist%
\advance\!countA 1
\ifodd\!countA
\expandafter\!rightappend\the\!dimenA\withCS{\!Rule}\to\!Flist%
\expandafter\!leftappend\the\!dimenA\withCS{\!Rule}\to\!Blist%
\else
\expandafter\!rightappend\the\!dimenA\withCS{\!Skip}\to\!Flist%
\expandafter\!leftappend\the\!dimenA\withCS{\!Skip}\to\!Blist%
\fi}%
\!leaderlength=\!zpt
\def\!Rule##1{\advance\!leaderlength ##1}%
\def\!Skip##1{\advance\!leaderlength ##1}%
\!Flist%
\ifdim\!leaderlength>\!zpt
\else
\def\!Flist{\!Skip{24in}}\def\!Blist{\!Skip{24in}}\ignorespaces
\def\!UDlist{\\{\!zpt}\\{24in}}\ignorespaces
\!leaderlength=24in
\fi
\!dashingon}
% ** \!dashingon -- puts the curve drawing routines into dash mode
% ** \!dashingoff -- puts the curve drawing routines into solid mode
% ** These are internal commands, invoked by \setdashpattern and \setsolid
\def\!dashingon{%
\def\!advancedashing{\!!advancedashing}%
\def\!drawlinearsegment{\!lineardashed}%
\def\!puthline{\!putdashedhline}%
\def\!putvline{\!putdashedvline}%
% \def\!putsline{\!putdashedsline}%
\ignorespaces}%
\def\!dashingoff{%
\def\!advancedashing{\relax}%
\def\!drawlinearsegment{\!linearsolid}%
\def\!puthline{\!putsolidhline}%
\def\!putvline{\!putsolidvline}%
% \def\!putsline{\!putsolidsline}%
\ignorespaces}
% ** \setdots <LENGTH> -- sets up a dot/skip pattern where dot (actually
% ** the current plotsymbol) is plunked down once for every LENGTH
% ** traveled along the curve. LENGTH defaults to 5pt.
% ** See Subsection 6.1 of the manual.
\def\setdots{%
\!ifnextchar<{\!setdots}{\!setdots<5pt>}}
\def\!setdots<#1>{%
\!dimenB=#1\advance\!dimenB -\plotsymbolspacing
\ifdim\!dimenB<\!zpt
\!dimenB=\!zpt
\fi
\setdashpattern <\plotsymbolspacing,\!dimenB>}
% ** \setdotsnear <LENGTH> for <ARC LENGTH>
% ** sets up a dot pattern where the dots are approximately LENGTH apart,
% ** the total length of the pattern is ARC LENGTH, and the pattern
% ** begins and ends with a dot. See Subsection 6.3 of the manual.
\def\setdotsnear <#1> for <#2>{%
\!dimenB=#2\relax \advance\!dimenB -.05pt
\!dimenC=#1\relax \!countA=\!dimenC
\!dimenD=\!dimenB \advance\!dimenD .5\!dimenC \!countB=\!dimenD
\divide \!countB \!countA
\ifnum 1>\!countB
\!countB=1
\fi
\divide\!dimenB \!countB
\setdots <\!dimenB>}
% ** \setdashes <LENGTH> -- sets up a dash/skip pattern where the dash
% ** and the skip are each of length LENGTH (the dash is formed by
% ** plunking down the current plotsymbol over an arc of length LENGTH
% ** and so may actually be longer than LENGTH. LENGTH defaults to 5pt.
% ** See Subsection 6.1 of the manual.
\def\setdashes{%
\!ifnextchar<{\!setdashes}{\!setdashes<5pt>}}
\def\!setdashes<#1>{\setdashpattern <#1,#1>}
% ** \setdashesnear ...
% ** Like \setdotsnear; the pattern begins and ends with a dash.
% ** See Subsection 6.3 of the manual.
\def\setdashesnear <#1> for <#2>{%
\!dimenB=#2\relax
\!dimenC=#1\relax \!countA=\!dimenC
\!dimenD=\!dimenB \advance\!dimenD .5\!dimenC \!countB=\!dimenD
\divide \!countB \!countA
\ifodd \!countB
\else
\advance \!countB 1
\fi
\divide\!dimenB \!countB
\setdashes <\!dimenB>}
% ** \setsolid -- puts the curve drawing routines in "solid line" mode,
% ** the default mode. See Subsection 6.1 of the manual.
\def\setsolid{%
\def\!Flist{\!Rule{24in}}\def\!Blist{\!Rule{24in}}%
\def\!UDlist{\\{24in}\\{\!zpt}}%
\!dashingoff}
\setsolid
% ** \findlength {CURVE CMDS}
% ** PiCTeX executes the \start, \ljoin, and \qjoin cmds comprising
% ** CURVE CMDS without plotting anything, but stashes the length
% ** of the phantom curve away in \totalarclength.
% ** See Subsection 6.3 of the manual.
\def\findlength#1{%
\begingroup
\setdashpattern <0pt, \maxdimen>
\setplotsymbol ({})
\dontsavelinesandcurves
#1%
\endgroup
\ignorespaces}
% *************************************************************
% *** DIVISION (Does long division of dimension registers) ***
% *************************************************************
% ** User command:
% ** \Divide {DIVIDEND} by {DIVISOR} forming {RESULT}
% ** Internal command
% ** \!divide{DIVIDEND}{DIVISOR}{RESULT}
% ** \!divide DIVIDEND [by] DIVISOR [to get] ANSWER
% ** Divides the dimension DIVIDEND by the dimension DIVISOR, placing the
% ** quotient in the dimension register ANSWER. Values are understood to
% ** be in points. E.g. 12.5pt/1.4pt=8.92857pt.
% ** Quotient is accurate to 1/65536pt=2**[-16]pt
% ** |DIVISOR| should be < 2048pt (about 28 inches).
\def\!divide#1#2#3{%
\!dimenB=#1% ** dimB holds current remainder (r)
\!dimenC=#2% ** dimC holds divisor (d)
\!dimenD=\!dimenB% ** dimD holds quotient q=r/d for this
\divide \!dimenD \!dimenC% ** step, in units of scaled pts
\!dimenA=\!dimenD% ** dimA eventually holds answer (a)
\multiply\!dimenD \!dimenC% ** r <-- r - dq
\advance\!dimenB -\!dimenD% ** First step complete. Have integer part
% ** of a, and corresponding remainder.
\!dimenD=\!dimenC% ** Temporarily use dimD to hold |d|
\ifdim\!dimenD<\!zpt \!dimenD=-\!dimenD
\fi
\ifdim\!dimenD<64pt% ** Branch on the magnitude of |d|
\!divstep[\!tfs]\!divstep[\!tfs]%
\else
\!!divide
\fi
#3=\!dimenA\ignorespaces}
% ** The following code handles divisors d with
% ** (1) .88in = 64pt <= d < 256pt = 3.54in
% ** (2) 3.54in = 256pt <= d < 2048pt = 28.34in
% ** Anything bigger than that may result in an overflow condition.
% ** For our purposes, we should never even see case (2).
\def\!!divide{%
\ifdim\!dimenD<256pt
\!divstep[64]\!divstep[32]\!divstep[32]%
\else
\!divstep[8]\!divstep[8]\!divstep[8]\!divstep[8]\!divstep[8]%
\!dimenA=2\!dimenA
\fi}
% ** The following macro does the real long division work.
\def\!divstep[#1]{% ** #1 = "B"
\!dimenB=#1\!dimenB% ** r <-- B*r
\!dimenD=\!dimenB% ** dimD holds quotient q=r/d for this
\divide \!dimenD by \!dimenC% ** step, in units of scaled pts
\!dimenA=#1\!dimenA% ** a <-- B*a + q
\advance\!dimenA by \!dimenD%
\multiply\!dimenD by \!dimenC% ** r <-- r - dq
\advance\!dimenB by -\!dimenD}
% ** \Divide: See Subsection 9.3 of the manual.
\def\Divide <#1> by <#2> forming <#3> {%
\!divide{#1}{#2}{#3}}
% *********************************************
% *** ELLIPSES (Draws ellipses and circles) ***
% *********************************************
% ** User commands
% ** \ellipticalarc axes ratio A:B DEGREES degrees from XSTART YSTART
% ** center at XCENTER YCENTER
% ** \circulararc DEGREES degrees from XSTART YSTART
% ** center at XCENTER YCENTER
% ** Internal command
% ** \!sinandcos{32*ANGLE in radians}{32*SIN}{32*COS}
% ** \ellipticalarc axes ratio A:B DEGREES degrees from XSTART YSTART
% ** center at XCENTER YCENTER
% ** Draws a elliptical arc starting at the coordinate point (XSTART,YSTART).
% ** The center of the ellipse of which the arc is a segment is at
% ** (XCENTER,YCENTER).
% ** The arc extends through an angle of DEGREES degrees (may be + or -).
% ** A:B is the ratio of the length of the xaxis to the length of
% ** the yaxis of the ellipse
% ** Sqrt{[(XSTART-XCENTER)/A]**2 + [(YSTART-YCENTER)/B]**2}
% ** must be < 512pt (about 7in).
% ** Doesn't modify the dimensions (ht, dp, wd) of the PiCture under
% ** construction.
% ** \circulararc -- See Subsection 5.3 of the manual.
\def\circulararc{%
\ellipticalarc axes ratio 1:1 }
% ** \ellipticalarc -- See Subsection 5.3 of the manual.
\def\ellipticalarc axes ratio #1:#2 #3 degrees from #4 #5 center at #6 #7 {%
\!angle=#3pt\relax% ** get angle
\ifdim\!angle>\!zpt
\def\!sign{}% ** counterclockwise
\else
\def\!sign{-}\!angle=-\!angle% ** clockwise
\fi
\!xxloc=\!M{#6}\!xunit% ** convert CENTER to dimension
\!yyloc=\!M{#7}\!yunit
\!xxS=\!M{#4}\!xunit% ** get STARTing point on rim of ellipse
\!yyS=\!M{#5}\!yunit
\advance\!xxS -\!xxloc% ** make center of ellipse (0,0)
\advance\!yyS -\!yyloc
\!divide\!xxS{#1pt}\!xxS % ** scale point on ellipse to point on
\!divide\!yyS{#2pt}\!yyS % corresponding circle
%
\let\!MC=\!M% ** save current c/d mode
\!setdimenmode% ** go into dimension mode
%
\!xS=#1\!xxS \advance\!xS\!xxloc
\!yS=#2\!yyS \advance\!yS\!yyloc
\!start (\!xS,\!yS)%
\!loop\ifdim\!angle>14.9999pt% ** draw in major portion of ellipse
\!rotate(\!xxS,\!yyS)by(\!cos,\!sign\!sin)to(\!xxM,\!yyM)
\!rotate(\!xxM,\!yyM)by(\!cos,\!sign\!sin)to(\!xxE,\!yyE)
\!xM=#1\!xxM \advance\!xM\!xxloc \!yM=#2\!yyM \advance\!yM\!yyloc
\!xE=#1\!xxE \advance\!xE\!xxloc \!yE=#2\!yyE \advance\!yE\!yyloc
\!qjoin (\!xM,\!yM) (\!xE,\!yE)
\!xxS=\!xxE \!yyS=\!yyE
\advance \!angle -15pt
\repeat
\ifdim\!angle>\!zpt% ** complete remaining arc, if any
\!angle=100.53096\!angle% ** convert angle to radians, divide
\divide \!angle 360 % ** by 2, and multiply by 32
\!sinandcos\!angle\!!sin\!!cos% ** get 32*sin & 32*cos
\!rotate(\!xxS,\!yyS)by(\!!cos,\!sign\!!sin)to(\!xxM,\!yyM)
\!rotate(\!xxM,\!yyM)by(\!!cos,\!sign\!!sin)to(\!xxE,\!yyE)
\!xM=#1\!xxM \advance\!xM\!xxloc \!yM=#2\!yyM \advance\!yM\!yyloc
\!xE=#1\!xxE \advance\!xE\!xxloc \!yE=#2\!yyE \advance\!yE\!yyloc
\!qjoin (\!xM,\!yM) (\!xE,\!yE)
\fi
%
\let\!M=\!MC% ** restore c/d mode
\ignorespaces}% ** if appropriate
% ** \!rotate(XREG,YREG)by(32cos,32sin)to(XXREG,YYREG)
% ** rotates (XREG,YREG) by angle with specfied scaled cos & sin to
% ** (XXREG,YYREG). Uses \!dimenA & \!dimenB as scratch registers.
\def\!rotate(#1,#2)by(#3,#4)to(#5,#6){%
\!dimenA=#3#1\advance \!dimenA -#4#2% ** Rcos(x+t)=Rcosx*cost - Rsinx*sint
\!dimenB=#3#2\advance \!dimenB #4#1% ** Rsin(x+t)=Rsinx*cost + Rcosx*sint
\divide \!dimenA 32 \divide \!dimenB 32
#5=\!dimenA #6=\!dimenB
\ignorespaces}
\def\!sin{4.17684}% ** 32*sin(pi/24) (pi/24=7.5deg)
\def\!cos{31.72624}% ** 32*cos(pi/24)
% ** \!sinandcos{32*ANGLE in radians}{\SINCS}{\COSCS}
% ** Computes the 32*sine and 32*cosine of a small ANGLE expressed in
% ** radians/32 and puts these values in the replacement texts of
% ** \SINCS and \COSCS
\def\!sinandcos#1#2#3{%
\!dimenD=#1% ** angle is expressed in radians/32: 1pt = 1/32rad
\!dimenA=\!dimenD% ** dimA will eventually contain 32sin(angle)in pts
\!dimenB=32pt% ** dimB will eventually contain 32cos(angle)in pts
\!removept\!dimenD\!value% ** get value of 32*angle, without "pt"
\!dimenC=\!dimenD% ** holds 32*angle**i/i! in pts
\!dimenC=\!value\!dimenC \divide\!dimenC by 64 % ** now 32*angle**2/2
\advance\!dimenB by -\!dimenC% ** 32-32*angle**2/2
\!dimenC=\!value\!dimenC \divide\!dimenC by 96 % ** now 32*angle**3/3!
\advance\!dimenA by -\!dimenC% ** now 32*(angle-angle**3/6)
\!dimenC=\!value\!dimenC \divide\!dimenC by 128 % ** now 32*angle**4/4!
\advance\!dimenB by \!dimenC%
\!removept\!dimenA#2% ** set 32*sin(angle)
\!removept\!dimenB#3% ** set 32*cos(angle)
\ignorespaces}
% *****************************************************************
% *** RULES (Draws rules, i.e., horizontal & vertical lines) ***
% *****************************************************************
% ** User command:
% ** \putrule [<XDIMEN,YDIMEN>] from XCOORD1 YCOORD1
% ** to XCOORD2 YCOORD2
% ** Internal commands:
% ** \!puthline [<XDIMEN,YDIMEN>] (h = horizontal)
% ** Set by dashpat to either: \!putsolidhline or \!putdashedhline
% ** \!putvline [<XDIMEN,YDIMEN>] (v = vertical)
% ** Either: \!putsolidvline or \!putdashedvline
% ** \putrule [<XDIMEN,YDIMEN>] from XCOORD1 YCOORD1
% ** to XCOORD2 YCOORD2
% ** Draws a rule -- dashed or solid depending on the current dash pattern --
% ** from (X1,Y1) to (X2,Y2). Uses TEK's \hrule & \vrule & \leaders
% ** constructions to handle horizontal & vertical lines efficiently both
% ** in terms of execution time and space in the DVI file.
% ** See Subsection 4.1 of the manual.
\def\putrule#1from #2 #3 to #4 #5 {%
\!xloc=\!M{#2}\!xunit \!xxloc=\!M{#4}\!xunit%
\!yloc=\!M{#3}\!yunit \!yyloc=\!M{#5}\!yunit%
\!dxpos=\!xxloc \advance\!dxpos by -\!xloc
\!dypos=\!yyloc \advance\!dypos by -\!yloc
%
\ifdim\!dypos=\!zpt
\def\!!Line{\!puthline{#1}}\ignorespaces
\else
\ifdim\!dxpos=\!zpt
\def\!!Line{\!putvline{#1}}\ignorespaces
\else
\def\!!Line{}
\fi
\fi
\let\!ML=\!M% ** save current coord\dimen mode
\!setdimenmode% ** express locations in dimens
\!!Line%
\let\!M=\!ML% ** restore previous c/d mode
\ignorespaces}
% ** \!putsolidhline [<XDIMEN,YDIMEN>]
% ** Place horizontal solid line
\def\!putsolidhline#1{%
\ifdim\!dxpos>\!zpt
\put{\!hline\!dxpos}#1[l] at {\!xloc} {\!yloc}
\else
\put{\!hline{-\!dxpos}}#1[l] at {\!xxloc} {\!yyloc}
\fi
\ignorespaces}
% ** \!putsolidvline [shifted <XDIMEN,YDIMEN>]
% ** Place vertical solid line
\def\!putsolidvline#1{%
\ifdim\!dypos>\!zpt
\put{\!vline\!dypos}#1[b] at {\!xloc} {\!yloc}
\else
\put{\!vline{-\!dypos}}#1[b] at {\!xxloc} {\!yyloc}
\fi
\ignorespaces}
\def\!hline#1{\hbox to #1{\leaders \hrule height\linethickness\hfill}}
\def\!vline#1{\vbox to #1{\leaders \vrule width\linethickness\vfill}}
% ** \!putdashedhline [<XDIMEN,YDIMEN>]
% ** Place dashed horizontal line
\def\!putdashedhline#1{%
\ifdim\!dxpos>\!zpt
\!DLsetup\!Flist\!dxpos
\put{\hbox to \!totalleaderlength{\!hleaders}\!hpartialpattern\!Rtrunc}
#1[l] at {\!xloc} {\!yloc}
\else
\!DLsetup\!Blist{-\!dxpos}
\put{\!hpartialpattern\!Ltrunc\hbox to \!totalleaderlength{\!hleaders}}
#1[r] at {\!xloc} {\!yloc}
\fi
\ignorespaces}
% ** \!putdashedhline [<XDIMEN,YDIMEN>]
% ** Place dashed vertical line
\def\!putdashedvline#1{%
\!dypos=-\!dypos% ** vertical leaders go from top to bottom
\ifdim\!dypos>\!zpt
\!DLsetup\!Flist\!dypos
\put{\vbox{\vbox to \!totalleaderlength{\!vleaders}
\!vpartialpattern\!Rtrunc}}#1[t] at {\!xloc} {\!yloc}
\else
\!DLsetup\!Blist{-\!dypos}
\put{\vbox{\!vpartialpattern\!Ltrunc
\vbox to \!totalleaderlength{\!vleaders}}}#1[b] at {\!xloc} {\!yloc}
\fi
\ignorespaces}
% ** The rest of the macros in this section are subroutines used by
% ** \!putdashedhline and \!putdashedvline.
\def\!DLsetup#1#2{% ** Dashed-Line set up
\let\!RSlist=#1% ** set !Rule-Skip list
\!countB=#2% ** convert rule length to integer (number of sps)
\!countA=\!leaderlength% ** ditto, leaderlength
\divide\!countB by \!countA% ** number of complete leader units
\!totalleaderlength=\!countB\!leaderlength
\!Rresiduallength=#2%
\advance \!Rresiduallength by -\!totalleaderlength% \** excess length
\!Lresiduallength=\!leaderlength
\advance \!Lresiduallength by -\!Rresiduallength
\ignorespaces}
\def\!hleaders{%
\def\!Rule##1{\vrule height\linethickness width##1}%
\def\!Skip##1{\hskip##1}%
\leaders\hbox{\!RSlist}\hfill}
\def\!hpartialpattern#1{%
\!dimenA=\!zpt \!dimenB=\!zpt
\def\!Rule##1{#1{##1}\vrule height\linethickness width\!dimenD}%
\def\!Skip##1{#1{##1}\hskip\!dimenD}%
\!RSlist}
\def\!vleaders{%
\def\!Rule##1{\hrule width\linethickness height##1}%
\def\!Skip##1{\vskip##1}%
\leaders\vbox{\!RSlist}\vfill}
\def\!vpartialpattern#1{%
\!dimenA=\!zpt \!dimenB=\!zpt
\def\!Rule##1{#1{##1}\hrule width\linethickness height\!dimenD}%
\def\!Skip##1{#1{##1}\vskip\!dimenD}%
\!RSlist}
\def\!Rtrunc#1{\!trunc{#1}>\!Rresiduallength}
\def\!Ltrunc#1{\!trunc{#1}<\!Lresiduallength}
\def\!trunc#1#2#3{%
\!dimenA=\!dimenB
\advance\!dimenB by #1%
\!dimenD=\!dimenB \ifdim\!dimenD#2#3\!dimenD=#3\fi
\!dimenC=\!dimenA \ifdim\!dimenC#2#3\!dimenC=#3\fi
\advance \!dimenD by -\!dimenC}
% ****************************************************************
% *** LINEAR ARC (Draws straight lines -- solid and dashed) ***
% ****************************************************************
% ** User commands
% ** \inboundscheckoff
% ** \inboundscheckon
% ** Internal commands
% ** \!start (XCOORD,YCOORD)
% ** \!ljoin (XCOORD,YCOORD)
% ** \!drawlinearsegment -- set by \dashpat to either
% ** \!linearsolid or \!lineardashed
% ** \!advancedashing -- set by \dashpat to either
% ** \relax or \!!advancedashing
% ** \!plotifinbounds -- set by \inboundscheck off/on to either
% ** \!plot or \!!plotifinbounds
% ** \!initinboundscheck -- set by \inboundscheck off/on to either
% ** \relax or \!!initinboundscheck
% \plotsymbolspacing ** distance between consecutive plot positions
% \!xS ** starting x
% \!yS ** starting y
% \!xE ** ending x
% \!yE ** ending y
% \!xdiff ** x_end - x_start
% \!ydiff ** y_end - y_start
% \!distacross ** how far along curve next point to be plotted is
% \!arclength ** approximate length of arc for current interval
% \!downlength ** remaining length for "pen" to be down
% \!uplength ** length for "pen" to be down
% \!intervalno ** counts segments to curve
% \totalarclength ** cumulative distance along curve
% \!npoints ** approximately (arc length / plotsymbolspacing)
% ** Calls -- \!Pythag, \!divide, \!plot
% ** \!start (XCOORD,YCOORD)
% ** Sets initial point for linearly (or quadratically) interpolated curve
\def\!start (#1,#2){%
\!plotxorigin=\!xorigin \advance \!plotxorigin by \!plotsymbolxshift
\!plotyorigin=\!yorigin \advance \!plotyorigin by \!plotsymbolyshift
\!xS=\!M{#1}\!xunit \!yS=\!M{#2}\!yunit
\!rotateaboutpivot\!xS\!yS
\!copylist\!UDlist\to\!!UDlist% **\!UDlist has the form \\{dimen1}\\{dimen2}..
% ** Routine will draw dashed line with pen
% ** down for dimen1, up for dimen2, ...
\!getnextvalueof\!downlength\from\!!UDlist
\!distacross=\!zpt% ** 1st point goes at start of curve
\!intervalno=0 % ** initialize interval counter
\global\totalarclength=\!zpt% ** initialize distance traveled along curve
\ignorespaces}
% ** \!ljoin (XCOORD,YCOORD)
% ** Draws a straight line starting at the last point specified
% ** by the most recent \!start, \!ljoin, or \!qjoin, and
% ** ending at (XCOORD,YCOORD).
\def\!ljoin (#1,#2){%
\advance\!intervalno by 1
\!xE=\!M{#1}\!xunit \!yE=\!M{#2}\!yunit
\!rotateaboutpivot\!xE\!yE
\!xdiff=\!xE \advance \!xdiff by -\!xS%** xdiff = xE - xS
\!ydiff=\!yE \advance \!ydiff by -\!yS%** ydiff = yE - yS
\!Pythag\!xdiff\!ydiff\!arclength% ** arclength = sqrt(xdiff**2+ydiff**2)
\global\advance \totalarclength by \!arclength%
\!drawlinearsegment% ** set by dashpat to \!linearsolid or \!lineardashed
\!xS=\!xE \!yS=\!yE% ** shift ending points to starting points
\ignorespaces}
% ** The following routine is used to draw a "solid" line between (xS,yS)
% ** and (xE,yE). Points are spaced nearly every \plotsymbolspacing length
% ** along the line.
\def\!linearsolid{%
\!npoints=\!arclength
\!countA=\plotsymbolspacing
\divide\!npoints by \!countA% ** now #pts =. arclength/plotsymbolspacing
\ifnum \!npoints<1
\!npoints=1
\fi
\divide\!xdiff by \!npoints
\divide\!ydiff by \!npoints
\!xpos=\!xS \!ypos=\!yS
%
\loop\ifnum\!npoints>-1
\!plotifinbounds
\advance \!xpos by \!xdiff
\advance \!ypos by \!ydiff
\advance \!npoints by -1
\repeat
\ignorespaces}
% ** The following routine is used to draw a dashed line between (xS,yS)
% ** and (xE,yE). The dash pattern continues from the previous segment.
\def\!lineardashed{%
% **
\ifdim\!distacross>\!arclength
\advance \!distacross by -\!arclength %nothing to plot in this interval
%
\else
%
\loop\ifdim\!distacross<\!arclength
% ** plot point, interpolating linearly in x and y
\!divide\!distacross\!arclength\!dimenA% ** dimA = across/arclength
\!removept\!dimenA\!t% ** \!t holds value in dimA, without the "pt"
\!xpos=\!t\!xdiff \advance \!xpos by \!xS
\!ypos=\!t\!ydiff \advance \!ypos by \!yS
\!plotifinbounds
\advance\!distacross by \plotsymbolspacing
\!advancedashing
\repeat
%
\advance \!distacross by -\!arclength% ** prepare for next interval
\fi
\ignorespaces}
\def\!!advancedashing{%
\advance\!downlength by -\plotsymbolspacing
\ifdim \!downlength>\!zpt
\else
\advance\!distacross by \!downlength
\!getnextvalueof\!uplength\from\!!UDlist
\advance\!distacross by \!uplength
\!getnextvalueof\!downlength\from\!!UDlist
\fi}
% ** \inboundscheckoff & \inboundscheckon: See Subsection 5.5 of the manual.
\def\inboundscheckoff{%
\def\!plotifinbounds{\!plot(\!xpos,\!ypos)}%
\def\!initinboundscheck{\relax}\ignorespaces}
\def\inboundscheckon{%
\def\!plotifinbounds{\!!plotifinbounds}%
\def\!initinboundscheck{\!!initinboundscheck}%
\!initinboundscheck\ignorespaces}
\inboundscheckoff
% ** The following code plots the current point only if it falls in the
% ** current plotarea. It doesn't matter if the coordinate system has
% ** changed since the plotarea was set up. However, shifts of the plot
% ** are ignored (how the plotsymbol stands relative to its plot position is
% ** unknown anyway).
\def\!!plotifinbounds{%
\ifdim \!xpos<\!checkleft
\else
\ifdim \!xpos>\!checkright
\else
\ifdim \!ypos<\!checkbot
\else
\ifdim \!ypos>\!checktop
\else
\!plot(\!xpos,\!ypos)
\fi
\fi
\fi
\fi}
\def\!!initinboundscheck{%
\!checkleft=\!arealloc \advance\!checkleft by \!xorigin
\!checkright=\!arearloc \advance\!checkright by \!xorigin
\!checkbot=\!areabloc \advance\!checkbot by \!yorigin
\!checktop=\!areatloc \advance\!checktop by \!yorigin}
% *********************************
% *** LOGTEN (Log_10 function) ***
% *********************************
%
% ** \!logten{X}
% ** Calculates log_10 of X. X and LOG10(X) are in fixed point notation.
% ** X must be positive; it may have an optional `+' sign; any number
% ** of digits may be specified for X. The absolute error in LOG10(X) is
% ** less than .0001 (probably < .00006). That's about as good as you
% ** hope for, since TEX only operates to 5 figures after the decimal
% ** point anyway.
% \!rootten=3.162278pt **** These are values are set in ALLOCATIONS
% \!tenAe=2.543275pt (=A5)
% \!tenAc=2.773839pt (=A3)
% \!tenAa=8.690286pt (=A1)
\def\!logten#1#2{%
\expandafter\!!logten#1\!nil
\!removept\!dimenF#2%
\ignorespaces}
\def\!!logten#1#2\!nil{%
\if -#1%
\!dimenF=\!zpt
\def\!next{\ignorespaces}%
\else
\if +#1%
\def\!next{\!!logten#2\!nil}%
\else
\if .#1%
\def\!next{\!!logten0.#2\!nil}%
\else
\def\!next{\!!!logten#1#2..\!nil}%
\fi
\fi
\fi
\!next}
\def\!!!logten#1#2.#3.#4\!nil{%
\!dimenF=1pt % ** DimF holds log10 original argument
\if 0#1%
\!!logshift#3pt % ** Argument < 1
\else % ** Argument >= 1
\!logshift#2/% ** Shift decimal pt as many places
\!dimenE=#1.#2#3pt % ** as there are figures in #2
\fi % ** Now dimE holds revised X want log10 of
\ifdim \!dimenE<\!rootten% ** Transform X to XX between sqrt(10)
\multiply \!dimenE 10 % ** and 10*sqrt(10)
\advance \!dimenF -1pt
\fi
\!dimenG=\!dimenE% ** dimG <- (XX + 10)
\advance\!dimenG 10pt
\advance\!dimenE -10pt % ** dimE <- (XX - 10)
\multiply\!dimenE 10 % ** dimE = 10*(XX-10)
\!divide\!dimenE\!dimenG\!dimenE% ** Now dimE=10t==10*(XX-10)/(XX+10)
\!removept\!dimenE\!t% ** !t=10t, with "pt" removed
\!dimenG=\!t\!dimenE% ** dimG=100t**2
\!removept\!dimenG\!tt% ** !tt=100t**2, with "pt" removed
\!dimenH=\!tt\!tenAe% ** dimH=10*a5*(10t)**2 /100
\divide\!dimenH 100
\advance\!dimenH \!tenAc% ** ditto + 10*a3
\!dimenH=\!tt\!dimenH% ** ditto * (10t)**2 /100
\divide\!dimenH 100
\advance\!dimenH \!tenAa% ** ditto + 10*a1
\!dimenH=\!t\!dimenH% ** ditto * 10t / 100
\divide\!dimenH 100 % ** Now dimH = log10(XX) - 1
\advance\!dimenF \!dimenH}% ** dimF = log10(X)
\def\!logshift#1{%
\if #1/%
\def\!next{\ignorespaces}%
\else
\advance\!dimenF 1pt
\def\!next{\!logshift}%
\fi
\!next}
\def\!!logshift#1{%
\advance\!dimenF -1pt
\if 0#1%
\def\!next{\!!logshift}%
\else
\if p#1%
\!dimenF=1pt
\def\!next{\!dimenE=1p}%
\else
\def\!next{\!dimenE=#1.}%
\fi
\fi
\!next}
% ***********************************************************
% *** PICTURES (Basic setups for PiCtures; \put commands) ***
% ***********************************************************
% ** User Commands:
% ** \beginpicture
% ** \endpicture
% ** \endpicturesave <XREG,YREG>
% ** \setcoordinatesystem units <XUNIT,YUNIT> point at XREF YREF
% ** \put {OBJECT} [ORIENTATION] <XSHIFT,YSHIFT> at XCOORD YCOORD
% ** \multiput {OJBECT} [ORIENTATION] <XSHIFT,YSHIFT>) at
% ** XCOORD YCOORD
% ** *NUMBER_OF_TIMES DXCOORD DYCOORD /
% ** \accountingon
% ** \accountingoff
% ** \stack [ORIENTATION] <LEADING> {LIST OF ITEMS}
% ** \lines [ORIENTATION] {LINES}
% ** \Lines [ORIENTATION] {LINES}
% ** \setdimensionmode
% ** \setcoordinatemode
% ** \Xdistance
% ** \Ydistance
% ** Internal commands:
% ** \!setputobject{OBJECT}{[ORIENTATION]<XSHIFT,YSHIFT>}
% ** \!dimenput{OBJECT}[ORIENTATION]<XSHIFT,YSHIFT>(XDIMEN,YDIMEN)
% ** \!setdimenmode
% ** \!setcoordmode
% ** \!ifdimenmode
% ** \!ifcoordmode
% ** \beginpicture
% ** \endpicture
% ** \endpicturesave <XREG,YREG>
% ** \beginpicture ... \endpicture creates an hbox. Objects are
% ** placed in this box using the \put command and the like (see below).
% ** The location of an object is specified in terms of coordinate system(s)
% ** established by \setcoordinatesystem. Each coordinate system (there
% ** might be just one) specifies the length of 1 horizontal unit, the length
% ** of 1 vertical unit, and the coordinates of a "reference point". The
% ** reference points of various coordinate systems will be in the same
% ** physical location. The macros keep track of the size of the objects
% ** and their locations. The resulting hbox is the smallest hbox which
% ** encloses all the objects, and whose TEK reference point is the point
% ** on the left edge of the box closest vertically to the PICTEX reference
% ** point. Using \endpicturesave, you can (globally) save the distance TEK's
% ** reference point is to the right (respectively, up from) PICTEX's
% ** reference point in the dimension register \XREG (respectively \YREG).
% ** You can then \put the picture OBJECT into a larger picture so that its
% ** reference point is at (XCOORD,YCOORD) with the command
% ** \put {picture OBJECT} [Bl] <\XREG, \YREG> at XCOORD YCOORD
% ** \beginpicture : See Subsection 1.1 of the manual.
\def\beginpicture{%
\setbox\!picbox=\hbox\bgroup%
\!xleft=\maxdimen
\!xright=-\maxdimen
\!ybot=\maxdimen
\!ytop=-\maxdimen}
% ** \endpicture : See Subsection 1.1 of the manual.
\def\endpicture{%
\ifdim\!xleft=\maxdimen% ** check if nothing was put in picbox
\!xleft=\!zpt \!xright=\!zpt \!ybot=\!zpt \!ytop=\!zpt
\fi
\global\!Xleft=\!xleft \global\!Xright=\!xright
\global\!Ybot=\!ybot \global\!Ytop=\!ytop
\egroup%
\ht\!picbox=\!Ytop \dp\!picbox=-\!Ybot
\ifdim\!Ybot>\!zpt
\else
\ifdim\!Ytop<\!zpt
\!Ybot=\!Ytop
\else
\!Ybot=\!zpt
\fi
\fi
\hbox{\kern-\!Xleft\lower\!Ybot\box\!picbox\kern\!Xright}}
% ** \endpicturesave : See Subsection 8.4 of the manual.
\def\endpicturesave <#1,#2>{%
\endpicture \global #1=\!Xleft \global #2=\!Ybot \ignorespaces}
% ** \setcoordinatesystem units <XUNIT,YUNIT>
% ** point at XREF YREF
% ** Each of `units <XUNIT,YUNIT>' and `point at XREF YREF'
% ** are optional.
% ** Unit lengths must be given in dimensions (e.g., <10pt,1in>).
% ** Default unit lengths are 1pt, 1pt, or previous unit lengths.
% ** Reference point is specified in current units (e.g., 3 5 ).
% ** Default reference point is 0 0 , or previous reference point.
% ** Unit lengths and reference points obey TEX's scoping rules.
% ** See Subsection 1.2 of the manual.
\def\setcoordinatesystem{%
\!ifnextchar{u}{\!getlengths }
{\!getlengths units <\!xunit,\!yunit>}}
\def\!getlengths units <#1,#2>{%
\!xunit=#1\relax
\!yunit=#2\relax
\!ifcoordmode
\let\!SCnext=\!SCccheckforRP
\else
\let\!SCnext=\!SCdcheckforRP
\fi
\!SCnext}
\def\!SCccheckforRP{%
\!ifnextchar{p}{\!cgetreference }
{\!cgetreference point at {\!xref} {\!yref} }}
\def\!cgetreference point at #1 #2 {%
\edef\!xref{#1}\edef\!yref{#2}%
\!xorigin=\!xref\!xunit \!yorigin=\!yref\!yunit
\!initinboundscheck % ** See linear.tex
\ignorespaces}
\def\!SCdcheckforRP{%
\!ifnextchar{p}{\!dgetreference}%
{\ignorespaces}}
\def\!dgetreference point at #1 #2 {%
\!xorigin=#1\relax \!yorigin=#2\relax
\ignorespaces}
% ** \put {OBJECT} [XY] <XDIMEN,YDIMEN> at (XCOORD,YCOORD)
% ** `[XY]' and `<XDIMEN,YDIMEN>' are optional.
% ** First OBJECT is placed in an hbox (the "objectbox") and then a
% ** "reference point" is assigned to the objectbox as follows:
% ** [1] first, the reference point is taken to be the center of the box;
% ** [2] next, centering is overridden by the specifications
% ** X=l -- reference point along the left edge of the objectbox
% ** X=r -- reference point along the right edge of the objectbox
% ** Y=b -- reference point along the bottom edge of the objectbox
% ** Y=B -- reference point along the Baseline of the objectbox
% ** Y=t -- reference point along the top edge of the objectbox;
% ** [3] finally the reference point is shifted left by XDIMEN, down
% ** by YDIMEN (both default to 0pt).
% ** The objectbox is placed within PICBOX with its reference point at
% ** (XCOORD,YCOORD).
% ** If OBJECT is a saved box, say box0, you have to write
% ** \put{\box0}... or \put{\copy0}...
% ** The objectbox is void after the put.
% ** See Subsection 2.1 of the manual.
\long\def\put#1#2 at #3 #4 {%
\!setputobject{#1}{#2}%
\!xpos=\!M{#3}\!xunit \!ypos=\!M{#4}\!yunit
\!rotateaboutpivot\!xpos\!ypos%
\advance\!xpos -\!xorigin \advance\!xpos -\!xshift
\advance\!ypos -\!yorigin \advance\!ypos -\!yshift
\kern\!xpos\raise\!ypos\box\!putobject\kern-\!xpos%
\!doaccounting\ignorespaces}
% ** \multiput etc. Like \put. The objectbox is not voided until the
% ** termininating /, and is placed repeatedly with:
% ** XCOORD YCOORD -- the objectbox is put down with its reference point
% ** at (XCOORD,YCOORD);
% ** *N DXCOORD DYCOORD -- each of N times the current
% ** (xcoord,ycoord) is incremented by (DXCOORD,DYCOORD), and the
% ** objectbox is put down with its reference point at (xcoord,ycoord)
% ** (This specification has to follow an XCOORD YCOORD pair)
% ** See Subsection 2.2 of the manual.
\long\def\multiput #1#2 at {%
\!setputobject{#1}{#2}%
\!ifnextchar"{\!putfromfile}{\!multiput}}
\def\!putfromfile"#1"{%
\expandafter\!multiput \input #1 /}
\def\!multiput{%
\futurelet\!nextchar\!!multiput}
\def\!!multiput{%
\if *\!nextchar
\def\!nextput{\!alsoby}%
\else
\if /\!nextchar
\def\!nextput{\!finishmultiput}%
\else
\def\!nextput{\!alsoat}%
\fi
\fi
\!nextput}
\def\!finishmultiput/{%
\setbox\!putobject=\hbox{}%
\ignorespaces}
% ** \!alsoat XCOORD YCOORD
% ** The objectbox is put down with reference point at XCOORD,YCOORD
\def\!alsoat#1 #2 {%
\!xpos=\!M{#1}\!xunit \!ypos=\!M{#2}\!yunit
\!rotateaboutpivot\!xpos\!ypos%
\advance\!xpos -\!xorigin \advance\!xpos -\!xshift
\advance\!ypos -\!yorigin \advance\!ypos -\!yshift
\kern\!xpos\raise\!ypos\copy\!putobject\kern-\!xpos%
\!doaccounting
\!multiput}
% ** \!alsoby*N DXCOORD DYCOORD
% ** N times, the current (XCOORD,YCOORD) is advanced by (DXCOORD,DYCOORD),
% ** and the current (shifted, oriented) OBJECT is put down.
\def\!alsoby*#1 #2 #3 {%
\!dxpos=\!M{#2}\!xunit \!dypos=\!M{#3}\!yunit
\!rotateonly\!dxpos\!dypos
\!ntemp=#1%
\!!loop\ifnum\!ntemp>0
\advance\!xpos by \!dxpos \advance\!ypos by \!dypos
\kern\!xpos\raise\!ypos\copy\!putobject\kern-\!xpos%
\advance\!ntemp by -1
\repeat
\!doaccounting
\!multiput}
% ** \accountingoff : Suspends PiCTeX's accounting of the aggregate
% ** size of the picture box.
% ** \accounting on : Reinstates accounting.
% ** See Subsection 8.2 of the manual.
\def\accountingon{\def\!doaccounting{\!!doaccounting}\ignorespaces}
\def\accountingoff{\def\!doaccounting{}\ignorespaces}
\accountingon
\def\!!doaccounting{%
\!xtemp=\!xpos
\!ytemp=\!ypos
\ifdim\!xtemp<\!xleft
\!xleft=\!xtemp
\fi
\advance\!xtemp by \!wd
\ifdim\!xright<\!xtemp
\!xright=\!xtemp
\fi
\advance\!ytemp by -\!dp
\ifdim\!ytemp<\!ybot
\!ybot=\!ytemp
\fi
\advance\!ytemp by \!dp
\advance\!ytemp by \!ht
\ifdim\!ytemp>\!ytop
\!ytop=\!ytemp
\fi}
\long\def\!setputobject#1#2{%
\setbox\!putobject=\hbox{#1}%
\!ht=\ht\!putobject \!dp=\dp\!putobject \!wd=\wd\!putobject
\wd\!putobject=\!zpt
\!xshift=.5\!wd \!yshift=.5\!ht \advance\!yshift by -.5\!dp
\edef\!putorientation{#2}%
\expandafter\!SPOreadA\!putorientation[]\!nil%
\expandafter\!SPOreadB\!putorientation<\!zpt,\!zpt>\!nil\ignorespaces}
\def\!SPOreadA#1[#2]#3\!nil{\!etfor\!orientation:=#2\do\!SPOreviseshift}
\def\!SPOreadB#1<#2,#3>#4\!nil{\advance\!xshift by -#2\advance\!yshift by -#3}
\def\!SPOreviseshift{%
\if l\!orientation
\!xshift=\!zpt
\else
\if r\!orientation
\!xshift=\!wd
\else
\if b\!orientation