diff options
Diffstat (limited to 'Master/texmf-dist/source/generic/xypic/xy.doc')
-rw-r--r-- | Master/texmf-dist/source/generic/xypic/xy.doc | 8324 |
1 files changed, 8324 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/generic/xypic/xy.doc b/Master/texmf-dist/source/generic/xypic/xy.doc new file mode 100644 index 00000000000..54ac9fca7d0 --- /dev/null +++ b/Master/texmf-dist/source/generic/xypic/xy.doc @@ -0,0 +1,8324 @@ +%% $Id: xy.doc,v 3.7 1999/02/16 15:12:50 krisrose Exp $ +%% +%% Basic Xy-pictures: Xy-pic bootstrap and kernel macros. +%% Copyright (c) 1991-1999 Kristoffer H. Rose <krisrose@ens-lyon.fr> +%% +%% This file is part of the Xy-pic package for graphs and diagrams in TeX. +%% Copyright (c) 1991-1999 Kristoffer H. Rose <krisrose@ens-lyon.fr> +%% +%% 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\else\message{not reloaded}\endinput\fi +\let\xyloaded=\relax + +% NOTE: Apart from the actual macros (as also found in xy.tex), this file +% contains both the Xy-pic kernel reference manual and TeXnical documentation. +% See xyrefer.man and xysource.man for how to typeset this information. + +\message{Bootstrap\string'ing\string:} + +{\catcode96 12\catcode`\#6\catcode`\.12\catcode`\:12\catcode`\'12\catcode`\@11 +\ifx\xywarnifdefined\undefined\else \immediate\write16{}% + \immediate\write16{Xy-pic Warning: \string\xywarnifdefined\space redefined.}% + \immediate\write16{}\fi +\gdef\xywarnifdefined#1{\ifx#1\undefined\else \immediate\write16{}% + \immediate\write16{Xy-pic Warning: `\string#1' redefined.}% + \immediate\write16{}\fi} +\xywarnifdefined\xydef@ \gdef\xydef@#1{\xywarnifdefined#1\gdef#1} +\xywarnifdefined\xylet@ \gdef\xylet@#1{\xywarnifdefined#1\global\let#1} +\xywarnifdefined\xynew@ + \gdef\xynew@#1#2{\xywarnifdefined#2\csname new#1\endcsname#2}} + +\message{catcodes\string,} + +\xywarnifdefined\xyuncatcodes +\xywarnifdefined\xyreuncatcodes \def\xyreuncatcodes{\edef\xyuncatcodes{% + \catcode92 0 \catcode123 1 \catcode125 2 \catcode37 14 + \catcode 9 \the\catcode 9 \catcode10 \the\catcode10 \catcode12 \the\catcode12 + \catcode35 \the\catcode35 \catcode36 \the\catcode36 \catcode38 \the\catcode38 + \catcode43 \the\catcode43 \catcode45 \the\catcode45 \catcode46 \the\catcode46 + \catcode47 \the\catcode47 + \catcode60 \the\catcode60 \catcode61 \the\catcode61 \catcode62 \the\catcode62 + \catcode64 \the\catcode64 \catcode96 \the\catcode96 + \newlinechar \the\newlinechar \endlinechar \the\endlinechar }} +\xyreuncatcodes + +\xywarnifdefined\xycatcodes \def\xycatcodes{% + \catcode 9 10 + \catcode 35 6 \catcode 36 3 \catcode 38 4 + \catcode 43 12 \catcode 45 12 \catcode 46 12 \catcode 47 12 + \catcode 60 12 \catcode 61 12 \catcode 62 12 + \catcode 64 11 \catcode 96 12 } + +\xycatcodes + +\message{docmode,} + +{\catcode`\|0 \xywarnifdefined|DOCMODE +\gdef|DOCMODE#1{\ifx(#1\relax \xycatcodes \expandafter\ignorespaces + \else \skipspecials@ \expandafter\docm@\fi}% + +\xywarnifdefined\skipspecials@ +\gdef\skipspecials@{% + \catcode`\\12 \catcode`\{12 \catcode`\}12 \catcode`\#12 \catcode`\%12 + \catcode`\^^L12 \endlinechar`\^^J }% + +\catcode`\/=12 \lccode`\/`\\% +\lccode`\D`\D \lccode`\O`\O \lccode`\C`\C \lccode`\M`\M \lccode`\E`\E +\lowercase{% +\xywarnifdefined\docm@ \gdef\docm@{\docm@i}% +\xywarnifdefined\docm@i \gdef\docm@i#1^^J{\docm@ii#1/DOCMODE\docm@iii}% +\xywarnifdefined\docm@ii + \gdef\docm@ii#1/DOCMODE{\def\next@{#1}\futurelet\next\docm@iii}% +\xywarnifdefined\docm@iii \gdef\docm@iii#1\docm@iii{% + \ifx\next\docm@iii \let\next\next@ \docecho@ \let\next@\docm@ + \else\ifx\next@\empty \let\next@\docfinish@ + \else \edef\next@{\noexpand\docm@iv\next@/DOCMODE#1\noexpand\docm@iv}% + \fi\fi \next@}% +\xywarnifdefined\docm@iv + \gdef\docm@iv#1/DOCMODE\docm@iv{\def\next{#1}\docecho@ \docm@}}% + +\xywarnifdefined\docecho@ \global\let\docecho@\relax +\xywarnifdefined\docfinish@ \gdef\docfinish@{\xyuncatcodes|DOCMODE\next}} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + After giving an overview of the \Xy-pic environment in \S??[env], + this \FILE\ document the basic concepts of \Xy-picture construction + in \S??[basics], including the maintained `graphic state'. The + following sections give the precise syntax rules of the main \Xy-pic + constructions: the position language in~\S??[pos], the object + constructions in~\S??[object], and the picture `decorations' + in~\S??[decor]. \S??[objectlib] presents the kernel repertoire of + objects for use in pictures; \S??[option] documents the interface to + \Xy-pic options like the standard `feature' and `extension' options. + +\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Details of the implementation are not discussed here but in the + complete \TeX\-nical documentation~\cite{RM95:Xy-picCSTC}. +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Section \S??[algo] documents the more complicated algorithms used to + compute directions, edges, and connections. +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{The \Xy-pic implementation} +??=[env] + + This section briefly discusses the various aspects of the present + \Xy-pic kernel implementation of which the user should be aware. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Loading \Xy-pic} +??=[env.loading]??w[loading] + + \Xy-pic is careful to set up its own environment in order to function + with a large variety of formats. For most formats a single line with + the command +$$ + ??c![\input xy] +$$ + in the preamble of a document file should load the kernel (see + `integration with standard formats' below for variations possible + with certain formats, in particular \LaTeX~\cite{L94:LaTeX}). + + The rest of this section describes things you must consider if you + need to use \Xy-pic together with other macro packages, style + options, or formats. The less your environment deviates from plain + \TeX\ the easier it should be. +\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Consult the \TeX\-nical documentation~\cite{RM95:Xy-picCSTC} for the + exact requirements for other definitions to coexist with \Xy-pic. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{File header:} +??w[file header] + + Here is what actually happens in the header of |xy.doc|. It contains + the copyright message, protection against ??w![loading] the file more + than once, and then bootstrap code to handle category codes and the + ??c![DOCMODE] format---we explain each separately below: + +\DOCHEADER + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Privacy:} +??w[privacy] + + \Xy-pic will warn about control sequences it redefines---thus you can + be sure that there are no conflicts between \Xy-pic-defined control + sequences, those of your format, and other macros, provided you + load??w[loading] \Xy-pic last and get no ??w![warning + messages] like +$$ + |Xy-pic Warning: `|\dots|' redefined.|??w[redefined] +$$ + In general the \Xy-pic kernel will check all control sequences it + redefines "except" that (1)~generic temporaries like ??c![\next] are + not checked, (2)~predefined font identifiers (see~\S??[env.fonts]) + are assumed intentionally preloaded, and (3)~some of the more exotic + control sequence names used internally (like |@{-}|) are only + checked to be different from ??c![\relax]. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This is handled by ??c![\xywarnifdefined]---after we have ensured + that it is unique itself\footnote{This may seem paranoid but in fact + many inconvieniences in the \TeX\ world stem from the fact that + somebody copied somebody elses definition of, say, + {\tt\string\xywarnifdefined}, modified it, and then used it in + something that somehow got distributed! The `flat name space' + problem remains \TeX\ largest problem as a programming language in + this \TeX\ hackers opinion.}. ??c![\xydef@], ??c![\xylet@], and + |\xynew@{|<type>|}|??c[\xynew@] are abbreviations used to this end + throughout \Xy-pic instead of ??c![\let], ??c![\def], and the + |\new|<type> commands. + + Next some auxilliaries: |\xydefcsname@| is similar to |\xydef@| + except that it builds the control sequence with ??c![\csname] \dots\ + ??c![\endcsname] which means that it is |\relax| when undefined---there + is thus no way to prevent redefinition of control sequences bound to + ??c![\relax]~\frowny. + +\DOCMODE( +\xydef@\xydefcsname@#1{\DN@{#1}\DNii@##1{% + \ifx ##1\relax\else \xywarning@{\string`\string##1\string' redefined}\fi + \def##1}% + \expandafter\nextii@\csname\codeof\next@\endcsname} +\DOCMODE) + + |\xyletcsnamecsname@| is to ??c![\let] one weird control sequence + be the same as another using several |\expandafter|s: + +\DOCMODE( +\xydef@\xyletcsnamecsname@#1#2{\def\1{#1}\def\2{#2}\DN@##1##2{% + \ifx ##1\relax\else \xywarning@{`\string##1\string' redefined}\fi + \let##1=##2}% + \expandafter\expandafter\expandafter\next@ + \expandafter\csname\expandafter\codeof\expandafter\1\expandafter\endcsname + \csname\codeof\2\endcsname} +\DOCMODE) + + Finally ??c![\codeof]: a useful hack used to allow any characters in + control sequences: ??c![\codeof]<cs> expands to the characters of the + control sequence <cs> as a string of `other' characters, \ie, all of + category 12 and with a \verb*/ /$_{12}$ after every control sequence. + The <cs> must be a macro or it blows up. + +\DOCMODE( +\xywarnifdefined\codeof +\xywarnifdefined\codeof@ +{\catcode`\:=12 % to ensure that all of :-> and <-: are other :-) + \gdef\codeof#1{\expandafter\codeof@\meaning#1<-:} + \gdef\codeof@#1:->#2<-:{#2}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Category codes:\ } + + The situation is complicated by the flexibility of + \TeX's input format. The culprit is the `??w![category code]' + concept of \TeX\ (\cf~\cite[p.37]{K84:TeXbook}): when loaded \Xy-pic + requires the characters {\tt\char32}|\{}%| (the first is a space) to + have their standard meaning and all other printable characters to + have the "same category as when \Xy-pic will be used"---in particular + this means that (1)~you should surround the ??w![loading] of \Xy-pic + with ??c![\makeatother] \dots\ ??c![\makeatletter] when loading it + from within a \LaTeX\ package, and that (2)~\Xy-pic should be loaded + after files that change category codes like the ??c![german.sty] that + makes |"| active??w[active characters]. Some styles require that you + reset the catcodes for every diagram, \eg, with ??c![french.sty] you + should use the command |\english| before every |\xymatrix|. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + We define ??c![\xyuncatcodes] to restore the current catcodes, and + ??c![\xycatcodes] to install our own. + + Here is an exact list of the category codes which \Xy-pic requires + (all standard in plain \TeX): +$$ +\vcenter{\tabskip=.5em plus1fil \halign to\displaywidth{#\hfil&&\hfil#\hfil\cr + character(s) &|\| &|{| &|}| &CR &TAB SP&|A|--|Z| |a|--|z| &|0|--|9| &|%| \cr + category code & 0 & 1 & 2 & 5 & 10 & 11 & 12 & 14 \cr} +}$$ + Furthermore none of the remaining printable ASCII characters +$$ + |!"#$&'()*,/:;?@[]^_`||~| +$$ + may be of category 0, 1, 2, 9, 14, or 15, because all should be + tokens allowed in the replacement text of a |\def|---this also means + that they may not be active characters defined to be ``|\outer|''! + + All other catcodes needed are established using ??c![\xycatcodes] + defined above---this is the reason the macros must be loaded at a + time where the category codes are stable (otherwise it will make them + stable!). + + Internally \Xy-pic enforces the following category codes: +$$ +\vcenter{\tabskip=.5em plus1fil \halign to\displaywidth{#\hfil&&\hfil#\hfil\cr + character &|#|&|$|&|&|&|'|&|+|&|-|&|.|&|<|&|=|&|>|&|@|&|`|\cr + ASCII code & 35& 36& 38& 39& 43& 45& 46& 60& 61& 62& 64& 96\cr + category code& 6 & 3 & 4 & 12& 12& 12& 12& 12& 12& 12& 11& 12\cr + abbreviation&|HASH|&|DOLL|&|AND|&|RQ|&|PLUS|&|DASH|&|DOT| + &|LT|&|EQ|&|GT|&|AT|&|LQ|\cr} +}$$ + with special control sequences named |\add|<abbreviation>|@| that + take an argument and expand to it followed by the original character + token, \ie, many tests throughout the program look like |\addDOT@| + |\ifx| |\next| \dots + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\DOCMODE( +\xywarnifdefined\addAT@ +\xywarnifdefined\addHASH@ +\xywarnifdefined\addDOLL@ +\xywarnifdefined\addAND@ +\xywarnifdefined\addRQ@ +\xywarnifdefined\addPLUS@ +\xywarnifdefined\addDASH@ +\xywarnifdefined\addDOT@ +\xywarnifdefined\addLT@ +\xywarnifdefined\addEQ@ +\xywarnifdefined\addGT@ +\xywarnifdefined\addLQ@ + +\xydef@\xymakeADD@#1#2 #3 {\ifnum\catcode#3=6 \def#1##1{##1#2#2}% + \else \def#1##1{##1#2}\fi} + +\xydef@\xyrecat@{\xymakeADD@\addAT@} +\xydef@\xyrecat{\xyrecat@} +\xydef@\xyresetcatcodes{\def\xyrecat{\xyrecat@}\xyreuncatcodes + \input xyrecat \relax \xyuncatcodes} + +\xyuncatcodes \xyresetcatcodes \xycatcodes + +\xydef@\testAND@{{\aftergroup\ifx + \addAND@\ifx\next\addFalse@\else\addTrue@\fi}} +\xydef@\addFalse@{\aftergroup\iffalse} +\xydef@\addTrue@{\aftergroup\iftrue} +\DOCMODE) + +\inputdoc!{xyrecat.doc} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The last block of the \Xy-pic header bootstraps the ``??c![DOCMODE] + format'' used in |.doc| variants of \Xy-pic macro files in order to + keep documentation and macros together in a literal programming style + (this is redundant in the |xy.tex| macro file where all instances of + |DOCMODE| have been eliminated (see chapter \S??g[:Makefile] for how + this is accomplished) but it is included anyway since users may load + options still in |DOCMODE| format). The details of |DOCMODE| are + described in |xydoc.sty|, a special \LaTeX\ package used to typeset + \Xy-pic documentation; please read it if you intend to write \Xy-pic + options. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Integration with standard formats} +??w[formats] +% + This is handled by the |xyidioms.tex| file and the integration as a + \LaTeX~\cite{L94:LaTeX} package by |xy.sty|. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + We input |xyidioms.tex| from the kernel: + +\DOCMODE( +\input xyidioms +\DOCMODE) + +\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\paragraph*{xyidioms.tex:} +??c[xyidioms.tex]% +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\paragraph*{xyidioms.doc:} +??c[xyidioms.doc]% +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\inputdoc!{xyidioms.doc} + +\paragraph{xy.sty:} +??c[xy.sty]% +%% + If you use ??w![\LaTeX] then this file makes it possible to + load??w[loading] \Xy-pic as a `??w![package]' using the + ??w![\LaTeXe]~\cite{L94:LaTeX} ??c![\usepackage] command: +% +\begin{defs1} +??c![\usepackage] |[|<option>|,|\dots|]| |{xy}| +\end{defs1} +\noindent\unskip +% + where the <option>s will be interpreted as if passed to + ??c![\xyoption] (\cf~\S??[option]). + + The only exceptions to this are the options having the same names as + those driver package options of \GROUP~??g[:drivers], which appear in + \cf~\cite[table 11.2, p.317]{GMS94:LaTeXC} or the \LaTeXe\ |graphics| + bundle. These will automatically invoke any backend extension + required to best emulate the \LaTeXe\ behaviour. (This means that, + \eg, ??C![dvips] and ??C![textures] can be used as options to the + ??c![\documentclass] command, with the normal effect.) + + The file also works as a \LaTeX~2.09~\cite{L86:LaTeX} `??w![style + option]' although you will then have to load options with the + |\xyoption| mechanism described in \S??[option]. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Here is the raw source of |xy.sty|. + +\inputdoc0{xy.sty} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Logo, version, and messages} +??=[env.logo] + + Loading \Xy-pic prints a ??w![banner] containing the version and + author of the kernel; small progress ??w![messages] are printed when + each major division of the kernel has been loaded. Any options + loaded will announce themself in a similar fashion. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Of these, ??c![\stripRCS] is a very useful hack for extracting the + first component of an RCS |$|\dots|$| keyword value. + +\DOCMODE( +\xydef@\stripRCS$#1${\stripRCS@#1: @@ @@@} +\xydef@\stripRCS@#1: #2@ #3@@@{% + \ifx @#2\string?\else\ifx :#2\else\stripRCS@@#2\fi\fi} +\xydef@\stripRCS@@#1 #2: @{#1} + +\edef\next{\stripRCS$Revision: 3.7 $} +\xylet@\xyversion=\next + +\edef\next{\stripRCS$Date: 1999/02/16 15:12:50 $} +\xylet@\xydate=\next + +\xydef@\Xygreet@{% + \W@{}% + \W@{ Xy-pic version \xyversion\space<\xydate>}% + \W@{ Copyright (c) 1991-1998 by Kristoffer H. Rose <krisrose@ens-lyon.fr>}% + \W@{ Xy-pic is free software: see the User\string's Guide for details.}% + \W@{}} +\Xygreet@ +\expandafter\everyjob\expandafter{\the\everyjob\Xygreet@} + +\message{Loading kernel:} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + If you refer to \Xy-pic in your written text (please do~\smiley~) + then you can use the command ??c![\Xy]|-pic| to typeset the + ``??w![\Xy-pic]'' ??w![logo]. The ??w![version] of the kernel is + typeset by ??c![\xyversion] and the release date by ??c![\xydate] (as + found in the banner). By the way, the \Xy-pic "name"\footnote{No + description of a \TeX\ program is complete without an explanation of + its name.} originates from the fact that the first version was + little more than support for $(x,y)$ coordinates in a configurable + coordinate system where the main idea was that "all" operations could + be specified in a manner independent of the orientation of the + coordinates. This property has been maintained except that now the + package allows explicit absolute orientation as well. + +\DOCMODE( +\xydef@\Xy{\leavevmode + \hbox{\kern-.1em X\kern-.3em\lower.4ex\hbox{Y\kern-.15em}}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Messages that start with ``|Xy-pic| ??c![Warning]'' are indications + that something needs your attention; an ``|Xy-pic| ??c![Error]'' will + stop \TeX\ because \Xy-pic does not know how to proceed. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + We use the input line number if available and rudimentary help in the + form of a reference to the manual if no specific help string is + given. ??c![\newlinechar] is set locally to |^^J| while writing such + that messages of several lines can be written. + +\DOCMODE( +\message{messages;} + +\xywarnifdefined\thelineno@ +\ifx\inputlineno\undefined \edef\thelineno@{\string?} +\else \def\thelineno@{\the\inputlineno}\fi +\xydef@\xytracelineno@{ \string[\jobname:\thelineno@\string]} + +\xydef@\xywarning@#1{{\newlinechar=10 % + \W@{}\W@{Xy-pic Warning: #1\xytracelineno@.}\W@{}}} + +\xydef@\xyerror@#1#2{\if\inxy@\xy@{ERROR #1}{}\fi + {\def\2{#2}\newlinechar=10 % + \ifx\2\empty \errhelp{See the Xy-pic manual for further information.}% + \else \errhelp{#2}\fi + \errmessage{Xy-pic error: #1}}} +\DOCMODE) + + Finally one that I hope will never get expanded~\frowny + +\DOCMODE( +\xydef@\xybug@#1{{\newlinechar=10 % + \errhelp{This is a bug in Xy-pic and should not happen!^^J% +If it did then please send a bug report with the offending Xy-pic code^^J% +to the author of Xy-pic, krisrose@ens-lyon.fr.}% + \errmessage{Xy-pic BUG: #1 -- notify krisrose@ens-lyon.fr.}}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Fonts} +??=[env.fonts] + + The \Xy-pic kernel implementation makes its drawings using five + specially designed ??w![fonts]:% +% +??w[dashes]??w[tips]??w[circles]??w[hooks]??w[squiggles] +$$ +\begin{array}{\otherbar c\otherbar c\otherbar l\otherbar} +\hline + \hbox{Font} & \hbox{Characters} & \hbox{Default}\\ +\hline + ??c![\xydashfont]& \hbox{dashes} & ??c![xydash10]\\ + ??c![\xyatipfont]& \hbox{arrow tips, upper half} & ??c![xyatip10]\\ + ??c![\xybtipfont]& \hbox{arrow tips, lower half} & ??c![xybtip10]\\ + ??c![\xybsqlfont]& \hbox{quarter circles for\qquad} & ??c![xybsql10]\\ + & \hbox{\qquad hooks and squiggles} &\\ + ??c![\xycircfont]& \hbox{$1/8$ circle segments} & ??c![xycirc10]\\ +\hline +\end{array} +$$ + The first four contain variations of characters in a large number of + directions, the last contains 1/8 circle segments. + +\paragraph*{Note:} + The default fonts are not part of the \Xy-pic kernel "specification": + they just set a standard for what drawing capabilities should at + least be required by an \Xy-pic implementation. Implementations + exploiting capabilitites of particular output devices are in use. + Hence the fonts are only loaded by \Xy-pic if the control sequence + names are undefined---this is used to preload them at different sizes + or prevent them from being loaded at all. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + To be more precise, \Xy-pic requires ??c![\xydashfont] to be a + "??w![semidirectional]" font as \MF\ will generate with the driver + file ??c![xyd2.mf]---this is very important because the "??w![italic + corrections]" of the characters in this particular font are used to + approximate trigonometric computations, so if you replace + ??c![\xydashfont] be sure to replace it with another semidirectional + font! Similarly, the three fonts ??c![\xyatipfont], + ??c![\xybtipfont], and ??c![\xybsqlfont] should be + "??w![directional]" as \MF\ will generate with the driver file + ??c![xyd.mf]. + + Finally, ??c![\xycircfont] should contain $1/8$ circle segments of + various radii as described in |xycirc10.mf|. + + The following code loads the fonts "unless it was already loaded" and + defines some associated dimensions for ??c![\xydashfont] and + ??c![\xybsqlfont]: for each of these $f$ we define $f_\ell$ as the + length of a unit in the current direction (used when juxtaposing for + connections), $f_h$ as the height of the unit (used for several + parallel connections), and $f_w$ as the `line width' of the unit (to + know how to interface to rules). + +\DOCMODE( +\message{fonts;} + +\xydef@\xyfont@#1{\ifx#1\undefined \DN@{\global\font#1}\expandafter\next@ + \else \xywarning@{Using previously loaded \string#1\space font}\fi} + +\xyfont@\xydashfont=xydash10 +\xydef@\xydashl@{\fontdimen6\xydashfont} +\xydef@\xydashh@{\fontdimen5\xydashfont} +\xydef@\xydashw@{\fontdimen8\xydashfont} + +\xyfont@\xyatipfont=xyatip10 +\xyfont@\xybtipfont=xybtip10 + +\xyfont@\xybsqlfont=xybsql10 +\xydef@\xybsqll@{\fontdimen6\xybsqlfont} +\xydef@\xybsqlh@{\fontdimen5\xybsqlfont} +\xydef@\xybsqlw@{\fontdimen8\xybsqlfont} + +\xyfont@\xycircfont=xycirc10 +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Allocations} +??=[env.alloc]??w[allocation] + + One final thing that you must be aware of is that \Xy-pic allocates a + significant number of dimension registers and some counters, token + registers, and box registers, in order to represent the state and do + computations. The current kernel allocates 4~counters, + 28~dimensions, 2~box registers,4~token registers, 1~read channel, and + 1~write channel (when running under \LaTeX; some other formats use + slightly more because standard generic temporaries are used). + Options may allocate further registers (currently loading + "everything" loads 6~dimen-, 3~toks-, 1~box-, and 9~count-registers + in addition to the kernel ones). + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\DOCMODE( +\message{allocations:} +\DOCMODE) + + See \S??[env.loading] for scratch register allocations. + +\paragraph*{Picture state:} + + These realise the picture state as described in \S??[basics.state]: + $c$, $p$, the "base", and the picture size: + +\DOCMODE( +\message{state,} + +\xynew@{dimen}\X@c +\xynew@{dimen}\Y@c +\xynew@{dimen}\U@c +\xynew@{dimen}\D@c +\xynew@{dimen}\L@c +\xynew@{dimen}\R@c +\xynew@{toks}\Edge@c + +\xynew@{dimen}\X@p +\xynew@{dimen}\Y@p +\xynew@{dimen}\U@p +\xynew@{dimen}\D@p +\xynew@{dimen}\L@p +\xynew@{dimen}\R@p +\xynew@{toks}\Edge@p + +\xynew@{dimen}\X@origin \X@origin=\z@ +\xynew@{dimen}\Y@origin \X@origin=\z@ +\xynew@{dimen}\X@xbase \X@xbase=1mm +\xynew@{dimen}\Y@xbase \Y@xbase=\z@ +\xynew@{dimen}\X@ybase \X@ybase=\z@ +\xynew@{dimen}\Y@ybase \Y@ybase=1mm + +\xynew@{dimen}\X@min +\xynew@{dimen}\Y@min +\xynew@{dimen}\X@max +\xynew@{dimen}\Y@max +\DOCMODE) + +\paragraph*{Drop and connect:} + + |\lastobjectbox@| stores the most recently dropped + object.??c[\lastobject] + +\DOCMODE( +\xynew@{box}\lastobjectbox@ +\DOCMODE) + + |\zerodotbox@|??c[\zerodot] is of zero size with a `dot' in the form + of a rule the width and height as the line width of the line font; + ??c![\zz@] is `almost-zero-check'. + +\DOCMODE( +\xynew@{box}\zerodotbox@ +\setbox\zerodotbox@=\hbox{\dimen@=.5\xydashw@ + \kern-\dimen@ \vrule width\xydashw@ height\dimen@ depth\dimen@} +\wd\zerodotbox@=\z@ \ht\zerodotbox@=\z@ \dp\zerodotbox@=\z@ + +\xynew@{dimen}\almostz@ \almostz@=50sp +\xydef@\zz@#1{\ifdim#1<\z@-\fi#1<\almostz@\relax} + +\xynew@{if}\iftmp@ +\DOCMODE) + +\paragraph*{Direction state:} + + The ??w![direction] state is rather complicated and described in + detail in~\S??[algo.direction]. + +\DOCMODE( +\message{direction,} + +\xynew@{dimen}\d@X +\xynew@{dimen}\d@Y +\xydef@\sd@X{} +\xydef@\sd@Y{} + +\xynew@{count}\K@ \K@=1024 +\xynew@{count}\KK@ \KK@=32 + +\xynew@{count}\Direction +\xynew@{dimen}\K@dXdY +\xynew@{dimen}\K@dYdX + +\xydef@\cosDirection{} +\xydef@\sinDirection{} + +\xywarnifdefined\DirectionChar +\xywarnifdefined\SemiDirectionChar +\DOCMODE) + +\paragraph*{Miscellaneous:} + + Finally some generic allocations used in the following: + +\DOCMODE( +\xynew@{read}\xyread@ % for `safe input' +\xynew@{write}\xywrite@ % for `saving' to .xyc file + +\xynew@{count}\csp@ % for `control stack pointer' +\xynew@{dimen}\quotPTK@ % for `fractions' +\DOCMODE) + + The required temporaries are defined by |xyidioms.tex|. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Utility macros} +??=[env.util] + + Finally we define some utility macros. + +\DOCMODE( +\message{utility macros;} +\DOCMODE) + +\paragraph*{Simple queue:} +??w[queue] + + Just appending to the ??c![\toks@] list. + +\DOCMODE( +\xydef@\addtotoks@#1{\toks@=\expandafter{\the\toks@#1}} +\DOCMODE) + +\paragraph*{Safe input:} + + Check that file is available before input. Tries the alternate + extension |.doc| in case the |.tex| file is not there. The second is + the lowest level function used when the desired files cannot be + preloaded and do not exist in |.doc| form. + +\DOCMODE( +\xydef@\xyinputorelse@#1#2{% + \expandafter\let\expandafter\next@\csname#1loaded\endcsname + \ifx\next@\empty \else + \DN@{\xyinputorelse@@{#1}{\xyinputorelse@@{#1.doc}{#2}}}% + \fi \next@} + +\xydef@\xyinputorelse@@#1#2{\openin\xyread@=#1 % + \ifeof\xyread@ \DN@{#2}\else \DN@{\closein\xyread@\input#1 }\fi \next@} +\DOCMODE) + +\paragraph*{Continuation stack:} + + This is used to `??w![enter]' a new ??w![context] and `??w![leave]' + to the previous context. It works as a stack defining a control + sequence for each level, thus using a counter as the stack pointer. + Defines the following +% +\begin{defs} + |\csp@| & `Continuation Stack Pointer' \cr + |\enter@{|<code>|}| & Enter new block with <code> expanded as continuation\cr + |\nter@{|<code>|}| & Enter new block with<code> as continuation\cr + |\dontleave@| & Execute continuation without leaving block\cr + |\unenter@| & Leave block without executing its continuation\cr + |\leave@| & Leave block (execute its continuation)\cr +\end{defs} + + So |\enter@{}\leave@| is a noop and |\leave@| is the same as + |\dontleave@\unenter@|. + +\DOCMODE( +\global\csp@=\z@ + +\xydef@\enter@#1{\global\advance\csp@\@ne + \expandafter\xdef\csname cs@\number\csp@\endcsname{#1}\ignorespaces} + +\xydef@\nter@#1{\global\advance\csp@\@ne + \expandafter\gdef\csname cs@\number\csp@\endcsname{#1}\ignorespaces} + +\xydef@\dontleave@{\csname cs@\number\csp@\endcsname} + +\xydef@\unenter@{\global\advance\csp@\m@ne} + +\xydef@\leave@{\expandafter\unenter@\csname cs@\number\csp@\endcsname} +\DOCMODE) + +\paragraph*{Fractions:} +??w[fraction computation] + + Below we often use a factor on the form of a quotient $A/B$. Here is + a hack to get it; it is not very precise but suffices for our needs. +% +\begin{defs} + |\quotient@| <cs> |{|$A$|}| |{|$B$|}| & + Defines <cs> to expand (immediately) to the factor corresponding to + $A/B$; $A$, $B$ must be dimensions where $\abs{A}\lt|\maxdimen|/|KK|$ + and $\abs{B}\gt|KK|$ +\cr + |\quotient@@| <cs> |{|$A$|}| |{|$B$|}| & + Same, but uses $8|KK|$ for |KK|. +\cr +\end{defs} +% + "Notes": (1) If |\c| is a count register, then |{1\c}| is a legal + dimension. (2) Really computes +$$ + \left((A*\abs{|KK|}) / (B/\abs{|KK|})\right) * \left(|1pt|/\abs{|K|}\right) +$$ + and then defines <cs> to expand to the resulting |pt| value. This + means that results are only reasonable for + $\abs{A}\ll|\maxdimen|/|KK|$ and $\abs{B}\gg|KK|$. + +\DOCMODE( +\quotPTK@=\p@ \divide\quotPTK@\K@ +\xylet@\quotsign@@=\empty +\xywarnifdefined\removePT@ +{\catcode`p=12 \catcode`t=12 \gdef\removePT@#1pt{#1}} + +\xydef@\quotient@#1#2#3{\A@=#2\relax \B@=#3\relax + \ifdim\A@<\z@\def\quotsign@@{-}\else\def\quotsign@@{+}\fi + \ifdim\quotsign@@\A@<15pt \multiply\A@\K@ + \else\ifdim\quotsign@@\A@<511pt \multiply\A@\KK@ + \advance\B@\ifdim\B@<\z@-\fi 16sp \divide\B@\KK@ + \else + \advance\B@\ifdim\B@<\z@-\fi 512sp \divide\B@\K@ + \fi\fi + \ifdim\ifdim\B@<\z@-\fi\B@<\quotPTK@ \xywarning@{division overflow}% + \else \advance\A@.5\B@ \divide\A@\B@ \fi + \multiply\A@\quotPTK@ \edef#1{\expandafter\removePT@\the\A@}} + +\xydef@\quotient@@#1#2#3{\A@=#2\relax \B@=#3\relax \multiply\A@\KK@ + \advance\B@\ifdim\B@<\z@-\fi 128sp \divide\B@\KK@ \divide\B@ 8 % + \ifdim\B@=\z@\else \advance\A@.5\B@ \divide\A@\B@ \fi + \B@=.125\quotPTK@ \multiply\A@\B@ \edef#1{\expandafter\removePT@\the\A@}} +\DOCMODE) + +\paragraph*{Loops:} + + \Xy-pic uses its own |\loop@| to avoid interference with plain + ??c![\loop]. + +\DOCMODE( +\xydef@\loop@#1\repeat@{\def\body@{#1}\iterate@}\xylet@\repeat@=\fi +\xydef@\iterate@{\body@\expandafter\iterate@\else\fi} +\DOCMODE) + +\paragraph*{Execution:} + + All ??w![execution] of \Xy-commands should be `indirect', \ie, + execute +$$ + |\xy@{|<source>|}{|<internal commands>|}| +$$ + where the <internal commands> directly do the desired operation(s). + This is used for tracing and can be used to separate parsing and + execution by changing |\xy@|; |\oxy@| is kept stable such that + |\let\xy@=\oxy@| will reestablish a sane state; it should only be + changed with |\change@oxy@| to make this easy to verify. + +\DOCMODE( +\xydef@\xyinitial@#1#2{\DN@{#1}% + \xyerror@{command used out of context: \codeof\next@}{}} + +\xylet@\xy@=\xyinitial@ +\xylet@\oxy@=\xy@ + +\xydef@\change@oxy@#1{\let\oxy@=#1\relax +% \W@{*OXY@:=\meaning\oxy@}% +} +\DOCMODE) + + This is also used to check whether an \Xy-picture is already + active; use as |\if\inxy@|\dots|\else|\dots|\fi|: + +\DOCMODE( +\xydef@\inxy@{T\ifx\xy@\xyinitial@ F\else T\fi} +\DOCMODE) + + The final execution command is a trick used to put bits of the user's + input inside the |\next@| scratch macro "with the user's catcodes + intact": |\xy@@ix@{|\dots|}| is the same as + |\xy@@{\global\toks9={|\dots|}}| except for the category codes used + for the \dots. + +\DOCMODE( +\xydef@\xyxy@@ix@{\begingroup + \xyuncatcodes\afterassignment\endgroup\global\toks9=} +\DOCMODE) + + This to save some tokens -- maybe not worth it: + +\DOCMODE( +\xydef@\xy@@{\xy@{}} +\DOCMODE) + + Finally this to establish a sane state -- only use within a group! + +\DOCMODE( +\xydef@\plainxy@{\let\xy@=\xyxy@ \change@oxy@\xy@ \let\xy@@ix@=\xyxy@@ix@} +\DOCMODE) + + \TODO: Clean up all uses of these such that <source> is always that + and only that. Define a method for `inner' \aka\ `implied' <source> + that doesn't really count in that it is a consequence of some other + source\dots + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Picture basics} +??=[basics] + + The basic concepts involved when constructing \Xy-pictures are + positions and objects, and how they combine to form the state used by + the graphic engine. + + The general structure of an \Xy-picture is as follows: +% +\begin{defs1} +% + ??c![\xy] <pos> <decor> ??c![\endxy] \cr +% +\end{defs1} +\noindent\unskip +% + builds a box with an \Xy-picture (\LaTeX\ users may substitute + |\begin{xy}| \dots\ |\end{xy}| if they prefer). + + <pos> and <decor> are components of the special `graphic language' + which \Xy-pictures are specified in. We explain the language + components in general terms in this \S\ and in more depth in the + following \S\S. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The code for the |\xy|\dots|\endxy| command is presented last in this + section. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Positions} +??=[basics.pos] + + All "??w![positions]" may be written |<|$X$|,|$Y$|>| where ??w![$X$] + is the \TeX\ dimension distance "right" and ??w![$Y$] the distance + "up" from the "??w![zero position]" ??c![0] of the \Xy-picture (|0| + has coordinates |<0mm,0mm>|, of course). The zero position of the + \Xy-picture determines the box produced by the + ??c![\xy]\dots??c![\endxy] command together with the four parameters + ??w![$X_{\min}$], ??w![$X_{\max}$], ??w![$Y_{\min}$], and + ??w![$Y_{\max}$] set such that all the objects in the picture are + `contained' in the following rectangle: +$$ +\xy.(-13,-12).(25,15)="b"*\frm{-}*@{o}, + "b"+<2pc,-.8pc>*{|0|};"b"*{}**@{.}, + "b"+L+<-2pc,-.8pc>*!UR\txt{\TeX\ reference point};"b"+L*@{*}**@{.}, + "b"+0; + "b"+L **@{-} ?>*@{>} ?*++!U{X_{\min}}, + "b"+R **@{-} ?>*@{>} ?(.7)*++!U{X_{\max}}, + "b"+D **@{-} ?>*@{>} ?(.7)*++!L{Y_{\min}}, + "b"+U **@{-} ?>*@{>} ?*++!L{Y_{\max}} +\endxy +$$ + where the distances follow the ``up and right~$\gt0$'' principle, + \eg, the indicated \TeX\ reference point has coordinates + |<|$X_{\min}$|,0pt>| within the \Xy-picture. The zero position does + not have to be contained in the picture, but $X_{\min} \le X_{\max} + \land Y_{\min} \le Y_{\max}$ always holds. The possible positions + are described in detail in~\S??[pos]. + + When an \Xy-picture is entered in "??w![math mode]" then the + reference point becomes the ``vcenter'' instead, \ie, we use the + point |<|$X_{\min}$|,-\the\fontdimen22>| as reference point. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Objects} +??=[basics.object] + + The simplest form of putting things into the picture is to `drop' an + "??w![object]" at a position. An object is like a \TeX\ box except + that it has a general "??w![Edge]" around its reference point---in + particular this has the "??w![extents]" (\ie, it is always contained + within) the dimensions ??w![$L$], ??w![$R$], ??w![$U$], and ??w![$D$] + away from the reference point in each of the four directions left, + right, up, and down. Objects are encoded in \TeX\ boxes using the + convention that the ??w![\TeX\ reference point] of an object is at + its left edge, thus shifted |<|${-}L$|,0pt>| from the center---so a + \TeX\ box may be said to be a rectangular object with $L=|0pt|$. + Here is an example: +$$ + \let\objectstyle=\scriptstyle + \xy(0,0).(-10,-5).(15,8)*\frm{-}="box"*@{o}+0; + "box"+L*{}**@{.}?*{L}, + "box"+R*{}**@{.}?*{R}, + "box"+D*{}**@{.}?*{D}, + "box"+U*{}**@{.}?*{U}, + "box"+L+<-2pc,-.8pc>*!UR\hbox{\TeX\ reference point}; + "box"+L*{\bullet}*{}**@{.}, + \endxy +$$ + The object shown has a rectangle edge but others are available even + though the kernel only supports rectangle and circle edges. It is + also possible to use entire \Xy-pictures as objects with a rectangle + edge, |0| as the reference point, $L={-X_{\min}}$, $R={X_{\max}}$, + $D={-Y_{\min}}$, and $U={Y_{\max}}$. The commands for objects are + described in~\S??[object]. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Connections} +??=[basics.connect] + + Besides having the ability to be dropped at a position in a picture, + all objects may be used to "??w![connect]" the two current objects of + the state, \ie, $p$ and $c$. For most objects this is done by + `filling' the straight line between the centers with as many copies + as will fit between the objects: +$$ + \let\objectstyle=\scriptscriptstyle + \xy*=<12pt>[o]{p}="P"*\cir{} ; (60,15)*=<18pt,8pt>{c}="C"*\frm{-}**@{--} +% + **\xybox{(0,0).(-3,-2).(2,3)*\frm{.}="box"*@{o}+0; + "box"+L**@{.}?*{L}, + "box"+R**@{.}?*{R}, + "box"+D**@{.}?*{D}, + "box"+U**@{.}?*{U}}, + \endxy +$$ + The ways the various objects connect are described along with the + objects. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Decorations} +??=[basics.decor] + + When the ??c![\xy] command reaches something that can not be + interpreted as a continuation of the position being read, then it is + expected to be a "??w![decoration]", \ie, in a restricted set of + \TeX\ commands which add to pictures. Most such commands are + provided by the various "user options" (\cf~\S??[option])---only a + few are provided within the kernel to facilitate programming of such + options (and user macros) as described in~\S??[decor]. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{The \Xy-pic state} +??=[basics.state] + + Finally we summarise the user-accessible parts of the + ??w![\Xy-picture state] of two positions together with the + last object associated with each: the "previous", ??w![$p$], is the + position |<|??w![$X_p$]|,| ??w![$Y_p$]|>| with the object + ??w![$L_p$], ??w![$R_p$], ??w![$D_p$], ??w![$U_p$], ??w!["Edge$_p$"], + and the "current", ??w![$c$], is the position |<|??w![$X_c$]|,| + ??w![$Y_c$]|>| with the object ??w![$L_c$], ??w![$R_c$], ??w![$D_c$], + ??w![$U_c$], ??w!["Edge$_c$"]. + + Furthermore, \Xy-pic has a configurable "??w![cartesian coordinate + system]" described by an "origin" position + |<|??w![$X_"origin"$]|,|??w![$Y_"origin"$]|>| + and two "base vectors" |<|??w![$X_"xbase"$]|,|??w![$Y_"xbase"$]|>| + and~|<|??w![$X_"ybase"$]|,|??w![$Y_"ybase"$]|>| + accessed by the usual notation using parentheses: +$$ +\arraycolsep=.25em \begin{array}{rclll} + |(|x|,|y|)| & = & |<| & X_"origin" + x*X_"xbase" + y*X_"ybase" & |,| \\ + & & & Y_"origin" + x*Y_"xbase" + y*Y_"ybase" & |>| \\ +\end{array} +$$ + This is explained in full when we show how to set the base in + note~??[base] of \S??[pos]. + + Finally typesetting a connection will setup a ``??w![placement + state]'' for referring to positions on the connection that is + accessed through a special |?| position construction; this is also + discussed in detail in \S??[pos]. + + The \Xy-pic "??w![state]" consists of all these parameters + together. They are initialised to zero except for + $X_"xbase"=Y_"ybase"=|1mm|$. + +\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + The edges are not directly available but points on the edges may be + found using the different <corner> forms described in \S??[pos]. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + The edges are are available to the programmer as token lists; see + \S??[algo.edge] for details. + +\subparagraph*{Procedure:} + + ??c![\xy]\ \dots\ ??c![\endxy] builds an object from an \Xy-pic <pos> + <decor> sequence as follows: (??_[xy1])~|\xy| starts the |\hbox| to + contain the \Xy-picture, (??_[xy2])~starts an inner box to be resized + appropriately later, sets |\xy@| to just execute immediately, and + makes a fresh scope for global internal names, and + (??_[xy3])~initialises the \Xy-pic state (setting the size to a + ridiculously large negative value), and finally passes control to + the <pos> parser. + + Some care is taken to `lift' the diagram a bit to `vcenter' it when + in math mode, and ??c![\mathsurround] is set to zero to make changes + into math mode safe. + +\DOCMODE( +\message{pictures: \string\xy,} + +\xydef@\xy{\ifmmode\expandafter\xymath@\else\expandafter\xynomath@\fi} +\xydef@\xymath@{\hbox\bgroup \dimen@=\the\fontdimen22\textfont\tw@ \xyinside@} +\xydef@\xynomath@{\hbox\bgroup \dimen@=\z@ \xyinside@} + +\xydef@\xyinside@{% + \saveXyStyle@ \aftergroup\xycheck@end %?*[xy1] + \setboxz@h\bgroup %?*[xy2] + \plainxy@ + \X@c=\z@ \Y@c=\z@ \czeroEdge@ %?*[xy3] + \X@p=\z@ \Y@p=\z@ \U@p=\z@ \D@p=\z@ \L@p=\z@ \R@p=\z@ \Edge@p={\zeroEdge}% + \X@min=\hsize \X@max=-\hsize \Y@min=\hsize \Y@max=-\hsize + \mathsurround=\z@ + \expandafter\POS\everyxy@@} + +\xydef@\czeroEdge@{\U@c=\z@ \D@c=\U@c \L@c=\U@c \R@c=\U@c \Edge@c={\zeroEdge}} + +\xydef@\xyxy@#1#2{#2} + +\xywarnifdefined\everyxy +\expandafter\def\addEQ@\everyxy#1{\def\everyxy@@{#1}\ignorespaces} + +\xylet@\everyxy@@=\empty +\DOCMODE) + + When finished |\endxy| does a |\relax| to disable any parser still + active and (??_[endxy1])~resets the size of the generated box to zero + if no (unhidden) objects were inserted, and (??_[endxy2])~defines a + command to end both the temporary and the `proper' box and set its + size correctly---this uses ??c![\edef] to expand the required + dimensions used within the temporary box before leaving the two + groups (namely the temporary box and the `proper' box). + +\DOCMODE( +\xydef@\endxy{\if\inxy@\else\xyerror@{Unexpected \string\endxy}{}\fi + \relax + \dimen@=\Y@max \advance\dimen@-\Y@min %?*[endxy1] + \ifdim\dimen@<\z@ \dimen@=\z@ \Y@min=\z@ \Y@max=\z@ \fi + \dimen@=\X@max \advance\dimen@-\X@min + \ifdim\dimen@<\z@ \dimen@=\z@ \X@min=\z@ \X@max=\z@ \fi + \edef\tmp@{\egroup %?*[endxy2] + \setboxz@h{\kern-\the\X@min\boxz@}% + \ht\z@=\the\Y@max \dp\z@=-\the\Y@min \wdz@=\the\dimen@ + \noexpand\maybeunraise@ \raise\dimen@\boxz@ + \noexpand\recoverXyStyle@ \egroup \noexpand\xy@end + \U@c=\the\Y@max \D@c=-\the\Y@min \L@c=-\the\X@min \R@c=\the\X@max}\tmp@} + +\xydef@\maybeunraise@{\if\inxy@\else \dimen@ii=\dp\z@ + \ifdim\dimen@ii<\z@ \advance\dimen@\dimen@ii \fi\fi} +\DOCMODE) + + If an |\xy| is not properly closed by an |\endxy| then the error + message is produced. This happens if (a)~too many |\xy|s or (b)~too + many |\endxy|s or (c)~if there is the correct number of each but the + grouping becomes unbalanced due to a misplaced |}| or |\egroup|. + +\DOCMODE( +\xydef@\xycheck@end{\xyFN@\xycheck@end@} +\xydef@\xycheck@end@{\ifx\next\xy@end\DN@\xy@end{}\else\DN@{\xy@end}\fi\next@} +\xydef@\xy@end{% + \xyerror@{An \string\xy\space environment is not closed correctly.}% + {I expected \string\endxy. You probably have an umatched {} grouping.}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + It is possible to insert an `initial' piece of <pos> <decor> at the + start of every \Xy-picture with the declaration +% +\begin{defs1} +|\everyxy={| <text> |}| +\end{defs1} +\noindent\unskip +% + This will act as if the <text> was typed literally right after each + ??c![\xy] command, parsing the actual contents as if it follows this + -- thus it is recommended that <text> has the form <pos>|,| such that + users can continue with <pos> <decor>. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Positions} +??=[pos] + +\DOCMODE( +\message{positions,} +\DOCMODE) + + A <pos>ition is a way of specifying locations as well as dropping + objects at them and decorating them---in fact any aspect of the + \Xy-pic state can be changed by a <pos> but most will just change the + coordinates and/or shape of~$c$. + +\begin{figure*}[tp]\SQUEEZE +\vss +\begin{syntax} + ??w![<pos>] + &\iss & <coord> + & $c\from<coord>$ +\cr + &\orr & <pos> ??c![+] <coord> + & $c \from <pos> + <coord>$??^[arithmetic] +\cr + &\orr & <pos> ??c![-] <coord> + & $c \from <pos> - <coord>$??^[arithmetic] +\cr + &\orr & <pos> ??c![!] <coord> + & $c\from<pos>$ then ??!^[skew] $c$ by <coord> +\cr + &\orr & <pos> ??c![.] <coord> + & $c\from<pos>$ but also ??!^[covering] $<coord>$ +\cr + &\orr & <pos> ??c![,] <coord> + & $c\from<pos>$ then $c\from<coord>$ +\cr + &\orr & <pos> ??c![;] <coord> + & $c\from<pos>$, swap $p$ and $c$, $c\from<coord>$ +\cr + &\orr & <pos> ??c![:] <coord> + & $c\from<pos>$, set ??!^[base], $c\from<coord>$ +\cr + &\orr & <pos> ??c![::] <coord> + & $c\from<pos>$, $"ybase"\from c-"origin"$, $c\from<coord>$ +\cr + &\orr & <pos> ??c![*] <object> + & $c\from<pos>$, ??!^[drop] <object> +\cr + &\orr & <pos> ??c![**] <object> + & $c\from<pos>$, ??!^[connect] using <object> +\cr + &\orr & <pos> ??c![?] <place> + & $c\from<pos>$, $c\from\hbox{??!^[<place>]}$ +\cr + &\orr & <pos> ??c![@] <stacking> + & $c\from<pos>$, do <stacking>??^[stack] +\cr + &\orr & <pos> ??c![=] <saving> + & $c\from<pos>$, do <saving>??^[save] +\cr +\noalign{\smallbreak} +% + ??w![<coord>] + &\iss & <vector> + & <pos> is <vector> with zero size +\cr + &\orr & <empty> \orr\ ??c![c] + & reuse last $c$ (do nothing) +\cr + &\orr & ??c![p] + & $p$ +\cr + &\orr & ??c![x] \orr\ ??c![y] + & ??!^[axis intersection] with $\overline{pc}$ +\cr + &\orr & ??c![s]<digit> \orr\ |s{|<number>|}| + & ??!^[stack] position <digit> or <number> below the top +\cr + &\orr & |"|<id>|"| + & restore what was ??!^[saved] as <id> earlier +\cr + &\orr & |{| <pos> <decor> |}| + & the $c$ resulting from interpreting the ??!^[group] +\cr +\noalign{\smallbreak} +% + ??w![<vector>] + &\iss & ??c![0] + & zero +\cr + &\orr & |<| <dimen> |,| <dimen> |>| + & absolute??c[<>] +\cr + &\orr & |<| <dimen> |>| + & absolute with equal dimensions +\cr + &\orr & |(| <factor> |,| <factor> |)| + & in current ??!^[base]??c[()] +\cr + &\orr & ??c![a] |(| <number> |)| + & ??!^[angle in current base] +\cr + &\orr & <corner> + & from reference point to <corner> of $c$ +\cr + &\orr & <corner> |(| <factor> |)| + & The <corner> multiplied with <factor> +\cr + &\orr & |/| <direction> <dimen> |/| + & vector <dimen> ??!^[in <direction>]??c[//] +\cr +\noalign{\smallbreak} +% + ??w![<corner>] + &\iss & ??c![L]\orr??c![R]\orr??c![D]\orr??c![U] + & ??!^[offset] to left, right, down, up side +\cr + &\orr & ??c![CL]\orr??c![CR]\orr??c![CD]\orr??c![CU]\orr??c![C] + & ??!^[offset] to center of side, true center +\cr + &\orr & ??c![LD]\orr??c![RD]\orr??c![LU]\orr??c![RU] + & ??!^[offset] to actual left/down, \dots\ corner +\cr + &\orr & ??c![E]\orr??c![P] + & ??!^[offset] to nearest/proportional edge point to $p$ +\cr +\noalign{\smallbreak} +% + ??w![<place>] + &\iss & ??c![<] <place> \orr\ ??c![>] <place> + & ??!^[shave] ??c![(0)]/??c![(1)] to edge of $p$/$c$, $f \from |0|/|1|$ +\cr + &\orr & |(| <factor> |)| <place> + & $f \from <factor>$ +\cr + &\orr & <slide> + & ??!^[pick place] and apply <slide> +\cr + &\orr & ??c![!] |{|<pos>|}| <slide> + & ??!^[intercept] with line setup by <pos> and apply <slide> +\cr +\noalign{\smallbreak} +% + ??w![<slide>] + &\iss & |/| <dimen> |/| + & ??!^[slide] <dimen> further along connection +\cr + &\orr & <empty> + & no slide +\cr +\end{syntax} +\unskip\vskip-1em +\caption{\protect<pos>itions.}??=[f.pos] +\vfill +\end{figure*} + + All possible positions are shown in figure~??[f.pos] with explanatory + notes below. + +\begin{exercise} + Which of the positions |0|, |<0pt,0pt>|, |<0pt>|, |(0,0)|, and + |/0pt/| is different from the others? +\answertext{In the default setup they are all denote the reference point of + the \Xy-picture but the cartesian coordinate <pos> ??c![(0,0)] + denotes the point "origo" that may be changed to something else using + the |:| operator.} +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Parsing:} + + First the ??c![\POS] and ??c![\afterPOS] <decor>ations, and similar + ??c![\afterCOORD] and ??c![\afterVECTORorEMPTY] ones. They handle + parsing of <pos>, <coord>, and <vector>; parsing of <corner> and + <place> is presented along with note~??[corner] and~??[<place>] + explaining them. + +\DOCMODE( +\xydef@\POS{\afterPOS{}} + +\xydef@\afterPOS#1{% + \DN@##1{\def\afterPOS@{\def\afterPOS@{##1}#1}}% + \expandafter\next@\expandafter{\afterPOS@}% + \afterCOORD{\xyFN@\POS@}} + +\xylet@\afterPOS@=\empty + +\xydef@\afterCOORD#1{% + \DN@##1{\def\afterCOORD@{\def\afterCOORD@{##1}#1}}% + \expandafter\next@\expandafter{\afterCOORD@}% + \afterVECTORorEMPTY{\xy@@\czeroEdge@ \afterCOORD@}{\xyFN@\COORD@}} + +\xylet@\afterCOORD@=\empty + +\xydef@\afterVECTORorEMPTY#1#2{% + \DN@##1{\def\afterVECTOR@{\def\afterVECTOR@{##1}% + \ifVECTORempty@\DN@{#2}\else\DN@{#1}\fi \next@}}% + \expandafter\next@\expandafter{\afterVECTOR@}% + \xyFN@\VECTOR@} + +\xynew@{if}\ifVECTORempty@ +\xylet@\afterVECTOR@=\empty +\DOCMODE) + + The ??c![\afterVECTORorEMPTY] command is special in that it takes two + arguments: the `continuation' if a <vector> was found and the + continuation if <empty> was found (this is not applicable to the + other two since <empty> is a legal <coord> and thus also a legal + <pos>). + + Next we proceed with the actual parsing primitives: |\COORD@|, + |\POS@|, and |\VECTOR@|. These are bound to |\xyCOORD@|, |\xyPOS@|, + and |\xyVECTOR@| in order to be extendable, \eg, the |matrix| option + extends <coord> to support the |[|"row"|,| "column"|]| format by + redefining |\COORD@| to first test for this new format and then call + |\xyCOORD@|. + + The parsing commands above are set up such that they all first call + the |\VECTOR@| command. <coord> and <pos> parsing then proceeds with + calling the |\COORD@| if there was no <vector>. <pos> parsing then + calls |\POS@| to continue the <pos> (in both cases). + + First <vector>s: + +\DOCMODE( +\xydef@\xyVECTOR@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\VECTOR@}%gobble spaces + \else \ifcat A\noexpand\next \let\next@=\VECTOR@letter + \else \let\next@=\VECTOR@other \fi\fi \next@} + +\xylet@\VECTOR@=\xyVECTOR@ +\DOCMODE) + + All letters used for <vector>s are uppercase <corner>s except for |a| + used for angles (where the main code is in note~??[angle in current + base]); this is also where we introduce the auxiliary + |\notrelaxorelse@| that takes two control sequences and expands the + first unless it is relax in which case it expands the second: + +\DOCMODE( +\def\notrelaxorelse@#1#2{\ifx#1\relax \expandafter#2\else\expandafter#1\fi} + +\xydef@\VECTOR@letter{% + \ifx a\next \expandafter\VECTOR@a \else \expandafter\CORNER@ \fi} + +\xydef@\VECTOR@a a(#1){\xy@{a(#1)}{\vfromcartesianangle@{#1}}% + \VECTORempty@false \afterVECTOR@} +\DOCMODE) + + The <corner> trick is to do nothing when there is nothing and + initialise both $X$ and $Y$ in all other cases. + +\DOCMODE( +\xydef@\CORNER@{% + \xy@{}{\A@=-.5\L@c \advance\A@.5\R@c \B@=-.5\D@c \advance\B@.5\U@c + \let\nextii@=\zeroit@}% + \VECTORempty@true\CORNER@i} + +\xydef@\zeroit@#1{#1=\z@} + +\xydef@\CORNER@i{% + \ifx D\next \DN@ D{\xy@{D}{\Y@c=-\D@c \nextii@\X@c \B@=\Y@c}\CORNER@ii}% + \else\ifx U\next \DN@ U{\xy@{U}{\Y@c= \U@c \nextii@\X@c \B@=\Y@c}\CORNER@ii}% + \else\ifx L\next \DN@ L{\xy@{L}{\X@c=-\L@c \nextii@\Y@c \A@=\X@c}\CORNER@ii}% + \else\ifx R\next \DN@ R{\xy@{R}{\X@c= \R@c \nextii@\Y@c \A@=\X@c}\CORNER@ii}% + \else\ifx C\next \DN@ C{\xy@{C}{\X@c= \A@ \Y@c= \B@}\CORNER@ii}% + \else\ifx E\next \DN@ E{\xy@{E}{% + \A@=\X@c \B@=\Y@c \the\Edge@c\z@ \advance\X@c-\A@ \advance\Y@c-\B@}% + \CORNER@ii}% + \else\ifx P\next \DN@ P{\xy@{P}{% + \A@=\X@c \B@=\Y@c \the\Edge@c\thr@@ \advance\X@c-\A@ \advance\Y@c-\B@}% + \CORNER@ii}% + \else\ifx (\next %) + \DN@(##1){\xy@{(##1)}{\X@c=##1\X@c \Y@c=##1\Y@c}\afterVECTOR@}% + \else \let\next@=\afterVECTOR@ + \fi\fi\fi\fi\fi\fi\fi\fi \next@} + +\xydef@\CORNER@ii{\xy@@{\let\nextii@=\eat@}% + \VECTORempty@false \xyFN@\CORNER@i} +\DOCMODE) + + |\CORNER@i| recognises the |(|<factor>|)| also; this does no harm as + it was never called if the first character was a |(|. + + The remaining <vector> forms just set $X$ and $Y$. + +\DOCMODE( +\xydef@\VECTOR@other{% + \addLT@\ifx \next + \addGT@{\addLT@\DN@##1}{\xy@{<##1>}{\vfromabsolute@{##1}}% + \VECTORempty@false\afterVECTOR@}% + \else\ifx (\next %) + \DN@({\xyFN@\VECTOR@other@open}%) + \else\ifx /\next %/ + \DN@/##1/{\xy@@ix@{{##1}}% + \xy@{/##1/}{\expandafter\vfromslide@\the\toks9 }% + \VECTORempty@false\afterVECTOR@}% + \else\ifx 0\next + \DN@ 0{\xy@{0}{\X@c=\z@ \Y@c=\z@}\VECTORempty@false\afterVECTOR@}% + \else + \DN@{\VECTORempty@true\afterVECTOR@}% + \fi\fi\fi\fi \next@} +\DOCMODE) + + \HACK: escape out in case of the special |(*| introducer\dots picked + up by the <coord> parser, then. + +\DOCMODE( +\xydef@\VECTOR@other@open{% + \ifx *\next \DN@{\VECTORempty@true \xyFN@\afterVECTOR@(}%) + \else + \DN@##1){\xy@{(##1)}{\vfromcartesian@{##1}}\VECTORempty@false\afterVECTOR@}% + \fi \next@} +\DOCMODE) + + Next <coord>inates that are not <vector>s: + +\DOCMODE( +\xydef@\xyCOORD@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\COORD@}%gobble spaces + \else \ifcat A\noexpand\next \let\next@=\xyCOORD@letter + \else \let\next@=\xyCOORD@other \fi\fi \next@} + +\xylet@\COORD@=\xyCOORD@ + +\xydef@\xyCOORD@letter{% + \ifx c\next + \DN@ c{\xy@{c}{}\afterCOORD@}% + \else\ifx p\next + \DN@ p{\xy@{p}\cfromp@ \afterCOORD@}% + \else\ifx x\next + \DN@ x{\xy@{x}{\R@c=\X@xbase \U@c=\Y@xbase \intersect@}\afterCOORD@}% + \else\ifx y\next + \DN@ y{\xy@{y}{\R@c=\X@ybase \U@c=\Y@ybase \intersect@}\afterCOORD@}% + \else\ifx s\next + \DN@ s##1{\xy@{s{##1}}{\cfroms@{##1}}\afterCOORD@}% + \else \let\next@=\afterCOORD@ \fi\fi\fi\fi\fi \next@} + +\xydef@\xyCOORD@other{% + \ifx "\next %" + \DN@"##1"{\xy@{"##1"}{\cfromid@{##1}}\afterCOORD@}% + \else\ifx \bgroup\next + \DN@##1{\xy@{{##1}}{\enter@{\pfromthep@\basefromthebase@}}% + \silencexy@ \POS##1\relax \unsilencexy@ \xy@@\leave@ \afterCOORD@}% + \else\ifx (\next %) + \DN@({\xyFN@\xyCOORD@other@open}%) + \else \let\next@=\afterCOORD@ \fi\fi\fi \next@} + +\xynew@{if}\ifsilentxy@ + +\xydef@\silencexy@{% + \ifsilentxy@ \nter@{}% + \else \nter@{\silentxy@false \let\xy@=\unsilent@@xy@} + \silentxy@true \let\unsilent@@xy@=\xy@ \def\xy@##1##2{\unsilent@@xy@{}{##2}}% + \fi} + +\xydef@\unsilencexy@{\leave@} + +\xydef@\xyCOORD@other@open{% + \ifx *\next + \DN@*##1*){\xy@{(*}{\enter@{\pfromthep@\basefromthebase@}}% + \POS##1\relax \xy@{*)}\leave@ \afterCOORD@}% + \else \DN@{\xyFN@\afterCOORD@(}%) + \fi \next@} +\DOCMODE) + + Finally <pos> parsing after <coord> (possibly <vector>) is + interpreted: + +\DOCMODE( +\xydef@\xyPOS@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\POS@}%gobble spaces + \else\addPLUS@\ifx \next + \addPLUS@\DN@{\xy@+{\enter@\cplusthec@}% + \afterCOORD{\xy@@\leave@ \xyFN@\POS@}}% + \else\addDASH@\ifx \next + \addDASH@\DN@{\xy@-{\enter@\cplusthec@}% + \afterCOORD{\xy@@{\X@c=-\X@c \Y@c=-\Y@c\leave@}\xyFN@\POS@}}% + \else\ifx !\next + \DN@ !{\xy@!{\enter@\cskewthec@}\afterCOORD{\xy@@\leave@ \xyFN@\POS@}}% + \else\addDOT@\ifx \next + \addDOT@\DN@{\xy@.{\enter@\cmergethec@}% + \afterCOORD{\xy@@\leave@ \xyFN@\POS@}}% + \else\ifx ,\next + \DN@ ,{\xy@,{\comma@@}\afterCOORD{\xyFN@\POS@}}% + \else\ifx ;\next + \DN@ ;{\xy@;{\swap@}\afterCOORD{\xyFN@\POS@}}% + \else\ifx :\next + \DN@ :{\xyFN@\POS@colon}% + \else\addEQ@\ifx \next + \addEQ@\DN@{\xyFN@\saveid@}% + \else\ifx *\next + \DN@ *{\xyFN@\POS@star}% + \else \ifx ?\next + \DN@?{\xy@?{}\afterPLACE{\xyFN@\POS@}}% + \else \addAT@\ifx \next + \addAT@\DN@{\xyFN@\STACK@}% + \else + \let\next@=\afterPOS@ + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@} + +\xylet@\comma@@=\relax + +\xylet@\POS@=\xyPOS@ +\DOCMODE) + + |\comma@@| is a hook used to change the operation of |,|, \eg, when + reading a stack setup where it means `push'. + + The final functions serve only to distinguish between the single + character |:|/|*| and dual character |::|/|**| operators: + +\DOCMODE( +\xydef@\POS@colon{\DNii@{\afterCOORD{\xyFN@\POS@}}% + \ifx :\next \xy@{::}{\setbase@@\X@c\Y@c}\DN@:{\nextii@}% + \else \xy@:{\setbase@\X@p\Y@p\X@c\Y@c}\let\next@=\nextii@ \fi + \next@} + +\xydef@\POS@star{% + \ifx *\next + \DN@*##1##{\nextii@{##1}}% + \DNii@##1##2{\xy@@ix@{{##1}{##2}}% + \xy@{**##1{##2}}{\expandafter\connect@\the\toks9 }\xyFN@\POS@}% + \else + \DN@##1##{\nextii@{##1}}% + \DNii@##1##2{\xy@@ix@{{##1}{##2}}% + \xy@{*##1{##2}}{\expandafter\drop@\the\toks9 }\xyFN@\POS@}% + \fi + \next@} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Simple actions:} + + Next follow the simplest actions; the complicated ones are explained + along with their notes below. + +\DOCMODE( +\xydef@\cfromp@{\X@c=\X@p \Y@c=\Y@p \U@c=\U@p \D@c=\D@p \L@c=\L@p \R@c=\R@p + \Edge@c=\expandafter{\the\Edge@p}} + +\xydef@\pfromc@{\X@p=\X@c \Y@p=\Y@c \U@p=\U@c \D@p=\D@c \L@p=\L@c \R@p=\R@c + \Edge@p=\expandafter{\the\Edge@c}} + +\xydef@\swapdimen@#1#2{\dimen@=#1\relax #1=#2\relax #2=\dimen@} + +\xynew@{toks}\swaptoks@@ + +\xydef@\swap@{\swapdimen@\X@c\X@p \swapdimen@\Y@c\Y@p + \swapdimen@\U@c\U@p\swapdimen@\D@c\D@p \swapdimen@\L@c\L@p\swapdimen@\R@c\R@p + \swaptoks@@=\Edge@c \Edge@c=\Edge@p \Edge@p=\swaptoks@@} +\DOCMODE) + + Next the parsing of coordinate pairs in |<>|: + +\DOCMODE( +\xydef@\vfromabsolute@#1{\vfromabsolute@@#1,@} + +\xydef@\vfromabsolute@@#1,#2@{\X@c=#1\relax + \DN@{#2}\ifx\next@\empty \Y@c=\X@c + \else \DN@##1,{\Y@c=##1}\next@#2\relax \fi +% \advance\X@c 1sp \advance\Y@c 1sp %HACK +} +\DOCMODE) + + The next group of commands are used to store on the control stack + with the |\enter@| command, so they "expand" to something useful: + +\DOCMODE( +\xydef@\cfromthec@{\X@c=\the\X@c \Y@c=\the\Y@c + \U@c=\the\U@c \D@c=\the\D@c \L@c=\the\L@c \R@c=\the\R@c + \Edge@c={\expandafter\noexpand\the\Edge@c}} + +\xydef@\cfromthep@{\X@c=\the\X@p \Y@c=\the\Y@p + \U@c=\the\U@p \D@c=\the\D@p \L@c=\the\L@p \R@c=\the\R@p + \Edge@c={\expandafter\noexpand\the\Edge@p}} + +\xydef@\pfromthep@{\X@p=\the\X@p \Y@p=\the\Y@p + \U@p=\the\U@p \D@p=\the\D@p \L@p=\the\L@p \R@p=\the\R@p + \Edge@p={\expandafter\noexpand\the\Edge@p}} + +\xydef@\pfromthec@{\X@p=\the\X@c \Y@p=\the\Y@c + \U@p=\the\U@c \D@p=\the\D@c \L@p=\the\L@c \R@p=\the\R@c + \Edge@p={\expandafter\noexpand\the\Edge@c}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{notes} + +\note??=[arithmetic] +% + When doing arithmetic with |+| and |-| then the resulting current + object inherits the size of the <coord>, \ie, the right + argument---this will be zero if the <coord> is a <vector>. + +\begin{exercise} + How do you set $c$ to an object the same size as the saved object + |"ob"| but moved |<|$X$|,|$Y$|>|? +\answertext{Use the <pos>ition |<|$X$|,|$Y$|>+"ob"|.} +\end{exercise} + +\DOCMODE( +\xydef@\cplusthec@{\advance\X@c\the\X@c \advance\Y@c\the\Y@c} +\DOCMODE) + +\note??=[skew] +% + "Skewing" using |!| just means that the reference point of $c$ is + moved with as little change to the shape of the object as possible, + \ie, the edge of~$c$ will remain in the same location except that it + will grow larger to avoid moving the reference point outside~$c$. +% +\begin{exercise} + What does the <pos> \dots|!R-L| do? +\answertext{It first sets $c$ according to ``\dots''. Then it changes $c$ to + the point right of $c$ at the same distance from the right edge of + $c$ as its width, $w$, \ie, +$$ +\xy + *+\hbox{The \dots}="it" *\frm{_\}}!D-U*{w} + ,{"it"+RD}.{"it"+RU}.{"it"!R-L*{\times}+0}!C *\frm{_\}}!D-U*{w} +\endxy +$$} +\end{exercise} +% + \BUG: The result of |!| is always a rectangle currently. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Procedure:} + + |!| moves the center of $c$ by a temporarily read $c'$ and then + readjusts the extents: +$$ +\begin{array}{rclcl} + D_c &:=& Y'+Y_c - \min(Y'-D', Y'+Y_c) &=& \max(Y_c+D',0)\\ + U_c &:=& \max(Y'+U', Y'+Y_c) - (Y'+Y_c) &=& \max(U'-Y_c,0)\\ + Y_c &:=& Y'+Y_c\\ + L_c &:=& X'+X_c - \min(X'-L', X'+X_c) &=& \max(X_c+L',0)\\ + R_c &:=& \max(X'+R', X'+X_c) - (X'+X_c) &=& \max(R'-X_c,0)\\ + X_c &:=& X'+X_c\\ +\end{array} +$$ + +\DOCMODE( +\xydef@\cskewthec@{% + \noexpand\cskew@{\the\Y@c}{\the\X@c}{\the\D@c}{\the\U@c}{\the\L@c}{\the\R@c}} + +\xydef@\cskew@#1#2#3#4#5#6{% + \D@c=#3\advance\D@c \Y@c \ifdim\D@c<\z@ \D@c=\z@ \fi + \U@c=#4\advance\U@c-\Y@c \ifdim\U@c<\z@ \U@c=\z@ \fi + \advance\Y@c#1% + \L@c=#5\advance\L@c \X@c \ifdim\L@c<\z@ \L@c=\z@ \fi + \R@c=#6\advance\R@c-\X@c \ifdim\R@c<\z@ \R@c=\z@ \fi + \advance\X@c#2% + \Edge@c={\rectangleEdge}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[covering] +% + A <pos> "covers" another if it is a rectangle with size sufficiently + large that the other is ``underneath''. The |.| operation + ``extends'' a <pos> to cover an additional one---the reference point + of $c$ is not moved but the shape is changed to a rectangle such that + the entire $p$ object is covered. + + \BUG: non-rectangular objects are first ``translated'' into a + rectangle by using a diagonal through the object as the diagonal of + the rectangle. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Procedure:} + + |.| takes a temporary object $c'$ and adjusts the extents of $c$ such + that it is covered. +$$ +\begin{array}{rclcl} + L_c &:=& X' - \min(X'-L_c, X-L) &=& \max(L_c, A+L)\\ + R_c &:=& \max(X'+R_c, X+R) - X' &=& \max(R_c, -A+R)\\ + D_c &:=& Y' - \min(Y'-D_c, Y-D) &=& \max(D_c, B+D)\\ + U_c &:=& \max(Y'+U_c, Y+U) - Y' &=& \max(U_c, -B+U)\\ +\end{array} +$$ + with $|<|A|,|B|>| = |<|X'-X|,|Y'-Y|>|$. First method~2 of the object + is used to convert it into a rectangle. + +\DOCMODE( +\xydef@\cmergethec@{% + \noexpand\cmerge@{\the\Y@c}{\the\X@c}{\the\D@c}{\the\U@c}{\the\L@c}{\the\R@c}} + +\xydef@\cmerge@#1#2#3#4#5#6{\the\Edge@c4% + \A@=#2\advance\A@-\X@c \B@=#1\advance\B@-\Y@c + \dimen@=#5\advance\L@c \A@ \ifdim\L@c<\dimen@ \L@c=\dimen@ \fi + \dimen@=#6\advance\R@c-\A@ \ifdim\R@c<\dimen@ \R@c=\dimen@ \fi + \dimen@=#3\advance\D@c \B@ \ifdim\D@c<\dimen@ \D@c=\dimen@ \fi + \dimen@=#4\advance\U@c-\B@ \ifdim\U@c<\dimen@ \U@c=\dimen@ \fi + \advance\X@c\A@ \advance\Y@c\B@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[base] +% + The operations |:| and |::| set the "base" used for <coord>inates + having the form $|(|x|,|y|)|$. The |:| operation will set + |<|$X_"origin"$|,| $Y_"origin"$|>| to~$p$, |<|$X_"xbase"$|,| + $Y_"xbase"$|>| to $c-"origin"$, and~|<|$X_"ybase"$|,| $Y_"ybase"$|>| + to |<|${-}Y_"xbase"$|,| $X_"xbase"$|>| (this ensures that it is a + usual square coordinate system). The |::| operation may then be used + afterwards to make nonsqare bases by just setting "ybase" to + $c-"origin"$. Here are two examples: firstly |0;<1cm,0cm>:| sets the + coordinate system +$$ +\xy + <0cm,0cm>*@{o};<1cm,0cm>: + (0,0);{(1,0)**@{-}?>*@{>}},{(0,1)**@{-}?>*@{>}}, + (0,0)*+!UR\hbox{\small"origin"}, + (1,0)*+!LC\hbox{\small"xbase"}, + (0,1)*!D\hbox{\small"ybase"}, + (1,1)*{*}*++!CL{|(1,1)|}+0;(0,1)**@{.},(1,0)**@{.} +\endxy +$$ + while~|<1cm,.5cm>;<2cm,1.5cm>:<1cm,1cm>::|\hfil defines +$$ +\xy + <0cm,0cm>*@{o}, <1cm,.5cm>;<2cm,1.5cm>: +% + (0,0);{(0,1)**@{--}?(1)*@{>}}, + (0,1)*+!R\txt\small{"ybase"\\before\\{\tt::}}, +% + <1cm,1cm>:: + (0,0);{(1,0)**@{-}?(1)*@{>}},{(0,1)**@{-}?(1)*@{>}}, + (0,0)*+!LU\txt\small{"origin"}, + (1,0)*+!LC\txt\small{"xbase"}, + (0,1)*!D\txt\small{"ybase"}, + (1,1)*{*}*++!CL{|(1,1)|}+0;(0,1)**@{.},(1,0)**@{.} +\endxy +$$ + where in each case the $\circ$ is at |0|, the base vectors have been + drawn and the $\times$ is at |(1,1)|. + + When working with cartesian coordinates these three special <factor>s + are particularly useful: +% +\begin{defs} + ??c![\halfroottwo] & $0.70710678\approx{1\over2}\sqrt2$ \cr + ??c![\partroottwo] & $0.29289322\approx 1-{1\over2}\sqrt2$ \cr + ??c![\halfrootthree] & $0.86602540\approx{1\over2}\sqrt3$ \cr +\end{defs} +\noindent\unskip +% + More can be defined using |\def| (or |\newcommand| in \LaTeX). + +\DOCMODE( +\xydef@\halfroottwo{.70710678} +\xydef@\partroottwo{.29289322} +\xydef@\halfrootthree{.8660254} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Procedure:} + + The code chosen by the parsing is very simple; the only tricky bit is + to ensure that |\basefromthebase@| always expands to set the current + base. + +\DOCMODE( +\xydef@\vfromcartesian@#1{\vfromcartesian@@#1@} + +\xydef@\vfromcartesian@@#1,#2@{% + \X@c=\X@origin \advance\X@c#1\X@xbase \advance\X@c#2\X@ybase + \Y@c=\Y@origin \advance\Y@c#1\Y@xbase \advance\Y@c#2\Y@ybase} + +\xydef@\setbase@#1#2#3#4{% + \X@origin=#1\relax \Y@origin=#2\relax + \X@xbase=#3\relax \advance\X@xbase-\X@origin + \Y@xbase=#4\relax \advance\Y@xbase-\Y@origin + \X@ybase=-\Y@xbase \Y@ybase=\X@xbase} + +\xydef@\setbase@@#1#2{% + \X@ybase=#1\relax \advance\X@ybase-\X@origin + \Y@ybase=#2\relax \advance\Y@ybase-\Y@origin} + +\xydef@\basefromthebase@{\X@origin=\the\X@origin \Y@origin=\the\Y@origin + \X@xbase=\the\X@xbase \Y@xbase=\the\Y@xbase + \X@ybase=\the\X@ybase \Y@ybase=\the\Y@ybase} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[angle in current base] +% + An "angle" $\alpha$ in \Xy-pic is the same as the coordinate pair + $|(|\cos\alpha|,|\sin\alpha|)|$ where $\alpha$ must be an integer + interpreted as a number of degrees. Thus the <vector> |a(0)| is the + same as |(1,0)| and |a(90)| as |(0,1)|, etc. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The translation involves several steps: (??_[ang1])~Normalise the + argument to be within $[0^\circ:360^\circ[$. (??_[ang2])~Flip angle + around $x$-axis and then $y$-axis to ensure it is in the first + quadrant, \ie, within $[0^\circ:90^\circ[$. (??_[ang3])~Flip around + diagonal to ensure angle within $[0^\circ:45^\circ[$. + (??_[ang4])~Find values $\phi\le\alpha\lt\psi$ from the table in + figure~??[f.angles] (using recursive table lookup -- at most 3 tests + needed). (??_[ang5])~build vector $(x,y)$ interpolated between the + sin/cos values for $\phi$ and $\psi$ using the formula +$$ + \left(\cos\phi + k(\cos\psi-\cos\phi) , + \sin\phi + k(\sin\psi-\sin\phi) \right) ~, + \quad\hbox{where}~k = \frac{\alpha-\phi}{\psi-\phi} +$$ + (??_[angx])~build the chosen vector. + +\begin{figure*}[tp] + \noindent Vectors for angles in $[0^\circ:45^\circ]$: contains all + angles required to typeset fractions up to $\frac{n}{12}\times2\pi$, + $\frac1{16}\times2\pi$, and $\frac1{24}\times2\pi$ exactly, and two + extra low ones to ensure that all gaps are less than $5^\circ$ and + the precision of all sine/cosines better than $\frac1{1000}$. + $$ + \small + \def"{\vphantom{\frac()}\frac} + \begin{array}{\otherbar l\otherbar r@{~}l\otherbar c\otherbar c\otherbar} + \hline + ~\alpha & (\cos\alpha, & \sin\alpha) & \hbox{fractions of $2\pi$} & + \hbox{flipped fractions of $2\pi$} \\ + \hline + ~0&(1,&0) & "0{n} + & "12,"14,"24,"28,"34,"36,"3{12},"48,"5{10},"68,"6{12},"9{12} \\ + ~4.090909 & (.99677570, & .08023846) & - & - \\ + ~6 & (.99452190, & .10452846) & - & - \\ + ~8.181818 & (.98982144, & .14231484) & "3{11} & "8{11} \\ + 10 & (.98480775, & .17364818) & "79 & "29 \\ + 12.857143 & (.97492791, & .22252093) & "27 & "57 \\ + 15 & (.96592583, & .25881905) & "1{24} & \\ + 16.363636 & (.95949297, & .28173256) & "6{11} & "5{11} \\ + 18 & (.95105652, & .30901699) & "3{10},"45,"8{10} & "15,"2{10},"7{10} \\ + 20 & (.93969262, & .34202014) & "59 & "49 \\ + 22.5 & (.92387953, & .38268343) & "1{16} & \\ + 24.545455 & (.90963200, & .41541501) & "9{11} & "2{11} \\ + 25.714286 & (.90096887, & .43388374) & "47 & "37 \\ + 30 & (.86602540, & .5) & "13,"1{12},"26,"39,"4{12},"56,"7{12},"{10}{12} + & "16,"23,"2{12},"46,"5{12},"69,"8{12},"{11}{12} \\ + 32.727273 & (.84125353, & .54064082) & "1{11} & "{10}{11} \\ + 36 & (.80901699, & .58778525) & "1{10},"35,"6{10} & "25,"4{10},"9{10} \\ + 38.571429 & (.78183148, & .62348980) & "67 & "17 \\ + 40 & (.76604444, & .64278761) & "19 & "89 \\ + 40.909091 & (.75574957, & .65486073) & "4{11} & "7{11} \\ + 45 & (.70710678, & .70710678) & "18,"38,"58,"78 & - \\ + \hline + \end{array} + $$ + \caption{Computing angle vectors} + ??=[f.angles] +\end{figure*} + +\DOCMODE( +\xydef@\vfromcartesianangle@#1{\enter@\basefromthebase@ \R@=#1\p@ + \B@=360\p@ %?*[ang1] + \loop@ \ifdim\R@<\z@ \advance\R@\B@ \repeat@ + \loop@ \ifdim\R@>\B@ \advance\R@-\B@ \repeat@ + \ifdim\R@<.5\B@\else \R@=-\R@ \advance\R@\B@ %?*[ang2] + \X@ybase=-\X@ybase \Y@ybase=-\Y@ybase \fi + \B@=180\p@ + \ifdim\R@<.5\B@\else \R@=-\R@ \advance\R@\B@ + \X@xbase=-\X@xbase \Y@xbase=-\Y@xbase \fi + \B@=90\p@ %?*[ang3] + \ifdim\R@<.5\B@ \let\nextiii@=\literal@ + \else \R@=-\R@ \advance\R@\B@ \def\nextiii@##1,##2@{##2,##1@}\fi + \dimen@=\z@ \DN@{1,0@}% %?*[ang4] + \dimen@ii=45\p@ \DNii@{.70710678,.70710678@}% + \chooseangleinterval@ + {\chooseangleinterval@ + {\chooseangleinterval@ + {\chooseangleinterval@ + {\chooseangleinterval@ + {}% + {4.090909}{.99677570,.08023846@}% + {}}% + {6}{.99452190,.10452846@}% + {\chooseangleinterval@ + {}% + {8.181818}{.98982144,.14231484@}% + {}}}% + {10}{.98480775,.17364818@}% + {\chooseangleinterval@ + {}% + {12.857143}{.97492791,.22252093@}% + {}}}% + {15}{.96592583,.25881905@}% + {\chooseangleinterval@ + {\chooseangleinterval@ + {}% + {16.363636}{.95949297,.28173256@}% + {}}% + {18}{.95105652,.30901699@}% + {\chooseangleinterval@ + {}% + {20}{.93969262,.34202014@}% + {}}}}% + {22.5}{.92387953,.38268343@}% + {\chooseangleinterval@ + {\chooseangleinterval@ + {\chooseangleinterval@ + {}% + {24.545455}{.90963200,.41541501@}% + {}}% + {25.714286}{.90096887,.43388374@}% + {}}% + {30}{.86602540,.5@}% + {\chooseangleinterval@ + {\chooseangleinterval@ + {}% + {32.727273}{.84125353,.54064082@}% + {}}% + {36}{.80901699,.58778525@}% + {\chooseangleinterval@ + {\chooseangleinterval@ + {}% + {38.571429}{.78183148,.62348980@}% + {}}% + {40.909091}{.75574957,.65486073@}% + {\chooseangleinterval@ + {}% + {40}{.76604444,.64278761@}% + {}}}}}% + \A@=\R@ \advance\A@-\dimen@ %?*[ang5] + \ifdim\ifdim\A@<\z@-\fi\A@<.01\p@ \edef\next@{\expandafter\nextiii@\next@}% + \else \B@=\dimen@ii \advance\B@-\R@ + \ifdim\A@<\B@ \dimen@=\toradians@\A@ + \edef\next@{\next@ \expandafter\removePT@\the\dimen@ @}% + \else \dimen@=-\toradians@\B@ + \edef\next@{\nextii@ \expandafter\removePT@\the\dimen@ @}% + \fi + \expandafter\interpolatepoint@\next@ + \edef\next@{\expandafter\nextiii@\next@}% + \fi + \expandafter\vfromcartesian@@\next@ %?*[angx] + \leave@} + +\xydef@\chooseangleinterval@#1#2#3#4{% + \B@=#2\p@ \def\next{#3}% + \ifdim\R@<\B@ \dimen@ii=\B@ \let\nextii@=\next #1% + \else \dimen@=\B@ \let\next@=\next \ifdim\B@<\R@ #4\fi\fi} + +\xydef@\interpolateinterval@#1,#2@#3,#4@{% + \A@=#1\p@ \dimen@=#3\p@ \advance\dimen@-\A@ \advance\A@\next\dimen@ + \B@=#2\p@ \dimen@=#4\p@ \advance\dimen@-\B@ \advance\B@\next\dimen@ + \edef\next@{\expandafter\removePT@\the\A@,\expandafter\removePT@\the\B@ @}} + +\xydef@\toradians@{0.01745329} + +\xydef@\interpolatepoint@#1,#2@#3@{% + \A@=#1\p@ \dimen@ii=#3\A@ \dimen@ii=-.5\dimen@ii \advance\A@#3\dimen@ii + \dimen@=-#2\p@ \advance\A@#3\dimen@ + \B@=#2\p@ \dimen@ii=#3\B@ \dimen@ii=-.5\dimen@ii \advance\B@#3\dimen@ii + \dimen@=#1\p@ \advance\B@#3\dimen@ + \edef\next@{\expandafter\removePT@\the\A@,\expandafter\removePT@\the\B@ @}} +\DOCMODE) + + Figure~\ref{f.alldirections} shows all directions. + +\begin{figure}[ht] +\begin{center}\leavevmode +\def\a#1(#2){\save"o";a(#2)**@{-}*+__!P{\scriptscriptstyle#1#2}\restore} +\def\ad(#1){\save"o",a(#1)*{\cdot}\restore} +% +\newcount\n \newcount\m +\xy (50,0):0*{\kern.7pt\scriptstyle\ddot\smile}*[o]\cir<4pt>{}="o"\relax +\n=0 % +\loop + \expandafter\a\expandafter(\the\n)% + \advance\n1 \expandafter\ad\expandafter(\the\n)% + \advance\n1 \expandafter\ad\expandafter(\the\n)% + \advance\n1 \expandafter\ad\expandafter(\the\n)% + \advance\n1 \expandafter\ad\expandafter(\the\n)% + \advance\n1 \ifnum360>\n\relax \repeat +\a~, (360)% +\endxy +\end{center} +\caption{All directions.}\label{f.alldirections} +\end{figure} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[drop] +% + To "drop" an <object> at $c$ with |*| means to actually physically + typeset it in the picture with reference position at $c$---how this + is done depends on the <object> in question and is described in + detail in~\S??[object]. The intuition with a drop is that it + typesets something at $|<|X_c|,|Y_c|>|$ and sets the edge of $c$ + accordingly. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\subparagraph*{Procedure:} + + (??_[drop1])~sets up the direction to allow for directionals and + builds the requested <object> in the (global) |\lastobjectbox@| box, + (??_[drop2])~adjust the picture size unless it is a hidden object, + setting $|\dimen@| = X_c-L_c$, and (??_[drop3])~drop the object in + the picture at the right point by setting |box0| and using the + |\Drop@@| method. + +\DOCMODE( +\xydef@\drop@#1#2{%*[drop1] + \global\setbox\lastobjectbox@=\object#1{#2}% + \ifHidden@ \dimen@=\X@c \advance\dimen@-\L@c \else %?*[drop2] + \dimen@=\Y@c \advance\dimen@ \U@c \ifdim\Y@max<\dimen@ \Y@max=\dimen@ \fi + \dimen@=\Y@c \advance\dimen@-\D@c \ifdim\dimen@<\Y@min \Y@min=\dimen@ \fi + \dimen@=\X@c \advance\dimen@ \R@c \ifdim\X@max<\dimen@ \X@max=\dimen@ \fi + \dimen@=\X@c \advance\dimen@-\L@c \ifdim\dimen@<\X@min \X@min=\dimen@ \fi + \fi + \ifInvisible@\else %?*[drop3] + \setboxz@h{\kern\dimen@ \raise\Y@c\box\lastobjectbox@}% + \ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ {\Drop@@}\fi} +\DOCMODE) + + \NOTE: All typesetting into a picture should use or emulate |\drop@|! + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[connect] +% + The "connect" operation |**| will first compute a number of internal + parameters describing the direction from~$p$ to~$c$ and then typesets + a connection filled with copies of the <object> as illustrated + in~\S??[basics.connect]. The exact details of the connection depend + on the actual <object> and are described in general in~\S??[object]. + The intuition with a connection is that it typesets something + connecting $p$ and $c$ and sets the |?| <pos> operator up accordingly. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\subparagraph*{Procedure:} + + Set up the direction to allow for directional objects, then save + $c$, build the <object> in |\lastobjectbox@|, restore $c$, and perform + the |\Connect@@| method to connect using |\lastobjectbox@|. + +\DOCMODE( +\xydef@\connect@#1#2{\setupDirection@ \enter@{\cfromthec@}% + \global\setbox\lastobjectbox@=\object#1{#2}\leave@ + \Connect@@} + +\xydef@\preconnect@#1#2{\setupDirection@ \enter@{\cfromthec@}% + \global\setbox\lastobjectbox@=\object#1{#2}\leave@ \connectStore@ + \ifInvisible@ \Connect@@ \else \Invisible@true\Connect@@\Invisible@false \fi} +\DOCMODE) + + The |\preconnect| command is for internal use by arrow \dots\ it + makes use of the following: + +\DOCMODE( +\xynew@{box}\connectobjectbox@@ +\xylet@\connectDrop@@=\empty +\xylet@\connectpreXY@style@=\empty +\xylet@\connectpostXY@style@=\empty + +\xylet@\connectRest@@=\empty + +\xydef@\connectStore@{% + \global\setbox\connectobjectbox@@=\copy\lastobjectbox@ + \let\connectDrop@@=\Drop@@ + \let\connectpreXY@style@ =\preXY@style@ + \let\connectpostXY@style@=\postXY@style@ + \xdef\connectRest@@{% + \def\noexpand\Upness@{\Upness@}% + \def\noexpand\Leftness@{\Leftness@}% + \ifInvisible@ \noexpand\Invisible@true \else \noexpand\Invisible@false \fi + \ifHidden@ \noexpand\Hidden@true \else \noexpand\Hidden@false \fi}} + +\xydef@\connectRestore@{% + \ifvbox\connectobjectbox@@ + \setbox\lastobjectbox@=\copy\voidb@x + \else + \global\setbox\lastobjectbox@=\copy\connectobjectbox@@ + \fi + \let\Drop@@=\connectDrop@@ + \global\let\preXY@style@ =\connectpreXY@style@ + \global\let\postXY@style@=\connectpostXY@style@ + \connectRest@@} +\DOCMODE) + + See note `??w![define <shape>]' for the use of |\preXY@style@| and + |\postXY@style@| to apply special <style>s, specified via + <object-modifier>s; being saved here by |\connectStore@| as + |\connectpreXY@style@| and |\connectpostXY@style@| to be reset by + |\connectRestore@|. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[shave]??=[pick place]??=[<place>] +% + Using |?| will ``pick a place'' along the most recent connection + typeset with |**|. What exactly this means is determined by the + object that was used for the connection and by the modifiers + described in general terms here. + + The ``shave'' modifiers in a <place>, |<| and |>|, change the default + <factor>, $f$, and how it is used, by `moving' the positions that + correspond to |(0)| and |(1)| (respectively): These are initially set + equal to~$p$ and~$c$, but shaving will move them to the point on the + edge of $p$ and $c$ where the connection ``leaves/enters'' them, and + change the default $f$ as indicated. When one end has already been + shaved thus then subsequent shaves will correspond to sliding the + appropriate position(s) a \TeX\ ??c![\jot] (usually equal to |3pt|) + further towards the other end of the connection (and past it). + Finally the "pick" action will pick the position located the fraction + $f$ of the way from |(0)| to |(1)| where $f=|0.5|$ if it was not set + (by |<|, |>|, or explicitly). + + All this is probably best illustrated with some examples: each + $\otimes$ in figure~??[f.places] is typeset by a sequence of the form + $p$|;| $c$ |**@{.}| |?|<place> |*{\oplus}| where we indicate the + |?|<place> in each case. (We also give examples of <slide>s.) + +\begin{figure*}[tb] +$$ + \def\[#1]#2{\def\2{#2}% + \POS "p";"c"**{} + #2*+=[o]{\oplus}="x"*=<5em,3em>{}-#1*!#1\hbox{{\tt\codeof\2}}; + "x"**@{-}?>*@{>}\ignorespaces}% + % +\xy + <0pt,110pt>*[o]=<20pt>{}="p"*\frm{oo}+L*!RC\hbox{$p$ is circular:~}, + <270pt,0pt>*=<4em>\txt<4em>{$c$ is a square text!}="c"*\frm{-,}, + "p";"c"**@{--}\relax + % + \[UR]{?(0)} + \[UR]{?(1)} + \[UR]{?} + \[UR]{?(.7)} + % + \[D]{?<>(.5)} + \[DL]{?<>(.2)(.5)} + \[DL]{?<} + \[UR]{?<<<} + \[UR]{?<<</1cm/} + \[D]{?<(0)} + \[DL]{?>} + \[D]{?>>>>} + % + \[DL]{?<>(.7)} + \[D]{?>(.7)} +\endxy +$$ +\caption{Example \protect<place>s}??=[f.places] +\end{figure*} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Procedure:} + + The code for parsing <place> is the following. To get first |<>| to + move to edge and the remaining to move a ??c![\jot] we have both + initial and continuing versions for each, the idea being that the + second and following go to the edge of a small temporary object with + radius |\jot|. + + \NOTE: This parser tests the "new parsing principle" that |\xy@| + should always be called as |\xy@{| "source" |}{| "target" |}|! + +% \HACK: `Helps' the `arrow' feature: in the procedure for path +% sub-segments, it is necessary to know the value of |\PLACEf@| both at +% the (possibly delayed) time when the sub-segments are being typeset +% and also at the time when the subsegments are being processed (and +% packaged to be delayed by the |\xy@@|). Thus it is necessary for any +% changes to the value of |\PLACEf@| to be both immediate and +% delayed. The reason is that |\bstartPLACE@| and |\bendPLACE@| read +% values from |\PLACEf@| and are themselves delayed by calls to |\xy@@| +% -- these delayed calls need to know what |\PLACEf@| will be when they +% are used. + +\DOCMODE( +\xydef@\afterPLACE#1{% + \DN@##1{\def\afterPLACE@{\xy@@\leave@ \def\afterPLACE@{##1}#1}}% + \expandafter\next@\expandafter{\afterPLACE@}% + \def\PLACEf@{{.5}}% + \xy@@{\enter@{\pfromthep@}% + \Creset@@ \def\PLACEf@{{.5}}% + \let\PLACEedgep@@=\PLACEedgep@ \let\PLACEedgec@@=\PLACEedgec@}% + \xyFN@\PLACE@} + +\xydef@\PLACEf@{} + +\xydef@\PLACEedgep@@{} +\xydef@\PLACEedgec@@{} + +\xydef@\PLACEedgep@{\Cshavep@@ \def\PLACEedgep@@{\Cslidep@@\jot}} +\xydef@\PLACEedgec@{\Cshavec@@ \def\PLACEedgec@@{\Cslidec@@{-\jot}}} + +\xylet@\afterPLACE@=\empty + +\xydef@\PLACE@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\PLACE@}%gobble spaces + \else\addLT@\ifx \next + \addLT@\DN@{\addLT@\xy@{\def\PLACEf@{{0}}\PLACEedgep@@}\xyFN@\PLACE@}% + \else\addGT@\ifx \next + \addGT@\DN@{\addGT@\xy@{\def\PLACEf@{{1}}\PLACEedgec@@}\xyFN@\PLACE@}% + \else\ifx (\next %) + \DN@(##1){\def\PLACEf@{{##1}}\xy@{(##1)}{\def\PLACEf@{{##1}}}\xyFN@\PLACE@}% + \else\ifx !\next + \DN@!{\xyFN@\PLACE@intercept}% + \else + \DN@{\xy@@{\expandafter\Calong@@\PLACEf@ \czeroEdge@}\PLACE@@}% + \fi\fi\fi\fi\fi \next@} + +\xydef@\PLACE@intercept{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\PLACE@intercept}%gobble spaces + \else\ifx \bgroup\next + \DN@##1{\xy@{!{##1}}{}\PLACE@intercept@{##1}}% + \else\ifx (\next %) + \DN@(*##1*){\xy@{!(*##1*)}{}\PLACE@intercept@{##1}}% + \else \DN@{\xyerror@{{<pos>} expected after ! in <place>}{}}% + \fi\fi\fi \next@} + +\xydef@\PLACE@intercept@#1{% + \xy@@{\enter@{\pfromthep@\basefromthebase@}\begingroup}% + \xy@@ix@{#1}\xy@@{\plainxy@ \expandafter\POS\the\toks9\relax + \edef\next@{\endgroup + \X@c =\the\X@c \Y@c=\the\Y@c \X@p=\the\X@p \Y@p=\the\Y@p}% + \next@ \Cintercept@@ \leave@}% + \PLACE@@} + +\xydef@\PLACE@@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\PLACE@@}%gobble spaces + \else\ifx /\next \DN@/##1/{\xy@{/##1/}{\Cslidec@@{##1}}\afterPLACE@}% + \else \let\next@=\afterPLACE@ + \fi\fi \next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[slide] +% + A <slide> will move the position a dimension further along the + connection at the picked position. For straight connections (the + only ones kernel \Xy-pic provides) this is the same as adding a + vector in the tangent direction, \ie, $|?|\dots|/|A|/|$ is the same + as $|?|\dots|+/|A|/|$. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[intercept] +% + This special <place> finds the point where the last connection + intercepts with the line from $p$ to $c$ as setup by the <pos>, thus + usually this will have the form |!{|<coord>|;|<coord>|}|\footnote{The + braces can be replaced by |(*|\dots|*)| "once", \ie, there can be no + other braces nested inside it.}, for example, + \BUG: Only works for straight arrows at present. +% +\begin{code} +\xy <1cm,0cm>: + (0,0)*=0{+}="+" ; + (2,1)*=0{\times}="*" **@{.} , + (1,0)*+{A} ; (2,2)*+{B} **@{-} + ?!{"+";"*"} *{\bullet} +\endxy +\end{code} +\displaycode\noindent +% + will typeset +% +$$\docode$$ + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[axis intersection] +% + The positions denoted by the "axis intersection" + <coord>inates~??c![x] and~??c![y] are the points where the line + through $p$ and $c$ intersects with each axis. The following figure + illustrates this: +$$ + \xy;<1cm,.5cm>:<-.5cm,.5cm>:: + (0,0)*+!UR{"origin"}; + (1,0)*+!DR{"xbase"}**@{-}?>*@{>}, + (0,0);(0,1)*+!DR{"ybase"}**@{-}?>*@{>}, + (0.5,-1)="p"*@{o}*!LU\hbox{~$p$}; + p+<.25cm,.5cm>="c"*@{o}*!LU\hbox{~$c$}*{}?(1), + % + "p";"c",x*+!LD{|x|}*@{*}*{}**@{.};(1,0)**@{.}, + "p";"c",y*!U{\strut|y|}*@{*}*{}**@{.};(0,0)**@{.}, + \endxy +$$ + +\begin{exercise} +% + Given predefined points $A$, $B$, $C$, and $D$ (stored as objects + |"A"|, |"B"|, |"C"|, and |"D"|), write a <coord> specification that + will return the point where the lines $\overline{AB}$ and + $\overline{CD}$ cross (the point marked with a large circle here): +% +\begin{code} +\xy + % + % set up and mark A, B, C, and D: + (0,0)="A" *\cir<1pt>{}*+!DR{A}, + (7,10)="B" *\cir<1pt>{}*+!DR{B}, + (13,8)="C" *\cir<1pt>{}*+!DL{C}, + (15,4)="D" *\cir<1pt>{}*+!DL{D}, + % + % goto intersection and name+circle it: + {"A";"B":"C";"D",x} ="I" *\cir<3pt>{}, + % + % make dotted lines: + "I";"A"**{} +/1pc/;-/1pc/ **@{..}, + "I";"D"**{} +/1pc/;-/1pc/ **@{..} + % +\endxy +\end{code} +$$\docode$$ +% +\answertext{The <coord> ``|{"A";"B":| |"C";"D",| |x}|'' returns the cross + point. Here is how the author typeset the diagram in the exercise:} +\answercode +\answertext{\displaycode\noindent A |?!|\dots\ <place> could also have been + used.} +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Procedure:} + + We solve the following equation in $a,b$: +$$ + "origin" + a*|<|R_c|,|U_c|>| = c - b*(c-p) +$$ + and then set +$$ + |<|X_c|,|Y_c|>| := |<|X_c|,|Y_c|>| - b*(c-p) + \quad\textrm{with zero size}\quad + D_c,U_c,L_c,R_c := 0,0,0,0. +$$ + The code uses $c=(X_c,Y_c,D_c,U_c,L_c,R_c)$ and $A,B$ as temporaries + and computes: +$$ +\begin{array}{rcl} + |<|dX|,|dY|>| &:=& |<|X_c|,|Y_c|>| - |<|X_p,Y_p|>| \\[1pt] + |<|A|,|B|>| &:=& |<|X_c|,|Y_c|>| - |<|X_"origin"|,|Y_"origin"|>| \\[1pt] + |<|D_c|,|L_c|>| &:=& |<| \Det{R& dX\\U&dY} |,| + \Det{R&A\\U&B} |>| \\[1pt] + |<|X_c|,|Y_c|>| &:=& |<|X_c|,|Y_c|>| - (L_c/D_c)*|<|dX|,|dY|>| +\end{array} +$$ + where we really do $D := (R/|pt|)dY - (U/|pt|)dX$ and similarly for + $L$. + +\DOCMODE( +\xydef@\intersect@{%?*[intersect@] + \d@X=\X@c \advance\d@X-\X@p \d@Y=\Y@c \advance\d@Y-\Y@p + \A@=\X@c \advance\A@-\X@origin \B@=\Y@c \advance\B@-\Y@origin + \edef\next@{\expandafter\removePT@\the\R@c}% + \edef\nextii@{\expandafter\removePT@\the\U@c}% + \D@c=\next@\d@Y \advance\D@c-\nextii@\d@X \divide\D@c\KK@ + \L@c=\next@\B@ \advance\L@c-\nextii@\A@ \divide\L@c\KK@ + \ifdim\D@c=\z@\zeroDivide@\else \quotient@\next@\L@c\D@c \fi + \advance\X@c-\next@\d@X \advance\Y@c-\next@\d@Y + \czeroEdge@} +\DOCMODE) + + When there is no intersection point a wrong answer is returned, + accompanied by a warning message. This behaviour can be altered by + assigning a different value to the hook: |\zeroDivide@|. This macro + must store a number in |\next@|. + +\DOCMODE( +\xydef@\zeroDivide@@{\zeroDivide@message{\intersect@}{treated as 0}\DN@{0}} +\xydef@\zeroDivide@message#1#2{\xywarning@{division by 0 in \string#1, #2}} +\xylet@\zeroDivide@=\zeroDivide@@ + +\xydef@\zeroDivideLimit@@{\ifdim\L@c=\z@ \DN@{0}% + \else\ifdim\L@c<\z@\DN@{-\zeroDivide@Limit}% + \else\DN@{\zeroDivide@Limit}\fi\fi + \zeroDivide@message{\intersect@}{replaced by \zeroDivide@Limit}} +\xydef@\zeroDivideLimit@#1{\edef\zeroDivide@Limit{#1}% + \let\zeroDivide@=\zeroDivideLimit@@} +\xylet@\zeroDivideLimit=\zeroDivideLimit@ +\DOCMODE) + + By specifying |\zeroDivideLimit{|<num>|}| the user can locally + establish that ${x\over0} = \sgn(x)$<num>, whenever such a division + by zero would otherwise occur in an intersection calculation. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[group] +% + A <pos> <decor> "grouped" in |{}|-braces\footnote{One can use + |(*|\dots|*)| instead also here.} is interpreted in a local scope in + the sense that any $p$ and "base" built within it are forgotten + afterwards, leaving only the $c$ as the result of the <coord>. + \NOTE: Only $p$ and "base" are restored -- it is not a \TeX\ group. + +\begin{exercise} + What effect is achieved by using the <coord>inate ``|{;}|''? +\answertext{To copy the $p$ value to $c$, \ie, equivalent to ``|p|''.} +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The code is inside |\POS@|. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[in <direction>] +% + The vector $|/|Z|/|$, where $Z$ is a <dimen>sion, is the same as the + vector $|<|Z\cos\alpha|,|Z\sin\alpha|>|$ where $\alpha$ is the angle + of the last direction set by a connection (\ie, with |**|) or + subsequent placement (|?|) position. + +\DOCMODE( +\xydef@\vfromslide@#1{\enter@\DirectionfromtheDirection@ \begingroup + \plainxy@\afterDIRECTIONorEMPTY\vfromslide@i\vfromslide@i#1@} + +\xydef@\vfromslide@i#1@{\DN@{#1}% + \edef\next{\endgroup + \ifx\next@\empty \dimen@=.5pc \else \dimen@=#1\relax \fi + \X@c=\cosDirection\dimen@ \Y@c=\sinDirection\dimen@}\next + \leave@} +\DOCMODE) + + It is possible to give a <direction> as described in the next section + (figure~??[f.object], note~??[direction] in particular) that will + then be used to set the value of $\alpha$. It is also possible to + omit the <dimen> in which case it is set to a default value of + |.5pc|. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[offset]??=[corner] +% + A <corner> is an offset from the current $|<|X_c|,|Y_c|>|$ position + to a specific position on the edge of the $c$ object (the two-letter + ones may be given in any combination): +$$ +\def\[#1]{\POS"box"+#1="x";"box" + **{} ?</-2em/*+\hbox{\tt#1};"x",**@{-}?>*@{>}} +% +\xy.(-5,-4).(15,9)*\frm{-}="box"*{c}="c"; + "box"+L**@{.}, "box"+R**@{.}, "box"+D**@{.}, "box"+U**@{.} +% + \[L] \[R] \[D] \[U] + \[LD]\[RD]\[LU]\[RU] + \[CL]\[CR]\[DC]\[UC] \[C] \[P] + \POS"box"+(-20,-8)*{p}="p";"c"**@{.},"box"**{}\[E] +\endxy +$$ + The `edge point' |E| lies on the edge along the line from $p$ to the + centre of the object, in contrast to the `proportional' point |P| + which is also a point on the edge but computed in such a way that the + object looks as much `away from $p$' as possible. + + Finally, a following $|(|f|)|$ suffix will multiply the offset vector + by the <factor> $f$. + +\begin{exercise} + What is the difference between the <pos>itions |c?<| and |c+E|? +\answertext{When using the kernel connections that are all straight there is + no difference, \eg, |**{}?<| and |**{}+E| denote exactly the same + position. However, for other connections it is not necessarily the + case that the point where the connection enters the current object, + denoted by |?<|, and the point where the straight line from $p$ + enters the object, denoted by |+E|, coincide.} +\end{exercise} + +\begin{exercise} +\begin{code} +\xy *=<3cm,1cm>\txt{Box}*\frm{-} + !U!R(.5) *\frm{..}*{\bullet} \endxy +\end{code} +% + What does this typeset? +% +\displaycode +\noindent + "Hint": ??c![\frm] is defined by the frame extension and just + typesets a frame of the kind indicated by the argument. +% +\answercode +\answertext{The code typesets the picture $$\docode$$} +\end{exercise} + + \BUG: Currently only the single-letter corners (??c![L], ??c![R], + ??c![D], ??c![U], ??c![C], ??c![E], and ??c![P]) will work for any + shape---the others silently assume that the shape is rectangular. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[stack]??=[<stack op>eration] +% + The "stack" is a special construction useful for storing a sequence + of <pos>itions that are accessible using the special + <coord>inates~|s|$n$, where $n$~is either a single digit or a + positive integer in |{}|s: |s0| is always the `top' element of the + stack and if the stack has depth $d$ then the `bottom' element of the + stack has number |s{|$d-1$|}|. The stack is said to be `empty' when + the depth is~$0$ and then it is an error to access any of the |s|$n$ + or `pop' which means remove the top element, shifting what is in |s1| + to |s0|, |s2| to |s1|, etc. Similarly, `push~$c$' means to shift + |s0| to |s1|, etc., and then insert the $c$ as the new |s0|. + + The stack is manipulated as follows: +% +\begin{defs} + |@|<stacking> & Action \cr +\noalign{\nobreak\smallskip\nobreak\hrule\nobreak\smallskip\nobreak}% + ??c![@+]<coord> & push $<coord>$ \cr + ??c![@-]<coord> & $c\from<coord>$ then pop \cr + ??c![@=]<coord> & load stack with <coord> \cr + ??c![@@]<coord> & do $<coord>$ for $c\from$ stack \cr + ??c![@i] & initialise \cr + ??c![@(] & enter new frame \cr + ??c![@)] & leave current frame \cr +\end{defs} +\noindent\unskip +% + To `load stack', means to load the entire stack with the positions + set by <coord> within which |,| means `push $c$'. + + To `do <coord> for all stack elements' means to set $c$ to each + element of the stack in turn, from the bottom and up, and for each + interpret the <coord>. Thus the first interpretation has $c$ set to + the bottom element of the stack and the last has $c$ set to~|s0|. If + the stack is empty, the <coord> is not interpreted at all. + + These two operations can be combined to repeat a particular <coord> + for several points, like this: +% +\begin{code} +\xy + @={(0,-10),(10,3),(20,-5)} @@{*{P}} +\endxy +\end{code} +\displaycode\noindent +% + will typeset +% +$$\docode$$ + + Finally, the stack can be forcibly cleared using |@i|, however, this + is rarely needed because of |@(|, which saves the stack as it is, and + then clears it, such when it has been used (and is empty), and |@)| + is issued, then it is restored as it was at the time of the~|@(|. + +\begin{exercise} + How would you change the example above to connect the points as shown + below? +% +\begin{code} +\xy + @={(0,-10),(10,3),(20,-5)}, + s0="prev" @@{;"prev";**@{-}="prev"} +\endxy +\end{code} +% +$$\docode$$ +% +\answercode +\answertext{This does the job, saving each point to make the previous point + available for the next piece:\displaycode\noindent Notice how we + close the line by first saving |s0|, the last point visited, such + that the first point will be connected to it.} +% +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + First the stack top and bottom, both initially~$-1$: + +\DOCMODE( +\xydef@\s@bot{-1} +\xydef@\s@top{-1} +\DOCMODE) + + Next the function to set $c\from|s|n$, \ie, test that $"bot"\lt + n+"bot"\lt "top"$ and then run the associated stack element. + +\DOCMODE( +\xydef@\cfroms@#1{\tests@{#1}\runs@\outofranges@} + +\xydef@\tests@#1#2#3{\DN@{#3}% + \count@=\s@top \advance\count@-#1\relax + \ifnum\count@>\s@bot\relax \ifnum\count@>\s@top\else\DN@{#2}\fi\fi + \next@} + +\xydef@\runs@{\csname S@\the\count@\endcsname} + +\xydef@\outofranges@{\count@=\s@top \advance\count@-\s@bot + \xyerror@{stack index out of range (should be 0..\the\count@)}{}} +\DOCMODE) + + Finally the actual code to do the stack operations: it depends on the + `code' passed after |@|; spaces are not allowed: + +\DOCMODE( +\xydef@\STACK@{% + \addPLUS@\ifx\next + \addPLUS@\DN@{\xy@{@+}{}\afterCOORD{\xy@@\spushc@ \xyFN@\POS@}}% + \else\addDASH@\ifx\next + \addDASH@\DN@{\xy@{@-}{}\afterCOORD{\xy@@\spop@ \xyFN@\POS@}}% + \else \ifx i\next \DN@ i{\xy@{@i}\sinit@ \xyFN@\POS@}% + \else \ifx (\next \DN@ ({\xy@{@(}\senter@ \xyFN@\POS@}% + \else \ifx )\next \DN@ ){\xy@{@)}\sleave@ \xyFN@\POS@}% + \else\addEQ@\ifx\next \addEQ@\DN@{\STACK@load}% + \else\addAT@\ifx\next \addAT@\DN@{\xy@{@@}{}\smap@}% + \else \DN@##1{\xyerror@{illegal stack command ##1}{}\afterCOORD{\xyFN@\POS@}}% + \fi\fi\fi\fi\fi\fi\fi \next@} + +\xydef@\STACK@load{\xy@{@=}{% + \if\sempty@\else \xywarning@{loading on top of non-empty stack}\sinit@ \fi + \let\comma@@=\spushc@}% + \afterCOORD{\xy@@{\spushc@ \let\comma@@=\relax}\xyFN@\POS@}} + +\xydef@\spushc@{% + \count@=\s@top \advance\count@\@ne \edef\s@top{\the\count@}% + \expandafter\edef\csname S@\s@top\endcsname{\cfromthec@}} + +\xydef@\spushid@#1{\DNii@{#1}\edef\nextii@{\codeof\nextii@}% + \expandafter\let\expandafter\next@\csname Q@\nextii@\endcsname + \ifx\next@\relax \xyerror@{<pos> \string"\nextii@\string" not defined}{}% + \else + \count@=\s@top \advance\count@\@ne \edef\s@top{\the\count@}% + \DNii@##1{\expandafter\def\csname S@\s@top\endcsname{##1}}% + \expandafter\nextii@\expandafter{\next@}% + \fi} + +\xydef@\idfroms@#1#2{% + \tests@{#2}{\DN@{\idfromxy@{#1}}% + \expandafter\expandafter\expandafter\next@ + \expandafter\expandafter\expandafter{\csname S@\the\count@\endcsname}% + }\outofranges@} + +\xydef@\spop@{\count@=\s@top + \ifnum\count@>\s@bot \advance\count@\m@ne \edef\s@top{\the\count@}% + \else \xyerror@{nothing to pop from stack}{}\fi} + +\xydef@\sinit@{\edef\s@top{\s@bot}} + +\xydef@\senter@{% + \count@=\s@top \advance\count@\@ne + \expandafter\edef\csname S@\the\count@\endcsname{\s@bot}% + \edef\s@bot{\the\count@}\edef\s@top{\the\count@}} + +\xydef@\sleave@{% + \ifnum\s@bot=\s@top\else \xywarning@{leaving non-empty stack}\sinit@ \fi + \ifnum\s@bot>\m@ne \edef\s@bot{\csname S@\s@top\endcsname}% + \count@=\s@top \advance\count@\m@ne \edef\s@top{\the\count@}% + \edef\sbot{\the\count@}\fi} + +\xydef@\sempty@{\ifnum\s@top=\s@bot TT\else TF\fi} +\DOCMODE) + + |\smap@| maps a <coord> over a stack: + +\DOCMODE( +\xydef@\xytotoks@#1#2{\addtotoks@{#2}} +\xydef@\xytotoks@@toksix@#1{\addtotoks@{\toks9={#1}}} + +\xydef@\smap@{% + \begingroup \toks@={}\let\xy@=\xytotoks@ \change@oxy@\xy@ + \let\xy@@ix@=\xytotoks@@toksix@ + \afterCOORD{\expandafter\endgroup + \expandafter\smapxy@@\expandafter{\the\toks@}\xyFN@\POS@}} + +\xydef@\smapxy@@#1{\xy@@{\edef\smapp@@{\s@bot}\smapxy@i{#1}}} + +\xylet@\smapp@@=\empty + +\xydef@\smapxy@i#1{% + \ifnum\smapp@@<\s@top + \count@=\smapp@@ \advance\count@\@ne \edef\smapp@@{\the\count@}% + \DN@{\csname S@\smapp@@\endcsname #1\relax \smapxy@i{#1}}% + \else \let\next@=\relax + \fi \next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[save]??=[saved] +% + It is possible to define new <coord>inates on the form |"|<id>|"| by + "saving" the current $c$ using the \dots|="|<id>|"| <pos>ition form. + Subsequent uses of |"|<id>|"| will then reestablish the $c$ at the + time of the saving. + + Using a |"|<id>|"| that was never defined is an error, however, + saving into a name that was previously defined just replaces the + definition without warning, \ie, |"|<id>|"| always refers to the last + thing saved with that <id>. + + However, many other things can be `saved': in general |@|<saving> has + either of the forms +% +\begin{defs} + |@:"|<id>|"| & |"|<id>|"| restores current "base" \cr + |@|<coord>|"|<id>|"| & |"|<id>|"| reinterprets <coord> \cr + |@@"|<id>|"| & |@="|<id>|"| reloads this stack \cr +\end{defs} +\noindent\unskip +% + The first form defines |"|<id>|"| to be a macro that restores the + current "base". + + The second does not depend on the state at the time of definition at + all; it is a macro definition. You can pass parameters to such a + macro by letting it use coordinates named |"1"|, |"2"|, etc., and + then use |="1"|, |="2"|, etc., just before every use of it to set the + actual values of these. \NOTE: it is not possible to use a <coord> + of the form |"|<id>|"| directly: write it as |{"|<id>|"}|. +% +\begin{exercise} + Write a macro |"dbl"| to double the size of the current~$c$ object, + \eg, changing it from the dotted to the dashed outline in this + figure: +% +\begin{code} +\xy ={.{+DL(2)}.{+UR(2)}}"dbl", + *+<3pc,2pc>{+}*\frm{.}, "dbl"*\frm{--} +\endxy +\end{code} +$$ +\docode +$$ +\answercode +\answertext{The author used \displaycode\noindent to typeset the figure in + the exercise.} +\end{exercise} + + The final form defines a special kind of macro that should only be + used after the |@=| stack operation: the entire current stack is + saved such that the stack operation |@="|<id>|"| will reload it. + + \NOTE: There is no distinction between the `name spaces' of <id>s + used for saved coordinates and other things. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This parser distinguishes between the cases: + +\DOCMODE( +\xydef@\saveid@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\saveid@}%gobble spaces + \else \ifx "\next\DN@"##1"{\xy@{="##1"}{\idfromc@{##1}}\xyFN@\POS@}% + \else \ifx :\next\DN@:##1"##2"{\xy@{=:"##2"}{\idfrombase@{##2}}\xyFN@\POS@}% + \else\addAT@\ifx\next + \addAT@\DN@"##1"{\xy@{=@"##1"}{\idfromstack@{##1}}\xyFN@\POS@}% + \else \ifx s\next + \DN@ s##1"##2"{\xy@{=s##1"##2"}{\idfroms@{##2}{##1}}\xyFN@\POS@}% + \else\addEQ@\ifx\next \let\saveid@COORD@@=\saveid@COORDii + \addEQ@\DN@{\xyFN@\saveid@COORD}% + \else \let\saveid@COORD@@=\saveid@COORDi \let\next@=\saveid@COORD + \fi\fi\fi\fi\fi\fi \next@} + +\xylet@\saveid@COORD@@=\relax +\DOCMODE) + + Here is the code for saving/restoring a position and a base. + +\DOCMODE( +\xydef@\idfromc@#1{\DN@{#1}% + \expandafter\edef\csname Q@\codeof\next@\endcsname{\cfromthec@}} + +\xydef@\idfrombase@#1{\DN@{#1}% + \expandafter\edef\csname Q@\codeof\next@\endcsname{\basefromthebase@}} + +\xydef@\idfromstack@#1{% + \toks@={\if\sempty@\else + \xywarning@{loading on top of non-empty stack}\sinit@ \fi}% + \count@=\s@bot \advance\count@\@ne + \ifnum\count@>\s@top\else + \loop@ + \expandafter\let\expandafter\next@\csname S@\the\count@\endcsname + \expandafter\addtotoks@\expandafter{\next@}% + \ifnum\count@<\s@top \advance\count@\@ne \addtotoks@{\spushc@}\repeat@ + \fi + \DN@{#1}\edef\next@##1{% + \def\expandafter\noexpand\csname Q@\codeof\next@\endcsname{##1}}% + \expandafter\next@\expandafter{\the\toks@}} + +\xydef@\saveid@COORD{% + \begingroup \toks@={}\let\xy@=\xytotoks@ \change@oxy@\xy@ + \let\xy@@ix@=\xytotoks@@toksix@ + \afterCOORD{\expandafter\saveid@COORDi\expandafter{\the\toks@}}} + +\xydef@\saveid@COORDi#1#2"#3"{\endgroup \xy@@{\idfromxy@{#3}{#1}}\xyFN@\POS@} +\xydef@\saveid@COORDii#1#2"#3"{\endgroup \xy@@{\idfromcxy@{#3}{#1}}\xyFN@\POS@} + +\xydef@\idfromxy@#1#2{\DN@{#1}% + \expandafter\def\csname Q@\codeof\next@\endcsname{#2}} + +\xydef@\idfromcxy@#1#2{\DN@{#1}% + \expandafter\edef\csname Q@\codeof\next@\endcsname{\cfromthec@#2}} + +\xydef@\cfromid@#1{\DNii@{#1}\edef\nextii@{\codeof\nextii@}% + \expandafter\let\expandafter\next@\csname Q@\nextii@\endcsname + \ifx\next@\relax \xyerror@{<pos> \string"\nextii@\string" not defined}{}% + \else \expandafter\next@\fi} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\end{notes} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Objects} +??=[object] + +\DOCMODE( +\message{objects,} +\DOCMODE) + + Objects are the entities that are manipulated with the |*| and |**| + <pos> operations above to actually get some output in \Xy-pictures. + As for <pos>itions the operations are interpreted strictly from left + to right, however, the actual object is built "before" all the + <modifier>s take effect. The syntax of objects is given in + figure~??[f.object] with references to the notes below. \REMARK: It + is "never" allowed to include braces |{}| inside <modifier>s! In + case you wish to do something that requires |{|\dots|}| then check in + this manual whether you can use |(*|\dots|*)| instead. If not then + you will have to use a different construction! + +\begin{figure*}[tp] +\begin{syntax} +% + ??w![<object>] + &\iss & <modifier> <object> + & apply <modifier> to <object> +\cr + &\orr & <objectbox> + & build <objectbox> then apply its <modifier>s +\cr +\noalign{\smallbreak} +% +\cr + ??w![<objectbox>] + &\iss & |{| <text> |}| + & ??!^[build default] object +\cr + &\orr & <library object> \orr\ |@|<dir> + & use <library object> or <dir>ectional (see~\S??[objectlib]) +\cr + &\orr & <\TeX\ box> |{| <text> |}| + & ??!^[build box] object with <text> using the given <\TeX\ box> + command, \eg, ??c![\hbox] +\cr + &\orr & ??c![\object] <object> + & wrap up the <object> as a ??!^[finished object box] +\cr + &\orr & ??c![\composite] |{| <composite> |}| + & build ??!^[composite object box] +\cr + &\orr & ??c![\xybox] |{| <pos> <decor> |}| + & package ??!^[entire \Xy-picture as object] +\cr +\noalign{\smallbreak} +% + ??w![<modifier>] + &\iss & |!| <vector> + & <object> has its reference point ??!^[shifted] by <vector> +\cr + &\orr & |!| + & <object> has the original reference point reinstated +\cr + &\orr & <add op> <size> + & change ??!^[<object> size] +\cr + &\orr & ??c![h] \orr\ ??c![i] + & <object> is ??!^[hidden], ??!^[invisible] +\cr + &\orr & |[| <shape> |]| + & <object> is given the specified ??!^[<shape>] +\cr + &\orr & ??c![[=] <shape> |]| + & ??!^[define <shape>] to reestablish ??w![current object style] +\cr + &\orr & <direction> + & set current direction for this <object> +\cr +\noalign{\smallbreak} +% + ??w![<add op>] + &\iss & |+| \orr\ |-| \orr\ |=| \orr\ |+=| \orr\ |-=| + & grow, shrink, set, grow to, shrink to +\cr +\noalign{\smallbreak} +% + ??w![<size>] + &\iss & <empty> + & ??!^[default size] +\cr + &\orr & <vector> + & size as sides of rectangle covering the <vector> +\cr +\noalign{\smallbreak} +% + ??w![<direction>] + &\iss & <diag> + & <diag>onal ??!^[direction] +\cr + &\orr & ??c![v] <vector> + & ??!^[direction] of <vector> +\cr + &\orr & ??c![q]|{| <pos> <decor> |}| + & ??!^[direction] from $p$ to $c$ after <pos> <decor> +\cr + &\orr & <direction> ??c![:] <vector> + & vector relative ??!^[to <direction>] +\cr + &\orr & <direction> |_| \orr\ <direction> |^| + & $90^\circ$ clockwise/anticlockwise ??!^[to <direction>] +\cr +% + ??w![<diag>] + &\iss & <empty> + & last used direction (not necessarily ??!^[diagonal]) +\cr + &\orr & |l|\orr|r|\orr|d|\orr|u| + & left, right, down, up ??!^[diagonal] +\cr + &\orr & |ld|\orr|rd|\orr|lu|\orr|ru| + & left/down, \dots\ ??!^[diagonal] +\cr +\noalign{\smallbreak} +% + ??w![<composite>] + &\iss & <object> + & first object is required +\cr + &\orr & <composite> |*| <object> + & add <object> to ??!^[composite object box] +% +\end{syntax} +\caption{\protect<object>s.} +??=[f.object] +\end{figure*} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + We first discuss the parser and then summarise the required methods. + The entry point to use of objects is ??c![\object] described in note + ??[finished object box]. This should always be used because it + initialises the token list and redefines |\xy@| to be |\addtotoks@| + such that we can use <pos> parser routines within the <object>! + +\paragraph*{Parsing:} + + The <object> parser |\OBJECT@| will first parse the <modifier>s, + storing the action of each in sequence on the |\toks@| token list. + When there are no more modifiers we insert ??c![\objectbox] if we have + reached the |{| otherwise we just assume that the rest of the + <object> is some kind of box construction. + + "Note": The <modifier> actions doing shifts are implemented by having + an independent vector for the shift: $|<|R_p|,|U_p|>|$ always + contains the vector from the current to the original \TeX\ reference + point; furthermore the initial $L_c$ is saved as $L_p$ such that we + can retrieve the original (\Xy-pic) reference point again. Modifying + the $p$ values is safe because all actual changes are done in a local + scope after the entire <object> is parsed and we have built the + object box (in |\OBJECT@@|). + + The <modifier>s changing the direction are executed while parsing to + make sure that the direction used when building the <object> is + right, and restored in the right sequence while evaluating the + <modifier>s afterwards. + +\DOCMODE( +\xydef@\OBJECT@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\OBJECT@}%gobble spaces + \else\ifcat A\noexpand\next \let\next@=\OBJECT@letter + \else \let\next@=\OBJECT@other \fi\fi \next@} + +\xydef@\OBJECT@letter{% + \ifx i\next \DN@ i{\addtotoks@\Invisible@true \xyFN@\OBJECT@}% + \else\ifx h\next\DN@ h{\addtotoks@\Hidden@true \xyFN@\OBJECT@}% + \else\ifx o\next\DN@ o{\xywarning@{Obsolete o modifier used}\OBJECT@shape{o}}% + \else\ifx x\next\DN@ x{\xywarning@{Obsolete x modifier used}\OBJECT@shape{}}% + \else\ifx @\next\DN@ @##1##{% +% +\xywarning@{Impossible @ (letter) should not be here!!} +% + \OBJECT@@{\dir##1}}% + \else \let\next@=\OBJECT@direction + \fi\fi\fi\fi\fi \next@} + +\xydef@\OBJECT@other{% + \ifx !\next \DN@!{\OBJECT@shift}% + \else\addPLUS@\ifx \next \DN@{\OBJECT@change}% + \else\addDASH@\ifx \next \DN@{\OBJECT@change}% + \else\addEQ@\ifx \next \DN@{\OBJECT@set}% + \else\ifx [\next %] + \DN@[##1]{\xy@{[##1]}{\OBJECT@shape{##1}}}% + \else\ifx ^\next \let\next@=\OBJECT@direction + \else\ifx _\next \let\next@=\OBJECT@direction + \else\ifx :\next \let\next@=\OBJECT@direction + \else\ifx ?\next + \DN@ ?{\xywarning@{\string? modifier used}\xyFN@\OBJECT@direction}% + \else\ifx (\next %) + \let\next@=\OBJECT@direction + \else\addAT@\ifx\next \addAT@\DN@##1##{\OBJECT@@{\dir##1}}% + \else \DN@##1##{\OBJECT@@{##1}}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi \next@} +\DOCMODE) + + |\OBJECT@@| is where we actually build the box by first + ??_[OBJ0]~saving the previous edge in case it is needed, then + ??_[OBJ1]~setting the defaults (including temporarily resetting + |\xy@| to execute in case any |\xy@|s are used internally), + ??_[OBJ2]~building the object box (which might change them) using + ??c![\objectbox] if no other command specified and setting the + $D,U,L,R$ dimensions ad required using the |\Leftness@| and + |\Upness@| methods, and finally ??_[OBJ3]~setting up the $R_p,U_p$ + dimensions (as discussed above) and applying the <modifier>s stored + in |\toks@| and dumping the modified box. + +\DOCMODE( +\xydef@\prevEdge@@{\zeroEdge} + +\xydef@\OBJECT@@#1#2{% + \expandafter\def\expandafter\prevEdge@@\expandafter{\the\Edge@c}%?*[OBJ0] + \expandafter\Edge@c\expandafter{\objectEdge}%?*[OBJ1] + \Invisible@false\Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}% + \gdef\preXY@style@{}\gdef\postXY@style@{}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@\relax}% + \DN@{#1}\ifx\next@\empty \DNii@{#2}%?*[OBJ2] + \ifx\nextii@\empty \DN@{\hbox\bgroup\no@}\else \let\next@=\objectbox \fi\fi + \setbox\z@=\next@{#2}\L@c=\Leftness@\wdz@ \R@c=\wdz@ \advance\R@c-\L@c + \D@c=\dp\z@ \advance\D@c\ht\z@ \U@c=\Upness@\D@c \advance\D@c-\U@c + \R@p=\z@ \L@p=\L@c \U@p=\U@c \advance\U@p-\ht\z@ \D@p=-\U@p %?*[OBJ3] + \the\toks@\toks@={}\setboxz@h{\kern\R@p \raise\U@p\boxz@}% + \checkZeroEdge@ + \dimen@=\L@c \advance\dimen@\R@c \wdz@=\dimen@ \ht\z@=\U@c \dp\z@=\D@c \boxz@ + \OBJECT@x} + +\xydef@\adjustLR@{% + \ifdim\zz@\wdz@ \L@c=\z@ \R@c=\z@ \dimen@=\Leftness@\p@ + \ifdim\dimen@<\z@ \L@c=\dimen@ \R@c=-\L@c + \else\ifdim\dimen@>\p@ \L@c=\dimen@ \advance\L@c-\p@ \R@c=-\L@c \fi\fi + \else \L@c=\Leftness@\wdz@ \R@c=\wdz@ \advance\R@c-\L@c \fi} + +\xydef@\adjustUD@{\dimen@=\ht\z@ \advance\dimen@\dp\z@ + \ifdim\zz@\dimen@ \U@c=\z@ \D@c=\z@ \dimen@=\Upness@\p@ + \ifdim\dimen@<\z@ \U@c=\dimen@ \D@c=-\L@c + \else\ifdim\dimen@>\p@ \U@c=\dimen@ \advance\U@c-\p@ \D@c=-\L@c \fi\fi + \else \D@c=\dimen@ \U@c=\Upness@\dimen@ \advance\D@c-\U@c \fi} + +\def\checkZeroEdge@{% + \DN@{}% + \ifdim\zz@\L@c \ifdim\zz@\R@c \ifdim\zz@\U@c \ifdim\zz@\D@c + \DN@{\Edge@c={\zeroEdge}}\fi\fi\fi\fi + \next@} +\DOCMODE) + + As an optimisation |\OBJECT@@| sets the edge type of all zero-sized + objects to ??c![\zeroEdge]. + + |\OBJECT@x| cleans up the object by ensuring that it defines all the + required methods: Essentially it terminates the box with the sequence + ``|}| |\def\Drop@@{|\dots|}| |\def\Connect@@{|\dots|}| |\D@c=|\dots\ + |\U@c=|\dots\ |\L@c=|\dots\ |\R@c=|\dots\ | \Invisible@|\dots + |\Hidden@|\dots\ |\def\Leftness@{|\dots|}| |\def\Upness@{|\dots|}|'' + where each \dots\ is set to the method defined within the object + creation environment (started with |\hbox{| in |\OBJECT@@| or + possibly elsewhere). We use rather heavy expansion hacking with + |\toks@| to create the sequence so please look the other + way\dots\smiley + +\DOCMODE( +\xydef@\OBJECT@x{\toks@={\egroup\def\Drop@@}% + \expandafter\addtotoks@\expandafter{\expandafter{\Drop@@}\def\Connect@@}% + \expandafter\addtotoks@\expandafter{\expandafter{\Connect@@}}% + \edef\tmp@{\D@c=\the\D@c \U@c=\the\U@c \L@c=\the\L@c \R@c=\the\R@c + \Edge@c={\expandafter\noexpand\the\Edge@c}% + \ifInvisible@\noexpand\Invisible@true\else\noexpand\Invisible@false\fi + \ifHidden@\noexpand\Hidden@true\else\noexpand\Hidden@false\fi + \def\noexpand\Leftness@{\Leftness@}\def\noexpand\Upness@{\Upness@}}% + \expandafter\addtotoks@\expandafter{\tmp@}\the\toks@} +\DOCMODE) + +\paragraph*{Methods:} +??w[object methods] + + In addition to the ``current object properties'' for $c$ + (\cf~??[basics.state]) the following methods are set up by all + objects: + +\begin{defs} + |\Invisible@true| or |\Invisible@false| & whether object is ??!^[invisible]\cr + |\Hidden@true| or |\Hidden@false| & whether object is ??!^[hidden]\cr + |\def\Leftness@{|<factor>|}| & the desired $L/(L+R)$\cr + |\def\Upness@{|<factor>|}| & the desired $U/(D+U)$\cr + |\def\Drop@@{|\dots|}| & code that outputs the object, assuming |\boxz@| is + of zero size and has the object displaced $|<|X|,|Y|>|$ + inside---usually just |\def|'d to |\styledboxz@|\cr + |\def\Connect@@{|\dots|}| & code that builds a connection from $p$ to $c$, + assuming |\last|\-|object|\-|box@| contains the object\cr +\end{defs} + + It is important to |\def| and not |\let| the last four methods since + the \TeX\-nique used in |\OBJECT@x| (and elsewhere) of passing them + to surrounding scopes depends on it. The |\Connect@@| method should + in turn setup several submethods as described in detail in + ??[algo.connection]. + + Suitable defaults are set up by |\OBJECT@@| above which is why any + box generating command can be used to construct objects as explained + in note ??[build default] below. + + Here are the declarations: + +\DOCMODE( +\xynew@{if}\ifInvisible@ +\xynew@{if}\ifHidden@ + +\xydef@\Leftness@{} +\xydef@\Upness@{} + +\xydef@\Drop@@{\styledboxz@} +\xydef@\Connect@@{} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{notes} +% +\note??=[build default] +% + An <object> is built using |\object|\-|box|??c[\objectbox] + |{|<text>|}|. |\object|\-|box| is initially defined as +% +\begin{code} +\def\objectbox#1{% + \hbox{$\objectstyle{#1}$}} +\let\objectstyle=\displaystyle +\end{code} +\displaycode +% + but may be redefined by options or the user. The <text> should thus + be in the mode required by the ??c![\objectbox] command---with the + default |\objectbox| shown above it should be in math mode. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + Actually it is + +\DOCMODE( +\xydef@\objectbox#1{\hbox{$\m@th\objectstyle{#1}$}} + +\xylet@\objectstyle=\textstyle +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[build box] +% + An <object> built from a \TeX\ box with dimensions $w*(h+d)$ will + have $L_c=R_c=w/2$, $U_c=D_c=(h+d)/2$, thus initially be equipped + with the adjustment |!C| (see note~??[shifted]). In particular: in + order to get the reference point on the (center of) the base line of + the original <\TeX~box> then you should use the <modifier> |!|; to + get the reference point identical to the \TeX\ reference point use + the modifier |!!L|. + + \TeX\-nical remark: Any macro that expands to something that starts + with a <box> may be used as a <\TeX~box> here. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + This is done by the parsing above. +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[finished object box] +% + Takes an object and constructs it, building a box; it is then + processed according to the preceeding modifiers. This form makes it + possible to use any <object> as a \TeX\ box (even outside of + \Xy-pictures) because a finished object is always also a box. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This macro is the main entry point to the <object> parser. It + furthermore initialises the modifier list and the previous object + edge. + +\DOCMODE( +%\xydef@\object{\hbox\bgroup\object@} +\xydef@\object{\hbox\bgroup\resetStyle@\object@} + +\xydef@\object@{% + \edef\next@{={\DirectionfromtheDirection@}}\expandafter\toks@\next@ +% \resetStyle@\plainxy@ \xyFN@\OBJECT@} + \plainxy@ \xyFN@\OBJECT@} +\DOCMODE) + + The initial value of |\toks@| <modifier> list is explained in + note~??[direction] below. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[composite object box] +% + Several <object>s can be combined into a single object using the + special command ??c![\composite] with a list of the desired objects + separated with |*|s as the argument. The resulting box (and object) + is the least rectangle enclosing all the included objects. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + First we collect all the objects smash on top of each other in box0 + while we maintain the maximal extents in $(DULR)_p$. Then we reset + box0 to contain the same but with the right spacing around. + +\DOCMODE( +\xydef@\composite#1#{\hbox\bgroup\composite@{#1}} + +\xydef@\composite@#1#2{% + \DN@{#1}\ifx\next@\empty\else\xywarning@{no variants of + \string\composite\space allowed}\fi + \global\setbox9=\hbox\bgroup + \D@p=-\maxdimen \U@p=-\maxdimen \L@p=-\maxdimen \R@p=-\maxdimen + \xyFN@\composite@i#2@} + +\xydef@\composite@i{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\composite@i}%gobble spaces + \else\ifx *\next \DN@ *{\xyFN@\composite@i}% + \else\ifx @\next \DN@ @{\composite@x}% + \xyerror@{<composite> object expected}{}\czeroEdge@ + \else \DN@{\composite@ii}\fi\fi\fi \next@} + +\xydef@\composite@ii#1#{\composite@iii{#1}} + +\xydef@\composite@iii#1#2{% + \setbox\z@=\object#1{#2}% + \ifInvisible@ \setboxz@h{}\else + \setboxz@h{\kern-\L@c \boxz@}\ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ {\Drop@@}\fi + \ifHidden@\else + \ifdim\U@p<\U@c \U@p=\U@c \fi \ifdim\D@p<\D@c \D@p=\D@c \fi + \ifdim\R@p<\R@c \R@p=\R@c \fi \ifdim\L@p<\L@c \L@p=\L@c \fi + \fi + \xyFN@\composite@iv} + +\xydef@\composite@iv{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\composite@iv}%gobble spaces + \else \ifx @\next \DN@ @{\composite@x}% + \else \let\next@=\composite@i \fi\fi \next@} + +\xydef@\composite@x{% + \edef\tmp@{\egroup + \D@c=\the\D@p \U@c=\the\U@p \L@c=\the\L@p \R@c=\the\R@p}\tmp@ + \setboxz@h{\kern\L@c\box9}\ht\z@=\U@c \dp\z@=\D@c + \dimen@=\L@c \advance\dimen@\R@c \wdz@=\dimen@ + \Edge@c={\rectangleEdge}\computeLeftUpness@ \boxz@ + \OBJECT@x} + +\xydef@\computeLeftUpness@{% + \dimen@=\L@c \advance\dimen@\R@c + \ifdim\zz@\dimen@ \def\Connect@@{\straight@{\dottedSpread@\jot}}% + \ifdim\zz@\L@c\else + \DN@{\zeroEdge}\expandafter\DNii@\expandafter{\the\Edge@c}% + \ifx\next@\nextii@\Edge@c={\rectangleEdge}\fi\fi + \else \quotient@\Leftness@\L@c\dimen@ \fi + \dimen@=\U@c \advance\dimen@\D@c + \ifdim\zz@\dimen@ \def\Connect@@{\straight@{\dottedSpread@\jot}}% + \ifdim\zz@\U@c\else + \DN@{\zeroEdge}\expandafter\DNii@\expandafter{\the\Edge@c}% + \ifx\next@\nextii@\Edge@c={\rectangleEdge}\fi\fi + \else \quotient@\Upness@\U@c\dimen@ \fi} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note ??=[entire \Xy-picture as object] +% + Take an entire \Xy-picture and wrap it up as a box as described + in~\S??[basics.pos]. Makes nesting of \Xy-pictures possible: the + inner picture will have its own zero point which will be its + reference point "in" the outer picture when it is placed there. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This is simple exploiting the fact that |\endxy| actually sets up the + extents of the `object': + +\DOCMODE( +\xydef@\xybox#1{\xy#1\endxy \Edge@c={\rectangleEdge}\computeLeftUpness@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[shifted] +% + An object is "shifted" a <vector> by moving the point inside it which + will be used as the reference point. This effectively pushes the + object the same amount in the opposite direction. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Shifting uses the special value of $R_p$ and $U_p$ used while + evalutaing the <modifier>s. The fact that shifts like |!C| refer to + the initial object's size means that we should parse the <vector> + such that its actions happen at modification time\dots hence + |\xytotoks@| is used to delay execution. + +\DOCMODE( +\xydef@\OBJECT@shift{% + \let\xy@=\xytotoks@ \afterVECTORorEMPTY + {\OBJECT@shift@}% + {\addtotoks@{\X@c=-\L@c \advance\X@c\R@p \advance\X@c\L@p \Y@c=\U@p}% + \OBJECT@shift@}} + +\xydef@\OBJECT@shift@{% + \addtotoks@{\advance\U@p-\Y@c + \advance\L@c\X@c \advance\R@c-\X@c \advance\D@c\Y@c \advance\U@c-\Y@c + \computeLeftUpness@}% + \let\xy@=\oxy@ \xyFN@\OBJECT@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{exercise} + What is the difference between the <pos>itions |0*{a}!DR| and + |0*!DR{a}|? +\answertext{The first typesets ``$a$'' centered around |0| and then moves $c$ + to the lower right corner, the second typesets ``$a$'' above the |0| + point and does not change $c$. With a ``$+$'' at |0| they look like + this: $\vcenter{\xy*{+}*{a}!DR\endxy}$ and + $\vcenter{\xy*{+}*!DR{a}\endxy}$.}% +\end{exercise} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[<object> size]??=[change size]??=[<size>]??=[default size] +% + A <size> is a pair $|<|W|,|H|>|$ of the width and height of a + rectangle. When given as a <vector> these are just the vector + coordinates, \ie, the <vector> starts in the lower left corner and + ends in the upper right corner. The possible <add op>erations that + can be performed are described in the following table. +$$ +\begin{array}{\otherbar c\otherbar l\otherbar} +\hline + \hbox{<add op>} & \hbox{description} \\ +\hline + |+| & \hbox{grow} \\ + |-| & \hbox{shrink} \\ + |=| & \hbox{set to} \\ + |+=| & \hbox{grow to at least} \\ + |-=| & \hbox{shrink to at most} \\ +\hline +\end{array} +$$ + In each case the <vector> may be omitted which invokes the ``default + size'' for the particular <add op>: +$$ +\begin{array}{\otherbar c\otherbar l\otherbar} +\hline + \hbox{<add op>} & \hbox{default}\\ +\hline + |+| & |+<|2*"objectmargin"|>| \\ + |-| & |-<|2*"objectmargin"|>| \\ + |=| & |=<|"objectwidth"|,|"objectheight"|>| \\ + |+=| & |+=<|\max(L_c+R_c,D_c+U_c)|>| \\ + |-=| & |-=<|\min(L_c+R_c,D_c+U_c)|>| \\ +\hline +\end{array} +$$ + The defaults for the first three are set with the commands +% +\begin{defs1} + ??c![\objectmargin] <add op> |{|<dimen>|}| \cr + ??c![\objectwidth] <add op> |{|<dimen>|}| \cr + ??c![\objectheight] <add op> |{|<dimen>|}| \cr +\end{defs1} +\noindent\unskip +% + where <add op> is interpreted in the same way as above. + +\DOCMODE( +\xylet@\objectmargin@=\jot +\xylet@\objectwidth@=\z@ +\xylet@\objectheight@=\z@ + +\xydef@\objectmargin{\afterADDOP{\Addop@@\objectmargin@}} +\xydef@\objectwidth{\afterADDOP{\Addop@@\objectwidth@}} +\xydef@\objectheight{\afterADDOP{\Addop@@\objectheight@}} +\DOCMODE) + + The defaults for |+=|/|-=| are such that the resulting object will be + the smallest containing/largest contained square. + +\begin{exercise} + How are the objects typeset by the <pos>itions ``|*+UR{\sum}|'' and + ``|*+DL{\sum}|'' enlarged? +\answertext{They have the outlines + $$\xy*+UR{\sum}*\frm{-}*{+}\endxy + \quad\textrm{and}\quad + \xy*+DL{\sum}*\frm{-}*{+}\endxy$$ + because the first is enlarged by the positive offset to the upper + right corner and the second by the negative offset to the lower left + corner.} +\end{exercise} + + \BUG: Currently changing the size of a circular object is buggy---it + is changed as if it is a rectangle and then the change to the $R$ + parameter affects the circle. This should be fixed probably by a + generalisation of the |o| shape to be ovals or ellipses with + horizontal/vertical axes. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The three cases distinguished by the parsing above are handled + similarly: they insert the parsed/default vector into $X,Y$ in the + modifications and then perform the operation at that time using the + |\xytotoks@| trick described in note~??[shifted]: + +\DOCMODE( +\xydef@\OBJECT@change{% + \afterADDOP{% + \addEQ@\ifx \next + \addtotoks@{\X@c=\D@c \advance\X@c\U@c \Y@c=\L@c \advance\Y@c\R@c}% + \else + \addtotoks@{\X@c=\objectmargin@ \advance\X@c\X@c \Y@c=\X@c}% + \fi + \let\xy@=\xytotoks@ + \afterVECTORorEMPTY\OBJECT@change@\OBJECT@change@}} + +\xydef@\OBJECT@set{% + \afterADDOP{% + \let\xy@=\xytotoks@ \afterVECTORorEMPTY\OBJECT@change@ + {\addtotoks@{\X@c=\objectwidth@ \Y@c=\objectheight@}\OBJECT@change@}}} +\DOCMODE) + + The real work is done by the following command: a hack using + expansion tricks to make use of the |\Addop@@| known now on the + values in $X,Y$ at modification time. + +\DOCMODE( +\xydef@\OBJECT@change@{% + \addtotoks@{\advance\R@c\L@c \advance\R@p-\L@c \let\tmp@=\R@c}% + \expandafter\addtotoks@\expandafter{\Addop@@\tmp@\X@c\R@c=\tmp@ + \L@c=\Leftness@\R@c \advance\R@p\L@c \advance\R@c-\L@c}% + \addtotoks@{\advance\D@c\U@c \let\tmp@=\D@c}% + \expandafter\addtotoks@\expandafter{\Addop@@\tmp@\Y@c\D@c=\tmp@ + \U@c=\Upness@\D@c \advance\D@c-\U@c}% + \let\xy@=\oxy@ \xyFN@\OBJECT@} +\DOCMODE) + + It is clearly crucial that |\Addop@@| expands to its action + immediately! Also note that enlarging changes the initial box offset + in the horizontal direction only, \ie, $R_p$. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Finally the code to interpret an <add op> used above: This + simply parses it and creates a macro |\Addop@@| that takes a + control sequence and a parameter <dimen> as arguments, and + expands directly to commands that perform the <add op> of the + <dimen> on the control sequence: +$$ +\begin{array}{\otherbar c\otherbar l\otherbar} +\hline + \hbox{<add op>} & \hbox{effect of |\Addop@@| "cs" $D$} \\ +\hline + |+| & "cs" \from "cs"+D \\ + |-| & "cs" \from "cs"-D \\ + |=| & "cs" \from D \\ + |+=| & "cs" \from \left\{ + \begin{array}{cc} D & \hbox{if $D\le"cs"$} \\ + "cs" & \hbox{if $D\gt"cs"$} \end{array}\right. + \\[1pt] + |-=| & "cs" \from \left\{ + \begin{array}{cc} D & \hbox{if $D\ge"cs"$} \\ + "cs" & \hbox{if $D\lt"cs"$} \end{array}\right. + \\[1pt] +\hline +\end{array} +$$ + Furthermore ??c![\afterADDOP] leaves the |\next| token set to |=| in + the last three cases only (this is used to determine the right + default value in the size changes above). + + The ??c![\afterADDOP] macro is relatively simple because <add op>s + don't nest: + +\DOCMODE( +\xydef@\afterADDOP#1{\def\afterADDOP@{#1}\xyFN@\ADDOP@} + +\xylet@\afterADDOP@=\empty + +\xydef@\ADDOP@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\ADDOP@}%gobble spaces + \else\addPLUS@\ifx \next \addPLUS@\DN@{\xyFN@\ADDOP@plus}% + \else\addDASH@\ifx \next \addDASH@\DN@{\xyFN@\ADDOP@minus}% + \else\addEQ@\ifx \next + \addEQ@\DN@{\def\Addop@@{\Addop@0+=}\afterADDOP@}% + \else + \DN@{\def\Addop@@{\Addop@0+=}\afterADDOP@}% + \fi\fi\fi\fi \next@} + +\xydef@\ADDOP@plus{% + \addEQ@\ifx \next + \addEQ@\DN@{\def\Addop@@{\Addop@0+<}\afterADDOP@}% + \else + \DN@{\def\Addop@@{\Addop@1+=}\afterADDOP@}% + \fi \next@} + +\xydef@\ADDOP@minus{% + \addEQ@\ifx \next + \addEQ@\DN@{\def\Addop@@{\Addop@0+>}\afterADDOP@}% + \else + \DN@{\def\Addop@@{\Addop@1-=}\afterADDOP@}% + \fi \next@} +\DOCMODE) + + The work is done by the general |\Addop@| |{|$f$|}| |{|$\pm$|}| + |{|$\bowtie$|}| |{|"cs"|}| $D$ that defines +$$ +"cs" \equiv \left\{ + \begin{array}{ll} + f*"cs"~{\pm}~D & \hbox{if $\lnot ((f*"cs"~{\pm}~D)~{\bowtie}~D)$} \\ + "cs" & \hbox{otherwise} \end{array}\right. +$$ + and also leaves the dimension in |\dimen@|. + +\DOCMODE( +\xydef@\Addop@#1#2#3#4#5{% + \dimen@=#4\relax \edef#4{\the\dimen@}% + \dimen@=#1\dimen@ \advance\dimen@#2#5\relax %\advance\dimen@ 1sp %HACK + \ifdim\dimen@#3#4\else \edef#4{\the\dimen@}\fi + \ifx\xy@\xyinitial@\else \DN@##1{\xy@@{\edef#4{##1}\checkZeroEdge@}}% + \expandafter\next@\expandafter{#4}\fi} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[hidden] +% + A "hidden" object will be typeset but hidden from \Xy-pic in that it + won't affect the size of the entire picture as discussed + in~\S??[basics.pos]. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + This is handled by the |\ifHidden@| conditional allocated with the + methods. +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[invisible] +% + An "invisible" object will be treated completely normal except that + it won't be typeset, \ie, \Xy-pic will behave as if it was. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + This is handled by the |\ifInvisible@| conditional allocated with the + methods. +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[<shape>] +% + Setting the "shape" of an object forces the shape of its edge to be + as indicated. The kernel provides three shapes that change the edge, + namely ??C![.], ??C![], and ??C![o], corresponding to the outlines +$$ +\let\objectstyle=\scriptstyle +\xy*{*}\endxy +\quad +\textrm{,} +\quad +\xy(0,0).(-10,-4).(15,7)*\frm{-}="box"*{*}+0; + "box"+L*{}**@{.}?*{L}, + "box"+R*{}**@{.}?*{R}, + "box"+D*{}**@{.}?*{D}, + "box"+U*{}**@{.}?*{U} +\endxy +\quad +\textrm{, and} +\quad +\xy*[o]=<40pt>{*}="box"*\cir{}+0; + "box"+L*{}**@{.}?*{L}, + "box"+R*{}**@{.}?*{R}, + "box"+D*{}**@{.}?*{D}, + "box"+U*{}**@{.}?*{U} +\endxy +$$ + where the $*$ denotes the point of the reference position in the + object (the first is a point). Extensions can provide more shapes, + however, all shapes set the extent dimensions $L$, $R$, $D$, + and $U$. + + The default shape for objects is ??C![] and for plain coordinates it + is ??C![.]. + +\DOCMODE( +\xydef@\objectEdge{\rectangleEdge} +\DOCMODE) + + Furthermore the <shape>s ??C![r], ??C![l], ??C![u], and ??C![d], are + defined for convenience to adjust the object to the indicated side by + setting the reference point such that the reference point is the same + distance from the opposite of the indicated edge and the two + neighbour edges but never closer to the indicated side than the + opposite edge, \eg, the object |[r]\hbox{Wide text}| has reference + point at the $*$ in $\xy*[r]\hbox{Wide text}*\frm{-}*{*}\endxy$ but + the object |[d]\hbox{Wide text}| has reference + point at the $*$ in $\xy*[d]\hbox{Wide text}*\frm{-}*{*}\endxy$. + Finally, ??C![c] puts the reference point at the center. + +\DOCMODE( +\xydefcsname@{shape [r]}{\advance\U@p\D@c \centerobject@ + \ifdim\L@c>\D@c + \advance\R@c\L@c \L@c=.5\U@c \advance\L@c.5\D@c \advance\R@c-\L@c \fi + \advance\U@p-\D@c} +\xydefcsname@{shape [l]}{\advance\U@p\D@c \centerobject@ + \ifdim\L@c>\D@c + \advance\L@c\R@c \R@c=.5\U@c \advance\R@c.5\D@c \advance\L@c-\R@c \fi + \advance\U@p-\D@c} +\xydefcsname@{shape [u]}{\advance\U@p\D@c \centerobject@ + \ifdim\D@c>\L@c + \advance\U@c\D@c \D@c=.5\L@c \advance\D@c.5\R@c \advance\U@c-\D@c \fi + \advance\U@p-\D@c} +\xydefcsname@{shape [d]}{\advance\U@p\D@c \centerobject@ + \ifdim\D@c>\L@c + \advance\D@c\U@c \U@c=.5\L@c \advance\U@c.5\R@c \advance\D@c-\U@c \fi + \advance\U@p-\D@c} +\xydefcsname@{shape [c]}{\advance\U@p\D@c \centerobject@ \advance\U@p-\D@c} + +\xydef@\centerobject@{% + \advance\D@c\U@c \D@c=.5\D@c \U@c=\D@c \advance\L@c\R@c \L@c=.5\L@c \R@c=\L@c} +\DOCMODE) + + \NOTE: Extensions can add new <shape> object <modifier>s which are + then called <style>s. These will always be either of the form + |[|<keyword>|]| or |[|<character> <argument>|]|. Some of these + <style>s do other things than set the edge of the object. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + A ``simple shape'' is just a control sequence |\shape [|<shape>|]| + setting the appropriate edge. When such a |[|<shape>|]| modifier is + encountered then we expand this control sequence onto the modifier + queue, unless a control sequence |\style [|<shape>|]| exists: then + that is expected to do it (and whatever else is required). + +\DOCMODE( +\xydef@\OBJECT@shape#1{\DN@{shape [#1]}% + \expandafter\let\expandafter\nextii@\csname\codeof\next@\endcsname + \ifx\nextii@\relax\DN@{style [#1]}% + \expandafter\let\expandafter\nextii@\csname\codeof\next@\endcsname + \ifx\nextii@\relax \DN@{\OBJECT@shapei[#1]}% + \else\DN@{\nextii@\xyFN@\OBJECT@}\fi + \else \expandafter\addtotoks@\expandafter{\nextii@}% + \DN@{\xyFN@\OBJECT@}% + \fi \next@} + +\xydefcsname@{shape []}{\the\Edge@c5\relax}% +\xydefcsname@{shape [Outer]}{\the\Edge@c5\relax}% +\xydefcsname@{shape [Inner]}{\the\Edge@c4\relax}% +\xydefcsname@{shape [o]}{\Edge@c={\circleEdge}\the\Edge@c5\relax + \Edge@c={\circleEdge}\def\prevEdge@@{\circleEdge}} +\xydefcsname@{shape [.]}{\czeroEdge@} +\DOCMODE) + + Add more simple shapes by defining more commands like these and + proceed with coding the |\|\dots|Edge| command as described + in~\S??[algo.edge]. + + Alternatively it is a ``complex shape'' of which none are defined in + the kernel but some options like more variation\dots It is + characterised by its first token and the rest of the contents of the + ??C![]s is the argument (remember: no |{}[]| characters!); it is + searched for as control sequence |\[|<shape>|...]| overridden + in the same way by |\*stylechar@|<shape>|@|. + +\DOCMODE( +\def\OBJECT@shapei[#1#2]{\DN@{shape [#1...]}% + \expandafter\let\expandafter\next\csname\codeof\next@\endcsname + \ifx\next\relax\DN@{*stylechar@#1@}% + \expandafter\let\expandafter\next\csname\codeof\next@\endcsname + \ifx\next\relax\DNii@{shape [#1#2]}% + \xywarning@{illegal [<shape>] ignored: \codeof\nextii@\space not defined}% + \DN@{\xyFN@\OBJECT@}% + \else% Delete this: \expandafter\addtotoks@\expandafter{\next{#2}}% + \DN@{\next{#2}\xyFN@\OBJECT@}% + \fi + \else + +\expandafter\addtotoks@\expandafter{\next{#2}}\DN@{\next{#2}\xyFN@\OBJECT@}% + \fi \next@} +\DOCMODE) + + \BUG: The above is messy! + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[define <shape>] +% + While typesetting an object, some of the properties are considered + part of the `??w![current object style]??w[style]'. Initially this + means nothing but some of the <style>s defined by extensions have + this status, \eg, colours |[red]|, |[blue]| say, using the |xycolor| + extension, or varying the width of lines using |xyline|. Such styles + are processed "left-to-right"; for example, +$$ +|*[red][green][=NEW][blue]{A}| +$$ + will typeset a blue |A| and define |[NEW]| to set the colour to green + (all provided that |xycolor| has been loaded, of course). + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The method of requesting a special effect is via the <shape> + modifiers. However the code required for implementation is quite + different. In particular it must allow for the different ways in + which the <driver> may implement the |\special|s required to + activate, and turn off, the effect. Another difficulty is that the + <style> applies also to nested sub-parts of any <object>. This means + that the code cannot be wholly delayed until after the <object> has + been constructed. + + Usually some value has to be stored, so as to be accessible to + sub-parts, though the |\special| commands cannot be fully constructed + until the <object> is completely known and ready to be |\Drop@@| or + |\Connect@@|'ed. + + Finally, the overhead in using |\special| commands can be quite high + with some |dvi|-drivers. Thus it is not best that every <style> + request generate a |\special| command; indeed {\it two} |\special| + commands, since each style-change also requires a command to revert + to the previous style, after the change is no longer applicable. + + Thus, as with <shape>s, all the style-change requests are stored + until the <object> is ready to be |\Drop@@|'ed. This also helps with + getting the sequencing correct when later requests compound on, or + override, earlier requests. + + When the <style> requests are processed, after the <object> has been + constructed, information of the form <control-word>|{|<data>|}| is + added to a global list called |\preXY@style@|. Similar information is + added to another global list |\postXY@style@|, for the purpose of + reverting the style parameters, within the <driver>-file, to their + previous values prior to the current <object>. + + Both lists are initially <empty> at the start of an <object>. The + contents of these lists are processed when the macros + |\xypre@Style@@| and |\xypost@Style@@| are encountered in the + expansion of |\styledboxz@|. + +\DOCMODE( +\xydef@\preXY@style@{} +\xydef@\postXY@style@{} + +\xydef@\resetStyle@{\gdef\preXY@style@{}\gdef\postXY@style@{}} +\DOCMODE) + + The <data> contains the code needed to implement the requested + style-change, with the particular <driver> being used. + + The <control-word> is a macro whose expansion could be fixed, or + could depend upon what other style-change requests are made for this + <object>. Its purpose is to decide whether or not the <data> is + actually required. If so, it is added to the token-list + |\styletoks@| for later use. + + Whether the <control-word>|{|<data>|}| tokens are prepended or + appended to the global lists depends upon the nature of the + style-change requested. For example, with |*[red][green]|<object> + the information |\|<set-color>|{|<green>|}| could be appended to + |\preXY@style@|, with |\|<revert-to-color>|{|<red>|}| prepended to + |\postXY@style@|. Then the dvi-output would set the color to <red> + then <green> and restore it first to <red> then <black>. + + \TODO: A more sophisticated implementation could instead prepend + |\|<set-color>|{|<green>|}| to |\preXY@style@| and append + |\|<revert-to-color>|{|<red>|}| to |\postXY@style@|. Now the first + |\|<set-color> encountered adds its <data> to |\styletoks@| then + rebinds |\|<set-color> to |\eat@|, to ignore subsequent occurrences. + Similarly |\|<revert-to-color> is rebound so that only the is + restoration to <black> is retained. + + This latter strategy is preferred when the overhead for a |\special| + command is high, within the <driver>'s output. Indeed the \PS\ + back-end is even more efficient. Since \PS\ is itself a programming + language, the <data> can be just the \PS\ code. A single |\special| + command is sufficient to accommodate {\it all\/} the style-changes + for an individual <object>. This is achieved by rebinding + |\xydoprestyles@@| and |\xydopoststyles@@| to include the <data> + within an appropriately prepared |\special| command. + +\DOCMODE( +\xynew@{toks}{\styletoks@} +\xydef@\addtostyletoks@#1{% + \expandafter\styletoks@\expandafter{\the\styletoks@#1}} +\DOCMODE) + + The <data> to be used is collected in the token-list |\styletoks@|. + If this is <empty> for an <object> then the style processing is + skipped completely. For safety, in case multiple occurences of + |\xypre@Style@| have somehow slipped into the token stream, these and + |\xypost@Style@@| are bound to |\relax| until the <object> is + finished. Indeed |\xypost@Style@@| is always bound to |\relax| unless + |\styletoks@| is non-empty. + +\DOCMODE( +\xydef@\styledboxz@{% +% +%\W@{STYLED BOX:}% +%\W@{: PRE={\meaning\xypre@Style@@}}% +% + \xypre@Style@@ +% +%{\expandafter\DN@\expandafter{\the\styletoks@}\W@{: STYLTOKS={\codeof\next@}}}% +% + \boxz@ +% +%\W@{: POST={\meaning\xypost@Style@@}}% +% + \xypost@Style@@} + +\xydef@\xypre@Style@{\styletoks@={}\saveXyStyle@\preXY@style@ + \expandafter\DN@\expandafter{\the\styletoks@}% + \ifx\next@\empty \DN@{\let\xypre@Style@@=\relax + \let\xypost@Style@@=\relax \xypre@skipStyle@}% + \else + \let\xypre@Style@@=\relax \let\xypost@Style@@=\xypost@Style@ + \DN@{\expandafter\xydoprestyles@\expandafter{\the\styletoks@}}% + \fi \next@ } + +\xydef@\xypost@Style@{\styletoks@={}\postXY@style@ + \expandafter\xydopoststyles@\expandafter{\the\styletoks@}% + \let\xypost@Style@@=\relax \let\xypre@Style@@=\xypre@Style@ } + +\xydef@\xypre@skipStyle@#1\xypost@Style@@{#1\relax + \let\xypre@Style@@=\xypre@Style@ } + +\xydef@\xydoprestyles@@{\literal@} +\xydef@\xydopoststyles@@{\literal@} +\xylet@\xydoprestyles@=\xydoprestyles@@ +\xylet@\xydopoststyles@=\xydopoststyles@@ +\DOCMODE) + + Some extensions use the following macros to add style <data> to the + global macros. Here code is added sequentially to |\preXY@style@| so + that it is acted upon in the order of occurrence (FIFO) of the + <shape> modifiers. Code is added to |\postXY@style@| in reverse order + (LIFO), so that each addition to |\preXY@style@| can be closed off, + if necessary, in correctly nested sequence. + +\DOCMODE( +\xydef@\modXYstyle@{% + \ifx\xy@style@\empty\resetStyle@\fi \checkXyStyle@ + \expandafter\expandafter\expandafter\DN@ + \expandafter\expandafter\expandafter{\preXYstyle@@}% + \ifx\next@\empty\else\DN@{\modXYstyle@@}\fi \next@ } + +\xydef@\modXYstyle@@{% + \DN@##1{\expandafter\def\expandafter\tmp@\expandafter{##1}}% + \expandafter\next@\expandafter{\preStyle@@}% + \DN@##1{\expandafter\gdef\expandafter\preXY@style@\expandafter{% + \preXY@style@ ##1}}\expandafter\next@\expandafter{\tmp@}% + \DN@##1{\expandafter\def\expandafter\tmp@\expandafter{##1}}% + \expandafter\next@\expandafter{\postStyle@@}% + \DN@##1{\expandafter\gdef\expandafter\postXY@style@\expandafter{% + \tmp@ ##1}}\expandafter\next@\expandafter{\postXY@style@}} + +\xydef@\xy@style@{} +\xydef@\checkXyStyle@{\ifx\xy@style@\empty\resetStyle@\fi + \let\xy@style@=\relax} +\DOCMODE) + + The |\preStyle@| and |\postStyle@| temporarily hold style <data>. + The macro |\preXYstyle@@| is used to check whether there is any + <data> to process. Normally this is just an alias for |\preStyle@@|, + but some back-ends may use the two control-names differently. + +\DOCMODE( +\xydef@\preStyle@@{} +\xydef@\postStyle@@{} +\xydef@\preXYstyle@@{\relax} + +\xydef@\loadxystyle@{% + \let\xypre@Style@@=\xypre@Style@ \def\preXYstyle@@{\preStyle@@}} + +\loadxystyle@ +\DOCMODE) + + Initially styles are activated but can be suppressed using + |\Unloadstyle@|. + +\DOCMODE( +\xydef@\Unloadstyle@{% + \let\xypre@Style@@=\relax \let\xypost@Style@@=\relax + \def\preXYstyle@@{\relax}} +\DOCMODE) + + Global macros are used, so that the same styles can be reused by + successive objects without having to re-interpret <shape> modifiers, + as described next. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Saving styles:\ } + + Once specified for an <object>, the collection of <style>s can be + assigned a name, using ??c![[=]<word>|]|. Then |[|<word>|]| becomes a + new <style>, suitable for use with the same or other <objects>s. Use + a single <word> built from ordinary letters. If |[|<word>|]| already + had meaning the new definition will still be imposed, but the + following type of warning will be issued: +$$ +|Xy-pic Warning: Redefining style [|<word>|]| +$$ + The latter warning will appear if the definition occurs within an + ??c![\xymatrix]. This is perfectly normal, being a consequence of the + way that the matrix code is handled. Similarly the message may appear + several times if the style definition is made within an ??c![\ar]. + +\begin{code} + \setbox0=\hbox{% + \xy\drop[OrangeRed][=A]{}\endxy} +\end{code} + +\noindent + The following illustrates how to avoid these messages by defining the + style without typesetting anything. + +\displaycode + + \NOTE{~1:} The current colour is regarded as part of the style for + this purpose. + + \NOTE{~2:} Such namings are global in scope. They are intended to + allow a consistent style to be easily maintained between various + pictures and diagrams within the same document. + +\DOCMODE( +\xydefcsname@{shape [=...]}#1{\checkXyStyle@ \addtotoks@{\xynamestyle@{#1}}} + +\xydef@\xynamestyle@#1{\checkXyStyle@ + \expandafter\DNii@\expandafter{\csname shape [#1]\endcsname}% + \expandafter\ifx\nextii@\relax %%\xywarning@{Defining new style [#1]}% + \else\xywarning@{Redefining style [#1]}\fi + \expandafter\xynamestyle@@\csname shape [#1]\endcsname } + +\xydef@\xynamestyle@@#1{% + \expandafter\def\expandafter\tmp@\expandafter{\preXY@style@}% + \DN@##1{\def\tmp@{\checkXyStyle@\gdef\preXY@style@{##1}}}% + \expandafter\next@\expandafter{\preXY@style@}% + \DN@##1{\expandafter\gdef\expandafter#1\expandafter{\tmp@ + \gdef\postXY@style@{##1}}}% + \expandafter\next@\expandafter{\postXY@style@}\DN@{}} +\DOCMODE) + + If the same <style> is intended for several <object>s occurring + in succession, the |[||*]| <modifier> can be used on the later + <object>s. This only works when |[||*]| precedes any other <style> + modifiers; it is local in scope, recovering the last <style>s used + at the same level of \TeX\ grouping. + +\DOCMODE( +\xydef@\prevXypreStyle@@{} +\xydef@\prevXypostStyle@@{} + +\xydef@\saveXyStyle@{\expandafter + \def\expandafter\prevXypreStyle@@\expandafter{\preXY@style@}% + \expandafter\def\expandafter\prevXypostStyle@@\expandafter{% + \postXY@style@}} + +\xydef@\recoverXyStyle@{\expandafter + \gdef\expandafter\preXY@style@\expandafter{\prevXypreStyle@@}% + \expandafter\gdef\expandafter\postXY@style@\expandafter{% + \prevXypostStyle@@}} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Defining new effects} + + Allow new effects to be declared and a default action provided. The + name is constructed from |#1| and the action to be taken is passed as + |#2|. If |#3| is non-empty then overwrite any existing definition for + a control sequence of the same name. + +\DOCMODE( +\xydef@\newxystyle#1#2#3{% + \DN@{#3}\ifx\next@\empty + \xydefcsname@{shape [#1]}{\csname xyshape@#1@\endcsname}% + \else \expandafter\def\csname shape [#1]\endcsname{% + \csname xyshape@#1@\endcsname}\fi + \DN@{#2}\ifx\next@\empty + \expandafter\def\csname xyshape@#1@\endcsname{% + \xyundefinedStyle@{#1}{}@@}% + \else \expandafter\def\csname xyshape@#1@\endcsname{#2}\fi} + +\xydef@\xyundefinedStyle@#1#2@@{% + \xywarning@{style #1 not defined, nothing to apply}} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Support for a new <style> takes the following form, in which + |\thestyle@| expands to the current value of the <style> information + to be maintained. If this is kept in a <count> or <dimen> register, + named |\xystyle@| say, then replace |\thestyle@| by + |\the\style@|. (However due to the large number of <dimen>s already + allocated, it is preferable to keep a text form of the value in + |\thestyle@|.) + +\begin{code} +\xyshape@stylechange@{\modifystyle@{<how>}} +\xydef@\modifystyle@#1{\checkXyStyle@ + \edef\prevstyle@{\thestyle@}\modifystyle@@{#1}% + \let\prestyle@=\prestyle@@ \let\poststyle@=\poststyle@@ + \applystyle@\prestyle@{\thestyle@}\poststyle@{\prevstyle@}} +\xydef@\resetstyle@@#1{\def\thestyle@{#1}\outputstyle@{#1}} +\xydef@\outputstyle@#1{\transformstyle@{#1}% + \expandafter\stylespecial@\expandafter{\next@}} +\xylet@\transformstyle@@=\DN@ +\xylet@\transformstyle@=\transformstyle@@ +\end{code} +\displaycode + + In the above the macros |\modifystyle@@| and |\stylespecial@| are + adapted to the particular <style> information, see below. Typically + <how> is actual \TeX\ code and |\modifystyle@@| is simply |\literal@| + to execute this code. Typesetting is done by |\stylespecial@#1| + which is typically of the form |\special{|<key> |#1}|. + + The |\transformstyle@| is required in case a dvi-<driver> needs + information in a form that is different to how \Xy-pic maintains it + in |\thestyle@|. A <driver> file should define |\|<driver>|@style@@| + to perform the transformation and place its result in |\next@|. + Install this macro using |\let\transformstyle@=\|<driver>|@style@@| + within the <driver> installation macro. + +\medskip + + Next we discuss |\applystyle@|; which uses |\prestyle@|, + |\prestyle@@|, |\poststyle@| and |\poststyle@@|. There are two + strategies here, affecting how much information is placed into the + dvi-file, indicated by the alternative expansions given above. The + appropriateness for a given style must be decided by the author of + the style-option. + + Suppose several modifications are made to a particular style + parameter. We must build a list of commands |\prestyle@{|<value>|}|, + to be executed later, which will recover the required value. Also we + build a list of commands |\poststyle@{|<value>|}| to reset to the + previous value. + + In most cases it is only the result of the modifications that need be + placed into the dvi-file. Since we do not know how many, if any, more + modifications follow we could store each new result {\em after} the + previous, so that its effect will override the previous value. This + is building a FIFO list for the |\prestyle@| commands, with a FILO + list for the |\poststyle@| commands: + +\DOCMODE( +\xydef@\applyFIFOstyle@#1#2#3#4{\bgroup + \styletoks@={\egroup\gdef\preXY@style@}% + \expandafter\toks@\expandafter{\preXY@style@}% + \expandafter\addtotoks@\expandafter{\expandafter#1\expandafter{#2}}% + \expandafter\addtostyletoks@\expandafter{\expandafter{\the\toks@}% + \gdef\postXY@style@}% + \expandafter\toks@\expandafter{\expandafter#3\expandafter{#4}}% + \expandafter\addtotoks@\expandafter{\postXY@style@}% + \expandafter\addtostyletoks@\expandafter{\expandafter{\the\toks@}}% + \the\styletoks@ } +\DOCMODE) +% +\noindent + Use this via: + |\applyLIFOstyle@\prestyle@{\thestyle@}\poststyle@{\prevstyle@}|. + \newline With this method each modification places two entries into + the dvi-file; there is no need for separate |\prestyle@| and + |\prestyle@@| macros. + + Perhaps a more efficient strategy is to build a LIFO list for the + |\prestyle@| commands. This way the required value is encountered + first. This first instance should then cancel all subsequent + instances of |\prestyle@|. This is where the need comes for a + |\prestyle@@|. Accompanying this is a FIFO list for the + |\poststyle@| commands, with a corresponding |\poststyle@@| to kill + subsequent instances: + +\DOCMODE( +\xydef@\applyLIFOstyle@#1#2#3#4{\bgroup + \styletoks@={\egroup\gdef\preXY@style@}% + \expandafter\toks@\expandafter{\expandafter#1\expandafter{#2}}% + \expandafter\addtotoks@\expandafter{\preXY@style@}% + \expandafter\addtostyletoks@\expandafter{\expandafter{\the\toks@}% + \gdef\postXY@style@}% + \expandafter\toks@\expandafter{\postXY@style@}% + \expandafter\addtotoks@\expandafter{\expandafter#3\expandafter{#4}}% + \expandafter\addtostyletoks@\expandafter{\expandafter{\the\toks@}}% + \the\styletoks@ } +\DOCMODE) + +\noindent + Use this via: + |\applyLIFOstyle@\prestyle@{\thestyle@}\poststyle@{\prevstyle@}|. + \newline The advantage here is that only two pieces of data need be + output to the dvi-file, no matter how many modifications are + requested. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[diagonal]??=[direction]??=[<direction>] +% + Setting the current direction is simply pretending for the + typesetting of the object (and the following <modifier>s) that some + connection set it -- the <empty> case just inherits the previous + direction. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The code just calls the general <direction> parser below: + +\DOCMODE( +\xydef@\OBJECT@direction{\afterDIRECTIONorEMPTY{% + \edef\next@{{\DirectionfromtheDirection@}}\expandafter\addtotoks@\next@ + \xyFN@\OBJECT@}% + {\xyFN@\OBJECT@}} +\DOCMODE) + + Here is the <direction> parser: first the parts parsing the <diag> + part then the parts parsing the <trailer> part: + +\DOCMODE( +\xydef@\afterDIRECTIONorEMPTY#1#2{% + \DN@##1{\def\afterDIRECTION@{\def\afterDIRECTION@{##1}% + \ifDIRECTIONempty@\DN@{#2}\else\DN@{#1}\fi \next@}}% + \expandafter\next@\expandafter{\afterDIRECTION@}% + \xyFN@\DIRECTION@} + +\xylet@\afterDIRECTION@=\empty +\xynew@{if}\ifDIRECTIONempty@ + +\xydef@\DIRECTION@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\DIRECTION@}%gobble spaces + \else\ifx v\next \DN@ v{\DIRECTION@v}% + \else\ifx \bgroup\next \let\next@=\DIRECTION@group + \else\ifx (\next \DN@({\xyFN@\DIRECTION@open}%)) + \else + \DN@{\count@=8 % + \afterDIAG{\ifnum\count@=8 \DN@{\DIRECTIONempty@true \xyFN@\DIRECTION@i}% + \else \DN@{\xy@@{\dimen@=\xydashl@}\Directionfromdiag@}\fi \next@}}% + \fi\fi\fi\fi \next@} + +\xydef@\DIRECTION@open{% + \ifx *\next \DN@*##1*){\DIRECTION@group{##1}}% + \else \DN@{\xyerror@{(* <pos> *) expected}{} \xyFN@\DIRECTION@i}% + \fi \next@} +\DOCMODE) + +\paragraph*{Diagonal directions.} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + It is particularly easy to set <diag>onal directions: +$$ +\xy *[o]\cir<1pc>{}="c", + "c"; (-1,-1)**{},p+/4pc/ *+{|dl|=|ld|} **@{-}?>*@{>}, + "c"; ( 0,-1)**{},p+/4pc/ *+{|d|} **@{-}?>*@{>}, + "c"; ( 1,-1)**{},p+/4pc/ *+{|dr|=|rd|} **@{-}?>*@{>}, + "c"; ( 1, 0)**{},p+/4pc/ *+{|r|} **@{-}?>*@{>}, + "c"; ( 1, 1)**{},p+/4pc/ *+{|ur|=|ru|} **@{-}?>*@{>}, + "c"; ( 0, 1)**{},p+/4pc/ *+{|u|} **@{-}?>*@{>}, + "c"; (-1, 1)**{},p+/4pc/ *+{|ul|=|lu|} **@{-}?>*@{>}, + "c"; (-1, 0)**{},p+/4pc/ *+{|l|} **@{-}?>*@{>}, +\endxy +$$ + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + More to the point, <diag>onals are stored internally as +$$ +\xy *\cir<1pc>{}="c", + "c"; (-1,-1)**{},p+/3pc/ *+{|0|} **@{-}?>*@{>}, + "c"; ( 0,-1)**{},p+/3pc/ *+{|1|} **@{-}?>*@{>}, + "c"; ( 1,-1)**{},p+/3pc/ *+{|2|} **@{-}?>*@{>}, + "c"; ( 1, 0)**{},p+/3pc/ *+{|3|} **@{-}?>*@{>}, + "c"; ( 1, 1)**{},p+/3pc/ *+{|4|} **@{-}?>*@{>}, + "c"; ( 0, 1)**{},p+/3pc/ *+{|5|} **@{-}?>*@{>}, + "c"; (-1, 1)**{},p+/3pc/ *+{|6|} **@{-}?>*@{>}, + "c"; (-1, 0)**{},p+/3pc/ *+{|7|} **@{-}?>*@{>}, +\endxy +$$ + Expanding |\afterDIAG{|<stuff>|}|<diag> will result in |\count@| + being set to the <diag> code (not changed in case the <diag> is + <empty>) before expanding <stuff>. + +\DOCMODE( +\def\afterDIAG#1{\def\afterDIAG@{#1}\xyFN@\DIAG@} + +\xydef@\DIAG@{% + \ifx d\next \DN@ d{\count@=1 \xyFN@\DIAG@@}% + \else\ifx r\next \DN@ r{\count@=3 \xyFN@\DIAG@@}% + \else\ifx u\next \DN@ u{\count@=5 \xyFN@\DIAG@@}% + \else\ifx l\next \DN@ l{\count@=7 \xyFN@\DIAG@@}% + \else \let\next@=\afterDIAG@ + \fi\fi\fi\fi \next@} + +\xydef@\DIAG@@{\ifcase\count@ \or +%\count@=1 3 5 7 + \DIAG@@@ l0r2\or\or \DIAG@@@ d2u4\or\or \DIAG@@@ r4l6\or\or \DIAG@@@ u6d0% + \else\xybug@{impossible <diag> number}\fi + \next@} + +\xydef@\DIAG@@@#1#2#3#4{% + \ifx #1\next \count@=#2\DN@#1{\afterDIAG@}% + \else \ifx #3\next \count@=#4\DN@#3{\afterDIAG@}% + \else \let\next@=\afterDIAG@ \fi\fi} +\DOCMODE) + + The action in case of a <diag> is simply to pick the right direction + setup routine according to the encoding, getting the <diag> from + |\count@| and the length of the $d$ vector from |\dimen@|: + +\DOCMODE( +\xydef@\Directionfromdiag@{\ifcase\count@ + \xy@@{\dlDirection@\dimen@}% + \or \xy@@{\dDirection@\dimen@}% + \or \xy@@{\drDirection@\dimen@}% + \or \xy@@{\rDirection@\dimen@}% + \or \xy@@{\urDirection@\dimen@}% + \or \xy@@{\uDirection@\dimen@}% + \or \xy@@{\ulDirection@\dimen@}% + \or \xy@@{\lDirection@\dimen@}% + \or % 8 is legal and means change nothing + \else\xybug@{impossible <diag>}\fi + \DIRECTIONempty@false \xyFN@\DIRECTION@i} +\DOCMODE) + +\paragraph*{Vector directions.} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Alternatively |v|<vector> sets the direction as if the connection + from |0| to the <vector> had been typeset except that the "origin" is + assumed zero such that directions $|v(|x|,|y|)|$ mean the natural + thing, \ie, is the direction of the connection from |(0,0)| to + $|(|x|,|y|)|$. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The action for a |v| reads a <vector> and sets the direction + accordingly using some expansion hackery to propagate it out. The + "origin" is cleared locally to make |v(|$x$|,|$y$|)| behave as it + should. + +\DOCMODE( +\xydef@\DIRECTION@v{% + \xy@{v}{\enter@{\cfromthec@ \X@origin=\the\X@origin \Y@origin=\the\Y@origin + \X@p=\the\X@p \Y@p=\the\Y@p}% + \X@origin=\z@ \Y@origin=\z@}% + \afterVECTORorEMPTY + {\xy@@{\X@p=\z@ \Y@p=\z@ \setupDirection@ \leave@}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}% + {\xy@@\leave@ \xyerror@{<vector> expected after v}{}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}} +\DOCMODE) + +\paragraph*{Complex direction.} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + In case the direction is not as simple, you can construct + |{| <pos> <decor> |}| that sets up $p$ and $c$ such that + $\overline{pc}$ has the desired direction. \NOTE: that you must use + the |(*|\dots|*)| form if this is to appear in an object <modifier>! + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The code for this is rather like the one for <vector>s. + +\DOCMODE( +\xydef@\DIRECTION@group#1{% + \xy@@{\begingroup}\xy@@ix@{#1}\xy@@{\plainxy@\expandafter\POS\the\toks9\relax + \setupDirection@\edef\next@{\endgroup \DirectionfromtheDirection@}\next@}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{exercise} + What effect is achieved by using <modifier>s |v/1pc/| and |v/-1pc/|? +\answertext{The first has no effect since the direction is set to be that of + a vector in the current direction, however, the second reverses the + current direction.} +\end{exercise} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[to <direction>] +% + Once the initial direction is established as either the last one or + an absolute one then the remainder of the <direction> is interpreted. + + Adding a single |^| or |_| denotes the result of rotating the default + direction a right angle in the positive and negative direction, \ie, + anti-/clockwise, respectively. \NOTE: Do \emph{not} use |^|\relax|^| + but only |__| to reverse the direction! + + A trailing |:|<vector> is like |v|<vector> but uses the + <direction> to set up a standard square base such that |:(0,1)| and + |:(0,-1)| mean the same as |:a(90)| and |:a(-90)| and as |^| and |_|, + respectively. + +\DOCMODE( +\xydef@\DIRECTION@i{% + \ifx ^\next \DN@ ^{\xy@^{\aboveDirection@\xydashl@}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}% + \else\ifx _\next \DN@ _{\xy@_{\belowDirection@\xydashl@}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}% + \else\ifx :\next \DN@ :{% + \xy@{:}{\enter@{\cfromthec@ \basefromthebase@ \X@p=\the\X@p \Y@p=\the\Y@p}% + \X@origin=\z@ \Y@origin=\z@ + \X@xbase=\cosDirection\xydashl@ \Y@xbase=\sinDirection\xydashl@ + \X@ybase=-\Y@xbase \Y@ybase=\X@xbase}% + \afterVECTORorEMPTY + {\xy@@{\X@p=\z@ \Y@p=\z@ \setupDirection@ \leave@}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}% + {\xy@@\leave@ \xyerror@{<vector> expected after :}{}% + \DIRECTIONempty@false \xyFN@\DIRECTION@i}}% + \else + \let\next@=\afterDIRECTION@ + \fi\fi\fi \next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{exercise} + What effect is achieved by using <modifier>s |v/1pc/:(1,0)| and + |v/-1pc/__|? +\answertext{None in both cases.} +\end{exercise} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\end{notes} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Decorations} +??=[decor] + +\DOCMODE( +\message{decorations;} +\DOCMODE) + + <Decor>ations are actual \TeX\ macros that decorate the current + picture in manners that depend on the state. They are allowed "after" + the <pos>ition either of the outer ??c![\xy]\dots??c![\endxy] or inside + |{|\dots|}|. The possibilities are given in figure~??[f.decor] with + notes below. + +\begin{figure*}[tp] +\vss +\begin{syntax} + ??w![<decor>] + &\iss & <command> <decor> + & either there is a command\dots +\cr + &\orr & <empty> + & \dots or there isn't. +\cr + ??w![<command>] + &\iss & ??c![\save] <pos> + & save ??!^[state], then do <pos> +\cr + &\orr & ??c![\restore] + & restore ??!^[state] saved by matcing |\save| +\cr + &\orr & ??c![\POS] <pos> + & interpret <pos> +\cr + &\orr & ??c![\afterPOS] |{| <decor> |}| <pos> + & interpret <pos> and then perform <decor> +\cr + &\orr & ??c![\drop] <object> + & drop <object> as the <pos> |*| operation +\cr + &\orr & ??c![\connect] <object> + & connect with <object> as the <pos> |**| operation +\cr + &\orr & ??c![\relax] + & do nothing +\cr + &\orr & <\TeX\ commands> + & any ??!^[\TeX\ commands] and user-defined macros \hfil\break + that neither generates output (watch out for stray + \hfil\break spaces!), nor changes the grouping, may be used +\cr + &\orr & ??c![\xyverbose]\orr??c![\xytracing]\orr??c![\xyquiet]\kern-1pc + &\kern1pc ??!^[tracing] commands +\cr + &\orr & ??c![\xyignore] |{|<pos> <decor>|}| + & ??!^[ignore] \Xy-code +\cr + &\orr & ??c![\xycompile] |{|<pos> <decor>|}| + & ??!^[compile] to file <prefix><no>|.xyc| +\cr + &\orr & ??c![\xycompileto]|{|<name>|}{|<pos><decor>|}|\kern-1pc + &\kern1pc ??!^[compile] to file <name>|.xyc| +\cr +\end{syntax} +\caption{\protect<decor>ations.} +??=[f.decor] +\vfill +\end{figure*} + + Most options add to the available <decor>, in particular the |v2| + option loads many more since \Xy-pic versions prior to 2.7 provided + most features as <decor>. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Simple decorations:} + + ??c![\POS] and ??c![\afterPOS] have already been defined; the + following are just simple applications of previously defined + commands: + +\DOCMODE( +\xydef@\drop#1#{\DN@##1{\xy@@ix@{{#1}{##1}}% + \xy@{\drop#1{##1}}{\expandafter\drop@\the\toks9 }\ignorespaces}\next@} + +\xydef@\connect#1#{\DN@##1{\xy@@ix@{{#1}{##1}}% + \xy@{\connect#1{##1}}{\expandafter\connect@\the\toks9 }\ignorespaces}\next@} + +\xydef@\preconnect#1#{\DN@##1{\xy@@ix@{{#1}{##1}}% + \xy@{\connect#1{##1}}{\expandafter\preconnect@\the\toks9 }\ignorespaces}\next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{notes} +% +\note??=[state] +% + Saving and restoring allows `excursions' where lots of things are + added to the picture without affecting the resulting \Xy-pic state, + \ie, $c$, $p$, and "base", and without requiring matching |{}|s. The + independence of |{}| is particularly useful in conjunction with the + ??c![\afterPOS] command, for example, the definition + +\begin{code} +\def\ToPOS{\save\afterPOS{% + \POS**{}?>*@2{>}**@{-}\restore};p,} +\end{code} +\gdocode +\displaycode + + will cause the code |\ToPOS|<pos> to construct a double-shafted arrow + from the current object to the <pos> (computed relative to it) such + that +% +\begin{code} +\xy *{A} \ToPOS +<10mm,2mm> \endxy +\end{code} +% + \thecode\ will typeset the picture \docode. + +\paragraph*{Note:} + Saving this way in fact uses the same state as the |{}| `grouping', + so the code $p_1$|,| |{|$p_2$|\save},| \dots\ |{\restore}| will have + $c=p_1$ both at the \dots\ and at the end! + +\DOCMODE( +\xydef@\save{\relax\saveC} +\xydef@\saveC{\xy@\save\save@ \POS} + +\xydef@\save@{\enter@{\cfromthec@ \pfromthep@ \basefromthebase@}} + +\xydef@\restore{\xy@\restore\leave@ \ignorespaces} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[\TeX\ commands] +% + One very tempting kind of \TeX\ commands to perform as <decor> is + arithmetic operations on the \Xy-pic state. This will work in simple + \Xy-pictures as described here but be warned: "it is not portable" + because all \Xy-pic execution is indirect, and this is used by + several options in nontrivial ways. Check the \TeX-nical + documentation~\cite{RM95:Xy-picCSTC} for details about this! + + Macros that expand to <decor> will always do the same, though. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + \TeX\ hackers like the author may enjoy changing the \Xy-pic state + directly using <decor> of the form |\xy@{|<id>|}{|<code>|}|\dots + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[tracing] +% + ??c![\xyecho] will turn on echoing of all interpreted \Xy-pic <pos> + characters. \BUG: Not completely implemented yet. ??c![\xyverbose] + will switch on a tracing of all \Xy-pic commands executed, with line + numbers. ??c![\xytracing] traces even more: the entire \Xy-pic state + is printed after each modification. ??c![\xyquiet] restores default + quiet operation. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The trick is to replace the |\xy@| command such that it calls the + `normal' one between writing out a trace message and the state. + +\DOCMODE( +\xydef@\xyecho{% + \xy@\xyecho{\let\xy@=\xyecho@ \message{\string\xyecho}}\POS} + +\xydef@\xyecho@#1#2{{\def\1{#1}\ifx\1\empty\else\message{\codeof\1}\fi}% + \oxy@{#1}{#2}} + +\xydef@\xyverbose{% + \xy@\xyverbose{\let\xy@=\xyverbose@ + \W@{Xy: \string\xyverbose\xytracelineno@}}\POS} + +\xydef@\xyverbose@#1#2{% + {\def\1{#1}\ifx\1\empty\else\W@{Xy: \codeof\1\xytracelineno@}\fi}% + \oxy@{#1}{#2}} + +\xydef@\xytracing{% + \xy@\xytracing{\let\xy@=\xytracing@ + \W@{Xy TRACE: \string\xytracing\xytracelineno@}\xystatus@:}\POS} + +\xydef@\xytracing@#1#2{{\def\1{#1}\def\2{#2}% + \W@{Xy TRACE: \codeof\1 {\codeof\2}\xytracelineno@}}\oxy@{#1}{#2}\xystatus@:} + +\xydef@\xystatus@#1{\xystatus@cp{#1}% + \W@{#1 d=<\the\d@X,\the\d@Y> + Direction=\the\Direction=\string(\cosDirection,\sinDirection\string)}% + \W@{#1 base=<\the\X@origin,\the\Y@origin>+% + <\the\X@xbase,\the\Y@xbase>x+<\the\X@ybase,\the\Y@ybase>y}% + \W@{#1 min/max=<\the\X@min,\the\Y@min>/<\the\X@max,\the\Y@max> + S=\the\csp@}} + +\xydef@\xystatus@cp#1{% + \W@{#1 c=<\the\X@c,\the\Y@c> \expandafter\string\the\Edge@c + \string[\the\L@c+\the\R@c,\the\D@c+\the\U@c\string] + \ifInvisible@ I\fi\ifHidden@ H\fi}% + \W@{#1 p=<\the\X@p,\the\Y@p> \expandafter\string\the\Edge@p + \string[\the\L@p+\the\R@p,\the\D@p+\the\U@p\string]}} + +\xydef@\xystatus@c#1{% + \W@{#1<\the\X@c,\the\Y@c> \expandafter\string\the\Edge@c + \string[\the\L@c+\the\R@c,\the\D@c+\the\U@c\string]}} + +\xydef@\xyquiet{\xy@\xyquiet{\let\xy@=\oxy@}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[ignore] +% + Ignoring means that the <pos> <decor> is still parsed the usual way + but nothing is typeset and the \Xy-pic state is not changed. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + We ignore in a group to ensure that nothing done inside `leaks' to + the outside. + +\DOCMODE( +\xydef@\xyignore#1{\xy@\xyignore{\xyignore@{#1}}\ignorespaces} + +\xydef@\xyignore@#1{{\let\xy@=\xyeat@ \change@oxy@\xy@ \POS#1\relax}} + +\xydef@\xyeat@#1#2{} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[compile] +% + It is possible to save an intermediate form of commands that generate + parts of an \Xy-picture to a file such that subsequent typesetting of + those parts is significantly faster: this is called + "??w![compiling]". The produced file contains code to check that the + compiled code still corresponds to the same <pos><decor> as well as + efficient \Xy-code to redo it; if the <pos><decor> has changed then + the compilation is redone. + + There are two ways to use this. The direct is to invent a <name> for + each diagram and then embrace it in + |\xycompileto{|<name>|}||{|\dots|}| -- this dumps the compiled code + into the file <name>|.xyc|. + + When many diagrams are compiled then it is easier to add + ??c![\xycompile]|{|\dots|}| around the <pos><decor> to be compiled. + This will assign file names numbered consecutively with a <prefix> + which is initially the expansion of |\jobname-| but may be set with +% +\begin{defs1} +??c![\CompilePrefix]|{|<prefix>|}| +\end{defs1} +\noindent\unskip +% + This has the disadvantage, however, that if additional compiled + \Xy-pictures are inserted then all subsequent pictures will have to + be recompiled. One particular situation is provided, though: when + used within constructions that typeset their contents more than once + (such as most ??w![\AMS-\LaTeX] equation constructs) then the + declaration +% +\begin{defs1} +??c![\CompileFixPoint]|{|<id>|}| +\end{defs1} +\noindent\unskip +% + can be used inside the environment to fix the counter to have the + same value at every passage. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + It is done by just writing all |\xy@|-commands to the file. The file + establishes the correct input mode through use of the appropriate + commands itself. + +\DOCMODE( +\xydef@\xycompile@@{\jobname-} +\xydef@\xycompileno@@{0} + +\xydef@\CompilePrefix#1{% + \def\xycompile@@{#1}\xdef\xycompile@@{\codeof\xycompile@@}% + \xdef\xycompileno@@{0}} + +\xydef@\xycompile{% + \count@=\xycompileno@@ \advance\count@\@ne + \xdef\xycompileno@@{\ifnum10>\count@ 0\fi \the\count@}% + \edef\next{\noexpand\xycompileto{\xycompile@@\xycompileno@@}}\next} + +\xylet@\compilename@@=\empty +\xylet@\xyrecompile@@=\relax + +\xydef@\xycompileto#1#2{% + \if\inxy@ \DN@{\xy@@{\nter@{}}}% + \else \DN@{\xy \xy@@{\nter@{\endxy}}}\fi \next@ + \ifxysaving@ \xyerror@{Compilations can not be nested}{}\fi + \DN@{#1}\edef\compilename@@{\codeof\next@}\DNii@{#2}% + \def\xyrecompile@@{recompiling TRUNCATED}% + \expandafter\xyinputorelse@@\expandafter{\compilename@@.xyc}% + {\def\xyrecompile@@{compiling to}}% + \ifx\xyrecompile@@\relax \else \expandafter\xyrecompile@ \fi + \xy@@\leave@ \ignorespaces} +\DOCMODE) + + Recompilation is done by just writing all |\xy@|-commands to the + file. The file establishes the correct input mode and terminates + itself; after it has been finished it is simply reread to actually + get the drawing done in the document. + +\DOCMODE( +\xydef@\xyrecompile@{% + \message{(\xyrecompile@@\space\string`\compilename@@.xyc\string'}% + \DN@{\immediate\openout\xywrite@=}\expandafter\next@\compilename@@.xyc + \immediate\write\xywrite@{% + \string\xycompiled{\compilename@@}% + {\the\year/\the\month/\the\day\string:\the\time\xytracelineno@}% + {Xy-pic \xyversion}\xycomment@}% + \immediate\write\xywrite@{{\codeof\nextii@}\relax}% + {\xysaving@ \expandafter\POS\nextii@ \relax}% + \immediate\write\xywrite@{\string\xyendcompiled}% + \immediate\closeout\xywrite@ \message{done)}% + \expandafter\input\compilename@@.xyc + \outlines@@\writeoutline@\writeoutline@} + +\xydef@\xysaving@{\let\xy@=\xysave@ \change@oxy@\xy@ + \let\xy@@ix@=\xysave@@toksix@ \xysaving@true} + +\xynew@{if}\ifxysaving@ \xysaving@false + +\xydef@\xysave@#1#2{{\DN@{{#1}{#2}}% + \immediate\write\xywrite@{\string\xy@\codeof\next@\xycomment@}}} + +\xydef@\xysave@@toksix@#1{{\DN@{{#1}}% + \immediate\write\xywrite@{\string\xy@@ix@\codeof\next@\relax}}} + +\xywarnifdefined\xycomment@ +{\catcode`\%=12 \catcode`\(=1 \catcode`\)=2 \gdef\xycomment@(%)} +\DOCMODE) + + \HACK{1:} The |\ifxysaving@| can never be locally switched off! + Anyway it is used to allow a gross hack avoiding building a queue in + the matrix option that will generate too long lines!! + + \HACK{2:} |\xysave@@toksix@| is not doing the catcode jive because it + can never be invoked while loading a file (knock, knock~\smiley~). + + The initial command in all |.xyc| files check that this is the right + file and that neither the version of \Xy-pic nor the user's code has + changed: + +\DOCMODE( +\xydef@\xycompiled#1#2#3#4{\DN@{#1}\edef\next@{\codeof\next@}% + \ifx\next@\compilename@@\else + \xywarning@{This file does not contain the result of + \string\xycompileto{\compilename@@}{...}^^J% + but of \string\xycompileto{\next@}}\fi + \edef\next{Xy-pic \xyversion}\DN@{#3}\ifx\next\next@ + \DN@{#4}\ifx\next@\nextii@ \xycatcodes \outlines@@\relax\readoutline@ + \else \def\xyrecompile@@{recompiling to}\endinput \fi + \else \def\xyrecompile@@{Xy-pic version change - recompiling}\endinput \fi} + +\xydef@\xyendcompiled{\let\xyrecompile@@=\relax \xyuncatcodes\endinput} +\DOCMODE) + + Finally the fix-point thing. + +\DOCMODE( +\xydef@\CompileFixPoint#1{% + \expandafter\ifx\csname#1FIX@@\endcsname\relax + \expandafter\xdef\csname#1FIX@@\endcsname{\xycompileno@@}% + \else + \xdef\xycompileno@@{\csname#1FIX@@\endcsname}\fi} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Finally, when many `administrative typesetting runs' are needed, \eg, + readjusting \LaTeX\ cross references and such, then it may be an + advantage to not typeset any \Xy-pictures at all during the + intermediate runs. This is supported by the following declarations + which for each compilation creates a special file with the extension + ??c![.xyd] containing just the size of the picture: +% +\begin{defs1} +??c![\MakeOutlines]\cr +??c![\OnlyOutlines]\cr +??c![\ShowOutlines]\cr +??c![\NoOutlines]\cr +\end{defs1} +\noindent\unskip +% + The first does no more. The second uses the file to typesets a + dotted frame of the appropriate size instead of the picture (unless + the picture has changed and is recompiled, then it is typeset as + always and the |.xyd| file is recreated for subsequent runs). The + third shows the outlines as dotted rectangles. The last switches + outline processing completely off. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The implementation is all handled by |\outlines@@| which is called at + strategic places in the compilation macros above. It just expands to + nothing when the state is `No', the first argument when it is `Make', + and the second when it is `Only'. + +\DOCMODE( + +\xydef@\outlines@no#1#2{} +\xydef@\outlines@make#1#2{#1} +\xydef@\outlines@only#1#2{#2} + +\xylet@\outlines@@=\outlines@no +\xylet@\writeoutline@@=\relax +\xylet@\readoutline@@=\relax + +\xydef@\MakeOutlines{\let\outlines@@=\outlines@make} + +\xydef@\OnlyOutlines{\xywarning@{Compiled pictures only shown as outlines}% + \let\outlines@@=\outlines@only} + +\xydef@\ShowOutlines{\let\readoutline@@=\typesetoutline@} + +\xydef@\NoOutlines{\let\outlines@@=\outlines@no} + +\xydef@\writeoutline@{% + \DN@{\immediate\openout\xywrite@=}\expandafter\next@\compilename@@.xyd + \immediate\write\xywrite@{\xycomment@\space\compilename@@.xyd} + \immediate\write\xywrite@{% + \string\X@min=\the\X@min \string\X@max=\the\X@max + \string\Y@min=\the\Y@min \string\Y@max=\the\Y@max \string\relax}% + \writeoutline@@ + \immediate\closeout\xywrite@} + +\xynew@{if}\ifoutlineread@ + +\xydef@\readoutline@{\outlineread@true + \expandafter\xyinputorelse@@\expandafter{\compilename@@.xyd}% + {\def\xyrecompile@@{outline missing - recompiling to}\outlineread@false}% + \ifoutlineread@ \readoutline@@ + \writeoutline@\expandafter\xyendcompiled\fi} + +\xydef@\typesetoutline@{% + \xy@@{\czeroEdge@ \U@p=\z@ \D@p=\z@ \L@p=\z@ \R@p=\z@ \Edge@p={\zeroEdge}% + \X@p=\X@min \Y@p=\Y@min \X@c=\X@min \Y@c=\Y@max \connect@\dir{.}% + \X@p=\X@c \Y@p=\Y@c \X@c=\X@max \Y@c=\Y@max \connect@\dir{.}% + \X@p=\X@c \Y@p=\Y@c \X@c=\X@max \Y@c=\Y@min \connect@\dir{.}% + \X@p=\X@c \Y@p=\Y@c \X@c=\X@min \Y@c=\Y@min \connect@\dir{.}}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\end{notes} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Kernel object library} +??=[objectlib] + +\DOCMODE( +\message{kernel objects:} +\DOCMODE) + + In this section we present the "library objects" provided with the + kernel language---several options add more library objects. They fall + into three types: Most of the kernel objects (including all those + usually used with |**| to build connections) are "directionals", + described in \S??[objectlib.directionals]. The remaining kernel + library objects are "circles" of \S??[objectlib.circles] and "text" + of \S??[objectlib.text]. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Directionals} +??=[objectlib.directionals] + +\DOCMODE( +\message{directionals,} +\DOCMODE) + + The kernel provides a selection of "directionals": objects that + depend on the current direction. They all take the form +% +\begin{defs1} +% + ??c![\dir]<dir> \cr +% +\end{defs1} +\noindent\unskip +% + to typeset a particular <dir>ectional object. All have the structure +% +\begin{defs1} +% + <dir> \iss\ <variant>|{|<main>|}| \cr +% +\end{defs1} +\noindent\unskip +% + with <variant> being <empty> or one of the characters |^_23| and + <main> some mnemonic code. + + We will classify the directionals primarily intended for building + connections as "connectors" and those primarily intended for + placement at connection ends or as markers as "tips". + +\begin{figure*}[tp] + % + \def\Dx#1#2{\hbox{\def\1{#1{#2}}\enspace\tt\string\dir\codeof\1}} + % + \def\DC#1#{\DCx{#1}} + \def\DCx#1#2{ \Dx{#1}{#2} & \vcenter{\xy + 0*\cir<5pt>{} ; (16,5)*=<10.1pt>{}*\frm{-} **\dir#1{.} **h\dir#1{#2} + \endxy}} + % + \def\DT#1#{\DTx{#1}} + \def\DTx#1#2{\Dx{#1}{#2} & \vcenter{\xy + -(4,2.5)*{} ; (4,0)*{} **{} ?>*\dir#1{#2} **\dir#1{.} + \endxy}} + % + \def\Darray#1#2{{\let\\=\cr \tabskip=0pt plus 1fil % + \halign to\hsize{&\hfil$##$&$##$\hfil\\ + \noalign{\hbox to\hsize{\hss#1\hss}\smallskip}#2\crcr}\bigskip}} +% +\Darray{??!^[Dummy]}{\hbox{\tt\string\dir\string{\string}}} +% +\Darray{??!^[Plain connectors]}{% + \DC{-} &\DC2{-} &\DC3{-} \\ + \DC{.} &\DC2{.} &\DC3{.} \\ + \DC{~} &\DC2{~} &\DC3{~} \\ + \DC{--} &\DC2{--} &\DC3{--} \\ + \DC{~~} &\DC2{~~} &\DC3{~~} \\ +} +\bigskip +\Darray{??!^[Plain tips]}{% + \DT{>} &\DT^{>} &\DT_{>} &\DT2{>} &\DT3{>} \\ + \DT{<} &\DT^{<} &\DT_{<} &\DT2{<} &\DT3{<} \\ + \DT{|} &\DT^{|} &\DT_{|} &\DT2{|} &\DT3{|} \\ + \DT{(} &\DT^{(} &\DT_{(} \\ + \DT{)} &\DT^{)} &\DT_{)} \\ + & &\DT^{`} &\DT_{`} \\ + & &\DT^{'} &\DT_{'} +} +\bigskip +\Darray{??!^[Constructed tips]}{% + \DT{>>} &\DT^{>>} &\DT_{>>} &\DT2{>>} &\DT3{>>} \\ + \DT{<<} &\DT^{<<} &\DT_{<<} &\DT2{<<} &\DT3{<<} \\ + \DT{||} &\DT^{||} &\DT_{||} &\DT2{||} &\DT3{||} \\ + \DT{|-} &\DT^{|-} &\DT_{|-} &\DT2{|-} &\DT3{|-} \\ + \DT{>|} &\DT{>>|} &\DT{|<} &\DT{|<<} &\DT{*} \\ + \DT{+} &\DT{x} &\DT{/} &\DT{//} &\DT{o} +} +\caption{Kernel library \protect<dir>ectionals}??=[f.dir] +\end{figure*} + + Figure~??[f.dir] shows all the <dir>ectionals defined by the kernel + with notes below; each <main> type has a line showing the available + <variant>s. Notice that only some variants exist for each + <dir>---when a nonexisting variant of a <dir> is requested then the + <empty> variant is used silently. Each is shown in either of the two + forms available in each direction as applicable: connecting a + $\bigcirc$ to a $\Box$ (typeset by |**\dir|<dir>) and as a tip at the + end of a dotted connection of the same variant (\ie, typeset by the + <pos> |**\dir|<variant>|{.}| |?>| |*\dir|<dir>). + + As a special case an entire <object> is allowed as a <dir> by + starting it with a |*|: |\dir*| is equivalent to ??c![\object]. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Setup:} + + ??c![\dir] starts an <object> and passes control to a `finisher' named + |\dir|<variant>|{|<main>|}| otherwise to the one corresponding to an + <empty> <variant>. The kernel ones described here have in common + that they make use of the generic |\straight@| defined + in~\S??[algo.connection]. + +\DOCMODE( +\xydef@\dir{\hbox\bgroup\xyFN@\dir@i} + +\xydef@\dir@i{\ifx *\next \DN@*{\resetStyle@\object@}% + \else \let\next@=\dir@ii \fi \next@} + +\xydef@\dir@ii#1#{\dir@{#1}} + +\xydef@\dir@#1#2{\DN@{dir#1{#2}}% + \expandafter\let\expandafter\next\csname\codeof\next@\endcsname + \ifx\next\relax \DN@{dir{#2}}% + \expandafter\let\expandafter\next\csname\codeof\next@\endcsname + \ifx\next\relax \DN@{\dir#1{#2}}% + \xyerror@{illegal <dir>: \codeof\next@\space not defined}{}% + \let\next=\no@ \fi\fi \next} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{notes} + +\note??=[Dummy] + + You may use |\dir{}| for a ``dummy'' directional object (in fact this + is used automatically by |**{}|). This is useful for a uniform + treatment of connections, \eg, making the |?| <pos> able to find a + point on the straight line from $p$ to $c$ without actually + typesetting anything. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Uses an empty droppping, the |\no@@| connection. All the variants + are defined for optimisation reasons and it is also named |\dir{ }| + to allow spurious spaces: + +\DOCMODE( +\xydefcsname@{dir{}}{\no@} + +\xyletcsnamecsname@{dir0{}}{dir{}} +\xyletcsnamecsname@{dir1{}}{dir{}} +\xyletcsnamecsname@{dir^{}}{dir{}} +\xyletcsnamecsname@{dir_{}}{dir{}} +\xyletcsnamecsname@{dir2{}}{dir{}} +\xyletcsnamecsname@{dir3{}}{dir{}} + +\xyletcsnamecsname@{dir{ }}{dir{}} + +\xydef@\no@{\egroup \czeroEdge@ %\Invisible@false \Hidden@false %%%%HACK? + \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\setbox\z@=\copy\voidb@x}\def\Connect@@{\no@@}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[Plain connectors] + + The "plain connectors" group contains basic directionals that lend + themself to simple connections. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The bulk of the code is in fact in the description of these. First + each of the three types---lines, dots, and squiggles---then the code + for doubling and tripling. + +\paragraph*{Lines:} + + A single |\dir{-}| object is a dash in the current direction: build + box with character $C$ of the semidirectional ??c![\xydashfont]; use + the characters natural width $w$ and construct a height/depth from $d + = \abs{\sin(|\Direction|)}|em|$ (where |1em| is the dash length, + \cf~|xydash10.mf|) as follows: +$$ +\begin{array}{cccccc} + C & L & R & D & U & "flip if" \\ + 0\ldots30 & 0 & w & 0 & d & dY \lt 0 \\ + 31\ldots63 & 0 & w & d & 0 & dY \gt 0 \\ + 64\ldots95 & 0 & w & d & 0 & dX \lt 0 \\ + 96\ldots127 & 0 & w & 0 & d & dX \lt 0 \\ +\end{array} +$$ + where "flip" means shift the box opposite vertically and + horizontally, \ie, $(L,R,D,U) := (R,L,U,D)$, and then lower the box + $D-U$. + + "Procedure": (??_[line1])~Compute $d$, (??_[line2])~set $D,U$, and + flip condition, (??_[line3])~build box to get $w,L,R$, + (??_[line4])~dump box that is flipped if condition holds, and + (??_[line5])~finally setup the required parameters properly. + +\DOCMODE( +\xydefcsname@{dir1{-}}{\line@} +\xydefcsname@{dir2{-}}{\line@ \double@\xydashh@} +\xydefcsname@{dir3{-}}{\line@ \triple@\xydashh@} +\xyletcsnamecsname@{dir0{-}}{dir{}} +\xyletcsnamecsname@{dir{-}}{dir1{-}} +\xyletcsnamecsname@{dir{=}}{dir2{-}} + +\xydef@\line@{\dimen@=\sd@Y\sinDirection\xydashl@ %?*[line1] + \ifnum\SemiDirectionChar<31 \D@c=\z@ \U@c=\dimen@ \DN@{\d@Y<\z@}% %?*[line2] + \else\ifnum\SemiDirectionChar<64 \D@c=\dimen@ \U@c=\z@ \DN@{\z@<\d@Y}% + \else\ifnum\SemiDirectionChar<96 \D@c=\dimen@ \U@c=\z@ \DN@{\d@X<\z@}% + \else \D@c=\z@ \U@c=\dimen@ \DN@{\d@X<\z@}\fi\fi\fi + \setboxz@h{\line@@}\ht\z@=\U@c \dp\z@=\D@c %?*[line3] + \L@c=\z@ \R@c=\wdz@ + \ifdim\next@ \dimen@=\R@c \R@c=\L@c \L@c=\dimen@ %?*[line4] + \dimen@=\U@c \U@c=\D@c \D@c=\dimen@ \advance\dimen@-\U@c + \lower\dimen@\boxz@ + \else \boxz@ \fi +% +%\ifnum\SemiDirectionChar=31\relax +% \W@{LINE@(\the\SemiDirectionChar): WH=<\the\L@c+\the\R@c,\the\D@c+\the\U@c>; +% d=<\the\d@X,\the\d@Y>}\fi +% + \edef\tmp@{\egroup \U@c=\the\U@c \D@c=\the\D@c \L@c=\the\L@c \R@c=\the\R@c}% %?*[line5] + \tmp@ + \Edge@c={\rectangleEdge}%%%%%\Invisible@false\Hidden@false + \ifdim\z@<\U@c \def\Upness@{1}\else \def\Upness@{0}\fi + \ifdim\z@<\L@c \def\Leftness@{1}\else \def\Leftness@{0}\fi + \def\Drop@@{\styledboxz@}\def\Connect@@{\solid@}} + +\xydef@\line@@{{\xydashfont\SemiDirectionChar\/}} +\DOCMODE) + + \BUG: |\line@| should allow the size of the object to be changed + after typesetting---this should make |\Connect@@| do dashing. Hm. + + As mentioned above a dash will `Connect' to make lines by using rules + when strictly horizontal or vertical. This is controlled by enabling + or disabling the test |\ifjusthvtest@| discussed below. + +\DOCMODE( +\xydef@\solid@{% +% +%\W@{SOLID}\xystatus@:% +% + \checkXy@rules@\solidhrule@\solidvrule@{\straight@\solidSpread@}} + +\xydef@\checkXy@rules@#1#2#3{% + \dimen@=\Y@c \advance\dimen@-\Y@p + \ifjusthvtest@.05pt>\ifdim\dimen@<\z@-\fi\dimen@ \DN@{#1}% + \else \dimen@=\X@c \advance\dimen@-\X@p + \ifjusthvtest@.05pt>\ifdim\dimen@<\z@-\fi\dimen@ \DN@{#2}% + \else \DN@{#3}\fi\fi \next@} +\DOCMODE) + + Finally, we give the algorithm for `spreading' the dashes along a + solid line: just add an extra dash so they always overlap + (see~\S??[algo.connection] for a proper defintion of the requirements + to spreading). + +\DOCMODE( +\xydef@\solidSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + By default \Xy-pic will typeset horizontal and vertical |\dir{-}| + connections using \TeX\ rules. Unfortunately rules is the feature of + the DVI format most commonly handled wrong by DVI drivers. Therefore + \Xy-pic provides the <decor>ations +% +\begin{defs1} +% + ??c![\NoRules] \cr + ??c![\UseRules] \cr +% +\end{defs1} +\noindent\unskip +% + that will switch the use of such off and on. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + They simply redefine the conditional used to select typesetting + with rules in |\solid@| above: + +\DOCMODE( +\xylet@\ifjusthvtest@=\ifdim + +\xydef@\NoRules{\let\ifjusthvtest@=\iffalse} +\xydef@\UseRules{\let\ifjusthvtest@=\ifdim} +\DOCMODE) + + The actual typesetting essentially means calling |\drop@| to box with + a rule of the appropriate length and with line width set to that of + ??c![\xydashfont] (as stored in |\xydashw@|). + +\DOCMODE( +\xydef@\solidvrule@{\no@@ \solidvrule@typeset \ifHidden@\else\noinsert@\fi + \solidvrule@pre} + +\xydef@\solidvrule@pre{% +% +%\W@{VRULE SETUP}% +% + \def\Cbreak@@{% +% +%\W@{VRULE Cbreak}% +% + \connectRestore@ \swap@\lastbreak@@\swap@ + \solidvrule@typeset \edef\lastbreak@@{\cfromthec@}\Creset@@}% + \def\Clast@@{% +% +%\W@{VRULE Clast}% +%\let\Clast@@=\undefined +% + \connectRestore@ \Creset@@\swap@\lastbreak@@\swap@ + \solidvrule@typeset \Creset@@ \edef\lastbreak@@{\cfromthep@}}% +} + +\xydef@\solidvrule@typeset{% +% +%\W@{VRULE TYPESET}\xystatus@cp:% +% + \ifInvisible@ \let\next@=\relax \else \let\next@=\solidvrule@typeset@ \fi + \checkoverlap@@ \next@} + +\xydef@\solidvrule@typeset@{{% +% + \advance\X@c\X@p \X@c=.5\X@c \X@p=\X@c + \advance\X@c-.5\xydashw@ \advance\X@p.5\xydashw@ +% + \ifdim\Y@c<\Y@p \advance\Y@c\U@c \advance\Y@p-\D@p + \else \swapdimen@\Y@c\Y@p \advance\Y@c\U@p \advance\Y@p-\D@c \fi +% + \Droprule@}} + +\xydef@\solidhrule@{\no@@ \solidhrule@typeset \ifHidden@\else\noinsert@\fi + \solidhrule@pre} + +\xydef@\solidhrule@pre{% +% +%\W@{HRULE SETUP}% +% + \def\Cbreak@@{% +% +%\W@{HRULE Cbreak}% +% + \connectRestore@ \swap@\lastbreak@@\swap@ + \solidhrule@typeset \edef\lastbreak@@{\cfromthec@}\Creset@@}% + \def\Clast@@{% +% +%\W@{HRULE Clast}% +%\let\Clast@@=\undefined +% + \connectRestore@ \Creset@@\swap@\lastbreak@@\swap@ + \solidhrule@typeset \Creset@@ \edef\lastbreak@@{\cfromthep@}}% +} + +\xydef@\solidhrule@typeset{% +% +%\W@{HRULE TYPESET}\xystatus@cp:% +% + \ifInvisible@ \let\next@=\relax \else \let\next@=\solidhrule@typeset@ \fi + \checkoverlap@@ \next@} + +\xydef@\solidhrule@typeset@{{% + \ifdim\X@c<\X@p \advance\X@c\R@c \advance\X@p-\L@p + \else \swapdimen@\X@c\X@p \advance\X@c\R@p \advance\X@p-\L@c \fi + \advance\Y@c\Y@p \Y@c=.5\Y@c \Y@p=\Y@c + \advance\Y@c-.5\xydashw@ \advance\Y@p.5\xydashw@ + \Droprule@}} +\DOCMODE) + + |\Droprule@| puts the actual ink on the page: with lower left corner + at $c$ and upper right corner at~$p$. + +\DOCMODE( +\xydef@\Droprule@{\advance\X@p-\X@c +% +%\W@{: kern\the\X@c\space width\the\X@p\space depth-\the\Y@c\space +% height\the\Y@p}% +% + \setboxz@h{\kern\X@c \vrule width\X@p depth-\Y@c height\Y@p}% + \ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ \Drop@@} +\DOCMODE) + +\paragraph*{Dots:} + + |\dir{.}| creates a very boring dot when used as an <object>, but + interesting dotted lines when used to connect. ??c![\zerodot] should + expand to a zero-sized box with a dot (initialised to use + |\zero|\-|dotbox@|); the <object> is built using |\pointlike@| <text> + <spread-dimen> that we will use again later. + +\DOCMODE( +\xydef@\zerodot{\copy\zerodotbox@} + +\xydefcsname@{dir1{.}}{\point@} +\xydefcsname@{dir2{.}}{\point@ \double@\xydashh@} +\xydefcsname@{dir3{.}}{\point@ \triple@\xydashh@} +\xyletcsnamecsname@{dir0{.}}{dir{}} +\xyletcsnamecsname@{dir{.}}{dir1{.}} +\xyletcsnamecsname@{dir{:}}{dir2{.}} + +\xydef@\point@{\pointlike@\zerodot\p@} + +\xydef@\pointlike@#1#2{% + \setboxz@h{#1}\wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@\egroup +% \Invisible@false \Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}\ctipEdge@ + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@{\dottedSpread@{#2}}}} +\DOCMODE) + + This is reflected by the rather complicated spreading routine: + `Dotting' is the art of putting zero-sized objects together with + equal distance independent of the chosen direction. So we must + recompute the number of segments $N$ (likely to be very big or + ${-}1$) with trigonometry; using "radius" for the individual dots + this becomes +$$ +\begin{array}{lc} + ??_[dottedspread] + & A := \abs{\cos{|\Direction|}}*"radius"\\ + & B := \abs{\sin{|\Direction|}}*"radius"\\ + ??_[dottedspread1] + & "if"~A+B \gt \abs{|\d@X|}+\abs{|\d@Y|}~"then"~N=0~"and exit" \\ + ??_[dottedspread2] + & |<|A|,|B|>| := 2*|<|A|,|B|>|\\ + & "Filler" := <box with the original filler centered...>\\ + ??_[dottedspread3] + & |<\d@X,\d@Y>| := |<\d@X,\d@Y>| + |<\sd@X|*A|,\sd@Y|*B|>|\\ + & |<|X|,|Y|>| := |<|X|,|Y|>| + |<\sd@X|*A/2|,\sd@Y|*B/2|>|\\ + ??_[dottedspread4] + & N := \floor{"if"~\abs{|\d@X|}\gt\abs{|\d@Y|} + ~"then" \abs{|\d@X|}/A else \abs{|\d@Y|}/B} + 1 +\end{array} +$$ + as realised below: + +\DOCMODE( +\xydef@\dottedSpread@#1{%\setupDirection@ %?*[dottedspread] + \dimen@=#1\relax \DN@{\A@=2\A@ \B@=2\B@ \dottedSpread@i}% + \A@=\sd@X\cosDirection\dimen@ \B@=\sd@Y\sinDirection\dimen@ + \dimen@=\A@ \advance\dimen@\B@ %?*[dottedspread1] + \dimen@ii=\sd@X\d@X \advance\dimen@ii\sd@Y\d@Y + \ifdim\dimen@>\dimen@ii \DN@{\count@@=\z@}\fi + \next@} + +\xydef@\dottedSpread@i{%\setupDirection@ %?*[dottedspread2] + \global\setbox8=\hbox to\A@{\hss + \kern.5\A@\box\lastobjectbox@\kern.5\A@\hss}\dp8=.5\B@ \ht8=.5\B@ + \advance\d@X\sd@X\A@ \advance\d@Y\sd@Y\B@ %?*[dottedspread3] + \advance\X@c\sd@X.5\A@ \advance\Y@c\sd@Y.5\B@ + \ifdim\sd@Y\d@Y<\sd@X\d@X \dimen@=\sd@X\d@X %?*[dottedspread4] + \ifdim\zz@\A@\else \divide\dimen@\A@ \fi \count@@=\dimen@ + \else \dimen@=\sd@Y\d@Y + \ifdim\zz@\B@\else \divide\dimen@\B@ \fi \count@@=\dimen@ + \fi \advance\count@@\@ne} +\DOCMODE) +% +\noindent + A particular aspect of this is that we have to enlarge and recenter + the actual box used for the typesetting (|\lastobjectbox@|). + +\paragraph*{Squiggles:} + + These are just a lot of box maneuvering using the directional + characters of ??c![\xybsqlfont] (see~|xybsql10.mf| for details): + +\DOCMODE( +\xydefcsname@{dir1{~}}{\squiggle@} +\xydefcsname@{dir2{~}}{\squiggle@ \double@\xybsqlh@} +\xydefcsname@{dir3{~}}{\squiggle@ \triple@\xybsqlh@} +\xyletcsnamecsname@{dir0{~}}{dir{}} +\xyletcsnamecsname@{dir{~}}{dir1{~}} + +\xydef@\squiggle@{\xybsqlfont + \dimen@=\sd@X\cosDirection\xybsqll@ \advance\dimen@.1\p@ + \dimen@ii=\sd@Y\sinDirection\xybsqll@ + \kern\dimen@\squiggle@@ + \edef\tmp@{\egroup \U@c=\the\dimen@ii \L@c=\the\dimen@}\tmp@ + \wdz@=2\L@c \R@c=\L@c \ht\z@=\U@c \D@c=\U@c \dp\z@=\U@c + \Edge@c={\rectangleEdge}% +% \Invisible@false \Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@\squiggledSpread@}} + +\xydef@\squiggle@@{\DirectionChar \count@=\DirectionChar + \advance\count@-64 \ifnum\count@<\z@ \advance\count@128 \fi \char\count@} +\DOCMODE) + + The interesting bit is that they spread by not spreading, \ie, by + centering between the endpoints---this means +$$ +\begin{array}{ll} + X := X - d/2, dX := dX - d + &\hbox{where}~ d = |\sd@X|(\abs{dX} - N*A + |.1pt|)\\ + Y := Y - d/2, dY := dY - d + &\hbox{where}~ d = |\sd@Y|(\abs{dY} - N*B + |.1pt|)\\ +\end{array} +$$ + +\DOCMODE( +\xydef@\squiggledSpread@{% + \dimen@=\d@X \advance\dimen@-\sd@X\count@@\A@ \advance\dimen@\sd@X.3\p@ + \advance\X@c-.5\dimen@ \advance\d@X-\dimen@ + \dimen@=\d@Y \advance\dimen@-\sd@Y\count@@\B@ \advance\dimen@\sd@Y.3\p@ + \advance\Y@c-.5\dimen@ \advance\d@Y-\dimen@} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Double and triple directionals:} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + As can be seen by the last two columns, these (and most of the other + connectors) also exist in double and triple versions with a |2| or a + |3| prepended to the name. For convenience |\dir{=}| and |\dir{:}| + are synonyms for |\dir2{-}| and |\dir2{.}|, respectively; similarly + |\dir{==}| is a synonym for |\dir2{--}|. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This is very simple, really: |\double@| and |\triple@| do the work by + redefining the |\Drop@@| method to do its job twice and thrice. + \TODO: should probably extend any already defined |\Drop@@| method? + +\DOCMODE( +%\xydef@\double@#1{\edef\Drop@@{\dimen@=#1\relax +% \dimen@=.5\dimen@ \A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@ +% \setbox2=\hbox{\kern\A@\raise\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 % +% \setbox2=\hbox{\kern-\A@\raise-\B@\boxz@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 }} + +%\xydef@\triple@#1{\edef\Drop@@{\dimen@=#1\relax +% \A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@ +% \setbox2=\hbox{\kern\A@\raise\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 % +% \setbox2=\hbox{\kern-\A@\raise-\B@\copy\z@}\dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 +% \dp\z@=\z@ \ht\z@=\z@ \wdz@=\z@ \boxz@}} + +\xydef@\double@#1{\edef\Drop@@{\dimen@=#1\relax + \dimen@=.5\dimen@ \A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@ + \setboxz@h{\setbox2=\hbox{\kern\A@\raise\B@\copy\z@}% + \dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 % + \setbox2=\hbox{\kern-\A@\raise-\B@ \noexpand\boxz@}% + \dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 }% + \ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ \noexpand\styledboxz@}} + +\xydef@\triple@#1{\edef\Drop@@{\dimen@=#1\relax + \A@=-\sinDirection\dimen@ \B@=\cosDirection\dimen@ + \setboxz@h{\setbox2=\hbox{\kern\A@\raise\B@\copy\z@}% + \dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 % + \setbox2=\hbox{\kern-\A@\raise-\B@\copy\z@}% + \dp2=\z@ \ht2=\z@ \wd2=\z@ \box2 % + \dp\z@=\z@ \ht\z@=\z@ \wdz@=\z@ \noexpand\boxz@}% + \ht\z@=\z@ \dp\z@=\z@ \wd\z@=\z@ \noexpand\styledboxz@}} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Dashing directionals:} + + First traditional dashing: + +\DOCMODE( +\xydefcsname@{dir1{--}}{\dash@} +\xydefcsname@{dir2{--}}{\dash@ \double@\xydashh@} +\xydefcsname@{dir3{--}}{\dash@ \triple@\xydashh@} +\xyletcsnamecsname@{dir0{--}}{dir{}} +\xyletcsnamecsname@{dir{--}}{dir1{--}} +\xyletcsnamecsname@{dir{==}}{dir2{--}} + +\xydef@\dash@{\line@ \wdz@=2\wdz@ \ht\z@=2\ht\z@ \dp\z@=2\dp\z@ + \multiply\D@c\tw@ \multiply\U@c\tw@ \multiply\L@c\tw@ \multiply\R@c\tw@ + \def\Connect@@{\straight@\dashedSpread@}} +\DOCMODE) + + Since the dashes should reach the endpoints we do this: +$$ +\begin{array}{l} + "if"~ N\gt 0 ~"then"~ N := N+1\\ + dX := dX + d/2 ~"where"~ d = |\sd@X|A\\ + dY := dY + d/2 ~"where"~ d = |\sd@Y|B\\ + "if"~ dX\gt 0 ~"then"~ X := X + A/2\\ + Y := Y + |\sd@Y|A/2\\ +\end{array} +$$ +\DOCMODE( +\xydef@\dashedSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi + \advance\d@X\sd@X.5\A@ \advance\d@Y\sd@Y.5\B@ + \ifdim\z@<\d@X \advance\X@c.5\A@ \fi \advance\Y@c\sd@Y.5\B@} +\DOCMODE) + + Dashed dashing of squiggled lines are simpler since squiggles are + symmetric: + +\DOCMODE( +\xydefcsname@{dir1{~~}}{\dashsquiggle@} +\xydefcsname@{dir2{~~}}{\dashsquiggle@ \double@\xybsqlh@} +\xydefcsname@{dir3{~~}}{\dashsquiggle@ \triple@\xybsqlh@} +\xyletcsnamecsname@{dir0{~~}}{dir{}} +\xyletcsnamecsname@{dir{~~}}{dir1{~~}} + +\xydef@\dashsquiggle@{\squiggle@ + \multiply\D@c\tw@ \multiply\U@c\tw@ \multiply\L@c\tw@ \multiply\R@c\tw@ + \dimen@=\L@c \advance\dimen@\R@c \wdz@=\dimen@ \ht\z@=\U@c \dp\z@=\D@c + \def\Connect@@{\straight@\dashsquiggledSpread@}} +\DOCMODE) + + The spreading of squiggles is similarly simpler: we just shave $1/4$ + squiggle size of each end of the conection in order to eliminate the + blank space at both ends: + +\DOCMODE( +\xydef@\dashsquiggledSpread@{\ifnum\z@<\count@@ \advance\count@@\@ne \fi + \advance\X@c.5\A@ \advance\d@X.5\A@ \advance\Y@c.25\B@ \advance\d@Y.5\B@} +\DOCMODE) + + Finally ``dashed dotting'' synonyms: + +\DOCMODE( +\xyletcsnamecsname@{dir1{..}}{dir{.}} +\xyletcsnamecsname@{dir2{..}}{dir2{.}} +\xyletcsnamecsname@{dir3{..}}{dir3{.}} +\xyletcsnamecsname@{dir{..}}{dir1{.}} +\xyletcsnamecsname@{dir{::}}{dir2{.}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[Plain tips] + + The group of "plain tips" contains basic objects that are useful as + markers and arrowheads making connections, so each is shown at the + end of a dotted connection of the appropriate kind. + + They may also be used as connectors and will build dotted + connections. \eg, |**@{>}| typesets +$$ + \xy 0*++{}; (10,3)*++{} **@{>} \endxy +$$ + +\begin{exercise} + Typeset the following two $+$s and a tilted square: +\begin{code} +$$\xy + *{+}; p+(6,3)*{+} **{} ?(1) + *@{-} *!/-5pt/^\dir{-} + *^\dir{-} *!/^-5pt/\dir{-} +\endxy$$ +\end{code} +\docode +% + "Hint": the dash created by |\dir{-}| has the length |5pt| (here). +% +\answercode +\answertext{One way is} +\answertext\displaycode +\answertext{Thus we first create the two $+$s as $p$ and $c$ and connect them + with the dummy connection |**{}| to setup the direction parameters. + Then we move `on top of $c$' with |?(1)| and position the four sides + of the square using |^| and |_| for local direction changes and + |/|<dimen>|/| for skewing the resulting object by moving its + reference point in the opposite direction.}% +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\DOCMODE( +\xylet@\ctipEdge@=\czeroEdge@ +\DOCMODE) + + \TODO: Change tips to have a tiny size of 2sp which may be taken as + an indication that it is a tip (this can be used by some features, + \eg, `arrow'). + +\paragraph*{Arrow heads:} + + The ones intended for single connections are just characters from + ??c![\xyatipfont] and ??c![\xybtipfont]. + +\DOCMODE( +\xydefcsname@{dir1{>}}{\tip@} +\xydefcsname@{dir^{>}}{\atip@} +\xydefcsname@{dir_{>}}{\btip@} +\xyletcsnamecsname@{dir0{>}}{dir{}} +\xyletcsnamecsname@{dir{>}}{dir1{>}} + +\xydefcsname@{dir1{<}}{\reverseDirection@\tip@} +\xydefcsname@{dir^{<}}{\reverseDirection@\btip@} +\xydefcsname@{dir_{<}}{\reverseDirection@\atip@} +\xyletcsnamecsname@{dir0{<}}{dir{}} +\xyletcsnamecsname@{dir{<}}{dir1{<}} + +\xydef@\tip@{\tip@x\tip@@} +\xydef@\atip@{\tip@x\atip@@} +\xydef@\btip@{\tip@x\btip@@} + +\xydef@\tip@x#1{#1\egroup + \ctipEdge@ %\Invisible@false \Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}} + +\xydef@\tip@@{\atip@@\btip@@} +\xydef@\atip@@{\xyatipfont\DirectionChar} +\xydef@\btip@@{\xybtipfont\DirectionChar} +\DOCMODE) + + Double and triple tips are realised by taking the two halfs and + `wringing them apart'; as the naming indicates they are meant to be + put at the end of |2|- and |3|-connections. This is currently done + the slightly hacky (but efficient) way of adding directly to + ??c![\DirectionChar]; maybe this should be using |\vDirection@|? + +\DOCMODE( +\xydefcsname@{dir2{>}}{\Tip@} +\xydefcsname@{dir2{<}}{\reverseDirection@\Tip@} + +\xydef@\Tip@{\kern2.5pt \vrule height2.5pt depth2.5pt width\z@ + \Tip@@ \kern2.5pt \egroup + \U@c=2.5pt \D@c=2.5pt \L@c=2.5pt \R@c=2.5pt \Edge@c={\circleEdge}% +% \Invisible@false \Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}} + +\xydef@\Tip@@{\count@=\DirectionChar + \advance\count@-4 \ifnum\count@<\z@ \advance\count@128 \fi + \xyatipfont\char\count@ + \advance\count@ 8 \ifnum127<\count@ \advance\count@-128 \fi + \xybtipfont\char\count@} + +\xydefcsname@{dir3{>}}{\Ttip@} +\xydefcsname@{dir3{<}}{\composite@{}{:(-1,0)\dir3{>}}} + +\xydef@\Ttip@{\kern3.2pt \vrule height3.2pt depth3.2pt width\z@ + \Ttip@@ \kern3.2pt \egroup + \U@c=3.2pt \D@c=3.2pt \L@c=3.2pt \R@c=3.2pt \Edge@c={\circleEdge}% +% \Invisible@false \Hidden@false + \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@{\dottedSpread@\jot}}} + +\xydef@\Ttip@@{% + \setboxz@h\bgroup\reverseDirection@\line@ \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ + \kern-\L@c \boxz@ \kern\L@c + {\vDirection@(1,-.31)\xydashl@ \xyatipfont\char\DirectionChar}% + {\vDirection@(1,+.31)\xydashl@ \xybtipfont\char\DirectionChar}} +\DOCMODE) + +\paragraph*{Stopper:} + + |\dir{||}| makes a `stopper' using just the appropriate + ??c![\xydashfont] character rotated $90^\circ$ and centered; the |^| + and |_| variants are just shifted appropriately and two are used to + make the |2| and |3| variants longer. + +\DOCMODE( +\xydefcsname@{dir1{|}}{\stopper@} +\xydefcsname@{dir^{|}}{\aboveDirection@\xydashl@ + \shiftdir@\line@\z@ \pointlike@{}\xydashh@} +\xydefcsname@{dir_{|}}{\belowDirection@\xydashl@ + \shiftdir@\line@\z@ \pointlike@{}\xydashh@} +\xydefcsname@{dir2{|}}{\stopper@ \double@\xydashh@} +\xydefcsname@{dir3{|}}{\stopper@ \double@{2\xydashh@}} + +\xyletcsnamecsname@{dir0{|}}{dir{}} +\xyletcsnamecsname@{dir{|}}{dir1{|}} + +\xydef@\stopper@{\tip@x\stopper@@} + +\xydef@\stopper@@{\setboxz@h{\count@=\SemiDirectionChar \advance\count@64 % + \ifnum127<\count@ \advance\count@-128 \fi \xydashfont\char\count@\/}% + \setboxz@h{\kern-.5\wdz@ \dimen@=\sd@Y\cosDirection\xydashl@ + \ifnum\SemiDirectionChar=95 \dimen@=\sd@X\sd@Y\dimen@ \fi + \raise.5\dimen@\boxz@}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} +\DOCMODE) + +\paragraph*{Hooks:} + + These are halfcircles opening towards or opposite ??c![\Direction] and + fastened by their center or either endpoint. Build by lots of box + manipulation with the ??c![\xybsqlfont] quarter circles\dots\smiley + +\DOCMODE( +\xydefcsname@{dir1{(}}{\hook@} +\xydefcsname@{dir^{(}}{\ahook@} +\xydefcsname@{dir_{(}}{\bhook@} +\xyletcsnamecsname@{dir0{(}}{dir{}} +\xyletcsnamecsname@{dir{(}}{dir1{(}} + +\xydefcsname@{dir1{)}}{\reverseDirection@\hook@} +\xydefcsname@{dir^{)}}{\reverseDirection@\bhook@} +\xydefcsname@{dir_{)}}{\reverseDirection@\ahook@} +\xyletcsnamecsname@{dir0{)}}{dir{}} +\xyletcsnamecsname@{dir{)}}{dir1{)}} + +\xydef@\hook@{\tip@x\hook@@} +\xydef@\hook@@{\setboxz@h{\xybsqlfont + \vDirection@(1,-1){.707107\xybsqll@}% + \hbox{\DirectionChar + \kern-\d@Y\raise\d@X\hbox{\count@=\DirectionChar \advance\count@-32 % + \ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} + +\xydef@\ahook@{\tip@x\ahook@@} +\xydef@\ahook@@{\setboxz@h{\xybsqlfont + \vDirection@(1,-1){.707107\xybsqll@}\kern-\d@X + \lower\d@Y\hbox{\DirectionChar + \kern-\d@Y\raise\d@X\hbox{\count@=\DirectionChar \advance\count@-32 % + \ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} + +\xydef@\bhook@{\tip@x\bhook@@} +\xydef@\bhook@@{\setboxz@h{\xybsqlfont + \vDirection@(-1,-1){.707107\xybsqll@}\DirectionChar + \kern\d@X\raise\d@Y\hbox{\count@=\DirectionChar \advance\count@-96 % + \ifnum\count@<\z@ \advance\count@128 \fi \char\count@}}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} +\DOCMODE) + +\paragraph*{Quarter turns:} + + These are quarter circles fastened by their start or end point in + ??c![\Direction]. Build by box manipulation of the ??c![\xybsqlfont] + quarter circles. The intention is that the |`'| directionals are + half the corresponding |()| directional. + +\DOCMODE( +\xydefcsname@{dir^{'}}{\reverseDirection@\bturn@} +\xydefcsname@{dir_{'}}{\reverseDirection@\aturn@} + +\xydefcsname@{dir^{`}}{\aturn@} +\xydefcsname@{dir_{`}}{\bturn@} + +\xydef@\aturn@{\tip@x\aturn@@} +\xydef@\aturn@@{\setboxz@h{\xybsqlfont + \vDirection@(1,-1){.707107\xybsqll@}\kern-\d@X + \lower\d@Y\hbox{\DirectionChar}}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} + +\xydef@\bturn@{\tip@x\bturn@@} +\xydef@\bturn@@{\setboxz@h{\xybsqlfont + \vDirection@(-1,-1){.707107\xybsqll@}\DirectionChar}% + \wdz@=\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\note??=[Constructed tips] + + These tips are combinations of the plain tips provided for + convenience (and optimised for efficiency). New ones can be + constructed using ??c![\composite] and by declarations of the form +% +\begin{defs1} +% + ??c![\newdir] <dir> |{|<composite>|}|\cr +% +\end{defs1} +\noindent\unskip +% + which defines ??c![\dir]<dir> as the <composite> (see note~??[composite + object box] for the details). + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + ??c![\newdir] is simple: + +\DOCMODE( +\xydef@\newdir#1#{\newdir@{#1}} + +\xydef@\newdir@#1#2#3{\xydefcsname@{dir#1{#2}}{\composite@{}{#3}}} +\DOCMODE) + + Then the somewhat more efficient |\shiftdir@| used internally for + moving a tip in the current direction---it does so by making a local + hbox within which the argument tip is constructed and subsequently + shifted and made of zero size. Use as +$$ + |\shiftdir@|<tip@><dimen><tip@> +$$ + where <tip@> means a tip command without the leading |\hbox{|. + +\DOCMODE( +\xydef@\shiftdir@#1#2{% + \setbox\z@=\hbox\bgroup#1\relax + \setboxz@h{\dimen@ii=#2\relax + \dimen@=-\cosDirection\dimen@ii \advance\dimen@-\L@c + \kern\dimen@ \lower\sinDirection\dimen@ii\boxz@}% + \wdz@\z@ \ht\z@=\z@ \dp\z@=\z@ \boxz@} +\DOCMODE) + + Then the tips, with the |\tipjot@| hook allowing changing the spacing + of tips used for single lines. + +\DOCMODE( +\xylet@\tipjot@=\jot + +\xydefcsname@{dir1{>>}}{\shiftdir@\tip@\tipjot@ \tip@} +\xydefcsname@{dir^{>>}}{\shiftdir@\atip@\tipjot@ \atip@} +\xydefcsname@{dir_{>>}}{\shiftdir@\btip@\tipjot@ \btip@} +\xydefcsname@{dir2{>>}}{\composite@{}{h!/\tipjot@/\dir2{>}*\dir2{>}}} +\xydefcsname@{dir3{>>}}{\composite@{}{h!/\tipjot@/\dir3{>}*\dir3{>}}} +\xyletcsnamecsname@{dir0{>>}}{dir{}} +\xyletcsnamecsname@{dir{>>}}{dir1{>>}} + +\xydefcsname@{dir1{<<}}{\reverseDirection@ \shiftdir@\tip@\tipjot@ \tip@} +\xydefcsname@{dir^{<<}}{\reverseDirection@ \shiftdir@\btip@\tipjot@ \btip@} +\xydefcsname@{dir_{<<}}{\reverseDirection@ \shiftdir@\atip@\tipjot@ \atip@} +\xydefcsname@{dir2{<<}}{\composite@{}{h!/-\tipjot@/\dir2{<}*\dir2{<}}} +\xydefcsname@{dir3{<<}}{\composite@{}{h!/-\tipjot@/\dir3{<}*\dir3{<}}} +\xyletcsnamecsname@{dir0{<<}}{dir{}} +\xyletcsnamecsname@{dir{<<}}{dir1{<<}} + +\xydefcsname@{dir1{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@ + \pointlike@{}\jot} +\xydefcsname@{dir^{||}}{\shiftdir@{\aboveDirection@\xydashl@\line@}\xydashh@ + \shiftdir@{\aboveDirection@\xydashl@\line@}\z@ \pointlike@{}\jot} +\xydefcsname@{dir_{||}}{\shiftdir@{\belowDirection@\xydashl@\line@}\xydashh@ + \shiftdir@{\belowDirection@\xydashl@\line@}\z@ \pointlike@{}\jot} +\xydefcsname@{dir2{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@ + \pointlike@{}\jot \double@\xydashh@} +\xydefcsname@{dir3{||}}{\shiftdir@\stopper@\xydashh@ \shiftdir@\stopper@\z@ + \pointlike@{}\jot \double@{2\xydashh@}} +\xyletcsnamecsname@{dir0{||}}{dir{}} +\xyletcsnamecsname@{dir{||}}{dir1{||}} + +\xydefcsname@{dir1{>|}}{\shiftdir@\stopper@\z@ \tip@} +\xydefcsname@{dir2{>|}}{\composite@{}{\dir2{>}*\dir2{|}}} +\xydefcsname@{dir3{>|}}{\composite@{}{\dir3{>}*\dir3{|}}} +\xyletcsnamecsname@{dir0{>|}}{dir{}} +\xyletcsnamecsname@{dir{>|}}{dir1{>|}} + +\xydefcsname@{dir1{>>|}}{\shiftdir@\stopper@\z@ \shiftdir@\tip@\tipjot@ \tip@} +\xydefcsname@{dir2{>>|}}{\composite@{}{h!/\tipjot@/\dir2{>}*\dir2{>}*\dir2{|}}} +\xydefcsname@{dir3{>>|}}{\composite@{}{h!/\tipjot@/\dir3{>}*\dir3{>}*\dir3{|}}} +\xyletcsnamecsname@{dir0{>>|}}{dir{}} +\xyletcsnamecsname@{dir{>>|}}{dir1{>>|}} + +\xydefcsname@{dir1{|<}}{\reverseDirection@ \shiftdir@\stopper@\z@ \tip@} +\xydefcsname@{dir2{|<}}{\reverseDirection@ \shiftdir@\stopper@\z@ \Tip@} +\xydefcsname@{dir3{|<}}{\reverseDirection@ \shiftdir@\stopper@\z@ \Ttip@} +\xyletcsnamecsname@{dir0{|<}}{dir{}} +\xyletcsnamecsname@{dir{|<}}{dir1{|<}} + +\xydefcsname@{dir1{|<<}}{\reverseDirection@ + \shiftdir@\stopper@\z@ \shiftdir@\tip@\tipjot@ \tip@} +\xydefcsname@{dir2{|<<}}{% + \composite@{}{h!/-\tipjot@/\dir2{<}*\dir2{<}*\dir2{|}}} +\xydefcsname@{dir3{|<<}}{% + \composite@{}{h!/-\tipjot@/\dir3{<}*\dir3{<}*\dir3{|}}} +\xyletcsnamecsname@{dir0{|<<}}{dir{}} +\xyletcsnamecsname@{dir{|<<}}{dir1{|<<}} + +\xydefcsname@{dir1{|-}}{\shiftdir@\stopper@\z@ + \shiftdir@\line@\z@ \pointlike@{}\jot} +\xydefcsname@{dir^{|-}}{\shiftdir@{\aboveDirection@\xydashl@ \line@}\z@ + \shiftdir@\line@\z@ \pointlike@{}\jot} +\xydefcsname@{dir_{|-}}{\shiftdir@{\belowDirection@\xydashl@ \line@}\z@ + \shiftdir@\line@\z@ \pointlike@{}\jot} +\xydefcsname@{dir2{|-}}{\shiftdir@\stopper@\z@ + \shiftdir@\line@\z@ \pointlike@{}\jot \double@\xydashh@} +\xydefcsname@{dir3{|-}}{\shiftdir@\stopper@\z@ + \shiftdir@\line@\z@ \pointlike@{}\jot \triple@\xydashh@} +\xyletcsnamecsname@{dir0{|-}}{dir{}} +\xyletcsnamecsname@{dir{|-}}{dir1{|-}} +\xyletcsnamecsname@{dir{|=}}{dir2{|-}} + +\xydefcsname@{dir{+}}{% + \DN@##1{\composite@{}{##10\dir{|}*!C##10\dir{-}}}\addEQ@\next@} +\xyletcsnamecsname@{dir0{+}}{dir{}} + +\xydefcsname@{dir{x}}{\vDirection@(1,1)\jot + \DN@##1{\composite@{}{##10\dir{|}*!C##10\dir{-}}}\addEQ@\next@} +\xyletcsnamecsname@{dir0{x}}{dir{}} + +\xydefcsname@{dir{/}}{\vDirection@(1,-.3)\jot \stopper@} +\xyletcsnamecsname@{dir0{/}}{dir{}} + +\xydefcsname@{dir{//}}{\vDirection@(1,-.3)\jot + \shiftdir@\stopper@\xydashh@ \stopper@} +\xyletcsnamecsname@{dir0{//}}{dir{}} + +\xydefcsname@{dir{*}}{\solidpoint@} +\xydef@\solidpoint@{% + \pointlike@{\kern-1.8pt\lower1.8pt\hbox{$\scriptstyle\bullet$}}\jot} +\xyletcsnamecsname@{dir0{*}}{dir{}} + +\xydefcsname@{dir{o}}{\hollowpoint@} +\xydef@\hollowpoint@{% + \pointlike@{\kern-1.8pt\lower1.8pt\hbox{$\scriptstyle\circ$}}\jot} +\xyletcsnamecsname@{dir0{o}}{dir{}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\end{notes} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\begin{figure*}[ht] +\vss +\begin{syntax} +% + \multispan3|\cir| <radius> |{| <cir> |}|\hfil + & <cir>cle segment with <radius> +\cr +\noalign{\nobreak\smallskip\nobreak\hrule\nobreak\smallskip\nobreak} +% + ??w![<radius>] + &\iss & <empty> + & use $R_c$ as the radius +\cr + &\orr & <vector> + & use $X$ of the <vector> as radius +\cr +\noalign{\smallbreak} +% + ??w![<cir>] + &\iss & <empty> + & full circle of <radius> +\cr + &\orr & <diag> <orient> <diag> + & partial circle from first <diag>onal through to the + second <diag>onal in the <orient>ation +\cr +\noalign{\smallbreak} +% + ??w![<orient>] + &\iss & |^| + & anticlockwise +\cr + &\orr & |_| + & clockwise +\cr +\end{syntax} +\caption{\protect<cir>cles.} +??=[f.cir] +\vfill +\end{figure*} + + +\subsection{Circle segments} +??=[objectlib.circles] + +\DOCMODE( +\message{circles,} +\DOCMODE) + + Circle <object>s are round and typeset a segment of the circle + centered at the reference point. The syntax of circles is described + in figure~??[f.cir] with explanations below. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The |\cir| command is the hub: it parses the optional <radius> (to + |\R@|, default from $R_c$) and |{|<cir>|}|, bailing out with a + |\zerodot| if the radius is to small: + +\DOCMODE( +\xydef@\cir#1#{\hbox\bgroup + \afterVECTORorEMPTY{\xy@@{\R@=\X@c}\cir@}{\xy@@{\R@=\R@c}\cir@}#1@} + +\xydef@\cir@#1@#2{% + \DN@{#1}\ifx\next@\empty\else \xyerror@{illegal circle <radius>: must be + <vector> or <empty>}{}\fi + \afterCIRorDIAG{\xyFN@\cir@cir}{\xyFN@\cir@diag}#2@} +\DOCMODE) + + The code to actually typeset the <cir> just parsed starts by checking + that the <cir> was immediately followed by the |@| we put there in + |\cir|: + +\DOCMODE( +\xydef@\cir@cir{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\cir@cir}%gobble spaces + \else \ifx @\next \DN@ @{\cir@i}% + \else \xyerror@{illegal <cir>: must have form <diag><orient><diag> or + <empty>}{}% + \fi\fi \next@} +\DOCMODE) + + Similarly when an <empty> one was given---the parser will recognise + this as a <diag> but we hack that here: + +\DOCMODE( +\xydef@\cir@diag{% + \DN@{\xyerror@{illegal <cir>: must have form <diag><orient><diag> or + <empty>}{}}% + \ifx @\next \ifnum\count@=8 % + \DN@ @{\def\CIRin@@{0}\def\CIRorient@@{\CIRfull@}\def\CIRout@@{7}\cir@i}% + \fi\fi \next@} +\DOCMODE) + + \dots and then use the constructed methods to build it: + +\DOCMODE( +\xydef@\cir@i{% + \ifnum\CIRin@@=8 \xyerror@{incomplete <cir> specification}{% +The <cir> you specified as <diag><orient><diag> is not sufficiently specific.}% + \def\CIRin@@{0}\fi + \ifdim\R@<.5\p@ \R@=\z@ \zerodot + \else \CIRorient@@ \cirbuild@ \fi + \L@c=\R@ \R@c=\R@ \D@c=\R@ \U@c=\R@ \def\Leftness@{.5}\def\Upness@{.5}% + \def\Drop@@{\styledboxz@}\def\Connect@@{\straight@\relax}% + \Edge@c={\circleEdge}\OBJECT@x} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Parsing:} + + The |\afterCIRorDIAG| parser handles the parsing: it either +% +\begin{itemize} + +\item + parses the <cir> and sets "in", "orient", and "out", and passes + control to the first argument continuation, or + +\item + parses the single <diag> specified, store it in |\count@| (as |8| if + an <empty> one given), and pass control to the second continuation + argument, + +\end{itemize} +% + where the <diag> internal representation number of note~??[diagonal] + of is used. An <empty> circle is treated as an <empty> diagonal; + specifying an <empty> first <diag> of a <cir> is equivalent to using + the value of the "in" method at call time. + + The parser is very simple, setting methods stored in the usual + |@@|-terminated control sequences (\TODO: Rename all non-method + control sequences that end in |@@|\dots to use |@|<romannumeral> + suffixes\dots): + +\DOCMODE( +\xydef@\CIRin@@{3} +\xydef@\CIRout@@{3} +\xylet@\CIRorient@@=\empty + +\xydef@\afterCIRorDIAG#1#2{\def\afterCIR@{#1}\def\afterCIRDIAG@{#2}\xyFN@\CIR@} + +\xylet@\afterCIR@=\empty +\xylet@\afterCIRDIAG@=\empty + +\xydef@\CIR@{\count@=8 \afterDIAG{\edef\CIRin@@{\the\count@}\xyFN@\CIR@@}} + +\xydef@\CIR@@{% + \ifx \space@\next \expandafter\DN@\space{\xyFN@\CIR@@}%gobble spaces + \else\ifx ^\next + \DN@ ^{\def\CIRorient@@{\CIRacw@}% + \afterDIAG{\edef\CIRout@@{\the\count@}\afterCIR@}}% + \else\ifx _\next + \DN@_{\def\CIRorient@@{\CIRcw@}% + \afterDIAG{\edef\CIRout@@{\the\count@}\afterCIR@}}% + \else + \DN@{\def\CIRorient@@{\relax}\afterCIRDIAG@}% + \fi\fi\fi \next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The default is to generate a "full circle" with the specified radius, + \eg, +$$ +\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0} +\begin{array}{ccc} + |\xy*\cir<4pt>{}\endxy| + &\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{}\endxy} +\cr + |\xy*{M}*\cir{}\endxy| + &\hbox{---}& \quotesmash{\xy*{M}*\cir{}\endxy} +\end{array} +$$ + All the other circle segments are subsets of this and have the shape + that the full circle outlines. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Finally we present the "orient" methods. They use these `internal + methods' to actually draw the circles + +\DOCMODE( +\xylet@\CIRtest@@=\relax +\xydef@\CIRlo@@{0} +\xydef@\CIRhi@@{0} +\DOCMODE) + + Below we call them "lo", "hi", and "test"; the first two are coded as + described in note ??[diagonal] and the last takes two arguments: a + dimension and something to do if the test succeeds. |\count@@| and + |\count@| should be set to "in" and "out" internally as well in case + |\cirbuild@| and friends below should be used. + + The dummy "orient" used for simple circles is the simplest: + +\DOCMODE( +\xydef@\CIRfull@{\def\CIRtest@@##1##2{##2}} +\DOCMODE) + + The kernel |\cirbuild@| builds the actual <object> using characters + from the ??c![\xycircfont] assumed coded like |xycirc10.mf|: + |\cirrestrict@@| choses a group and adjusts the radius |\R@| to fit it + exactly. The group is multiplied by 8 to get the group character + offset [|\count@|]. + +\DOCMODE( +\xydef@\cirbuild@{\cirrestrict@@ \multiply\count@8 % + \circhar@0\circhar@7\kern\dimen@ + \circhar@1\circhar@6\kern\dimen@ + \circhar@2\circhar@5\kern\dimen@ + \circhar@3\circhar@4\kern\dimen@} + +\xydef@\circhar@#1{% + \setboxz@h{\circhar@@{#1}}\dimen@=\wdz@ \wdz@=\z@ \ht\z@=\R@ \dp\z@=\R@ + \CIRtest@@#1{\styledboxz@}\setbox\z@=\copy\voidb@x} + +\xydef@\circhar@@#1{{\xycircfont \advance\count@#1\relax \char\count@}} +\DOCMODE) + + |\cirrestrict@@| computes the group $g$ [|\count@|] of circle segments + to use from the radius $r$ [|\R@|] using the formula (the reverse of + the one in |xycirc10.mf|) +$$ +\def\arraystretch{1} +g = \left\{ \begin{array}{ll} + \floor{r\over1|pt|}-1 &\textrm{if}~ 1|pt|\le r\lt 8|pt|\\ + \floor{r\over2|pt|}+3 &\textrm{if}~ 8|pt|\le r\lt 16|pt|\\ + \floor{r\over4|pt|}+7 &\textrm{if}~16|pt|\le r\lt 32|pt|\\ + 15 &\textrm{if}~32|pt|\le r \end{array} +\right. +$$ + (where we know from |\cir@i| that $r\ge\frac12|pt|$), and then + adjusts the radius to be exactly the one chosen through the use of + group $g$ using the formula in |xycirc10.mf|\dots this is necessary + because of the restriction on |tfm| files that they can only have 15 + different nonzero heights and depths. Subsequent calls to + |\cirrestrict@@| should compute the same values. + +\DOCMODE( +\xydef@\cirrestrict@@{\begingroup \dimen@=\R@ + \setboxz@h{\xycircfont\char\z@\char\@ne}\A@=\wdz@ + \ifdim\R@<8\A@ \count@=\dimen@ \divide\count@\A@ \advance\count@\m@ne + \else\ifdim\R@<16\A@ \count@=\dimen@ + \dimen@=2\A@ \divide\count@\dimen@ \advance\count@3 % + \else\ifdim\R@<32\A@ \count@=\dimen@ + \dimen@=4\A@ \divide\count@\dimen@ \advance\count@7 % + \else \count@=15 \fi\fi\fi + \R@=\A@ + \ifnum\count@<8 \multiply\R@\count@ \advance\R@\A@ + \else\ifnum\count@<12 \multiply\R@\count@ \multiply\R@\tw@ \advance\R@-6\A@ + \else\ifnum\count@<16 \multiply\R@\count@ \multiply\R@ 4 \advance\R@-28\A@ + \else \multiply\R@ 32 \fi\fi\fi + \edef\@tmp{\endgroup \R@=\the\R@ \count@=\the\count@}\@tmp} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + "Partial circle segments" with <orient>ation are the part of the full + circle that starts with a tangent vector in the direction of the + first <diag>onal (see note~??[diagonal]) and ends with a tangent + vector in the direction of the other <diag>onal after a clockwise + (for |_|) or anticlockwise (for |^|) turn, \eg, +$$ +\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0} +\begin{array}{ccc} + |\xy*\cir<4pt>{l^r}\endxy| + &\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{l^r}\endxy} +\\ + |\xy*\cir<4pt>{l_r}\endxy| + &\hbox{---}& \quotesmash{\xy*\cir<4pt>{l_r}\endxy} +\\ + |\xy*\cir<4pt>{dl^u}\endxy| + &\hbox{---}& \quotesmash{\xy*\cir<4pt>{dl^u}\endxy} +\\ + |\xy*\cir<4pt>{dl_u}\endxy| + &\hbox{---}& \quotesmash{\xy*\cir<4pt>{dl_u}\endxy} +\\ + |\xy*+{M}*\cir{dr_ur}\endxy| + &\hbox{---}& \quotesmash{\xy*+{M}*\cir{dr_ur}\endxy} +\end{array} +$$ + If the same <diag> is given twice then nothing is typeset, \eg, +$$ +\def\quotesmash#1{\setbox0=\hbox{``$\vcenter{#1}$''}\ht0=8pt \dp0=3pt \box0} +\begin{array}{ccc} + |\xy*\cir<4pt>{u^u}\endxy| + &\hbox{typesets}& \quotesmash{\xy*\cir<4pt>{u^u}\endxy} +\end{array} +$$ + Special care is taken to setup the <diag>onal defaults: +% +\begin{itemize} + +\item + After |^| the default is the diagonal $90^\circ$ anticlockwise from + the one before the |^|. + +\item + After |_| the default is the diagonal $90^\circ$ clockwise from the + one before the |_|. + +\end{itemize} +% + The <diag> before |^| or |_| is required for ??c![\cir] <objects>. + +\begin{exercise} + Typeset the following shaded circle with radius |5pt|: +% +\begin{code} +$$\xy + *\cir<5pt>{} + *!<-.2pt,.2pt>\cir<5pt>{dr^ul} + *!<-.4pt,.4pt>\cir<5pt>{dr^ul} + *!<-.6pt,.6pt>\cir<5pt>{dr^ul} +\endxy$$ +\end{code} +\docode +% +\answertext{One way is to add extra half circles skewed such that they create + the illusion of a shade:} +\answercode +\answertext\displaycode +\end{exercise} + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + These two macros implement the defaults and setup of "lo" and "hi" + for anticlockwise and clockwise segments. Here is what they set: +$$ +\begin{array}{\otherbar c\otherbar cc\otherbar l\otherbar} +\hline + ??w![<cir>] & "lo" & "hi" & "test"(s) \\ +\hline + d_1|^|d_2, d_1\le d_2 & d_1 -_8 1 & d_2 -_8 1 & {"lo"\le s}\wedge{s\lt "hi"}\\ + d_1|^|d_2, d_1\gt d_2 & d_2 -_8 1 & d_1 -_8 1 & {s \lt"lo"} \vee {"hi"\le s}\\ + d_1|_|d_2, d_1\lt d_2 & d_1 +_8 3 & d_2 +_8 3 & {s \lt"lo"} \vee {"hi"\le s}\\ + d_1|_|d_2, d_1\ge d_2 & d_2 +_8 3 & d_1 +_8 3 & {"lo"\le s}\wedge{s\lt "hi"}\\ +\hline +\end{array} +$$ + where $+_8$ and $-_8$ are $+$ and $-$ modulo 8; $d_1$ and $d_2$ are + in |\count@@| and |\count@|, respectively. + +\DOCMODE( +\xydef@\CIRacw@{\count@@=\CIRin@@ \count@=\CIRout@@ + \ifnum\count@=8 \count@=\count@@ + \ifnum\count@<6 \advance\count@\tw@ \else \advance\count@-6 \fi \fi + \ifnum\count@@<\@ne \advance\count@@7 \else \advance\count@@\m@ne \fi + \ifnum\count@<\@ne \advance\count@7 \else \advance\count@\m@ne \fi + \ifnum\count@@>\count@ \let\CIRtest@@=\CIRtest@outside + \edef\CIRlo@@{\the\count@}\edef\CIRhi@@{\the\count@@}% + \else \let\CIRtest@@=\CIRtest@inside + \edef\CIRlo@@{\the\count@@}\edef\CIRhi@@{\the\count@}% + \fi} + +\xydef@\CIRcw@{\count@@=\CIRin@@ \count@=\CIRout@@ + \ifnum\count@=8 \count@=\count@@ + \ifnum\count@>\@ne \advance\count@-\tw@ \else \advance\count@6 \fi \fi + \ifnum\count@@<5 \advance\count@@\thr@@ \else \advance\count@@-5 \fi + \ifnum\count@<5 \advance\count@\thr@@ \else \advance\count@-5 \fi + \ifnum\count@@<\count@ \let\CIRtest@@=\CIRtest@outside + \edef\CIRlo@@{\the\count@@}\edef\CIRhi@@{\the\count@}% + \else \let\CIRtest@@=\CIRtest@inside + \edef\CIRlo@@{\the\count@}\edef\CIRhi@@{\the\count@@}% + \fi} + +\xydef@\CIRtest@inside#1#2{\let\next@=\relax + \ifnum\CIRlo@@>#1\else \ifnum#1<\CIRhi@@\DN@{#2}\fi\fi \next@} + +\xydef@\CIRtest@outside#1#2{\let\next@=\relax + \ifnum\CIRlo@@>#1\DN@{#2}\else \ifnum#1<\CIRhi@@\else\DN@{#2}\fi\fi \next@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Text} +??=[objectlib.text] + +\DOCMODE( +\message{text;} +\DOCMODE) + + Text in pictures is supported through the <object> construction +% +\begin{defs1} +??c![\txt] <width> <style> |{|<text>|}|\cr +\end{defs1} +\noindent\unskip +% + that builds an object containing <text> typeset to <width> using + <style>; in <text> |\\| can be used as an explicit line break; all + lines will be centered. <style> should either be a font command or + some other stuff to do for each line of the <text> and <width> should + be either |<|<dimen>|>| or <empty>. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The code just parses the <width> defaulting it to |<\maxdimen>| which + is recognised as `free form'. + +\DOCMODE( +\xydef@\txt{\hbox\bgroup \xyFN@\txt@} + +\xydef@\txt@{% + \addLT@\ifx\next \addGT@{\addLT@\DN@##1}{\A@=##1\txt@i}% + \else \DN@{\A@=\maxdimen \txt@i}\fi \next@} + +\xydef@\txt@i#1#{% + \setboxz@h{#1\mathstrut}\dimen@=\ht\z@ \advance\dimen@\dp\z@ + \baselineskip=1.1\dimen@ \lineskip=.2\dimen@ \lineskiplimit=\lineskip + \def\txtline@@##1{\txtline@{#1}{##1}}\object@\txt@ii} + +\xylet@\txtline@@=\eat@ +\xydef@\txtline@#1#2{\relax\setboxz@h{#1{\ignorespaces #2\unskip}}% + \ifdim\A@<\wdz@ \setboxz@h{\hsize=\A@ + \leftskip=0pt plus4em \rightskip=\leftskip + \parfillskip=0pt \parindent=0pt % + \spaceskip=.3333em \xspaceskip=.5em % + \pretolerance=9999 \tolerance=9999 % + \hyphenpenalty=9999 \exhyphenpenalty=9999 % + \vbox{#1\noindent\ignorespaces #2\unskip}}% + \else\ifdim\A@<\maxdimen\setboxz@h to\A@{\hfil\boxz@\hfil}\fi\fi + \boxz@} + +\xydef@\txt@ii#1{\vbox{% + \let\\=\cr + \tabskip=\z@skip \halign{\relax\hfil\txtline@@{##}\hfil\cr\leavevmode#1\crcr}}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{\Xy-pic options} +??=[option] +% + \NOTE: \LaTeXe\ users should also consult the paragraph on ``xy.sty'' + in~\S??[env.loading]. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Loading} +??=[option.loading] +% + \Xy-pic is provided with a growing number of options supporting + specialised drawing tasks as well as exotic output devices with + special graphic features. These should all be loaded using this + uniform interface in order to ensure that the \Xy-pic environment is + properly set up while reading the option. +% +\begin{defs1} +% + ??c![\xyoption] |{| <option> |}| \cr + ??c![\xyrequire] |{| <option> |}| +% +\end{defs1} +\noindent\unskip +% + ??c![\xyoption] will cause the loading of an \Xy-pic option file + which can have one of several names. These are tried in sequence: + |xy|<option>|.tex|, |xy|<option>|.doc|, |xy|<short>|.tex|, and + |xy|<short>|.doc|, where <short> is <option> truncated to 6 (six) + characters to conform with the TWG-TDS~\cite{TWG-TDS}. + + ??c![\xyrequire] is the same except it is ignored if an option with + the same name is already present (thus does not check the version + etc.). + +\DOCMODE( +\message{options;} + +\xylet@\xyoption@@=\relax + +\xydef@\xyoption#1{\DN@{#1}\edef\next@{\codeof\next@}% + \csname xyeveryrequest@\next@ @\endcsname + \xyinputorelse@{xy#1}{\xyoption@truncated#1@@@@@@@@@,#1@}% + \def\xyoption@@{#1}\edef\xyoption@@{\codeof\xyoption@@} + \expandafter\let\expandafter\next@\csname xy\xyoption@@ version\endcsname + \expandafter\let\csname xy\xyoption@@ loaded\endcsname=\next@ + \runxywith@ \ignorespaces} + +\xydef@\xyoption@truncated#1#2#3#4#5#6#7@#8,#9@{% + \DN@{#7}\ifx\next@\empty \DN@##1##2{##2}\else\let\next@=\xyinputorelse@ \fi + \next@{xy#1#2#3#4#5#6}% + {\DN@{#1#2#3#4#5#6}\edef\next@{\codeof\next@}% + \xyerror@{No `\next@' option}{% +Your \xyoption{#9} request could not be granted: the required^^J% +file `xy#9.tex' could not be located. Please make sure that it is^^J% +properly installed before continuing.}}} + +\xydef@\xyrequire#1{\DN@{#1}\edef\next@{\codeof\next@}% + \csname xyeveryrequest@\next@ @\endcsname + \expandafter\let\expandafter\next@\csname xy\codeof\next@ loaded\endcsname + \ifx \next@\relax \DN@{\xyoption{#1}}\else \DN@{\ignorespaces}\fi \next@} +\DOCMODE) + + Sometimes some declarations of an option or header file or whatever + only makes sense after some particular other option is loaded. In + that case the code should be wrapped in the special command +% +\begin{defs1} + ??c![\xywithoption] |{| <option> |}| |{| <code> |}| \cr +\end{defs1} +\noindent\unskip +% + which indicates that if the <option> is already loaded then <code> + should be executed now, otherwise it should be saved and if <option> + ever gets loaded then <code> should be executed afterwards. \NOTE: + The <code> should allow more than one execution; it is saved with the + catcodes at the time of the ??c![\xywithoption] command. + +\DOCMODE( +\xylet@\xywith@@=\empty + +\xydef@\runxywith@{\let\xywithdo@@=\xywithtest@ \xywith@@} + +\xydef@\xywithoption#1#2{\DN@{#1}\edef\next@{\codeof\next@}% + \expandafter\let\expandafter\nextii@\csname xy\next@ loaded\endcsname + \ifx \nextii@\relax + \expandafter\def\expandafter\xywith@@\expandafter{\xywith@@ + \xywithdo@@{#1}{#2}}% + \else \expandafter\xywithrun@\expandafter{\next@}{#2}\fi} + +\xydef@\xywithtest@#1#2{\DN@{#1}\edef\next@{\codeof\next@}% + \ifx\next@\xyoption@@ \expandafter\xywithrun@\expandafter{\next@}{#2}\fi} + +\xydef@\xywithrun@#1#2{\csname xyeverywithoption@#1@\endcsname #2} +\DOCMODE) + + Finally, it is possible to declare <code> as some commands to be + executed before every actual execution of + ??c![\xywithoption]\-|{|<option>|}|\-|{|\dots|}|, and similarly + <code> to be executed before every |\xyoption{|<option>|}| and + |\xyrequire{|<option>|}| (collectively called `requests'):: +% +\begin{defs1} + ??c![\xyeverywithoption] |{| <option> |}| |{| <code> |}| \cr + ??c![\xyeveryrequest] |{| <option> |}| |{| <code> |}| \cr +\end{defs1} +\noindent\unskip +% + This is most often used by an option to activate some hook every time + it is requested itself. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + These last two use the usual expansion trickery to define or append + to the control sequences named |\xyevery|\-|request@|\-<option>|@| + and |\xyevery|\-|withoption@|\-<option>|@| used in the definitions + above. + +\DOCMODE( +\xydef@\xyevery@#1#2#3{\DN@{#2}\edef\next@{\codeof\next@}% + \expandafter\ifx\csname xyevery#1@\next@ @\endcsname\relax + \expandafter\let\csname xyevery#1@\next@ @\endcsname=\empty \fi + \DNii@##1{\expandafter\def\expandafter##1\expandafter{##1#3}}% + \expandafter\nextii@\csname xyevery#1@\next@ @\endcsname} + +\xydef@\xyeveryrequest{\xyevery@{request}} +\xydef@\xyeverywithoption{\xyevery@{withoption}} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Option file format} +??=[option.fileformat] +% + Option files must have the following structure: + +\begin{quote} + |%%| <identification> \\ + |%%| <copyright, \etc> + + |\ifx\xyloaded\undefined \input xy \fi| + + |\xyprovide{|<option>|}{|<name>|}{|<version>|}%| \\ + \null\qquad\qquad |{|<author>|}{|<email>|}{|<address>|}| + + ??w![<body of the option>] + + ??c![\xyendinput] +\end{quote} +% + The 6 arguments to ??c![\xyprovide] should contain the following: +% +\begin{description} + +\item[<option>] + Option load name as used in the ??c![\xyoption] command. This should + be safe and distinguishable for any operating system and is thus + limited to characters chosen among the lowercase letters (|a|--|z|), + digits (|0|--|9|), and dash (|-|), and all options should be uniquely + identifiable by the first 6 (six) characters only. + +\item[<name>] + Descriptive name for the option. + +\item[<version>] + Identification of the version of the option. + +\item[<author>] + The name(s) of the author(s). + +\item[<email>] + The electronic mail address(es) of the author(s) "or" the affiliation + if no email is available. + +\item[<address>] + The postal address(es) of the author(s). + +\end{description} +% + This information is used not only to print a nice banner but also to + (1)~silently skip loading if the same version was preloaded and + (2)~print an error message if a different version was preloaded. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The ??c![\xyprovide] command checks that the option is not already + loaded and that the loaded version is the same as the preloaded one + by checking the existence and contents of the macro + |\xy|<option>|loaded|. Finally it calls ??c![\xycatcodes] such that + the option internals are loaded in `\TeX\ programming mode'. + ??c![\xyendinput] undoes this. + +\DOCMODE( +\xydef@\xyprovide#1#2#3#4#5#6{% + \def\xyoption@@{#1}\edef\xyoption@@{\codeof\xyoption@@}\edef\next@{#3}% + \message{ Xy-pic option: #2 v.\next@}% + \expandafter\let\expandafter\nextii@\csname xy\xyoption@@ loaded\endcsname + \ifx \next@\nextii@ \message{not reloaded}\endinput + \else + \ifx \nextii@\relax\else \xyerror@{Option `\xyoption@@' version mismatch}{% +You previously loaded, or the format has preloaded, a different version^^J% +of this option. Just continue to try to load this version instead (and^^J% +be prepared for a lot of warnings about redefinitions).}% + \fi + \expandafter\let\csname xy\xyoption@@ version\endcsname=\next@ + \expandafter\let\expandafter\xyenddocmode@\csname DOCMODE\endcsname + \expandafter\let\csname DOCMODE\endcsname\xyprovidedocmode@ + \xycatcodes + \fi \ignorespaces} + +\xydef@\xyendinput{\expandafter\let\csname DOCMODE\endcsname=\xyenddocmode@ + \message{loaded}\xyuncatcodes\endinput} +\DOCMODE) + + The above is futher complicated because an option may loaded in its + |DOCMODE| form (ending in |.doc|). So we make sure that the mode + that skips documentation, defined in the |xy.tex| file header, is + active now. + +\DOCMODE( +\expandafter\xylet@\expandafter\xyprovidedocmode@\csname DOCMODE\endcsname +\xylet@\xyenddocmode@=\relax +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + The `dummy' option described in~\S??g[:dummy] is a minimal option + using the above features. It uses the special |DOCMODE| format to + include its own documentation for this document (like all official + \Xy-pic options) but this is not a requirement. + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Driver options} +??=[option.drivers] +% + The ??w![<driver>] options described in \GROUP~??g[:drivers] require + special attention because each driver can support several + ??w![extension] options, and it is sometimes desirable to change + <driver> or even mix the support provided by several.\footnote{The + kernel support described here is based on the (now defunct) + |xydriver| include file by Ross Moore.} + + A <driver> option is loaded as other options with + |\xyoption{|<driver>|}| (or through \LaTeXe\ class or package options + as described in~\S??[env.loading]). The special thing about a + <driver> is that loading it simply declares the name of it, + establishes what extensions it will support, and selects it + temporarily. Thus the special capabilities of the driver will only + be exploited in the produced DVI file if some of these extensions are + also loaded and if the driver is still selected when output is + produced. Generally, the order in which the options are loaded is + immaterial. (Known exceptions affect only internal processing and + are not visible to the user in terms of language and expected output.) + In particular one driver can be preloaded in a format and a different + one used for a particular document. + + The following declarations control this: +% +\begin{defs} +??c![\UseSingleDriver] & forces one driver only \cr +??c![\MultipleDrivers] & allows multiple drivers \cr +??c![\xyReloadDrivers] & resets driver information \cr +\end{defs} +\noindent\unskip +% + The first command restores the default behaviour: that ony one + <driver> is allowed, \ie, each loading of a <driver> option cancels + the previous. The second allows consecutive loading of drivers such + that when loading a <driver> only the extensions actually supported + are selected, leaving other extensions supported by previously + selected drivers untouched. Beware that this can be used to create + DVI files that cannot be processed by any actual DVI driver program! + + The last command is sometimes required to reset the \Xy-pic <driver> + information to a sane state, for example, after having applied one of + the other two in the middle of a document, or when using simple + formats like plain \TeX\ that do not have a clearly distinguished + preamble. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Driver database.} + + The main structure, the list of `loaded' and `selected' <driver>s + (ordered by age), is implemented as traditional \TeX\ `|\do|-lists' + (applications of |\do{|<driver>|}| to each element). + +\DOCMODE( +\xydef@\xydriversloaded@@{\do{unload}} +\xylet@\xydriversselected@@=\empty +\DOCMODE) +% + This is used to provide entry points into a secondary structure that + lists for each <driver> the extensions supported by that driver. As + should be apparent from the above, only the |unload| <driver> is + present initially: it represents the implementation technique used + for the extension when no <driver> is selected. Every extension must + add an entry which reestablishes the default implementation of the + extension: + +\DOCMODE( +\xylet@\xydriver@unload@support@@=\empty +\DOCMODE) +% + All <driver>s will have a similar structure named + |\xydriver@|\-<driver>\-|@support@@| which contains the extensions + supported by that particular <driver>: the `signature' of each driver + as |\doii|-list with two arguments (hence the |ii|~\smiley~): the + extension and the command to install the <driver>-extension + combination. + + The two selection principles differ significantly. When only a + single <driver> is selectable then all extensions need to be unloaded + "before" the selection. When multiple <driver>s are allowed then + only the added support needs to be executed. + +\DOCMODE( +\xydef@\selectdriver@#1{\DN@{#1}\edef\next@{\codeof\next@}% + \expandafter\selectdriver@@\expandafter{\next@}} + +\xydef@\selectdriver@single#1{\xysetup@@{\def\xydriversselected@@{\do{#1}}% + \xyLoadDrivers@}\let\selectdriver@@=\changedriver@single} + +\xydef@\changedriver@single#1{\xysetup@@{\def\xydriversselected@@{\do{#1}}% + \xyReloadDrivers@}} + +\xydef@\selectdriver@multiple#1{\expandafter\xysetup@@\expandafter{% + \expandafter\def\expandafter\xydriversselected@@\expandafter{% + \xydriversselected@@ \do{#1}}% + \let\do=\activatedriver@ \xydriversselected@@}} + +\xydef@\UseSingleDriver{\let\selectdriver@@=\selectdriver@single} +\xydef@\MultipleDrivers{\let\selectdriver@@=\selectdriver@multiple} + +\xydef@\xyLoadDrivers@{\let\do=\activatedriver@ \xydriversselected@@} +\xydef@\xyReloadDrivers@{\activatedriver@{unload}\xyLoadDrivers@} +\xylet@\xyReloadDrivers=\xyReloadDrivers@ + +\xydef@\activatedriver@#1{% + \let\doii=\activatedriversupport@ \csname xydriver@#1@support@@\endcsname} + +\xydef@\activatedriversupport@#1#2{% + \expandafter\ifx\csname xy#1loaded\endcsname\relax\DN@{}% + \else\DN@{#2}\fi \next@} + +\UseSingleDriver +\DOCMODE) + + Finally we define the following to get complete independence of load + sequence: at every loading of an extension option known to be + supported, we run through the list of presently selected drivers to + activate any support for it, using the following: + +\DOCMODE( +\xydef@\xyselectoptionsupport@{\let\do=\activatedriver@ \xydriversselected@@} +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + As the above suggests it sometimes makes sense to load <driver>s in + the actual textual part of a document, however, it is recommended + that only drivers "also" loaded in the preamble are reloaded later, + and that ??c![\xyReloadDrivers] is used when there is doubt about the + state of affairs. In case of confusion the special command + ??c![\xyShowDrivers] will list all the presently supported and + selected driver-extension pairs to the \TeX\ log. + +\DOCMODE( +\xydef@\xyShowDrivers{{\W@{Loaded:}\let\do=\doShow \xydriversloaded@@ + \let\next@=\empty + \def\do##1{\ifx\next@\empty \DN@{##1}% + \else \expandafter\DN@\expandafter{\next@, ##1}\fi}% + \xydriversselected@@\W@{Selected: \next@.}}} + +\def\doShow#1{\let\next@=\empty + \def\doii##1##2{\ifx\next@\empty \DN@{##1}% + \else \expandafter\DN@\expandafter{\next@, ##1}\fi}% + \csname xydriver@#1@support@@\endcsname + \W@{ <driver> #1 supports \next@.}} +\DOCMODE) + +\DOCMODE1%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + It is not difficult to add support for additional <driver>s; how is + described in the \TeX\-nical documentation. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\paragraph*{Driver internals.} + + A <driver> option files must have the following structure: + +\begin{quote} + |%%| <identification> \\ + |%%| <copyright, \etc> + + |\ifx\xyloaded\undefined \input xy \fi| + + |\xyprovide{|<option>|}{|<name>|}{|<version>|}%| \\ + \null\qquad\qquad |{|<author>|}{|<email>|}{|<address>|}| + + |\newdriver{%|\\ + |\xyaddsupport{|<extension>|}|<cs>\\ + \vdots\\ + |}| + + <body of the {<driver>} option> + + ??c![\xyendinput] +\end{quote} +% + There should be an ??c![\xyaddsupport] command for each supported + <extension> which specicifies the <cs> (control sequence) with which + the indicated support is "activated". + + The ??c![\newdriver] command first establishes the `support' list for + the <driver> (running the argument), then adds the <driver> to the + `loaded' list, and finally selects it now and for every subsequent + request of this <driver> option. + + It is important that the <cs> that "activates" each driver/extension + combination only does "rebinding of hooks". In order to see what + hooks are available for an extension, look for declarations of the + form +% +\begin{defs1} + ??c![\xyaddunsupport] |{|<extension>|}| <cs> +\end{defs1} +\noindent\unskip +% + and see what rebindings that <cs> does: those are the + hokks. "because" they are the ones that will be safely reestablished! + This should be adherede to because both activation and deactivation + <cs>s may be executed many times. + + The procedure is as follows: (??_[newdr1])~add the driver and clear + its support control sequence unless it is already defined, + (??_[newdr2])~execute the support commands, and (??_[newdr3])~setup + to select it after loading. + +\DOCMODE( +\xydef@\newdriver#1{% + \def\nextiii@##1{%?*[newdr1] + \expandafter\def\expandafter\xydriversloaded@@ + \expandafter{\xydriversloaded@@\do{##1}}% + \expandafter\let\csname xydriver@\xyoption@@ @support@@\endcsname=\empty}% + \def\do##1{\DNii@{##1}\ifx\xyoption@@\nextii@ \let\nextiii@=\eat@ \fi}% + \xydriversloaded@@ \expandafter\nextiii@\expandafter{\xyoption@@}% + #1\relax %?*[newdr2] + \DN@##1{\xywithoption{##1}{%?*[newdr3] + \selectdriver@{##1}\xyeveryrequest{##1}{\selectdriver@{##1}}}}% + \expandafter\next@\expandafter{\xyoption@@}\ignorespaces} +\DOCMODE) + + The support commands merely add to the support |\do|-lists which in + turn (??_[adddr1])~adds |\doii{|<extension>|}{|\dots|}| to the + |\xydriver@|<driver>|@support@@| control sequence and adds a check + for when to apply it every time that <extension> is requested! + + +\DOCMODE( +\xydef@\xyaddsupport{\expandafter\xyadddriversupport@\expandafter{\xyoption@@}} +\xydef@\xyaddunsupport{\xyadddriversupport@{unload}} + +\xydef@\xyadddriversupport@#1#2#3{% + \DNii@{#1}\edef\nextii@{\codeof\nextii@}% + \def\nextiii@{#2}\edef\nextiii@{\codeof\nextiii@}% +% +% CHECK that the <driver> is loaded! +\def\next{\xybug@{<driver> \nextii@\space not loaded}}% +\def\do##1{\DN@{##1}\edef\next@{\codeof\next@}% + \ifx\next@\nextii@ \let\next=\relax \fi}\xydriversloaded@@ \next +% +% CHECK that the specified <extension> is not already supported! +\def\next{\xybug@{<driver> \nextii@\space already supports \nextiii@}}% +\def\doii##1##2{\DN@{##1}\edef\next@{\codeof\next@}% + \ifx\next@\nextiii@ \let\next=\relax \fi}\xydriversloaded@@ \next +% + \DN@##1##2{\ifx##1\relax \let##1=\empty \fi %?*[adddr1] + \expandafter\def\expandafter##1\expandafter{##1\doii{##2}{#3}}}% + \expandafter\expandafter\expandafter\next@ + \expandafter\expandafter\csname xydriver@\nextii@ @support@@\endcsname + \expandafter{\nextiii@}% + \DN@##1{\expandafter\xyeverywithoption\expandafter{\nextiii@}{% + \xytestforsupport@{##1}}}% + \expandafter\next@\expandafter{\nextii@}\xydriversloaded@@ + \ignorespaces} + +\xydef@\xytestforsupport@#1{\def\do##1{\DN@{##1}\DNii@{#1}% + \ifx\next@\nextii@ \expandafter\xyselectoptionsupport@ \fi}} +\DOCMODE) + +\paragraph*{Driver related messages.} + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Most extensions will print a warning when a capability is used which + is not supported by the presently loaded <driver>. Such messages are + only printed once, however, (for some formats they are repeated at + the end). Similarly, when the support of an extension that exploits + a particular <driver> is used a warning message will be issued that + the DVI file is not portable. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + This is implemented by defining a control sequence for each such + warning and repeat it at the end. Warnings should be issued using + one of +% +\begin{defs1} +|\xyununsupportwarning@| |{|<extension>|}| |{|<message>|}|\cr +|\xyunsupportwarning@| |{|<driver>|}| |{|<extension>|}| \cr +\end{defs1} + +\DOCMODE( +\xynew@{if}\ifunsupportwarnings@ + +\xydef@\xyunsupportwarning@#1#2{{% + \DN@{#1}\edef\next@{\codeof\next@} + \expandafter\ifx\csname xywarn@unload@\next@ @\endcsname\relax + \expandafter\gdef\csname xywarn@unload@\next@ @\endcsname{}% + \ifunsupportwarnings@ \xyclosedown@@\xyunsupportwarnings@@ \fi + \global\unsupportwarnings@true + \expandafter\gdef\expandafter\xyunsupportwarnings@@\expandafter{% + \xyunsupportwarnings@@ \W@{ #2.}}% + \W@{}% + \W@{Xy-pic Warning: `\next@' reproduction is NOT EXACT\xytracelineno@:}% + \W@{ #2.}% + \W@{}% + \fi}} + +\xydef@\xyunsupportwarnings@@{\W@{}% + \W@{Xy-pic Warning: The produced DVI file is NOT EXACT:}} + +\xynew@{if}\ifsupportwarnings@ + +\xydef@\xysupportwarning@#1#2{{% + \DN@{#1}\edef\next@{\codeof\next@}\DNii@{#2}\edef\nextii@{\codeof\nextii@}% + \expandafter\ifx\csname xywarn@\next@ @\nextii@ @\endcsname\relax + \expandafter\gdef\csname xywarn@\next@ @\nextii@ @\endcsname{}% + \ifsupportwarnings@ \xyclosedown@@\xysupportwarnings@@ \fi + \global\supportwarnings@true + \expandafter\gdef\expandafter\xysupportwarnings@@\expandafter{% + \xysupportwarnings@@ \driverextensioncomplain@{#1}{#2}}% + \W@{}% + \W@{Xy-pic Warning: The produced DVI file is NOT PORTABLE\xytracelineno@:}% + \driverextensioncomplain@{#1}{#2}% + \W@{}% + \fi}} + +\xydef@\xysupportwarnings@@{% + \W@{Xy-pic Warning: The produced DVI file is NOT PORTABLE:}} + +\xydef@\driverextensioncomplain@#1#2{% + \DN@{#1}\edef\next@{\codeof\next@}\DNii@{#2}\edef\nextii@{\codeof\nextii@}% + \W@{ It contains <driver> `\next@' \string\special s for the `\nextii@' + extension.}} +\DOCMODE) + + Backwards compatibility\dots + +\DOCMODE( +\xydef@\dvimessage@#1#2{\xysupportwarning@{#1}{#2}} + +\xynew@{if}\ifxydrivernoloads@ +\xydef@\xydrivernoload@#1{\xyerror@{Could not load xy#1.tex}{}% + \xydrivernoloads@true} + +\xydef@\xydriverfail@#1{\xyerror@{Sorry, #1 not supported.}{}} + +\xydef@\xyunload@#1{\xywarning@{Unloading #1.}} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section{Algorithms} +??=[algo] + + This section presents the more complicated algorithms used in + \Xy-pic. + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Directions} +??=[algo.direction] + +\DOCMODE( +\message{algorithms: directions,} +\DOCMODE) + + The "direction state" is described by the following parameters: +% +\begin{defs} +"Direction" & `angle' of the direction on $]-4K\dots4K]$ unit square \cr +"dX","dY" & the vector $c-p$ \cr +"sdX","sdY" & sign of "dX" and "dY" \cr +|\K@dXdY|,|\K@dYdX| & quotients $K\frac{"dX"}{"dY"}$ and + $K\frac{"dY"}{"dX"}$ (as dimensions in sp) \cr +"DirectionChar","SemiDirectionChar" & |\chardefs| for directional + and semidirectional fonts \cr +"cosDirection","sinDirection" & factors in the range $]-1\dots1]$ + corresponding to cos and sin of Direction \cr +\end{defs} +% + where the ``$]-4K\dots4K]$ unit square'' has the following angles: +$$ +\xy *[]=<3pc>{}="c"*\frm{-}, + "c"; (-1,-1)**{},p+/4pc/ *+{0} **@{-}?>*@{>}, + "c"; ( 0,-1)**{},p+/4pc/ *+{K} **@{-}?>*@{>}, + "c"; ( 1,-1)**{},p+/4pc/ *+{2K} **@{-}?>*@{>}, + "c"; ( 1, 0)**{},p+/4pc/ *+{3K} **@{-}?>*@{>}, + "c"; ( 1, 1)**{},p+/4pc/ *+{4K} **@{-}?>*@{>}, + "c"; ( 0, 1)**{},p+/4pc/ *+{{-}3K} **@{-}?>*@{>}, + "c"; (-1, 1)**{},p+/4pc/ *+{{-}2K} **@{-}?>*@{>}, + "c"; (-1, 0)**{},p+/4pc/ *+{{-}K} **@{-}?>*@{>}, +\endxy +$$ + where the intermediate $K$ angle in each interval correspond to + equidistant points on the unit square. Thus only for + $n\in\{-3,2,1,0,1,2,3,4\}$ the angle of direction $n*K$ is exactly + $n*45^\circ - 135^\circ$ ($0^\circ$ being the direction straight + right). + + As usual |\DirectionfromtheDirection@| expands to code setting the + current direction. + +\DOCMODE( +\xydef@\DirectionfromtheDirection@{\noexpand\Direction=\the\Direction + \noexpand\d@X=\the\d@X \noexpand\d@Y=\the\d@Y + \def\noexpand\sd@X{\sd@X}\def\noexpand\sd@Y{\sd@Y}% + \noexpand\K@dXdY=\the\K@dXdY \noexpand\K@dYdX=\the\K@dYdX + \chardef\noexpand\DirectionChar=\the\DirectionChar + \chardef\noexpand\SemiDirectionChar=\the\SemiDirectionChar + \def\noexpand\cosDirection{\cosDirection}% + \def\noexpand\sinDirection{\sinDirection}% + \noexpand\resetupDirection@} +\DOCMODE) + + The actual direction computation is done using + |\setupDirection@|. + +\paragraph*{Procedure:} +% + Is really not so complicated. [??_[Dir1]]~"dX" and "dY" are computed + from $c-p$ and we skip if the current setting is based on these (this + is stored in the internal |\Directiontest@@| method); + [??_[Diri1]]~if the direction is one of the principal ones then + proceed with an optimised special case for those; otherwise proceed + with the generic code. + +\DOCMODE( +\xydef@\Directiontest@@#1#2{#2} + +\xydef@\setupDirection@{% + \d@X=\X@c\advance\d@X-\X@p \d@Y=\Y@c\advance\d@Y-\Y@p %?*[Dir1] + \Directiontest@@\relax\setupDirection@i} + +\xydef@\setupDirection@i{\DN@{\setupDirection@ii}%?*[Diri1] + \ifdim\d@X=\d@Y + \ifdim\zz@\d@Y \DN@{}% + \else\ifdim\d@X<\z@ \DN@{\dlDirection@{-1.4142\d@X}}% + \else \DN@{\urDirection@{1.4142\d@X}}\fi\fi + \else\ifdim\d@X<\d@Y + \ifdim\zz@\d@X \DN@{\uDirection@\d@Y}% + \else\ifdim\zz@\d@Y \DN@{\lDirection@{-\d@X}}% + \else\ifdim-\d@X=\d@Y \DN@{\ulDirection@{-1.4142\d@X}}\fi\fi\fi + \else + \ifdim\zz@\d@X \DN@{\dDirection@{-\d@Y}}% + \else\ifdim\zz@\d@Y \DN@{\rDirection@\d@X}% + \else\ifdim\d@X=-\d@Y \DN@{\drDirection@{1.4142\d@X}}\fi\fi\fi + \fi\fi \next@} +\DOCMODE) + + The procedures for the special <diag>onal cases are summarised in + this table: +$$ +\let\|=\otherbar +\begin{array}{\|c\|r\|rl\|c\|rl\|} +\hline +\mbox{<diag>onal} & "Direction" & \cos("Direction"),& \sin("Direction") + & "sign"("dX","dY") & "Char" & "Semi" \\ +\hline + |dl| & 0 & {-\sqrt{\frac12}},& {-\sqrt{\frac12}} & -,- & 127 & 127 \\ + |d| & K & 0,& -1 & +,- & 15 & 31 \\ + |dr| & 2K & {\sqrt{\frac12}},& {-\sqrt{\frac12}} & +,- & 31 & 63 \\ + |r| & 3K & 1,& 0 & +,+ & 47 & 95 \\ + |ur| & 4K & {\sqrt{\frac12}},& {\sqrt{\frac12}} & +,+ & 63 & 127 \\ + |u| &-3K & 0,& 1 & +,+ & 79 & 31 \\ + |ul| &-2K & {-\sqrt{\frac12}},& {\sqrt{\frac12}} & -,+ & 95 & 63 \\ + |l| & -K & -1,& 0 & -,+ & 111 & 95 \\ +\hline +\end{array} +$$ + In each case the argument is used as the unit circle, \ie, non-zero + of "dX" and "dY", and $|<|K\frac{"dX"}{"dY"}|,|K\frac{"dY"}{"dX"}|>| + := "KK"*|<|"dX"|,|"dY"|>|$\dots + +\DOCMODE( +\xydef@\dlDirection@{\Direction=\z@ + \def\cosDirection{-.7071}\def\sinDirection{-.7071}\def\sd@X{-}\def\sd@Y{-}% + \chardef\DirectionChar=127\relax\chardef\SemiDirectionChar=127\relax + \K@dXdY=1\K@ \K@dYdX=1\K@ \fixedDirection@} + +\xydef@\dDirection@{\Direction=\K@ + \def\cosDirection{0}\def\sinDirection{-1}\def\sd@Y{-}%\def\sd@X{+} + \edef\sd@X{\ifdim\X@c<\X@p-\else+\fi}% + \chardef\DirectionChar=15\relax\chardef\SemiDirectionChar=31\relax + \K@dXdY=\z@ \K@dYdX=\KK@\K@ \fixedDirection@} + +\xydef@\drDirection@{\dimen@ii=2\K@ \Direction=\dimen@ii + \def\cosDirection{+.7071}\def\sinDirection{-.7071}\def\sd@X{+}\def\sd@Y{-}% + \chardef\DirectionChar=31\relax\chardef\SemiDirectionChar=63\relax + \K@dXdY=-1\K@ \K@dYdX=-1\K@ \fixedDirection@} + +\xydef@\rDirection@{\dimen@ii=3\K@ \Direction=\dimen@ii + \def\cosDirection{+1}\def\sinDirection{0}\def\sd@X{+}%\def\sd@Y{+}% + \edef\sd@Y{\ifdim\Y@c<\Y@p-\else+\fi}% + \chardef\DirectionChar=47\relax\chardef\SemiDirectionChar=95\relax + \K@dXdY=\KK@\K@ \K@dYdX=\z@ \fixedDirection@} + +\xydef@\urDirection@{\dimen@ii=4\K@ \Direction=\dimen@ii + \def\cosDirection{+.7071}\def\sinDirection{+.7071}\def\sd@X{+}\def\sd@Y{+}% + \chardef\DirectionChar=63\relax\chardef\SemiDirectionChar=127\relax + \K@dXdY=1\K@ \K@dYdX=1\K@ \fixedDirection@} + +\xydef@\uDirection@{\dimen@ii=-3\K@ \Direction=\dimen@ii + \def\cosDirection{0}\def\sinDirection{+1}\def\sd@Y{+}%\def\sd@X{+} + \edef\sd@X{\ifdim\X@c<\X@p-\else+\fi}% + \chardef\DirectionChar=79\relax\chardef\SemiDirectionChar=31\relax + \K@dXdY=\z@ \K@dYdX=\KK@\K@ \fixedDirection@} + +\xydef@\ulDirection@{\dimen@ii=-2\K@ \Direction=\dimen@ii + \def\cosDirection{-.7071}\def\sinDirection{+.7071}\def\sd@X{-}\def\sd@Y{+}% + \chardef\DirectionChar=95\relax\chardef\SemiDirectionChar=63\relax + \K@dXdY=-1\K@ \K@dYdX=-1\K@ \fixedDirection@} + +\xydef@\lDirection@{\Direction=-\K@ + \def\cosDirection{-1}\def\sinDirection{0}\def\sd@X{-}%\def\sd@Y{+}% + \edef\sd@Y{\ifdim\Y@c<\Y@p-\else+\fi}% + \chardef\DirectionChar=111\relax\chardef\SemiDirectionChar=95\relax + \K@dXdY=\KK@\K@ \K@dYdX=\z@ \fixedDirection@} + +\xydef@\fixedDirection@#1{\dimen@ii=#1\relax + \d@X=\cosDirection\dimen@ii \d@Y=\sinDirection\dimen@ii + \resetupDirection@} +\DOCMODE) + + Here is the procedure for the generic code. +% +\begin{itemize} + +\item[{??_[Dirii1]}] + Make sign variables and slopes: $"sdX" := "sign"("dX")$, $"sdY" := + "sign"("dY")$, $K\frac{"dX"}{"dY"} := + "sdX"*"sdY"*\floor{\abs{"KK"*"dX"} / \abs{"dY"/"KK"}}$, and + $K\frac{"dY"}{"dX"} := "sdX"*"sdY"*\floor{\abs{"KK"*"dY"} / + \abs{"dX"/"KK"}}$, where the somewhat exotic computation method is + used to ensure that the `native' floor function provided by \TeX\ + |\divide| can be used (it only acts predictably for positive + numbers), that overflow is avoided even for large $"dX","dY"$, and + that it is reasonable to use the convention of |\quotient@| that + division by zero is like multiplying with one\dots Also takes care + not to multiply too big dimensions with each other. + +\item[{??_[Dirii2]}] + If ${-K} \le K\frac{"dX"}{"dY"} \le K$ then the direction is mostly + up or down: if $"dY"\lt0$ [down, ??_[Dirii2a]]: $"Direction" := - + K\frac{"dX"}{"dY"} + 1K$; else [up, ??_[Dirii2b]]: $"Direction" := - + K\frac{"dX"}{"dY"} - 3K$. + +\item[{??_[Dirii3]}] + If ${-K} \lt K\frac{"dY"}{"dX"} \lt K$ then direction is mostly left + or right: if $"dX"\lt0$ [left, ??_[Dirii3a]]: $"Direction" := + K\frac{"dY"}{"dX"} - K$; else [right, ??_[Dirii3b]]: $"Direction" := + K\frac{"dY"}{"dX"} + 3K$. + +\item[{??_[Dirii4]}] + Compute character codes for direction and semidirection fonts. + [??_[Dirii4a]]: $"DirectionChar" := (8K+"Direction"+K/32) + \hbox{~div~} (K/16) - 1$; while $"DirectionChar" \gt 127: + "DirectionChar" -:= 128$. [??_[Dirii4b]]: $"SemiDirectionChar" := + (8K+"Direction"+K/64) \hbox{~div~} (K/32) - 1$; while + $"SemiDirectionChar" \gt 127: "SemiDirectionChar" -:= 128$. In both + cases the $8K$ are added to ensure that \TeX\ will round down. + \HACK: The |16|, |\KK@|, and |64| in these lines are really $K/64$, + $K/32$, and $K/16$\dots + +\item[{??_[Dirii5]}] + Build "cosDirection" and "sinDirection" from appropriate characters + in the |\xydashfont|. [??_[Dirii5]]: $"cosDirection" := + "wd"(|\xydashfont| "SemiDirectionChar")$. [??_[Dirii5b]] $C := + "SemiDirectionChar"-64$, if $C\lt0$: $C := C+128$, $"sinDirection" := + "wd"(|\xydashfont| C)$. + +\item[{??_[Dirii6]}] + Register this "dX","dY" for next time. + +\end{itemize} + +\DOCMODE( +\xydef@\setupDirection@ii{% + \ifdim\d@X<\z@ \def\sd@X{-}\else \def\sd@X{+}\fi %?*[Dirii1] + \ifdim\d@Y<\z@ \def\sd@Y{-}\else \def\sd@Y{+}\fi + \K@dXdY=\sd@X\d@X \ifdim\K@dXdY<500pt \multiply\K@dXdY\KK@ \fi + \dimen@=\sd@Y\d@Y +% \advance\dimen@.5\KK@ \divide\dimen@\KK@ + \advance\dimen@\ifdim\dimen@<\z@-\fi.5\KK@ \divide\dimen@\KK@ + \ifdim\dimen@=\z@\else %\count@=\dimen@ \divide\count@\tw@ + \advance\K@dXdY by.5\dimen@\relax \divide\K@dXdY\dimen@ + \fi \K@dXdY=\sd@X\sd@Y\K@dXdY + \K@dYdX=\sd@Y\d@Y \ifdim\K@dYdX<500pt \multiply\K@dYdX\KK@ \fi + \dimen@=\sd@X\d@X +% \advance\dimen@.5\KK@ \divide\dimen@\KK@ + \advance\dimen@\ifdim\dimen@<\z@-\fi.5\KK@ \divide\dimen@\KK@ + \ifdim\dimen@=\z@\else %\count@=\dimen@ \divide\count@\tw@ + \advance\K@dYdX by.5\dimen@\relax \divide\K@dYdX\dimen@ + \fi \K@dYdX=\sd@X\sd@Y\K@dYdX + \Direction=\maxdimen + \ifnum\K@dXdY<-\K@ \else \ifnum\K@<\K@dXdY \else %?*[Dirii2] + \ifdim \d@Y<\z@ %?*[Dirii2a] + \Direction=\K@ \advance\Direction-\K@dXdY + \else %?*[Dirii2b] + \Direction=\K@ \multiply\Direction-\thr@@ \advance\Direction-\K@dXdY + \fi\fi\fi + \ifnum-\K@<\K@dYdX \ifnum\K@dYdX<\K@ %?*[Dirii3] + \ifdim \d@X<\z@ %?*[Dirii3a] + \Direction=-\K@ \advance\Direction\K@dYdX + \else %?*[Dirii3b] + \Direction=\K@ \multiply\Direction\thr@@ \advance\Direction\K@dYdX + \fi\fi\fi + \ifnum\Direction=\maxdimen + \Direction=\K@dYdX \advance\Direction-\K@dXdY + \advance\Direction\ifnum\Direction<\z@-\fi\@ne \divide\Direction\tw@ + \ifnum\K@dXdY<\z@ \advance\Direction\K@ \advance\Direction\K@ + \else \advance\Direction-\K@ \advance\Direction-\K@ \fi + \fi + \imposeDirection@i + \resetupDirection@ %?*[Dirii6] + } + +\xydef@\imposeDirection@{\count@@=\Direction + \loop@\ifnum\count@@>4096 \advance\count@@-8192 \repeat@ + \loop@\ifnum\count@@<-4096 \advance\count@@8192 \repeat@ + \def\sd@X{+}\ifnum\count@@<\K@ \relax + \ifnum\count@@>-3072 \def\sd@X{-}\fi\fi + \def\sd@Y{+}\ifnum\count@@<3072 \relax + \ifnum\count@@>-\K@ \relax\def\sd@Y{-}\fi\fi + \imposeDirection@i + \d@X=\cosDirection\xydashl@ \d@Y=\sinDirection\xydashl@ + \resetupDirection@} + +\xydef@\imposeDirection@i{% + \count@@=\K@ \multiply\count@@ by8 \advance\count@@\Direction %?*[Dirii4] + \count@=\count@@ \advance\count@\KK@ \divide\count@64 \advance\count@\m@ne %?*[Dirii4a] + \loop@\ifnum127<\count@ \advance\count@-128 \repeat@ + \chardef\DirectionChar\count@ + \advance\count@@16 \divide\count@@\KK@ \advance\count@@\m@ne %?*[Dirii4b] + \loop@\ifnum127<\count@@ \advance\count@@-128 \repeat@ + \chardef\SemiDirectionChar\count@@ + \setbox8=\hbox{\xydashfont\SemiDirectionChar\/}% %?*[Dirii5] + \quotient@@\cosDirection{\sd@X\wd8}\xydashl@ + \setbox8=\hbox{\xydashfont\count@=\SemiDirectionChar\advance\count@-64 %?*[Dirii5b] + \ifnum\count@<\z@ \advance\count@128 \fi \char\count@\/}% + \quotient@@\sinDirection{\sd@Y\wd8}\xydashl@} + +\xydef@\getxyDirection@#1{\xy@@\bgroup\xy@@ix@{#1}% + \xy@@{\expandafter\POS\the\toks9\relax\setupDirection@ + \edef\next@{\egroup \Direction=\the\Direction}\next@ \imposeDirection@ }} +\DOCMODE) + + Finally some special cases used by the <direction>s and directional + library objects. All manipulate the Direction dependent parameters + and then call |\resetupDirection@|: |\reverseDirection| reverses it; + |\above|- and |\belowDirection@| are for |^| and |_|, and + $|\vDirection@(|x|,|y|){|L|}|$ is for $|:(|x|,|y|)|$, \ie, computes + a new direction as the vector +$$ + |<| X - x*\cos\alpha*L - y*({-}\sin\alpha)*L |,| + Y - x*\sin\alpha*L - y*\cos\alpha*L |>| +$$ + where $\alpha$ is the previous direction angle. + +\DOCMODE( +\xydef@\reverseDirection@{% + \d@X=-\d@X \d@Y=-\d@Y + \ifdim\d@X<\z@ \def\sd@X{-}\else \def\sd@X{+}\fi + \ifdim\d@Y<\z@ \def\sd@Y{-}\else \def\sd@Y{+}\fi + \dimen@=4\K@ \ifnum\Direction<\z@ \advance\Direction\dimen@ + \else \advance\Direction-\dimen@ \fi + \count@=\DirectionChar \ifnum\count@<64 \advance\count@64 % + \else \advance\count@-64 \fi \chardef\DirectionChar=\count@ + \edef\cosDirection{\if-\cosDirection\else-\cosDirection\fi}% + \edef\sinDirection{\if-\sinDirection\else-\sinDirection\fi}% + \resetupDirection@} + +\xydef@\aboveDirection@#1{% + \dimen@=\d@X \d@X=-\d@Y \d@Y=\dimen@ + \dimen@=\K@dXdY \K@dXdY=-\K@dYdX \K@dYdX=-\dimen@ + \ifdim\d@X<\z@ \def\sd@X{-}\else \def\sd@X{+}\fi + \ifdim\d@Y<\z@ \def\sd@Y{-}\else \def\sd@Y{+}\fi + \dimen@=2\K@ \ifdim 1\Direction<\dimen@\else \dimen@=-6\K@ \fi + \advance\Direction\dimen@ + \count@=\DirectionChar \ifnum\count@<96 \advance\count@32 % + \else \advance\count@-96 \fi \chardef\DirectionChar=\count@ + \count@=\SemiDirectionChar \ifnum\count@<64 \advance\count@64 % + \else \advance\count@-64 \fi \chardef\SemiDirectionChar=\count@ + \let\tmp@=\cosDirection + \edef\cosDirection{\if-\sinDirection\else-\sinDirection\fi}% + \let\sinDirection=\tmp@ + \dimen@=#1\relax \d@X=\cosDirection\dimen@ \d@Y=\sinDirection\dimen@ + \resetupDirection@} + +\xydef@\belowDirection@#1{% + \dimen@=\d@X \d@X=\d@Y \d@Y=-\dimen@ + \dimen@=\K@dXdY \K@dXdY=-\K@dYdX \K@dYdX=-\dimen@ + \ifdim\d@X<\z@ \def\sd@X{-}\else \def\sd@X{+}\fi + \ifdim\d@Y<\z@ \def\sd@Y{-}\else \def\sd@Y{+}\fi + \dimen@=-2\K@\ifdim 1\Direction<\dimen@\dimen@=6\K@\fi + \advance\Direction\dimen@ + \count@=\DirectionChar \ifnum\count@<32 \advance\count@96 % + \else \advance\count@-32 \fi \chardef\DirectionChar=\count@ + \count@=\SemiDirectionChar \ifnum\count@<64 \advance\count@64 % + \else \advance\count@-64 \fi \chardef\SemiDirectionChar=\count@ + \let\tmp@=\sinDirection + \edef\sinDirection{\if-\cosDirection\else-\cosDirection\fi}% + \let\cosDirection=\tmp@ + \dimen@=#1\relax \d@X=\cosDirection\dimen@ \d@Y=\sinDirection\dimen@ + \resetupDirection@} + +\xydef@\vDirection@(#1,#2)#3{\dimen@ii=#3\relax + \dimen@=#1\dimen@ii \dimen@ii=#2\dimen@ii + \d@X=\cosDirection\dimen@ \advance\d@X-\sinDirection\dimen@ii + \d@Y=\sinDirection\dimen@ \advance\d@Y \cosDirection\dimen@ii + \X@p=\X@c \advance\X@p-\d@X \Y@p=\Y@c \advance\Y@p-\d@Y + \setupDirection@\ignorespaces} +\DOCMODE) + + The above all make use of the following; use them also when the + direction state is known to be correct: |\resetDirection@| should be + called when $p$ and/or $c$ are moved along the line $\vec{pc}$, + |\resetupDirerection| when the entire direction state is changed in a + consistent manner. + +\DOCMODE( +\xydef@\resetDirection@{% + \d@X=\X@c\advance\d@X-\X@p \d@Y=\Y@c\advance\d@Y-\Y@p + \let\next@=\resetupDirection@ + \ifdim\sd@X\d@X<\z@ \let\next@=\setupDirection@i \fi + \ifdim\sd@Y\d@Y<\z@ \let\next@=\setupDirection@i \fi + \next@} + +\xydef@\resetupDirection@{% + \edef\Directiontest@@##1##2{\noexpand\DN@{##2}% + \noexpand\ifdim\noexpand\d@X=\the\d@X\relax + \noexpand\ifdim\noexpand\d@Y=\the\d@Y\relax \noexpand\DN@{##1}% + \noexpand\fi\noexpand\fi \noexpand\next@}} + +\xydef@\unsetupDirection@{\def\Directiontest@@##1##2{##2}} +\DOCMODE) + + Finally the initial direction: up! + +\DOCMODE( +\uDirection@\xydashl@ +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Edges} +??=[algo.edge] + + An "Edge" is a token list describing the edge of an object. It must + have the form |{|<expandable token> <unexpandable tokens>|}|. + To find the edge of an object then first make it the current object + and then do +$$ + |\the\Edge@c|<code> +$$ + where <code> determines what should be done: +% +\begin{itemize} + +\item[0] + $c$ is changed to be equal to the point on the edge intersecting with + the line segment from $p$ (for ??c![E] <corner>, also this was the + v2.6 behaviour). + + \NOTE: This should not change any of $A$, $B$, or any component of + the state except $X_c$ and $Y_c$! + +\item[1] + Test whether the center of $p$, \ie, $|<|X_p|,|Y_p|>|$, is `inside' + the $c$ object (or on the edge). Sets the test |\ifInside@| + accordingly. + +\item[2] + Set |\dimen@| to the distance from the center to the edge towards~$p$ + (as set with code~0). + + \NOTE: This is only positive in the direction towards $p$ + (thus negative-sized circles and rectangles make it negative). + +\item[3] + $c$ is changed to be equal to the point on the edge furthest in the + direction towards $p$ (for ??c![P] <corner>). + + \NOTE: This should not change any of $A$, $B$, or any component of + the state except $X_c$ and $Y_c$! + +\item[4] + Replace $c$ with rectangle with corners where the line from $p$ + intersects with the edge of $c$ (thus this is the inner rectangle + with corners as the current direction dictates). + +\item[5] + Replace $c$ with smallest rectangle that encloses the current object + completely. + +\end{itemize} +% + (if this reminds the reader of a `dictionary' as used by + object-oriented programming languages then they probably share this + author's regret that \TeX\ is not object-oriented :-) + +\DOCMODE( +\message{edges,} + +\xynew@{if}\ifInside@ +\DOCMODE) + +\paragraph*{Points:} + + The simplest shape is none at all -- a point. + +\DOCMODE( +\xydef@\zeroEdge#1{% + \ifcase#1\relax \or \Inside@false \or \dimen@=\z@ + \or \else \Edge@c={\rectangleEdge}\fi} +\DOCMODE) + +\paragraph*{Circles and Ellipses:} + + Next we define round things, with several special cases for the + individual variants described below: centered circular, centered + elliptical, and general elliptical. The only `intelligent' choice + is for the `Under' method where the object is forced to be a centered + variant before applying either the circular or elliptical version. + +\DOCMODE( +\xydef@\circleEdge#1{\ifcase#1\expandafter\circleEdge@ + \or \expandafter\circleUnder@ \or \dimen@=\R@c + \or \expandafter\circleProp@ \or \expandafter\circleInner@ + \else \expandafter\circleOuter@ \fi} + +\xydef@\circleEdge@{\DN@{\ellipseEdge@}% + \ifdim\R@c=\L@c\relax \ifdim\U@c=\D@c\relax + \ifdim\R@c=\U@c\DN@{\circlecentredEdge@}% + \else\DN@{\ellipsecentredEdge@}\fi + \fi\fi \next@} + +\xydef@\circleProp@{\DN@{\reverseDirection@\ellipseEdge@}% + \ifdim\R@c=\L@c\relax \ifdim\U@c=\D@c\relax + \ifdim\R@c=\U@c\DN@{\reverseDirection@\circlecentredEdge@}% + \else\DN@{\reverseDirection@\ellipsecentredEdge@}\fi + \fi\fi \next@} + +\xydef@\circleUnder@{\Inside@false + \ifdim\X@p=\X@c \relax \ifdim\Y@p=\Y@c \Inside@true \fi \fi + \ifInside@ \else \expandafter \circleCentre@ \fi} + +\xydef@\circleCentre@{{% + \ifdim\L@c=\R@c \relax\else + \dimen@=\R@c\advance\dimen@-\L@c \divide\dimen@\tw@ + \advance\X@c\dimen@ \advance\R@c-\dimen@ \fi + \d@X=\X@c \advance\d@X-\X@p \d@X=\ifdim\d@X<\z@-\fi\d@X + \ifdim\U@c=\D@c\relax \else + \dimen@=\U@c\advance\dimen@-\D@c \divide\dimen@\tw@ + \advance\Y@c\dimen@ \advance\U@c-\dimen@ \fi + \d@Y=\Y@c \advance\d@Y-\Y@p \d@Y=\ifdim\d@Y<\z@-\fi\d@Y + \DN@{}\ifdim\d@X>\R@c \relax \else \ifdim\d@Y>\U@c \relax + \else \ifdim\U@c=\R@c \DN@{\circlecentredUnder@}% + \else \DN@{\ellipsecentredUnder@}\fi + \fi\fi \next@}} + +\xydef@\circleInner@{\DN@{\ellipseInner@}% + \ifdim\R@c=\L@c\relax \ifdim\U@c=\D@c\relax + \ifdim\R@c=\U@c\DN@{\circlecentredInner@}% + \else\DN@{\ellipsecentredInner@}\fi + \fi\fi \next@} + +\xydef@\circleOuter@{\DN@{\ellipseOuter@}% + \ifdim\R@c=\L@c\relax \ifdim\U@c=\D@c\relax + \ifdim\R@c=\U@c\DN@{\circlecentredOuter@}% + \else\DN@{\ellipsecentredOuter@}\fi + \fi\fi \next@} +\DOCMODE) + +\subparagraph*{True circles, centered:} Code~0 moves $|<|X_c|,|Y_c|>|$ to the + point $|<|X_c - R_c*\cos\alpha|,| Y_c - R_c*\sin\alpha|>|$ where + $\alpha$ is the current direction angle, code~1 tests whether the + $p$ center is located between those two points., code~2 just returns + the radius, code~3 is as code~0 and code~4 is the only nontrivial + one, replacing with the inner symmetric rectangle with corner at the + point of code~0. + +\DOCMODE( +\xydef@\circlecentredEdge@{% + \dimen@=-\cosDirection\R@c \advance\X@c\dimen@ + \dimen@=-\sinDirection\R@c \advance\Y@c\dimen@} + +\xydef@\circlecentredUnder@{% + \loop\ifdim\R@c>100\p@ \circlescale@ \repeat + \edef\tmp@{\expandafter\removePT@\the\R@c}\dimen@=\tmp@\R@c + \edef\tmp@{\expandafter\removePT@\the\d@X}\advance\dimen@-\tmp@\d@X + \edef\tmp@{\expandafter\removePT@\the\d@Y}\advance\dimen@-\tmp@\d@Y + \ifdim\dimen@>\z@ \aftergroup\Inside@true \fi} + +%%\xydef@\circlescale@{\divide\R@c\KK@ \divide\d@X\KK@ \divide\d@Y\KK@ } +\xydef@\circlescale@{\divide\R@c\KK@ \divide\d@X\KK@ \divide\d@Y\KK@ } + +\xydef@\circlecentredInner@{% + \L@c=\sd@X\cosDirection\R@c \D@c=\sd@Y\sinDirection\R@c + \R@c=\L@c \U@c=\D@c \Edge@c={\rectangleEdge}} + +\xydef@\circlecentredOuter@{% + \L@c=\R@c \D@c=\R@c \U@c=\D@c \Edge@c={\rectangleEdge}} +\DOCMODE) + +\subparagraph*{Ellipsis, centered:} When $c$ is at the centre of an + elliptical object, first rescale the axes to make the object + circular. Rescale $dX$ and $dY$ appropriately, reset the direction + and move to the edge as previously. Then scale back to + the original shape, adjusting $X_c$ and $Y_c$ appropriately. + +\DOCMODE( +\xydef@\ellipsecentredEdge@{\bgroup \X@p=\X@c \Y@p=\Y@c + \ifdim\U@c>\R@c + \X@c=\cosDirection\U@c \Y@c=\sinDirection\U@c + \quotient@\tmp@\U@c\R@c \X@c=\tmp@\X@c \R@c=\U@c + \else + \X@c=\cosDirection\R@c \Y@c=\sinDirection\R@c + \quotient@\tmp@\R@c\U@c \Y@c=\tmp@\Y@c + \fi + \advance\X@c\X@p \advance\Y@c\Y@p + \setupDirection@ \X@c=\X@p \Y@c=\Y@p \circlecentredEdge@ + \d@X=\X@c \advance\d@X-\X@p \d@Y=\Y@c \advance\d@Y-\Y@p + \ifdim\U@c>\L@c \quotient@\tmp@\L@c\U@c \d@X=\tmp@\d@X + \else \quotient@\tmp@\U@c\R@c \d@Y =\tmp@\d@Y \fi + \X@c=\X@p \advance\X@c\d@X \Y@c=\Y@p \advance\Y@c\d@Y + \edef\next@{\egroup \X@c=\the\X@c \Y@c=\the\Y@c}\next@ }% + +\xydef@\ellipsecentredUnder@{% + \ifdim\R@c>64\p@ \circlescale@ \divide\U@c\KK@ + \else \ifdim\U@c>64\p@ \circlescale@ \divide\U@c\KK@ \fi\fi + \edef\tmp@{\expandafter\removePT@\the\R@c}\d@Y=\tmp@\d@Y + \edef\tmp@{\expandafter\removePT@\the\U@c}\d@X=\tmp@\d@X + \R@c=\tmp@\R@c \circlecentredUnder@ } +\DOCMODE) + + For elliptical objects the Outer-rectangle retains all the + extents, so just change the edge-type. + +\DOCMODE( +\xydef@\ellipsecentredOuter@{\Edge@c={\rectangleEdge}} +\DOCMODE) + + For elliptical objects the Inner-rectangle needs to + be calculated for each direction. This is done by + first finding the edge, using |\ellipseEdge@| or + |\ellipsecentredEdge@| when appropriate. + +\DOCMODE( +\xydef@\ellipsecentredInner@{% + \bgroup \X@p=\X@c \Y@p=\Y@c \ellipsecentredEdge@ +% \advance\X@c-\X@p \L@c=\ifdim\X@c<\z@-\fi\L@c + \advance\X@c-\X@p \L@c=\ifdim\X@c<\z@-\fi\X@c +% \advance\Y@c-\Y@p \D@c=\ifdim\Y@c<\z@-\fi\D@c + \advance\Y@c-\Y@p \D@c=\ifdim\Y@c<\z@-\fi\Y@c + \edef\next@{\egroup \L@c=\the\L@c \D@c=\the\D@c}\next@ + \R@c=\L@c \U@c=\D@c \Edge@c={\rectangleEdge}} +\DOCMODE) + +\subparagraph*{Non-centered variants:} The code for the more general + |\ellipseEdge@| uses a Newton iteration to solve a quadratic + equation. + + First locate the actual centre of the ellipse and + the lengths of the major axis $a$ and minor axis $b$. + Let $(x,y)$ denote the displacement of the required + edge point from the centre of the ellipse, + so that ${x^2\over a^2}+{y^2\over b^2}=1$. + Now let $(dx,dy)$ be the displacement from the centre + to the reference point; then $x=dx+s \cos\theta$ and + $y=dy+s\sin\theta$ where $s$ is the distance to $(x,y)$ + in the required direction $\theta$. + We must find the value of $s$, presumed to satisfy $s\ge0$. + + If $a\lt b$ we search for a root of +\begin{eqnarray*} +f\left({s\over a}\right) &= \;\; +\left(\tilde{dx}+{s\over a}\cos\theta\right)^2 ++\left(\tilde{dy}+{s\over a}{a\over b}\sin\theta\right)^2 & \cr +f'\left({s\over a}\right) &= \;\; +2\left(\tilde{dx}+{s\over a}\cos\theta\right)\cos\theta ++ 2\left(\tilde{dy}+{s\over a}{a\over b}\sin\theta\right) +{a\over b}\sin\theta +\end{eqnarray*} + where $\tilde{dx} = dx/a$ and $\tilde{dy} = dy/b$. + By choosing a starting value $s_0=2a+2b$ the Newton-iteration + converges rapidly to the correct root, provided $b\gt0$. +\smallskip +\noindent + If $a\gt b$ then we solve a similar quadratic in ${s\over b}$. + + \TODO: + The case of $a=0$ or $b=0$, so that the ellipse degenerates + to a line segment, should be trapped earlier. + Such an object would be more easily handled as a degenerate + case of a rectangle. + + \TODO: + In the case when the reference point lies outside the ellipse + the Newton iteration is not guaranteed to converge. + A simple test --- $s$ growing rather than decreasing in size --- + detects possible converge problems and exits the iteration. + The following message is issued \dots + $$|Xy-pic warning: poor convergence.|$$ + Often, particularly when the reference point is on or near + the edge of the ellipse, + an acceptable approximation to the edge has been found anyway. + +\DOCMODE( +\xydef@\ellipseEdge@{\bgroup + \A@=\R@c \B@=\U@c + \ifdim\R@c=\L@c \d@X=\z@ + \else \d@X=.5\R@c \advance\d@X-.5\L@c + \advance\A@\L@c \divide\A@\tw@ \fi + \ifdim\U@c=\D@c \d@Y=\z@ + \else \d@Y=.5\U@c \advance\d@Y-.5\D@c + \advance\B@\D@c \divide\B@\tw@ \fi + \bgroup + \L@c=\A@ \U@c=\B@ + \R@p=\U@c \advance\R@p\L@c \multiply\R@p\tw@ + \ifdim\B@<\A@ \quotient@\tmp@\U@c\L@c \R@c=\tmp@\p@ \D@c=\p@ + \quotient@\tmp@\R@p\L@c \R@p=\tmp@\p@ + \else + \ifdim\A@<\B@ \quotient@\tmp@\L@c\U@c \D@c=\tmp@\p@ \R@c=\p@ + \quotient@\tmp@\R@p\U@c \R@p=\tmp@\p@ + \else + \R@c=\p@ \D@c=\p@ \quotient@\tmp@\R@p\U@c \R@p=\tmp@\p@ + \fi\fi + \quotient@\sd@X\d@X\L@c \d@X=\sd@X\p@ + \quotient@\sd@Y\d@Y\U@c \d@Y=\sd@Y\p@ + \loop + \bgroup \U@p=-\p@ \D@p=\z@ + \ifdim\R@c<\p@ + \edef\tmp@{\expandafter\removePT@\the\R@c}\dimen@=\tmp@\R@p + \advance\d@X\cosDirection\dimen@ + \else \advance\d@X\cosDirection\R@p \fi + \edef\sd@X{\expandafter\removePT@\the\d@X}% + \advance\U@p\sd@X\d@X + \ifdim\R@c<\p@ + \edef\tmp@{\expandafter\removePT@\the\R@c}\dimen@=\tmp@\d@X + \advance\D@p\cosDirection\dimen@ + \else \advance\D@p\cosDirection\d@X \fi +% + \ifdim\D@c<\p@ + \edef\tmp@{\expandafter\removePT@\the\D@c}\dimen@=\tmp@\R@p + \advance\d@Y\sinDirection\dimen@ + \else \advance\d@Y\sinDirection\R@p \fi + \edef\sd@Y{\expandafter\removePT@\the\d@Y}% + \advance\U@p\sd@Y\d@Y + \ifdim\D@c<\p@ + \edef\tmp@{\expandafter\removePT@\the\D@c}\dimen@=\tmp@\d@Y + \advance\D@p\sinDirection\dimen@ + \else \advance\D@p\sinDirection\d@Y \fi + \multiply\D@p\tw@ + \dimen@=\ifdim\U@p<\z@-\fi\U@p + \ifdim\dimen@<.01\p@ \U@p=\z@ + \else + \quotient@\tmp@\U@p\D@p \U@p=\tmp@\p@ + \ifdim\U@p<\z@\xywarning@{poor convergence}\U@p=\z@ + \else \advance\R@p-\U@p \U@p=\ifdim\U@p<\z@-\fi\U@p + \fi \fi + \edef\next@{\egroup \R@p=\the\R@p \U@p=\the\U@p \D@p=\the\D@p}\next@ + \ifdim\U@p>\z@ \repeat + \edef\next@{\egroup \dimen@=\the\R@p}\next@ + \edef\tmp@{\expandafter\removePT@\the\dimen@}% + \ifdim\B@<\A@ \dimen@=\tmp@\B@ \else \dimen@=\tmp@\A@ \fi + \dimen@=-\dimen@ + \advance\X@c\cosDirection\dimen@ + \advance\Y@c\sinDirection\dimen@ + \edef\next@{\egroup \X@c=\the\X@c \Y@c=\the\Y@c}\next@ }% +\DOCMODE) + + The `Under' procedure is identical to the centered version. + +\DOCMODE( +\xydef@\ellipseOuter@{\Edge@c={\rectangleEdge}} + +\xydef@\ellipseInner@{% + \bgroup \X@p=\X@c \Y@p=\Y@c \ellipseEdge@ + \d@X=\X@c\advance\d@X-\X@p + \ifdim\d@X>\z@ \R@p=\d@X \L@p=\R@p + \ifdim\L@c=\R@c\else\advance\L@p\L@c \advance\L@p-\R@c \fi + \else \L@p=-\d@X \R@p=\L@p + \ifdim\L@c=\R@c \else\advance\R@p\R@c \advance\R@p-\L@c \fi + \fi + \d@Y=\Y@c\advance\d@Y-\Y@p + \ifdim\d@Y>\z@ \U@p=\d@Y \D@p=\U@p + \ifdim\D@c=\U@c\else\advance\D@p\D@c \advance\D@p-\U@c \fi +%\else \D@p=-\d@X \R@p=\D@p + \else \D@p=-\d@Y \U@p=\D@p % <<<<<<======== + \ifdim\D@c=\U@c\else\advance\U@p\U@c \advance\U@p-\D@c \fi + \fi + \edef\next@{\egroup + \L@c=\the\L@p \D@c=\the\D@p \R@c=\the\R@p \U@c=\the\U@p}% + \next@ \Edge@c={\rectangleEdge}} +\DOCMODE) + +\paragraph*{Rectangles:}\leavevmode + + Rectangles intersection is slightly more complicated and handled + separately for the horizontal and vertical case. + +\DOCMODE( +\xydef@\rectangleEdge#1{\ifcase#1\expandafter\rectangleEdge@ + \or \expandafter\rectangleUnder@ \or \expandafter\rectangleDist@ + \or \expandafter\rectangleProp@ %%%\or \expandafter\rectangleInner@ BUG! + \else \relax \fi} +\DOCMODE) + + \BUG: no `Inner' for rectangles! + +\DOCMODE( +% \rectangleEdge@ +% Sets <X,Y> to the intersection of a line from <X-dX,Y-dY> to <X,Y> +% and the rectangle from <X-L,Y-D> to <X+R,Y+U>: +% +% %1a dY<0, dX<0: X := X + min{R, U*|dX/dY|}, +% Y := Y + min{U, R*|dY/dX|}; +% b dY<0, dX=0: Y := Y + U; +% c dY<0, dX>0: X := X - min{L, U*|dX/dY|}, +% Y := Y + min{U, L*|dY/dX|}; +% +% %2a dY=0, dX<0: X := X + R; +% b dY=0, dX=0: ; +% c dY=0, dX>0: X := X - L; +% +% %3a dY>0, dX<0: X := X + min{R, D*|dX/dY|}, +% Y := Y - min{D, R*|dY/dX|}; +% b dY>0, dX=0: Y := Y - D; +% c dY>0, dX>0: X := X - min{L, D*|dX/dY|}, +% Y := Y - min{D, L*|dY/dX|}; +% +% %4 \resetupDirection@ to register that even though dX,dY changed all +% Direction parameters are is still valid! +% +% NOTE: d=0 really means |d| < .05pt. +% +\xydef@\rectangleEdge@{% + \ifdim\d@Y<-.05\p@ \rectangleEdge@i %1 + \else\ifdim\d@Y<.05\p@ \rectangleEdge@ii %2 + \else \rectangleEdge@iii\fi\fi + \resetupDirection@} + +\xydef@\rectangleEdge@i{% + \ifdim\d@X<-.05\p@ + \settomin@\X@c+\R@c\U@c\d@X\d@Y \settomin@\Y@c+\U@c\R@c\d@Y\d@X%1a + \else\ifdim\d@X<.05\p@ \advance\Y@c\U@c %1b + \else \settomin@\X@c-\L@c\U@c\d@X\d@Y \settomin@\Y@c+\U@c\L@c\d@Y\d@X %1c + \fi\fi} + +\xydef@\rectangleEdge@ii{% + \ifdim\d@X<-.05\p@ \advance\X@c\R@c %2a + \else\ifdim\d@X<.05\p@ %2b + \else \advance\X@c-\L@c %2c + \fi\fi} + +\xydef@\rectangleEdge@iii{% + \ifdim\d@X<-.05\p@ + \settomin@\X@c+\R@c\D@c\d@X\d@Y \settomin@\Y@c-\D@c\R@c\d@Y\d@X%3a + \else\ifdim\d@X<.05\p@ \advance\Y@c-\D@c %3b + \else \settomin@\X@c-\L@c\D@c\d@X\d@Y \settomin@\Y@c-\D@c\L@c\d@Y\d@X %3c + \fi\fi} + +\xydef@\settomin@#1#2#3#4#5#6{% + % Perform d := #2 min{#3, #4*|#5/#6|}; #1 := #1+d ... + \edef\nextii@{\A@=\the\A@ \B@=\the\B@}\quotient@\next@{#5}{#6}\nextii@ + \dimen@=\sd@X\sd@Y\next@#4\relax + \ifdim#3<\dimen@ \dimen@=#3\fi \advance#1#2\dimen@} +\DOCMODE) + + Checking that $p$ is under is simpler: Normally it is not but + if $c=p$ or ($-L_c \lt X_p-X_c \lt R_c$ and $-D_c \lt Y_p-Y_c \lt + U_c$) then it is. + +\DOCMODE( +\xydef@\rectangleUnder@{\Inside@false + \ifdim\X@p=\X@c \ifdim\Y@p=\Y@c \Inside@true \fi\fi + \ifInside@ \else + \dimen@=\X@p \advance\dimen@-\X@c + \ifdim \dimen@>-\L@c \relax \ifdim\dimen@<\R@c + \dimen@=\Y@p \advance\dimen@-\Y@c + \ifdim \dimen@>-\D@c \relax \ifdim\dimen@<\U@c + \Inside@true + \fi\fi\fi\fi\fi } +\DOCMODE) + + Calculating the width is like computing the edge point, just simpler: + (??_[rDist])~Set $A$ to the horizontal and $B$ to the vertical + distance applicable; if either is zero (or close) use the other + unmodified . (??_[rDisti])~If both nonzero use + $\min(A/\cos\alpha,B/\sin\alpha)$ where $\alpha$ is the current angle. + +\DOCMODE( +\xydef@\rectangleDist@{\let\next@=\rectangleDist@i %?*[rDist] + \ifdim\d@X<-.05\p@ \dimen@=\R@c + \else\ifdim\d@X<.05\p@ \dimen@=\z@ \DN@{\dimen@=\dimen@ii}% + \else \dimen@=\L@c \fi\fi + \ifdim\d@Y<-.05\p@ \dimen@ii=\U@c + \else\ifdim\d@Y<.05\p@ \DN@{}% + \else \dimen@ii=\D@c \fi\fi + \next@} + +\xydef@\rectangleDist@i{%?*[rDisti] + \begingroup \quotient@\next\p@{\sd@X\cosDirection\p@}% + \edef\next{\endgroup \dimen@=\next\dimen@}\next + \begingroup \quotient@\next\p@{\sd@Y\sinDirection\p@}% + \edef\next{\endgroup \dimen@ii=\the\dimen@ii}\next + \ifdim\dimen@ii<\dimen@ \dimen@=\dimen@ii \fi} +\DOCMODE) + + Setting $c$ to the `proportional edge point' is straight out of + v2.6's |\setlabel@@| macro\dots + +\DOCMODE( +% First rotate to opposite direction. + +% Then compute Leftf,Upf [\next@,\nextii@]: +% 0,(D-2K)/2K for 2K < D <= 4K [right] +% (2K-D)/2K,0 for 0 < D <= 2K [down] +% 1,-D/2K for -2K < D <= 0 [left] +% (D+4K)/2K,1 for -4K < D <= -2K [up] + +% Finally set <X,Y> to +% < X - L + Leftf*(R+L) , Y + U - Upf*(D+U) > + +\xydef@\rectangleProp@{% + \enter@{\A@=\the\A@ \B@=\the\B@ \DirectionfromtheDirection@}% + \reverseDirection@ + \dimen@=1\Direction \count@=\K@ \multiply\count@\tw@ + \ifnum \Direction>\count@ + \DN@{0}% + \advance\dimen@-2\K@ \quotient@\nextii@{\dimen@}{2\K@}% + \else\ifnum \Direction>\z@ + \dimen@=-\dimen@ \advance\dimen@2\K@ \quotient@\next@{\dimen@}{2\K@}% + \DNii@{0}% + \else\ifnum \Direction>-\count@ + \DN@{1}% + \quotient@\nextii@{-\dimen@}{2\K@}% + \else + \advance\dimen@4\K@ \quotient@\next@{\dimen@}{2\K@}% + \DNii@{1}% + \fi\fi\fi + \advance\X@c-\L@c \dimen@=\L@c \advance\dimen@\R@c + \ifdim\dimen@=\z@ \advance\X@c 2\L@c \else \advance\X@c\next@\dimen@ \fi + \advance\Y@c+\U@c \dimen@=\D@c \advance\dimen@\U@c + \ifdim\dimen@=\z@ \advance\Y@c-2\U@c \advance\Y@c\Upness@\U@c + \else \advance\Y@c-\nextii@\dimen@ \fi + \leave@} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +\subsection{Connections} +??=[algo.connection] + +\DOCMODE( +\message{connections;} +\DOCMODE) + + Connections describe how a particular <object> may be used to connect + $p$ to $c$. The following parameters and methods are defined by any + connection; they should be used in the indicated + sequence:??w[connection methods] +% +\begin{description} + +\item[|\Invisible@@|, |\Hidden@@|, and |\Drop@@|:] as for <object>. + +\item[|\Creset@@|:] + (Re)set the connection parameters to allow use of the following to + move to a point on the connection (this is what the interpretation of + <pos> |?| does first). All effects obtained by the following methods + are undone: |\Creset@@| reestablishes the state to what it was just + after the |\Connect@@| every time. + +\item[|\Cshavep@@| or |\Cshavec@@|:] + Change $p$ or $c$ to a zero-sized object at the start or finish of + the connection (the first |<| and |>| <place> components). + +\item[|\Calong@@{|<factor>|}|:] + Move $c$ to point the <factor> along the connection and set the + direction parameters as a tangent to it in this point (the + |(|<factor>|)| <place> component). + +\item[|\Cslidep@@{|<dimen>|}| or |\Cslidec@@{|<dimen>|}|:] + Move $p$ or $c$ the <dimen>sion further in the current direction. + Can be used both before and after the |\Calong@@| method (these + handle subsequent |<| and |>| as well as the |/|<slide>|/| <place> + component). + +\item[|\Cintercept@@|:] + Set $c$ to a zerosized object at the point where the connection + crosses the straight line from $p$ to $c$ (the |!{|\dots|}| <place> + component). + +\item[|\Cbreak@@| and |\Clast@@|:] + These support typesetting of the connection in several `subsegments' + as used by the arrow option. The idea is the following, using the + internal "lastbreak" and "nextbreak" positions: +\begin{enumerate} + +\item |\Connect@@| sets $"lastbreak":=p$ and $"nextbreak":=c$ + +\item The commands |\Cslidec@@|, |\Cslidep@@|, and |\Cintercept@@|, set + "nextbreak" logically to the position that is obtained by the + manipulation. + +\item |\Cbreak@@| retypesets the connection except only the piece + from "lastbreak" to the current $c$ object, which "must" be at on top + of "nextbreak", is typeset. Afterwords it sets + $"lastbreak":="nextbreak"$ and $"nextbreak":=c$ (where $c$ is the + original $c$ of the connection). + +\item The command |\Clast@@| typesets from "lastbreak" and the remainder of + the connection, and resets $"lastbreak":=p$ and $"nextbreak":=c$. + +\end{enumerate} +\end{description} +% + Notice that it is not necessary for "nextbreak" to actually exist, in + fact in the kernel it is just an alias for $c$ at the time + |\Cbreak@@| is called. + + These are the defaults for basic \Xy-pictures that only has straight + connections hence the macros all starting with |\no|\dots are rather + simple -- in particular they just merge with zerosized objects at the + locations cutoff locations (this was inherited from the broken + |arrow| code~\smiley~). + +\DOCMODE( +\xydef@\Creset@@{} +\xydef@\Cshavep@@{\noCshavep@@} +\xydef@\Cshavec@@{\noCshavec@@} +\xydef@\Cslidep@@{\noCslidep@@} +\xydef@\Cslidec@@{\noCslidec@@} +\xydef@\Calong@@{\noCalong@@} +\xydef@\Cintercept@@{\noCintercept@@} +\xydef@\Cbreak@@{\noCbreak@@} +\xydef@\Clast@@{\noClast@@} + +\xylet@\lastbreak@@=\empty + +\xydef@\noCshavep@@{\setupDirection@ + \enter@{\cfromthec@ \DirectionfromtheDirection@}% + \reverseDirection@ \cfromp@ \the\Edge@c\z@ + \pfromc@ \leave@ \resetDirection@} + +\xydef@\noCshavec@@{\setupDirection@ \the\Edge@c\z@ \resetDirection@} + +\xydef@\noCslidep@@#1{\dimen@=#1\relax + \advance\X@p\cosDirection\dimen@ \advance\Y@p\sinDirection\dimen@ + \resetDirection@} + +\xydef@\noCslidec@@#1{\dimen@=#1\relax + \advance\X@c\cosDirection\dimen@ \advance\Y@c\sinDirection\dimen@ + \resetDirection@} + +\xydef@\noCalong@@#1{% + \d@X=#1\d@X \d@Y=#1\d@Y \X@c=\X@p \Y@c=\Y@p \advance\X@c\d@X \advance\Y@c\d@Y + \resetupDirection@} +\DOCMODE) + + Next the intercept method that just uses |\intersect@|. + +\DOCMODE( +\xydef@\noCintercept@@{\enter@{\pfromthep@}% + \begingroup\Creset@@ \edef\tmp@{\endgroup + \X@origin=\the\X@p \Y@origin=\the\Y@p \R@c=\the\d@X \U@c=\the\d@Y}\tmp@ + \loop@\dimen@=\ifdim\R@c<\z@-\fi\R@c \advance\dimen@\ifdim\U@c<\z@-\fi\U@c + \ifdim\dimen@>10\p@ \advance\R@c \ifdim\R@c<\z@-\fi 16sp \divide\R@c\KK@ + \advance\U@c \ifdim\U@c<\z@-\fi 16sp \divide\U@c\KK@ \repeat@ + \intersect@ \leave@} +\DOCMODE) + + And finally the dummy `break' method which of course does nothing + except the required shifting. + +\DOCMODE( +\xydef@\noCbreak@@{\edef\lastbreak@@{\cfromthec@}} +\xydef@\noClast@@{\Creset@@ \edef\lastbreak@@{\cfromthep@}} +\DOCMODE) + + The kernel only defines one kind of connection which is used by + default: `filling' many copies of the connect object on the straight + line from $p$ to $c$. + + First the `dummy' connection type |no| used for <object>s where it + doesn't really make sense to `connect', and used to provide defaults + for easy operations: + +\DOCMODE( +\xydef@\no@@{\setupDirection@ \edef\lastbreak@@{\cfromthep@}% + \enter@{\cfromthec@\pfromthep@\DirectionfromtheDirection@}% + \edef\Creset@@{\cfromthec@ \pfromthep@ \DirectionfromtheDirection@}% + \edef\next@{{\sd@X}{\sd@Y}}\expandafter\straightcheckoverlap@\next@ + \setupDirection@ \the\Edge@c\z@ + \swap@\reverseDirection@\the\Edge@c\z@\swap@\reverseDirection@ + \resetDirection@ + \edef\Cshavep@@{\DirectionfromtheDirection@ + \pfromthep@\noexpand\resetDirection@}% + \edef\Cshavec@@{\DirectionfromtheDirection@ + \cfromthec@\noexpand\resetDirection@}% + \leave@ + \def\Cslidep@@{\noCslidep@@}\def\Cslidec@@{\noCslidec@@}% + \def\Calong@@{\noCalong@@}\def\Cintercept@@{\noCintercept@@}% + \def\Cbreak@@{\noCbreak@@}\def\Clast@@{\noClast@@}\noinsert@} + +\xydef@\noinsert@{\ifHidden@\else + \ifdim\Y@c>\Y@max \Y@max=\Y@c \fi \ifdim\Y@p>\Y@max \Y@max=\Y@p \fi + \ifdim\Y@c<\Y@min \Y@min=\Y@c \fi \ifdim\Y@p<\Y@min \Y@min=\Y@p \fi + \ifdim\X@c>\X@max \X@max=\X@c \fi \ifdim\X@p>\X@max \X@max=\X@p \fi + \ifdim\X@c<\X@min \X@min=\X@c \fi \ifdim\X@p<\X@min \X@min=\X@p \fi + \fi} +\DOCMODE) + + Next `straight' connections that use the following special parameters + to customises how to repeat a `filler' object as many times as needed + to draw the connection: +% +\begin{description} + +\item[|\lastobjectbox@|:] box to fill with; assumed to be `trimmed' to have + only the size needed for the filler; size is $w*(h+d)$). + +\end{description} +% + The method is called as |\straight@{|<spread>|}| where <spread> is a + macro to expand "after" the number of fillers $N$ (in |\count@@|) is + known and with $A=w$ and $B=d+h$ but "before" any filling is done. + May change $N$ as well as $"dX","dY",X,Y,w,d,h$ in order to affect + the filling. + +\subparagraph*{Procedure:} +% + [??_[Strgt1]] setup direction parameters, clear the break state, and + define the |\Creset@@| macro to reestablish this initial state; + [??_[Strgt2]] build macro to discover if the edges of the objects + overlap (it edges were removed); [??_[Strgt3]] move both $p,c$ to the + edges of the objects\dots and define the |\Cshave*@@| macros + accordingly; [??_[Strgt4]] choose either to ignore the connection if + requested or there is overlap between the objects of choose either + vbox or hbox version (see below)\dots; and [??_[Strgt5]] build + |\Calong@@|, |\Cbreak@@|, and |\Clast@@| macros, and reset $pc$. + + \NOTE: Assumes that the direction is not tampered with between Creset + is defined and used\dots + +\DOCMODE( +\xydef@\Spread@@{} +\xydef@\checkoverlap@@{} + +\xydef@\straight@#1{\setupDirection@ \def\Spread@@{#1}% %?*[Strgt1] + \edef\Creset@@{\cfromthec@ \pfromthep@ \DirectionfromtheDirection@}% + \edef\lastbreak@@{\cfromthep@}% + \edef\next@{{\sd@X}{\sd@Y}}\expandafter\straightcheckoverlap@\next@ %?*[Strgt2] + \setupDirection@ \the\Edge@c\z@ + \swap@\reverseDirection@\the\Edge@c\z@\swap@\reverseDirection@ + \resetDirection@ + \edef\Cshavep@@{\DirectionfromtheDirection@ + \pfromthep@\noexpand\resetDirection@}% + \edef\Cshavec@@{\DirectionfromtheDirection@ + \cfromthec@\noexpand\resetDirection@}% + \noinsert@ %?*[Strgt3b] + \straight@typeset %?*[Strgt4] + \def\Cbreak@@{\straightCbreak@}\def\Clast@@{\straightClast@}% +% \DN@{\solidSpread@}\ifx\next@\Spread@@ +% \checkXy@rules@\solidhrule@pre\solidvrule@pre\relax +% \fi + \def\Cslidep@@{\noCslidep@@}\def\Cslidec@@{\noCslidec@@}%?*[Strgt5] + \def\Calong@@{\noCalong@@}\def\Cintercept@@{\noCintercept@@}% + \Creset@@} + +\xydef@\straightcheckoverlap@#1#2{\def\checkoverlap@@{% + \ifdim#1\X@p>#1\X@c \let\next@=\relax \fi + \ifdim#2\Y@p>#2\Y@c \let\next@=\relax \fi}} + +\xydef@\straight@typeset{% + \ifInvisible@ \let\next@=\relax + \else\ifdim 1\Direction<-2\K@ \DN@{\straightv@}% + \else\ifdim 1\Direction<\z@ \DN@{\straighth@}% + \else\ifdim 1\Direction<2\K@ \DN@{\straightv@}% + \else \DN@{\straighth@}% + \fi\fi\fi\fi \checkoverlap@@ \next@} +\DOCMODE) + + The methods |\straightCbreak@| and |\straightClast@| implement the + break method parametrised on the `typeset' primitive which is usually + |\straight@typeset| which is a simplified version of |\straight@| + that does not initialise. This relies on the connection being + straight: the |Cbreak@@| method executes $p,c := + p|.|"lastbreak",c|.|"nextbreak"$ and |Clast@@| executes $p,c := + p|.|"lastbreak",c$, where in both cases the |[Inner]| modifier is + applied just before the merging to make sure the edge is respected by + the merged object. + +\DOCMODE( +\xylet@\nextbreak@@=\empty + +\xydef@\straightCbreak@{\connectRestore@ + \edef\nextbreak@@{\cfromthec@}% + \Creset@@ \swap@ \the\Edge@c4\enter@{\cmergethec@}\lastbreak@@ \leave@ + \swap@ \the\Edge@c4\enter@{\cmergethec@}\nextbreak@@ \leave@ + \setupDirection@ + \the\Edge@c\z@ + \swap@ \reverseDirection@ \the\Edge@c\z@ \swap@ \reverseDirection@ + \resetDirection@ \noinsert@ \straight@typeset + \Creset@@ \let\lastbreak@@=\nextbreak@@} + +\xydef@\straightClast@{\connectRestore@ + \Creset@@ \swap@ \the\Edge@c4\enter@{\cmergethec@}\lastbreak@@ \leave@ + \swap@ + \setupDirection@ + \the\Edge@c\z@ + \swap@\reverseDirection@ \the\Edge@c\z@ \swap@\reverseDirection@ + \resetDirection@ \noinsert@ \straight@typeset + \Creset@@ \edef\lastbreak@@{\cfromthep@}} +\DOCMODE) + + Now for the typesetting -- to summarise: these are parametrised on + direction parameters and use $X,Y$: endpoint of connection + (`Direction end'). $"dX","dY"$: connection distance (`Direction + vector'). |\Leftness@| of <object>. |\lastobjectbox@| to fill with; + assumed to be `trimmed'. |\Spread@@| to expand to modify the default + spreading used. |\Drop@@| to expand to actually typeset the finished + connection when it is in box0! \NOTE: Must make box0 void to avoid + `box leaks'. + + Two variants exist: one for mostly horisontal and one for mostly + vertical filling. We detail the `mostly horisontal' one: + + [??_[StrH0]] start box; +% + [??_[StrH1]] compute initial adjustment ($X$ right and $Y$ up) and + $A := w$, $B := h+d$, $N = \floor(\abs{"dX"} / A)$, + and run user supplied Spread; +% + [??_[StrH2]] adjust first filler position horizontally: + if $dX\gt0$ then $X := X-w$; +% + [??_[StrH4]] adjust first filler vertically: $Y := Y - + "sdX"*L*("dY"/"dX")*w$ where $L = \textup{if} dX>0 \textup{then} + (1-Leftness) \textup{else} Leftness$; +% + [??_[StrH3]] recompute the move dimensions ($A$ right and $B$ up): + $A := -"sdX"(\abs{dX} - w) / (N-1)$, + $B := "sdY"\abs{"sdX"(w)*"dY"/"dX" - dY} / (N-1)$, + and set the filler box to have $w := A$; +% + [??_[StrH5]] output first filler adjusted $X,Y$ and the following $N-1$ + each $A$ further right and raised $B$ more than the previous; +% + and finally end object with usual bravour! + +\DOCMODE( +\xydef@\straighth@{\setbox\z@=\hbox{% + \setbox8=\copy\lastobjectbox@ + \A@=\wd8\relax \B@=\dp8\relax \advance\B@\ht8\relax %?*[StrH1] + \ifdim \A@=\z@ \count@@=\m@ne + \else \dimen@=\sd@X\d@X \divide\dimen@\A@ \count@@=\dimen@ \fi + \Spread@@ + \ifdim\d@X>\z@ \advance\X@c-\wd8\relax\fi %?*[StrH2] + \dimen@=-\sd@X\wd8\relax %?*[StrH4] + \multiply\dimen@\K@dYdX \divide\dimen@\K@ + \ifdim\d@X>\z@ \advance\Y@c\dimen@ \advance\Y@c-\Leftness@\dimen@ + \else \advance\Y@c\Leftness@\dimen@ \fi + \dimen@=\wd8\relax \A@=\sd@X\d@X \advance\A@-\dimen@ %?*[StrH3] + \B@=\sd@X\dimen@ \multiply\B@\K@dYdX \divide\B@\K@ + \advance\B@-\d@Y \B@=\sd@Y\B@ + \count@=\count@@ \advance\count@\m@ne + \ifnum\z@<\count@ \divide\A@\count@ \divide\B@\count@ \fi + \A@=-\sd@X\A@ \B@=\sd@Y\B@ \wd8=\A@ + \kern\X@c \count@=\z@ %?*[StrH5] + \loop@\ifnum\count@<\count@@ \advance\count@\@ne + \raise\Y@c\copy8\relax \advance\Y@c\B@ \repeat@}% + \ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}} +\DOCMODE) + + The mosly vertical is analogous. \BUG: |\dimen@| holds the unadjusted + $h+d$ throughout -- somehow it works anyway! + +\DOCMODE( +\xydef@\straightv@{\setbox\z@=\vtop{% + \setbox8=\copy\lastobjectbox@ + \A@=\wd8\relax \B@=\dp8\relax \advance\B@\ht8\relax + \ifdim \B@=\z@ \count@@=\m@ne + \else \dimen@=\sd@Y\d@Y \divide\dimen@\B@ \count@@=\dimen@ \fi + \Spread@@ + \dimen@=\dp8\relax \advance\dimen@\ht8\relax + \B@=\sd@Y\d@Y \advance\B@-\dimen@ + \A@=\sd@Y\dimen@ \multiply\A@\K@dXdY \divide\A@\K@ \advance\A@-\d@X + \A@=\sd@X\A@ \count@=\count@@ \advance\count@\m@ne + \ifnum\z@<\count@ \divide\B@\count@ \divide\A@\count@ \fi + \B@=\sd@Y\B@ \A@=\sd@X\A@ \ht8=\B@ \dp8=\z@ + \ifdim\d@Y<\z@ + \advance\Y@c\dimen@ \advance\Y@c\Upness@\B@ + \else + \advance\dimen@\Upness@\B@ \advance\Y@c-\dimen@ \advance\Y@c\B@ + \fi + \advance\Y@c\B@ + \ifdim\d@X<\z@ \else \advance\X@c-\wd8\relax \fi + \null \kern-\Y@c \count@=\z@ + \loop@\ifnum\count@<\count@@ \advance\count@\@ne + \nointerlineskip \moveright\X@c\copy8\relax \advance\X@c\A@ + \repeat@}% + \ht\z@=\z@ \wd\z@=\z@ \dp\z@=\z@ {\Drop@@}} +\DOCMODE) + +\DOCMODE2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + + +\section*{End \& log} + + \Xy-pic ends with a message saying so. + +\DOCMODE( +\message{ Xy-pic loaded}\xyuncatcodes \endinput +\DOCMODE) + + \Xy-pic is maintained using the RCS ``Revision Control System'' by + Walther F.~Tichy. The following is the revision history since the + first release to Usenet. + +\DOCMODE( +% $Log: xy.doc,v $ +% Revision 3.7 1999/02/16 15:12:50 krisrose +% Interim release (Y&Y fonts now free). +% +% Revision 3.6 1998/03/06 01:28:05 krisrose +% Releasing (with Y&Y fonts). +% +% Revision 3.5 1997/05/28 13:05:01 krisrose +% Fixed missing breaks bug. +% +% 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.2 1995/09/19 18:22:27 kris +% Bug fix 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/05 22:20:09 kris +% Buglets... +% +% Revision 2.13 1995/07/04 15:11:17 kris +% Ready to release v3? +% +% Revision 2.12 1994/10/25 11:55:12 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.10 1994/06/15 12:55:07 kris +% Second 3beta release: bug fixes. +% +% Revision 2.9 1994/06/09 14:59:19 kris +% Release 3beta. +% +% Revision 2.8 1994/04/11 09:31:09 kris +% Second (bug fix) 3alpha release [corrected]. +% +% 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. +% +% MAJOR REWRITE and REORGANISATION: +% File xypic.doc split into separate files: xy.doc for `kernel' and other +% files with the `extensions' and `features'. +% Documented in special DOCMODE LaTeX-based format supported by xydoc.sty. +% +% Revision 2.6.1.1 1992/07/01 07:08:24 kris +% Send to EuroTeX '92... +% +% Revision 2.6 1992/06/24 01:23:34 kris +% Added hooks using font xyqc10. +% Added new POSitions: * and !. +% Added triple lines \Ssolid and \Ddashed. +% +% Revision 2.5 1992/02/24 03:30:54 kris +% Fixed bugs in \Direction calculation logic... +% Added (FACTOR) to \rotate to allow arbitrary rotation. +% ` intermediate points now accept an optional /RADIUS argument. +% Added \Tip with wide tip. +% [See ChangeLog for further details]. +% +% Revision 2.4 1992/01/22 02:15:10 kris +% Fixed bugs [with thanks]: +% No spurious arrow heads with LaTeX: \pit now undefined [Werner Struckmann] +% \Solid works: sets \Density [Dave Bowen] +% Short diagonal lines work...major rewrite of \connectv@ [Eric Domenjoud] +% +% Revision 2.3 1992/01/13 23:28:12 kris +% Swapped definitions of \ddtoX and \uutoX [found by Nico Verwer]. +% Diagonal lines were wrong [Eric Domenjoud]. +% +% Revision 2.2 1992/01/09 04:05:40 kris +% Still problems with rules in frames and horizontal/vertical \solids. Grrr. +% +% Revision 2.1 1992/01/02 14:54:07 kris +% Release version. +% +% Revision 1.40 1991/12/17 04:53:23 kris +% Version distributed as `final draft' on Usenet. +\DOCMODE) + +\DOCMODE3%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% Tell Emacs that this is a LaTeX document and how it is formatted: +% Local Variables: +% mode:latex +% fill-prefix:"\t" +% fill-column:77 +% paragraph-separate:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]" +% paragraph-start:"^[ \t\f]*$\\|^[^\t]\\|\\\\\\\\\\|\\$\\$\\|[^\n\\\\][%&]" +% TeX-parse-self:nil +% LaTeX-indent-level:1 +% TeX-brace-indent-level:1 +% End: |