summaryrefslogtreecommitdiff
path: root/macros/eplain/tex/arrow.tex
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/eplain/tex/arrow.tex
Initial commit
Diffstat (limited to 'macros/eplain/tex/arrow.tex')
-rw-r--r--macros/eplain/tex/arrow.tex597
1 files changed, 597 insertions, 0 deletions
diff --git a/macros/eplain/tex/arrow.tex b/macros/eplain/tex/arrow.tex
new file mode 100644
index 0000000000..9c43c2fe3c
--- /dev/null
+++ b/macros/eplain/tex/arrow.tex
@@ -0,0 +1,597 @@
+% arrow.tex: macros for commutative diagrams.
+%
+% Copyright (C) 1991,1992 Steven T. Smith.
+% stsmith@ll.mit.edu
+%
+% This program 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, or (at your option)
+% any later version.
+%
+% This program 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 file; see the file COPYING. If not, write to the
+% Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+% Boston, MA 02110-1301, USA.
+%
+% As a special exception, when this file is read by TeX when
+% processing a TeX source document, you may use the result without
+% restriction.
+
+% Version 0 Released for alpha testing, November 16, 1991.
+% Version 0.1 Morphism positions for slanted lines improved, Nov. 17, 1991.
+% Version 0.11 \biline changed to \bisline for compatible naming. 11/21/91
+% Version 0.2 Equate \lft & \rt w. _ and ^ instead of L_{12} & R_{12}. 1/20/92
+% Version 1.0 Distributed with Eplain. 1/20/92
+% Version 1.1 Purged \newcount's, etc.; Warner ref.; \getch@nnel logic. 4/21/92
+% Version 1.11 Replace \smash with \smash@@ (for amstex compatibility) 3/27/96
+
+
+
+% Syntax: \[arrow](X,Y) or
+% \[arrow](X,Y)\lft{MOR} (morphism placed left of arrow) or
+% \[arrow](X,Y)\rt{MOR} (morphism placed right of arrow)
+%
+% [arrow] is one of
+% sline (straight line)
+% dotline (dotted line) * Unimplemented
+% arrow (straight arrow)
+% dotarrow (dotted arrow) * Unimplemented
+%
+% The following allow plain versions and some combination of \lft and \rt.
+% biarrow (two straight arrows)
+% adjarrow (two adjoint arrows)
+% bisline (two straight lines)
+%
+% Also, for left, right, up, and down mappings:
+%
+% \mapright (or \mapright^{f_*}, \mapright_{f_*})
+% \mapleft (ditto)
+% \mapup (use \rt and \lft as above)
+% \mapdown (ditto)
+%
+% And variants of these (can use combinations of ^/_ and lft/rt):
+%
+% \bimapright (two right arrows)
+% \bimapleft (two left arrows)
+% \adjmapright (two adjoint arrows; <- over ->)
+% \adjmapleft (two adjoint arrows; -> over <-)
+% \hline (horizontal line)
+% \dothline (dotted horizontal line) * Unimplemented
+% \bihline (two horizontal lines)
+%
+% \bimapdown (two down arrows)
+% \bimapup (two left arrows)
+% \adjmapdown (two adjoint arrows; down then up)
+% \adjmapup (two adjoint arrows; up then down)
+% \vline (vertical line)
+% \dotvline (dotted vertical line) * Unimplemented
+% \bivline (two vertical lines)
+
+% Use \thinlines temporarily to find the current catcode of @, so we can
+% restore it at the end.
+\edef\thinlines{\the\catcode`@ }%
+\catcode`@ = 11
+\let\@oldatcatcode = \thinlines
+
+
+% I changed \smash to \smash@@ in these macros to avoid AMSTEX conflict.
+
+\def\smash@@{\relax % \relax, in case this comes first in \halign
+ \ifmmode\def\next{\mathpalette\mathsm@sh}\else\let\next\makesm@sh
+ \fi\next}
+\def\makesm@sh#1{\setbox\z@\hbox{#1}\finsm@sh}
+\def\mathsm@sh#1#2{\setbox\z@\hbox{$\m@th#1{#2}$}\finsm@sh}
+\def\finsm@sh{\ht\z@\z@ \dp\z@\z@ \box\z@}
+
+% Adapted LaTeX code for drawing lines and vectors
+
+% Note: to ensure compatibility with LaTeX, all LaTeX control
+% sequences have been renamed. Control sequence names containing the
+% at sign (@) have been changed to contain an ampersand (&) instead.
+\edef\@oldandcatcode{\the\catcode`& }%
+\catcode`& = 11
+
+% LaTeX macros changed here:
+% \line - changed to \drawline
+% \vector - changed to \drawvector
+% \@badlinearg - simply uses \errmessage now
+% \@height, \@width, and \@depth are changed to height, width, and depth
+% \@sline and \@svector - changed so that \hbox{\drawline...} yields
+% a box of positive width and positive height for a positive slope
+% and positive depth for a negative slope.
+% \@hline and \@hvector - likewise
+% \unitlength eliminated; pass dimensions to \drawline and \drawvector.
+
+% LaTeX's while loop
+\def\&whilenoop#1{}%
+\def\&whiledim#1\do #2{\ifdim #1\relax#2\&iwhiledim{#1\relax#2}\fi}%
+\def\&iwhiledim#1{\ifdim #1\let\&nextwhile=\&iwhiledim
+ \else\let\&nextwhile=\&whilenoop\fi\&nextwhile{#1}}%
+
+% LaTeX's \line and \vector macros:
+\newif\if&negarg
+\newdimen\&wholewidth
+\newdimen\&halfwidth
+
+\font\tenln=line10
+
+\def\thinlines{\let\&linefnt\tenln \let\&circlefnt\tencirc
+ \&wholewidth\fontdimen8\tenln \&halfwidth .5\&wholewidth}%
+\def\thicklines{\let\&linefnt\tenlnw \let\&circlefnt\tencircw
+ \&wholewidth\fontdimen8\tenlnw \&halfwidth .5\&wholewidth}%
+
+\def\drawline(#1,#2)#3{\&xarg #1\relax \&yarg #2\relax \&linelen=#3\relax
+ \ifnum\&xarg =0 \&vline \else \ifnum\&yarg =0 \&hline \else \&sline\fi\fi}%
+
+\def\&sline{\leavevmode
+ \ifnum\&xarg< 0 \&negargtrue \&xarg -\&xarg \&yyarg -\&yarg
+ \else \&negargfalse \&yyarg \&yarg \fi
+ \ifnum \&yyarg >0 \&tempcnta\&yyarg \else \&tempcnta -\&yyarg \fi
+ \ifnum\&tempcnta>6 \&badlinearg \&yyarg0 \fi
+ \ifnum\&xarg>6 \&badlinearg \&xarg1 \fi
+ \setbox\&linechar\hbox{\&linefnt\&getlinechar(\&xarg,\&yyarg)}%
+ \ifnum \&yyarg >0 \let\&upordown\raise \&clnht\z@
+ \else\let\&upordown\lower \&clnht \ht\&linechar\fi
+ \&clnwd=\wd\&linechar
+ \&whiledim \&clnwd <\&linelen \do {%
+ \&upordown\&clnht\copy\&linechar
+ \advance\&clnht \ht\&linechar
+ \advance\&clnwd \wd\&linechar
+ }%
+ \advance\&clnht -\ht\&linechar
+ \advance\&clnwd -\wd\&linechar
+ \&tempdima\&linelen\advance\&tempdima -\&clnwd
+ \&tempdimb\&tempdima\advance\&tempdimb -\wd\&linechar
+ \hskip\&tempdimb \multiply\&tempdima \@m
+ \&tempcnta \&tempdima \&tempdima \wd\&linechar \divide\&tempcnta \&tempdima
+ \&tempdima \ht\&linechar \multiply\&tempdima \&tempcnta
+ \divide\&tempdima \@m
+ \advance\&clnht \&tempdima
+ \ifdim \&linelen <\wd\&linechar \hskip \wd\&linechar
+ \else\&upordown\&clnht\copy\&linechar\fi}%
+
+\def\&hline{\vrule height \&halfwidth depth \&halfwidth width \&linelen}%
+
+\def\&getlinechar(#1,#2){\&tempcnta#1\relax\multiply\&tempcnta 8
+ \advance\&tempcnta -9 \ifnum #2>0 \advance\&tempcnta #2\relax\else
+ \advance\&tempcnta -#2\relax\advance\&tempcnta 64 \fi
+ \char\&tempcnta}%
+
+\def\drawvector(#1,#2)#3{\&xarg #1\relax \&yarg #2\relax
+ \&tempcnta \ifnum\&xarg<0 -\&xarg\else\&xarg\fi
+ \ifnum\&tempcnta<5\relax \&linelen=#3\relax
+ \ifnum\&xarg =0 \&vvector \else \ifnum\&yarg =0 \&hvector
+ \else \&svector\fi\fi\else\&badlinearg\fi}%
+
+\def\&hvector{\ifnum\&xarg<0 \rlap{\&linefnt\&getlarrow(1,0)}\fi \&hline
+ \ifnum\&xarg>0 \llap{\&linefnt\&getrarrow(1,0)}\fi}%
+
+\def\&vvector{\ifnum \&yarg <0 \&downvector \else \&upvector \fi}%
+
+\def\&svector{\&sline
+ \&tempcnta\&yarg \ifnum\&tempcnta <0 \&tempcnta=-\&tempcnta\fi
+ \ifnum\&tempcnta <5
+ \if&negarg\ifnum\&yarg>0 % 3d quadrant; dp > 0
+ \llap{\lower\ht\&linechar\hbox to\&linelen{\&linefnt
+ \&getlarrow(\&xarg,\&yyarg)\hss}}\else % 4th quadrant; ht > 0
+ \llap{\hbox to\&linelen{\&linefnt\&getlarrow(\&xarg,\&yyarg)\hss}}\fi
+ \else\ifnum\&yarg>0 % 1st quadrant; ht > 0
+ \&tempdima\&linelen \multiply\&tempdima\&yarg
+ \divide\&tempdima\&xarg \advance\&tempdima-\ht\&linechar
+ \raise\&tempdima\llap{\&linefnt\&getrarrow(\&xarg,\&yyarg)}\else
+ \&tempdima\&linelen \multiply\&tempdima-\&yarg % 2d quadrant; dp > 0
+ \divide\&tempdima\&xarg
+ \lower\&tempdima\llap{\&linefnt\&getrarrow(\&xarg,\&yyarg)}\fi\fi
+ \else\&badlinearg\fi}%
+
+\def\&getlarrow(#1,#2){\ifnum #2 =\z@ \&tempcnta='33\else
+\&tempcnta=#1\relax\multiply\&tempcnta \sixt@@n \advance\&tempcnta
+-9 \&tempcntb=#2\relax\multiply\&tempcntb \tw@
+\ifnum \&tempcntb >0 \advance\&tempcnta \&tempcntb\relax
+\else\advance\&tempcnta -\&tempcntb\advance\&tempcnta 64
+\fi\fi\char\&tempcnta}%
+
+\def\&getrarrow(#1,#2){\&tempcntb=#2\relax
+\ifnum\&tempcntb < 0 \&tempcntb=-\&tempcntb\relax\fi
+\ifcase \&tempcntb\relax \&tempcnta='55 \or
+\ifnum #1<3 \&tempcnta=#1\relax\multiply\&tempcnta
+24 \advance\&tempcnta -6 \else \ifnum #1=3 \&tempcnta=49
+\else\&tempcnta=58 \fi\fi\or
+\ifnum #1<3 \&tempcnta=#1\relax\multiply\&tempcnta
+24 \advance\&tempcnta -3 \else \&tempcnta=51\fi\or
+\&tempcnta=#1\relax\multiply\&tempcnta
+\sixt@@n \advance\&tempcnta -\tw@ \else
+\&tempcnta=#1\relax\multiply\&tempcnta
+\sixt@@n \advance\&tempcnta 7 \fi\ifnum #2<0 \advance\&tempcnta 64 \fi
+\char\&tempcnta}%
+
+\def\&vline{\ifnum \&yarg <0 \&downline \else \&upline\fi}%
+
+\def\&upline{\hbox to \z@{\hskip -\&halfwidth \vrule width \&wholewidth
+ height \&linelen depth \z@\hss}}%
+
+\def\&downline{\hbox to \z@{\hskip -\&halfwidth \vrule width \&wholewidth
+ height \z@ depth \&linelen \hss}}%
+
+\def\&upvector{\&upline\setbox\&tempboxa\hbox{\&linefnt\char'66}\raise
+ \&linelen \hbox to\z@{\lower \ht\&tempboxa\box\&tempboxa\hss}}%
+
+\def\&downvector{\&downline\lower \&linelen
+ \hbox to \z@{\&linefnt\char'77\hss}}%
+
+\def\&badlinearg{\errmessage{Bad \string\arrow\space argument.}}%
+
+%INITIALIZATION
+\thinlines
+
+% Allocate registers using the rules of p.~346 of {\sl The \TeX book}.
+\countdef\&xarg 0
+\countdef\&yarg 2
+\countdef\&yyarg 4
+\countdef\&tempcnta 6
+\countdef\&tempcntb 8
+
+\dimendef\&linelen 0
+\dimendef\&clnwd 2
+\dimendef\&clnht 4
+\dimendef\&tempdima 6
+\dimendef\&tempdimb 8
+
+\chardef\@arrbox 0
+\chardef\&linechar 2
+\chardef\&tempboxa 2 % \&linechar and \&tempboxa don't interfere.
+
+
+% Macros for abstract nonsense
+
+% Macros for slanted lines and arrows.
+
+\let\lft^%
+\let\rt_% distinguish between \rt and \lft
+
+\newif\if@pslope % test for positive slope
+\def\@findslope(#1,#2){\ifnum#1>0
+ \ifnum#2>0 \@pslopetrue \else\@pslopefalse\fi \else
+ \ifnum#2>0 \@pslopefalse \else\@pslopetrue\fi\fi}%
+
+\def\generalsmap(#1,#2){\getm@rphposn(#1,#2)\plnmorph\futurelet\next\addm@rph}%
+
+% Put arrow in \@arrbox, then add morphisms later.
+
+% Single lines and arrows.
+\def\sline(#1,#2){\setbox\@arrbox=\hbox{\drawline(#1,#2){\sarrowlength}}%
+ \@findslope(#1,#2)\d@@blearrfalse\generalsmap(#1,#2)}%
+\def\arrow(#1,#2){\setbox\@arrbox=\hbox{\drawvector(#1,#2){\sarrowlength}}%
+ \@findslope(#1,#2)\d@@blearrfalse\generalsmap(#1,#2)}%
+
+% Double lines, arrows, and adjoint arrows.
+\newif\ifd@@blearr
+
+\def\bisline(#1,#2){\@findslope(#1,#2)%
+ \if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
+ \getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
+ \rlap{\drawline(#1,#2){\sarrowlength}}%
+ \hskip\@hchannel\hbox{\drawline(#1,#2){\sarrowlength}}}%
+ \d@@blearrtrue\generalsmap(#1,#2)}%
+\def\biarrow(#1,#2){\@findslope(#1,#2)%
+ \if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
+ \getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
+ \rlap{\drawvector(#1,#2){\sarrowlength}}%
+ \hskip\@hchannel\hbox{\drawvector(#1,#2){\sarrowlength}}}%
+ \d@@blearrtrue\generalsmap(#1,#2)}%
+\def\adjarrow(#1,#2){\@findslope(#1,#2)%
+ \if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
+ \getch@nnel(#1,#2)\setbox\@arrbox=\hbox{\@upordown\@vchannel
+ \rlap{\drawvector(#1,#2){\sarrowlength}}%
+ \hskip\@hchannel\hbox{\drawvector(-#1,-#2){\sarrowlength}}}%
+ \d@@blearrtrue\generalsmap(#1,#2)}%
+
+% Morphism placement.
+
+% Logic for positioning morphisms on slanted arrows:
+% If \lft then
+% \hskip by -\@hmorphdflt
+% if \@pslopetrue then \raise by \@vmorphdflt
+% else \lower by \@vmorphdflt
+% Else if \rt then
+% \hskip by \@hmorphdflt
+% if \@pslopetrue then \lower by \@vmorphdflt
+% else \raise by \@vmorphdflt
+%
+% \@hmorphdflt and \@vmorphdflt defined by \getm@rphposn
+% Advance \morphdist by .5\channelwidth if double arrows
+%
+% Use \@shiftmorph to allow users to move morphisms
+
+% Logic for \@shiftmorph:
+% If \rtm@rph then
+% if \hmorphposnrt=0 then hshift by\hmorphposn else hshift by\hmorphposnrt
+% if \vmorphposnrt=0 then vshift by\vmorphposn else vshift by\vmorphposnrt
+% Else
+% if \hmorphposnlft=0 then hshift by\hmorphposn else hshift by\hmorphposnlft
+% if \vmorphposnlft=0 then vshift by\vmorphposn else vshift by\vmorphposnlft
+
+\newif\ifrtm@rph
+\def\@shiftmorph#1{\hbox{\setbox0=\hbox{$\scriptstyle#1$}%
+ \setbox1=\hbox{\hskip\@hm@rphshift\raise\@vm@rphshift\copy0}%
+ \wd1=\wd0 \ht1=\ht0 \dp1=\dp0 \box1}}%
+\def\@hm@rphshift{\ifrtm@rph
+ \ifdim\hmorphposnrt=\z@\hmorphposn\else\hmorphposnrt\fi \else
+ \ifdim\hmorphposnlft=\z@\hmorphposn\else\hmorphposnlft\fi \fi}%
+\def\@vm@rphshift{\ifrtm@rph
+ \ifdim\vmorphposnrt=\z@\vmorphposn\else\vmorphposnrt\fi \else
+ \ifdim\vmorphposnlft=\z@\vmorphposn\else\vmorphposnlft\fi \fi}%
+
+\def\addm@rph{\ifx\next\lft\let\temp=\lftmorph\else
+ \ifx\next\rt\let\temp=\rtmorph\else\let\temp\relax\fi\fi \temp}%
+
+\def\plnmorph{\dimen1\wd\@arrbox \ifdim\dimen1<\z@ \dimen1-\dimen1\fi
+ \vcenter{\box\@arrbox}}%
+\def\lftmorph\lft#1{\rtm@rphfalse \setbox0=\@shiftmorph{#1}%
+ \if@pslope \let\@upordown\raise \else \let\@upordown\lower\fi
+ \llap{\@upordown\@vmorphdflt\hbox to\dimen1{\hss % \dimen1=\wd\@arrbox
+ \llap{\box0}\hss}\hskip\@hmorphdflt}\futurelet\next\addm@rph}%
+\def\rtmorph\rt#1{\rtm@rphtrue \setbox0=\@shiftmorph{#1}%
+ \if@pslope \let\@upordown\lower \else \let\@upordown\raise\fi
+ \llap{\@upordown\@vmorphdflt\hbox to\dimen1{\hss
+ \rlap{\box0}\hss}\hskip-\@hmorphdflt}\futurelet\next\addm@rph}%
+
+% Get appropriate shifts for morphisms and double lines at various slopes
+% Syntax e.g.: \@getshift(1,2){\@hchannel}{\@vchannel}{\channelwidth}%
+
+\def\getm@rphposn(#1,#2){\ifd@@blearr \dimen@\morphdist \advance\dimen@ by
+ .5\channelwidth \@getshift(#1,#2){\@hmorphdflt}{\@vmorphdflt}{\dimen@}\else
+ \@getshift(#1,#2){\@hmorphdflt}{\@vmorphdflt}{\morphdist}\fi}%
+
+\def\getch@nnel(#1,#2){\ifdim\hchannel=\z@ \ifdim\vchannel=\z@
+ \@getshift(#1,#2){\@hchannel}{\@vchannel}{\channelwidth}%
+ \else \@hchannel\hchannel \@vchannel\vchannel \fi
+ \else \@hchannel\hchannel \@vchannel\vchannel \fi}%
+
+\def\@getshift(#1,#2)#3#4#5{\dimen@ #5\relax
+ \&xarg #1\relax \&yarg #2\relax
+ \ifnum\&xarg<0 \&xarg -\&xarg \fi
+ \ifnum\&yarg<0 \&yarg -\&yarg \fi
+ \ifnum\&xarg<\&yarg \&negargtrue \&yyarg\&xarg \&xarg\&yarg \&yarg\&yyarg\fi
+ \ifcase\&xarg \or % There is no case 0
+ \ifcase\&yarg % case 1
+ \dimen@i \z@ \dimen@ii \dimen@ \or % case (1,0)
+ \dimen@i .7071\dimen@ \dimen@ii .7071\dimen@ \fi \or
+ \ifcase\&yarg % case 2
+ \or % case 0,2 wrong
+ \dimen@i .4472\dimen@ \dimen@ii .8944\dimen@ \fi \or
+ \ifcase\&yarg % case 3
+ \or % case 0,3 wrong
+ \dimen@i .3162\dimen@ \dimen@ii .9486\dimen@ \or
+ \dimen@i .5547\dimen@ \dimen@ii .8321\dimen@ \fi \or
+ \ifcase\&yarg % case 4
+ \or % case 0,2,4 wrong
+ \dimen@i .2425\dimen@ \dimen@ii .9701\dimen@ \or\or
+ \dimen@i .6\dimen@ \dimen@ii .8\dimen@ \fi \or
+ \ifcase\&yarg % case 5
+ \or % case 0,5 wrong
+ \dimen@i .1961\dimen@ \dimen@ii .9801\dimen@ \or
+ \dimen@i .3714\dimen@ \dimen@ii .9284\dimen@ \or
+ \dimen@i .5144\dimen@ \dimen@ii .8575\dimen@ \or
+ \dimen@i .6247\dimen@ \dimen@ii .7801\dimen@ \fi \or
+ \ifcase\&yarg % case 6
+ \or % case 0,2,3,4,6 wrong
+ \dimen@i .1645\dimen@ \dimen@ii .9864\dimen@ \or\or\or\or
+ \dimen@i .6402\dimen@ \dimen@ii .7682\dimen@ \fi \fi
+ \if&negarg \&tempdima\dimen@i \dimen@i\dimen@ii \dimen@ii\&tempdima\fi
+ #3\dimen@i\relax #4\dimen@ii\relax }%
+
+\catcode`\&=4 % Back to alignment tab
+
+
+% Macros for horizontal and vertical lines and arrows.
+% These macros use an idea from Appendix~D, p.~374 of the Texbook.
+% Usage: `\mapright^f', `\mapleft', etc.
+% `\mapdown\lft{f}', `\mapup\rt{g}', `\mapdown', etc.
+
+% \toks@ will contain the token sequence that defines the arrow and morphisms;
+% ensure that \toks@={\mathop{\vcenter{\smash@@{horiz. arrow}}}\limits} to start.
+\def\generalhmap{\futurelet\next\@generalhmap}%
+\def\@generalhmap{\ifx\next^ \let\temp\generalhm@rph\else
+ \ifx\next_ \let\temp\generalhm@rph\else \let\temp\m@kehmap\fi\fi \temp}%
+\def\generalhm@rph#1#2{\ifx#1^
+ \toks@=\expandafter{\the\toks@#1{\rtm@rphtrue\@shiftmorph{#2}}}\else
+ \toks@=\expandafter{\the\toks@#1{\rtm@rphfalse\@shiftmorph{#2}}}\fi
+ \generalhmap}%
+\def\m@kehmap{\mathrel{\smash@@{\the\toks@}}}%
+
+\def\mapright{\toks@={\mathop{\vcenter{\smash@@{\drawrightarrow}}}\limits}%
+ \generalhmap}%
+\def\mapleft{\toks@={\mathop{\vcenter{\smash@@{\drawleftarrow}}}\limits}%
+ \generalhmap}%
+\def\bimapright{\toks@={\mathop{\vcenter{\smash@@{\drawbirightarrow}}}\limits}%
+ \generalhmap}%
+\def\bimapleft{\toks@={\mathop{\vcenter{\smash@@{\drawbileftarrow}}}\limits}%
+ \generalhmap}%
+\def\adjmapright{\toks@={\mathop{\vcenter{\smash@@{\drawadjrightarrow}}}\limits}%
+ \generalhmap}%
+\def\adjmapleft{\toks@={\mathop{\vcenter{\smash@@{\drawadjleftarrow}}}\limits}%
+ \generalhmap}%
+\def\hline{\toks@={\mathop{\vcenter{\smash@@{\drawhline}}}\limits}%
+ \generalhmap}%
+\def\bihline{\toks@={\mathop{\vcenter{\smash@@{\drawbihline}}}\limits}%
+ \generalhmap}%
+
+\def\drawrightarrow{\hbox{\drawvector(1,0){\harrowlength}}}%
+\def\drawleftarrow{\hbox{\drawvector(-1,0){\harrowlength}}}%
+\def\drawbirightarrow{\hbox{\raise.5\channelwidth
+ \hbox{\drawvector(1,0){\harrowlength}}\lower.5\channelwidth
+ \llap{\drawvector(1,0){\harrowlength}}}}%
+\def\drawbileftarrow{\hbox{\raise.5\channelwidth
+ \hbox{\drawvector(-1,0){\harrowlength}}\lower.5\channelwidth
+ \llap{\drawvector(-1,0){\harrowlength}}}}%
+\def\drawadjrightarrow{\hbox{\raise.5\channelwidth
+ \hbox{\drawvector(-1,0){\harrowlength}}\lower.5\channelwidth
+ \llap{\drawvector(1,0){\harrowlength}}}}%
+\def\drawadjleftarrow{\hbox{\raise.5\channelwidth
+ \hbox{\drawvector(1,0){\harrowlength}}\lower.5\channelwidth
+ \llap{\drawvector(-1,0){\harrowlength}}}}%
+\def\drawhline{\hbox{\drawline(1,0){\harrowlength}}}%
+\def\drawbihline{\hbox{\raise.5\channelwidth
+ \hbox{\drawline(1,0){\harrowlength}}\lower.5\channelwidth
+ \llap{\drawline(1,0){\harrowlength}}}}%
+
+% Vertical arrows are handled differently because there is no \mathop.
+% \toks@ will contain the token sequence that defines the arrow and morphisms;
+% ensure that \toks@={\vcenter{vertical arrow}} to start.
+\def\generalvmap{\futurelet\next\@generalvmap}%
+\def\@generalvmap{\ifx\next\lft \let\temp\generalvm@rph\else
+ \ifx\next\rt \let\temp\generalvm@rph\else \let\temp\m@kevmap\fi\fi \temp}%
+% Prepend or append to \toks@ depending on \rt or \lft.
+\toksdef\toks@@=1
+\def\generalvm@rph#1#2{\ifx#1\rt % append
+ \toks@=\expandafter{\the\toks@
+ \rlap{$\vcenter{\rtm@rphtrue\@shiftmorph{#2}}$}}\else % prepend
+ \toks@@={\llap{$\vcenter{\rtm@rphfalse\@shiftmorph{#2}}$}}%
+ \toks@=\expandafter\expandafter\expandafter{\expandafter\the\expandafter
+ \toks@@ \the\toks@}\fi \generalvmap}%
+\def\m@kevmap{\the\toks@}%
+
+\def\mapdown{\toks@={\vcenter{\drawdownarrow}}\generalvmap}%
+\def\mapup{\toks@={\vcenter{\drawuparrow}}\generalvmap}%
+\def\bimapdown{\toks@={\vcenter{\drawbidownarrow}}\generalvmap}%
+\def\bimapup{\toks@={\vcenter{\drawbiuparrow}}\generalvmap}%
+\def\adjmapdown{\toks@={\vcenter{\drawadjdownarrow}}\generalvmap}%
+\def\adjmapup{\toks@={\vcenter{\drawadjuparrow}}\generalvmap}%
+\def\vline{\toks@={\vcenter{\drawvline}}\generalvmap}%
+\def\bivline{\toks@={\vcenter{\drawbivline}}\generalvmap}%
+
+\def\drawdownarrow{\hbox to5pt{\hss\drawvector(0,-1){\varrowlength}\hss}}%
+\def\drawuparrow{\hbox to5pt{\hss\drawvector(0,1){\varrowlength}\hss}}%
+\def\drawbidownarrow{\hbox to5pt{\hss\hbox{\drawvector(0,-1){\varrowlength}}%
+ \hskip\channelwidth\hbox{\drawvector(0,-1){\varrowlength}}\hss}}%
+\def\drawbiuparrow{\hbox to5pt{\hss\hbox{\drawvector(0,1){\varrowlength}}%
+ \hskip\channelwidth\hbox{\drawvector(0,1){\varrowlength}}\hss}}%
+\def\drawadjdownarrow{\hbox to5pt{\hss\hbox{\drawvector(0,-1){\varrowlength}}%
+ \hskip\channelwidth\lower\varrowlength
+ \hbox{\drawvector(0,1){\varrowlength}}\hss}}%
+\def\drawadjuparrow{\hbox to5pt{\hss\hbox{\drawvector(0,1){\varrowlength}}%
+ \hskip\channelwidth\raise\varrowlength
+ \hbox{\drawvector(0,-1){\varrowlength}}\hss}}%
+\def\drawvline{\hbox to5pt{\hss\drawline(0,1){\varrowlength}\hss}}%
+\def\drawbivline{\hbox to5pt{\hss\hbox{\drawline(0,1){\varrowlength}}%
+ \hskip\channelwidth\hbox{\drawline(0,1){\varrowlength}}\hss}}%
+
+
+% Macros for setting commutative diagrams.
+
+% A macro inspired by Ex.~18.46 of the TeXbook.
+\def\commdiag#1{\null\,
+ \vcenter{\commdiagbaselines
+ \m@th\ialign{\hfil$##$\hfil&&\hfil$\mkern4mu ##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}%
+
+\def\commdiagbaselines{\baselineskip15pt \lineskip3pt \lineskiplimit3pt }%
+% A macro inspired by Francis Borceux's Diagram macros for LaTeX
+% (FBORCEUX@BUCLLN11.BITNET).
+\def\gridcommdiag#1{\null\,
+ \vcenter{\offinterlineskip
+ \m@th\ialign{&\vbox to\vgrid{\vss
+ \hbox to\hgrid{\hss\smash@@{$##$}\hss}}\crcr
+ \mathstrut\crcr\noalign{\kern-\vgrid}
+ #1\crcr\mathstrut\crcr\noalign{\kern-.5\vgrid}}}\,}%
+
+% Default parameters
+% Define default heights and widths for arrows using the golden ratio.
+% Note that 5:3 (for sline) and 3:2 (for vector) approximate this ratio.
+\newdimen\harrowlength \harrowlength=60pt
+\newdimen\varrowlength \varrowlength=.618\harrowlength
+\newdimen\sarrowlength \sarrowlength=\harrowlength
+
+% Morphism placement
+\newdimen\hmorphposn \hmorphposn=\z@
+\newdimen\vmorphposn \vmorphposn=\z@
+\newdimen\morphdist \morphdist=4pt
+
+\dimendef\@hmorphdflt 0 % These two dimensions are
+\dimendef\@vmorphdflt 2 % defined by \getm@rphposn
+
+\newdimen\hmorphposnrt \hmorphposnrt=\z@
+\newdimen\hmorphposnlft \hmorphposnlft=\z@
+\newdimen\vmorphposnrt \vmorphposnrt=\z@
+\newdimen\vmorphposnlft \vmorphposnlft=\z@
+\let\hmorphposnup=\hmorphposnrt
+\let\hmorphposndn=\hmorphposnlft
+\let\vmorphposnup=\vmorphposnrt
+\let\vmorphposndn=\vmorphposnlft
+
+% Default grid size for \gridcommdiag
+\newdimen\hgrid \hgrid=15pt
+\newdimen\vgrid \vgrid=15pt
+
+% Horizontal and vertical distance between double lines and arrows.
+\newdimen\hchannel \hchannel=0pt
+\newdimen\vchannel \vchannel=0pt
+\newdimen\channelwidth \channelwidth=3pt
+
+\dimendef\@hchannel 0 % Defined via the
+\dimendef\@vchannel 2 % macro \getch@nnel
+
+\catcode`& = \@oldandcatcode
+\catcode`@ = \@oldatcatcode
+
+
+% Some examples
+
+%\parskip=20pt
+%
+%The first example:
+%$$\commdiag{A&\mapright^f&B&\mapleft^g&C\cr
+%\mapdown\lft\psi&\arrow(3,-2)\rt s&\mapup\rt\phi&
+%\arrow(-3,2)\lft l&\mapdown\rt\theta\cr
+%D&\mapright_h&E&\mapleft_{\int_0^t{\bf A}\,d\sigma}&F\cr}$$
+%
+%
+%Covering homotopy property (Bott and Tu, {\it Differential Forms in
+%Algebraic Topology}):
+%$$\commdiag{Y&\mapright^f&E\cr \mapdown&\arrow(3,2)\lft{f_t}&\mapdown\cr
+%Y\times I&\mapright^{\bar f_t}&X}$$
+%
+%
+%Universal mapping property (Warner, {\it Foundations of Differentiable
+%Manifolds and Lie Groups}): $$\varrowlength=20pt
+%\commdiag{V\otimes W\cr \mapup\lft\phi&\arrow(3,-1)\rt{\tilde l}\cr
+%V\times W&\mapright^l&U\cr}$$
+%
+%
+%A cube (Francis Borceux):
+%$$\harrowlength=48pt \varrowlength=48pt \sarrowlength=20pt
+%\def\cross#1#2{\setbox0=\hbox{$#1$}%
+% \hbox to\wd0{\hss\hbox{$#2$}\hss}\llap{\unhbox0}}
+%\gridcommdiag{&&B&&\mapright^b&&D\cr
+%&\arrow(1,1)\lft a&&&&\arrow(1,1)\lft d\cr
+%A&&\cross{\hmorphposn=12pt\mapright^c}{\vmorphposn=-12pt\mapdown\lft f}
+%&&C&&\mapdown\rt h\cr\cr
+%\mapdown\lft e&&F&&\cross{\hmorphposn=-12pt\mapright_j}
+%{\vmorphposn=12pt\mapdown\rt g}&&H\cr
+%&\arrow(1,1)\lft i&&&&\arrow(1,1)\rt l\cr
+%E&&\mapright_k&&G\cr}$$
+%
+%Zassenhaus's Butterfly Lemma (Lang, {\it Algebra}):
+%$$\hgrid=16pt \vgrid=8pt \sarrowlength=32pt
+%\def\cross#1#2{\setbox0=\hbox{$#1$}%
+% \hbox to\wd0{\hss\hbox{$#2$}\hss}\llap{\unhbox0}}
+%\def\l#1{\llap{$#1$\hskip.5em}}
+%\def\r#1{\rlap{\hskip.5em$#1$}}
+%\gridcommdiag{&&U&&&&V\cr &&\bullet&&&&\bullet\cr
+%&&\sarrowlength=16pt\sline(0,1)&&&&\sarrowlength=16pt\sline(0,1)\cr
+%&&\l{u(U\cap V)}\bullet&&&&\bullet\r{(U\cap V)v}\cr
+%&&&\sline(2,-1)&&\sline(2,1)\cr
+%&&\cross{=}{\sline(0,1)}&&\bullet&&\cross{=}{\sline(0,1)}\cr\cr
+%&&\l{^{\textstyle u(U\cap v)}}\bullet&&\cross{=}{\sline(0,1)}&&
+% \bullet\r{^{\textstyle(u\cap V)v}}\cr
+%&\sline(2,1)&&\sline(2,-1)&&\sline(2,1)&&\sline(2,-1)\cr
+%\l{u}\bullet&&&&\bullet&&&&\bullet\r{v}\cr
+%&\sline(2,-1)&&\sline(2,1)&&\sline(2,-1)&&\sline(2,1)\cr
+%&&\bullet&&&&\bullet\cr &&u\cap V&&&&U\cap v\cr}$$