% Logic Eprints %Submitted 0635 Sat Oct 09, 1993 by: andretta@di.unito.it ( ) %logic/andretta/how_to_win_some_simple_iteration_games %logic/andretta/how_to_win_some_simple_iteration_games/diagram.sty % % diagram.sty: LaTeX commutative diagram macros % Author: Paul Burchard % Version: 13 Jan 1991 % % Copyright (c) 1990 by Paul Burchard % % Anyone may use this file or its programs for educational or non-profit % purposes if this file is not altered or renamed in any way. All other % rights reserved. Due credit should be given to Marc-Paul van der Hulst % whose macros inspired many of the features offered by this package. Thanks % also to Bill Richter for his topological torture testing of this package. % % % ---INTRODUCTION--- % % The "diagram" environment provided by this document-style option allows the % user to create complex commutative diagrams whose arrows may (in any % combination): % % * slant in any of the 16 principal compass directions (rounded to grid) % * span several rows and/or columns of the diagram % * have labels on either or both sides, with adjustable positioning % * intersect other arrows % * be dotted or headless arrows instead of ordinary arrows % % The environment automatically generates a correctly scaled and shaped % rectangular---not necessarily square---grid so that formulas may be % comfortably placed at the "nodes" of this grid. Nodes may then be % connected with arrows; the environment will automatically leave room so % that the arrows don't touch the formulas at those nodes. % % Here are some examples of commands to produce arrows: % % \arrow{e} % simple east-pointing arrow 1 col wide % \arrow{s,lr}{\alpha}{\beta} % south-pointing, labelled on left by % % $\alpha$ and on right by $\beta$ % \arrow[2]{ene,t,-}{bond} % double-long eastnortheast-pointing % % (4 cols right by 2 rows up) headless % % arrow, with top label $bond$ % % Here is an example diagram (the center of the diagram contains two % intersecting diagonal arrows, in case it's not clear!): % % \[ % a b* \begin{diagram}[B^*] % A ---> B* ---> C \node{A} \arrow{e,t}{a} \arrow{s,l}{c} \arrow{ese} % | \____ _____/ | \node{B^*} \arrow{e,t}{b^*} % c | ___X____ | d \node{C} \arrow{s,r}{d} \arrow{wsw} \\ % v `/_ _\' v \node{D} \arrow[2]{e,b}{e} % D -----------> E \node[2]{E} % e \end{diagram} % \] % % % ---USER'S MANUAL--- % % To use the "diagram" macros, make sure that you or your system have the % "auxdefs.sty" style option available. Then begin your LaTeX file with: % % \documentstyle[diagram]{DOCSTYLE} % % where DOCSTYLE is your document style (e.g., "article"). Now you will be % able to use the "diagram" environment. It should be used in MATH MODE only. % Its usage is as follows: % % \begin{diagram}[BIGNODE] % NODE ARROW ARROW ... NODE ARROW ARROW ... .... \\ % NODE ARROW ARROW ... NODE ARROW ARROW ... .... \\ % ... % NODE ARROW ARROW ... NODE ARROW ARROW ... .... % \end{diagram} % % where the optional argument BIGNODE is the text of the widest and tallest % NODE, which is used to determine the correct _size_ and _shape_ for the % grid. The _size_ can be adjusted to taste by setting \dgARROWLENGTH; see % the section on user-adjustable parameters below. (The _shape_ will be % determined by \dgCOLUMNWIDTH if you do not specify the BIGNODE.) % % Each NODE places a centered formula at a new grid point, and the ARROWs % which follow this NODE but precede the next NODE will be attached by their % tails to the same grid point. A node is specified by: % % \node[NCOLS]{FORMULA} % % where the optional argument NCOLS tells how many grid columns to move % forward from the previous node (default is 1), and the FORMULA is math mode % material. % % The \\ command moves to the next grid row. As usual, the final row % should not end with a \\, and any row may be prematurely terminated. % More generally, it is possible to move NROWS rows down at once using % % \\[NROWS] % % % An ARROW is specified by the \arrow command, which may also be used in % MATH MODE independent of the "diagram" environment. Its usage depends % on the number of labels desired: % % \arrow[SIZE]{TYPE,OPTIONS} % \arrow[SIZE]{TYPE,ONELABEL,OPTIONS}{LABEL} % \arrow[SIZE]{TYPE,TWOLABEL,OPTIONS}{LABEL1}{LABEL2} % % Here the optional integer argument SIZE tells how many times its normal % length the arrow should be made (thus \arrow[2]{e} will span two columns % while \arrow[2]{s} will span two rows). % % The arrow TYPE may be chosen from the compass point directions: % % n,e,s,w,ne,nw,se,sw,nne,nnw,sse,ssw,ene,ese,wnw,wsw % % Any LABELs present are math mode material. The ONELABEL specifier may be % chosen from: % % t % top % b % bottom % l % left (use ONLY with vertical arrows) % r % right (use ONLY with vertical arrows) % % The TWOLABEL specifier may be chosen from: % % tb % top and bottom % lr % left and right (use ONLY with vertical arrows) % % Any OPTIONs (with their preceding commas) are optional, and may be selected % from this list: % % .. % dotted arrow ] % - % headless arrow (i.e. a line) ]--- mutually exclusive % ! % invisible arrow ] % % FRAC % place label at the point FRAC/ARROWPARTS of the way % % from arrow tail to arrow tip % % The FRAC option is allowed to be any single digit 1,2,3,...,ARROWPARTS-1. % The default value of ARROWPARTS is 4 (it can be changed, see below). % % % ---USER-ADJUSTABLE PARAMETERS--- % % The diagram environment provides a rectangular grid whose size and aspect % ratio (width:height of grid rectangles) are chosen on the basis of % BIGNODE. Due to font limitations, the only grid aspect ratios for which % LaTeX can provide the full required set of compass-point arrows are 1:2, % 2:3, 1:1, 3:2, 2:1 (but we don't use the first two). So the integer % \dgMAXSQUARE is the maximum aspect ratio of BIGNODE for which the square % (1:1) grid will be chosen, while \dgMINDBLSQ is the minimum aspect ration % of BIGNODE for which the ``double-square'' (2:1) grid will be chosen; in % between, the 3:2 grid is used. % \newcount\dgMAXSQUARE \dgMAXSQUARE=4\relax \newcount\dgMINDBLSQ \dgMINDBLSQ=10\relax % % If no BIGNODE is supplied, the default value is: % \makebox[\dgCOLUMNWIDTH]{$()$} % \newskip\dgCOLUMNWIDTH \dgCOLUMNWIDTH=2em\relax % % Once the grid aspect ratio has been chosen, the grid size is determined % from BIGNODE and the requirement that horizontal arrows must have at least % \dgARROWLENGTH of room between two adjacent BIGNODEs, when padding is taken % into account. All nodes will be padded (to keep arrows away from them) by % increasing their apparent horizontal size by \dgHORIZPAD and their apparent % vertical size by \dgVERTPAD. % \newskip\dgARROWLENGTH \dgARROWLENGTH=2.5em\relax \newskip\dgHORIZPAD \dgHORIZPAD=1em\relax \newskip\dgVERTPAD \dgVERTPAD=2ex\relax % % \dgLABELOFFSET is the (approximate) distance which will separate labels % from their arrows. An arrow is divided into \dgARROWPARTS parts for % custom positioning of labels along the arrow; the only sensible choices for % this number are 2,4,6,8,10. % \newskip\dgLABELOFFSET \dgLABELOFFSET=.7ex\relax \newcount\dgARROWPARTS \dgARROWPARTS=4\relax % % The following two parameters regulate the appearance of dotted arrows. % \newskip\dgDOTSPACING \dgDOTSPACING=0.35em \newskip\dgDOTSIZE \dgDOTSIZE=1.5\fontdimen8\tenln % % By default, nodes are typeset \displaystyle, and labels \scriptstyle. This % is controlled by the commands \dgeverynode (which is executed prior to the % FORMULA of every node) and \dgeverylabel (which is executed prior to the % LABEL formula of every label). They can be changed with \renewcommand. % \newcommand{\dgeverynode}{\displaystyle} \newcommand{\dgeverylabel}{\scriptstyle} % % % ---TECHNICAL NOTES--- % % In order to modulate the size of horizontal arrows to fit in the gaps left % between formulas (which may be several columns wide), all the horizontal % arrows occurring in a row are first saved up (in \dg@ALIST) along with % the data on node widths (in \dg@NLIST). Then, once the row is otherwise % complete, the saved horizontal arrows are drawn in. % % All command names defined here except \diagram, \enddiagram, \node, % \arrow, and \\ begin with "\dg". All private commands contain an `@' % in their name. The commands \node and \\ are only defined within the % "diagram" environment. % % Requires the presence of "auxdefs.sty". % % Spaces following the \end{diagram} are ignored. % % % ---INCLUDED MACROS--- % % Use "auxdefs" to conveniently define macros/environs with an optional arg, % or environments which ignore subsequent spaces. % \ifx\@auxdefsloaded\relax \else \input{auxdefs.sty}\fi % % % ---INTERNAL VARIABLES--- % \newcount\dg@HORIZ \newcount\dg@VERT \newcount\dg@SIZE \newcount\dg@USERSIZE \newcount\dg@X \newcount\dg@XMAX \newcount\dg@Y \newcount\dg@XGRID \newcount\dg@YGRID \newcount\dg@DX \newcount\dg@DY \newcount\dg@XLBL \newcount\dg@YLBL \newcount\dg@XOFFSET \newcount\dg@YOFFSET \newcount\dg@LBLOFF \newcount\dg@XLBLOFF \newcount\dg@YLBLOFF \newcount\dg@LBLPOS \newcount\dg@XNODE \newcount\dg@YNODE \newcount\dg@XTEMP \newcount\dg@YTEMP \newcount\dg@ZTEMP \newcount\dg@XEND \newcount\dg@WEND \newskip\dg@XPAD \newskip\dg@YPAD \newbox\dg@NODEBOX \newif\ifdg@SAVE % % % ---THE DIAGRAM ENVIRONMENT--- % % For usage, see above. % It ignores spaces following the \end{diagram}, % just like most LaTeX built-in environments do (thus the `*'). % \newoptenvironment*{diagram}{\hbox to\dgCOLUMNWIDTH{$()$\hss}}[1]{% % Determine unpadded width and (height+depth) of BIGNODE (first in sp's). \setbox\dg@NODEBOX=\hbox{$\dgeverynode{#1}$}% \dg@XNODE=\wd\dg@NODEBOX \dg@YNODE=\ht\dg@NODEBOX \advance\dg@YNODE by\dp\dg@NODEBOX % Choose XGRID:YGRID from 1:1, 3:2, 2:1 (only ones LaTeX can handle). % Make decision on basis of aspect ratio of *unpadded* BIGNODE. \ifnum\dg@YNODE=\z@ \dg@ZTEMP=\z@ \else \dg@ZTEMP=\dg@XNODE \divide\dg@ZTEMP by\dg@YNODE \fi \ifnum\dg@ZTEMP>\dgMAXSQUARE \ifnum\dg@ZTEMP<\dgMINDBLSQ \dg@XGRID=\thr@@ \dg@YGRID=\tw@ \else \dg@XGRID=\tw@ \dg@YGRID=\@ne \fi \else \dg@XGRID=\@ne \dg@YGRID=\@ne \fi % Add padding onto BIGNODE for all other computations. \advance\dg@XNODE by\dgHORIZPAD \advance\dg@YNODE by\dgVERTPAD % Determine \unitlength so that simple horizontal arrows would be % ARROWLENGTH long if every node were (padded) BIGNODE. \dg@XTEMP=\dgARROWLENGTH \advance\dg@XTEMP by\dg@XNODE \divide\dg@XTEMP by\dg@XGRID \divide\dg@XTEMP by\@m \unitlength=1sp\relax \multiply\unitlength by\dg@XTEMP % Convert dimensions to \unitlength's. \divide\dg@XNODE by\dg@XTEMP \divide\dg@YNODE by\unitlength \dg@LBLOFF=\dgLABELOFFSET \divide\dg@LBLOFF by\unitlength % Compute padding for entire diagram. \dg@XPAD=\unitlength \multiply\dg@XPAD by\dg@XNODE \divide\dg@XPAD by \tw@ \dg@YPAD=\unitlength \multiply\dg@YPAD by\dg@YNODE \divide\dg@YPAD by \tw@ % diagram is padded \vcenter{}. \hspace*{\dg@XPAD}% \vcenter\bgroup \hsize=0pt\relax\parindent=0pt\relax \parskip=0pt\relax\baselineskip=0pt\relax \vspace*{\dg@YPAD}% \begin{picture}(0,0)% % \node, \\, and \arrow are only defined within a diagram. \let\node=\dg@node \let\\=\dg@cr \let\arrow=\dg@arrow % Reset coordinates (X starts at col -1 so first \node will work). \dg@X=-\@m \multiply\dg@X by\dg@XGRID \dg@Y=\z@ \dg@XMAX=\z@\relax % Clear save space for horizontal arrows; enter save mode. \let\dg@ALIST=\@empty \let\dg@NLIST=\@empty \dg@SAVEtrue % \enddiagram }{% % Exit save mode and print out saved horizontal arrows. \dg@SAVEfalse \dg@ALIST % Compute size of diagram. \global\dg@HORIZ=\dg@XMAX\relax \global\dg@VERT=-\dg@Y\relax \end{picture} % Tell TeX how big grid is, since we made it invisible. \raisebox{\z@}[\z@][\dg@VERT\unitlength]{}% \vspace*{\dg@YPAD}% \egroup \hspace*{\dg@HORIZ\unitlength}\hspace*{\dg@XPAD}}% % % % ---MAKING NODES--- % % Usage: \dg@node[NCOLS]{FORMULA} \newoptcommand{\dg@node}{\@ne}[2]{% % Reset coordinates, updating XMAX. \dg@XTEMP=\@m \multiply\dg@XTEMP by\dg@XGRID \ifnum #1>\@ne \multiply\dg@XTEMP by #1\relax \fi \advance\dg@X by\dg@XTEMP\relax \ifnum\dg@XMAX<\dg@X \dg@XMAX=\dg@X \fi % Measure FORMULA, saving position and padded width on \dg@NLIST like so: % ...,\dg@XTEMP=\relax\dg@ZTEMP=\relax,... \setbox\dg@NODEBOX=\hbox{$\dgeverynode{#2}$}% \dg@ZTEMP=\wd\dg@NODEBOX \advance\dg@ZTEMP by\dgHORIZPAD \divide\dg@ZTEMP by\unitlength \toks\z@=\expandafter{\dg@NLIST}% \edef\dg@NLIST{\the\toks\z@,\noexpand\dg@XTEMP=\number\dg@X\noexpand\relax \noexpand\dg@ZTEMP=\number\dg@ZTEMP\noexpand\relax}% % Center FORMULA at current node. \put(\dg@X,\dg@Y){\dg@makebox{\box\dg@NODEBOX}}}% % Go to beginning of NROWS-th next grid row. % Usage: \dg@cr[NROWS] \newoptcommand{\dg@cr}{\@ne}[1]{% % Print out saved horizontal arrows; clear save space for next row. \dg@SAVEfalse \dg@ALIST \let\dg@ALIST=\@empty \let\dg@NLIST=\@empty \dg@SAVEtrue % Reset coordinates (X starts at column -1 so first \node will work). \dg@YTEMP=\@m \multiply\dg@YTEMP by\dg@YGRID \ifnum #1>\@ne \multiply\dg@YTEMP by #1\relax \fi \advance\dg@Y by -\dg@YTEMP \dg@X=-\@m \multiply\dg@X by\dg@XGRID\relax}% % % % ---MAKING ARROWS--- % \newoptcommand{\dg@arrow}{\@ne}[2]{% % Keep all arrow geometry parameters local (\endgroup is in \dg@process). \begingroup % Get optional arrow USERSIZE. \dg@USERSIZE=#1\relax \ifnum\dg@USERSIZE<\@ne \dg@USERSIZE=\@ne \fi % Parse arrow specification. \dg@parse{#2}% % Calculate the rest of the geometry parameters, unless save mode is on % and the arrow is horizontal, in which case just save the arrow. \let\dg@process=\dg@draw \ifdg@SAVE \ifnum\dg@DY=\z@ % Arrow saved with orig LBLTYPE, so don't re-position args. \let\dg@process=\dg@save \ifx\dg@label\dgl@b \let\dg@label=\dgl@t \fi \ifx\dg@label\dgl@r \let\dg@label=\dgl@l \fi \else \dg@calc \fi \else \dg@calc \fi \dg@label{\dg@process{#1}{#2}}}% % Parse arrow specification: comma-separated list of features. % Usage: \dg@parse{TYPE,ONEORTWOLABEL,OPTION,...} \def\dg@parse#1{% % Set default labeling and options. \let\dg@label=\dgl@ \dgo@ % Scan list, reading TYPE, LBLTYPE, and OPTIONs in turn. \let\dg@type=\@empty \let\dg@lbltype=\@empty \@for\dg@list:=#1\do{% \ifx\dg@type\@empty \let\dg@type=\dg@list \else\ifx\dg@lbltype\@empty \let\dg@lbltype=\dg@list % In case LBLTYPE not given, try it as an OPTION. % Note: LBLTYPE and OPTION names must not conflict. \@ifundefined{dgo@\dg@list}{}{\@nameuse{dgo@\dg@list}}% \else % Process OPTIONs in turn; ignore bad OPTIONs. \@ifundefined{dgo@\dg@list}{}{\@nameuse{dgo@\dg@list}}% \fi\fi}% % TYPE must be specified (but default to "e" in case of trouble). % Get basic geometry parameters. \@ifundefined{dgt@\dg@type}{\dgt@e}{\@nameuse{dgt@\dg@type}}% % If LBLTYPE valid, get arg handler. \@ifundefined{dgl@\dg@lbltype}{}{\dg@letname\dg@label{dgl@\dg@lbltype}}} % Draw labelled arrow, using computed parameters. % After using parameters, keep them local by doing an \endgroup to % match \dg@arrow's \begingroup. % Usage: \dg@draw{IGNORE}{IGNORE}{LABEL1}{LABEL2} \def\dg@draw#1#2#3#4{% \put(\dg@X,\dg@Y){\dg@makebox{% \begin{picture}(0,0)% \thinlines \put(\dg@XOFFSET,\dg@YOFFSET){\dg@VECTOR(\dg@DX,\dg@DY){\dg@SIZE}}% \put(\dg@XLBL,\dg@YLBL){\dg@makebox{% \begin{picture}(0,0)% \put(\dg@XLBLOFF,\dg@YLBLOFF){% \dg@makebox[\dg@LBLONE]{$\dgeverylabel{#3}$}}% \put(-\dg@XLBLOFF,-\dg@YLBLOFF){% \dg@makebox[\dg@LBLTWO]{$\dgeverylabel{#4}$}}% \end{picture}}}% \end{picture}}} \endgroup}% % Instead of drawing arrow now, save it on \dg@ALIST, like so: % ...\dg@X=\relax\dg@arrow[]{}... % If either LABEL1 or LABEL2 is empty, it will simply be ignored. % Usage: \dg@save{SIZE}{SPEC}{LABEL1}{LABEL2} \def\dg@save#1#2#3#4{% \endgroup % to match \dg@arrow's \begingroup \toks\z@=\expandafter{\dg@ALIST}% \toks\tw@={\dg@arrow[#1]{#2}{#3}{#4}}% \edef\dg@ALIST{\the\toks\z@% \noexpand\dg@X=\number\dg@X\noexpand\relax\the\toks\tw@}}% % Make \arrow command available for use outside of diagrams. \newoptcommand{\arrow}{\@ne}[2]{% % Parse arrow specification just to check how many labels. \dg@parse{#2}% % Text arrow uses original LBLTYPE, so don't re-position args. \ifx\dg@label\dgl@b \let\dg@label=\dgl@t \fi \ifx\dg@label\dgl@r \let\dg@label=\dgl@l \fi \dg@label{\dg@textarrow{#1}{#2}}}% \def\dg@textarrow#1#2#3#4{% \mathop{{\dgHORIZPAD=0pt\relax\dgVERTPAD=0pt\relax \begin{diagram}[] \node{}\arrow[#1]{#2}{#3}{#4}\node{} \end{diagram}}}} % Calculate all the arrow geometry parameters: % X, Y, DX, DY, SIZE, XOFFSET, YOFFSET, VECTOR, % XLBL, YLBL, XLBLOFF, YLBLOFF, LBLONE, LBLTWO, % from the (preliminary) values of these basic arrow parameters: % X, Y, USERSIZE, SIZE, DX, DY, VECTOR, LBLPOS % using also the diagram parameters: % XGRID, YGRID, YNODE, LBLOFF, NLIST, ARROWPARTS. % No args. Uses temp vars XTEMP, YTEMP, ZTEMP, XEND, WEND. \def\dg@calc{% % Adjust arrow direction to GRIDTYPE (1:1, 3:2, or 2:1). \multiply\dg@DX by\dg@XGRID \multiply\dg@DY by\dg@YGRID \dg@rmcommondiv\tw@\dg@DX\dg@DY \dg@rmcommondiv\thr@@\dg@DX\dg@DY % Scale arrow to requested USERSIZE. \multiply\dg@SIZE by\dg@USERSIZE \multiply\dg@SIZE by\@m \ifnum\dg@DX=\z@ % % Vertical arrow. % % SIZE measures vertical extent. \multiply\dg@SIZE by\dg@YGRID % Arrow shortened by YNODE and offset by YNODE/2 (sign change below). \dg@XOFFSET=\z@ \dg@YOFFSET=\dg@YNODE \divide\dg@YOFFSET by\tw@ \advance\dg@SIZE by -\dg@YNODE % Labels at (YNODE/2 + SIZE*LBLPOS/ARROWPARTS) [SIZE already corrected]. \def\dg@LBLONE{r}\def\dg@LBLTWO{l}% \dg@XLBL=\z@ \dg@YLBL=\dg@SIZE \multiply\dg@YLBL by\dg@LBLPOS \divide\dg@YLBL by\dgARROWPARTS\relax \advance\dg@YLBL by\dg@YOFFSET \dg@changesign\dg@YLBL by\dg@DY \dg@changesign\dg@YOFFSET by\dg@DY \else % Nonvertical arrow, so SIZE measures horizontal extent. \multiply\dg@SIZE by\dg@XGRID \ifnum\dg@DY=\z@ % % Horizontal arrow---uses info in NLIST. % % Let padded width of source (target) node be WSOURCE (WTARGET). % Arrow tail offset by XOFFSET=WSOURCE/2 (sign corrected below). \dg@XEND=\dg@X \dg@getwidth{\dg@NLIST}{\dg@XEND}{\dg@WEND}% \dg@XOFFSET=\dg@WEND \divide\dg@XOFFSET by\tw@ \dg@YOFFSET=\z@ % Arrow SIZE shortened by (WSOURCE+WTARGET)/2. \dg@XTEMP=\@m \multiply\dg@XTEMP by\dg@XGRID \multiply\dg@XTEMP by\dg@USERSIZE \dg@changesign\dg@XTEMP by\dg@DX \advance\dg@XEND by\dg@XTEMP\relax \dg@getwidth{\dg@NLIST}{\dg@XEND}{\dg@WEND}% \divide\dg@WEND by\tw@ \advance\dg@SIZE by -\dg@XOFFSET \advance\dg@SIZE by -\dg@WEND % Labels at (WSOURCE/2 + SIZE*LBLPOS/ARROWPARTS) % [SIZE already corrected]. \def\dg@LBLONE{b}\def\dg@LBLTWO{t}% \dg@XLBL=\dg@SIZE \multiply\dg@XLBL by\dg@LBLPOS \divide\dg@XLBL by\dgARROWPARTS\relax \advance\dg@XLBL by\dg@XOFFSET \dg@changesign\dg@XLBL by\dg@DX \dg@YLBL=\z@ \dg@changesign\dg@XOFFSET by\dg@DX \else % % Slanted arrow. % % Offset arrow in its own dir so as to leave vertical space YNODE/2. % SIZE is reduced so other end has same offset. \dg@YOFFSET=\dg@YNODE \dg@changesign\dg@YOFFSET by\dg@DY \dg@XOFFSET=\dg@YOFFSET \multiply\dg@XOFFSET by\dg@DX \divide\dg@XOFFSET by\dg@DY \ifnum\dg@XOFFSET>\z@ \advance\dg@SIZE by -\dg@XOFFSET \else \advance\dg@SIZE by \dg@XOFFSET \fi \divide\dg@XOFFSET by\tw@ \divide\dg@YOFFSET by\tw@ % Labels at ( XOFFSET+-SIZE*LBLPOS/ARROWPARTS , % YOFFSET+-SIZE*LBLPOS*DY/(ARROWPARTS*DX) ) % [SIZE already corrected]. \def\dg@LBLONE{br}\def\dg@LBLTWO{tl}% \ifnum\dg@DX<\z@ \ifnum\dg@DY>\z@ \def\dg@LBLONE{bl}\def\dg@LBLTWO{tr}\fi\fi \ifnum\dg@DX>\z@ \ifnum\dg@DY<\z@ \def\dg@LBLONE{bl}\def\dg@LBLTWO{tr}\fi\fi \dg@XLBL=\dg@SIZE \multiply\dg@XLBL by\dg@LBLPOS \divide\dg@XLBL by\dgARROWPARTS\relax \dg@changesign\dg@XLBL by\dg@DX \dg@YLBL=\dg@XLBL \multiply\dg@YLBL by\dg@DY \divide\dg@YLBL by\dg@DX \advance\dg@XLBL by\dg@XOFFSET \advance\dg@YLBL by\dg@YOFFSET \fi \fi % (XLBL,YLBL) is the displacement from the tail NODE to the point along % the arrow where the labels will be attached. The offset of first label % from this attachment point is the vector % (XLBLOFF,YLBLOFF) := LBLOFF*sgn(DX)*(-DY,DX)/max(|DX|,|DY|) % if DX is nonzero, and otherwise % (XLBLOFF,YLBLOFF) := LBLOFF*(-1,0); % The second label is offset from the same point by (-XLBLOFF,-YLBLOFF). \dg@XLBLOFF=-\dg@DY \dg@changesign\dg@XLBLOFF by\dg@DX \dg@YLBLOFF=\dg@DX \dg@changesign\dg@YLBLOFF by\dg@DX \ifnum\dg@DX=\z@ \dg@XLBLOFF=\m@ne \fi \dg@XTEMP=\dg@DX \dg@changesign\dg@XTEMP by\dg@DX \dg@YTEMP=\dg@DY \dg@changesign\dg@YTEMP by\dg@DY \ifnum\dg@YTEMP>\dg@XTEMP \dg@XTEMP=\dg@YTEMP \fi \multiply\dg@XLBLOFF by\dg@LBLOFF \divide\dg@XLBLOFF by\dg@XTEMP \multiply\dg@YLBLOFF by\dg@LBLOFF \divide\dg@YLBLOFF by\dg@XTEMP \relax}% % Remove common divisor DIV from two number registers \NUM1 and \NUM2. % Usage: \dg@rmcommondiv{DIV}{\NUM1}{\NUM2} % NOTE: uses XTEMP and YTEMP. \def\dg@rmcommondiv#1#2#3{% \dg@XTEMP=#2\relax \divide\dg@XTEMP by#1\relax \multiply\dg@XTEMP by#1\relax \dg@YTEMP=#3\relax \divide\dg@YTEMP by#1\relax \multiply\dg@YTEMP by#1\relax \ifnum\dg@XTEMP=#2\relax \ifnum\dg@YTEMP=#3\relax \divide#2 by#1\relax \divide#3 by#1\relax \fi\fi}% % Multiply number register \NUM1 by sign of \NUM2. % Usage: \dg@changesign\NUM1 by\NUM2 (no space between "by" and \NUM2) \def\dg@changesign#1by#2{% \ifnum #2<\z@ \multiply#1 by\m@ne \else\ifnum #2=\z@ #1=\z@ \fi\fi}% % Determine from NLIST the width of the node at XCOORD and store the % answer in number register \WIDTH (if no such node, set \WIDTH=0). % Usage: \dg@getwidth{NLIST}{XCOORD}{\WIDTH} % NOTE: Uses XTEMP, ZTEMP. See \dg@node. \def\dg@getwidth#1#2#3{% #3=\z@ \expandafter\@for\expandafter\dg@list\expandafter:\expandafter=#1\do{% \dg@XTEMP=\m@ne % impossible X in case \dg@list is empty \dg@list \ifnum #2=\dg@XTEMP #3=\dg@ZTEMP\fi}}% % \makebox(0,0)[POS]{TEXT} with POS expanded beforehand. % Usage: \dg@makebox[POS]{TEXT} \newoptcommand{\dg@makebox}{}[2]{% \expandafter\makebox\expandafter(\expandafter 0\expandafter,\expandafter0\expandafter)\expandafter[#1]{#2}}% % Produces nothing. % Usage:\dg@novector(X,Y){LaTeX_LENGTH} \def\dg@novector(#1,#2)#3{}% % Dotted arrow. % Uses temp vars XTEMP, YTEMP, ZTEMP, XEND, WEND. % Usage:\dg@dotvector(X,Y){LaTeX_LENGTH} \def\dg@dotvector(#1,#2)#3{% \begingroup \dg@XTEMP=#1\relax \dg@YTEMP=#2\relax \let\dg@NDOTS=\dg@XEND \let\dg@DOTDIAM=\dg@WEND % Compute number of dots: make x-spacing be DOTSPACING for arrows % of |slope| <= 1, and make y-spacing be DOTSPACING otherwise. % This way true spacing is never more than 30 percent off from DOTSPACING. \dg@NDOTS=\unitlength \multiply\dg@NDOTS by#3\relax \dg@ZTEMP=\dg@YTEMP \dg@changesign\dg@YTEMP by\dg@ZTEMP \ifnum\dg@XTEMP>\z@ \ifnum\dg@YTEMP>\dg@XTEMP \multiply\dg@NDOTS by\dg@YTEMP \divide\dg@NDOTS by\dg@XTEMP \fi \else\ifnum\dg@XTEMP<\z@ \ifnum\dg@YTEMP>-\dg@XTEMP \multiply\dg@NDOTS by\dg@YTEMP \divide\dg@NDOTS by-\dg@XTEMP \fi \fi\fi \dg@YTEMP=\dg@ZTEMP \divide\dg@NDOTS by\dgDOTSPACING % Compute increment vector between dots and round to \unitlength's. % Use NDOTS for this, not DOTSPACING, since DOTSPACING not exactly obeyed. \dg@ZTEMP=\unitlength \multiply\dg@ZTEMP by#3\relax \divide\dg@ZTEMP by\dg@NDOTS \ifnum\dg@XTEMP=\z@ \dg@changesign\dg@ZTEMP by\dg@YTEMP \dg@YTEMP=\dg@ZTEMP \else \dg@changesign\dg@ZTEMP by\dg@XTEMP \multiply\dg@YTEMP by\dg@ZTEMP \divide\dg@YTEMP by\dg@XTEMP \dg@XTEMP=\dg@ZTEMP \fi \divide\dg@XTEMP by\unitlength \divide\dg@YTEMP by\unitlength % draw dotted line with \multiput; add arrowhead as zero-length \vector. \begin{picture}(0,0) \dg@DOTDIAM=\dgDOTSIZE \divide\dg@DOTDIAM by\unitlength \multiput(0,0)(\dg@XTEMP,\dg@YTEMP){\dg@NDOTS}{\circle*{\dg@DOTDIAM}}% \multiply\dg@XTEMP by\dg@NDOTS \multiply\dg@YTEMP by\dg@NDOTS \put(\dg@XTEMP,\dg@YTEMP){\vector(#1,#2){0}}% \end{picture}% \endgroup}% % \let command \CMD equal funny-name command \NAME. % Usage: \dg@letname{\CMD}{NAME}. \def\dg@letname#1#2{% \relax\expandafter\let\expandafter #1\csname #2\endcsname\relax}% % Arg handlers, one for each LBLTYPE. % Grab specified labels from following input and feed them to \PROCESS. % Usage: \dgl@LBLTYPE{\PROCESS}... \def\dgl@#1{#1{}{}}% \def\dgl@t#1#2{#1{#2}{}}% \def\dgl@b#1#2{#1{}{#2}}% \def\dgl@tb#1#2#3{#1{#2}{#3}}% \def\dgl@l#1#2{#1{#2}{}}% \def\dgl@r#1#2{#1{}{#2}}% \def\dgl@lr#1#2#3{#1{#2}{#3}}% % Arrow variations, one for each OPTION (plus default). % Usage: \dgo@OPTION \@namedef{dgo@}{\let\dg@VECTOR=\vector \dg@LBLPOS=\dgARROWPARTS \divide\dg@LBLPOS by\tw@}% \@namedef{dgo@..}{\let\dg@VECTOR=\dg@dotvector}% \@namedef{dgo@-}{\let\dg@VECTOR=\line}% \@namedef{dgo@!}{\let\dg@VECTOR=\dg@novector}% \@namedef{dgo@1}{\dg@LBLPOS=\@ne\relax}% \@namedef{dgo@2}{\dg@LBLPOS=\tw@\relax}% \@namedef{dgo@3}{\dg@LBLPOS=3\relax}% \@namedef{dgo@4}{\dg@LBLPOS=4\relax}% \@namedef{dgo@5}{\dg@LBLPOS=5\relax}% \@namedef{dgo@6}{\dg@LBLPOS=6\relax}% \@namedef{dgo@7}{\dg@LBLPOS=7\relax}% \@namedef{dgo@8}{\dg@LBLPOS=8\relax}% \@namedef{dgo@9}{\dg@LBLPOS=9\relax}% % Depending on the TYPE, set preliminary values of basic arrow parameters: % \dg@DX, \dg@DY, \dg@SIZE, % to values which would be appropriate for a 1x1, 1:1 grid. % Usage: \dgt@TYPE \def\dgt@e{\dg@DX=\@ne \dg@DY=\z@ \dg@SIZE=\@ne}% \def\dgt@w{\dg@DX=\m@ne \dg@DY=\z@ \dg@SIZE=\@ne}% \def\dgt@n{\dg@DX=\z@ \dg@DY=\@ne \dg@SIZE=\@ne}% \def\dgt@s{\dg@DX=\z@ \dg@DY=\m@ne \dg@SIZE=\@ne}% \def\dgt@ne{\dg@DX=\@ne \dg@DY=\@ne \dg@SIZE=\@ne}% \def\dgt@se{\dg@DX=\@ne \dg@DY=\m@ne \dg@SIZE=\@ne}% \def\dgt@nw{\dg@DX=\m@ne \dg@DY=\@ne \dg@SIZE=\@ne}% \def\dgt@sw{\dg@DX=\m@ne \dg@DY=\m@ne \dg@SIZE=\@ne}% \def\dgt@nne{\dg@DX=\@ne \dg@DY=\tw@ \dg@SIZE=\@ne}% \def\dgt@nnw{\dg@DX=\m@ne \dg@DY=\tw@ \dg@SIZE=\@ne}% \def\dgt@sse{\dg@DX=\@ne \dg@DY=-\tw@ \dg@SIZE=\@ne}% \def\dgt@ssw{\dg@DX=\m@ne \dg@DY=-\tw@ \dg@SIZE=\@ne}% \def\dgt@ene{\dg@DX=\tw@ \dg@DY=\@ne \dg@SIZE=\tw@}% \def\dgt@ese{\dg@DX=\tw@ \dg@DY=\m@ne \dg@SIZE=\tw@}% \def\dgt@wnw{\dg@DX=-\tw@ \dg@DY=\@ne \dg@SIZE=\tw@}% \def\dgt@wsw{\dg@DX=-\tw@ \dg@DY=\m@ne \dg@SIZE=\tw@}%