%% This is file 'diagmac2.sty' %% %% Copyright (C) 1997 J. C. Reynolds, john.reynolds@cs.cmu.edu %% 2004-09 R. D. Tennent, rdt@cs.queensu.ca %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2003/12/01 or later. %% %% This work has the LPPL maintenance status "author-maintained". %MACROS FOR DIAGRAMS - J. C. Reynolds - December 1987 % Modified to use pict2e.sty by Bob Tennent % Changes indicated thusly: %%%pict2e % Changelog: % % Version 2.1 May 2009 % % Two extensions added: \drawedgebar and \ctec % User Manual TeXified and expanded % % Version 2.0 February 2004 % % Modified to use pict2e.sty % Changes indicated thusly: %%%pict2e \ProvidesPackage{diagmac2}[2009/05/09 v2.1 LaTeX style for (category-theory) diagrams] \AtBeginDocument{\RequirePackage{pict2e}} %%%pict2e \def\slopemax{1000} %%%pict2e slope factor maximum %This file contains general-purpose macros for drawing diagrams in LATEX, %followed by additional macros especially for category-theory diagrams. %A user's manual is given in the file diagmac2.tex, and a test program is %%%pict2e %given in the file diagmactest.tex. %GENERAL-PURPOSE MACROS %The following control symbols may need to be redefined by the user. \def\diagramunit{1pt}%Redefine only in main program or at the beginning % of \diagram or \ctdiagram. \def\centerheight{3pt} \def\edgeheaddisp{4pt} \def\circleheaddisp{2pt} \def\diameterlist{1pt,2pt,3pt,4pt,5pt,6pt,7pt,8pt,9pt,10pt,11pt,% 12pt,13pt,14pt,15pt,16pt,20pt,24pt,28pt,32pt,36pt,40pt,} %%%pict2e: not used %Redefine if circle fonts are different. %The following registers store the representation of diagram and/or %expression programs: \newdimen\texpr\newdimen\bexpr\newdimen\lexpr\newdimen\rexpr%current rectangle \newdimen\xcenter\newdimen\ycenter%center point \newcount\xslope\newcount\yslope%slope of current edge \newdimen\xstart\newdimen\ystart%start point of current edge \newdimen\xend\newdimen\yend%end point of current edge \newdimen\dcircle%diameter of current circle \newdimen\xcircle\newdimen\ycircle%center of current circle \newcount\zzisedge%1 if current edge is defined, 0 otherwise \newcount\zziscircle%1 if current circle is defined, 0 otherwise \newbox\zzdiagbox%printable material in state \newdimen\zztotlwidth\newdimen\zztotrwidth%horizontal extent of box material \newdimen\zztotheight\newdimen\zztotdepth%vertical extent of box material %The following registers are assigned globally to communicate information %across group boundaries: \newdimen\zzglobaltotlwidth\newdimen\zzglobaltotrwidth \newdimen\zzglobaltotheight\newdimen\zzglobaltotdepth \newdimen\zzglobalxcenter\newdimen\zzglobalycenter \newcount\zzglobalcnA %The following registers are used locally for various purposes: \newdimen\zzdmA\newdimen\zzdmB\newdimen\zzdmC\newdimen\zzdmD\newdimen\zzdmE \newdimen\zzdmF\newdimen\zzdmG\newdimen\zzdmH\newdimen\zzdmI \newcount\zzcnA\newcount\zzcnB\newcount\zzcnC \newcount\zzcnD\newcount\zzcnE\newcount\zzcnF \newcount\zzcnG\newcount\zzcnH\newcount\zzcnI %Hidden macros and other defined control symbols: % generally used macros: \zzsetupbox\zznoshadow\zzissue\zzrecordwidth % \zzrecordheight\zzmultdiagramunit\zzmakepicture\zzsqroot\zzdistance % \zzreduceterms % error-checking macros: \zzisnegside\zzcheckedge\zzcheckslope\zzcheckslopea % \zzcheckcircle\zzcheckbool\zzcheckposdimen\zzchecknonnegnum % used by \vertex: \zzconsvertexlist\zzconsvertexlista\zzconsvertexlistb % used by \rect: \zzprocrect % used by \hexagon: \zzprochexagon % used by \octagon and \rorect: \zzprococtagon % used by \diamond: \zzprocdiamond % used by \rorect: \zzprocrorecta\zzsearchdiameterlist\zzsearchdiameterlista % \zzsearchdiameterlistb % used by \outline: \zzoutlinepoly\zzoutlinepolya\zzoutlinepolyb % \zzoutlinepolyc % used by \outline with \rorect: \zzoutlinerorect % used by \setedge: \zzsearchvertexlist\zzsearchvertexlista % \zzsearchvertexlistb % used by \shadeedge: \zzcastpoly\zzcastpolya\zzcastpolyb % \zzcastpolyc\zzcastpolye\zzcastpolyf\zzcastpolyg % used by \drawdashedge, \drawdotedge, and \drawsolidedge: \zzdrawedge % used by \drawedgehead: \zzdrawedgeheada % used by all abutment macros: \zzslidehoriz\zzslidevert\zzclosestpoly % \zzclosestpolya\zzclosestpolyb\zzclosestpolyc\zzclosestpolyd % used by edge abutment macros: \zzabut % used by circle abutment macros: \zzabutcircle\zzabutcirclea\zzrotate % used by \shadeedge and all abutment macros: \zzcastpolyd % used by \drawcircle: \zzdrawcirclea % multiply defined control symbols: \zzvertexlist\zzshadow\zzglobalshadow % \zztesta\zztestb\zzvertexitem\zzprocpoly\zzprocrorect\zznext % \zzstartshadow\zzendshadow\zzlocalshadow %\diagram creates a box, initializes \zztotlwidth, \zztotrwidth, and %\zzvertexlist, sets \zzisedge to 0, executes #1, which must be a diagram %program, and then issues the resulting box, surrounded by kerns so that %there are no horizontal overhangs. \def\diagram#1{{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt \zztotlwidth=0pt\zztotrwidth=0pt\def\zzvertexlist{\end}\zzisedge=0\relax #1\relax\kern\zztotrwidth\global\zzglobaltotlwidth=\zztotlwidth $} \kern-\zzglobaltotlwidth\box\zzdiagbox}} %\zzsetupbox sets \zzdiagbox to the expression #1 modified by the program #2. %It also sets \zzglobalxcenter and \zzglobalycenter to the coordinates of %the center relative to the reference point, \zzglobaltotlwidth to the %negative of the left overhang width of the expression, and \zzglobalshadow %to the shadow established by the program, relative to the reference point. %Before executing #2, it initializes \texpr, \bexpr, \lexpr, \rexpr, %\xcenter, and \ycenter appropriately, and sets \zziscircle to 0. \def\zzsetupbox#1#2{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt \setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$} \texpr=\ht\zzdiagbox\bexpr=-\dp\zzdiagbox\rexpr=\wd\zzdiagbox\lexpr=0pt \xcenter=\rexpr\divide\xcenter by 2\ycenter=\centerheight \zztotlwidth=0pt\zztotrwidth=\rexpr\def\zzshadow{\zznoshadow0pt,0pt:;} \zziscircle=0 \box\zzdiagbox\kern-\rexpr #2\relax \global\zzglobalxcenter=\xcenter\global\zzglobalycenter=\ycenter \global\zzglobaltotlwidth=\zztotlwidth\kern\zztotrwidth \global\let\zzglobalshadow=\zzshadow $}} %\zznoshadow is a dummy shadowing routine that gives an error when executed. \def\zznoshadow#1,#2:;{\errmessage{ATTEMPT TO OUTLINE OR ABUT AN EXPRESSION WITH NO SHADOW}} %\leftghost (\rightghost) sets \xcenter to \lexpr plus (\rexpr minus) %half of the width of its argument. \def\leftghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$} \xcenter=\wd\zzdiagbox\divide\xcenter by 2\advance\xcenter by \lexpr} \def\rightghost#1{\setbox\zzdiagbox=\hbox{$\mathsurround=0pt{{#1}}$} \xcenter=\wd\zzdiagbox\divide\xcenter by -2\advance\xcenter by \rexpr} %\zzissue should be executed after \zzsetupbox. It issues the contents of %\zzdiagbox with its center placed at \zzdmA, \zzdmB (which are modified), %and adjusts \zztotlwidth and \zztotrwidth appropriately. \def\zzissue{\advance\zzdmA by -\zzglobalxcenter \advance\zzdmB by -\zzglobalycenter \zzdmC=\zzdmA\advance\zzdmC by \wd\zzdiagbox \zzdmD=\zzdmA\advance\zzdmD by \zzglobaltotlwidth \zzrecordwidth\zzdmD\zzdmC \kern\zzdmA\raise\zzdmB\box\zzdiagbox\kern-\zzdmC} %\zzrecordwidth adjusts \zztotlwidth to be the minimum of its previous value %and #1, and adjusts \zztotrwidth to be the maximum of its previous value %and #2. \def\zzrecordwidth#1#2{\relax\ifdim#1<\zztotlwidth\relax\zztotlwidth=#1\fi \ifdim\zztotrwidth<#2\relax\zztotrwidth=#2\fi} %\zzrecordheight adjusts \zztotheight to be the maximum of its previous value %and #1, and adjusts \zztotdepth to be the minimum of its previous value %and #2. \def\zzrecordheight#1#2{\relax\ifdim\zztotheight<#1\relax\zztotheight=#1\fi \ifdim#2<\zztotdepth\relax\zztotdepth=#2\fi} %\placed executes \zzsetupbox{#3}{#4} and issues the contents of the resulting %\zzdiagbox with its center placed at #1, #2 (which must be dimensions). %\place is similar except that #1, #2 must be integer multiples of %\diagramunit. \def\placed#1#2#3#4{\zzsetupbox{#3}{#4}\zzdmA=#1\zzdmB=#2\zzissue} \def\place#1,#2:#3#4{\zzsetupbox{#3}{#4}\zzmultdiagramunit\zzdmA{#1} \zzmultdiagramunit\zzdmB{#2}\zzissue} %\zzmultdiagramunit sets #1 to #2 times \diagramunit. \def\zzmultdiagramunit#1#2{#1=\diagramunit\multiply#1 by #2\relax} %\vertex#1,#2:#3#4 executes \zzsetupbox{#3}{#4}, issues the contents of the %resulting \zzdiagbox with its center placed at #1, #2 times \diagramunit, %adjusts \zztotlwidth and \zztotrwidth appropriately, and adds \zzglobalshadow %to the beginning of \zzvertexlist (unless \zzglobalshadow is a call of %\zznoshadow) after readjusting the shadow to be relative %to the coordinates of the enclosing box. \def\vertex#1,#2:#3#4{\place{#1},{#2}:{#3}{#4}\zzcnA=#1\zzcnB=#2\relax \expandafter\zzconsvertexlist\zzglobalshadow} \def\zzconsvertexlist#1#2,#3:#4;{\def\zztesta{#1}\def\zztestb{\zznoshadow} \ifx\zztesta\zztestb\else \advance\zzdmA by #2\advance\zzdmB by #3\relax \edef\zzvertexitem{\the\zzcnA,\the\zzcnB:\noexpand #1\the\zzdmA,\the\zzdmB:#4;} \expandafter\zzconsvertexlista\zzvertexlist\fi} \def\zzconsvertexlista{\expandafter\zzconsvertexlistb\zzvertexitem} \def\zzconsvertexlistb#1\end{\def\zzvertexlist{#1\end}} %\rect, \hexagon, \octagon, and \diamond (and, roughly speaking, \rorect) %are polygon descriptors. A polygon descriptor defines \zzshadow to have % the form \somecontrolsymbol #1,#2:#3; such that executing %\zzshadow causes a call \zzprocpoly{#1}{#2}{}, where %depends only upon the parameter #3. Here #1, #2 are the %coordinates of a vertex of a convex polygon, and is a list of %triples describing the edges of the polygon in clockwise order. If an %edge is x = xs.t + x0, y = ys.t + y0 for 0 < t < tend (with the start at %t = 0 and the end at t = tend when the edge is traversed in clockwise %order) the the trip describing the edge is {xs}{ys}{tend}, where xs and %ys are numbers (the brackets may be omitted for single-digit numbers) %and tend is a dimension. xs and ys must have a least common divisor of one. \def\rect{\zzdmC=\rexpr\advance\zzdmC by -\lexpr \zzdmD=\texpr\advance\zzdmD by -\bexpr \zzisnegside{\zzdmC}{RECT}\zzisnegside{\zzdmD}{RECT} \edef\zzshadow{\noexpand\zzprocrect \the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}} \def\zzprocrect#1,#2:#3,#4;{\zzprocpoly {#1}{#2}{10{#3}0{-1}{#4}{-1}0{#3}01{#4}}} \def\zzisnegside#1#2{\relax\ifdim#1<0pt\errmessage {#2 WITH NEGATIVE SIDE}\fi} \def\hexagon{\zzdmC=\rexpr\advance\zzdmC by -\lexpr \zzdmD=\texpr\advance\zzdmD by -\bexpr\divide\zzdmD by 4 \zzisnegside{\zzdmC}{HEXAGON}\zzisnegside{\zzdmD}{HEXAGON} \edef\zzshadow{\noexpand\zzprochexagon \the\lexpr,\the\texpr:\the\zzdmC,\the\zzdmD;}} \def\zzprochexagon#1,#2:#3,#4;{\zzprocpoly{#1}{#2} {10{#3}1{-2}{#4}{-1}{-2}{#4}{-1}0{#3}{-1}2{#4}12{#4}}} \def\octagon#1{\zzdmC=#1\zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD \advance\zzdmD by \rexpr\advance\zzdmD by -\lexpr \advance\zzdmE by \texpr\advance\zzdmE by -\bexpr \zzdmF=\lexpr\advance\zzdmF by \zzdmC \zzisnegside{\zzdmC}{OCTAGON}\zzisnegside{\zzdmD}{OCTAGON} \zzisnegside{\zzdmE}{OCTAGON} \edef\zzshadow{\noexpand\zzprococtagon \the\zzdmF,\the\texpr:\the\zzdmC,\the\zzdmD,\the\zzdmE;}} \def\zzprococtagon#1,#2:#3,#4,#5;{\zzprocpoly{#1}{#2} {10{#4}1{-1}{#3}0{-1}{#5}{-1}{-1}{#3}{-1}0{#4}{-1}1{#3}01{#5}11{#3}}} \def\diamond{\zzdmC=\texpr\advance\zzdmC by -\bexpr \advance\zzdmC by \rexpr\advance\zzdmC by -\lexpr\divide\zzdmC by 2 \zzdmD=\lexpr\advance\zzdmD by \rexpr\divide\zzdmD by 2 \zzdmE=\texpr\advance\zzdmE by \bexpr\divide\zzdmE by 2\advance\zzdmE by \zzdmC \zzisnegside{\zzdmC}{DIAMOND} \edef\zzshadow{\noexpand\zzprocdiamond \the\zzdmD,\the\zzdmE:\the\zzdmC;}} \def\zzprocdiamond#1,#2:#3;{\zzprocpoly{#1}{#2} {1{-1}{#3}{-1}{-1}{#3}{-1}1{#3}11{#3}}} \def\rorect#1#2#3{\zzcheckposdimen{#1}{FIRST}{RORECT} \zzcheckbool{#2}{SECOND}{RORECT}\zzcheckbool{#3}{THIRD}{RORECT} \zzdmD=\rexpr\advance\zzdmD by -\lexpr\zzdmE=\texpr\advance\zzdmE by -\bexpr \zzdmC=#1\relax \ifnum#2=1\relax\ifdim\zzdmD>\zzdmC\relax\zzdmC=\zzdmD\fi\fi \ifnum#3=1\relax\ifdim\zzdmE>\zzdmC\relax\zzdmC=\zzdmE\fi\fi %\expandafter\zzsearchdiameterlist\diameterlist\end\zzdmC=\zzdmF\relax %%%pict2e \ifdim\zzdmC>\zzdmD\relax\zzdmD=\zzdmC\fi \ifdim\zzdmC>\zzdmE\relax\zzdmE=\zzdmC\fi \zzdmF=\lexpr\advance\zzdmF by \rexpr\divide\zzdmF by 2 \zzdmG=\bexpr\advance\zzdmG by \texpr\divide\zzdmG by 2 \edef\zzshadow{\noexpand\zzprocrorect \the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;}} \def\zzsearchdiameterlist#1{\def\zztesta{#1}\def\zztestb{\end} \ifx\zztesta\zztestb\let\zznext=\zzsearchdiameterlista \else\let\zznext=\zzsearchdiameterlistb\fi\zznext #1} \def\zzsearchdiameterlista#1\end{} \def\zzsearchdiameterlistb#1,{\zzdmF=#1\relax \ifdim\zzdmF<\zzdmC\relax\let\zznext=\zzsearchdiameterlist \else\let\zznext=\zzsearchdiameterlista\fi\zznext} %\outline uses \zzoutlinepoly and \zzoutlinerorect to issue an outline of %the shadow. \def\outline{\def\zzprocpoly{\zzoutlinepoly} \def\zzprocrorect{\zzoutlinerorect}\zzshadow} %\zzmakepicture encapsulates all usage of the LATEX picture facility. \def\zzmakepicture#1{{\setlength{\unitlength}{1sp}\begin{picture}(0,0) #1\relax \global\zzglobaltotlwidth=\zztotlwidth\global\zzglobaltotrwidth=\zztotrwidth \global\zzglobaltotheight=\zztotheight\global\zzglobaltotdepth=\zztotdepth \end{picture}\vrule height\zzglobaltotheight depth-\zzglobaltotdepth width0pt} \zztotlwidth=\zzglobaltotlwidth\zztotrwidth=\zzglobaltotrwidth} \def\zzoutlinepoly#1#2#3{\zzmakepicture{\zzdmA=#1\zzdmB=#2\relax \zztotheight=\zzdmB\zztotdepth=\zzdmB\zzoutlinepolya #3\end}} \def\zzoutlinepolya#1{\def\zztesta{#1}\def\zztestb{\end} \ifx\zztesta\zztestb\let\zznext=\zzoutlinepolyb \else\let\zznext=\zzoutlinepolyc\fi\zznext {#1}} \def\zzoutlinepolyb#1{} \def\zzoutlinepolyc#1#2#3{\zzrecordwidth\zzdmA\zzdmA\zzrecordheight\zzdmB\zzdmB \zzdmE=#3\multiply\zzdmE by #1\zzdmF=#3\multiply\zzdmF by #2\relax \zzcnA=\zzdmA\zzcnB=\zzdmB\relax \ifnum #1=0\relax\zzcnC=\zzdmF\else\zzcnC=\zzdmE\fi \ifnum\zzcnC<0\relax\zzcnC=-\zzcnC\fi \put(\zzcnA,\zzcnB){\line(#1,#2){\zzcnC}} \advance\zzdmA by \zzdmE\advance\zzdmB by \zzdmF \zzoutlinepolya} \def\zzoutlinerorect#1,#2:#3,#4,#5;{\zzmakepicture{ \zzdmA=#1\zzdmB=#2\zzdmC=#3\zzdmD=#4\zzdmE=#5 \zzcnA=\zzdmA\zzcnB=\zzdmB\zzcnC=\zzdmC\zzcnD=\zzdmD\zzcnE=\zzdmE \ifnum\zzcnD=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)} \else\ifnum\zzcnE=\zzcnC\relax\put(\zzcnA,\zzcnB){\oval(\zzcnD,\zzcnE)} \else\advance\zzcnE by -\zzcnC \zzcnF=\zzcnE\divide\zzcnF by 2\advance\zzcnF by \zzcnB \put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[t]} \advance\zzcnF by -\zzcnE \put(\zzcnA,\zzcnF){\oval(\zzcnD,\zzcnC)[b]} \zzcnC=\zzcnD\divide\zzcnC by 2\advance\zzcnA by \zzcnC \put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}} \advance\zzcnA by -\zzcnD \put(\zzcnA,\zzcnF){\line(0,1){\zzcnE}}\fi\fi \zztotheight=\zzdmE\divide\zztotheight by 2\advance\zztotheight by \zzdmB \zztotdepth=\zztotheight\advance\zztotdepth by -\zzdmE \zzdmC=\zzdmD\divide\zzdmC by -2\advance\zzdmC by \zzdmA \advance\zzdmD by \zzdmC\zzrecordwidth\zzdmC\zzdmD}} %\border, \borderto, and \symmetrize adjust the current rectangle. \def\border#1#2{\advance\texpr by #2\advance\bexpr by -#2 \advance\lexpr by -#1\advance\rexpr by #1} \def\borderto#1#2{\zzdmA=\rexpr\advance\zzdmA by -\lexpr\relax \ifdim#1>\zzdmA\relax\advance\zzdmA by -#1\divide\zzdmA by 2 \advance\rexpr by -\zzdmA\advance\lexpr by \zzdmA\fi \zzdmA=\texpr\advance\zzdmA by -\bexpr\relax \ifdim#2>\zzdmA\relax\advance\zzdmA by -#2\divide\zzdmA by 2 \advance\texpr by -\zzdmA\advance\bexpr by \zzdmA\fi} \def\symmetrize{\zzdmA=\texpr\advance\zzdmA by -\ycenter \zzdmB=\ycenter\advance\zzdmB by -\bexpr\relax \ifdim\zzdmA<\zzdmB\relax\zzdmA=\zzdmB\fi \texpr=\ycenter\advance\texpr by \zzdmA \bexpr=\ycenter\advance\bexpr by -\zzdmA} %\setedge#1,#2,#3,#4: accepts four numbers (giving dimensions as multiples of %\diagramunit). It sets \xstart, \ystart, \xend, \yend to #1, #2, #3, %#4, each multiplied by \diagramunit, and \xslope, \yslope to numbers % giving the slope of the line from \xstart, \ystart to \xend, \yend, %reduced to have a least common divisor. It uses \zzsearchvertexlist to set %\zzstartshadow (\zzendshadow) to the \zzshadow stored on \zzvertexlist with %coordinates #1, #2 (#3, #4). It sets \zzisedge to 1. \def\setedge#1,#2,#3,#4:{\zzcnA=#1\zzcnB=#2 \zzmultdiagramunit\xstart\zzcnA\zzmultdiagramunit\ystart\zzcnB \expandafter\zzsearchvertexlist\zzvertexlist \let\zzstartshadow=\zzshadow \zzcnA=#3\zzcnB=#4 \zzmultdiagramunit\xend\zzcnA\zzmultdiagramunit\yend\zzcnB \expandafter\zzsearchvertexlist\zzvertexlist \let\zzendshadow=\zzshadow \xslope=#3\advance\xslope by -#1\relax \yslope=#4\advance\yslope by -#2\relax \zzreduceterms\xslope\yslope{START AND END OF EDGE ARE BOTH THE SAME} \xslope=\zzcnC\yslope=\zzcnD\zzisedge=1} %\zzreduceterms sets \zzcnC and \zzcnD to the results of dividing the numbers % #1 and #2 by their greatest common divisor. The error message #3 is given %if #1 and #2 are both zero. \def\zzreduceterms#1#2#3{{ \ifnum#1<0\relax\zzcnA=-#1\else\zzcnA=#1\fi \ifnum#2<0\relax\zzcnB=-#2\else\zzcnB=#2\fi \loop\ifnum\zzcnB>0\relax \zzcnC=\zzcnA\divide\zzcnC by \zzcnB\multiply\zzcnC by -\zzcnB \advance\zzcnC by \zzcnA\zzcnA=\zzcnB\zzcnB=\zzcnC \repeat\relax \ifnum\zzcnA=0\errmessage{#3}\fi \global\zzglobalcnA=\zzcnA} \zzcnC=#1\divide\zzcnC by \zzglobalcnA\zzcnD=#2\divide\zzcnD by \zzglobalcnA} %\zzsearchvertexlist\zzvertexlist searches \zzvertexlist for an entry of the %form #1,#2:#3; for which #1 = \zzcnA and #2 = \zzcnB. If such an entry is %found, \zzshadow is defined to be #3;. Otherwise, \zzshadow is defined to be %\zzdmE=\zzdmA\zzdmF=\zzdmB. \def\zzsearchvertexlist#1{\def\zztesta{#1}\def\zztestb{\end} \ifx\zztesta\zztestb\def\zzshadow{\zzdmE=\zzdmA\zzdmF=\zzdmB} \let\zznext=\zzsearchvertexlista \else\let\zznext=\zzsearchvertexlistb\fi\zznext #1} \def\zzsearchvertexlista#1\end{} \def\zzsearchvertexlistb#1,#2:#3;{\relax \ifnum\zzcnA=#1\relax\ifnum\zzcnB=#2\relax \def\zzshadow{#3;}\let\zznext=\zzsearchvertexlista \else\let\zznext=\zzsearchvertexlist\fi \else\let\zznext=\zzsearchvertexlist\fi\zznext} %\shadeedge shades the start and end of the current edge, changing \xstart, %\ystart, \xend, \yend. \def\shadeedge{\zzcheckedge{SHADE} \def\zzprocpoly{\zzcastpoly}\def\zzprocrorect{\zzprocrorecta} \zzdmA=\xstart\zzdmB=\ystart\zzcnA=\xslope\zzcnB=\yslope \zzstartshadow\xstart=\zzdmE\ystart=\zzdmF \zzdmA=\xend\zzdmB=\yend\zzcnA=-\xslope\zzcnB=-\yslope \zzendshadow\xend=\zzdmE\yend=\zzdmF} \def\zzcheckedge#1{\relax\ifnum\zzisedge=0\relax\errmessage {ATTEMPT TO #1 NONEXISTENT EDGE}\fi} %\zzprocrorecta is used as the definition of \zzprocrorect within \shadeedge %and \zzabut. It causes a rounded rectangle to be treated as the %circumscribed octagon for purposes of shadowing or abutment. \def\zzprocrorecta#1,#2:#3,#4,#5;{\zzdmC=#3 \multiply\zzdmC by 53\divide\zzdmC by 181 \zzdmD=\zzdmC\multiply\zzdmD by -2\zzdmE=\zzdmD \advance\zzdmD by #4\advance\zzdmE by #5 \zzdmF=#4\divide\zzdmF by -2\advance\zzdmF by #1\advance\zzdmF by \zzdmC \zzdmG=#5\divide\zzdmG by 2\advance\zzdmG by #2 \edef\zzlocalshadow{\noexpand\zzprococtagon \the\zzdmF,\the\zzdmG:\the\zzdmC,\the\zzdmD,\the\zzdmE;} \zzlocalshadow} %\zzcastpoly computes the outgoing intersection of a directed line, %x = xs.t+x0, y = ys.t+y0 with a convex polygon. It is called %by defining \zzprocpoly to be \zzcastpoly, setting \zzdmA, \zzdmB, \zzcnA, %\zzcnB to x0, y0, xs, ys, and executing \zzshadow, which must have been %defined by a polygon descriptor. The result is left in \zzdmE, \zzdmF. %If the directed line does not intersect the polygon, the result is the %point on the line that is closest to the polygon. \def\zzcastpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0 \zzcastpolya #3\end} \def\zzcastpolya#1{\def\zztesta{#1}\def\zztestb{\end} \ifx\zztesta\zztestb\let\zznext=\zzcastpolyg \else\let\zznext=\zzcastpolyc\fi\zznext {#1}} \def\zzcastpolyb#1\end{\zzcnC=\zzcnA\multiply\zzcnC by \zzcnA \zzcnD=\zzcnB\multiply\zzcnD by \zzcnB\advance\zzcnC by \zzcnD \zzdmE=\zzdmC\advance\zzdmE by -\zzdmA\multiply\zzdmE by \zzcnA \zzdmF=\zzdmD\advance\zzdmF by -\zzdmB\multiply\zzdmF by \zzcnB \advance\zzdmE by \zzdmF\divide\zzdmE by \zzcnC\zzdmF=\zzdmE \multiply\zzdmE by \zzcnA\advance\zzdmE by \zzdmA \multiply\zzdmF by \zzcnB\advance\zzdmF by \zzdmB} \def\zzcastpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax \zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax \ifnum\zzcnD>0\relax \ifnum\zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\else \zzdmE=\zzdmA\advance\zzdmE by -\zzdmC\multiply\zzdmE by \zzcnB \zzdmF=\zzdmB\advance\zzdmF by -\zzdmD\multiply\zzdmF by \zzcnA \advance\zzdmE by -\zzdmF\divide\zzdmE by \zzcnD\relax \ifdim\zzdmE>#3\relax\zzcnC=3\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya \else\ifnum\zzcnC=3\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\else \ifdim\zzdmE<0pt\relax \ifnum\zzcnC=1\let\zznext=\zzcastpolyb\else \zzcnC=2\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi \else\zzcastpolyf{#1}{#2}\let\zznext=\zzcastpolye\fi\fi\fi\fi \else\ifnum\zzcnC=3\let\zznext=\zzcastpolyb \else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzcastpolya\fi\fi \zznext} \def\zzcastpolyd#1#2#3{ \zzdmE=#3\multiply\zzdmE by #1\advance\zzdmC by \zzdmE \zzdmE=#3\multiply\zzdmE by #2\advance\zzdmD by \zzdmE} \def\zzcastpolye#1\end{} \def\zzcastpolyf#1#2{\zzdmF=\zzdmE \multiply\zzdmE by #1\relax\advance\zzdmE by \zzdmC \multiply\zzdmF by #2\relax\advance\zzdmF by \zzdmD} \def\zzcastpolyg#1{\zzcastpolyb\end} %\shiftedge changes \xstart, \ystart, \xend, \yend so as to displace %the edge from \xstart, \ystart to \xend, \yend by a vector of length %#1 (a dimension) that is rotated 90 degrees counterclockwise from the edge. \def\shiftedge#1{\zzcheckedge{SHIFT} \zzdistance\xslope\yslope \zzdmA=#1\multiply\zzdmA by 100\divide\zzdmA by \zzglobalcnA\zzdmB=\zzdmA \multiply\zzdmA by -\yslope\multiply\zzdmB by \xslope \advance\xstart by \zzdmA \advance\xend by \zzdmA \advance\ystart by \zzdmB \advance\yend by \zzdmB} %\zzsqroot#1 accepts an integer and sets \zzglobalcnA to the integer part %of its square root. It works for numbers up to at least 1,000,000,000. \def\zzsqroot#1{{\zzcnA=#1 %x is \zzcnA, y is \zzcnB, n is \zzcnC, z is \zzcnD \zzcnC=0\zzcnD=1 \loop\zzcnE=\zzcnA\divide\zzcnE by \zzcnD\advance\zzcnE by 1 \relax\ifnum\zzcnD<\zzcnE\relax \advance \zzcnC by 1\multiply\zzcnD by 2 \repeat \zzcnB=0 \loop\ifnum\zzcnC>0\relax \advance\zzcnC by -1\divide\zzcnD by 2 \zzcnE=\zzcnB\advance\zzcnE by \zzcnD\multiply\zzcnE by \zzcnE\relax \ifnum\zzcnA<\zzcnE\relax\else\advance\zzcnB by \zzcnD\fi \repeat \global\zzglobalcnA=\zzcnB}} %\zzdistance#1#2 accepts two integers and sets \zzglobalcnA to 100 times %the square root of the sum of their squares. \def\zzdistance#1#2{{\zzcnA=#1\multiply\zzcnA by \zzcnA \zzcnB=#2\multiply\zzcnB by \zzcnB \advance\zzcnA by \zzcnB\multiply\zzcnA by 10000 \zzsqroot\zzcnA}} %\drawdashedge, \drawdotedge, or \drawsolidedge draws a dashed, dotted, or %solid line along the current edge. \def\drawdashedge#1#2#3#4{\zzcnA=1\zzdmA=#1\zzdmB=#2 \zzcheckposdimen\zzdmA{FIRST}{DRAWDASHEDGE} \zzcheckposdimen\zzdmB{SECOND}{DRAWDASHEDGE} \zzchecknonnegnum{#3}{THIRD}{DRAWDASHEDGE} \zzchecknonnegnum{#4}{FOURTH}{DRAWDASHEDGE} \zzcnI=#3\relax\advance\zzcnI by #4\relax \ifnum\zzcnI>0\else\errmessage {SUM OF THIRD AND FOURTH PARAMETERS OF DRAWDASHEDGE MUST BE POSITIVE}\fi \advance\zzdmB by \zzdmA \zzdrawedge{\advance\zzcnC by -\zzcnD \zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax \ifnum\zzcnG>0\relax \zzcnH=\zzcnG\multiply\zzcnH by \zzcnE\advance\zzcnC by -\zzcnH \zzcnH=\zzcnI\multiply\zzcnH by \zzcnG \advance\zzcnH by #3\divide\zzcnC by \zzcnH \zzcnH=#3\multiply\zzcnH by \zzcnC\advance\zzcnD by \zzcnH \multiply\zzcnC by \zzcnI\advance\zzcnE by \zzcnC \else\advance\zzcnD by \zzcnC\fi} {\line(\xslope,\yslope){\zzcnD}}} \def\zzcheckposdimen#1#2#3{\relax\ifdim#1>0pt\else\errmessage{ #2 PARAMETER OF #3 MUST BE POSITIVE}\fi} \def\zzchecknonnegnum#1#2#3{\relax\ifnum#1<0\relax\errmessage{ #2 PARAMETER OF #3 MUST BE NONNEGATIVE}\fi} \def\drawdotedge#1#2{\zzcnA=0\zzdmA=0pt\zzdmB=#1 \zzcheckposdimen\zzdmB{}{DRAWDOTEDGE}\zzcheckbool{#2}{SECOND}{DRAWDOTEDGE} \zzdrawedge{\zzcnG=\zzcnC\divide\zzcnG by \zzcnE\relax \ifnum\zzcnG<1\relax\zzcnG=1\fi\zzcnE=\zzcnC\divide\zzcnE by \zzcnG\relax \ifnum#2=0\relax\advance\zzcnG by -1\fi} {\kern-1.39pt\raise-.76pt\hbox{.}}} \def\drawsolidedge{\zzcnA=1\zzdmA=0pt\zzdmB=0pt \zzdrawedge{\zzcnG=0\zzcnD=\zzcnC} {\line(\xslope,\yslope){\zzcnD}}} \def\zzdrawedge#1#2{\zzcheckedge{DRAW}\relax \ifnum\zzcnA=1\relax\zzcheckslope\xslope\yslope\slopemax{SOLID OR DASHED EDGE}\fi%%%pict2e \zzcnA=\xstart\zzcnB=\ystart\zzcnD=\zzdmA\zzcnE=\zzdmB\relax \ifnum\xslope=0\relax\zzcnC=\yend\advance\zzcnC by -\zzcnB\zzcnF=\yslope \else\zzcnC=\xend\advance\zzcnC by -\zzcnA\zzcnF=\xslope \zzdistance\xslope\yslope\relax \ifnum\xslope<0\relax\global\zzglobalcnA=-\zzglobalcnA\fi \multiply\zzcnD by 100\divide\zzcnD by \zzglobalcnA\multiply\zzcnD by \xslope \multiply\zzcnE by 100\divide\zzcnE by \zzglobalcnA\multiply\zzcnE by \xslope \fi \ifnum\zzcnF<0\relax\zzcnC=-\zzcnC\fi \ifnum\zzcnC>0\relax #1\relax \ifnum\zzcnF<0\relax\zzcnE=-\zzcnE\fi\zzcnF=\zzcnE\relax \ifnum\xslope=0\relax\zzcnE=0 \else\multiply\zzcnF by \yslope\divide\zzcnF by \xslope\fi \zzmakepicture{\loop\put(\zzcnA,\zzcnB){#2} \ifnum\zzcnG>0\relax\advance\zzcnG by -1 \advance\zzcnA by \zzcnE\advance\zzcnB by \zzcnF\repeat \zzrecordwidth\xstart\xstart\zzrecordwidth\xend\xend \zztotheight=\ystart\zztotdepth=\ystart\zzrecordheight\yend\yend}\fi} %\drawedgehead draws an arrowhead along the current edge. \def\drawedgehead#1#2#3{\zzcheckbool{#2}{SECOND}{DRAWEDGEHEAD} \zzcheckbool{#3}{THIRD}{DRAWEDGEHEAD}\zzcnB=#3 \relax\ifnum#2=1\relax\zzcnA=#1\relax \zzdrawedgeheada\xstart\ystart\xend\yend\xslope\yslope \else\zzcnA=100\advance\zzcnA by -#1\relax \zzdrawedgeheada\xend\yend\xstart\ystart{-\xslope}{-\yslope}\fi} %\zzcheckbool gives an error message unless its first argument is 1 or 0. \def\zzcheckbool#1#2#3{ \ifnum#1<0\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi \ifnum#1>1\errmessage{#2 PARAMETER OF #3 MUST BE 1 OR 0}\fi} \def\zzdrawedgeheada#1#2#3#4#5#6{\zzcheckedge{DRAW ARROWHEAD FOR} \zzcheckslope{#5}{#6}\slopemax{ARROWHEAD}%%%pict2e \zzdmA=#3\advance\zzdmA by -#1 \divide\zzdmA by 10\multiply\zzdmA by \zzcnA\divide\zzdmA by 10 \zzdmB=#4\advance\zzdmB by -#2 \divide\zzdmB by 10\multiply\zzdmB by \zzcnA\divide\zzdmB by 10 \relax\ifnum\zzcnB=1\relax \zzdistance{#5}{#6}\zzdmC=\edgeheaddisp \multiply\zzdmC by 100\divide\zzdmC by \zzglobalcnA\zzdmD=\zzdmC \multiply\zzdmC by #5\multiply\zzdmD by #6 \advance\zzdmA by \zzdmC\advance\zzdmB by \zzdmD\fi \advance\zzdmA by #1\zzcnA=\zzdmA\advance\zzdmB by #2\zzcnB=\zzdmB \zzmakepicture{\put(\zzcnA,\zzcnB){\vector(#5,#6){0}} \zzrecordwidth\zzdmA\zzdmA\zztotheight=\zzdmB\zztotdepth=\zzdmB}} %\zzcheckslope gives an errormessage if the absolute value of #1 or #2 %is greater than #3. \def\zzcheckslope#1#2#3#4{\relax \ifnum#1>#3\zzcheckslopea{#1}{#2}{#4}\fi \ifnum#1<-#3\zzcheckslopea{#1}{#2}{#4}\fi \ifnum#2>#3\zzcheckslopea{#1}{#2}{#4}\fi \ifnum#2<-#3\zzcheckslopea{#1}{#2}{#4}\fi} \def\zzcheckslopea#1#2#3{\errmessage{\the#1,\the#2 IS ILLEGAL SLOPE FOR #3}} %The following macros each call \zzsetupbox{#2}{#3} and then issue the %resulting expression so that its shadow touches the edge x = \xslope.t %+\xstart, y = \yslope.t+\ystart. \abutX places the expression to the X %of the edge. For \abutleft and \abutright, #1 gives the y-coordinate %of the expression as an integer multiple of \diagramunit. For \abutbelow %and \abutabove, #1 gives the x-coordinate similarly. The macros \abutXd %are similar, except that #1 should be a dimension. \def\abutleft#1:#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{1}} \def\abutright#1:#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{1}} \def\abutbelow#1:#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{1}} \def\abutabove#1:#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{1}} \def\abutleftd#1#2#3{\zzabut{#1}{#2}{#3}{-\yslope}{\zzslidehoriz}{0}} \def\abutrightd#1#2#3{\zzabut{#1}{#2}{#3}{\yslope}{\zzslidehoriz}{0}} \def\abutbelowd#1#2#3{\zzabut{#1}{#2}{#3}{\xslope}{\zzslidevert}{0}} \def\abutaboved#1#2#3{\zzabut{#1}{#2}{#3}{-\xslope}{\zzslidevert}{0}} \def\zzabut#1#2#3#4#5#6{\zzcheckedge{ABUT TO} \zzsetupbox{#2}{#3}\zzcnA=\xslope\zzcnB=\yslope \relax\ifnum#4<0\relax\zzcnA=-\zzcnA\zzcnB=-\zzcnB\fi \def\zzprocpoly{\zzclosestpoly}\def\zzprocrorect{\zzprocrorecta} \zzglobalshadow \advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter \relax\ifnum#6=1\relax\zzmultdiagramunit\zzdmA{#1}\else\zzdmA=#1\fi \zzdmB=\zzdmA#5\relax\zzissue} \def\zzslidehoriz{\relax\ifnum\yslope=0\errmessage {ABUTLEFT OR ABUTRIGHT ATTEMPTED FOR HORIZONTAL EDGE}\fi \advance\zzdmA by \zzdmD\advance\zzdmA by -\ystart \multiply\zzdmA by \xslope\divide\zzdmA by \yslope \advance\zzdmA by \xstart\advance\zzdmA by -\zzdmC} \def\zzslidevert{\relax\ifnum\xslope=0\errmessage {ABUTBELOW OR ABUTABOVE ATTEMPTED FOR VERTICAL EDGE}\fi \advance\zzdmB by \zzdmC\advance\zzdmB by -\xstart \multiply\zzdmB by \yslope\divide\zzdmB by \xslope \advance\zzdmB by \ystart\advance\zzdmB by -\zzdmD} %\zzclosestpoly finds the vertex of a convex polygon that is closest to a %directed line, x = xs.t+x0, y = ys.t+y0, assuming that the directed line %is to the left (right) of the polygon if ys is positive (negative) %and above (below) the polygon if xs is positive (negative). %It is called by defining \zzprocpoly to be \zzclosestpoly, setting \zzcnA, %\zzcnB to xs, ys, and executing \zzglobalshadow, which must have been %defined by a polygon descriptor. The output is left in \zzdmC, \zzdmD. \def\zzclosestpoly#1#2#3{\zzdmC=#1\zzdmD=#2\zzcnC=0\zzclosestpolya #3\end} \def\zzclosestpolya#1{\def\zztesta{#1}\def\zztestb{\end} \ifx\zztesta\zztestb\let\zznext=\zzclosestpolyb \else\let\zznext=\zzclosestpolyc\fi\zznext {#1}} \def\zzclosestpolyb#1{} \def\zzclosestpolyc#1#2#3{\zzcnD=\zzcnB\multiply\zzcnD by #1\relax \zzcnE=\zzcnA\multiply\zzcnE by #2\relax\advance\zzcnD by -\zzcnE\relax \ifnum\zzcnD>0\relax \ifnum\zzcnC=1\let\zznext=\zzclosestpolyd \else\zzcnC=0\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi \else\zzcnC=1\zzcastpolyd{#1}{#2}{#3}\let\zznext=\zzclosestpolya\fi \zznext} \def\zzclosestpolyd#1\end{} %\setcircle initializes \dcircle, \xcircle, and \ycircle to its first %three parameters, and sets \zziscircle to 1. \def\setcircle#1#2#3{\dcircle=#1\xcircle=#2\ycircle=#3\zziscircle=1} %\shiftcircle#1#2 displaces \xcircle, \ycircle by #1, #2. \def\shiftcircle#1#2{\zzcheckcircle{SHIFT} \advance\xcircle by #1\advance\ycircle by #2} \def\zzcheckcircle#1{\relax\ifnum\zziscircle=0\errmessage {ATTEMPT TO #1 NONEXISTENT CIRCLE}\fi} %\drawcircle draws quadrants of the current circle. \def\drawcircle#1#2#3#4{\zzcheckcircle{DRAW}\zzdmA=\dcircle\divide\zzdmA by 2 \zzmakepicture{\zzcnA=\dcircle\zzcnB=\xcircle\zzcnC=\ycircle \zztotheight=\ycircle\zztotdepth=\ycircle \zzrecordwidth\xcircle\xcircle\relax \zzdrawcirclea{#1}{tr}{\zzdmA}{\zzdmA}\zzdrawcirclea{#2}{br}{\zzdmA}{-\zzdmA} \zzdrawcirclea{#3}{bl}{-\zzdmA}{-\zzdmA} \zzdrawcirclea{#4}{tl}{-\zzdmA}{\zzdmA}}} \def\zzdrawcirclea#1#2#3#4{\zzcheckbool{#1}{}{DRAWCIRCLE}\ifnum#1=1\relax \put(\zzcnB,\zzcnC){\oval(\zzcnA,\zzcnA)[#2]} \zzdmB=\xcircle\advance\zzdmB by #3\zzrecordwidth\zzdmB\zzdmB \zzdmB=\ycircle\advance\zzdmB by #4\zzrecordheight\zzdmB\zzdmB\fi} %\drawcirclehead issues an arrowhead placed on the current circle. \def\drawcirclehead#1#2#3{\zzcheckcircle{DRAW ARROWHEAD FOR} \zzreduceterms{#1}{#2}{0,0 ARE ILLEGAL PARAMETERS FOR DRAWCIRCLEHEAD} \zzdistance{\zzcnC}{\zzcnD}\zzcheckbool{#3}{THIRD}{DRAWCIRCLEHEAD} \ifnum#3=1\relax\zzcnA=\zzcnD\zzcnB=-\zzcnC\else\zzcnA=-\zzcnD\zzcnB=\zzcnC\fi \zzdmA=\dcircle\multiply\zzdmA by 50\divide\zzdmA by \zzglobalcnA \zzdmB=\circleheaddisp\multiply\zzdmB by 100\divide\zzdmB by \zzglobalcnA \zzdmE=\zzdmA\multiply\zzdmE by \zzcnC\zzdmC=\xcircle\advance\zzdmC by \zzdmE \zzdmE=\zzdmB\multiply\zzdmE by \zzcnA\advance\zzdmC by \zzdmE \zzdmE=\zzdmA\multiply\zzdmE by \zzcnD\zzdmD=\ycircle\advance\zzdmD by \zzdmE \zzdmE=\zzdmB\multiply\zzdmE by \zzcnB\advance\zzdmD by \zzdmE \zzcnC=\zzdmC\zzcnD=\zzdmD\zzcheckslope\zzcnA\zzcnB\slopemax{ARROWHEAD}%%%pict2e \zzmakepicture{\put(\zzcnC,\zzcnD){\vector(\zzcnA,\zzcnB){0}} \zzrecordwidth\zzdmC\zzdmC\zztotheight=\zzdmD\zztotdepth=\zzdmD}} %The next four macros cause an expression to be abutted to the current %circle. \def\abutcircleleft#1#2#3{\zzabutcircle{#1}{#2}{#3}{} \zzslidehoriz{\relax\ifdim\zzdmA>\zzdmH\relax\zzdmH=\zzdmA\fi}} \def\abutcircleright#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate\zzrotate} \zzslidehoriz{\relax\ifdim\zzdmA<\zzdmH\relax\zzdmH=\zzdmA\fi}} \def\abutcirclebelow#1#2#3{\zzabutcircle{#1}{#2}{#3}{\zzrotate} \zzslidevert{\relax\ifdim\zzdmB>\zzdmI\relax\zzdmI=\zzdmB\fi}} \def\abutcircleabove#1#2#3{\zzabutcircle {#1}{#2}{#3}{\zzrotate\zzrotate\zzrotate} \zzslidevert{\relax\ifdim\zzdmB<\zzdmI\relax\zzdmI=\zzdmB\fi}} \def\zzabutcircle#1#2#3#4#5#6{\zzcheckcircle{ABUT TO} \zzsetupbox{#2}{#3}\def\zzprocpoly{\zzclosestpoly} \def\zzprocrorect{\zzprocrorecta} \zzdmF=\dcircle\divide\zzdmF by 2 \zzdmG=\dcircle\multiply\zzdmG by 100\divide\zzdmG by 283 \xstart=-\zzdmF\ystart=0pt\xslope=0\yslope=-1 \zzabutcirclea{#1}{#4}{#5}\zzdmH=\zzdmA\zzdmI=\zzdmB \xstart=-\zzdmG\ystart=\zzdmG\xslope=-1\yslope=-1 \zzabutcirclea{#1}{#4}{#5}#6\relax \xstart=-\zzdmG\ystart=-\zzdmG\xslope=1\yslope=-1 \zzabutcirclea{#1}{#4}{#5}#6\relax \zzdmA=\zzdmH\advance\zzdmA by \xcircle \zzdmB=\zzdmI\advance\zzdmB by \ycircle \zzissue} \def\zzabutcirclea#1#2#3{#2\relax \zzcnA=\xslope\zzcnB=\yslope \zzglobalshadow \advance\zzdmC by -\zzglobalxcenter\advance\zzdmD by -\zzglobalycenter \zzdmA=#1\zzdmB=\zzdmA #3\relax} \def\zzrotate{\zzdmE=\xstart\xstart=-\ystart\ystart=\zzdmE \zzcnC=\xslope\xslope=-\yslope\yslope=\zzcnC} %MACROS FOR CATEGORY-THEORY DIAGRAMS %The following control symbols may be redefined by the user: \def\ctvertexstyle{\displaystyle} \def\ctabutstyle{\textstyle} \def\ctvertexborderlr{3pt} \def\ctvertexbordertb{4pt} \def\ctloopdiameter{20pt} \def\ctabutcircledisp{5pt} \def\ctabutborderlr{2pt} \def\ctabutbordertb{2pt} \def\ctabutborderinset{3pt} \def\ctabutborderinsetdouble{6pt}%Must be twice \ctabutborderinset \def\ctdoubleedgedisp{2pt} %The following registers are used locally: \newdimen\zzdmX\newdimen\zzdmY %Hidden macros and other defined control symbols: % used by \ctdiagram: \diagram\ctsolid\cthead % used by \ctv and \ctvg: \vertex\border\rect % used by \ctgl: \leftghost % used by \ctgr: \rightghost % used by \ctlptl, \ctlptlcc, \ctlptr, \ctlptrcc, \ctlpbr, \ctlpbrcc, % \ctlpbl, \ctlpblcc: \zzctlp\border\setcircle\shiftcircle\drawcircle % \drawcirclehead\abutcircleleft\abutcircleright\zzctabutprog % \octagon % used by \cten, \ctet, \cteb, \ctel, \cter, \ctetg, \ctebg, \ctelg, \cterg, % \ctetb, \ctelr, \ctetbg, \ctelrg: \setedge\zzctxmean\zzctymean % \zzmultdiagramunit\zzcte\zzctee\shadeedge\abutaboved\abutbelowd % \abutleftd\abutrightd\zzctabutprog\border\octagon\shiftedge % \drawsolidedge\zzctdrawdashedge\drawdashedge\zzctdrawdotedge % \drawdotedge\zzctdrawedgehead\drawedgehead\zzctnodrawedgehead % multiply defined control symbols: \zzctdrawedge\zzctdrawhead % \zzctxmeanadj\zzctymeanadj %\ctdiagram is similar to \diagram, except that it executes \ctsolid and %\cthead before the expression program #1. \def\ctdiagram#1{\diagram{\ctsolid\cthead\ctoutermid #1}} %\ctvg is similar to \vertex except that the expression #3 is printed in %\ctvertexstyle mode, and the expression program #4 is followed by a %standard program that borders the current rectangle by \ctvertexborderlr %on the sides and \ctvertexbordertb on the top and bottom, and then %creates a rectangular shadow. \ctv is similar to \ctvg except that the %expression program is empty (except for the standard program). \def\ctvg#1,#2:#3#4{\vertex #1,#2:{\ctvertexstyle #3}{#4\relax \border\ctvertexborderlr\ctvertexbordertb\rect}} \def\ctv#1,#2:#3{\ctvg #1,#2:{#3}{}} %\ctgl and \ctgr are similar to \leftghost and \rightghost except that %the expression #1 is printed in \ctvertexstyle. \def\ctgl#1{\leftghost{\ctvertexstyle #1}} \def\ctgr#1{\rightghost{\ctvertexstyle #1}} %The following eight macros print a three-quarter-circle loop of diameter %\ctloopdiameter at one of the corners of an expanded current rectangle, %with an arrowhead at one end of the loop. \def\ctlptl#1{\zzctlp{\lexpr\texpr}{{0pt}\circleheaddisp}{1011}{101} {\abutcircleleft\ctabutcircledisp}{#1}} \def\ctlptlcc#1{\zzctlp{\lexpr\texpr}{{-\circleheaddisp}{0pt}}{1011}{0{-1}0} {\abutcircleleft\ctabutcircledisp}{#1}} \def\ctlptr#1{\zzctlp{\rexpr\texpr}{\circleheaddisp{0pt}}{1101}{0{-1}1} {\abutcircleright\ctabutcircledisp}{#1}} \def\ctlptrcc#1{\zzctlp{\rexpr\texpr}{{0pt}\circleheaddisp}{1101}{{-1}00} {\abutcircleright\ctabutcircledisp}{#1}} \def\ctlpbr#1{\zzctlp{\rexpr\bexpr}{{0pt}{-\circleheaddisp}}{1110}{{-1}01} {\abutcircleright{-\ctabutcircledisp}}{#1}} \def\ctlpbrcc#1{\zzctlp{\rexpr\bexpr}{\circleheaddisp{0pt}}{1110}{010} {\abutcircleright{-\ctabutcircledisp}}{#1}} \def\ctlpbl#1{\zzctlp{\lexpr\bexpr}{{-\circleheaddisp}{0pt}}{0111}{011} {\abutcircleleft{-\ctabutcircledisp}}{#1}} \def\ctlpblcc#1{\zzctlp{\lexpr\bexpr}{{0pt}{-\circleheaddisp}}{0111}{100} {\abutcircleleft{-\ctabutcircledisp}}{#1}} \def\zzctlp#1#2#3#4#5#6{\border\ctvertexborderlr\ctvertexbordertb \setcircle\ctloopdiameter #1 \border{-\ctvertexborderlr}{-\ctvertexbordertb} \shiftcircle #2\drawcircle #3\drawcirclehead #4 #5{\ctabutstyle #6}\zzctabutprog} \def\zzctabutprog{\border\ctabutborderlr\ctabutbordertb \borderto{\ctabutborderinsetdouble}{\ctabutborderinsetdouble} \octagon\ctabutborderinset} %\cten#1,#2,#3,#4: draws a shaded edge from #1,#2 to #3,#4, possibly with %an arrowhead at its end. \def\cten#1:{\setedge#1:\shadeedge\zzctdrawedge\zzctdrawhead1} %The following four macros draw a shaded edge, possibly with an arrowhead %at the end, and abut an expression to the edge at its midpoint. \def\ctet#1:#2{\setedge#1:\zzctxmean\zzcte\abutaboved{#2}\zzctxmeanadj} \def\cteb#1:#2{\setedge#1:\zzctxmean\zzcte\abutbelowd{#2}\zzctxmeanadj} \def\ctel#1:#2{\setedge#1:\zzctymean\zzcte\abutleftd{#2}\zzctymeanadj} \def\cter#1:#2{\setedge#1:\zzctymean\zzcte\abutrightd{#2}\zzctymeanadj} \def\zzctxmean{\zzdmX=\xstart\advance\zzdmX by \xend\divide\zzdmX by 2} \def\zzctymean{\zzdmX=\ystart\advance\zzdmX by \yend\divide\zzdmX by 2} \def\zzcte#1#2#3{\shadeedge #3\zzctdrawedge\zzctdrawhead1 #1\zzdmX{\ctabutstyle #2}\zzctabutprog} %The next four macros behave similarly to those above, but abut an %expression to a specified point on the edge. \def\ctetg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte \abutaboved{#3}\relax} \def\ctebg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte \abutbelowd{#3}\relax} \def\ctelg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte \abutleftd{#3}\relax} \def\cterg#1;#2:#3{\setedge#1:\zzmultdiagramunit\zzdmX{#2}\zzcte \abutrightd{#3}\relax} %\ctetb (\ctelr) draws a pair of shaded edges, with two expressions %abutted to the top and bottom (left and right) of the midpoint. %\ctetbg and \ctelrg are similar, but abut to a specified point on the edge. \def\ctetb#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTETB} \zzcheckbool{#3}{SIXTH}{CTETB} \setedge#1:\zzctxmean\zzctee\xslope\abutaboved\abutbelowd {#2}{#3}{#4}{#5}\zzctxmeanadj} \def\ctelr#1:#2#3#4#5{\zzcheckbool{#2}{FIFTH}{CTELR} \zzcheckbool{#3}{SIXTH}{CTELR} \setedge#1:\zzctymean\zzctee\yslope\abutleftd\abutrightd {#2}{#3}{#4}{#5}\zzctymeanadj} \def\ctetbg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTETBG} \zzcheckbool{#5}{EIGHTH}{CTETBG}\setedge#1:\zzmultdiagramunit\zzdmX{#2} \zzctee\xslope \abutaboved{\zzmultdiagramunit\zzdmX{#3}\abutbelowd}{#4}{#5}{#6}{#7}\relax} \def\ctelrg#1;#2,#3:#4#5#6#7{\zzcheckbool{#4}{SEVENTH}{CTELRG} \zzcheckbool{#5}{EIGHTH}{CTELRG}\setedge#1:\zzmultdiagramunit\zzdmX{#2} \zzctee\yslope \abutleftd{\zzmultdiagramunit\zzdmX{#3}\abutrightd}{#4}{#5}{#6}{#7}\relax} \def\zzctee#1#2#3#4#5#6#7#8{ \ifnum#1>0\relax\zzdmY=\ctdoubleedgedisp\else\zzdmY=-\ctdoubleedgedisp\fi \shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#4} #2\zzdmX{\ctabutstyle #6}\zzctabutprog \multiply\zzdmY by -2\relax \shiftedge\zzdmY\shadeedge #8\zzctdrawedge\zzctdrawhead{#5} #3\zzdmX{\ctabutstyle #7}\zzctabutprog} %\ctinnermid defines \zzctxmeanadj and \zzctymeanadj so that \ctet, \cteb, %\ctel, \cter, \ctetb, and \ctelr recompute the midpoint of the current %edge after shading. \ctoutermid defines these control symbols so that %these routines do not recompute the midpoint. \def\ctinnermid{\def\zzctxmeanadj{\zzctxmean}\def\zzctymeanadj{\zzctymean}} \def\ctoutermid{\def\zzctxmeanadj{\relax}\def\zzctymeanadj{\relax}} %\zzctdrawdashedge draws a dashed edge. \def\zzctdrawdashedge{\relax \ifnum\xslope=0\relax\drawdashedge{7pt}{7pt}11 \else\ifnum\yslope=0\relax\drawdashedge{7pt}{7pt}11 \else\drawdashedge{15pt}{7pt}01\fi\fi} %\zzctdrawdotedge draws a dotted edge. \def\zzctdrawdotedge{\drawdotedge{8pt}1} %\ctsolid (\ctdash,\ctdot) defines \zzctdrawedge to be \drawsolidedge %(\zzctdrawdashedge,\zzctdrawdotedge), so that edges will be solid %(dashed, dotted). \def\ctsolid{\def\zzctdrawedge{\drawsolidedge}} \def\ctdash{\def\zzctdrawedge{\zzctdrawdashedge}} \def\ctdot{\def\zzctdrawedge{\zzctdrawdotedge}} %\zzctdrawedgehead places a forward-pointing arrowhead at the end of an edge %if #1=1 or a backward-pointing arrowhead at the beginning if #1=0. %\zzctnodrawedgehead is called in the same way but does nothing. \def\zzctdrawedgehead#1{\relax\ifnum#1=1\relax \drawedgehead{100}10\else\drawedgehead{0}00\fi} \def\zzctnodrawedgehead#1{} %\cthead (\ctnohead) defines \zzctdrawhead to be \zzctdrawedgehead %(\zzctnodrawedgehead), so that edges will (will not) have arrowheads. \def\cthead{\def\zzctdrawhead{\zzctdrawedgehead}} \def\ctnohead{\def\zzctdrawhead{\zzctnodrawedgehead}} % Extensions by Bob Tennent (May 2009): % %\drawedgebar draws a bar across the end of the current edge. % \def\drawedgebar{\zzdrawedgebara\xend\yend\xstart\ystart{-\xslope}{-\yslope}} \def\zzdrawedgebara#1#2#3#4#5#6{\zzcheckedge{DRAW ARROWBAR FOR} \zzcheckslope{#5}{#6}4{ARROWBAR} \zzdmA=#3\advance\zzdmA by -#1 \divide\zzdmA by 10\multiply\zzdmA by 100\divide\zzdmA by 10 \zzdmB=#4\advance\zzdmB by -#2 \divide\zzdmB by 10\multiply\zzdmB by 100\divide\zzdmB by 10 \zzdistance{#5}{#6}\zzdmC=0pt \multiply\zzdmC by 100\divide\zzdmC by \zzglobalcnA\zzdmD=\zzdmC \multiply\zzdmC by #5\multiply\zzdmD by #6 \advance\zzdmA by \zzdmC\advance\zzdmB by \zzdmD \advance\zzdmA by #1\zzcnA=\zzdmA\advance\zzdmB by #2\zzcnB=\zzdmB \zzmakepicture{\put(\zzcnA,\zzcnB){\line(#6,-#5){140000}} \zzrecordwidth\zzdmA\zzdmA\zztotheight=\zzdmB\zztotdepth=\zzdmB} \zzmakepicture{\put(\zzcnA,\zzcnB){\line(-#6,#5){140000}} \zzrecordwidth\zzdmA\zzdmA\zztotheight=\zzdmB\zztotdepth=\zzdmB} } % \ctec draws a bezier-curve edge from (#1,#2) to (#3,#4) using (#5,#6) as a % control point; the balanced math text #7 is centered at the control point % \def\ctec#1,#2,#3,#4,#5,#6:#7{ \ctv #5,#6:{#7} % get and save \xstart,\ystart after shadowing \setedge#1,#2,#5,#6: \def\zzprocpoly{\zzcastpoly}\def\zzprocrorect{\zzprocrorecta} \zzdmA=\xstart\zzdmB=\ystart\zzcnA=\xslope\zzcnB=\yslope \zzstartshadow\xstart=\zzdmE\ystart=\zzdmF \zzdmH=\xstart\zzdmI=\ystart % get \xend, \yend and shadow \setedge#5,#6,#3,#4: \def\zzprocpoly{\zzcastpoly}\def\zzprocrorect{\zzprocrorecta} \zzdmA=\xend\zzdmB=\yend\zzcnA=-\xslope\zzcnB=-\yslope \zzendshadow\xend=\zzdmE\yend=\zzdmF % draw head \zzctdrawhead1 % restore saved \xstart, \ystart \xstart=\zzdmH\ystart=\zzdmI % compute control-point parameters \zzcnA=#5\zzcnB=#6 \zzmultdiagramunit\zzdmH\zzcnA\zzmultdiagramunit\zzdmI\zzcnB \zzcnA=\xstart\zzcnB=\ystart\zzcnC=\xend\zzcnD=\yend\zzcnE=\zzdmH\zzcnF=\zzdmI % draw bezier curve \zzmakepicture{\qbezier(\zzcnA,\zzcnB)(\zzcnE,\zzcnF)(\zzcnC,\zzcnD) \zzrecordwidth\xstart\xstart\zzrecordwidth\xend\xend \zztotheight=\ystart\zztotdepth=\ystart\zzrecordheight\yend\yend}}