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