%% $Id: pst-tvz.tex 409 2010-10-30 18:31:11Z herbert $ %% COPYRIGHT 1993-2011 by Timothy Van Zandt % % This work may be distributed and/or modified under the % conditions of the LaTeX Project Public License, either version 1.3 % of this license or (at your option) any later version. % The latest version of this license is in % http://www.latex-project.org/lppl.txt % and version 1.3 or later is part of all distributions of LaTeX % version 2003/12/01 or later. % % This work consists of the file pstricks.tex, PostScript macros % for Generic TeX. % See the PSTricks User's Guide for description. % % %% % % ************************************************************************** % This is `pstree.doc'. Use as is or create a stripped input file % with pst-make.tex. See the PSTricks read-me file for details. % ************************************************************************** % % \EndDocPreamble % % \CharacterTable % {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z % Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z % Digits \0\1\2\3\4\5\6\7\8\9 % Exclamation \! Double quote \" Hash (number) \# % Dollar \$ Percent \% Ampersand \& % Acute accent \' Left paren \( Right paren \) % Asterisk \* Plus \+ Comma \, % Minus \- Point \. Solidus \/ % Colon \: Semicolon \; Less than \< % Equals \= Greater than \> Question mark \? % Commercial at \@ Left bracket \[ Backslash \\ % Right bracket \] Circumflex \^ Underscore \_ % Grave accent \` Left brace \{ Vertical bar \| % Right brace \} Tilde \~} % % % \part{pstree.doc} % % \section{Overview} % % An extensive description of these macros is contained in a separate file: ???? % % \section{Preliminaries} % % Start with the usual stuff: % \begin{macrocode} \csname PStvzLoaded\endcsname \let\PStvzLoaded\endinput \ifx\PSTnodesLoaded\endinput\else\input pst-node.tex\fi \ifx\PSTXKeyLoaded\endinput \else\input pst-xkey \fi % \def\fileversion{1.01} \def\filedate{2011/06/14} \message{ v\fileversion, \filedate (tvz,dg,hv)} \message{ v\fileversion, \filedate} \edef\TheAtCode{\the\catcode`\@} \catcode`\@=11 % \pst@addfams{pst-tvz} % \end{macrocode} % % \section{Profile/list operators} % % The lists are stored in command sequences, as comma separated lists of integers. This section contains various list operators. Most are optimized for singleton lists. % % \begin{macro}{\pstree@poptop,\pstree@gettop,\pstree@poptop} % If is a list, then "\pstree@puttop{}" expands to the list, with the first item replaced by , and "\pstree@gettop" expands to the first item in the list. "\pstree@poptop" removes the first item from the list and assigns it to , and the adds a 0 at the end of the list (so that the list does not change size, and in particular, will never be exhausted). % \begin{LVerbatim} % \begin{macrocode} \def\pstree@puttop#1{#1,\expandafter\pstree@@puttop} \def\pstree@@puttop#1,{} \def\pstree@gettop#1{\expandafter\pstree@@gettop#1\@nil} \def\pstree@@gettop#1,#2\@nil{#1} \def\pstree@poptop#1#2{\expandafter\pstree@@poptop#1\relax#1#2} \def\pstree@@poptop#1,#2\relax#3#4{% #4=#1\relax \def#3{#20,}} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@max} % "\pstree@max{}{}" assigns the maximum value in to . % \begin{macrocode} \def\pstree@max#1#2{% \pst@cntg=\z@ \expandafter\pstree@@max#1\relax #2=\pst@cntg}% \def\pstree@@max#1,#2{% \ifnum#1>\pst@cntg \pst@cntg=#1 \fi \ifx\relax#2\else \expandafter\pstree@@max \fi #2} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@add} % "\pstree@add{}{}" adds to each element of . % \begin{macrocode} \def\pstree@add#1#2{% \def\pst@tempg{}% \pst@cnth=#1\relax \expandafter\pstree@@add#2\relax \let#2\pst@tempg} \def\pstree@@add#1,#2{% \pst@cntg=#1 \advance\pst@cntg\pst@cnth \xdef\pst@tempg{\pst@tempg\the\pst@cntg,}% \ifx\relax#2\else \expandafter\pstree@@add \fi #2} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@tightfit,\pstree@loosefit} % \begin{LVerbatin} % \pstree@tightfit{}{}{} % \pstree@loosefit{}{}{} % \end{LVerbatim} % finds the distance between two successors. The inner profiles are and . The result is assigned to "\pst@cnth". "\pstree@loosefit" finds the distance between the bounding boxes. "\pstree@tightfit" finds the maximum distance level-by-level. I.e., "\pstree@tightfit" finds the maximum of the vector sum of the two lists, up to the end of the shortest list. "\pstree@loosefit" always returns a higher value that "\pstree@tightfit". % \begin{macrocode} \def\pstree@tightfit#1#2#3{% \pst@cnth=\z@ \let\pstree@xtightfit\pstree@@xtightfit \edef\next{\noexpand\pstree@@tightfit#1\relax#2\relax}% \next #3=\pst@cnth} \def\pstree@@tightfit#1,#2\relax#3,#4\relax{% \pst@cntg=#1 \advance\pst@cntg#3 \pstree@xtightfit \ifnum\pst@cntg>\pst@cnth \pst@cnth=\pst@cntg \fi \let\next\relax \ifx\relax#2\relax\else \ifx\relax#4\relax\else \def\next{\pstree@@tightfit#2\relax#4\relax}% \fi \fi \next} \def\pstree@@xtightfit{% \ifnum\psk@thisxtreesep=\z@ \let\pstree@xtightfit\relax \else \edef\pstree@xtightfit{\advance\pst@cntg\psk@thisxtreesep\relax}% \fi} \def\pstree@loosefit#1#2#3{% \pstree@max#1\pst@cnth \pstree@max#2#3% \advance#3\pst@cnth \ifnum\psk@thisxtreesep=\z@\else\pstree@xloosefit#1#2#3\fi} \def\pstree@xloosefit#1#2#3{% \let\next\relax%%%%%%%%%%%%%% hv 20101029 \edef\next{\noexpand\pstree@@xloosefit#3\relax#1\relax#2\relax}% \next} \def\pstree@@xloosefit#1\relax#2,#3\relax#4,#5\relax{% \ifx\relax#3\relax\else \ifx\relax#5\relax\else\advance#1\psk@thisxtreesep\relax\fi \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@zip} % \begin{LVerbatim} % \pstree@zip{}{}{}{} % \end{LVerbatim} % "\pstree@zip" subtracts from , and then sets to the item-by-item maximum of the resulting and . % % E.g., if is the current right profile in the row of sucessors, and is the right profile of the next successor, which is positioned "sp" units from the previous successor, then "" is set to the new outer profile of the row of successors. % % If is the current left profile of the row of successors, and is the left profile of the next successor, which is a total of "sp" units from the first successor, then "" is the new left profile of the row. % \begin{macrocode} \def\pstree@zip#1#2#3#4{% \pst@cnth=#1\relax \pst@cnth=-\pst@cnth \def\pst@tempg{}% \edef\next{\noexpand\pstree@@zip#2\relax#3\relax}% \next \global\let#4\pst@tempg} \def\pstree@@zip#1,#2\relax#3,#4\relax{% \pst@cntg=#1 \advance\pst@cntg\pst@cnth \edef\pst@tempg{\pst@tempg\ifnum#3>\pst@cntg#3\else\the\pst@cntg\fi,}% \let\next\relax %%%%%%%%%%%%%%%%%%%%%%%% hv \ifx\relax#2\relax \edef\pst@tempg{\pst@tempg#4}% \else \ifx\relax#4\relax \def\next{\pstree@@add#2\relax}% \else \def\next{\pstree@@zip#2\relax#4\relax}% \fi \fi \next} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@bimax} % "\pstree@max{}{}" sets to the maximum, item by item, of and . % \begin{macrocode} \def\pstree@bimax#1#2{% \def\pst@tempg{}% \edef\next{\noexpand\pstree@@bimax#1\relax#2\relax}% \next \global\let#1\pst@tempg} \def\pstree@@bimax#1,#2\relax#3,#4\relax{% \edef\pst@tempg{\pst@tempg\ifnum#1>#3 #1\else#3\fi,}% \let\next\relax%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% hv \ifx\relax#2\relax \edef\pst@tempg{\pst@tempg#4}% \else \ifx\relax#4\relax \edef\pst@tempg{\pst@tempg#2}% \let\next\relax \else \def\next{\pstree@@bimax#2\relax#4\relax}% \fi \fi \next} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@set} % "\pstree@set{}{}" sets each element of to . % \begin{macrocode} \def\pstree@set#1#2{% \pst@cntg=#1\relax \edef#2{\expandafter\pstree@@set#2\relax}} \def\pstree@@set#1,#2{% \the\pst@cntg,\ifx\relax#2\else\expandafter\pstree@@set\fi#2} % \end{macrocode} % \end{macro} % % % \section{Counters and boxes} % % \begin{macro}{\pstree@ID,\pstree@succID,\pstree@levelID} % "\pstree@ID" is used for identifying trees, for the purpose of syncronizing the distance between levels for all subtrees of the same tree. It is only used when the "levelsep" parameter value is preceded by "*", and the distance between levels must take into account the size of the objects. "\pstree@levelID" is the number of the level (0, 1, $\ldots$). "\pstree@succID" is the number of the successor (1, 2, $\ldots). "\pstree@nodeID" is the serial number of the node, used for node names. % \begin{macrocode} \newcount\pstree@ID \newcount\pstree@levelID \newcount\pstree@succID \newcount\pstree@nodeID % \end{macrocode} % \end{macro} % % \begin{macro}{\psTREE@sep,\psTREE@width} % These are used while constructing the row of successors. "\psTREE@sep" measures the distance between the previous and next successor. "\psTREE@width" measures is the distance between the center of the first and the center of the last successor. % \begin{macrocode} \newcount\psTREE@sep \newcount\psTREE@width % \end{macrocode} % \end{macro} % % \begin{macro}{\psTREE@height,\psTREE@depth,\pstree@height,\pstree@depth} % These were described on page \pageref{height}. % \begin{macrocode} \newcount\psTREE@height \newcount\psTREE@depth \newcount\pstree@cumlevelsep \newcount\pstree@numlevels % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@box} % Nodes and trees put themselves in "\pstree@box". A tree collects the root (which includes the root node's "\pstree@box", plus perhaps some "\special"'s lying outside this box) in "\pst@hbox". Then it saves the root in "\pstree@box", while it collects the successors in "\pst@hbox". The tree joins the root and the successors in "\pstree@box". % \begin{macrocode} \newbox\pstree@box % \end{macrocode} % \end{macro} % % \section{The tree macros} % % We begin with the main tree macros, which provide an outline of the algorithm. Much of this will be explained in detail when the component macros are defined. % \begin{macro}{\pstree} % We set up two ways of invoking trees. "\pstree" is ``short'', and ``\psTree'' is ``long''. % \begin{macrocode} \def\pstree{\pst@object{pstree}} \def\pstree@i#1#2{\psTree@i{#1}\\{#2}\endpsTree} % \end{macrocode} % \end{macro} % % \begin{macro}{\psTree,\endpsTree} % \begin{macrocode} \def\psTree{\pst@object{psTree}} \def\psTree@i{% \begingroup % \end{macrocode} % If we are in outer mode, then we set "shortput=tab" for abbreviated put commands used in trees. % Also, we have to change the tree identifier for the purpose of making nodes. Otherwise, we want to % kill off extraneous space by starting with "\pst@killglue" and ending with "\ignorespaces". % \begin{macrocode} \ifnum\psk@predmode=\m@ne \let\pstree@savedshortput\pst@shortput \psset{shortput=tab}% \else \pst@@killglue \fi % \end{macrocode} % "\psk@treeframe" is a hook that might contain commands for framing the tree. We save the value of the hook for later use, and then reset it globally. % \begin{macrocode} \let\pstree@thisframe\pstree@frame \global\let\pstree@frame\relax % \end{macrocode} % We save some variables that might be set globally, but whose values should be kept local to the tree, and a few other parameters that need to be restored if this is a subtree. % \begin{macrocode} \pstree@savevalues % \end{macrocode} % If we are in successor mode, then we need to skip levels before setting the graphics parameters. Levels are skipped at this point in the direction of the parent tree. % \begin{macrocode} \ifnum\psk@predmode=\m@ne \let\pstree@saveskiplevels\z@ \else \ifnum\psskiplevels>\z@\else \expandafter\pstree@checkskiplevels\pst@par,skiplevels=\z@,\@nil \fi \let\pstree@saveskiplevels\psskiplevels \ifnum\psskiplevels>\z@ \pstree@skipprofile \fi \fi % \end{macrocode} % Then we start a new group and set the graphics parameters. % \begin{macrocode} \use@par \let\pstree@saveadjustbbox\psk@adjustbbox \let\pstree@savetreerep\psk@treerep % \end{macrocode} % Initialize some things for aligning leaves. % \begin{macrocode} \if@leafaligntree \chardef\pstree@savemaxlevel\pstree@maxlevel \pstree@initleafalign \else \ifnum\psk@predmode=\psk@treemode\else \chardef\pstree@savemaxlevel\pstree@maxlevel \fi \fi % \end{macrocode} % If we are in outer mode, or if we are in tree mode and the tree has changed directions, then we need to change "\pstree@id", because for adjusting the level sep, we have to think of this as a new tree. Recall that in outer mode, "\psk@predmode" equals $-1$. % \begin{macrocode} \ifnum\psk@predmode=\psk@treemode \global\advance\pstree@ID\@ne \edef\pstree@id{\the\pstree@ID}% \fi % \end{macrocode} % We process the row, saving everything in "\pst@hbox": \def\\{\pstree@endrow\pst@object{pstreecr}}% \setbox\pstree@box\copy\voidb@x \let\pst@thisbox\relax \pst@makelongbox{}% \pstree@treemode \ignorespaces} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstreecr} % \begin{macrocode} \def\pstreecr@i{% \expandafter\pstree@checkskiplevels\pst@par,skiplevels=\z@,\@nil \ifnum\psskiplevels>\z@ \pstree@skiplevelseps \fi \pstree@initnestedpar \use@par \pstree@setlevelpar \edef\pspred{\pstree@gettop\pstree@basenodes}% \let\pst@thisbox\relax \pst@makelongbox{}% \pstree@treemode \ignorespaces} % \def\psPred#1{\psPred@i#10\@nil} \def\psPred@i#1#2\@nil{% \expandafter\ifcase\expandafter#1% \expandafter\psPred@ii\pstree@basenodes,,,,,,,,,\@nil} \def\psPred@ii#1,#2,#3,#4,#5,#6,#7,#8,#9,{% \or#1\or#2\or#3\or#4\or#5\or#6\or#7\or#8\or#9\fi\psPred@iii} \def\psPred@iii#1\@nil{} % \def\pstree@skiplevelseps{% \pst@cntg=\psskiplevels \loop \pstree@setlevelpar \advance\pstree@cumlevelsep\psk@thislevelsep\relax \edef\pstree@levelsizes{\pstree@levelsizes,\psk@thislevelsep,0,0}% \advance\pstree@numlevels\@ne \ifnum\pst@cntg>\@ne \advance\pst@cntg\m@ne \repeat} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@endrow} % The next three commands finish the construction of the tree by joining the root ("\pstree@box") and the successors ("\pst@hbox"). The tree is saved globally in "\pstree@box". % \begin{macrocode} \def\pstree@endrow{% \pst@@killglue \pst@endlongbox \pstree@checkrow % Check for missing objects or extra space. \ifvoid\pstree@box \pstree@InitTreeDim \else \pstree@joinrows % Join root and successors in a box. \pstree@joinprofiles % Adjust height, depth and profiles. \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\endpsTree} % \begin{macrocode} \def\endpsTree{% \pstree@endrow % \end{macrocode} % "\pstree@thisframe" may add a frame, and adjust the dimensions for the frame. % \begin{macrocode} \pstree@thisframe % \end{macrocode} % If this is not a proper subtree, and the "levelsep" is variable, then it is time to write the level sizes to a file. % \begin{macrocode} \ifPst@varlevelsep \ifnum\psk@predmode=\psk@treemode\else \pstree@writelevelsizes \fi \fi % \end{macrocode} % If this is a LeafAlign tree, we write "\pstree@maxlevel". Also, we restore the value of "\pstree@maxlevel", if appropriate. % \begin{macrocode} \if@leafaligntree \pstree@writemaxlevel \global\chardef\pstree@maxlevel\pstree@savemaxlevel \else \ifnum\psk@predmode=\psk@treemode\else \global\chardef\pstree@maxlevel\pstree@savemaxlevel \fi \fi % \end{macrocode} % Now we make the tree canonical, restore certain values for the predecessor tree, and add the tree to the current construction. % \begin{macrocode} \let\psk@adjustbbox\pstree@saveadjustbbox \let\psk@treerep\pstree@savetreerep \let\psskiplevels\pstree@saveskiplevels \pstree@makecanonical \pstree@restorevalues \pstree@build \ifnum\psk@treerep>\@ne\pstree@rep\fi \global\let\pssucc\pstree@savedsucc \endgroup \ifnum\psk@predmode>\m@ne\expandafter\ignorespaces\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@savevalues,\pstree@restorevalues} % Certain accounting values are set globally, and so we have to save and later restore their values (in case this is a nested tree). There are other values that are not set globally, but which have to be restored when adding this tree to the current row. % \begin{macrocode} \def\pstree@savevalues{% \edef\pstree@restorevalues{% \pst@ngdef\psTREE@leftprofile \pst@ngdef\psTREE@rightprofile \pst@ngdef\psTREE@levelsizes \pst@ngdef\psTREE@center \pst@ngdef\psTREE@leftbase \pst@ngdef\psTREE@rightbase \pst@ngdef\psTREE@centerbase \pst@ngdef\psTREE@rootnodes \pst@ngdef\psTREE@basenodes \pst@ngdef\psTREE@maxtreesep \pst@ngdef\psTREE@numlevels \pst@ngdef\psTREE@cumlevelsep \global\psTREE@height=\the\psTREE@height\relax \global\psTREE@depth=\the\psTREE@depth\relax \global\psTREE@width=\the\psTREE@width\relax \pst@ngdef\psTREE@addtreesep \pst@ngdef\psk@thistreesep \pst@ngdef\psk@thisxtreesep \pst@ngdef\psk@thistreenodesize \pst@ngdef\psk@thistreefit \global\pstree@succID=\the\pstree@succID\relax}} % \end{macrocode} % Now we use this to initialize these commands, just in case something goes wrong. % \begin{macro}{} {\def\pst@ngdef#1{\gdef\noexpand#1{}}\pstree@savevalues\pstree@restorevalues} % \end{macrocode} % \end{macro} % % % \section{Tree parameters} % % % \begin{macro}{\psset@treemode,\psk@treemode} % "treemode" refers to the direction that the tree grows. It is saved as an integer, with 0=down, 1=right, 2=up and 3=left. % \begin{macrocode} %%%??? Add error checking \define@key[psset]{pst-tvz}{treemode}[D]{% \chardef\psk@treemode \ifx#1U\@empty2\else\ifx#1R\@empty1\else\ifx#1L\@empty3\else\z@\fi\fi\fi \relax} \psset[pst-tvz]{treemode=D} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@treeflip,\ifpstreeflip} % "treeflip" determines the direction in which successors are added. When "false", successors are added from left to right for vertical trees, and from top to bottom for horizontal trees. When "true", the direction is switched. % \begin{macrocode} \define@boolkey[psset]{pst-tvz}[ps]{treeflip}[true]{} \psset[pst-tvz]{treeflip=false} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@root} % \begin{macrocode} \define@key[psset]{pst-tvz}{root}[\TC]{\def\psroot{#1}} \psset[pst-tvz]{root=\TC} % \end{macrocode} % \end{macro} % % \begin{macro}{\pst@dimtoint} %???? MOVE % \begin{macrocode} \def\pst@dimtoint#1#2{% should go into pstricks.tex \pssetlength\pst@dimg{#1}% \edef#2{\number\pst@dimg}} \def\pst@ngdef#1{\gdef\noexpand#1{#1}} % \end{macrocode} % \end{macro} % % \begin{macro} % {\psset@treesep,\psk@treesep,\psset@thistreesep,\psk@thistreesep} % "treesep" is the distance between nodes on the same level. There is a "this" version that does not affect subtrees. % \begin{macrocode} \define@key[psset]{pst-tvz}{treesep}[0.75cm]{\pst@dimtoint{#1}\psk@treesep} \psset[pst-tvz]{treesep=.75cm} % \define@key[psset]{pst-tvz}{thistreesep}{\pst@dimtoint{#1}\psk@thistreesep} % \end{macrocode} % \end{macro} % % \begin{macro} % {\psset@xtreesep,\psk@xtreesep,\psset@thisxtreesep,\psk@thisxtreesep} % "xtreesep" is the additional distance between nodes that do not have the same predecessor. There is a "this" version that does not affect subtrees. % \begin{macrocode} \define@key[psset]{pst-tvz}{xtreesep}[0.75cm]{\pst@dimtoint{#1}\psk@xtreesep} \psset[pst-tvz]{xtreesep=0pt} % \define@key[psset]{pst-tvz}{thisxtreesep}{\pst@dimtoint{#1}\psk@thisxtreesep} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@treenodesize,\psk@treenodesize, % \psset@thistreenodesize,\psk@thistreenodesize} % \begin{macrocode} \define@key[psset]{pst-tvz}{treenodesize}[-1pt]{% \pssetlength\pst@dimg{#1}% \divide\pst@dimg\tw@ \edef\psk@treenodesize{\number\pst@dimg}} \psset[pst-tvz]{treenodesize=-1pt} \define@key[psset]{pst-tvz}{thistreenodesize}[-1pt]{% \pssetlength\pst@dimg{#1}% \divide\pst@dimg\tw@ \edef\psk@thistreenodesize{\number\pst@dimg}} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@treefit,\psk@treefit} % \begin{macrocode} \define@key[psset]{pst-tvz}{treefit}[tight]{% \@ifundefined{pstree@#1fit}% {\@pstrickserr{Bad `treefit' parameter value: `#1'}\@ehpa}% {\def\psk@treefit{#1}}}% \psset[pst-tvz]{treefit=tight} % \define@key[psset]{pst-tvz}{thistreefit}[tight]{% \@ifundefined{pstree@#1fit}% {\@pstrickserr{Bad `treefit' parameter value: `#1'}\@ehpa}% {\def\psk@thistreefit{#1}}}% % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@treerep,\psk@treerep} % \begin{macrocode} \define@key[psset]{pst-tvz}{treerep}[1]{\chardef\psk@treerep#1\relax} \psset[pst-tvz]{treerep=1} \def\pstree@rep{% \ifnum\psk@treerep>\@ne \pst@cntg\psk@treerep \advance\pst@cntg\m@ne \chardef\psk@treerep\pst@cntg \pstree@build \expandafter\pstree@rep \fi} % \end{macro} % % \begin{macro}{\psk@adjustbbox} % The bounding box adjustment parameters define "\psk@adjustbbox" so that it changes "\pst@dima", etc. This is invoked must before nodes invoke "\psnode@makecanonical", or just after a tree is made into a canonical node. "\psk@adjustbbox". The values should not affect nested objects. % \begin{macrocode} \def\psk@adjustbbox{} \def\pstree@setadjustbbox#1#2{% \pssetlength\pst@dimg{#1}% \edef\psk@adjustbbox{\psk@adjustbbox#2\number\pst@dimg sp\relax}} \define@key[psset]{pst-tvz}{bbl}{\pstree@setadjustbbox{#1}{\pst@dima=}} \define@key[psset]{pst-tvz}{bbr}{\pstree@setadjustbbox{#1}{\pst@dimb=}} \define@key[psset]{pst-tvz}{bbh}{\pstree@setadjustbbox{#1}{\pst@dimc=}} \define@key[psset]{pst-tvz}{bbd}{\pstree@setadjustbbox{#1}{\pst@dimd=}} \define@key[psset]{pst-tvz}{xbbl}{\pstree@setadjustbbox{#1}{\advance\pst@dima}} \define@key[psset]{pst-tvz}{xbbr}{\pstree@setadjustbbox{#1}{\advance\pst@dimb}} \define@key[psset]{pst-tvz}{xbbh}{\pstree@setadjustbbox{#1}{\advance\pst@dimc}} \define@key[psset]{pst-tvz}{xbbd}{\pstree@setadjustbbox{#1}{\advance\pst@dimd}} % \end{macrocode} % \end{macro} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@showbbox,\psk@showbbox} % \begin{macrocode} \define@boolkey[psset]{pst-tvz}[Pst@]{showbbox}[true]{} \psset[pst-tvz]{showbbox=false} \def\pstree@showbbox{% \setbox\pstree@box=\hbox{% \psset{linewidth=.1pt,linecolor=black,linestyle=solid,% dimen=middle,fillstyle=none}% \def\pst@par{}\@starfalse \psframe@i(-\pst@dima,-\pst@dimd)(\pst@dimb,\pst@dimc)% \box\pstree@box}}% % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@levelsep,\psk@levelsep} % \begin{macrocode} \define@key[psset]{pst-tvz}{levelsep}[2cm]{\pst@dimtoint{#1}\psk@levelsep} \psset[pst-tvz]{levelsep=2cm} \define@key[psset]{pst-tvz}{thislevelsep}{\pst@dimtoint{#1}\psk@thislevelsep} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@varlevelsep,\ifPst@varlevelsep} % \begin{macrocode} \define@boolkey[psset]{pst-tvz}[Pst@]{varlevelsep}[true]{% \ifnum\psk@predmode=\psk@treemode \@pstrickserr{varlevelsep cannot be changed for proper subtrees}\@ehpa \fi} \let\psk@predmode\m@ne \let\if@predflip\iffalse %\fi \psset[pst-tvz]{varlevelsep=false} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@treeshift,\psk@treeshift} % \begin{macrocode} \define@key[psset]{pst-tvz}{treeshift}[0]{% \pssetlength\pst@dimg{#1}% \pst@dimg-\pst@dimg \edef\psk@treeshift{\number\pst@dimg}} \psset[pst-tvz]{treeshift=0} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@skiplevels,\psskiplevels} % \begin{macrocode} \define@key[psset]{pst-tvz}{skiplevels}[0]{\chardef\psskiplevels#1\relax} \psset[pst-tvz]{skiplevels=0} % \end{macrocode} % \end{macro} % % \begin{macro}{\def\pstree@initnestedpar} % This initialized the values of parameters that should not affect nested objects. % \begin{macrocode} \def\pstree@initnestedpar{% \def\psk@adjustbbox{}% \let\psk@treeshift\z@ \chardef\psskiplevels\z@ \chardef\psk@treerep\@ne \def\psk@thislevelsep{\psk@levelsep}% \def\psk@thistreesep{\psk@treesep}% \def\psk@thisxtreesep{\psk@xtreesep}% \def\psk@thistreenodesize{\psk@treenodesize}% \def\psk@thistreefit{\psk@treefit}% \def\psk@thisunary{\psk@unary}% \let\if@leafaligntree\iffalse} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@setlevelpar} % \begin{macrocode} \def\pstree@setlevelpar{% \advance\pstree@levelID\@ne \csname pstreehook\romannumeral\pstree@levelID\endcsname \ifPst@varlevelsep \ifnum\psk@predmode=\psk@treemode\else \pstree@initadjustlevelsep \fi \pstree@adjustlevelsep \fi \edef\pst@tposflip{\ifnum\psk@treemode>\@ne 1 sub neg \fi}}% % \end{macrocode} % \end{macro} % % % \section{Outer mode} % % \begin{macro}{\pstree@build@outer,\psnode@makecanonical@outer} % The canonical outer object is a node. % \begin{macrocode} \def\pstree@build@outer{% \leavevmode \hbox{% \vrule height \pst@dimc depth \pst@dimd width \z@ \kern\pst@dima \ifnum\psk@treerep>\@ne\copy\else\box\fi\pstree@box \kern\pst@dimb}} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@makecanonical@outer} % "\pstree@makecanonical@outer" converts trees to nodes. What the left and right profiles correspond to depends on whether the tree is horizontal or vertical, and on whether the tree is flipped. What the tree height and depth correspond to depends on the "treemode". % % When a tree is in mode, it may adjust its bounding box. % \begin{macrocode} \def\pstree@makecanonical@outer{% \pstree@gettreebbox \ifx\pstree@center\@empty \pst@dimg\pstree@width sp \divide\pst@dimg\tw@ \else \pst@dimg\pstree@center sp \fi \ifnum\pst@dimg=\z@\else \advance\pst@dima\pst@dimg \advance\pst@dimb-\pst@dimg \ifodd\psk@treemode \setbox\pstree@box\hbox{% \ifpstreeflip\lower\else\raise\fi\pst@dimg\box\pstree@box}% \else \setbox\pstree@box\hbox{% \kern\ifpstreeflip\else-\fi\pst@dimg\unhbox\pstree@box}% \fi \fi \wd\pstree@box=\z@ \dp\pstree@box=\z@ \ht\pstree@box=\z@} \def\pstree@gettreebbox{% \pstree@max\pstree@leftprofile\pst@cnta \pstree@max\pstree@rightprofile\pst@cntb \advance\pst@cntb\pstree@width \ifodd\psk@treemode \ifpstreeflip \pst@dimc\pst@cntb sp \pst@dimd\pst@cnta sp \else \pst@dimc\pst@cnta sp \pst@dimd\pst@cntb sp \fi \else \ifpstreeflip \pst@dima\pst@cntb sp \pst@dimb\pst@cnta sp \else \pst@dima\pst@cnta sp \pst@dimb\pst@cntb sp \fi \fi \ifcase\psk@treemode \pst@dimc\pstree@height sp \pst@dimd\pstree@depth sp \or \pst@dima\pstree@height sp \pst@dimb\pstree@depth sp \or \pst@dimc\pstree@depth sp \pst@dimd\pstree@height sp \or \pst@dima\pstree@depth sp \pst@dimb\pstree@height sp \fi \psk@adjustbbox \ifPst@showbbox \pstree@showbbox \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@outermode} % "\pstree@outermode" sets up some values that should be in effect for outer trees. A tree is "outer" is it is not nested inside any tree, or if it is inside any box other than a tree row (e.g., in a "\TR" node, or a label command). This means that "\pstree@outer" must be exected once below (for trees that are not nested inside any tree), and then "\pst@thisbox" is set to "\pstree@outer" inside a tree row. % % "\pst@tposflip" is a hook in the "tput" commands defined in "pst-node.tex" that flips the value of the positioning argument for trees, so that the number always refers to the distance from the predecessor node to successor node. This is initialized within trees, but in outer mode we want to disable the hook. % % "\pst@shortput" is also given a special meaning in trees, and we have to restore its value when entering outer mode. % % "\psk@bboxadust" stores the bounding box adjust parameters. We do not want these parameters to affect nested objects. % % Since "\pst@thisbox" may be set to "\pstree@outermode", the latter must reset "\pst@thisbox". % % Setting "\psk@predmode" to "\m@ne" is a useful flag for outer mode. % \begin{macrocode} \newif\ifpstree@outer \def\pstree@outermode{% \pstree@outertrue \let\pstree@makecanonical\pstree@makecanonical@outer \let\psnode@makecanonical\relax \let\pstree@build\pstree@build@outer \let\psk@predmode\m@ne \pstree@levelID=\z@ \chardef\pstree@maxlevel\z@ \let\pstree@themaxlevel\relax \def\pstree@id{outer}% \def\pst@tposflip{}% \let\pst@shortput\pstree@savedshortput \pstree@initnestedpar \let\pst@thisbox\relax} \let\pstree@savedshortput\pst@shortput \pstree@outermode % \end{macrocode} % \end{macro} % % \section{Constructing a row a successors} % % This described the process for the canonical tree row object. % % \begin{macro}{\pstree@succmode} % \begin{macrocode} \def\pstree@treemode{% \let\pstree@makecanonical\pstree@makecanonical@succ \let\psnode@makecanonical\psnode@makecanonical@succ \let\pstree@build\pstree@build@succ \pstree@initnestedpar \global\pstree@succID=\@ne \gdef\psTREE@addtreesep{\z@}% \global\let\pstree@center\@empty \global\let\psTREE@centerbase\@empty \let\psk@predmode\psk@treemode \let\if@predflip\ifpstreeflip \let\pst@thisbox\pstree@outermode} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@build@succ} % First we actually skip the levels, if necessary. % \begin{macrocode} \def\pstree@build@succ{% \ifnum\psskiplevels>\z@ \pstree@skiplevels \fi % \end{macrocode} % If "\pstree@succID=1", indicating that this is the first successor, the successor row dimensions are simply initialized. % \begin{macrocode} \ifnum\pstree@succID=\@ne \ifnum\psk@treerep>\@ne\copy\else\box\fi\pstree@box \pstree@initrowdim % \end{macrocode} % Otherwise, "\pstree@fit" sets "\psTREE@sep" to the distance between the centers of the previous and current successors, sets "\psTREE@width" to the total distance from the center of the first to the last successor, and updates the profiles. Then we position the current succcessor. % \begin{macrocode} \else \pstree@fit \ifodd\psk@predmode \if@predflip\raise\else\lower\fi\psTREE@width sp \else \kern\if@predflip-\fi\psTREE@sep sp \fi \ifnum\psk@treerep>\@ne\copy\else\box\fi\pstree@box \pstree@UpdateRowDim \fi \ifodd\psk@predmode\else \pst@dimg=\pstree@width sp \kern\if@predflip-\fi\pst@dimg \fi % \end{macrocode} % Now we update the row dimensions. % \begin{macrocode} \global\advance\pstree@succID\@ne} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@initrowdim} % The first successor's dimensions become the row's dimensions. % \begin{macrocode} \def\pstree@initrowdim{% \global\let\psTREE@leftprofile\pstree@leftprofile \global\let\psTREE@rightprofile\pstree@rightprofile \global\let\psTREE@levelsizes\pstree@levelsizes \global\psTREE@height\pstree@height\relax \global\psTREE@depth\pstree@depth\relax \global\psTREE@width\pstree@width\relax \global\let\psTREE@maxtreesep\pstree@maxtreesep \global\let\psTREE@center\pstree@center \xdef\psTREE@numlevels{\the\pstree@numlevels}% \xdef\psTREE@cumlevelsep{\the\pstree@cumlevelsep}% \global\let\psTREE@leftbase\pstree@leftbase \global\let\psTREE@rightbase\pstree@rightbase \global\let\psTREE@centerbase\pstree@centerbase \global\let\psTREE@rootnodes\pstree@rootnodes \global\let\psTREE@basenodes\pstree@basenodes} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@fit} % First we calculate the distance between successors: % \begin{macrocode} \def\pstree@fit{% %% I seem to have deleted the following lines for some reason at one point: \ifnum\psk@thistreenodesize<\z@ \let\pst@tempa\psTREE@rightprofile \let\pst@tempb\pstree@leftprofile \else \edef\pst@tempa{\pstree@puttop\psk@thistreenodesize\psTREE@rightprofile}% \edef\pst@tempb{\pstree@puttop\psk@thistreenodesize\pstree@leftprofile}% \fi \csname pstree@\psk@thistreefit fit\endcsname\pst@tempa\pst@tempb\psTREE@sep %% \csname pstree@\psk@thistreefit fit\endcsname %% \psTREE@rightprofile\pstree@leftprofile\psTREE@sep % \end{macrocode} % Then we add the "treesep", the width of the new object, and any extra space inserted by "\addtreesep". % \begin{macrocode} \advance\psTREE@sep\psk@thistreesep\relax \ifnum\psTREE@maxtreesep<\psTREE@sep \xdef\psTREE@maxtreesep{\the\psTREE@sep}% \fi \advance\psTREE@sep\psTREE@addtreesep\relax \gdef\psTREE@addtreesep{\z@}% \global\advance\psTREE@width\psTREE@sep} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@UpdateRowDim} % Now we update the row's dimensions. % \begin{macrocode} \def\pstree@UpdateRowDim{% \ifnum\psTREE@maxtreesep<\pstree@maxtreesep\relax \let\psTREE@maxtreesep\pstree@maxtreesep \fi %\advance\psTREE@sep\psTREE@width %% TVZ Deleted 96-Oct-18. \pstree@zip\psTREE@sep \psTREE@rightprofile\pstree@rightprofile\psTREE@rightprofile \pstree@zip\psTREE@width \pstree@leftprofile\psTREE@leftprofile\psTREE@leftprofile \global\advance\psTREE@width\pstree@width \pstree@bimax\psTREE@levelsizes\pstree@levelsizes \ifnum\pstree@height>\psTREE@height \global\psTREE@height\pstree@height\relax \fi \ifnum\pstree@depth>\psTREE@depth \global\psTREE@depth\pstree@depth\relax \fi \ifx\pstree@center\@empty\else \pst@cntg=\psTREE@width \advance\pst@cntg\pstree@center \xdef\psTREE@center{\the\pst@cntg}% \fi \xdef\psTREE@rootnodes{\psTREE@rootnodes\pstree@rootnodes}% \ifnum\pstree@numlevels<\psTREE@numlevels\else \global\let\psTREE@rightbase\pstree@rightbase \ifx\pstree@centerbase\@empty\else \pst@cntg=\pstree@centerbase\relax \advance\pst@cntg\psTREE@width \xdef\psTREE@centerbase{\the\pst@cntg}% \fi \ifnum\pstree@numlevels>\psTREE@numlevels\relax \global\let\psTREE@basenodes\pstree@basenodes \xdef\psTREE@numlevels{\the\pstree@numlevels}% \xdef\psTREE@cumlevelsep{\the\pstree@cumlevelsep}% \pst@cntg=\pstree@leftbase\relax \advance\pst@cntg-\psTREE@width \xdef\psTREE@leftbase{\the\pst@cntg}% \else \xdef\psTREE@basenodes{\psTREE@basenodes\pstree@basenodes}% \fi \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\treecenter} % "\treecenter" just remembers the current width of the row of successors. % \begin{macrocode} \def\treecenter{\xdef\psTREE@center{\the\psTREE@width}} % \end{macrocode} % \end{macro} % % \begin{macro}{\addtreesep} % \begin{macrocode} \def\addtreesep#1{% \pssetlength\pst@dimg{#1}% \xdef\psTREE@addtreesep{\number\pst@dimg}% \ignorespaces} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@checkrow} % "\pstree@checkrow" checks that the row has at least one successor, and that the row doesn't have extraneous space. % \begin{macrocode} \def\pstree@checkrow{% \ifnum\pstree@succID=\@ne \pst@makelongbox \pstree@treemode \psroot{\box\pst@hbox}% \ifnum\pstree@succID=\@ne\Tn\fi \pst@endlongbox \fi \ifnum\wd\pst@hbox=% \ifodd\psk@treemode\z@\else\ifpstreeflip-\fi\psTREE@width\fi \else \@pstrickserr{Extraneous space in tree row (Level \the\pstree@levelID)}\@ehpa \fi \wd\pst@hbox=\z@ \ht\pst@hbox=\z@ \dp\pst@hbox=\z@} % \end{macrocode} % \end{macro} % % % \section{Making canonical successors} % % "\psk@treemode" and "\ifpstreeflip" are the successor tree's "treemode" and "treeflip", and "\psk@predmode" and "\if@predflip" are the successor tree's "treemode" and "treeflip". % % \begin{macro}{\psnode@makecanonical@succ} % Terminal nodes are made into single-level trees. Because \TeX\ is pretty fast at processing conditionals, this should not take so long. Good thing, because terminal nodes are pretty common! % \begin{macrocode} \def\psnode@makecanonical@succ{% \edef\pstree@height{% \number \ifcase\psk@predmode\pst@dimc\or\pst@dima\or\pst@dimd\or\pst@dimb\fi}% \edef\pstree@depth{% \number \ifcase\psk@predmode\pst@dimd\or\pst@dimb\or\pst@dimc\or\pst@dima\fi}% \edef\pstree@leftprofile{% \number \ifodd\psk@predmode \if@predflip\pst@dimd\else\pst@dimc\fi \else \if@predflip\pst@dimb\else\pst@dima\fi \fi,}% \edef\pstree@rightprofile{% \number \ifodd\psk@predmode \if@predflip\pst@dimc\else\pst@dimd\fi \else \if@predflip\pst@dima\else\pst@dimb\fi \fi,}% %\edef\pstree@levelsizes{\pstree@height,\pstree@depth,}% Moved below. \pstree@numlevels\@ne \pstree@cumlevelsep\z@ \chardef\pstree@width\z@ \let\pstree@center\@empty \def\pstree@leftbase{\z@}% \def\pstree@rightbase{\z@}% \let\pstree@centerbase\@empty \edef\pstree@rootnodes{\pssucc,}% \let\pstree@basenodes\pstree@rootnodes \def\pstree@maxtreesep{\z@}% %%%% FIX ME?? (also, xtreesep inserted between multiple skiplevel-nodes.) \ifnum\psskiplevels>\z@ \let\pstree@saveskiplevels\psskiplevels \pstree@skipprofile %\pstree@cumlevelsep\pstree@skiplevelsep\relax %%% Caused extra skipping. \pst@cntg=\pstree@depth \advance\pst@cntg\pstree@skiplevelsep\relax \edef\pstree@depth{\the\pst@cntg}% \ifnum\pstree@height>\pstree@cumlevelsep \pst@cntg=\pstree@height\relax \advance\pst@cntg-\pstree@cumlevelsep \edef\pstree@height{\the\pst@cntg}% \else \def\pstree@height{0}% \fi \let\psskiplevels\pstree@saveskiplevels \fi \edef\pstree@levelsizes{\pstree@height,\pstree@depth,}% Used to be above \ifPst@leafalign\pstree@alignleaf\fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@makecanonical@succ} % \begin{macrocode} % The canonical successor is a subtree with the same orientation as the tree within which it is nested. Flipped trees of the same type are also easy. % \begin{macrocode} \def\pstree@makecanonical@succ{% \ifnum\psk@treemode=\psk@predmode \pstree@@makecanonical@succ % \end{macrocode} % Subtrees of a different type are first converted to canonical outer objects (and in the process, the bounding box may be adjusted), and then they are converted to canonical successor objects as if they were nodes. This is not the most efficient, but such rotated subtrees are not so common. A direct conversion would be faster, but would still involve extensive macros. % \begin{macrocode} \else \pstree@makecanonical@outer \def\pssucc,{\pstree@rootnodes}% \psnode@makecanonical@succ \fi} % \end{macrocode} % "\psk@treemode" and "\ifpstreeflip" are for the subtree. "\psk@predmode" and "\ifps@predflip" are for the predecessor tree. % \begin{macrocode} \def\pstree@@makecanonical@succ{% \ifx\psk@adjustbbox\@empty\else \@pstrickserr{You cannot adjust a proper subtree's bounding box}\@ehpa \let\psk@adjustbbox\relax \fi \ifx\ifpstreeflip\if@predflip\else \pstree@@@makecanonical@succ \fi \ifPst@showbbox \pstree@gettreebbox \fi} \def\pstree@@@makecanonical@succ{% \let\pst@tempg\pstree@leftprofile \let\pstree@leftprofile\pstree@rightprofile \let\pstree@rightprofile\pst@tempg \let\pst@tempg\pstree@leftbase \let\pstree@leftbase\pstree@rightbase \let\pstree@rightbase\pst@tempg \ifnum\pstree@width=\z@\else \pst@dimg=\pstree@width sp \multiply\pst@dimg\m@ne \ifodd\psk@treemode \setbox\pstree@box=\hbox{\raise\pst@dimg\box\pstree@box}% \else \setbox\pstree@box=\hbox to \pst@dimg{% \kern\pst@dimg\unhbox\pstree@box\hss}% \fi \fi \ifx\pstree@center\@empty\else \pst@cntg\pstree@width \advance\pst@cntg-\pstree@center\relax \edef\pstree@center{\the\pst@cntg}% \fi} % \end{macrocode} % \end{macro} % % % \section{Joining rows} % % \begin{macro}{\pstree@InitTreeDim} % The first successor's dimensions become the row's dimensions. % \begin{macrocode} \def\pstree@InitTreeDim{% \setbox\pstree@box\box\pst@hbox \let\pstree@leftprofile\psTREE@leftprofile \let\pstree@rightprofile\psTREE@rightprofile \let\pstree@levelsizes\psTREE@levelsizes \edef\pstree@height{\the\psTREE@height}% \edef\pstree@depth{\the\psTREE@depth}% \edef\pstree@width{\the\psTREE@width}% \let\pstree@maxtreesep\psTREE@maxtreesep \let\pstree@center\psTREE@center \pstree@numlevels\psTREE@numlevels\relax \pstree@cumlevelsep\psTREE@cumlevelsep\relax \let\pstree@leftbase\psTREE@leftbase \let\pstree@rightbase\psTREE@rightbase \let\pstree@centerbase\psTREE@centerbase \let\pstree@rootnodes\psTREE@rootnodes \let\pstree@basenodes\psTREE@basenodes} % \end{macrocode} % \end{macro} % % After a row has been processed, the left profiles are with respect to the center of the leftmost toplevel node, the right profiles are with respect to the center of the rightmost toplevel node, and "\psTREE@width" is the distance between the centers of the two extreme toplevel nodes. The row box's current point is the center of the leftmost toplevel node. That is, it is a tree! The previous rows have also been joined into a tree. Here is how we join two trees together, one on top of the other. % % Fist, we calculate the distance between the current point of the previous rows and the current point of the next row. We are matching the center of the base of the top row with the center of the root of the bottom row. % % % \begin{macro}{\pstree@setsucccenter} % \begin{macrocode} % "\pstree@setsucccenter" shifts the row's current point to the row's true center (either the midpoint between the two extreme successors or distance "\pstree@center" from the leftmost successor, adjusted by "treeshift"), and then adjust the profiles so that they are with respect to this center. % % First, find the distance from the left successor to the center, for the top of the bottom row. % \begin{macrocode} \def\pstree@joinrows{% \ifnum\pstree@succID=\tw@ \csname pstree@unarycenter@\psk@thisunary\endcsname \else \ifx\psTREE@center\@empty \pst@cnta\psTREE@width \divide\pst@cnta\tw@ \else \pst@cnta\psTREE@center\relax \fi \fi \advance\pst@cnta\psk@treeshift\relax % \end{macrocode} % Now do the same for bottom of the top row: % \begin{macrocode} \ifx\pstree@centerbase\@empty \psTREE@sep\pstree@leftbase \multiply\psTREE@sep\m@ne \advance\psTREE@sep\pstree@rightbase \advance\psTREE@sep\pstree@width \divide\psTREE@sep\tw@ \else \psTREE@sep\pstree@centerbase\relax \fi % \end{macrocode} % Now find the distance between the current points, after alignment: % \begin{macrocode} \advance\psTREE@sep-\pst@cnta % \end{macrocode} % Join the rows: % \begin{macrocode} \advance\pstree@cumlevelsep\psk@thislevelsep\relax \ifodd\psk@treemode \setbox\pstree@box=\hbox{% \box\pstree@box \kern\ifnum\psk@treemode=\thr@@-\fi\pstree@cumlevelsep sp \ifpstreeflip\raise\else\lower\fi\psTREE@sep sp\box\pst@hbox}% \else \setbox\pstree@box=\hbox{% \box\pstree@box \kern\ifpstreeflip-\fi\psTREE@sep sp \ifnum\psk@treemode=\z@\lower\else\raise\fi\pstree@cumlevelsep sp \box\pst@hbox}% \fi \wd\pstree@box=\z@ \ht\pstree@box=\z@ \dp\pstree@box=\z@} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@joinprofiles} % Adjust the profiles. % \begin{macrocode} \def\pstree@joinprofiles{% \ifnum\psskiplevels>\z@ \pstree@skiprowprofiles \fi \pst@cnta=-\psTREE@sep \pstree@add\pst@cnta\psTREE@leftprofile \advance\pst@cnta\psTREE@leftbase \edef\pstree@leftbase{\the\pst@cnta}% \edef\pstree@leftprofile{\pstree@leftprofile\psTREE@leftprofile}% \ifx\psTREE@centerbase\@empty\else \pst@cnta=\psTREE@sep \advance\pst@cnta\psTREE@centerbase \edef\pstree@centerbase{\the\pst@cnta}% \else \let\pstree@centerbase\@empty \fi \advance\psTREE@width-\pstree@width \advance\psTREE@width\psTREE@sep \pstree@add\psTREE@width\psTREE@rightprofile \edef\pstree@rightprofile{\pstree@rightprofile\psTREE@rightprofile}% \advance\psTREE@width\psTREE@rightbase \edef\pstree@rightbase{\the\psTREE@width}% \edef\pstree@levelsizes{% \pstree@levelsizes\psk@thislevelsep,\psTREE@levelsizes}% % \end{macrocode} % Then we calculate the resulting height and depth of the tree. % \begin{macrocode} \advance\psTREE@height-\pstree@cumlevelsep \ifnum\pstree@height<\psTREE@height \edef\pstree@height{\the\psTREE@height}% \fi \advance\psTREE@depth\pstree@cumlevelsep \ifnum\pstree@depth<\psTREE@depth \edef\pstree@depth{\the\psTREE@depth}% \fi \advance\pstree@numlevels\psTREE@numlevels\relax \let\pstree@basenodes\psTREE@basenodes} \def\pstree@skiprowprofiles{% \pst@cntc-\psTREE@sep \pst@cntd\pstree@leftbase\relax \advance\pst@cntc-\pst@cntd \pst@cnta\psTREE@width \advance\pst@cnta\psTREE@sep \advance\pst@cnta-\pstree@width \pst@cntb=\pstree@rightbase \advance\pst@cnta-\pst@cntb \pst@cntg\psskiplevels \advance\pst@cntg\@ne \divide\pst@cntc\pst@cntg \divide\pst@cnta\pst@cntg \loop \advance\pst@cntd\pst@cntc \advance\pst@cntb\pst@cnta \edef\pstree@leftprofile{\pstree@leftprofile\the\pst@cntd,}% \edef\pstree@rightprofile{\pstree@rightprofile\the\pst@cntb,}% \ifnum\pst@cntg>\tw@ \advance\pst@cntg\m@ne \repeat} % \end{macrocode} % \end{macro} % % % \section{Binary trees} % % \begin{macro}{\pstree@unarycenter@left,\pstree@unarycenter@right} % \begin{macrocode} \def\pstree@unarycenter@middle{\pst@cnta=\z@} \def\pstree@unarycenter@left{% \pst@cnta\psk@thistreesep\relax \divide\pst@cnta\tw@ \advance\pst@cnta \ifnum\psk@thistreenodesize<\z@ \pstree@gettop\psTREE@rightprofile \else \psk@thistreenodesize \fi \relax}% \def\pstree@unarycenter@right{% \pst@cnta\psk@thistreesep\relax \divide\pst@cnta\tw@ \advance\pst@cnta \ifnum\psk@thistreenodesize<\z@ \pstree@gettop\psTREE@leftprofile \else \psk@thistreenodesize \fi \multiply\pst@cnta\m@ne}% \def\pstree@unarycenter@leftternary{% \pst@cnta=% \ifnum\psk@thistreenodesize<\z@ \pstree@gettop\psTREE@rightprofile \else \psk@thistreenodesize \fi \multiply\pst@cnta\tw@ \advance\pst@cnta\psk@thistreesep\relax}% \def\pstree@unarycenter@rightternary{% \pst@cnta=% \ifnum\psk@thistreenodesize<\z@ \pstree@gettop\psTREE@leftprofile \else \psk@thistreenodesize \fi \multiply\pst@cnta\tw@ \advance\pst@cnta\psk@thistreesep \multiply\pst@cnta\m@ne}% % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@unary,\psk@unary} % \begin{macrocode} \define@key[psset]{pst-tvz}{unary}[middle]{% \@ifundefined{pstree@unarycenter@#1}% {\@pstrickserr{Bad unary parameter: `#1'}\@ehpa}% {\def\psk@unary{#1}}} \psset[pst-tvz]{unary=middle} \define@key[psset]{pst-tvz}{thisunary}[middle]{% \@ifundefined{pstree@unarycenter@#1}% {\@pstrickserr{Bad unary parameter: `#1'}\@ehpa}% {\def\psk@thisunary{#1}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\psltree,\psrtree} % \begin{macrocode} \newpsobject{psltree}{pstree}{thisunary=left} \newpsobject{psrtree}{pstree}{thisunary=right} % \end{macrocode} % \end{macro} % % \section{Skip levels} % % \begin{macro}{\pstree@checkskiplevels} % \begin{macrocode} \def\pstree@checkskiplevels#1skiplevels=#2,#3\@nil{% \chardef\psskiplevels#2\relax} % \end{macrocode} % \end{macro} % % % \begin{macro}{\pstree@skipprofile} % \begin{macrocode} \def\pstree@skipprofile{% \ifnum\psk@predmode=\m@ne \@pstrickserr{You can only skip levels in the successors of a tree}\@ehpa \else \pst@cnta=\psskiplevels \pst@cntb=\z@ \def\pstree@skiplevelsizes{}% \def\pstree@skiplevelprofiles{}% \pstree@@skipprofile \edef\pstree@skiplevelsep{\the\pst@cntb}% \fi} \def\pstree@@skipprofile{% \advance\pstree@levelID\@ne \csname pstreehook\romannumeral\pstree@levelID\endcsname \ifPst@varlevelsep \pstree@adjustlevelsep \fi \edef\pstree@skiplevelsizes{\pstree@skiplevelsizes\psk@thislevelsep,0,0}% \edef\pstree@skiplevelprofiles{0,\pstree@skiplevelprofiles}% \advance\pst@cntb\psk@thislevelsep\relax \pstree@initnestedpar \advance\pst@cnta\m@ne \ifnum\pst@cnta>\z@ \expandafter\pstree@@skipprofile \fi} % \end{macrocode} % \end{macro} % % \begin{macrocode} \def\pstree@skiplevels{% \ifx\pstree@center\@empty \pst@cnta\pstree@width \divide\pst@cnta\tw@ \else \pst@cnta\pstree@center\relax \fi \advance\pstree@cumlevelsep\pstree@skiplevelsep\relax \ifodd\psk@treemode \setbox\pstree@box=\hbox{% \kern\ifnum\psk@treemode=\thr@@-\fi\pstree@skiplevelsep sp \ifpstreeflip\lower\else\raise\fi\pst@cnta sp\box\pstree@box}% \else \setbox\pstree@box=\hbox{% \kern\ifpstreeflip-\fi\pst@cnta sp \ifnum\psk@treemode=\z@\lower\else\raise\fi\pstree@skiplevelsep sp \box\pstree@box}% \fi \wd\pstree@box=\z@ \ht\pstree@box=\z@ \dp\pstree@box=\z@ % Left profiles \ifnum\pst@cnta=\z@\else\pstree@add\pst@cnta\pstree@leftprofile\fi \pst@cntb\pstree@leftbase \advance\pst@cntb\pst@cnta \edef\pstree@leftbase{\the\pst@cntb}% \edef\pstree@leftprofile{\pstree@skiplevelprofiles\pstree@leftprofile}% \ifx\pstree@centerbase\@empty\else \pst@cntb\pstree@centerbase \advance\pst@cntb-\pst@cnta \edef\pstree@centerbase{\the\pst@cntb}% \fi \pst@cntb\pstree@width \advance\pst@cntb-\pst@cnta \ifnum\pst@cntb=\z@\else\pstree@add\pst@cntb\pstree@rightprofile\fi \edef\pstree@rightprofile{\pstree@skiplevelprofiles\pstree@rightprofile}% \advance\pst@cntb\pstree@rightbase \edef\pstree@rightbase{\the\pst@cntb}% \edef\pstree@levelsizes{\pstree@skiplevelsizes\pstree@levelsizes}% \ifnum\pstree@height>\pstree@skiplevelsep\relax \pst@cntb\pstree@skiplevelsep\relax \multiply\pst@cntb\m@ne \advance\pst@cntb\pstree@height \edef\pstree@height{\the\pst@cntb}% \else \def\pstree@height{\z@}% \fi \advance\pstree@numlevels\psskiplevels \def\pstree@width{0}% \def\pstree@center{}} % % \section{Variable level sep} % % \begin{macro}{\pstree@initauxout} % \begin{macrocode} \def\pstree@initauxout{% \@ifundefined{@latexerr}{% \immediate\openin1 \jobname.pst \ifeof1 \else {\catcode`\@=11 \input \jobname.pst}% \fi \immediate\closein1 \global\csname newwrite\endcsname\pstree@auxout \immediate\openout\pstree@auxout \jobname.pst }% {\global\let\pstree@auxout\@auxout}% \global\let\pstree@initauxout\relax} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@writelevelsizes} % \begin{macrocode} \def\pstree@writelevelsizes{% \ifx\if@filesw\iffalse\else \pstree@getlevelsizes \immediate\write\pstree@auxout{% \string\global\string\@namedef{pstree@levelsizes@\pstree@id}% {\pst@tempg}}% \fi} \def\pstree@getlevelsizes{% \def\pst@tempg{}% \expandafter\pstree@@getlevelsizes\psTREE@levelsizes\relax} \def\pstree@@getlevelsizes#1,#2,#3,#4,#5,#6{% \pst@cntg=#2\relax \advance\pst@cntg#4\relax \edef\pst@tempg{\pst@tempg\the\pst@cntg,}% \ifx\relax#6\else \def\next{\pstree@@getlevelsizes,#5,#6}% \expandafter\next \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@initadjustlevelsep} % \begin{macrocode} \def\pstree@initadjustlevelsep{% \pstree@initauxout \expandafter\let\expandafter\pstree@thelevelsizes \csname pstree@levelsizes@\pstree@id\endcsname \ifx\pstree@thelevelsizes\relax \def\pstree@thelevelsizes{0,}% \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@adjustlevelsep} % \begin{macrocode} \def\pstree@adjustlevelsep{% \pstree@poptop\pstree@thelevelsizes\pst@cntg \advance\pst@cntg\psk@thislevelsep\relax \edef\psk@thislevelsep{\the\pst@cntg}} % \end{macrocode} % \end{macro} % % % \section{Leaf alignment} % % \begin{macro}{\psset@leafalign,\ifPst@leafalign} % Call a tree whose terminal nodes should be aligned at the bottom of the tree a ``LeafAlign'' tree. % % In a LeafAlign tree, terminal nodes should align themselves by skipping levels, whenever "leafalign" is "true". The LeafAlign tree sets "\pstree@themaxlevel" to the number of the lowest level in the tree. When "leafalign" is "true", terminal nodes in the LeafAlign tree skip enough levels so that they end up at level "\pstree@themaxlevel". % % Setting "leafalign=true" has two effects. First, subsequent nodes take care of skipping levels. Second, top level tree or trees in the scope of the parameter setting become LeafAlign trees. "\psset@leafalign" sets "\if@leafaligntree" to "\iftrue", and this is reset to "\iffalse" by "\pstree@initnestedpar". % \begin{macrocode} \newif\ifPst@leafalign \define@key[psset]{pst-tvz}{leafalign}[true]{% \@nameuse{leafalign#1}% \let\if@leafaligntree\ifPst@leafalign}% \psset[pst-tvz]{leafalign=false} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@alignleaf} % This is invoked by "\psnode@makecanonical@succ" (i.e., by terminal nodes), when "leafalign" is true. % % We keep track of the number of the lowest level in a tree with "\pstree@maxlevel". This is set with "\chardef". % % The the terminal node skips as many levels as are needed. % \begin{macrocode} \def\pstree@alignleaf{% \ifnum\pstree@maxlevel<\pstree@levelID \global\chardef\pstree@maxlevel\pstree@levelID \fi \ifx\pstree@themaxlevel\relax\else \ifnum\psskiplevels>\z@\else \ifnum\pstree@themaxlevel>\pstree@levelID \pst@cntg=\pstree@themaxlevel \advance\pst@cntg-\pstree@levelID \chardef\psskiplevels\pst@cntg \pstree@saveskiplevels\psskiplevels \pstree@skipprofile \let\psskiplevels\pstree@saveskiplevels \fi \fi \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@writemaxlevel} % When a LeafAlign tree finishes processing its successors, it writes "\pstree@maxlevel" to a file. % \begin{macrocode} % \begin{macrocode} \def\pstree@writemaxlevel{% \ifx\if@filesw\iffalse\else \immediate\write\pstree@auxout{% \string\global\string\@namedef{pstree@maxlevel@% \pstree@id-\the\pstree@levelID-\the\pstree@succID}% {\the\pstree@maxlevel}}% \fi} % \end{macrocode} % % \begin{macro}{\pstree@writemaxlevel} % \begin{macrocode} % Before processing its successors, a LeafAlign tree looks for the value of "\pstree@maxlevel" that it might have written to the file, and assigns the value to "\pstree@themaxlevel": \def\pstree@initleafalign{% \pstree@initauxout \expandafter\let\expandafter\pstree@themaxlevel \csname pstree@maxlevel@% \pstree@id-\the\pstree@levelID-\the\pstree@succID \endcsname % \end{macrocode} % If "\pstree@themaxlevel" is equal to "\relax", then terminal nodes know that they should not try to align themselves. % % Then tree A needs to initialize "\pstree@maxlevel". % \begin{macrocode} \global\chardef\pstree@maxlevel\pstree@levelID} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstree@savemaxlevel} % "\pstree@maxlevel" is set globally. A LeafAlign tree should not pay attention to levels in a subtrees that (i) change directions, (ii) are root trees, or (iii) are LeafAlign trees. Such trees save the value of "\pstree@maxlevel" as "\pstree@savemaxlevel", and then restore the value globally at the end. Here, we just initialize it: % \begin{macrocode} \let\pstree@savemaxlevel\z@ % \end{macrocode} % \end{macro} % % % \section{Tree frames} % \let\pstree@frame\relax % \begin{macro}{\pstreeframe} % This one is not working. For one thing, "\pstree@getbbox" is not defined. % \begin{macrocode} \def\pstreeframe{\pst@object{pstreeframe}} \def\pstreeframe@i{% \let\pstree@theframe\pstreeframe@ii \let\pstree@theframepar\pst@par \let\pstree@theframestar\if@star} \def\pstreeframe@ii{% \pstree@getbbox \pst@dimg\pslinewidth \advance\pst@dimg\psframesep \advance\pst@dima\pst@dimg \advance\pst@dimb\pst@dimg \advance\pst@dimc\pst@dimg \advance\pst@dimd\pst@dimg \setbox\pstree@box=\hbox{% \let\pst@par\pstree@theframepar \let\if@star\pstree@theframestar \pst@useboxpar \ifpsboxsep\aftergroup\pstreeframe@iii\fi \def\psk@dimen{.5 }% \psframe@i(-\pst@dima,-\pst@dimd)(\pst@dimb,\pst@dimc)% \box\pstree@box}% \aftergroup\pstree@relaxtheframe}% \def\pstreeframe@iii{% \ifodd\psk@treemode \pst@cntg=\pst@dimc \pstree@set\pstree@upprofile \pst@cntg=\pst@dimd \pstree@set\pstree@downprofile \else \pstree@add\pst@dima\pstree@leftprofile \pstree@add\pst@dimb\pstree@rightprofile \fi} \def\pstree@relaxtheframe{\let\pstree@theframe\relax} \let\pstree@theframe\relax % \end{macrocode} % \end{macro} % % % \begin{macro}{\pstree@firstandlast} % "\pstree@firstandlast{}{}{}" assigns the first and last values in to and , respectively. % \begin{macrocode} \def\pstree@firstandlast#1#2#3{% \expandafter\pstree@@firstandlast\expandafter#2#1\relax,% #3=\pst@cntg} \def\pstree@@firstandlast#1#2,{% \pst@cntg=#2\relax #1=\pst@cntg \pstree@@@firstandlast} \def\pstree@@@firstandlast#1,{% \ifx\relax#1\else \pst@cntg=#1\relax \expandafter\pstree@@@firstandlast \fi} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstreecurve} % This so far does nothing useful. % \begin{macrocode} \def\pstreecurve{\pst@object{pstreecurve}} \def\pstreecurve@i{% \let\pstree@frame\pstreecurve@ii \let\pstree@theframepar\pst@par \let\pstree@theframestar\if@star} \def\pstreecurve@ii{% \setbox\pstree@box=\hbox{% \let\pst@par\pstree@theframepar \let\if@star\pstree@theframestar \pst@useboxpar \ifpsboxsep\aftergroup\pstreecurve@iv\fi \pstreecurve@iii \box\pstree@box}% \aftergroup\pstree@relaxtheframe}% \def\pstreecurve@iii{% \begin@ClosedObj \pst@dimg\pslinewidth \divide\pst@dimg2 \advance\pst@dimg\psframesep \ifodd\psk@treemode\pstreecurve@hcoor\else\pstreecurve@vcoor\fi \addto@pscode{[ \pst@coors}% \psccurve@ii} \def\pstreecurve@iv{% \pst@cnta=\pslinewidth \advance\pst@cnta\psframesep \ifodd\psk@treemode \pstree@add\pst@cnta\pstree@upprofile \pstree@add\pst@cnta\pstree@downprofile \else \pstree@add\pst@cnta\pstree@leftprofile \pstree@add\pst@cnta\pstree@rightprofile \fi} \def\pstreecurve@hcoor{% \advance\pst@dima\pst@dimg \advance\pst@dimb\pst@dimg \ifnum\psk@treemode=\@ne \pstree@firstandlast\pstree@upprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@upprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@number\pst@dima neg \pst@number\pst@dimh}% \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@coors \pst@number\pst@dimb \pst@number\pst@dimh}% \ifnum\psk@treemode=\@ne \pstree@firstandlast\pstree@downprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@downprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{% \pst@coor \pst@number\pst@dimb \pst@number\pst@dimh neg }% \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{% \pst@coors \pst@number\pst@dima neg \pst@number\pst@dimh neg }}% \def\pstreecurve@vcoor{% \advance\pst@dimc\pst@dimg \advance\pst@dimd\pst@dimg \ifnum\psk@treemode=\z@ \pstree@firstandlast\pstree@leftprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@leftprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@number\pst@dimh neg \pst@number\pst@dimc}% \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{% \pst@coors \pst@number\pst@dimh neg \pst@number\pst@dimd neg }% \ifnum\psk@treemode=\z@ \pstree@firstandlast\pstree@rightprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@rightprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@coors \pst@number\pst@dimh \pst@number\pst@dimd neg }% \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@coors \pst@number\pst@dimh \pst@number\pst@dimc}} % \end{macrocode} % \end{macro} % % \begin{macro}{\pstreepyramid} % This seems to do nothing. % \begin{macrocode} \def\pstreepyramid{\pst@object{pstreepyramid}} \def\pstreepyramid@i{% \let\pstree@frame\pstreepyramid@ii \let\pstree@theframepar\pst@par \let\pstree@theframestar\if@star} \def\pstreepyramid@ii{% \setbox\pstree@box=\hbox{% \let\pst@par\pstree@theframepar \let\if@star\pstree@theframestar \pst@useboxpar %\ifpsboxsep\aftergroup\pstreepyramid@iv\fi \pstreepyramid@iv \pstreepyramid@iii \box\pstree@box}% \aftergroup\pstree@relaxtheframe}% \def\pstreepyramid@iii{% \begin@ClosedObj \pst@dimg\pslinewidth \advance\pst@dimg\psframesep \ifodd\psk@treemode\pstreepyramid@hcoor\else\pstreepyramid@vcoor\fi \addto@pscode{[ \pst@tempg \pst@temph }% \pspolygon@ii} \def\pstreepyramid@iv{% \pst@cnta=\pslinewidth \advance\pst@cnta\psframesep \ifodd\psk@treemode \pstree@add\pst@cnta\pstree@upprofile \pstree@add\pst@cnta\pstree@downprofile \else \pstree@add\pst@cnta\pstree@leftprofile \pstree@add\pst@cnta\pstree@rightprofile \fi} \def\pstreepyramid@hcoor{% \def\pst@tempg{}% \def\pst@temph{}% \pst@dima=\z@ \pst@dimg=\pst@cntg sp \edef\next{% \pstree@levelsizes\relax \pstree@upprofile\relax \pstree@downprofile\relax}% \expandafter\pstreepyramid@@hcoor\next} \def\pstreepyramid@@hcoor#1,#2,#3,#4\relax#5,#6\relax#7,#8\relax{% \pst@dimc=#5sp \pst@dimd=#7sp \pst@dimd=-\pst@dimd \pst@dimb=#1sp \advance\pst@dimb\pst@dimg \pst@dimb=-\pst@dimb \advance\pst@dimb\pst@dima \edef\pst@tempg{\pst@tempg \pst@number\pst@dimb \pst@number\pst@dimc}% \edef\pst@temph{\pst@number\pst@dimb \pst@number\pst@dimd \pst@temph}% \pst@dimb=#2sp \advance\pst@dimb\pst@dimg \advance\pst@dimb\pst@dima \edef\pst@tempg{\pst@tempg \pst@number\pst@dimb \pst@number\pst@dimc}% \edef\pst@temph{\pst@number\pst@dimb \pst@number\pst@dimd \pst@temph}% \ifx\relax#1% \let\next\relax \else \pst@dimb=#3sp \advance\pst@dima\ifnum\psk@treemode=\@ne\else-\fi\pst@dimb \def\next{\pstreepyramid@@hcoor#4\relax#6\relax#8\relax}% \fi \next} \def\pstreepyramid@vcoor{% \advance\pst@dimc\pst@dimg \advance\pst@dimd\pst@dimg \ifnum\psk@treemode=\z@ \pstree@firstandlast\pstree@leftprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@leftprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@number\pst@dimh neg \pst@number\pst@dimc}% \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{% \pst@coors \pst@number\pst@dimh neg \pst@number\pst@dimd neg }% \ifnum\psk@treemode=\z@ \pstree@firstandlast\pstree@rightprofile\pst@cnta\pst@cntb \else \pstree@firstandlast\pstree@rightprofile\pst@cntb\pst@cnta \fi \pst@dimh=\pst@cntb sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@coors \pst@number\pst@dimh \pst@number\pst@dimd neg }% \pst@dimh=\pst@cnta sp \advance\pst@dimh\pst@dimg \edef\pst@coors{\pst@coors \pst@number\pst@dimh \pst@number\pst@dimc}} % \end{macrocode} % \end{macro} % % % \section{Edges and node names\label{edges}} % % The following applies to nodes that have a successor: % % There are two edge macros. "\psedge" is invoked following each node, except when there is a skipped level between the node and its predecessor, in which case "\skipedge" is invoked. "\psedge" and "\skipedge" can be set by the "edge" and "skipedge" parameters. Setting these parameters for a node should affect the edge drawn to that node, but other parameter changes to a node should not affect the way the edge is drawn. % To reconcile these two goals, after setting its graphics parameters, a node lets "\pstree@edge" be "\psedge" (or If levels are skipped, it lets "\pstree@skipedge" be "\psedge" and lets "\pstree@edge" be "\skipedge"). Then the node closes the group and invokes "\pstree@edge". % % \begin{macro}{\psset@edge,\psedge} % \begin{macrocode} \define@key[psset]{pst-tvz}{edge}[\ncline]{\def\psedge{#1}}% \psset[pst-tvz]{edge=\ncline} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@skipedge,\skipedge} % \begin{macrocode} \define@key[psset]{pst-tvz}{skipedge}[{}]{% \def\skipedge{#1}% \ifx\skipedge\@empty \def\skipedge{\psedge}% \else \ifx\skipedge\@none \def\skipedge##1##2{}% \fi \fi} \psset[pst-tvz]{skipedge={}} % \end{macrocode} % \end{macro} % % Each node sets "\pssucc" to "@T:\pstree@id:\the\pstree@levelID". This does not give every node a unique name, but a nodes name will never be overwritten until it is not needed. % % \begin{macro}{\pspred} % Here, we only initialize "\pspred", in case it is used inadvertently. % \begin{macrocode} \def\pspred{@T} % \end{macrocode} % \end{macro} % % % \section{Tree Nodes} % % For each of the PSTricks node commands, there should be a variant for trees that: % \begin{enumerate} % \item \label{bbt} % Invokes "\pst@@killglue". % % \item % Perhaps makes "\pst@hbox" and/or collect arguments. (Note: If a node is a tree's root or successor, then "\pst@thisbox" has been set to "\pstree@outermode" by the tree.) % % \item % Begins a group, and use graphics parameters. % % \item % Globally advance "\pstree@succID" by 1. % % \item \label{ebt} % Globally set "\pssucc" to "@T:\pstree@id:\the\pstree@levelID". % % \item \label{dn1} % Creates a zero-dimensional box, containing the node with name "\pssucc", and with the origin of the box located at the center of the node. (The center is the point the edges point to.) % % \item \label{dn2} % Sets "\pst@dima", etc., as described on page \pageref{nodesizes}. % % \item \label{bet} % Adjusts and/or shows the bounding box: % \begin{LVerbatim} % \psk@adjustbbox % \ifPst@showbbox\pstree@showbbox\fi % \end{LVerbatim} % % \item % Invokes "\psnode@makecanonical" and "\pstree@build". % % \item Saves the edge, closes the group, and invokes the edge (see Section \ref{edges}). % % \item \label{eet} % Invokes "\pst@shortput" (unless there is no predecessor, in which case it invokes "\ignorespaces"). % \end{itemize} % % % \begin{macro}{\begin@treenode,\end@treenode} % "\begin@treenode" takes care of steps \ref{bbt}--\ref{ebt}. "\end@treenode" takes care of steps \ref{bet}--\ref{eet}. A tree node typically invokes "\begin@treenode", takes care of steps \ref{dn1} and \ref{dn2}, and then invokes "\end@treenode". If the tree makes "\pst@hbox", then it must first invoke "\pst@@killglue". % \begin{macrocode} \def\begin@treenode{% \pst@@killglue \begingroup \use@par \xdef\pssucc{@T:\pstree@id:\the\pstree@levelID:\the\pstree@succID}} % \def\end@@treenode{% \psk@adjustbbox \ifPst@showbbox\pstree@showbbox\fi \psnode@makecanonical \pstree@build \ifnum\psskiplevels>\z@ \global\let\pstree@skipedge\psedge \global\let\pstree@edge\skipedge \else \global\let\pstree@edge\psedge \fi \endgroup \let\pst@tempa\ignorespaces \ifnum\pstree@levelID>\z@ \ifx\pstree@edge\@none\else \let\pst@tempa\pst@shortput \expandafter\pstree@makeedge\pstree@basenodes\relax\@empty \fi \fi \pst@tempa} % \def\pstree@makeedge#1,#2#3\@empty{% {\pstree@edge{#1}{\pssucc}}% \ifx#2\relax\else\let\pst@tempa\ignorespaces\expandafter\pstree@makeedge\fi #2#3\@empty} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tn} % "\Tn" is the exception. Because it is just a place holder, it sets "\pssucc" to "\pspred", and does not make an edge. % \begin{macrocode} \def\Tn{\pst@object{Tn}} \def\Tn@i{% \pst@@killglue \global\let\pssucc\pspred \begingroup \pst@dima=\z@ \pst@dimb=\z@ \pst@dimc=\z@ \pst@dimd=\z@ \setbox\pstree@box=\hbox{}% \psnode@makecanonical \pstree@build \endgroup \ignorespaces} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tp} % \begin{macrocode} \def\Tp{\pst@object{Tp}} \def\Tp@i{% \begin@treenode \pst@dima=\z@ \pst@dimb=\z@ \pst@dimc=\z@ \pst@dimd=\z@ \setbox\pstree@box=\hbox{% \pst@newnode{\pssucc}{10}{0 0 }{\tx@InitPnode}}% \end@treenode} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tc,\TC} % \begin{macrocode} \def\Tc{\pst@object{Tc}} \def\Tc@i#1{% \begin@treenode \pssetlength\pst@dima{#1}% \pst@dimb=\pst@dima \pst@dimc=\pst@dima \pst@dimd=\pst@dima \Pst@nodealignfalse \setbox\pstree@box=\hbox{\cnode@ii(\z@,\z@){#1}{\pssucc}}% \end@treenode} \def\TC{\pst@object{TC}} \def\TC@i{\Tc@i{\psk@radius}} % \end{macrocode} % \end{macro} % % \begin{macro}{\Toval} % \begin{macrocode} \def\Toval{\pst@object{Toval}} \def\Toval@i{\pst@@killglue\pst@makebox{\Toval@ii\ovalnode@ii}} \def\Toval@ii#1{% \begin@treenode \Pst@nodealigntrue \setbox\pstree@box=\hbox{#1\pssucc}% \pst@dima=\wd\pstree@box \divide\pst@dima\tw@ \pst@dimb=\pst@dima \pst@dimc=\ht\pstree@box \pst@dimd=\dp\pstree@box \setbox\pstree@box=\hbox to\z@{\hss\unhbox\pstree@box\hss}% \dp\pstree@box=\z@ \ht\pstree@box=\z@ \end@treenode} % \end{macrocode} % \end{macro} % % % \begin{macro}{\Tcircle,\TCircle} % \begin{macrocode} \def\Tcircle{\pst@object{Tcircle}} \def\Tcircle@i{\pst@@killglue\pst@makebox{\Toval@ii\circlenode@ii}} \def\TCircle{\pst@object{TCircle}} \def\TCircle@i{\pst@@killglue\pst@makebox{\Toval@ii\Circlenode@ii}} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tf} % \begin{macrocode} \def\Tf{\pst@object{Tf}} \def\Tf@i{\Toval@ii{\fnode@ii()}} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tdia} % \begin{macrocode} \def\Tdia{\pst@object{Tdia}} \def\Tdia@i{\pst@@killglue\pst@makebox{\Toval@ii\dianode@ii}} % \end{macrocode} % \end{macro} % % \begin{macro}{\Ttri} % \begin{macrocode} \def\Ttri{\pst@object{Ttri}} \def\Ttri@i{\pst@@killglue\pst@makebox{\Ttri@ii}} \def\Ttri@ii{% \begin@treenode \Pst@nodealigntrue \setbox\pstree@box=\hbox{\trinode@ii\pssucc}% \pst@dima=\pst@dimg % Set by \pst@triboxsep \pst@dimb=\wd\pstree@box \advance\pst@dimb-\pst@dima \pst@dimc=\ht\pstree@box \pst@dimd=\dp\pstree@box \setbox\pstree@box=\hbox to\z@{\hss\unhbox\pstree@box\hss}% \dp\pstree@box=\z@ \ht\pstree@box=\z@ \end@treenode} % \end{macrocode} % \end{macro} % % \end{macrocode} % \end{macro} % % % \begin{macro}{\Tr} % \begin{macrocode} \def\Tr{\pst@object{Tr}} \def\Tr@i{\pst@@killglue\pst@makebox{\Tr@ii{\rnode@iii\rnode@iv}}} \def\Tr@ii#1{% \begin@treenode \def\pstree@nodehook{% \xdef\pstree@next{\pst@dima=\number\pst@dima sp\relax}}% \Pst@nodealigntrue \setbox\pstree@box\hbox{#1\pssucc}% \pstree@next \pst@dimb=\wd\pstree@box \advance\pst@dimb-\pst@dima \pst@dimc=\ht\pstree@box \pst@dimd=\dp\pstree@box \setbox\pstree@box\hbox to\z@{\kern-\pst@dima\unhbox\pstree@box\hss}% \ht\pstree@box=\z@ \dp\pstree@box=\z@ \end@treenode} % \end{macrocode} % \end{macro} % % \begin{macro}{\TR} % \begin{macrocode} \def\TR{\pst@object{TR}} \def\TR@i{\pst@@killglue\pst@makebox{\Tr@ii{\rnode@iii\Rnode@ii}}} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tdot} % \begin{macrocode} \def\Tdot{\pst@object{Tdot}} \def\Tdot@i{% \begin@treenode \def\pstree@nodehook{\xdef\pstree@next{% \pst@dima=\number\pst@dimg sp\relax \pst@dimc=\number\pst@dimh sp\relax}}% \Pst@nodealignfalse \setbox\pstree@box=\hbox{\dotnode@ii(\z@,\z@)\pssucc}% \pstree@next \pst@dimb=\pst@dima \pst@dimd=\pst@dimc \end@treenode} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@fansize,\psk@fansize} % \begin{macrocode} \define@key[psset]{pst-tvz}{fansize}[1cm]{\pst@@getlength{#1}\psk@fansize} \psset[pst-tvz]{fansize=1cm} % \end{macrocode} % \end{macro} % % DEFINITION OF Tfan IS IN psn-beta.doc. % % \begin{macro}{\tx@Tfan} % \begin{macrocode} % \end{macrocode} % \end{macro} % % \begin{macro}{\Tfan} % \begin{macrocode} \def\Tfan{\pst@object{Tfan}} \def\Tfan@i{% \addto@par{edge=none,skipedge=none}% \begin@treenode \solid@star % For now, let \pst@dimb and \pst@dimd base and thickness of fan. \pst@dimb=\psk@fansize \pst@dimd=\pslinewidth \advance\pst@dimb-\pst@dimd \divide\pst@dimb 2 \divide\pst@dimd 2 % Set \pst@dima and \pst@dimc to leftsize and height of node \ifodd\psk@treemode \pst@dima=\pst@dimd \pst@dimc=\pst@dimb \else \pst@dima=\pst@dimb \pst@dimc=\pst@dimd \fi \setbox\pstree@box=\hbox{% \pst@newnode{\pssucc}{16}{}{% /Y 0 def /X 0 def /l \pst@number\pst@dima def /r l def /u \pst@number\pst@dimc def /d u def /NodePos { \tx@GetRnodePos } def}% \def\pst@linetype{1}% \nc@object{Closed}{\pspred}{\pssucc}{.5}{% tx@Dict begin \psline@iii pop end /w \pst@number\pst@dimb CLW 2 div sub def /m \ifodd\psk@treemode false \else true \fi def \tx@Tfan}}% \pst@dimb=\pst@dima \pst@dimd=\pst@dimc \end@treenode} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@tnsep,\psk@tnsep} % \begin{macrocode} \define@key[psset]{pst-tvz}{tnsep}[{}]{% \def\pst@tempg{#1}% \ifx\pst@tempg\@empty \def\psk@tnsep{\number\pslabelsep sp}% \else \pst@@getlength{#1}\psk@tnsep \fi} \psset[pst-tvz]{tnsep={}} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@tnyref,\psk@tnyref} % \begin{macrocode} \define@key[psset]{pst-tvz}{tnyref}[{}]{\def\psk@tnyref{#1}}% \psset[pst-tvz]{tnyref={}} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@tnheight,\psk@tnheight} % \begin{macrocode} \define@key[psset]{pst-tvz}{tnheight}[\ht\strutbox]{\def\psk@tnheight{#1}} \psset[pst-tvz]{tnheight=\ht\strutbox} \define@key[psset]{pst-tvz}{tndepth}[\dp\strutbox]{\def\psk@tndepth{#1}} \psset[pst-tvz]{tndepth=\dp\strutbox} % \end{macrocode} % \end{macro} % % \begin{macro}{\psset@tnpos,\psk@tnpos} % \begin{macrocode} \define@key[psset]{pst-tvz}{tnpos}[{}]{% \def\pst@tempg{#1}% \ifx\pst@tempg\@empty \def\psk@tnpos{% \ifcase\psk@treemode b\or r\or a\or l\fi}% \else \@ifundefined{pstree@tnput@#1}% {\@pstrickserr{Bad tnpos: `#1'}\@ehpa}% {\def\psk@tnpos{#1}}% \fi} \psset[pst-tvz]{tnpos={}} % \end{macrocode} % \end{macro} % \def\MakeShortTnput#1{% \def\end@treenode{\@ifnextchar#1{\tnput@}{\end@@treenode}}} \MakeShortTnput{~} % \begin{macro}{\tnput@} % \begin{macrocode} \def\tnput@#1{\pst@object{tnput}} \def\tnput@i{\pst@@killglue\pst@makebox{\tnput@ii}} \def\tnput@ii{% \begingroup \use@par \if@star\pst@starbox\fi \gdef\next{}% \csname pstree@tnput@\psk@tnpos\endcsname \endgroup \next \setbox\pstree@box=\box\pst@boxg \dp\pstree@box=\z@ \ht\pstree@box=\z@ \wd\pstree@box=\z@ \end@treenode} \@namedef{pstree@tnput@b}{% \pstree@tnput@@v\pst@dimd\ht\dp\lower\psk@tnheight} \@namedef{pstree@tnput@a}{% \pstree@tnput@@v\pst@dimc\dp\ht\raise\psk@tndepth} \def\pstree@tnput@@v#1#2#3#4#5{% \pst@dimh=\wd\pst@hbox \pst@dimg=\psk@href\pst@dimh \advance\pst@dimg\pst@dimh \divide\pst@dimg 2 \advance\pst@dimh-\pst@dimg \ifdim\pst@dimg>\pst@dima \xdef\next{\next\pst@dima=\number\pst@dimg sp\relax}% \fi \ifdim\pst@dimh>\pst@dimb \xdef\next{\next\pst@dimb=\number\pst@dimh sp\relax}% \fi \pst@dimh=\psk@tnsep\relax \ifdim\pst@dimh<\z@ \pst@dimh=-\pst@dimh \else \advance\pst@dimh#1% \fi \pssetlength\dimen@{#5}% \ifdim\dimen@>#2\pst@hbox \advance\pst@dimh\dimen@\relax \else \advance\pst@dimh#2\pst@hbox \fi \global\setbox\pst@boxg=\hbox{% \box\pstree@box #4\pst@dimh\hbox to\z@{\kern-\pst@dimg\unhbox\pst@hbox\hss}}% \xdef\next{\next#1=\number#3\pst@boxg sp\relax}} \@namedef{pstree@tnput@l}{% \pstree@tnput@@h\pst@dima{% \hss \lower\pst@dimg\box\pst@hbox \kern\pst@dimh \box\pstree@box}} \@namedef{pstree@tnput@r}{% \pstree@tnput@@h\pst@dimb{% \box\pstree@box \kern\pst@dimh \lower\pst@dimg\box\pst@hbox \hss}}% \def\pstree@tnput@@h#1#2{% \ifx\psk@tnyref\@empty \pssetlength\pst@dimg\psk@vref \else \pst@dimg=\ht\pst@hbox \advance\pst@dimg\dp\pst@hbox \pst@dimg=\psk@tnyref\pst@dimg \advance\pst@dimg-\dp\pst@hbox \fi \pst@dimh=\psk@tnsep\relax \ifdim\pst@dimh<\z@ \multiply\pst@dimh\m@ne \else \advance\pst@dimh#1% \fi \xdef\next{% \next#1=\number\pst@dimh sp\relax \advance#1\number\wd\pst@hbox sp\relax}% \global\setbox\pst@boxg=\hbox to\z@{#2}% \ifdim\ht\pst@boxg>\pst@dimc \xdef\next{\next\pst@dimc=\number\ht\pstree@box sp\relax}% \fi \ifdim\dp\pst@boxg>\pst@dimd \xdef\next{\next\pst@dimd=\number\dp\pstree@box sp\relax}% \fi} % \end{macrocode} % \end{macro} % % \catcode`\@=\TheAtCode\relax \endinput %% END pstree.tex