% \MakeShortVerb{\"} % \DeleteShortVerb{\|} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \input{use} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \chapter{Implementation} % \label{sec:implementation} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Introductory code} % \label{sec:implementationIntroduction} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Identification} % \label{sec:impIdentification} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{uml} % \end{macrocode} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Processing of options} % \label{sec:impOptions} % \begin{macro}{debug} % The option "debug" is used if you want some extra lines shown. % Intended for debugging of this package. % \begin{macrocode} \DeclareOption{debug}{ \def\umlDebugLineStyle{dashed} \def\umlDebugLength{1pt} } \DeclareOption{nodebug}{ \def\umlDebugLineStyle{none} \def\umlDebugLength{0pt} } % \end{macrocode} % \end{macro} % \noindent{}Default is the "nodebug" option. % \begin{macrocode} \ExecuteOptions{nodebug} \ProcessOptions % \end{macrocode} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Using other packages} % \label{sec:impUsing} % \packageName{uml.sty} relies heavily on the \LaTeX packages % \packageName{pstricks} and \packageName{pst-node} [PSTricks]. % Most of the graphics is displayed using \packageName{pstricks}. % \begin{macrocode} \RequirePackage{pstricks, pst-node} % \end{macrocode} %\noindent\packageName{keyval} [Keyval] is the package which handles % named options (like \verb§[name=Name, reference=Ref]§). % \begin{macrocode} \RequirePackage{keyval} % \end{macrocode} % \noindent\packageName{relsize} [Relsize] handles relative sizes, with % macros like "\Larger" and "\relsize{-1}". % \begin{macrocode} \RequirePackage{relsize} % \end{macrocode} % \noindent{}We also need the \packageName{color} package. Maybe I later on should make % uml.sty possible to use indepedent of color (with an option). % \begin{macrocode} \RequirePackage{color} % \end{macrocode} % \section{Scratch section} % Something not having another location a the moment. % I want the line numbers and the macro names to be right-aligned % together, close to the text. It is important to make a virtual % vertical line in order to make some order in the pages. % However, "doc.sty" contains a spurious space (in "\m@cro@", where % "\PrintMacroName" and where "\PrintEnvName" are used). This space % shows up after the macro name. To overcome this, I make a length % "\minusSpace" of length one negative space in the right font, and make % a "\hspace" of this length. % % This code shouldn't be placed here, but the location works, and it % is good to show what is done. % \begin{macrocode} \setlength\MacroIndent{0pt} \newlength\minusSpace \settowidth\minusSpace{\rmfamily\scriptsize \ } \setlength\minusSpace{-\minusSpace} \def\PrintMacroName#1{\strut \MacroFont \string #1\hspace*\minusSpace} \def\PrintDescribeMacro#1{\strut \MacroFont \string #1} \def\PrintDescribeEnv#1{\strut \MacroFont #1} \def\PrintEnvName#1{\strut \MacroFont #1} % \end{macrocode} % \subsection{foo} % \begin{macro}{\umlDebugLinestyle} % A linestyle normally none. The linestyle of invisible leading lines. % \begin{macrocode} \def\umlDebugLinestyle{none} % \end{macrocode} % \end{macro} % \begin{macro}{\umlDebugLength} % A length normally 0pt. E.g., the breadth of invisible lines. % \begin{macrocode} \def\umlDebugLength{0pt} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{General syntax} % \label{sec:impSyntax} % Users used to \LaTeX{} and PStricks will recognize a lot of syntax. % An important implementation point is that any contents (which can % affect variables) is typeset after all the variables is used. If not, % the different boxes inside each other get intertwined with strange % results. \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Lengths} % \label{sec:impSyntaxLengths} % \begin{macrocode} \psset{xunit=1em} \psset{yunit=1em} \psset{runit=1em} % \end{macrocode} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Coordinates} % \label{sec:impSyntaxCoordinates} % \begin{macrocode} \SpecialCoor \newlength{\umlNodeSep} \setlength{\umlNodeSep}{1em} % \end{macrocode} % A historical note here: First, "\umlBox" used to throw lots of pnodes % around. However, this used huge memory space. This way works much % better. However, I have not found any way to do the corresponding % thing in the relations. % \begin{macro}{\umlRight} % The first coordinate commands are very simple. % They takes as argument node. % \begin{macrocode} \newcommand\umlRight[1]{% [angle=0]#1} \newcommand\umlTop[1]{% [angle=90]#1} \newcommand\umlLeft[1]{% [angle=180]#1} \newcommand\umlBottom[1]{% [angle=270]#1} \newcommand\umlTopRight[1]{% [angle=0]#1|[angle=90]#1} \newcommand\umlBottomRight[1]{% [angle=0]#1|[angle=270]#1} \newcommand\umlTopLeft[1]{% [angle=180]#1|[angle=90]#1} \newcommand\umlBottomLeft[1]{% [angle=180]#1|[angle=270]#1} % \end{macrocode} % \end{macro} % \begin{macro}{\umlRightSep} % The "Sep" coordinate commands use "\umlNodeSep" to make % some space between the nodes. % \begin{macrocode} \newcommand\umlRightSep[1]{% [angle=0, nodesep=\umlNodeSep]#1} \newcommand\umlTopSep[1]{% [angle=90, nodesep=\umlNodeSep]#1} \newcommand\umlLeftSep[1]{% [angle=180, nodesep=\umlNodeSep]#1} \newcommand\umlBottomSep[1]{% [angle=270, nodesep=\umlNodeSep]#1} \newcommand\umlTopRightSep[1]{% [angle=0, nodesep=\umlNodeSep]#1|[angle=90, nodesep=\umlNodeSep]#1} \newcommand\umlBottomRightSep[1]{% [angle=0, nodesep=\umlNodeSep]#1|[angle=270, nodesep=\umlNodeSep]#1} \newcommand\umlTopLeftSep[1]{% [angle=180, nodesep=\umlNodeSep]#1|[angle=90, nodesep=\umlNodeSep]#1} \newcommand\umlBottomLeftSep[1]{% [angle=180, nodesep=\umlNodeSep]#1|[angle=270, nodesep=\umlNodeSep]#1} % \end{macrocode} % \end{macro} % \begin{macro}{\umlRightOpt} % This takes two mandatory arguments: Named options and the usual % node. % % Of course, it would be nice to mke the first argument optional, thus % \english{slåing sammen} "\umlRight" and "\umlRightOpt". However, % this does not work together with mandatory argument in "\umlBox". I % have found no elegant solution to this (despite some nights\dots) % \begin{macrocode} \newcommand\umlRightOpt[2]{% [angle=0, #1]#2} \newcommand\umlTopOpt[2]{% [angle=90, #1]#2} \newcommand\umlLeftOpt[2]{% [angle=180, #1]#2} \newcommand\umlBottomOpt[2]{% [angle=270, #1]#2} \newcommand\umlTopRightOpt[2]{% [angle=0, #1]#2|[angle=90, #1]#2} \newcommand\umlBottomRightOpt[2]{% [angle=0, #1]#2|[angle=270, #1]#2} \newcommand\umlTopLeftOpt[2]{% [angle=180, #1]#2|[angle=90, #1]#2} \newcommand\umlBottomLeftOpt[2]{% [angle=180, #1]#2|[angle=270, #1]#2} % \end{macrocode} % \end{macro} % \begin{macro}{\umlRightSep} % \begin{macrocode} \newcommand\umlRightSepOpt[2]{% [angle=0, nodesep=\umlNodeSep, #1]#2} \newcommand\umlTopSepOpt[2]{% [angle=90, nodesep=\umlNodeSep, #1]#2} \newcommand\umlLeftSepOpt[2]{% [angle=180, nodesep=\umlNodeSep, #1]#2} \newcommand\umlBottomSepOpt[2]{% [angle=270, nodesep=\umlNodeSep, #1]#2} \newcommand\umlTopRightSepOpt[2]{% [angle=0, nodesep=\umlNodeSep, #1]#2|[angle=90, nodesep=\umlNodeSep, #1]#2} \newcommand\umlBottomRightSepOpt[2]{% [angle=0, nodesep=\umlNodeSep, #1]#2|[angle=270, nodesep=\umlNodeSep, #1]#2} \newcommand\umlTopLeftSepOpt[2]{% [angle=180, nodesep=\umlNodeSep, #1]#2|[angle=90, nodesep=\umlNodeSep, #1]#2} \newcommand\umlBottomLeftSepOpt[2]{% [angle=180, nodesep=\umlNodeSep, #1]#2|[angle=270, nodesep=\umlNodeSep, #1]#2} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Angles} % \label{sec:impSyntaxAngles} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Drawable} % \label{sec:impDrawable} % Each main "uml.sty" command (those drawn as schemas at pages % \pageref{fig:approachStart}--\pageref{fig:approachEnd}) is implemented % in the same pattern. % \begin{macro}{\umlDrawableNull} % First, all the variables (in the "\umlDrawable" case, just one) are % set to their default values. % \begin{macrocode} \def\umlDrawableNull{% \def\umlImport{}% } % \end{macrocode} % \end{macro} % Of course, it would be more elegant to treat one variable at a time, % setting it to its default value and handling its named options at the % same place. However, I have not found any way to do so. % Then, the named options are handled. Most of them modify the % variables. In this case, there is only one named option ("import") % which modify one variable ("\umlColor"). In most cases, the named % option and the variable has corresponding names. % \begin{macro}{import-} % This named option is not properly implemented yet. % \begin{macrocode} \define@key{uml}{import}{% \def\umlColor{red}} % \end{macrocode} % \end{macro} % And then the command itself. % \begin{macro}{\umlDrawable} % This command does not do much work. It just process the nmed options. % \begin{macrocode} \newcommand\umlDrawable[2][]{% % \end{macrocode} % It sets its variables to default values, % \begin{macrocode} \umlDrawableNull% % \end{macrocode} % process the named options % \begin{macrocode} \setkeys{uml}{#1}% % \end{macrocode} % and typesets it second argument. This argument, the contents, % typically uses some of the variables. % \begin{macrocode} #2% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Element} % \label{sec:impElement} % \begin{macro}{\umlElementNull} % "\umlElement" follows the same pattern as "\umlDrawable" and the other % main commands; first, it sets its variables to the default values, % then handles the named options, and least define the command itself to % call its ``supercommand''. % \begin{macrocode} \def\umlElementNull{% \def\umlReference{refdef}% \def\umlStereotype{}% \def\umlSubof{}% \def\umlImportedFrom{}% \def\umlComment{}% \def\umlAbstract{}% } % \end{macrocode} % \end{macro} % \begin{macro}{reference-} % "ref" is provided as an short-form for "reference". % \begin{macrocode} \define@key{uml}{reference}{\def\umlReference{#1}} \define@key{uml}{ref}{\def\umlReference{#1}} % \end{macrocode} % \end{macro} %\begin{macro}{stereotype-} % The \LaTeX{} variable itself sometimes contains not only the % value itself, but some grahical stuff around. % \begin{macrocode} \define@key{uml}{stereotype}{% \def\umlType{\\{\hfill{}\phantom{x}<<#1>>\phantom{x}}}} % \end{macrocode} % \end{macro} % \begin{macro}{subof-} % \begin{macrocode} \define@key{uml}{subof}{% \def\umlSubof{{~Sub of: #1}\\}} % \end{macrocode} % \end{macro} % \begin{macro}{abstract-} % The "abstract" named option also affects the graphical name in "\umlStretchbox". % \begin{macrocode} \define@key{uml}{abstract}[]{% \def\umlAbstract{\emph}}% % \end{macrocode} % \end{macro} % \begin{macro}{importedFrom-} % \begin{macrocode} \define@key{uml}{importedFrom}{% \def\umlImportedFrom{{~From: #1}\\}} % \end{macrocode} % \end{macro} % \begin{macro}{comment-} % \begin{macrocode} \define@key{uml}{comment}{% \def\umlComment{{~#1}\\}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlElement} % The command itself just calls "\umlDrawable". % \begin{macrocode} \newcommand\umlElement[2][]{% \umlElementNull% \umlDrawable[#1]{#2}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Box} % \label{sec:impBox} \iffalse ********************************************************************\fi % \subsection{Positioning} % \label{sec:implementationClassPositions} % One of the main responsibilities of "\umlBox" is to place the box in % the right position. In order to achieve this, "\umlBox" uses two % macros, "\umlBoxPosCommand" and "\umlBoxPosDeltaCommand". Each of % these, in turn, uses other macros, which ultimately are set to default % values. How this happends is indicated in figure \ref{fig:impBoxPos}. % The user can modify this tree by the named options "pos", "posX", % "posY", "posDelta", "posDeltaX", "posDeltaY" and "refpoint". % \newcommand\myBox[4]{ % \rput(#1,#2){\rnode{#3}{ % \begin{tabular}{c}#4\end{tabular}}}} % \begin{figure}[htbp] % \begin{center} % \hspace*{-1cm} % \pspicture(-3cm,-3cm)(8cm,1.5cm) % \begin{small} % \myBox{2.5cm}{1cm}{Box}{"\bslash{}umlBox"} % \myBox{0cm}{0cm}{Command}{"\bslash{}umlBoxPosCommand"} % \myBox{-2cm}{-1cm}{Refpoint}{"\bslash{}umlRefpoint"\\"refpoint="} % \myBox{-2cm}{-2cm}{RefpointValue}{"bl"} % \myBox{2cm}{-1cm}{Pos}{"\bslash{}umlPos"\\"pos="} % \myBox{1cm}{-2cm}{XPos}{"\bslash{}umlPosX"\\"posX="} % \myBox{3cm}{-2cm}{YPos}{"\bslash{}umlPosY"\\"posY="} % \myBox{1cm}{-3cm}{XPosValue}{"(0,"{\gray "0"}")"} % \myBox{3cm}{-3cm}{YPosValue}{"("{\gray "0"}",0)"} % \ncline{<-}{Command}{Box} % \ncline{<-}{Refpoint}{Command} % \ncline{<-}{RefpointValue}{Refpoint} % \ncline{<-}{Pos}{Command} % \ncline{<-}{XPos}{Pos} % \ncline{<-}{YPos}{Pos} % \ncline{<-}{YPosValue}{YPos} % \ncline{<-}{XPosValue}{XPos} % \myBox{7cm}{0cm}{DCommand}{"\bslash{}umlBoxPosDeltaCommand"} % \myBox{7cm}{-1cm}{PosDelta}{"\bslash{}umlPosDelta"\\"posDelta="} % \myBox{6cm}{-2cm}{XPosDelta}{"\bslash{}umlPosDeltaX"\\"posDeltaX="} % \myBox{8cm}{-2cm}{YPosDelta}{"\bslash{}umlPosDeltaY"\\"posDeltaY="} % \myBox{6cm}{-3cm}{XPosDeltaValue}{"(0,"{\gray "0"}")"} % \myBox{8cm}{-3cm}{YPosDeltaValue}{"("{\gray "0"}",0)"} % \ncline{<-}{DCommand}{Box} % \ncline{<-}{Refpoint}{DCommand} % \ncline{<-}{RefpointValue}{Refpoint} % \ncline{<-}{PosDelta}{DCommand} % \ncline{<-}{XPosDelta}{PosDelta} % \ncline{<-}{YPosDelta}{PosDelta} % \ncline{<-}{YPosDeltaValue}{YPosDelta} % \ncline{<-}{XPosDeltaValue}{XPosDelta} % \end{small} % \endpspicture % \caption{Positioning of boxes. The arrows here means % ``calls''. The user can affects this tree by % several named options.} % \label{fig:impBoxPos} % \end{center} % \end{figure} % \begin{macro}{\umlBoxNullPositions} % First, the variables are set to their null values. This command is % called from "\umlBox" via "\umlBoxNull". % \begin{macrocode} \def\umlBoxNullPositions{% \def\umlPosCommand{% \rput[\umlRefpoint](\umlPos)}% \def\umlPos{\umlPosX|\umlPosY}% \def\umlPosX{0,0}% \def\umlPosY{0,0}% \def\umlPosDeltaCommand{% \rput[\umlRefpoint](\umlPosDelta)}% \def\umlPosDelta{\umlPosDeltaX|\umlPosDeltaY}% \def\umlPosDeltaX{0,0}% \def\umlPosDeltaY{0,0}% \def\umlRefpoint{bl}% }% % \end{macrocode} % \end{macro} % \begin{macro}{pos-} % Note that all the named options starting with "pos" % takes legal values as arguments. You % must write "posX={1em,0}" even if he zero is ignored. % \label{pos} % % This also afflicts AssociationEnd (section~\ref{sec:impAssociationEnd}). % \begin{macrocode} \define@key{uml}{pos}[0,0]{% \def\umlPos{#1}} \define@key{uml}{posX}[0,0]{% \def\umlPosX{#1}} \define@key{uml}{posY}[0,0]{% \def\umlPosY{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{posDelta-} % The reference point of the box is placed at $pos + posDelta$. % \begin{macrocode} \define@key{uml}{posDelta}[0,0]{% \def\umlPosDelta{#1}} \define@key{uml}{posDeltaX}[0,0]{% \def\umlPosDeltaX{#1}} \define@key{uml}{posDeltaY}[0,0]{% \def\umlPosDeltaY{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{refpoint-} % Legal values are \emph{reference points} (sec.\ \ref{sec:useReference}) % \begin{macrocode} \define@key{uml}{refpoint}{% \def\umlRefpoint{#1}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \subsection{Boxes in text} % \begin{macro}{\umlBoxNullBoxes} % Normally, a box is an empty hbox. This can be changed using % the named option "box=". It takes no values (i.e.\ % \english{eventuelle} values are ignored). It makes the box taking % the natural size of its contents. % \begin{macrocode} \def\umlBoxNullBoxes{% % \end{macrocode} % This is how the box is made a zero size hbox then the "box=" named % option are not in effect. % \begin{macrocode} \def\umlBoxH{\hbox to 0cm}% \def\umlBoxV{\smash}% }% % \end{macrocode} % \end{macro} % \begin{macro}{box-} % This gives the box its natural size. % \begin{macrocode} \define@key{uml}{box}{% \def\umlBoxH{}% no \hbox to 0cm \def\umlBoxV{}% no \smash anymore \def\umlPosCommand{}% no \rput... anymore \def\umlPosDeltaCommand{}}% Ditto % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \subsection{The visual appeareance} % \begin{macro}{\umlBoxNullVisual} % \begin{macrocode} \def\umlBoxNullVisual{% \def\umlGrayness{1}% \def\umlBorder{0mm}% \def\umlInnerBorder{0mm}% \def\umlOuterBorder{0mm}% }% % \end{macrocode} % \end{macro} % \begin{macro}{grayness-} % The grayness of the background in the box. % Legal values are real numbers between 0 (black) and 1 (white). % Default without named option is 1. Default with named option % is 0.85. % \begin{macrocode} \define@key{uml}{grayness}[.85]{% \def\umlGrayness{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{border-} % The thickness of the outer border. Default without named option is % 0~mm, with 0.4~pt. Legal values are lengths. % \begin{macrocode} \define@key{uml}{border}[0.4pt]{% \def\umlBorder{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{outerBorder-} % The margin around the border. % Default is "\umlhsep". % \begin{macrocode} \define@key{uml}{outerBorder}[\umlhsep]{% \def\umlOuterBorder{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{innerBorder-} % The space left between the edge of the box and its contents. % Default is 0mm. % \begin{macrocode} \define@key{uml}{innerBorder}[\umlhsep]{% \def\umlInnerBorder{#1}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \subsection{Size} % \begin{macro}{\umlBoxNullSize} % The minimum size of the box (or rather, the space left for the contents). % Different boxes (i.e., "\umlStretchBox" and "\umlDiagram" use % different algorithms for sizeing the box. % \begin{macrocode} \def\umlBoxNullSize{% % \end{macrocode} % \begin{macrocode} \def\umlSizeX{5mm}% \def\umlSizeY{7mm}% } % \end{macrocode} % \end{macro} % begin{macro}{size-} % Minimum values, used mostly by "\umlDiagram". % Legal values are lengths. % \begin{macrocode} \define@key{uml}{sizeX}{% \def\umlSizeX{#1}} \define@key{uml}{sizeY}{% \def\umlSizeY{#1}} % \end{macrocode} \iffalse ********************************************************************\fi % \subsection{Holding together all the named options} % \begin{macro}{\umlBoxNull} % Just to invoke the other macros. % \begin{macrocode} \def\umlBoxNull{% \umlBoxNullPositions% \umlBoxNullBoxes% \umlBoxNullVisual% \umlBoxNullSize% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{The command} % \label{sec:impBox} % \begin{macro}{\umlBox} % A box is a rectangle with position and size. % "\umlBox" takes two arguments: The named options and the contents. % \begin{macrocode} \newcommand\umlBox[2][]{\leavevmode% % \end{macrocode} % The variables are set to default % \begin{macrocode} \umlBoxNull% % \end{macrocode} % and "\umlElement" is invoked, with new contents. % \begin{macrocode} \umlElement[#1]{% % \end{macrocode} % Determines how large hbox \LaTeX{} should think this is % \begin{macrocode} \umlBoxH{% \hbox to 0cm or nothing \umlBoxV{% \smash or nothing % \end{macrocode} % rputs the stuff the right place % \begin{macrocode} \umlPosCommand{% \umlPosDeltaCommand{% % \end{macrocode} % the box is a node % \begin{macrocode} \rnode{\umlReference}{% % \end{macrocode} % with outer margin % \begin{macrocode} \setlength{\fboxrule}{0mm}% \setlength{\fboxsep}{\umlOuterBorder}% \fbox{% % \end{macrocode} % border % \begin{macrocode} \setlength{\fboxrule}{\umlBorder}% \setlength{\fboxsep}{0mm}% \fbox{% % \end{macrocode} % and some color and inner margin % \begin{macrocode} \setlength{\fboxsep}{\umlInnerBorder}% \colorbox[gray]{\umlGrayness}{% % \end{macrocode} % around the contents. % \begin{macrocode} #2% }% }% }% }% }% }% }% }% }% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Diagram} % \label{sec:implementationDiagram} % A diagram determines its size before typesetting the contents. This in % order to be able to place the contents relative to the borders of the diagram. % \begin{macro}{\umlDiagramNull} % The macro "\umlDiagramNull" sets the variables to their % default variables. % \begin{macrocode} \newcommand\umlDiagramNull{% \def\umlGrid{}% } % \end{macrocode} % \end{macro} % \begin{macro}{grid-} % This makes a grid inside the diagram. Legal values are lengths, % default are one unit. % % Bug: the grid named option does not work right now, after I had % to change "\umlDiagram" from using "\pspicture" to using rules. % "\pspicture" with huge contents crashed psdvi. And the grid isn't % so useful with the new positioning system. % \begin{macrocode} \define@key{uml}{grid}[1]{% \def\umlGrid{% {\ifx#1{}\else\psset{xunit=#1, yunit=#1}\fi% \psgrid[subgriddiv=1,griddots=5]}}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \subsection{The command} % \label{sec:impDiagram} % \begin{macro}{\umlDiagram} % \begin{macrocode} \newcommand\umlDiagram[2][]{% % \end{macrocode} % First, the variables are set to their default values. % \begin{macrocode} \umlDiagramNull% % \end{macrocode} % the grayness are set to be default 1 (white). % \begin{macrocode} \umlBox[grayness=1, #1]{% % \pspicture\umlBl(\umlSizeX, \umlSizeY)% % \end{macrocode} % \#2 is the contents. The rules are to make sure the diagram is big % enough. The rules are normally invisible, because "\umlDebugLength" % normally is 0~pt. % However, the rules must be evaluated before the contents, % \english{sånn at} possible "\umlBox"es does not inflict on "\umlSizeX" % and "\umlSizeY". Thus, the "\expandafter". % \begin{macrocode} \expandafter{#2}{% \rule{\umlDebugLength}{\umlSizeY}% \rule{\umlSizeX}{\umlDebugLength}}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Stretchbox} % \label{sec:impoStretchbox} % % "\umlStretchbox" is the first command to take three arguments: The % optional named options, a name and some contents. % \begin{macro}{\umlStretchboxNull} % \begin{macrocode} \newcommand\umlStretchboxNull{% \def\umlGraphicalName{StrechboxDefault{\umlAbstract\umlName}\\}% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlGraphicalName} % "\umlGraphicalName" is a name, possibly with some graphical fuzz, to % be printed in the box. % \end{macro} \iffalse ********************************************************************\fi % \begin{macro}{\umlStretchbox} % The macro itself just handles the name. The reference is by default % set to the name. % A stretchbox first typesets its contents, % and then take size depending on the contents. % This as opposed to a diagram, which determine the size first. % \begin{macrocode} \newcommand\umlStretchbox[3][]{% \def\umlName{#2}% \umlStretchboxNull% \umlBox[ref={#2}, #1]{% \rnode{\umlReference}{#3}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Package} % \label{sec:implementationPackage} % Bug: The \index{border=!in Package} "border=" named option does not % work in "\umlPackage". For some reason, a simple "\fbox" does not % seem to work. I have no time for this now. % \begin{macro}{\umlPackage} % \begin{macrocode} \newcommand\umlPackage[3][]{% % Null unneccessary \def\umlName{#1}% \umlStretchbox[#1,border=0mm]{#2}{% \def\umlGraphicalName{% {\umlhspace\hfill\relsize{2}\textbf{\umlName}% \rule{0mm}{2.3ex}\hfill\umlhspace}\\% }% \begin{tabular}{@{}l@{}}% % \end{macrocode} % The upper rectangle. It may seem natural to make this a % "\umlStretchbox", but then we risk variable interference between the % two instances of "\umlStretchbox". It does not work in practice either. % \begin{macrocode} \rnode{small\umlReference}{% \begin{tabular}{@{}|l|@{}}\hline% \umlStereotype% \umlGraphicalName% \umlImportedFrom% \umlComment% \umlSubof\hline% \end{tabular}}\cr% % \end{macrocode} % The lower rectangle % \begin{macrocode} \rnode{big\umlReference}{% \begin{tabular}{@{}|@{}l@{}|@{}}\hline% % \end{macrocode} % Start the boxes in the lower rectangle % \begin{macrocode} % \end{macrocode} % Insert the contain % \begin{macrocode} #3% \cr\hline% % \end{macrocode} % Here (in the "\cr"?), there is some vertical space. I still have % some work to do to understand the vertical lengths in tabular. % \begin{macrocode} \end{tabular}}% End of lower rectangle \end{tabular}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Classifier} % \label{sec:impClassifier} % % A classifier is a stretchbox which contains compartments. % A classifier can be instanciated, or be an instance. \iffalse ********************************************************************\fi % \begin{macro}{\umlClassifierNull} % \begin{macrocode} \newcommand\umlClassifierNull{% \def\umlObject{}} % \end{macrocode} % \end{macro} % \begin{macro}{object-} % This makes the classifier be an instance (object). % Graphically, this is shown by an line under the classifier name. % Note that instances cannot be abstract. % \begin{macrocode} \define@key{uml}{object}{% \def\umlObject{\underbar}} % \end{macrocode} % \end{macro} % \begin{macro}{instance-} % "instance" is provided as an equivalent to "object". % \begin{macrocode} \define@key{uml}{instance}{% \def\umlObject{\underbar}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \begin{macro}{\umlClassifier} % "\umlClassifier" is implemented as a table inside a "\umlStretchbox". % The contents must be able to be inside a table. % The contents is typically "\umlCompartment"s. % \begin{macrocode} \newcommand\umlClassifier[3][]{% % \end{macrocode} % Variables set to default values % \begin{macrocode} \umlClassifierNull% % \end{macrocode} % Names fixed. Uses "\umlAbstract". % \begin{macrocode} \def\umlName{#2}% % \end{macrocode} % Grayness and border are given default values, % possible to override. % \begin{macrocode} \umlStretchbox[grayness=0.85,border=.4pt,#1]{#2}{% % \end{macrocode} % "\umlGraphicalName" must be defined here not to be overridden by % "\umlStretchboxNull". % Note the invisible rule to make some space. % \begin{macrocode} \def\umlGraphicalName{% \rule{0mm}{2.8ex}% \umlhspace\larger\hfill\textbf{% \umlAbstract{\umlObject{\umlName}}}\hfill\umlhspace\\}% \begin{tabular}[tl]{@{}l@{}}% \umlStereotype% \umlGraphicalName% \umlImportedFrom% \umlComment% \umlSubof\hline% #3% \end{tabular}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Class} % \label{sec:implementationClass} \iffalse ********************************************************************\fi % \begin{macro}{\umlClass} % A class is a classifier with the three usual compartments. % % There is not much work left for "\umlClass": % \begin{macrocode} \newcommand\umlClass[4][]{% % \end{macrocode} % A "\umlClassNull" is unneccessary, as there is no variables here. % \begin{macrocode} \umlClassifier[#1]{#2}{% \umlCompartment{#3}% \umlCompartment{#4}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Schema} % \label{sec:impSchema} % \begin{macro}{\umlSchema} % A schema is a classifier with some more compartments. % \begin{macrocode} \newcommand\umlSchema[7][]{% % \end{macrocode} % "Null" unneccessary here too. % \begin{macrocode} \umlClassifier[#1]{#2}{% \umlCompartment{#3}% Attributes \umlCompartment{#4}% Methods \umlCompartment{#5}% Arguments \umlCompartment{#6}% Constraints \umlCompartment{#7}% Structure }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Compartment} % Classifiers (e.g., classes) are drawn as compartments (boxes) below each other. % "\umlCompartment" takes two arguments: a optional list of named % options, and the contents. % \begin{macro}{\umlCompartmentNull} % \begin{macrocode} \newcommand\umlCompartmentNull{% \def\umlCompartmentEmpty{\vspace*{-2ex}\cr\hline}% } % \end{macrocode} % \end{macro} % \begin{macro}{supress-} % \begin{macrocode} \define@key{uml}{supress}[]{% \def\umlCompartmentEmpty{}% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlSupressionOn} % To turn supression default on, use the command % \begin{macrocode} \newcommand\umlSupressionOn{% \renewcommand\umlCompartmentNull{% \def\umlCompartmentEmpty{}}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlSupressionOff} % off, use % \begin{macrocode} \newcommand\umlSupressionOff{% \renewcommand\umlCompartmentNull{% \def\umlCompartmentEmpty{\vspace*{-2ex}\cr\hline}}} % \end{macrocode} % \end{macro} % \begin{macro}{\ifisnull} % A handy command stolen from [AdvancedTeX, p.126]. % If first argument is empty, execute the second; else execute the third. % \begin{macrocode} \def\ifisnull#1#2#3{\def\inner{#1}% \ifx\inner\empty #2\else{}#3% \fi} % \end{macrocode} % \end{macro} % \begin{macro}{\umlCompartment} % \begin{macrocode} \newcommand\umlCompartment[2][]{% \umlCompartmentNull% \umlDrawable[#1]{% \ifisnull{#2}{% \umlCompartmentEmpty}{% #2\hline}}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Compartmentline} % \label{sec:impCompartmentline} % A compartmentline is a line of text \english{beregnet på} to be in a compartment. % Such a line should have some room before and after it, in order not % to touch the compartment border. % \begin{macro}{\umlhspace} % This make some horizontal space. % \begin{macrocode} \def\umlhsep{.5ex} \newcommand\umlhspace{\hspace*{\umlhsep}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlCompartmentline} % This should be straight-forward\dots % \begin{macrocode} \newcommand\umlCompartmentline[2][]{% \umlDrawable[#1]{% \umlhspace{}#2{}\umlhspace}\cr} % \end{macrocode} % \end{macro} % \begin{macro}{\umlCompartmentText} % Provided for backward compatibility. % \begin{macrocode} \newcommand\umlCompartmentText[1]{% \umlhspace#1\umlhspace\\} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{Feature} % \label{sec:impFeature} % % A feature is something attached to a classifier. % \begin{macro}{\umlVisibilityLength} % This is the hspace in front of the attribute name, where the % visibility is placed. % \begin{macrocode} \def\umlVisibilityLength{2ex} % \end{macrocode} %\end{macro} % \begin{macro}{\umlFeatureNull} % \begin{macrocode} \newcommand\umlFeatureNull{% \def\umlVisibility{}% \def\umlType{}% \def\umlPropertyString{}% \def\umlInitialValue{}% } % \end{macrocode} % \end{macro} % \begin{macro}{visibility-} % \begin{macrocode} \define@key{uml}{visibility}[+]{% \def\umlVisibility{\hbox to \umlVisibilityLength{#1\hfil}}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlTilde} % In \LaTeX{}, you may want to % write "\umlTilde" instead of "\verb!~!". % \begin{macrocode} \newcommand\umlTilde{\verb!~!} % \end{macrocode} % \end{macro} % \begin{macro}{propertyString-} % \begin{macrocode} \define@key{uml}{propertyString}{% \def\umlPropertyString{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{type-} % The data type returned from the feature. % \begin{macrocode} \define@key{uml}{type}{% \def\umlType{: #1}} % \end{macrocode} % \end{macro} % \begin{macro}{initialValue-} % \begin{macrocode} \define@key{uml}{initialValue}{% \def\umlInitialValue{= #1}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \begin{macro}{\umlFeature} % "\umlFeature" is implemented as a table inside a "\umlStretchbox". % The contents must be able to be inside a table. % The contents is typically "\umlCompartment"s. % \begin{macrocode} \newcommand\umlFeature[2][]{% \umlFeatureNull% \umlCompartmentline[#1]{#2}% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Attribute} % \begin{macro}{\umlAttributeNull} % \begin{macrocode} \def\umlAttributeNull{% \def\umlMultiplicity{}% \def\umlOrdering{}% \def\umlMultiplicityOrdering{}% } % \end{macrocode} % \end{macro} % \begin{macro}{default-} % This is provided as an alias to "initialValue" for the sake % of backward compatibility. Use is deprecated. % \begin{macrocode} \define@key{uml}{default}{% \def\umlInitialValue{ = #1}} % \end{macrocode} % \end{macro} % \begin{macro}{multiplicity-} % Examples of legal values are "{[1]}", "{[1..*]}" and "{[1..3,5..]}". % \begin{macrocode} \define@key{uml}{multiplicity}{% \def\umlMultiplicity{#1}% \def\umlMultiplicityOrdering{[\umlMultiplicity{} \umlOrdering]}} % \end{macrocode} % \end{macro} % \begin{macro}{ordering-} % Legal values are "ordered" and "unordered". % Absent value imply unordered. Default value with named option is ordered. % \begin{macrocode} \define@key{uml}{ordering}[ordered]{% \def\umlOrdering{#1}% \def\umlMultiplicityOrdering{[\umlMultiplicity{} \umlOrdering]}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlAttribute} % \begin{macrocode} \newcommand\umlAttribute[2][]{% \umlAttributeNull% \umlFeature[#1]{% \umlVisibility #2 \umlType \umlMultiplicityOrdering \umlInitialValue \umlPropertyString}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Method} % \begin{macro}{\umlMethodNull} % \begin{macrocode} \newcommand\umlMethodNull{% } % \end{macrocode} % \end{macro} % \begin{macro}{returntype-} % Alias to "type=". % \begin{macrocode} \define@key{uml}{returntype}{% \def\umlType{: #1}} % \end{macrocode} % \end{macro} % \begin{macro}{\umlMethod} % \begin{macrocode} \newcommand\umlMethod[3][]{% \umlMethodNull% \umlFeature[#1]{% \umlVisibility #2(#3) \umlType \umlPropertyString}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Argument} % \begin{macro}{\umlArgumentNull} % \begin{macrocode} \newcommand\umlArgumentNull{% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlArgument} % \begin{macrocode} \newcommand\umlArgument[2][]{% \umlArgumentNull% \umlFeature[#1]{% \emph{#2} \umlType \umlInitialValue}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{The relations} % \label{sec:implementationRelations} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Node connection points} % \begin{macro}{\umlRelationNullConnection} % \begin{macrocode} \newcommand\umlRelationNullConnection{% \def\umlNodesepA{0pt}% \def\umlNodesepB{0pt}% \def\umlOffsetA{0pt}% \def\umlOffsetB{0pt}% \def\umlAngleA{}% \def\umlAngleB{}% }% % \end{macrocode} % \end{macro} % \begin{macro}{angle-} % This is the angle at which the connector hits the node % \begin{macrocode} \define@key{uml}{angleA}{% \def\umlAngleA{#1}% } \define@key{uml}{angleB}{% \def\umlAngleB{#1}% } \define@key{uml}{angle}{% \def\umlAngleA{#1}% \def\umlAngleB{#1}% } % \end{macrocode} % \end{macro} % \begin{macro}{nodesep-} % The distance from the node to the connector end. % Legal values are lengths. % \begin{macrocode} \define@key{uml}{nodesepA}{% \def\umlNodesepA{#1}% } \define@key{uml}{nodesepB}{% \def\umlNodesepB{#1}% } \define@key{uml}{nodesep}{% \def\umlNodesepA{#1}% \def\umlNodesepB{#1}% } % \end{macrocode} % \end{macro} % \begin{macro}{offset-} % After the connection point is calculated, it is shift right (assumed % direction onto node) by this value. Legal values are lengths. % \begin{macrocode} \define@key{uml}{offsetA}{% \def\umlOffsetA{#1}% } \define@key{uml}{offsetB}{% \def\umlOffsetB{#1}% } \define@key{uml}{offset}{% \def\umlOffsetA{#1}% \def\umlOffsetB{#1}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Arm geometry} % \begin{macro}{\umlRelationNullArmGeometry} % \begin{macrocode} \newcommand\umlRelationNullArmGeometry{% \pssetlength\umlArmA{0pt}% \pssetlength\umlArmB{0pt}% \def\umlArmAngleA{0}% \def\umlArmAngleB{0}% } % \end{macrocode} % \end{macro} % \begin{macro}{armA-} % This is the lengths of the arms. % \begin{macrocode} \newlength\umlArmA \newlength\umlArmB \define@key{uml}{armA}{% \pssetlength\umlArmA{#1}} \define@key{uml}{armB}{% \pssetlength\umlArmB{#1}} \define@key{uml}{arm}{% \pssetlength\umlArmA{#1}% \pssetlength\umlArmB{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{armAngle-} % This is the angle of the arm. % \begin{macrocode} \define@key{uml}{armAngleA}{% \def\umlArmAngleA{#1}% } \define@key{uml}{armAngleB}{% \def\umlArmAngleB{#1}% } \define@key{uml}{armAngle}{% \def\umlArmAngleA{#1}% \def\umlArmAngleB{#1}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Visual appeareance} % \begin{macro}{\umlRelationNullVisual} % \begin{macrocode} \newcommand\umlRelationNullVisual{% \def\umlLinestyle{solid}% \def\umlLinecolor{black}% } % \end{macrocode} % \end{macro} % \begin{macro}{linestyle-} % Legal values are "none", "solid", "hashed" and "dotted". % \begin{macrocode} \define@key{uml}{linestyle}{% \def\umlLinestyle{#1} } % \end{macrocode} % \end{macro} % \begin{macro}{linecolor-} % The color of the line. % \begin{macrocode} \define@key{uml}{linecolor}{% \def\umlLinecolor{#1}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi % \begin{macro}{\umlRelationNull} % \begin{macrocode} \newcommand\umlRelationNull{% \umlRelationNullConnection% \umlRelationNullArmGeometry% \umlRelationNullVisual% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{The macro} % \begin{macro}{\umlRelation} % The command itself: % \begin{macrocode} \newcommand\umlRelation[3][]{% \umlRelationNull% % \end{macrocode} % The default reference is the \english{sammensetning} of the two references % \begin{macrocode} \umlElement[ref={#2#3}, #1]{% % \end{macrocode} % Putting the "Aa" and "Ba" nodes, default (without "angle=") first % \begin{macrocode} \ncline[linecolor=green, linestyle=\umlDebugLinestyle, offsetA=\umlOffsetA, nodesepA=\umlNodesepA, offsetB=\umlOffsetB, nodesepB=\umlNodesepB]{#2}{#3}% \lput{:R}(0){\pnode{Aa\umlReference}}% \lput{:R}(1){\pnode{Ba\umlReference}}% % \end{macrocode} % Then modifying "Aa", if "angleA=" or "angle=" is used % \begin{macrocode} \ifx\umlAngleA\empty\empty \else \ncdiag[linestyle=\umlDebugLinestyle, linecolor=magenta, % angleA=\umlAngleA, offsetA=\umlOffsetA, nodesepA=\umlNodesepA, offsetB=\umlOffsetB, nodesepB=\umlNodesepB ]{#2}{#2}% \lput{:R}(0){\pnode{Aa\umlReference}}\fi% % \end{macrocode} % And "Ba". % \begin{macrocode} \ifx\umlAngleB\empty\empty \else \ncdiag[linestyle=\umlDebugLinestyle, linecolor=magenta, % angleA=\umlAngleB, offsetA=\umlOffsetA, nodesepA=\umlNodesepA, offsetB=\umlOffsetB, nodesepB=\umlNodesepB ]{#3}{#3}% \lput{:R}(0){\pnode{Ba\umlReference}}\fi% % \end{macrocode} % Now, we can draw the line, from the "Aa" to the "Ba" node. % \begin{macrocode} \ncdiag[linestyle=\umlLinestyle, linecolor=\umlLinecolor, angleA=\umlArmAngleA, angleB=\umlArmAngleB, armA=\umlArmA, armB=\umlArmB ]{% Aa\umlReference}{% Ba\umlReference}% } % \end{macrocode} % Placing nodes "Ab" and "Bb". % If there is no arm A, % \begin{macrocode} \ifdim \umlArmA=0pt \lput{:R}(2){\pnode{Ab\umlReference}}% % \end{macrocode} % Else, if there is % \begin{macrocode} \else \lput{:R}(1){\pnode{Ab\umlReference}} \fi% % \end{macrocode} % If there is no arm B, % \begin{macrocode} \ifdim \umlArmB=0pt \lput{:R}(1){\pnode{Bb\umlReference}}% % \end{macrocode} % Else, if there is % \begin{macrocode} \else \lput{:R}(2){\pnode{Bb\umlReference}} \fi% % \end{macrocode} % Final nodes % \begin{macrocode} \lput{:R}(1){\pnode{Ac\umlReference}}% \lput{:R}(2){\pnode{Bc\umlReference}}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{About the spesific relations} % The different relations are specialized relations; they typically call % "\umlRelation" and "\umlSymbol" with an appropriate symbol. % \label{lengths} % \begin{macro}{\umlSymbolHeightDefault} % All the symbols are drawn with "0" as the upper border, % "-\umlSymbolHeightDefault" as the lower, % "-\umlSymbolWidthDefault" as the left and % "\umlSymbolWidthDefault" as the right one. These lengths can % be changed by the user. See, however, section \vref{sec:umlInner}. % \begin{macrocode} \newlength\umlSymbolHeightDefault \setlength\umlSymbolHeightDefault{1em} \newlength\umlSymbolWidthDefault \setlength\umlSymbolWidthDefault{.5em} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Association} % \label{sec:association} % \begin{macro}{\umlAssociation} % "\umlAssociation" is only a wrapper to "\umlReference". % \begin{macrocode} \newcommand\umlAssociation[3][]{% \umlRelation[#1]{#2}{#3}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Subclass (generalization)} % \begin{macro}{\umlSubclass} % A simple relation with a triangle as an endsymbol. % \begin{macrocode} \newcommand\umlSubclass[3][]{% \umlRelation[#1]{#2}{#3}% \def\umlEndSymbol{% \pspolygon*[linecolor=white](0,0)% (-\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% \pspolygon[](0,0)% Why does not dimen=inner work? (-\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% }% % \def\umlEndSymbol{% Alternative \umlEndSymbol % \pstriangle[dimen=inner](0,-\umlSymbolHeightDefault)% % (\umlSymbolWidthDefault,\umlSymbolHeightDefault)} % \end{macrocode} % Note that this depends on "\umlReference", which is set by % "\uml" whether the "relation=" option is used or not. Noone % could affect "\umlReference" between "\uml" and here. % \begin{macrocode} \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol}% } \def\umlGeneralization{\umlSubclass} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Inner class} % \label{sec:inner} % The making of this symbol gave some problems. After experimenting % with different interpolations and Bézier curves, I defined it to % consist of two clipped wedges. Each should of course have width $w % = $ "\umlWidthDefault" and height % $h = $"\umlHeightDefault". % The radius of the circle is $r$, and $r % = v + w$. This gives figure \vref{fig:innerSymbol}. % \begin{figure}[htbp] % This figure is drawn with an angle of 60 degrees. % \begin{center}{A% % \psset{unit=1.5cm} % \begin{pspicture}(-2,-2)(2,.25)% % \psgrid(0,0)(-2,-2)(1,.25) % \psline(-2,0)(2,0) % \pswedge(0,-.866){1}{120}{180} % \pscircle[](0,-.866){1} % \psarc[linewidth=2.4pt](0,-.866){1}{120}{180} % \psline(-.5,0)(-.5,-.866) % The symbols % \psbezier(-1,-.866)(-1,-.933)(-.75,-.933)(-.75,-1) % \psbezier(-.5,-.866)(-.5,-.933)(-.75,-.933)(-.75,-1) % \rput[t](-.75,-1){\rput(0,-1ex){$v$}} % \psbezier(-.5,-.866)(-.5,-.933)(-.25,-.933)(-.25,-1) % \psbezier(-0,-.866)(-0,-.933)(-.25,-.933)(-.25,-1) % \rput[t](-.25,-1){\rput(0,-1ex){$w$}} % \psbezier(0,0)(0.067,0)(0.067,-.433)(0.134,-.433) % \psbezier(0,-.866)(0.067,-.866)(0.067,-.433)(0.134,-.433) % \rput[l](.134,-.433){~$h$} % \end{pspicture} % \hspace{1cm} % \begin{pspicture}(-2,-2)(1,.25)% % \psline(-2,0)(1,0) % \psarc[linewidth=2.4pt](0,-.866){1}{120}{180} % \psarc[linewidth=2.4pt](-1,-.866){1}{0}{60} % \psline[linewidth=2.4pt](-1,-.866)(0,-.866) % \psline[linewidth=2.4pt](-.5,-1.75)(-.5,-.866) % \end{pspicture} % \caption{The inner class symbol} % \label{fig:innerSymbol}} % \end{center} % \end{figure} % We have $$r = v + w$$ and, from Pythagoras, $$r^2 = h^2 + w^2$$ % This gives $$r=\frac{h^2}{2v} + \frac{v}{2}$$ and % $$w=\frac{h^2}{2v}-\frac{v}{2}$$ and we know where to locate the % wedge. % However, while addition and subtraction of lengths is easy in % PStricks (only stepping back and forth), multiplication and division % of lengths is difficult, if not impossible. I really haven't found a % good solution to this problem. % The not-so-good problem is to define $w$ and $r$ as \TeX{} lengths % ("\umlInnerWidthDefault" and % "\umlInnerRadiusDefault") % and then assign them values manually. We % have to remember, then, that Pythagoras still should work. % Page \pageref{lengths} assign the default values $h=1$em, $v=.5$em. % This gives % \begin{macro}{\umlInnerWidthDefault} % $w=0.75$em % \begin{macrocode} \newlength\umlInnerWidthDefault \setlength\umlInnerWidthDefault{0.75em} % \end{macrocode} % \end{macro} % \begin{macro}{\umlInnerRadiusDefault} % and $r=1.25$em. % \begin{macrocode} \newlength\umlInnerRadiusDefault \setlength\umlInnerRadiusDefault{1.25em} % \end{macrocode} % \end{macro} % If we should implement the symbol by "\umlArc", we had to know some % angles. They would be easy to \english{regne ut} using trigonometry, % but that is difficult within \TeX. Then, we use "\umlCircle" and % "\psclip" instead. % Maybe this could be done easily using raw postscript? % \begin{macro}{\umlInner} % On some systems, the clipping makes some borders. Usually, this is % not a problem on printed material. % \begin{macrocode} \newcommand\umlInner[3][]{% \umlRelation[#1]{#2}{#3}% \def\umlEndSymbol{% \pspolygon*[linecolor=white](0,0)% (-\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault,-\umlSymbolHeightDefault)% \psclip{% \psframe[linewidth=0pt]% (-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)(0,0)} \pscircle(\umlInnerWidthDefault,-\umlSymbolHeightDefault)% {\umlInnerRadiusDefault} \endpsclip \psclip{% \psframe[linewidth=0pt]% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)(0,0)} \pscircle(-\umlInnerWidthDefault,-\umlSymbolHeightDefault)% {\umlInnerRadiusDefault} \endpsclip \psline(-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)} \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol} } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Instance} % \label{sec:instance} % \begin{macro}{\umlInstance} % The only new thing about "\umlInstance" is the addition of one named % option, the linestyle. % \begin{macrocode} \newcommand\umlInstance[3][]{% \umlRelation[linestyle=dashed, #1]{#2}{#3}% \def\umlEndSymbol{% \psline(-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,0)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)}% \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol} } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Aggregation} % \label{sec:aggregation} % \begin{macro}{\umlAggregation} % Endpoint is a diamond. % \begin{macrocode} \newcommand\umlAggregation[3][]{% \umlRelation[#1]{#2}{#3}% \def\umlEndSymbol{% % \end{macrocode} % Anyone said addition of lengths in PStricks was difficult? % \begin{macrocode} \rput(0,-\umlSymbolHeightDefault){% \psline*[linecolor=white](-\umlSymbolWidthDefault, 0)% (0,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault, 0)} \psline*[linecolor=white]% (-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,0)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault) \rput(0,-\umlSymbolHeightDefault){% \psline(-\umlSymbolWidthDefault, 0)% (0,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault, 0)} \psline(-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,0)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)} \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol} } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Composition} % \label{sec:composition} % \begin{macro}{\umlComposition} % End symbol is a filled diamond. % \begin{macrocode} \newcommand\umlComposition[3][]{% \umlRelation[#1]{#2}{#3}% \def\umlEndSymbol{% \rput(0,-\umlSymbolHeightDefault){% \psline*(-\umlSymbolWidthDefault, 0)% (0,-\umlSymbolHeightDefault)% (\umlSymbolWidthDefault, 0)} \psline*(-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,0)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)} \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol} } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Application} % \label{sec:application} % \begin{macro}{\umlApplication} % End symbol is a filled arrow. % \begin{macrocode} \newcommand\umlApplication[3][]{% \umlRelation[#1]{#2}{#3}% \lput(1.2){\pnode{argument\umlReference}}% \def\umlEndSymbol{% \pspolygon*(-\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,0)% (\umlSymbolWidthDefault, -\umlSymbolHeightDefault)% (0,-\umlSymbolWidthDefault)}% \umlSymbol[pos=B]{\umlReference}{\umlEndSymbol} } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{ToRelation} % \label{sec:associationClass} % \begin{macro}{\umlToRelationNull} % \begin{macrocode} \newcommand\umlToRelationNull{% \def\umlPosMeetLine{.5}% } % \end{macrocode} % \end{macro} % \begin{macro}{posMeetLine-} % Where this relation shall meet the relation. % \begin{macrocode} \define@key{uml}{posMeetLine}[.5]{% \def\umlPosMeetLine{#1}% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlAssociationClass} % Relation from a relation to a classifier % \begin{macrocode} \newcommand\umlToRelation[3][]{% \umlToRelationNull% % \end{macrocode} % We have to process the "posMeetLine" option before the "\lput". % This introduces some overhead, as "\setkeys" is run twice. % However, I expect this to be used relatively few times. % \begin{macrocode} \setkeys{uml}{#1}% \ncline[linecolor=red, linestyle=\umlDebugLinestyle]{Ac#3}{Bc#3}% \lput{:R}(\umlPosMeetLine){\pnode{ToRelation#3}}% \umlRelation[ref={#2#3}, #1]{#2}{ToRelation#3}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{AssociationClass and AssociationSchema} % \label{sec:associationClass} % \begin{macro}{\umlAssociationClass} % Relation from a relation to a schema symbol. % \begin{macrocode} \newcommand\umlAssociationSchema[3][]{% \umlToRelation[posMeetLine=.5, linestyle=dashed,#1]{#2}{#3}% } \newcommand\umlAssociationClass[3][]{% \umlAssociationSchema[#1]{#2}{#3}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Argument} % \label{sec:argument} % \begin{macro}{\umlArgumentRelation} % Relation from an application to an argument. % \begin{macrocode} \newcommand\umlArgumentRelation[3][]{% \umlToRelation[posMeetLine=.2,linestyle=dotted,#1]{#2}{#3}% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \section{AssociationEnd} % \label{sec:impAssociationEnd} % \begin{macro}{\umlAssociationEndNull} % \begin{macrocode} \newcommand\umlAssociationEndNull{% \def\umlAEcolor{black}% \def\umlAEOffset{\umlAEOffsetDefault}% \def\umlAEOffsetDefault{0pt}% \def\umlAEPos{0}% \def\umlAEPosAngle{\umlAEPosAngleDefault}% \def\umlAEPosAngleDefault{:U}% \def\umlAEAngle{\umlAEAngleDefault}% \def\umlAEAngleDefault{U}% \def\umlAERefpoint{B}% \def\umlAEHeight{\umlAEHeightDefault}% \def\umlAEHeightDefault{0pt}% \def\umlAENoderefClose{Ac}% \def\umlAENoderefFar{Bc}% \def\umlAEType{AssociationEnd}% } % \end{macrocode} % \end{macro} % \begin{macro}{import-} % \begin{macrocode} \define@key{umlAE}{import}{% \def\umlAEColor{red}} % \end{macrocode} % \end{macro} % \begin{macro}{offset-} % \begin{macrocode} \define@key{umlAE}{offset}{% \def\umlAEOffset{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{angle-} % Angle used to rotate the symbol itself. % \begin{macrocode} \define@key{umlAE}{angle}{% \def\umlAEAngle{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{posAngle-} % The angle used when positioning the symbol. % Legal values includes angles preceded by a colon (:), % indicting positioning relative to the relation. % This is expected to be used by subcommands, but % seldom by users. % \begin{macrocode} \define@key{umlAE}{posAngle}{% \def\umlAEPosAngle{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{height-} % \begin{macrocode} \define@key{umlAE}{height}{% \def\umlAEHeight{#1} } % \end{macrocode} % \end{macro} % \begin{macro}{refpoint-} % \begin{macrocode} \define@key{umlAE}{refpoint}{% \def\umlAERefpoint{#1}} % \end{macrocode} % \end{macro} % \begin{macro}{refpoint-} % \begin{macrocode} \define@key{umlAE}{type}{% \def\umlAEType{#1}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Pos} % \begin{macro}{pos-} % This value is used by "\umlAEFixPosLabel" and "\umlAEFixPosSymbol". % \begin{macrocode} \define@key{umlAE}{pos}{% \def\umlAEPos{#1}% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlFromTo} % A handy little procedure. If its first argument is "A" or "From", it % executes the second argument. If it is "B" or "To", it executes the % third. Used in the procedures like "\umlAssociationEndMakeA", % "\umlLabelMakeA" and "\umlSymbolMakeA". % \begin{macrocode} \newcommand\umlFromTo[3]{% \edef\umlAEPosArgument{#1}% \def\umlAEPosTmp{From}\ifx\umlAEPosArgument\umlAEPosTmp{}#2\fi% \def\umlAEPosTmp{A}\ifx\umlAEPosArgument\umlAEPosTmp{}#2\fi% \def\umlAEPosTmp{To}\ifx\umlAEPosArgument\umlAEPosTmp{}#3\fi% \def\umlAEPosTmp{B}\ifx\umlAEPosArgument\umlAEPosTmp{}#3\fi% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlAssociationEndUsePos} % If "\umlPos" is "A" or something (i.e., if "pos=A" or sth), % adjust some other parameters. % \begin{macrocode} \newcommand\umlAssociationEndUsePos{% % \begin{macrocode} \umlFromTo{\umlAEPos}{% \def\umlAENoderefClose{Aa}% \def\umlAENoderefFar{Ab}% \def\umlAEPos{0}% }{% \def\umlAENoderefClose{Ba}% \def\umlAENoderefFar{Bb}% \def\umlAEPos{0}% % \end{macrocode} % If this is a ``"B"'' type association end, % and this is an Label type association end, % invert the height. % \begin{macrocode} \def\umlTmp{Label}% \ifx\umlTmp\umlAEType% \edef\umlAEHeight{-\umlAEHeight}\fi% }% } % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{The command} % \begin{macro}{\umlAssociationEnd} % This places a symbol (third argument) on the \meta{From} end of % the relation (indicated by the second argument). % \begin{macrocode} \newcommand\umlAssociationEnd[3][]{% \umlAssociationEndNull% \setkeys{umlAE}{#1}% \umlAssociationEndUsePos% \ncline[linecolor=red, linestyle=\umlDebugLinestyle]{% \umlAENoderefClose#2}{\umlAENoderefFar#2}% \lput[\umlAERefpoint]{\umlAEPosAngle}(\umlAEPos){% \rput[\umlAERefpoint]{\umlAEAngle}(\umlAEOffset, \umlAEHeight){% #3}% }% }% % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Label} % \label{Labels}\label{sec:labels} % \begin{macro}{\umlLabel} % A label is a symbol with default height and offset. % \begin{macrocode} \newcommand\umlLabel[3][]{% % Null unneccesary \umlAssociationEnd[type=Label, offset=4ex, height=2ex, angle=N, #1]{% #2}{% #3}% } % \end{macrocode} %\end{macro} % \begin{macro}{\umlLabelA} % "\umlLabelA" and "\umlLabelB" are % provided for convenience and backward compatibility. % \begin{macrocode} \newcommand\umlLabelA[2][]{\umlLabel[#1,pos=A]{#2}} \newcommand\umlLabelB[2][]{\umlLabel[#1,pos=B]{#2}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Symbol} % \label{Symbols}\label{sec:symbols} % \begin{macro}{\umlSymbol} % A symbol is a symbol with default height and offset. % \begin{macrocode} \newcommand\umlSymbol[3][]{% % Null unneccesary \umlAssociationEnd[type=Symbol,offset=0ex,height=0ex, posAngle=:L,refpoint=t,#1]{% #2}{\umlSymbolUsePos% #3} } % \end{macrocode} %\end{macro} % \begin{macro}{\umlAssociationEndUsePos} % \begin{macrocode} \newcommand\umlSymbolUsePos{% \umlFromTo{\umlAEPos}{% }{% }% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlSymbolA} % "\umlSymbolA" and "\umlSymbolB" are % provided for convenience and backward compatibility. % \begin{macrocode} \newcommand\umlSymbolA[2][]{\umlSymbol[#1,pos=A]{#2}} \newcommand\umlSymbolB[2][]{\umlSymbol[#1,pos=B]{#2}} % \end{macrocode} % \end{macro} \iffalse ********************************************************************\fi \iffalse ********************************************************************\fi % \subsection{Navigability} % \begin{macro}{\umlNavigability} % A specialized version of "\umlAssociationEnd". % Takes two arguments: a list of named options, and the relation reference. % \begin{macrocode} \newcommand\umlNavigability[2][]{ \def\umlEndSymbol{\psline% (-1ex, -1.618ex)% (0,0)% (1ex, -1.618ex)}% \umlSymbol[#1]{#2}{\umlEndSymbol}% } % \end{macrocode} % \end{macro} % \begin{macro}{\umlNavigabilityA} % "\umlNavigabilityA" and "\umlNavigabilityB" are % provided for convenience and backward compatibility. % \begin{macrocode} \newcommand\umlNavigabilityA[2][]{\umlNavigability[#1,pos=A]{#2}} \newcommand\umlNavigabilityB[2][]{\umlNavigability[#1,pos=B]{#2}} % \end{macrocode} % \end{macro} % % \begin{macro}{\umlAEFixPosLabel} % % This sets a number of attributes of "\umlSymbol" based on % % "\umlAEPos" (set by "pos="). % % This has to be compatible with the settings in "\umlLabel" % % itself. % % \begin{macrocode} % \newcommand\umlAEFixPosLabel{% % % \end{macrocode} % % "From" given as argument % % \begin{macrocode} % \def\umlAEPosTmp{From}% % \ifx\umlAEPos\umlAEPosTmp% % \def\umlAENoderefClose{Aa}% % \def\umlAENoderefFar{Ab}% % \def\umlAEPos{0}% % \def\umlAEPosAngle{:L}% % \def\umlAERefpoint{t}% % \fi% % % \end{macrocode} % % "A" given as argument % % \begin{macrocode} % \def\umlAEPosTmp{A}% % \ifx\umlAEPos\umlAEPosTmp% % \def\umlAENoderefClose{Aa}% % \def\umlAENoderefFar{Ab}% % \def\umlAEPos{0}% % \def\umlAEPosAngle{:L}% % \def\umlAERefpoint{t}% % \fi% % % \end{macrocode} % % "To" given as argument % % \begin{macrocode} % \def\umlAEPosTmp{To}% % \ifx\umlAEPos\umlAEPosTmp% % \def\umlAENoderefClose{Ba}% % \def\umlAENoderefFar{Bb}% % \def\umlAEPos{0}% % \def\umlAEPosAngle{:L}% % \def\umlAERefpoint{t}% % \fi% % % \end{macrocode} % % "B" given as argument % % \begin{macrocode} % \def\umlAEPosTmp{B}% % \ifx\umlAEPos \umlAEPosTmp% % \def\umlAENoderefClose{Ba}% % \def\umlAENoderefFar{Bb}% % \def\umlAEPos{0}% % \def\umlAEPosAngle{:L}% % \def\umlAERefpoint{t}% % \fi% % } % % \end{macrocode} % % \end{macro} %\clearpage