%% $Id: xymatrix.doc,v 3.4 1997/05/18 01:14:25 krisrose Exp $ %% %% Xy-pic ``Matrix'' feature. %% Copyright (c) 1991-1997 Kristoffer H. Rose %% %% This file is part of the Xy-pic package for graphs and diagrams in TeX. %% See the companion README and INSTALL files for further information. %% Copyright (c) 1991-1997 Kristoffer H. Rose %% %% The Xy-pic package is free software; you can redistribute it and/or modify %% it under the terms of the GNU General Public License as published by the %% Free Software Foundation; either version 2 of the License, or (at your %% option) any later version. %% %% The Xy-pic package is distributed in the hope that it will be useful, but %% WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY %% or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License %% for more details. %% %% You should have received a copy of the GNU General Public License along %% with this package; if not, write to the Free Software Foundation, Inc., %% 675 Mass Ave, Cambridge, MA 02139, USA. %% \ifx\xyloaded\undefined \input xy \fi \xyprovide{matrix}{Matrix feature}{\stripRCS$Revision: 3.4 $}% {Kristoffer H.~Rose}{krisrose@brics.dk}% {BRICS/Computer Science, University of Aarhus, Ny Munkegade, building 540, DK--8000 Aarhus~C} \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% This option implements ``\Xy-matrices'', \ie, matrices where it is possible to refer to the entry objects by their row/column address. We first describe the general form of \Xy-matrices in~\S??[matrix], then in~\S??[coord] we summarise the new inate forms used to refer to entries. In~\S??[spacing] we explain what parameters can be set to change the spacing and orientation of the matrix, and in~\S??[entries] we explain how the appearance of the entries can be changed. \DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \paragraph*{Header:}\leavevmode \DOCHEADER \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{\Xy-matrices} ??=[matrix] % The fundamental command of this feature is % \begin{defs1} ??c![\xymatrix] |{||}| \end{defs1} \noindent\unskip % that reads a ??w![matrix] of entries in the generic \TeX\ row\&column format, \ie, where rows are separated with ??c![\\] and contain columns separated with ??c![&] (we discuss in the following sections what can be). Thus a matrix with "maxrow" rows and "maxcol" columns where each entry contains "row"|,|"col" is entered as $$ \begin{array}{llll} |\xymatrix{|\\ ~{|1,1 &|} &{|1,2 &|}\quad\cdots &{|1,|"maxcol"| \\|} \\ ~{|2,1 &|} &{|2,2 &|} &{|2,|"maxcol"| \\|} \\ ~~\vdots &\qquad\ddots \\ ~{"maxrow"|,1 &|}&{"maxrow"|,2 &|} &{"maxrow"|,|"maxcol"| }|} \end{array} $$ (\TeX\-nically the |&| character represents any `alignment tab', \ie, character with category code~4). A ??w![] can appear either in an \Xy-picture (as ) or ``stand-alone''. The aspects in which |\xymatrix| differs from ordinary matrix constructions, such as Plain \TeX's |\matrix{|\dots|}| and \LaTeX's |array| environment, are % \begin{itemize} \item arbitrary \Xy-pic ations may be specified in each entry and will be interpreted in a state where $c$ is the current entry, \item the entire matrix is an object itself with reference point as the top left entry, and \item a progress message ``||'' is printed for each matrix with $"rows"\times"cols"$ entries and \Xy-pic complexity "size" (the number of primitive operations performed), unless the declaration ??c![\SilentMatrices] is issued. \item Entries starting with a ??c![*] are special (described in~\S??[entries])\footnote{In general it is recommended that entries start with a non-expanding token, \ie, an ordinary (non-active) character, {\tt\otherbgroup}, or |\relax|, for compilation to work.}, so use |{*}| to get a $\star$. \end{itemize} % For example, % \begin{code} \xy \xymatrix{A&B\\C&D} \drop\frm{-} \drop\cir<8pt>{} \endxy \end{code} \displaycode % \noindent will typeset % $$\docode$$ % \BUG: Matrix nesting is not safe. Matrices are often quite slow to typeset so as a convenience all matrices can be set to compile (and not) automatically with the declarations % \begin{defs1} |\CompileMatrices| \cr |\NoCompileMatrices| \cr \end{defs1} \noindent\unskip % Matrices can be compiled or not individually, by using the explicit commands ??c![\xymatrixcompile] and ??c![\xymatrixnocompile] as well as by encapsulating in the usual |\xycompileto{|"name"|}{|\dots|}| (see note~??g[xy.doc:compile]). \NOTE: Matrices will only compile correctly if all entries start with a nonexpandable token, \ie, |{| or |\relax| or some non-active character. \DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \paragraph*{On the following code:} The complexity of this option stems from the fact that we cannot build the actual \Xy-picture until after the matrix has been typeset so that we know the sizes and places of all the entries. The handling described here is thus separated into several subprocedures. \paragraph*{Setup:} Not much---only to keep track of the rows and columns. These are not accesible to the user---should they? \DOCMODE( \xynew@{count}\Row \xynew@{count}\Col \xydef@\maxrow@{0} % highest row number used \xydef@\maxcol@{0} % highest column number used \xydef@\maxcolrow@{0} % a row with maximal number of columns \DOCMODE) There are some user-defined parameters summarised later. The following is an experimental set of `optimal' queueing macros using two queues and two counters to keep track of the progress. \DOCMODE( \xynew@{toks}\queue@ \xynew@{toks}\queue@@ \xynew@{count}\qcount@ \xynew@{count}\qcount@@ \xydef@\clearq@{% \global\queue@={}\global\qcount@=\@ne \global\queue@@={}\global\qcount@@=\z@} \xydef@\addq@#1{\global\advance\matrixsize@\@ne \ifnum\qcount@@<\qcount@ \let\addq@@=\addq@i \else \let\addq@@=\addq@ii \fi \expandafter\addq@@\the\queue@@\addq@@{#1}} \xylet@\addq@@=\relax \xydef@\addq@i#1\addq@@#2{% \global\advance\qcount@@\@ne \global\queue@@={#1#2}} \xydef@\addq@ii#1\addq@@#2{% \global\advance\qcount@\@ne \global\qcount@@=\z@ \global\queue@=\expandafter{\the\queue@#1#2}\global\queue@@={}} \xydef@\finishq@{\expandafter\addq@ii\the\queue@@\addq@@{}} \DOCMODE) \HACK: intended to make the addition of tokens to the token list faster: we first add to the `small' |\queue@@| as many times as we have added to the `big' |\queue@| before that. So we know we should always expand |\queue@@|: this is done first (last in the macro text). Then we call |\addq@@| that will either add to the small one or add the small one to the big one and then clear the small one! "Usage": Call |\clearq@| first. Then use |\addq@| as many times as desired. To get the queue in |\queue@| call |\finishq@| and use it. Finally clear |\queue@| (globally) or continue. \paragraph*{Main procedure:} Here is the main code which is concerned with initialisations and output of messages explaining how far the matrix construction has progressed. \DOCMODE( \xynew@{count}\matrixsize@ \xynew@{if}\ifnoisymatrices@ \noisymatrices@true \xydef@\SilentMatrices{\noisymatrices@false} \xydef@\NoisyMatrices{\noisymatrices@true} \xydef@\xymatrixnocompile{\global\matrixsize@=\z@ \ifnoisymatrices@\message{{} expected}{}}% \fi\fi\fi\fi \next@} \xydef@\xymatrix@ii#1{% % %\W@{ H@max=\meaning\H@max}% %\W@{ W@max=\meaning\W@max}% %\W@{ HW@max=\meaning\HW@max}% %\W@{ mkHrow@={\meaning\mkHrow@}}% %\W@{ mkWcol@={\meaning\mkWcol@}}% %\W@{ mkHmax@={\meaning\mkHmax@}}% %\W@{ mkWmax@={\meaning\mkWmax@}}% %\W@{ mkHWmax@={\meaning\mkHWmax@}}% % \xymatrix@pretypeset{#1}% % \ifnum\maxcol@=\z@ \mkWcol@ \mkWmax@ %\mkHrow@ \mkHmax@ \ifnum\maxcol@=\z@ \mkWcol@ \mkWmax@ \mkHrow@ \mkHmax@ \xdef\maxcol@{\the\Col}\xdef\maxcolrow@{\the\Row}\fi \ifnoisymatrices@\message{\maxcol@ x\maxrow@}\fi \xymatrix@measureit@@ \the\queue@ \global\queue@={}% \xymatrix@typeset{#1}\restore\xymatrix@insert \xy@@\leave@ \leave@ \ifnoisymatrices@\message{\the\matrixsize@>}\fi \ignorespaces} \DOCMODE) Here is where compilation of matrices is turned on/off. \DOCMODE( \xydef@\xymatrixcompile#1#{\xymatrixcompile@{#1}} \xydef@\xymatrixcompile@#1#2{\xycompile{\xymatrixnocompile#1{#2}}} \xydef@\CompileMatrices{\let\xymatrix=\xymatrixcompile} \xydef@\NoCompileMatrices{\let\xymatrix=\xymatrixnocompile} \DOCMODE) \TODO: Proper nesting that ensures that the matrix state is reestablished after the current one has been typeset. Each subprocedure is explained below. \paragraph*{Set row-rotation:} This sets the general direction of the rows as the current direction indicates. This direction is not known until \Xy-time so it gets put into the row/column definitions. \DOCMODE( \xydef@\xy@cossign@@{+} \xydef@\xy@sinsign@@{+} \xydef@\xy@cosabs@@{1} \xydef@\xy@sinabs@@{0} \xydef@\xy@tanabs@@{0} \xydef@\xy@cotabs@@{100} \xydef@\xymatrix@rotation{%?*[rotation] \xy@@{% \edef\xy@cossign@@{\ifdim\cosDirection\p@<\z@-\else+\fi}% \edef\xy@sinsign@@{\ifdim\sinDirection\p@<\z@-\else+\fi}% \edef\xy@cosabs@@{% \if\xy@cossign@@\cosDirection\else\xy@cossign@@\cosDirection\fi}% \edef\xy@sinabs@@{% \if\xy@sinsign@@\sinDirection\else\xy@sinsign@@\sinDirection\fi}% \dimen@=\xy@cosabs@@\p@ \dimen@ii=\xy@sinabs@@\p@ \ifdim\dimen@ii<.01\p@ \def\xy@cotabs@@{100}% \else \quotient@\xy@cotabs@@\dimen@\dimen@ii \fi \dimen@=\xy@cosabs@@\p@ \dimen@ii=\xy@sinabs@@\p@ \ifdim\dimen@<.01\p@ \def\xy@tanabs@@{100}% \else \quotient@\xy@tanabs@@\dimen@ii\dimen@ \fi}} \DOCMODE) \paragraph*{Pretypeset:} The purpose of this is to % \begin{itemize} \item set box8 to an halign with all the entries properly typeset to be measured in the next step, and \item store in a queue the operations that will define each entry as an object once the measurement is done and the distances between rows and columns is known. \end{itemize} % This is achieved as follows: Row/column counters, maxima, and queues are reset. The tab- and interlineskip is removed to make taking the constructed box apart easier. And the halign template is used to apply an appropriate action for each entry that updates the counters and queue. The special |\xymatrixsavedCOORD@| is used to store the original |\COORD@| except when diagrams are nested. \DOCMODE( \xylet@\xymatrixsavedCOORD@=\relax \xydef@\xymatrix@pretypeset#1{% \global\Row=\z@ \xdef\maxcol@{0}\clearq@ \setbox8=\vtop{% \ifx\xymatrixsavedCOORD@\relax \let\xymatrixsavedCOORD@=\COORD@ \fi \let\COORD@=\xymatrixCOORD@ \everycr{}\let\\=\cr \tabskip=\z@ \offinterlineskip \halign{\prentry@ ##!@&&\xyFN@\prentry@@##!@\cr#1\crcr}% \prentry@@@}% \xdef\maxrow@{\the\Row}% \finishq@} \DOCMODE) The first entry in each row is special; in particular it moves the entries from the columns of the previous row (if any) into the second-level queue: \DOCMODE( \xydef@\prentry@{\relax \ifnum\Row>\z@ \ifnum\maxcol@<\Col\xdef\maxcol@{\the\Col}\xdef\maxcolrow@{\the\Row}\fi \expandafter\xdef\csname maxcol@\the\Row\endcsname{\the\Col}\fi \global\advance\Row\@ne \global\Col=\z@ \xyFN@\prentry@@} \DOCMODE) The common part should first typeset the object. Then the resulting commands should be emitted as described below. While typesetting the entry, \Xy-commands are "disabled" by redefining |\xy@| to just `eat' its arguments, so they don't interfere\dots \DOCMODE( \xylet@\lastprentry@@=\relax \xydef@\xyeatall@{\let\xy@=\xyeat@ \change@oxy@\xyeat@ \let\xy@@ix@=\eat@} \xydef@\prentry@@{\global\advance\Col\@ne \let\next@=\prentry@@norm \ifoldxymatrix@\else \ifx *\next \DN@*{\xyFN@\prentry@@star}\fi \fi \next@} \xydef@\prentry@@star{\ifx *\next \DN@*{\xyFN@\prentry@@star@ii}% \else \DN@##1##{\prentry@@star@i{##1}}\fi \next@} \xydef@\prentry@@star@i#1#2#3!@{\gdef\lastprentry@@{*#1{#2}#3}% \setbox\lastobjectbox@=\object#1{#2}% \prentry@@x} \xydef@\prentry@@star@ii{% \ifx [\next \DN@[##1]{\DN@####1{\def\entrymodifiers@{[##1]####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\prentry@@norm}%] \else \DN@##1{\DN@####1{\def\entrymodifiers@{##1####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\prentry@@norm}% \fi \next@} \xydef@\prentry@@norm#1!@{\gdef\lastprentry@@{#1}% \DN@{\setbox\lastobjectbox@=\object}% \expandafter\next@\entrymodifiers@{\xyeatall@ \everyentry@ #1}% \prentry@@x} \xydef@\prentry@@x{% \edef\next@{{\noexpand\pre@emit{\the\Row}{\Upness@}{\the\Col}{\Leftness@}% {\the\L@c}{\the\R@c}{\the\D@c}{\the\U@c}{\expandafter\noexpand\the\Edge@c}}}% \expandafter\addq@\next@ \box\lastobjectbox@} \DOCMODE) Finally the following ensures that the last row in the diagram is treated correctly: if the last entry was an empty row then we ignore the row entirely if the |\ifoldxymatrix@| switch is set just as we ignore |*|-entries above. \DOCMODE( \xynew@{if}\ifoldxymatrix@ \oldxymatrix@false \xydef@\prentry@@@{\relax \let\next@=\prentry@@@i \ifoldxymatrix@ \ifnum\Col=\@ne \ifx\lastprentry@@\empty \global\advance\Row\m@ne \let\next@=\relax \fi\fi\fi \global\let\lastprentry@@=\relax \next@} \xydef@\prentry@@@i{% \ifnum\maxcol@<\Col \xdef\maxcol@{\the\Col}\xdef\maxcolrow@{\the\Row}\fi \expandafter\xdef\csname maxcol@\the\Row\endcsname{\the\Col}} \DOCMODE) Furthermore the code (??_[edge])~sets the edge and extents of the object and (??_[extents])~adds the object to the size of the matrix. \BUG: Currently ignores upness and leftness parameters. \DOCMODE( \xydef@\xy@minX@@{\z@} \xydef@\xy@maxX@@{\z@} \xydef@\xy@minY@@{\z@} \xydef@\xy@maxY@@{\z@} \xydef@\pre@emit#1#2#3#4#5#6#7#8#9{% % #1=R,#2=Upn,#3=C,#4=Leftn,#5=L,#6=R,#7=D,#8=U,#9=Edge. \global\Row=#1\global\Col=#3\relax \ifnum#3=\@ne \ifnum#1=\@ne \xy@@{\matrixorigin@}%?*[1,1] \else \count@@=#1\advance\count@@\m@ne %?*[r,1] \edef\next@{\noexpand\xy@@{\noexpand\cfromid@ {\xymatrixprefix@@\the\count@@,1}}}\next@ \pre@emit@ \W@maxout\Hrow@c@@\W@maxin\Hrow@in\xy@tanabs@@ \X@c\xy@sinsign@@\xy@sinabs@@\xymatrixrowsep@ \pre@emit@ \Hrow@c@@\W@maxout\Hrow@in\W@maxin\xy@cotabs@@ \Y@c{-\xy@cossign@@}\xy@cosabs@@\xymatrixrowsep@ \fi \else \count@@=#3\advance\count@@\m@ne %?*[r,c] \pre@emit@ \Wcol@c@@\H@maxout\Wcol@in\H@maxin\xy@cotabs@@ \X@c\xy@cossign@@\xy@cosabs@@\xymatrixcolsep@ \pre@emit@ \H@maxout\Wcol@c@@\H@maxin\Wcol@in\xy@tanabs@@ \Y@c\xy@sinsign@@\xy@sinabs@@\xymatrixcolsep@ \fi \DN@##1{\xy@@{\L@c=#5\R@c=#6\D@c=#7\U@c=#8\Edge@c={#9}\idfromc@{##1#1,#3}}}% \expandafter\next@\expandafter{\xymatrixprefix@@}%?*[edge] \xy@@{%?*[extents] \dimen@=\X@c \advance\dimen@-\L@c \ifdim\dimen@<\xy@minX@@ \edef\xy@minX@@{\the\dimen@}\fi \dimen@=\X@c \advance\dimen@+\R@c \ifdim\dimen@>\xy@maxX@@ \edef\xy@maxX@@{\the\dimen@}\fi \dimen@=\Y@c \advance\dimen@-\D@c \ifdim\dimen@<\xy@minY@@ \edef\xy@minY@@{\the\dimen@}\fi \dimen@=\Y@c \advance\dimen@+\U@c \ifdim\dimen@>\xy@maxY@@ \edef\xy@maxY@@{\the\dimen@}\fi}} \DOCMODE) The following procedure represents the similarity of the four lines for the coordinates in the computation above\dots \TODO: describe this properly\dots \DOCMODE( \xydef@\pre@emit@#1#2#3#4{#1\A@ #2\B@ #3\R@ #4\dimen@ \edef\next@{{\the\A@}{\the\B@}{\the\R@}{\the\dimen@}}% \expandafter\pre@emit@i\next@} \xydef@\pre@emit@i#1#2#3#4#5{\xy@@{% % Emit R := min(#1,#5#2) + min(#3,#5#4) \dimen@=#2\R@=#5\dimen@ \dimen@=#1\relax \ifdim\R@>\dimen@ \R@=\dimen@ \fi \dimen@=#4\B@=#5\dimen@ \dimen@=#3\relax \ifdim\B@>\dimen@ \B@=\dimen@ \fi \advance\R@\B@}% \pre@emit@ii} \xydef@\pre@emit@ii#1#2#3#4{\xy@@{% % Emit #1 := #1 + #2*[ R + #3#4 ] \dimen@=#4\dimen@=#3\dimen@ \advance\R@\dimen@ \advance#1#2\R@}} \xydef@\Wcol@in#1{#1=\csname Wcol@\the\Col\endcsname #1=.5#1} \xydef@\Wcol@out#1{#1=\csname Wcol@\the\Col\endcsname #1=.5#1} \xydef@\Wcol@c@@#1{#1=\csname Wcol@\the\count@@\endcsname #1=.5#1} \xydef@\W@maxin#1{#1=\W@max #1=.5#1} \xydef@\W@maxout#1{#1=\W@max #1=.5#1} \xydef@\Hrow@in#1{#1=\csname Hrow@\the\Row\endcsname #1=.5#1} \xydef@\Hrow@out#1{#1=\csname Hrow@\the\Row\endcsname #1=.5#1} \xydef@\Hrow@c@@#1{#1=\csname Hrow@\the\count@@\endcsname #1=.5#1} \xydef@\H@maxin#1{#1=\H@max #1=.5#1} \xydef@\H@maxout#1{#1=\H@max #1=.5#1} \DOCMODE) \BUG: It should be possible to change te adjustment more profoundly for individual entries, rows, and columns. \paragraph*{Measure:} Take the created box8 apart to define the macros |\Wcol@|"col" and |\Hrow@|"row" containing the width and height of the bounding box of the entries in the row/column. Finally the commands collected in the queue are executed (hopefully they'll invoke |\pre@emit| a number of times). This is a hook because some special cases won't need it\dots \DOCMODE( \xydef@\H@max{\z@} \xydef@\W@max{\z@} \xydef@\HW@max{\z@} \xydef@\mkHrow@{} \xydef@\mkWcol@{} \xydef@\mkHmax@{} \xydef@\mkWmax@{} \xydef@\mkHWmax@{} \xydef@\mkHWdefaults@{\let\xymatrix@measureit@@=\xymatrix@measureit \let\mkHrow@=\Hrow@R \let\mkWcol@=\Wcol@C \def\mkHmax@{\ifdim\dimen@>\H@max\relax \xdef\H@max{\the\dimen@}\fi}% \def\mkWmax@{\ifdim\dimen@>\W@max\relax \xdef\W@max{\the\dimen@}\fi}% \let\mkHWmax@=\HWmax@max} \xydef@\Hrow@R{\expandafter\xdef\csname Hrow@\the\Row\endcsname{\the\dimen@}} \xydef@\Wcol@C{\expandafter\xdef\csname Wcol@\the\Col\endcsname{\the\dimen@}} \xydef@\Hrow@max{\expandafter\gdef\csname Hrow@\the\Row\endcsname{\H@max}} \xydef@\Wcol@max{\expandafter\gdef\csname Wcol@\the\Col\endcsname{\W@max}} \xydef@\Hrow@HWmax{\expandafter\gdef\csname Hrow@\the\Row\endcsname{\HW@max}} \xydef@\Wcol@HWmax{\expandafter\gdef\csname Wcol@\the\Col\endcsname{\HW@max}} \xydef@\HWmax@max{% \ifdim\H@max>\W@max\global\let\HW@max=\H@max\else\global\let\HW@max=\W@max\fi} \xydef@\HWmax@set#1{\gdef\HW@max{#1}% \global\let\H@max=\HW@max \global\let\W@max=\HW@max} \xydef@\xymatrix@measureit{% \xdef\H@max{\z@}\xdef\W@max{\z@}% \setbox6=\vbox{\unvbox8 \global\Row=\maxrow@ \loop@ \dimen@ii=\lastskip\unskip \ifnum\z@<\Row \setbox4=\lastbox \dimen@=\dp4 \advance\dimen@\ht4 \mkHrow@ \mkHmax@ \ifnum\Row=\maxcolrow@ \setbox2=\hbox{\unhbox4 % \global\Col=\maxcol@ \loop@ \dimen@ii=\lastskip\unskip \ifnum\z@<\Col \setbox\z@=\lastbox \dimen@=\wdz@ \mkWcol@ \mkWmax@ \global\advance\Col\m@ne \repeat@}\fi \global\advance\Row\m@ne \repeat@}% \mkHWmax@} \xylet@\xymatrix@measureit@@=\relax \DOCMODE) \TODO: Allow non-default spacing between particular rows/columns as well as different justification of the entire matrix\dots \paragraph*{Typeset:} Retypeset the entire diagram using a hacked halign: its template typesets each entry as $$ |\POS|\,|"|"row"|,|"col"|"|\,|*|\,"object"\,|\relax|\,"\Xy-commands"|\relax| $$ where "object" is the contents of the entry translated into \Xy-pic form and "\Xy-commands" entails the commands used in this particular entry. \DOCMODE( \xydef@\xymatrix@typeset#1{% \clearq@ \hbox{\vtop{\xyqall@ \xy@@{\ifx\xymatrixsavedCOORD@\relax \enter@{\noexpand\let\noexpand\COORD@\noexpand\xymatrixsavedCOORD@}% \let\xymatrixsavedCOORD@=\COORD@ \let\COORD@=\xymatrixCOORD@ \else \enter@{}\fi}% \ifx\xymatrixsavedCOORD@\relax \let\xymatrixsavedCOORD@=\COORD@ \fi \let\COORD@=\xymatrixCOORD@ \kern\z@ \global\Row=\z@ \everycr{}\let\\=\cr \tabskip=\z@ \offinterlineskip \halign{\entry@##!@&&\entry@@##!@\cr#1\crcr}% \xy@@{\leave@}}}% \finishq@ \expandafter\xy@@\expandafter{\the\queue@}\global\queue@={}} \DOCMODE) Here are the template execution macros: We reset the |\queue@| for each entry, |\drop| it the usual way except first all \Xy-commands are `redirected' to the queue, and then typeset them. \DOCMODE( \xydef@\entry@{\relax \global\advance\Row\@ne \global\Col=\z@ \entry@@} \DOCMODE) Again some parsing determines whether this is a |*|-object or a normal object: \DOCMODE( \xydef@\entry@@{\global\advance\Col\@ne \DN@##1,##2,##3@{\xy@{ENTRY "##3##1,##2"}{\Row=##1 \Col=##2\relax \cfromid@{##3##1,##2}\pfromc@}}% \edef\nextii@{\the\Row,\the\Col,\xymatrixprefix@@ @}% \expandafter\next@\nextii@ \xyFN@\entry@@i} \xydef@\entry@@i{\let\next@=\entry@@norm \ifoldxymatrix@\else \ifx *\next \DN@*{\xyFN@\entry@@star}\fi \fi \next@} \xydef@\entry@@star{\ifx *\next \DN@*{\xyFN@\entry@@star@ii}% \else \DN@##1##{\entry@@star@i{##1}}\fi \next@} \xydef@\entry@@star@i#1#2#3!@{% \xy@@ix@{{#1}{#2}}\xy@@{\expandafter\dropentry@\the\toks9}% \setboxz@h{\xyqall@ \ifx\xymatrixsavedCOORD@\relax \let\xymatrixsavedCOORD@=\COORD@ \fi \let\COORD@=\xymatrixCOORD@ \everyentry@ #3}% \setbox\z@=\copy\voidb@x} \xydef@\entry@@star@ii{% \ifx [\next \DN@[##1]{\DN@####1{\def\entrymodifiers@{[##1]####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\entry@@norm}%] \else \DN@##1{\DN@####1{\def\entrymodifiers@{##1####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\entry@@norm}% \fi \next@} \xydef@\entry@@norm#1!@{% \DN@##1{\expandafter\xy@@ix@ \expandafter{\expandafter{\entrymodifiers@}{##1}}}% \expandafter\next@\expandafter{\everyentry@#1}% \xy@@{\expandafter\dropentry@\the\toks9}% \setbox\z@=\expandafter\object\entrymodifiers@{\xyqall@ \ifx\xymatrixsavedCOORD@\relax \let\xymatrixsavedCOORD@=\COORD@ \fi \let\COORD@=\xymatrixCOORD@ \everyentry@ #1}% \setbox\z@=\copy\voidb@x} \DOCMODE) Dropping the entry is just retypesetting it at the right location again ignoring the \Xy-stuff: \DOCMODE( \xydef@\dropentry@#1#2{\drop@{#1}{\xyeatall@ \ifx\xymatrixsavedCOORD@\relax \let\xymatrixsavedCOORD@=\COORD@ \fi \let\COORD@=\xymatrixCOORD@ #2}} \DOCMODE) The macros used for queuing are these; only the toks9 replacement is tricky; furthermore queueing is "not" done if we are saving because the effect will give the same result without risk of extremely long lines in the compiled file! \DOCMODE( \xydef@\xyqall@{% \ifxysaving@ \let\xy@=\xyqs@ \let\xy@@ix@=\xysave@@toksix@ \else \let\xy@=\xyq@ \let\xy@@ix@=\xyq@@toksix@ \fi \change@oxy@\xy@} \xydef@\xyq@#1#2{\addq@{#2}} \xydef@\xyq@@toksix@{\begingroup \xyuncatcodes \afterassignment\xyq@@toksix@i \global\toks9=} \xydef@\xyq@@toksix@i{% \DN@##1{\endgroup \xy@@{\global\toks9={##1}}}% \expandafter\next@\expandafter{\the\toks9}} \xydef@\xyqs@{\global\advance\matrixsize@\@ne \xysave@} \DOCMODE) \paragraph*{Insert:} Finally we insert the matrix in the \Xy-picture logically by ensuring that it has the right size \DOCMODE( \xydef@\xymatrix@insert{% \xy@@{\edef\nextii@{{\xy@minX@@}{\xy@maxX@@}{\xy@minY@@}{\xy@maxY@@}}% \expandafter\xymatrix@insert@\nextii@}} \xydef@\xymatrix@insert@#1#2#3#4{\matrixorigin@ \L@c=+\X@c \advance\L@c-#1\relax \R@c=-\X@c \advance\R@c+#2\relax \D@c=+\Y@c \advance\D@c-#3\relax \U@c=-\Y@c \advance\U@c+#4\relax \Edge@c={\rectangleEdge}} \DOCMODE) \TODO: Should handle other forms than reference point at center of~|"1,1"| as hardcoded here. In particular reference point at baseline of |"1,1"| would be useful\dots \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{New coordinate formats} ??=[coord] % It is possible within entries to refer to all the entries of the \Xy-matrix using the following special inate forms: % \begin{defs} % {}\kern-10pt|"|$r$|,|$c$|"|\kern5pt & Position and extents of entry in row $r$, column $c$ (top left is |"1,1"|) \cr {}\kern-15pt|[|$\Delta r$|,|$\Delta c$|]|\kern10pt & $\Delta r$ rows below, $\Delta c$ columns right of current entry \cr {}\kern-15pt|[| \star\ |]|\kern10pt & entry reached by s; each is one of |dulr| describing one `move' to a neighbor entry \cr {}\kern-15pt|[| \plus\ \ |]| & on straight line to "non-empty" |[|\star|]| \cr \end{defs} \noindent\unskip % So the current entry has the synonyms |[0,0]|, |[]|, |[rl]|, |[ud]|, |[dudu]|, etc., as well as its `absolute' name |"|$r$|,|$c$|"|. These forms are useful for defining diagrams where the entries are related, \eg, % \begin{code} $$\xy \xymatrix{ A \POS[];[d]**\dir{~}, [];[dr]**\dir{-} \\ B & C \POS[];[l]**\dir{.} } \endxy$$ \end{code} \docode % was typeset by % \displaycode % If an entry outside the \Xy-matrix is referenced then an error is reported. In case several matrices are used in the same diagram, and they refer to each other, then it is useful to give the matrices different |"||"| such that they can refer to each other using the following special coordinate forms that all have the same meaning except the target entry is picked from a particular matrix: % \begin{defs1} |"|$r$|,|$c$|"| \cr |["||"|$\Delta r$|,|$\Delta c$|]| \cr |["||"| \star\ |]| \cr |["||"| \plus\ \ |]| \cr \end{defs1} \noindent\unskip % In fact absolute references "must" always be given using |"||,||"|, "even inside the matrix itself". Here is an example using this: % \begin{code} \xy \xymatrix"*"{% A & B \\ C & D }% \POS*\frm{--} \POS-(10,3) \xymatrix{% A' \ar@{.}["*"] & B' \ar@{.}["*"] \\ C' \ar@{.}["*"] & D' \ar@{.}["*"] }% \POS*\frm{--} \endxy \end{code} $$\docode$$ % was typeset (using the `frame' extension and `arrow' feature) by % \displaycode \DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% These handle the parsing and interpretation of bracketed inates; the number is computed already at parse time: \DOCMODE( \xylet@\thematrixCOORD@@=\relax \xylet@\thematrixprefix@@=\relax \xydef@\xymatrixCOORD@{% \ifx [\next %] \DN@[##1]{\xy@{[##1]}{\def\thematrixCOORD@@{[##1]}}% \xyFN@\xymatrixCOORD@i##1]}% \else \let\next@=\xymatrixsavedCOORD@ \fi \next@} \xydef@\xymatrixCOORD@i{\count@=\Row \count@@=\Col \let\thematrixprefix@@=\xymatrixprefix@@ \ifcat A\noexpand\next \DN@##1{\expandafter\notrelaxorelse@\csname xymatrixCOORD@i@##1\endcsname \xymatrixCOORD@other}%[[ \else\ifx ]\next \DN@]{\xymatrixCOORD@x}% \else\ifx "\next \DN@"##1"{\DN@{##1}\edef\thematrixprefix@@{\codeof\next@}% \xyFN@\xymatrixCOORD@ii}% \else \let\next@=\xymatrixCOORD@other \fi\fi\fi \next@} \xydef@\xymatrixCOORD@i@u{\advance\count@ \m@ne\xyFN@\xymatrixCOORD@ii} \xydef@\xymatrixCOORD@i@d{\advance\count@ \@ne \xyFN@\xymatrixCOORD@ii} \xydef@\xymatrixCOORD@i@l{\advance\count@@\m@ne\xyFN@\xymatrixCOORD@ii} \xydef@\xymatrixCOORD@i@r{\advance\count@@\@ne \xyFN@\xymatrixCOORD@ii} \xydef@\xymatrixCOORD@ii{% \ifcat A\noexpand\next \DN@##1{\expandafter\notrelaxorelse@\csname xymatrixCOORD@i@##1\endcsname \xymatrixCOORD@error}% \else\ifx ]\next \DN@]{\xymatrixCOORD@x}% \else \let\next@=\xymatrixCOORD@xx \fi\fi \next@} \xydef@\xymatrixCOORD@error#1{\DN@{#1}% \xyerror@{illegal (\codeof\next@): illegal [...] target form}{}% \xyFN@\xymatrixCOORD@ii} \xydef@\xymatrixCOORD@other#1,#2]{% \advance\count@#1\advance\count@@#2\xymatrixCOORD@x} \DOCMODE) The next does the actual lookup at \Xy-time where we can still print an error message using the saved original form. \DOCMODE( \xydef@\xymatrixCOORD@x{% \DN@##1{\xy@@{% \expandafter\let\expandafter\next@\csname Q@##1\endcsname \ifx\next@\relax \xyerror@RC{##1}\else \next@ \fi}% \afterCOORD@}% \edef\nextii@{{\thematrixprefix@@\the\count@,\the\count@@}}% \expandafter\next@\nextii@} \xydef@\xymatrixCOORD@xx{% \DN@##1{\xy@@{% \expandafter\let\expandafter\next@\csname Q@##1\endcsname \ifx\next@\relax \xyerror@RC{##1}\else \next@\no@@ \fi}% \afterPLACE\xymatrixCOORD@after}% \edef\nextii@{{\thematrixprefix@@\the\count@,\the\count@@}}% \expandafter\next@\nextii@} \xydef@\xymatrixCOORD@after{% \ifx ]\next \DN@]{\afterCOORD@}% \else \let\next@=\xymatrixCOORD@error \fi \next@} \xydef@\xyerror@RC#1{\xyerror@{in entry \string"\the\Row,\the\Col\string": No \codeof\thematrixCOORD@@\space(is \string"#1\string") from here}{}} \DOCMODE) \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Spacing and rotation} ??=[spacing] % Any matrix can have its ??w![spacing]??w[matrix spacing] and ??w![orientation]??w[matrix orientation] changed by adding `switches' between |\xymatrix| and the opening |{|. The default spacing between entries of matrix is changed with the switches % \begin{defs1} ??c![@R] \cr ??c![@C] \cr ??c![@] \cr \end{defs1} \noindent\unskip % that change ??w![row spacing], ??w![column spacing], and both, respectively, as indicated by the and , where the may be omitted and can be given as one of |R| and |C| to indicate the current value of the parameter in question. \NOTE: there is "no default". In addition, \Xy-pic can be instructed to use a `??w![fixed grid]' for the matrix with the switches % \begin{defs1} ??c![@!R] \cr ??c![@!C] \cr ??c![@!] \end{defs1} \noindent\unskip % that ensure that the row spacing, column spacing, and both, respectively, pretending that "all" entries have the size of the largest entry (without modifying the real size of the entries, of course, only the spacing -- to get the entries to "really" have the same size use a |@*|\dots\ described in \S??[entries] below). The special variants % \begin{defs1} ??c![@!0] \cr ??c![@!=] \end{defs1} \noindent\unskip % pretend that entries have zero or height and width for computing row and column spacing; as above inserting |R| or |C| just after the |!| makes this affect only the row "or" column spacing, \eg, |@!R0| means that the row spacing only is between the centers of the rows. Finally, the spacing of things that are typeset can be adjusted separately: % \begin{defs1} ??c![@M] \cr ??c![@W] \cr ??c![@H] \cr ??c![@L] \end{defs1} \noindent\unskip % will adjust the ??w![entry margin], ??w![entry width], ??w![entry height], and ??w![label separation] used (the latter is actually passed to the arrow feature). \DOCMODE( \xylet@\xymatrix@addop@@=\relax \xydef@\xymatrix@at{\def\xymatrix@addop@@{\xymatrix@R\xymatrix@C}% \ifx \space@\next \expandafter\DN@\space{\xyFN@\xymatrix@at}%gobble spaces \else\ifx !\next \DN@!{\xyFN@\xymatrix@fix}% \else\addPLUS@\ifx \next \let\next@=\xymatrix@addop \else\addDASH@\ifx \next \let\next@=\xymatrix@addop \else\addEQ@\ifx \next \let\next@=\xymatrix@addop \else\ifx 1\next \DN@1{\def\everyentry@{\vphantom(}%) \let\objectmargin@=\p@ \xyFN@\xymatrix@setup}% \else\ifx R\next \def\xymatrix@addop@@{\xymatrix@R}\DN@ R{\xymatrix@addop}% \else\ifx C\next \def\xymatrix@addop@@{\xymatrix@C}\DN@ C{\xymatrix@addop}% \else\ifx M\next \def\xymatrix@addop@@{\xymatrix@M}\DN@ M{\xymatrix@addop}% \else\ifx L\next \def\xymatrix@addop@@{\xymatrix@L}\DN@ L{\xymatrix@addop}% \else\ifx H\next \def\xymatrix@addop@@{\xymatrix@H}\DN@ H{\xymatrix@addop}% \else\ifx W\next \def\xymatrix@addop@@{\xymatrix@W}\DN@ W{\xymatrix@addop}% \else\ifx *\next \DN@*{\xyFN@\xymatrix@mods}% \else \DN@{\afterDIRECTIONorEMPTY {\xymatrix@rotation \xyFN@\xymatrix@setup}{% \xyerror@{ or or one of RCMLHW*! expected}{}% \xyFN@\xymatrix@setup}}% \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@} \xydef@\xymatrix@fix{% \ifx \space@\next \expandafter\DN@\space{\xyFN@\xymatrix@fix}%gobble spaces \else\ifx R\next \let\mkHrow@=\Hrow@max \DN@ R{\xyFN@\xymatrix@fix@}% \else\ifx C\next \let\mkWcol@=\Wcol@max \DN@ C{\xyFN@\xymatrix@fix@}% \else \let\mkHrow@=\Hrow@HWmax \let\mkWcol@=\Wcol@HWmax \let\next@=\xymatrix@fix@ \fi\fi\fi \next@} \xydef@\xymatrix@fix@{% \ifx \space@\next \expandafter\DN@\space{\xyFN@\xymatrix@fix@}%gobble spaces \else\ifx 0\next \def\mkHWmax@{\HWmax@set\z@}\DN@ 0{\xyFN@\xymatrix@setup}% \else\addEQ@\ifx\next \addEQ@\DN@{\afterassignment\xymatrix@fix@x\dimen@ii=}% \else \let\mkHWmax@=\HWmax@max \let\next@=\xymatrix@setup \fi\fi\fi \next@} \xydef@\xymatrix@fix@x{% \edef\mkHWmax@{\noexpand\HWmax@set{\the\dimen@ii}}\xyFN@\xymatrix@setup} \xydef@\xymatrix@addop{\afterADDOP{\xyFN@\xymatrix@addop@}} \xydef@\xymatrix@addop@{% \ifx \space@\next \expandafter\DN@\space{\xyFN@\xymatrix@addop@}%gobble spaces \else\ifx R\next \DN@ R{\xy@{R}{}\dimen@ii=\xymatrixrowsep@\xymatrix@addop@x}% \else\ifx C\next \DN@ C{\xy@{C}{}\dimen@ii=\xymatrixcolsep@\xymatrix@addop@x}% \else \DN@{\afterassignment\xymatrix@addop@x\dimen@ii=}\fi\fi\fi \next@} \xydef@\xymatrix@addop@x{\expandafter\xy@\expandafter{\the\dimen@ii}{}% \xymatrix@addop@@ \xyFN@\xymatrix@setup} \xydef@\xymatrix@R{\Addop@@\xymatrixrowsep@\dimen@ii} \xydef@\xymatrix@C{\Addop@@\xymatrixcolsep@\dimen@ii} \xydef@\xymatrix@M{\Addop@@\objectmargin@\dimen@ii} \xydef@\xymatrix@L{\Addop@@\labelmargin@\dimen@ii} \xydef@\xymatrix@H{\Addop@@\objectheight@\dimen@ii} \xydef@\xymatrix@W{\Addop@@\objectwidth@\dimen@ii} \DOCMODE) The spacing can also be changed for en entire \TeX\ group by the declarations % \begin{defs1} |\xymatrixrowsep| |{||}| \cr |\xymatrixcolsep| |{||}| \cr \end{defs1} \noindent\unskip % The default spacing for both is |2pc|. \DOCMODE( \xydef@\xymatrixrowsep@{2pc} \xydef@\xymatrixcolsep@{2pc} \xydef@\xymatrixrowsep{\afterADDOP{\Addop@@\xymatrixrowsep@}} \xydef@\xymatrixcolsep{\afterADDOP{\Addop@@\xymatrixcolsep@}} \DOCMODE) % \TODO: optimize processing of matrices with constant grid. An entire matrix can be rotated by adding a rotation of the form % \begin{defs1} |@| \cr \end{defs1} \noindent\unskip % This will set the orientation of the rows to (the default corresponds to |r|, \ie, rows are oriented left to right). \DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% The code is the first procedure of the main matrix code above (??_[rotation]); factors are used by |\pre@emit|. \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection{Entries} ??=[entries] % The appearance of a single entry can be modified by entering it as % \begin{defs1} ??c![*] \end{defs1} \noindent\unskip % This makes the particular entry ignore the entry modifiers and typeset as a kernel object with the same reference point as the (center of) the default object would have had. Additional object s may be added to an otherwise ordinary entry by using the forms % \begin{defs1} ??c![**]|[||]| \cr %|**| \cr |**{|*|}| \cr \end{defs1} \noindent\unskip % The first sets the default for objects (\cf~note~??g[xy.doc:]), the second a default size (change, \cf~note~??g[xy.doc: size]), and the last makes it possible to add any modifier of~\S??g[xy.doc:object], \eg, for recentering entries after the ??w![default entry] form which is equivalent to `|!C| |+<|$2\times"object"\-"margin"$|>|' (with the effect of centering the object and add the "object"\-"margin") to all sides. \begin{exercise} Typeset the following diagram: % \begin{code} \xymatrix @!=1pc { **[l] A\times B \ar[r]^{/A} \ar[d]_{/B} & B \ar[d]^{\times A} \\ A \ar[r]_{B\times} & **[r] B\times A } \end{code} $$\docode$$ % \answercode \answertext{The author did \displaycode} \end{exercise} It is also possible to use these |@|s (as usual between |\xymatrix| and the leading |{|): % \begin{defs1} ??c![@*]|[||]| \cr |@*| \cr \end{defs1} \noindent\unskip % which are equivalent to changing all entries to behave as if they had started with the similar |**|-form. \TODO: Allow |**| for entries. If the default set of entry modifiers should be changed then the following declaration must be issued before the |\xymatrix| command; this is the only way to actually switch the initial default centering and spacing off: % \begin{defs1} ??c![\entrymodifiers]|={| \star\ |}| \end{defs1} \begin{exercise} How did the author typeset the following matrix? % \begin{code} \entrymodifiers={=<1pc>[o][F-]} \xymatrix @ur { A \save[];[r] **\dir{-}, [];[dr]**\dir{-}, [];[d] **\dir{-}\restore & B \\ C & D } \end{code} $$\docode$$ % \answercode \answertext{Modifiers are used to make all entries round with a frame -- the general form is used to ensure that the sequence is well-defined. Finally the matrix is rotated to make it possible to enter it as a simple square: \displaycode} \end{exercise} \BUG: The four constructions |@*[|\dots|]|, |**[|\dots|]|, |@*| , and, |**{|\dots|}|, "accumulate in reverse order". Only entries starting with a single |*| completely override the modifiers with a |@*|-construction. \DOCMODE( \xydef@\xymatrix@mods{% \ifx \space@\next \expandafter\DN@\space{\xyFN@\xymatrix@mods}%gobble spaces \else\ifx [\next \DN@ [##1]{\xy@{[##1]}{}\DN@####1{\def\entrymodifiers@{[##1]####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\xyFN@\xymatrix@setup}%] \else\addPLUS@\ifx \next \DN@##1{\DNii@{##1}\xyFN@\xymatrix@change}% \else\addDASH@\ifx \next \DN@##1{\DNii@{##1}\xyFN@\xymatrix@change}% \else\addEQ@\ifx \next \DN@##1{\DNii@{##1}\xymatrix@set}% \else \let\next@=\xymatrix@mods@error \fi\fi\fi\fi\fi \next@} \xydef@\xymatrix@set{% \begingroup \plainxy@ \afterVECTORorEMPTY\xymatrix@mods@x\xymatrix@mods@error} \xydef@\xymatrix@change{% \addEQ@\ifx\next \DN@##1{\expandafter\DNii@\expandafter{\nextii@##1}% \expandafter\xy@\expandafter{\nextii@}{}\begingroup \plainxy@ \afterVECTORorEMPTY\xymatrix@mods@x\xymatrix@mods@xx}% \else \DN@{\expandafter\xy@\expandafter{\nextii@}{}\begingroup \plainxy@ \afterVECTORorEMPTY\xymatrix@mods@x\xymatrix@mods@xx}\fi \next@} \xydef@\xymatrix@mods@x{\expandafter\xy@\expandafter{\nextii@}{}% \def\next@##1##2##3{\def\nextii@####1{##1##2####1##3}}% \addGT@{\addLT@{\expandafter\next@\expandafter{\nextii@}}}% \DN@##1{\gdef\tmp@@@{{##1}}}% \edef\nextiii@{{\the\X@c,\the\Y@c}}% \expandafter\expandafter\expandafter\next@ \expandafter\expandafter\expandafter{\expandafter\nextii@\nextiii@}% \endgroup \DN@##1{\xy@{##1}{}\DN@####1{\def\entrymodifiers@{##1####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\xyFN@\xymatrix@setup}% \expandafter\next@\tmp@@@} \xydef@\xymatrix@mods@xx{\expandafter\xy@\expandafter{\nextii@}{}% \expandafter\gdef\expandafter\tmp@@@\expandafter{\expandafter{\nextii@}}% \endgroup \DN@##1{\xy@{##1}{}\DN@####1{\def\entrymodifiers@{##1####1}}% \expandafter\next@\expandafter{\entrymodifiers@}\xyFN@\xymatrix@setup}% \expandafter\next@\tmp@@@} \xydef@\xymatrix@mods@error{\endgroup \xyerror@{Impossible @* .}{}\xyFN@\xymatrix@setup} \xywarnifdefined\entrymodifiers \expandafter\def\addEQ@\entrymodifiers#1{\def\entrymodifiers@{#1}\ignorespaces} \xydef@\entrymodifiers@{\entrybox} \xydef@\entrybox#1{\hbox{\setbox\z@=\objectbox{#1}% \L@p=\wdz@ \D@p=\ht\z@ \advance\D@p\dp\z@ \dimen@=\objectwidth@ \advance\dimen@-\L@p \ifdim\dimen@>\z@ \advance\L@p\dimen@ \R@p=.5\dimen@ \else \R@p=\z@ \fi \dimen@=\objectheight@ \advance\dimen@-\D@p \ifdim\dimen@>\z@ \advance\D@p\dimen@ \fi \dimen@=\objectmargin@ \advance\L@p2\dimen@ \advance\D@p2\dimen@ \U@p=-.5\ht\z@ \advance\U@p.5\dp\z@ \advance\R@p\objectmargin@ \setboxz@h{\kern\R@p \raise\U@p\boxz@}% \wdz@=\L@p \ht\z@=.5\D@p \dp\z@=.5\D@p \boxz@}} \DOCMODE) Finally, the following is specially suited for `one-line' matrices included in text: % \begin{defs1} ??c![@1] \cr \end{defs1} \noindent\unskip % will insert a `math strut' (|\vphantom(|) into each entry to make its centering appropriate for text. This is just an abbreviation using the following declaration which will setup that should be inserted before everything else in each entry. Initially it is empty but % \begin{defs1} ??c![\everyentry]|={| |}| \end{defs1} \noindent\unskip % will insert first in each entry; inside the counter registers ??c![\Row] and ??c![\Col] are set to the current entry's row and column, respectively. For example, % \begin{code} \everyentry={{\the\Row,\the\Col}} \xymatrix @*[F]@*[o] { {} \POS[];[r]**\dir{..} & \\ {} \POS[];[ur]**\dir{--} } \end{code} \displaycode \noindent\unskip % will typeset % $$\docode$$ \DOCMODE( \xywarnifdefined\everyentry \expandafter\def\addEQ@\everyentry#1{\def\everyentry@{#1}\ignorespaces} \xylet@\everyentry@=\empty \DOCMODE) \noindent\NOTE: When using compilation, changes to |\everyentry| and |\entrymodifiers| will "not" result in recompilation even when the constructed matrix changes -- you may have to remove the |.xyc| file manually. \begin{exercise} How did the author typeset the following diagram? % \begin{code} \xymatrix @W=3pc @H=1pc @R=0pc @*[F-] {% : \save+<-4pc,1pc>*\hbox{\it root} \ar[] \restore \\ {\bullet} \save*{} \ar`r[dd]+/r4pc/`[dd][dd] \restore \\ {\bullet} \save*{} \ar`r[d]+/r3pc/`[d]+/d2pc/ `[uu]+/l3pc/`[uu][uu] \restore \\ 1 } \end{code} $$\docode$$ % "Hints": The arrow feature was used to make the bending arrows and the frame extension for the frames around each cell. % \answercode \answertext{Here is how: \displaycode} \end{exercise} \DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \subsection*{End \& log} \DOCMODE( \xyendinput % $Log: xymatrix.doc,v $ % Revision 3.4 1997/05/18 01:14:25 krisrose % Essential bugfixes. % % Revision 3.3 1996/12/19 03:31:56 krisrose % Maintenance release % % Revision 3.1 1995/09/05 20:31:32 kris % Releasing! % % Revision 3.0 1995/07/07 20:14:21 kris % Major release w/new User's Guide! % % Revision 2.14 1995/07/06 02:56:02 kris % Buglets... % % Revision 2.13 1995/07/04 15:11:17 kris % Ready to release v3? % % Revision 2.12 1994/10/25 11:34:25 kris % Interim release just before v3 [works with AMS-LaTeX 1.2]... % % Revision 2.11 1994/07/05 10:37:32 kris % Third 3beta release [bug fixes]. % Experimental graph feature included (for ECCT-94 presentation). % % Revision 2.9 1994/06/09 15:02:49 kris % Release 3beta. % % Revision 2.8 1994/04/08 04:30:00 kris % Second (bug fix) 3alpha release. % % Revision 2.7 1994/03/08 02:06:01 kris % Release 3alpha. % % Revision 2.6.9.1 1994/03/07 04:22:46 kris % Last internal 3alpha and pre-2.7 release. % % NEW for version 2.7 extracted from diagram code in xypic.doc 2.6.1.1. \DOCMODE) \DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Tell Emacs how we are formatted: % Local Variables: % mode:latex % fill-prefix:"\t" % fill-column:77 % paragraph-separate:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]" % paragraph-start:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]" % LaTeX-indent-level:1 % TeX-brace-indent-level:1 % End: