diff --git a/.github/workflows/draft-joss-paper.yml b/.github/workflows/draft-joss-paper.yml new file mode 100644 index 000000000..56f5f3ddc --- /dev/null +++ b/.github/workflows/draft-joss-paper.yml @@ -0,0 +1,40 @@ +name: Draft JOSS paper + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + paper: + runs-on: ubuntu-latest + name: JOSS paper draft + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + repository: ${{ github.event.pull_request.head.repo.full_name }} + ref: ${{ github.event.pull_request.head.ref }} + + - name: Build draft PDF + uses: openjournals/openjournals-draft-action@master + with: + journal: joss + # This should be the path to the paper within your repo. + paper-path: joss/paper.md + + - name: Upload PDF + uses: actions/upload-artifact@v4 + with: + name: paper + # This is the output path where Pandoc will write the compiled + # PDF. Note, this should be the same directory as the input + # paper.md + path: joss/paper.pdf + + - name: Commit PDF to repository + uses: EndBug/add-and-commit@v9 + with: + message: '(auto) paper draft [skip ci]' + add: 'joss/paper.pdf' \ No newline at end of file diff --git a/joss/figures/tikz-uml.sty b/joss/figures/tikz-uml.sty new file mode 100755 index 000000000..0a30ccb58 --- /dev/null +++ b/joss/figures/tikz-uml.sty @@ -0,0 +1,5378 @@ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Start of tikz-uml.sty +% +% Some macros for UML Diagrams. +% Home page of project : +% Author: Nicolas Kielbasiewicz +% Style from : +% Fixed by Nicolas Kielbasiewicz (nicolas.kielbasiewicz@ensta-paristech.fr) in march 2016 to compile with pgf 3.00 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\NeedsTeXFormat{LaTeX2e}[1995/12/01]% +\ProvidesPackage{tikz-uml}[2011/01/26]% +% +\RequirePackage{ifthen}% +\RequirePackage{tikz}% +\RequirePackage{xstring}% +\RequirePackage{calc}% +\RequirePackage{pgfopts}% +\usetikzlibrary{backgrounds,arrows,shapes,fit,shadows,decorations.markings}% +% +\def\tikzumlPackageLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, packageLayers/.store in=\tikzumlPackageLayersNum}% +\def\tikzumlStateLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, stateLayers/.store in=\tikzumlStateLayersNum}% +\def\tikzumlFragmentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, fragmentLayers/.store in=\tikzumlFragmentLayersNum}% +\def\tikzumlComponentLayersNum{3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.initial=3}% +\pgfkeys{/tikzuml/options/.cd, componentLayers/.store in=\tikzumlComponentLayersNum}% +% +\ProcessPgfOptions{/tikzuml/options}% +% +\def\pgfsetlayersArg{background}% +\pgfdeclarelayer{background}% +\newcounter{tikzumlPackageLayers}% +\loop \pgfdeclarelayer{package\thetikzumlPackageLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,package\thetikzumlPackageLayers}% + \ifnum\tikzumlPackageLayersNum>\thetikzumlPackageLayers% + \stepcounter{tikzumlPackageLayers}% +\repeat% +% +\newcounter{tikzumlFragmentLayers}% +\loop \pgfdeclarelayer{fragment\thetikzumlFragmentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,fragment\thetikzumlFragmentLayers}% + \ifnum\tikzumlFragmentLayersNum>\thetikzumlFragmentLayers% + \stepcounter{tikzumlFragmentLayers}% +\repeat% +% +\newcounter{tikzumlStateLayers}% +\loop \pgfdeclarelayer{state\thetikzumlStateLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,state\thetikzumlStateLayers}% + \ifnum\tikzumlStateLayersNum>\thetikzumlStateLayers% + \stepcounter{tikzumlStateLayers}% +\repeat% +% +\newcounter{tikzumlComponentLayers}% +\loop \pgfdeclarelayer{component\thetikzumlComponentLayers}% + \xdef\pgfsetlayersArg{\pgfsetlayersArg,component\thetikzumlComponentLayers}% + \ifnum\tikzumlComponentLayersNum>\thetikzumlComponentLayers% + \stepcounter{tikzumlComponentLayers}% +\repeat% +% +\pgfdeclarelayer{lifelines}% +\pgfdeclarelayer{activity}% +\pgfdeclarelayer{connections}% +\xdef\pgfsetlayersArg{\pgfsetlayersArg,lifelines,activity,connections,main}% +\pgfsetlayers{\pgfsetlayersArg}% +% +\definecolor{myblue}{RGB}{51,102,153} + +\pgfkeys{/tikzuml/.cd, text/.initial=black, draw/.initial=black, font/.initial=\small,% + x/.initial=0, y/.initial=0,% + package type/.initial=tikzumlEmpty, fill package/.initial=blue!20,% + class width/.initial=10ex, simple interface width/.initial=4ex, class type/.initial=class, fill class/.initial=white, fill template/.initial=blue!2,% + narynode width/.initial=6ex,% + relation geometry/.initial=--, relation angle1/.initial=-30, relation angle2/.initial=30, relation loopsize/.initial=3em, relation weight/.initial=0.5, relation pos1/.initial=0.2, relation pos2/.initial=0.8, relation pos stereo/.initial=0.5,% + note width/.initial=3cm, fill note/.initial=green!20,% + fill system/.initial=white,% + fill usecase/.initial=blue!20,% + actor below/.initial=0.5cm,% + state join width/.initial=3ex,% + state decision width/.initial=3ex,% + state initial width/.initial=5ex,% + state final width/.initial=5.5ex,% + state enter width/.initial=5ex,% + state exit width/.initial=5ex,% + state end width/.initial=5ex,% + state history width/.initial=5ex,% + state deep history width/.initial=5ex,% + state width/.initial=8ex, fill state/.initial=blue!20,% + object stereo/.initial=object, fill object/.initial=blue!20,% + call dt/.initial=tikzumlEmpty, call padding/.initial=2, call type/.initial=synchron, fill call/.initial=white,% + fragment type/.initial=opt, fragment inner xsep/.initial=1, fragment inner ysep/.initial=1, fill fragment/.initial= none,% + create call dt/.initial=4,% + component width/.initial=8ex, fill component/.initial= blue!20,% + required interface distance/.initial=2.5cm, required interface width/.initial=1em, required interface padding/.initial=1cm,% + provided interface distance/.initial=3cm, provided interface width/.initial=1em, provided interface padding/.initial=1cm,% + port width/.initial=1ex, fill port/.initial= blue!20,% + fill assembly connector/.initial= white,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in tikzuml global, invalid option \keyname}% + }% +}% +% +\pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,% + x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,% + package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,% + class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,% + narynode width/.get=\tikzumlNaryNodeDefaultWidth,% + relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,% + note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,% + fill system/.get=\tikzumlSystemDefaultFillColor,% + fill usecase/.get=\tikzumlUseCaseDefaultFillColor,% + actor below/.get=\tikzumlActorDefaultBelow,% + state join width/.get=\tikzumlStateJoinDefaultWidth,% + state decision width/.get=\tikzumlStateDecisionDefaultWidth,% + state initial width/.get=\tikzumlStateInitialDefaultWidth,% + state final width/.get=\tikzumlStateFinalDefaultWidth,% + state enter width/.get=\tikzumlStateEnterDefaultWidth,% + state exit width/.get=\tikzumlStateExitDefaultWidth,% + state end width/.get=\tikzumlStateEndDefaultWidth,% + state history width/.get=\tikzumlStateHistoryDefaultWidth,% + state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,% + state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,% + object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,% + call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,% + fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,% + create call dt/.get=\tikzumlCreateCallDefaultDT,% + component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,% + required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,% + provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,% + port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor% +}% +% +% utility : change default colors +\newcommand{\tikzumlset}[1]{% + \pgfkeys{/tikzuml/.cd,#1}% + \pgfkeys{/tikzuml/.cd, text/.get=\tikzumlDefaultTextColor, draw/.get=\tikzumlDefaultDrawColor, font/.get=\tikzumlDefaultFont,% + x/.get=\tikzumlDefaultX, y/.get=\tikzumlDefaultY,% + package type/.get=\tikzumlPackageDefaultType, fill package/.get=\tikzumlPackageDefaultFillColor,% + class width/.get=\tikzumlClassDefaultWidth, simple interface width/.get=\tikzumlSimpleInterfaceDefaultWidth, class type/.get=\tikzumlClassDefaultType, fill class/.get=\tikzumlClassDefaultFillColor, fill template/.get=\tikzumlClassTemplateFillColorDefaultFillColor,% + narynode width/.get=\tikzumlNaryNodeWidth,% + relation geometry/.get=\tikzumlRelationDefaultGeometry, relation angle1/.get=\tikzumlRelationDefaultAngleO, relation angle2/.get=\tikzumlRelationDefaultAngleT, relation loopsize/.get=\tikzumlRelationDefaultLoopSize, relation weight/.get=\tikzumlRelationDefaultWeight, relation pos1/.get=\tikzumlRelationDefaultPosO, relation pos2/.get=\tikzumlRelationDefaultPosT, relation pos stereo/.get=\tikzumlRelationDefaultPosStereo,% + note width/.get=\tikzumlNoteDefaultWidth, fill note/.get=\tikzumlNoteDefaultFillColor,% + fill system/.get=\tikzumlSystemDefaultFillColor,% + fill usecase/.get=\tikzumlUseCaseDefaultFillColor,% + actor below/.get=\tikzumlActorDefaultBelow,% + state join width/.get=\tikzumlStateJoinDefaultWidth,% + state decision width/.get=\tikzumlStateDecisionDefaultWidth,% + state initial width/.get=\tikzumlStateInitialDefaultWidth,% + state final width/.get=\tikzumlStateFinalDefaultWidth,% + state enter width/.get=\tikzumlStateEnterDefaultWidth,% + state exit width/.get=\tikzumlStateExitDefaultWidth,% + state end width/.get=\tikzumlStateEndDefaultWidth,% + state history width/.get=\tikzumlStateHistoryDefaultWidth,% + state deep history width/.get=\tikzumlStateDeepHistoryDefaultWidth,% + state width/.get=\tikzumlStateDefaultWidth, fill state/.get=\tikzumlStateDefaultFillColor,% + object stereo/.get=\tikzumlObjectDefaultStereo, fill object/.get=\tikzumlObjectDefaultFillColor,% + call dt/.get=\tikzumlCallDefaultDT, call padding/.get=\tikzumlCallDefaultPadding, call type/.get=\tikzumlCallDefaultType, fill call/.get=\tikzumlCallDefaultFillColor,% + fragment type/.get=\tikzumlFragmentDefaultType, fragment inner xsep/.get=\tikzumlFragmentDefaultXSep, fragment inner ysep/.get=\tikzumlFragmentDefaultYSep, fill fragment/.get=\tikzumlFragmentDefaultFillColor,% + create call dt/.get=\tikzumlCreateCallDT,% + component width/.get=\tikzumlComponentDefaultWidth, fill component/.get=\tikzumlComponentDefaultFillColor,% + required interface distance/.get=\tikzumlRequiredInterfaceDefaultDistance, required interface width/.get=\tikzumlRequiredInterfaceDefaultWidth, required interface padding/.get=\tikzumlRequiredInterfaceDefaultPadding,% + provided interface distance/.get=\tikzumlProvidedInterfaceDefaultDistance, provided interface width/.get=\tikzumlProvidedInterfaceDefaultWidth, provided interface padding/.get=\tikzumlProvidedInterfaceDefaultPadding,% + port width/.get=\tikzumlPortDefaultWidth, fill port/.get=\tikzumlPortDefaultFillColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorDefaultFillColor% + }% +}% +% +% define a point +% arg : node/coordinates of the point +\newcommand{\umlpoint}[1]{% + \begin{pgfonlayer}{connections}% + \node[tikzuml control nodes style] at (#1) {};% + \end{pgfonlayer}% +}% +% +\newcommand{\tikzumlskipescape}[3][_]{% +\begingroup% + \def\_{#1}\edef\x{\endgroup% + \def\noexpand\csname #3\endcsname{#2}}\x% +}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% class diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\pgfkeys{/tikzuml/relation/.cd, attr1/.style args={#1|#2}{arg1=#1, mult1=#2},% + attr2/.style args={#1|#2}{arg2=#1, mult2=#2},% + attr/.style args={#1|#2}{arg=#1, mult=#2},% + recursive/.style args={#1|#2|#3}{angle1=#1, angle2=#2, loopsize=#3},% + anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2},% + recursive direction/.style args={#1 to #2}{recursive direction start=#1, recursive direction end=#2}% +}% +% +\pgfkeys{/tikzuml/note/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% +% +\tikzstyle{tikzuml simpleclass style}=[rectangle, minimum height=2em, node distance=2em]% +\tikzstyle{tikzuml simpleinterface style}=[circle, minimum height=1em, node distance=1em]% +\tikzstyle{tikzuml class style}=[rectangle split, rectangle split parts=3, rectangle split part align={center, left, left}, minimum height=2em, node distance=2em]% +\tikzstyle{tikzuml narynode style}=[diamond]% +\tikzstyle{tikzuml template style}=[dashed, inner ysep=0.5em, inner xsep=1ex]% +\tikzstyle{tikzuml control nodes style}=[fill=black, inner sep=1.5pt, circle]% +% +\tikzstyle{tikzuml association style}=[color=\tikzumlDefaultDrawColor, -]% +\tikzstyle{tikzuml bidirectional association style}=[color=\tikzumlDefaultDrawColor, angle45-angle45]% +\tikzstyle{tikzuml unidirectional association style}=[color=\tikzumlDefaultDrawColor, -angle 45]% +\tikzstyle{tikzuml aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-]% +\tikzstyle{tikzuml unidirectional aggregation style}=[color=\tikzumlDefaultDrawColor, open diamond-angle 45]% +\tikzstyle{tikzuml composition style}=[color=\tikzumlDefaultDrawColor, diamond-]% +\tikzstyle{tikzuml unidirectional composition style}=[color=\tikzumlDefaultDrawColor, diamond-angle 45]% +\tikzstyle{tikzuml nesting style}=[color=\tikzumlDefaultDrawColor]% +\tikzstyle{tikzuml dependency style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]% +\tikzstyle{tikzuml import style}=[color=\tikzumlDefaultDrawColor, -angle 45, dashed]% +\tikzstyle{tikzuml inherit style}=[color=\tikzumlDefaultDrawColor, -open triangle 45]% +\tikzstyle{tikzuml implements style}=[color=\tikzumlDefaultDrawColor, -open triangle 45, dashed]% +% +\pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, anchors/.style args={#1 and #2}{anchor1=#1, anchor2=#2}}% +% +\newcounter{tikzumlPackageClassNum}% +\newcounter{tikzumlPackageSubPackageNum}% +\newcounter{tikzumlRelationNum}% +\setcounter{tikzumlRelationNum}{1}% +\newcounter{tikzumlNoteNum}% +\setcounter{tikzumlNoteNum}{1}% +% +\newcounter{pos}% +\newcounter{posT}% +\newcounter{posStereo}% +% +\newcounter{tikzumlPackageLevel}% +\setcounter{tikzumlPackageLevel}{0}% +% +\newif\iftikzumlpackageSimpleStyle% +\newif\iftikzumlclassSimpleStyle% +\newif\iftikzumlclassCircleShape% +\newif\iftikzumlpackageWithoutCoords% +\newif\iftikzumlclassWithoutCoords% +\newif\iftikzumlassocclassWithoutCoords% +\newif\iftikzumlnoteWithoutCoords% +% +% define a uml package +% arg : package name +% optional : x, y: coordinates of the package +% type: stereotype of the package +% name: name of the package node +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the package position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newenvironment{umlpackage}[2][]{% + \pgfkeys{/tikzuml/package/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, style/.style={},% + name/.initial=tikzumlEmpty, type/.initial=\tikzumlPackageDefaultType, draw/.initial=\tikzumlDefaultDrawColor,% + fill/.initial=\tikzumlPackageDefaultFillColor, text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlpackageWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/package/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/package/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlpackage, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/package/.cd, #1}% + \pgfkeys{/tikzuml/package/.cd, x/.get=\tikzumlPackageXShift, y/.get=\tikzumlPackageYShift, name/.get=\tikzumlPackageName, type/.get=\tikzumlPackageTypeTmp,% + draw/.get=\tikzumlPackageDrawColor, fill/.get=\tikzumlPackageFillColor,% + text/.get=\tikzumlPackageTextColor% + }% + % + + % + \ifthenelse{\equal{\tikzumlPackageTypeTmp}{tikzumlEmpty}}{% + \def\tikzumlPackageType{}% + }{% + \expandafter\def\expandafter\tikzumlPackageType\expandafter{$\ll$\tikzumlPackageTypeTmp$\gg$ \\}% + }% + % + \ifnum\thetikzumlPackageLevel>0% + \let\tikzumlPackage@nameold\tikzumlPackage@fitname% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \let\tikzumlPackage@parentold\tikzumlPackage@parent% + \edef\tikzumlPackage@parent{\tikzumlPackage@parentold @@\tikzumlPackage@nameold}% + \else% + \def\tikzumlPackage@parent{}% + \def\tikzumlPackage@name{#2}% + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@fitname{\tikzumlPackage@name}}\x% + \fi% + % + \let\tikzumlPackage@nodeNameold\tikzumlPackage@nodeName% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlPackage@nodeName{\tikzumlPackage@name}}\x% + % + \ifthenelse{\equal{\tikzumlPackageName}{tikzumlEmpty}}{}{% + \def\tikzumlPackage@nodeName{\tikzumlPackageName}% + }% + % + \StrSubstitute{\tikzumlPackage@nodeName}{.}{@POINT@}{\tikzumlPackage@nodeName}% + % + \expandafter\gdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{}% + % + \setcounter{tikzumlPackageClassNum}{0}% + \setcounter{tikzumlPackageSubPackageNum}{0}% + \stepcounter{tikzumlPackageLevel}% + % + \begin{scope}[xshift=\tikzumlPackageXShift cm, yshift=\tikzumlPackageYShift cm]% +}{% + \addtocounter{tikzumlPackageLevel}{-1}% + \begin{pgfonlayer}{package\thetikzumlPackageLevel}% + % + % if contains no class, and not simple, one define a fictive node to enable the fit option + \ifnum\c@tikzumlPackageClassNum=0% + \ifnum\c@tikzumlPackageSubPackageNum=0% + \iftikzumlpackageWithoutCoords% + \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) {\phantom{\tikzumlPackage@nodeName}};% + \else% + \node[inner sep=1.5ex, /tikzuml/package/style] (\tikzumlPackage@nodeName-root) at (0,0) {\phantom{\tikzumlPackage@nodeName}};% + \fi% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{(\tikzumlPackage@nodeName-root)}% + \fi% + \fi% + % + \ifnum\c@tikzumlPackageLevel>0% + \def\tikzumlPackageFitTmp{\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent\endcsname{\tikzumlPackageFitTmp (\tikzumlPackage@nodeName) (\tikzumlPackage@nodeName-caption)}% + \stepcounter{tikzumlPackageSubPackageNum}% + \fi% + % + \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, inner sep=1.5ex, /tikzuml/package/style, fit = \csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname] (\tikzumlPackage@nodeName) {};% + \node[draw=\tikzumlPackageDrawColor, fill=\tikzumlPackageFillColor, text=\tikzumlPackageTextColor, font=\tikzumlDefaultFont, minimum height=1.5em, outer ysep=-0.3, anchor=south west] (\tikzumlPackage@nodeName-caption) at (\tikzumlPackage@nodeName.north west) {\begin{tabular}{c} \tikzumlPackageType \textbf{\tikzumlPackage@name}\end{tabular}};% + \end{pgfonlayer}% + \end{scope}% +}% +% +% shortcut to define an empty package +\newcommand{\umlemptypackage}[2][]{\begin{umlpackage}[#1]{#2} \end{umlpackage}}% +% +% define a uml class +% args : name of the class +% attributes of the class +% operations of the class +% optional : x, y: coordinates of the class +% width: of the class node +% type: type of class (class, interface, typedef, enum) +% tags: tagged values of class +% template: template parameters +% simple: if used, class is empty and drawn with a rectangle +% circle: if used with simple, class is empty and drawn with a circle +% draw, fill, fill template, and text: colors +% style: to manage every default TikZ option +% no coords: to tell that the class position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlclass}[4][]{% + \pgfkeys{/tikzuml/class/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType,% + tags/.initial={}, style/.style={},% + template/.initial={}, name/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor,% + fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,% + fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + simple/.is if=tikzumlclassSimpleStyle, circle/.is if=tikzumlclassCircleShape, no coords/.is if=tikzumlclassWithoutCoords,% + simple=false, circle=false, no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/class/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/class/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlclass, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/class/.cd,#1}% + % + \iftikzumlclassSimpleStyle% + \iftikzumlclassCircleShape% + \pgfkeys{/tikzuml/class/.cd, width/.initial=\tikzumlSimpleInterfaceDefaultWidth}% + \fi% + \fi% + % + \pgfkeys{/tikzuml/class/.cd, x/.get=\tikzumlClassX, y/.get=\tikzumlClassY, width/.get=\tikzumlClassMinimumWidth,% + type/.get=\tikzumlClassTypeTmp, tags/.get=\tikzumlClassTagsTmp, template/.get=\tikzumlClassTemplateFillColorParam,% + name/.get=\tikzumlClassName,% + draw/.get=\tikzumlClassDrawColor, fill/.get=\tikzumlClassFillColor,% + text/.get=\tikzumlClassTextColor, fill template/.get=\tikzumlClassTemplateFillColor% + }% + % + \ifthenelse{\equal{\tikzumlClassTypeTmp}{class}\OR\equal{\tikzumlClassTypeTmp}{abstract}}{% + \def\tikzumlClassType{}% + }{% + \expandafter\def\expandafter\tikzumlClassType\expandafter{$\ll$\tikzumlClassTypeTmp$\gg$ \\}% + }% + % + \ifthenelse{\equal{\tikzumlClassTagsTmp}{}}{% + \def\tikzumlClassTags{}% + }{% + \def\tikzumlClassTags{\\ \{\tikzumlClassTagsTmp\}}% + }% + % + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \def\tikzumlClassVPadding{}% + \def\tikzumlClassHPadding{}% + }{% + \def\tikzumlClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlClassName{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + \ifthenelse{\equal{\tikzumlClassName}{tikzumlEmpty}}{}{% + \def\tikzumlClassNodeName{\tikzumlClassName}% + }% + % + \StrSubstitute{\tikzumlClassNodeName}{:}{@COLON@}[\tikzumlClassNodeName]% + \StrSubstitute{\tikzumlClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlClassNodeName]% + % + \ifthenelse{\equal{\tikzumlClassTypeTmp}{abstract}}{% + \let\tikzumlClassNameOld\tikzumlClassName% + \def\tikzumlClassName{{\it \tikzumlClassNameOld}}% + }{}% + % + \def\tikzumlClassPos{\tikzumlClassX,\tikzumlClassY}% + \def\tikzumlClassAttributes{#3}% + \def\tikzumlClassOperations{#4}% + % + \iftikzumlclassSimpleStyle% + \iftikzumlclassWithoutCoords% + \iftikzumlclassCircleShape% + \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {};% + \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \else% + \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \fi% + \else% + \iftikzumlclassCircleShape% + \node[tikzuml simpleinterface style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {}; + \node[anchor=south] (\tikzumlClassNodeName-label) at (\tikzumlClassNodeName.north){\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \else% + \node[tikzuml simpleclass style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + };% + \fi% + \fi% + \else% + \iftikzumlclassWithoutCoords% + \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + \else% + \node[tikzuml class style, draw=\tikzumlClassDrawColor, fill=\tikzumlClassFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlClassMinimumWidth, /tikzuml/class/style] (\tikzumlClassNodeName) at (\tikzumlClassPos) {\begin{tabular}{c}\tikzumlClassVPadding \tikzumlClassType \tikzumlClassHPadding \textbf{\tikzumlClassName} \tikzumlClassHPadding \tikzumlClassTags \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlClassOperations% + \end{tabular}% + };% + \fi% + \fi% + % + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{}{% + \draw (\tikzumlClassNodeName.north east) node[tikzuml template style, name=\tikzumlClassNodeName-template, draw=\tikzumlClassDrawColor, fill=\tikzumlClassTemplateFillColor, text=\tikzumlClassTextColor, font=\tikzumlDefaultFont] {\tikzumlClassTemplateFillColorParam};% + }% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlClassTemplateFillColorParam}{}}{% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName)}% + }{% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlClassNodeName) (\tikzumlClassNodeName-template)}% + }% + \stepcounter{tikzumlComponentSubComponentNum}% + \fi% +}% +% +% shortcuts for interface, enum and typedef environments +\newcommand{\umlabstract}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlabstract, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=abstract,#1]{#2}{#3}{#4}% +}% +\newcommand{\umlinterface}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlinterface, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=interface,#1]{#2}{#3}{#4}% +}% +\newcommand{\umltypedef}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umltypedef, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=typedef,#1]{#2}{#3}{#4}% +}% +\newcommand{\umlenum}[4][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{type}}{% + \errmessage{TIKZUML ERROR : in umlenum, forbidden option type}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlclass[type=enum,#1]{#2}{#3}{#4} +}% +% +% shortcut to define an empty class +\newcommand{\umlemptyclass}[2][]{\umlclass[#1]{#2}{}{}}% +\newcommand{\umlsimpleclass}[2][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{simple}}{% + \errmessage{TIKZUML ERROR : in umlsimpleclass, forbidden option simple}% + }{}% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlemptyclass[simple, #1]{#2}% +}% +% +\newcommand{\umlsimpleinterface}[2][]{% + \pgfkeys{/tikzuml/class/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{simple}}{% + \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option simple}% + }{% + \ifthenelse{\equal{\keyname}{circle}}{% + \errmessage{TIKZUML ERROR : in umlsimpleinterface, forbidden option circle}% + }{}% + }% + }% + }% + \pgfkeys{/tikzuml/class/.cd, #1}% + \umlsimpleclass[circle, #1]{#2}% +}% +% underline the text for static arg +\newcommand{\umlstatic}[1]{\underline{#1}}% +\newcommand{\umlvirt}[1]{\textit{#1}}% +% +% define node for n-ary association +\newcommand{\umlNarynode}[2][]{% + \def\tikzumlNaryNodeAnchor{.north} + \def\tikzumlNaryNodeLabelPos{above} + \pgfkeys{/tikzuml/narynode/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNaryNodeDefaultWidth, name/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}}{% + \def\tikzumlNaryNodeAnchor{.north}% + \def\tikzumlNaryNodeLabelPos{above}% + }{% + \ifthenelse{\equal{\keyname}{above left}}{% + \def\tikzumlNaryNodeAnchor{.north west}% + \def\tikzumlNaryNodeLabelPos{above left}% + }{% + \ifthenelse{\equal{\keyname}{left}}{% + \def\tikzumlNaryNodeAnchor{.west}% + \def\tikzumlNaryNodeLabelPos{left}% + }{% + \ifthenelse{\equal{\keyname}{below left}}{% + \def\tikzumlNaryNodeAnchor{.south west}% + \def\tikzumlNaryNodeLabelPos{below left}% + }{% + \ifthenelse{\equal{\keyname}{below}}{% + \def\tikzumlNaryNodeAnchor{.south}% + \def\tikzumlNaryNodeLabelPos{below}% + }{% + \ifthenelse{\equal{\keyname}{below right}}{% + \def\tikzumlNaryNodeAnchor{.south east}% + \def\tikzumlNaryNodeLabelPos{below right}% + }{% + \ifthenelse{\equal{\keyname}{right}}{% + \def\tikzumlNaryNodeAnchor{.east}% + \def\tikzumlNaryNodeLabelPos{right}% + }{% + \ifthenelse{\equal{\keyname}{above right}}{% + \def\tikzumlNaryNodeAnchor{.north east}% + \def\tikzumlNaryNodeLabelPos{above right}% + }{% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/narynode/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlNarynode, invalid option \keyname}% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + \pgfkeys{/tikzuml/narynode/.cd,#1}% + \pgfkeys{/tikzuml/narynode/.cd, x/.get=\tikzumlNaryNodeX, y/.get=\tikzumlNaryNodeY, width/.get=\tikzumlNaryNodeMinimumWidth,% + name/.get=\tikzumlNaryNodeName,% + draw/.get=\tikzumlNaryNodeDrawColor, fill/.get=\tikzumlNaryNodeFillColor,% + text/.get=\tikzumlNaryNodeTextColor% + }% + % + \def\tikzumlNaryName{#2}% + % + \ifthenelse{\equal{\tikzumlNaryNodeName}{tikzumlEmpty}}{% + \edef\tikzumlNaryNodeName{\tikzumlNaryName}% + }{% + \edef\tikzumlNaryNodeName{\tikzumlNaryNodeName}% + }% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlNaryNode@nodeName{\tikzumlNaryNodeName}}\x% + % + \StrSubstitute{\tikzumlNaryNode@nodeName}{:}{@COLON@}[\tikzumlNaryNode@nodeName]% + \StrSubstitute{\tikzumlNaryNode@nodeName}{\_}{@UNDERSCORE@}[\tikzumlNaryNode@nodeName]% + % + \def\tikzumlNarynodePos{\tikzumlNaryNodeX,\tikzumlNaryNodeY}% + % + \node[tikzuml narynode style, draw=\tikzumlNaryNodeDrawColor, fill=\tikzumlNaryNodeFillColor, text=\tikzumlNaryNodeTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlNaryNodeMinimumWidth, minimum height=\tikzumlNaryNodeMinimumWidth, /tikzuml/narynode/style] (\tikzumlNaryNode@nodeName) at (\tikzumlNarynodePos) {};% + \draw (\tikzumlNaryNode@nodeName\tikzumlNaryNodeAnchor) node[\tikzumlNaryNodeLabelPos] {\tikzumlNaryName};% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlNaryNode@nodeName)}% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +\newdimen\tikzumlNestingSymbolSize% +% +% main command to define a relation between two classes +% args : src class +% dest class +% optional : geometry: geometry of the line +% weight: barycentric weight of the middle part when geometry is a 3-line +% arm1, arm2: lengths of first or last part when geometry id a 3-line +% arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation +% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation +% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation +% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation +% anchor1, anchor2: src/dest anchors on linked classes +% angle1, angle2, loopsize: start angle, end angle and size of the relation (only if recursive) +% stereo: stereotype of the relation +% pos stereo: position of the stereotype on the relation +% style: style of the relation (association, aggregation, composition, inherit, ...) +% name: rootname used for naming nodes of the relation +% recursive mode: type of recursive arrow (transition for state diagrams, or default) +% recursive direction start/end: when transition relation, start/end directions of the relation arrow +\newcommand{\umlrelation}[3][]{% + \pgfkeys{/tikzuml/relation/.cd, geometry/.initial=\tikzumlRelationDefaultGeometry, weight/.initial=\tikzumlRelationDefaultWeight,% + arm1/.initial=auto, arm2/.initial=auto,% + arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=\tikzumlRelationDefaultPosO, pos2/.initial=\tikzumlRelationDefaultPosT, pos/.initial=tikzumlEmpty,% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + angle1/.initial=\tikzumlRelationDefaultAngleO, angle2/.initial=\tikzumlRelationDefaultAngleT, loopsize/.initial=\tikzumlRelationDefaultLoopSize,% + stereo/.initial={}, pos stereo/.initial=\tikzumlRelationDefaultPosStereo,% + style/.initial=->, style2/.style={}, name/.initial=relation-\thetikzumlRelationNum,% + recursive mode/.initial=default, recursive direction start/.initial=right,% + recursive direction end/.initial=bottom,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}% + \OR\equal{\keyname}{interface}% + \OR\equal{\keyname}{padding}% + \OR\equal{\keyname}{width}% + \OR\equal{\keyname}{first arm}% + \OR\equal{\keyname}{second arm}% + \OR\equal{\keyname}{middle arm}% + \OR\equal{\keyname}{last arm}% + \OR\equal{\keyname}{distance}}{}{% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/relation/.cd, style2/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlrelation, invalid option \keyname}% + }% + }% + }% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, geometry/.get=\tikzumlRelationGeometry, weight/.get=\tikzumlRelationWeight,% + arm1/.get=\tikzumlRelationArmO, arm2/.get=\tikzumlRelationArmT,% + arg1/.get=\tikzumlRelationAttrName, arg2/.get=\tikzumlRelationAttrNameTO, arg/.get=\tikzumlRelationAttrNameTT,% + mult1/.get=\tikzumlRelationMultiplicity, mult2/.get=\tikzumlRelationMultiplicityTO, mult/.get=\tikzumlRelationMultiplicityTT,% + pos1/.get=\tikzumlRelationPosition, pos2/.get=\tikzumlRelationPositionTO, pos/.get=\tikzumlRelationPositionTT,% + align1/.get=\tikzumlRelationAlign, align2/.get=\tikzumlRelationAlignTO, align/.get=\tikzumlRelationAlignTT,% + anchor1/.get=\tikzumlRelationSrcAnchor, anchor2/.get=\tikzumlRelationDestAnchor,% + angle1/.get=\tikzumlRelationStartAngle, angle2/.get=\tikzumlRelationEndAngle, loopsize/.get=\tikzumlRelationLoopSize,% + stereo/.get=\tikzumlRelationStereoType, pos stereo/.get=\tikzumlRelationPositionStereotype,% + style/.get=\tikzumlRelationStyle, name/.get=\tikzumlRelationName,% + recursive mode/.get=\tikzumlRelationRecursiveMode,% + recursive direction start/.get=\tikzumlRelationRecursiveDirectionStart,% + recursive direction end/.get=\tikzumlRelationRecursiveDirectionEnd% + }% + % + \def\tikzumlSrcClassName{#2}% + % + % managing \_ in class names for node names + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]% + \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]% + % + \def\tikzumlDestClassName{#3}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]% + \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]% + % + % managing alias keys + \def\tikzumlRelationAttrNameT{\tikzumlRelationAttrNameTO\tikzumlRelationAttrNameTT}% + \def\tikzumlRelationMultiplicityT{\tikzumlRelationMultiplicityTO\tikzumlRelationMultiplicityTT}% + \def\tikzumlRelationAlignT{\tikzumlRelationAlignTO\tikzumlRelationAlignTT}% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \ifthenelse{\equal{\tikzumlRelationPositionTT}{tikzumlEmpty}}{% + \def\tikzumlRelationPositionT{\tikzumlRelationPositionTO}% + }{% + \def\tikzumlRelationPositionT{\tikzumlRelationPositionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\tikzumlRelationAlign}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\tikzumlRelationAlign}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\tikzumlRelationAlignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\tikzumlRelationAlignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\tikzumlRelationStereoType}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$\ll$\tikzumlRelationStereoType$\gg$}% + }% + + % def anchors macros + \ifthenelse{\equal{\tikzumlRelationSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlRelationSrcAnchor{}% + }{% + \let\tikzumlRelationSrcAnchorold\tikzumlRelationSrcAnchor% + \def\tikzumlRelationSrcAnchor{.\tikzumlRelationSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlRelationDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlRelationDestAnchor{}% + }{% + \let\tikzumlRelationDestAnchorold\tikzumlRelationDestAnchor% + \def\tikzumlRelationDestAnchor{.\tikzumlRelationDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\tikzumlRelationPosition}}% + \setcounter{posT}{100*\real{\tikzumlRelationPositionT}}% + \setcounter{posStereo}{100*\real{\tikzumlRelationPositionStereotype}}% + % + \pgfmathsetmacro{\tikzumlRelationWeightT}{1.0-\tikzumlRelationWeight}% + % + %\newcounter{tikzumlControlNodesNum}% + %\setcounter{tikzumlControlNodesNum}{0}% + % + \node[inner sep=0] (\tikzumlRelationName-middle) at (barycentric cs:\tikzumlSrcClassNodeName=\tikzumlRelationWeightT,\tikzumlDestClassNodeName=\tikzumlRelationWeight) {};% + % + % straight line + \ifthenelse{\equal{\tikzumlRelationGeometry}{--}}% + {% + \ifthenelse{\equal{\tikzumlSrcClassNodeName}{\tikzumlDestClassNodeName}}{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{default}}{% + \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize] \tikzumlLastArc% + node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} (\tikzumlDestClassNodeName) }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveMode}{transition}}{% + \xdef\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {}}% + \xdef\tikzumlMidOneArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {}}% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{% + \def\numArcs{3}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] % + node[midway, inner sep=0, name=\tikzumlRelationName-tmp, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-tmp) {};% + \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-tmp) {};% + }{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-tmp) {};% + \node[inner sep=0, name=\tikzumlRelationName-4] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-tmp) {};% + }% + \end{pgfonlayer}% + }{% + \def\numArcs{4}% + \xdef\tikzumlMidTwoArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {}}% + \xdef\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-7, anchor=center] {}}% + % + \begin{pgfonlayer}{connections}% + \draw (\tikzumlSrcClassNodeName) edge[in=\tikzumlRelationEndAngle, out=\tikzumlRelationStartAngle, distance=\tikzumlRelationLoopSize, draw=none] % + node[midway, name=\tikzumlRelationName-4, anchor=center] {} (\tikzumlDestClassNodeName);% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}\OR\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle -| \tikzumlRelationName-4) {};% + \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle |- \tikzumlRelationName-4) {};% + }{% + \node[inner sep=0, name=\tikzumlRelationName-2] at (\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle |- \tikzumlRelationName-4) {};% + \node[inner sep=0, name=\tikzumlRelationName-6] at (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle -| \tikzumlRelationName-4) {};% + }% + \end{pgfonlayer}% + }% + % + \ifnum\numArcs=4% + \ifnum\theposStereo>300% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype}}% + \fi% + \fi% + \fi% + % + \ifthenelse{\thepos=300\OR\thepos=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>300% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos>200% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\theposT=300\OR\theposT=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{bottom}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionEnd}{left}}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>300% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-300)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT>200% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \xdef\tikzumlMidTwoArc{\tikzumlMidTwoArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \fi% + \fi% + \fi% + \else% + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\thepos=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrName{above right}% + \def\posMultiplicity{below left}% + }{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\thepos>200% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \ifnum\thepos<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + }% + \fi% + \fi% + % + \ifthenelse{\theposT=100}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }% + }% + }% + }{}% + % + \ifthenelse{\theposT=200}{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{right}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{left}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }{% + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{top}}{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }% + }{% + \ifthenelse{\tikzumlRelationEndAngle<\tikzumlRelationStartAngle}{% + \def\posAttrNameT{above right}% + \def\posMultiplicityT{below left}% + }{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }% + }% + }% + }% + }{}% + % + \ifnum\theposT>200% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \ifnum\theposT<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + }% + \fi% + \fi% + \fi% + % + \ifthenelse{\equal{\tikzumlRelationRecursiveDirectionStart}{\tikzumlRelationRecursiveDirectionEnd}}{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5)}% + \fi% + }{% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName.\tikzumlRelationStartAngle) -- \tikzumlFirstArc (\tikzumlRelationName-2.center) -- \tikzumlMidOneArc (\tikzumlRelationName-4.center) -- \tikzumlMidTwoArc (\tikzumlRelationName-6.center) -- \tikzumlLastArc (\tikzumlDestClassNodeName.\tikzumlRelationEndAngle) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) (\tikzumlRelationName-6) (\tikzumlRelationName-7)}% + \fi% + }% + }{}% + }% + }{% + \def\arcNum{1}% + \def\arcNumT{1}% + % + \node[inner sep=0] (\tikzumlRelationName-1) at (\tikzumlRelationName-middle) {};% + \xdef\tikzumlLastArc{node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity}% + node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT}% + node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) }% + \fi% + }% + }{% + % first vertical then horizontal line + \ifthenelse{\equal{\tikzumlRelationGeometry}{|-}}% + {% + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center]{} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }% + \fi% + }{% + % first horizontal then vertical line + \ifthenelse{\equal{\tikzumlRelationGeometry}{-|}}% + {% + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center]{} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-3, anchor=center] {} }% + % + \begin{pgfonlayer}{connections}% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) }% + \fi% + }{% + % first vertical, then horizontal, finally vertical line + \ifthenelse{\equal{\tikzumlRelationGeometry}{|-|}}% + {% + %\setcounter{tikzumlControlNodesNum}{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{ }% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{% + \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{% + \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor |- \tikzumlRelationName-3) {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(0,\tikzumlRelationArmT) node[inner sep=0, name=\tikzumlRelationName-4] {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 -| \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(0,\tikzumlRelationArmO) node[inner sep=0, name=\tikzumlRelationName-2] {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 -| \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }% + \fi% + }{% + % first horizontal, then vertical, finally horizontal line + \ifthenelse{\equal{\tikzumlRelationGeometry}{-|-}}% + {% + %\setcounter{tikzumlControlNodesNum}{2}% + % + \def\tikzumlFirstArc{node[midway, inner sep=0, name=\tikzumlRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, inner sep=0, name=\tikzumlRelationName-5, anchor=center] {} }% + \def\tikzumlMidOneArc{}% + % + \begin{pgfonlayer}{connections}% + % + \ifthenelse{\equal{\tikzumlRelationArmO}{auto}}{% + \ifthenelse{\equal{\tikzumlRelationArmT}{auto}}{% + \node[inner sep=0] (\tikzumlRelationName-3) at (\tikzumlRelationName-middle) {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor -| \tikzumlRelationName-3) {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-3 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + }{% + \draw (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor)+(\tikzumlRelationArmT,0) node[inner sep=0, name=\tikzumlRelationName-4] {};% + \node[inner sep=0] (\tikzumlRelationName-2) at (\tikzumlRelationName-4 |- \tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + }{% + \draw (\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor)+(\tikzumlRelationArmO,0) node[inner sep=0, name=\tikzumlRelationName-2] {};% + \node[inner sep=0] (\tikzumlRelationName-4) at (\tikzumlRelationName-2 |- \tikzumlDestClassNodeName\tikzumlRelationDestAnchor) {};% + \node[inner sep=0] (\tikzumlRelationName-3) at (barycentric cs:\tikzumlRelationName-2=0.5,\tikzumlRelationName-4=0.5) {};% + }% + \end{pgfonlayer}% + % + \ifnum\theposStereo>200% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-200)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \ifnum\theposStereo<100% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \pgfmathsetmacro{\tikzumlRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + \fi% + % + \ifthenelse{\thepos=200\OR\thepos=100}{% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + }{}% + % + \ifthenelse{\thepos>200}{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-200)/100}% + \def\arcNum{3}% + }{% + \ifthenelse{\thepos<100}{% + \def\arcNum{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + }% + }% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + \ifnum\arcNum=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPosition, \posAttrName, \attrAlign] {\tikzumlRelationAttrName}% + node[pos=\tikzumlRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlRelationMultiplicity} }% + \fi% + % + \ifthenelse{\theposT=200\OR\theposT=100}{% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + }{}% + % + \ifthenelse{\theposT>200}{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-200)/100}% + \def\arcNumT{3}% + }{% + \ifthenelse{\theposT<100}{% + \def\arcNumT{1}% + }{% + \pgfmathsetmacro{\tikzumlRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + }% + }% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlMidOneArc{\tikzumlMidOneArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=3% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlRelationAttrNameT}% + node[pos=\tikzumlRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlRelationName-2.base) -- \tikzumlMidOneArc (\tikzumlRelationName-4.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlRelationDestAnchor) }% + \ifnum\thetikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitTmp (\tikzumlRelationName-1) (\tikzumlRelationName-2) (\tikzumlRelationName-3) (\tikzumlRelationName-4) (\tikzumlRelationName-5) }% + \fi% + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlRelationStyle}{tikzuml nesting style}}{% + \pgfarrowsdeclare{nested}{nested}{...} + { + \tikzumlNestingSymbolSize=0.2pt% + \advance\tikzumlNestingSymbolSize by .5\pgflinewidth% + \pgfsetdash{}{0pt} % do not dash + \pgfsetroundjoin % fix join + \pgfsetroundcap % fix cap + \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}% + \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}% + \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}% + \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}% + \pgfusepathqstroke% + }% + \draw[auto, nested-, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;% + }{ + \draw[auto, font=\tikzumlDefaultFont, \tikzumlRelationStyle, /tikzuml/relation/style2] \tikzumlPath ;% + } + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% +% +% shortcuts of \umlrelation +\newcommand{\umlHVrelation}[3][]{% + \pgfkeys{/tikzuml/HVrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVrelation/.cd, #1}% + \umlrelation[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHrelation}[3][]{% + \pgfkeys{/tikzuml/VHrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHrelation/.cd, #1}% + \umlrelation[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHrelation}[3][]{% + \pgfkeys{/tikzuml/HVHrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHrelation/.cd, #1}% + \umlrelation[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVrelation}[3][]{% + \pgfkeys{/tikzuml/VHVrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVrelation, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVrelation/.cd, #1}% + \umlrelation[geometry=|-|, #1]{#2}{#3}% +}% +% +% +% shortcuts for relations +\newcommand{\umlinherit}[3][]{\umlrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlimpl}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlreal}[3][]{\umlrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlassoc}[3][]{\umlrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlbiassoc}[3][]{\umlrelation[style={tikzuml bidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umluniassoc}[3][]{\umlrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlaggreg}[3][]{\umlrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umluniaggreg}[3][]{\umlrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlcompo}[3][]{\umlrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlunicompo}[3][]{\umlrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlimport}[3][]{\umlrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlnest}[3][]{\umlrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umldep}[3][]{\umlrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlfriend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVinherit}[3][]{\umlHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVimpl}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVreal}[3][]{\umlHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVassoc}[3][]{\umlHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniassoc}[3][]{\umlHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVaggreg}[3][]{\umlHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVuniaggreg}[3][]{\umlHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVcompo}[3][]{\umlHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVunicompo}[3][]{\umlHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVimport}[3][]{\umlHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVnest}[3][]{\umlHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlHVdep}[3][]{\umlHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHinherit}[3][]{\umlVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHimpl}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHreal}[3][]{\umlVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHassoc}[3][]{\umlVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniassoc}[3][]{\umlVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHaggreg}[3][]{\umlVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHuniaggreg}[3][]{\umlVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHcompo}[3][]{\umlVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHunicompo}[3][]{\umlVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHimport}[3][]{\umlVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHnest}[3][]{\umlVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlVHdep}[3][]{\umlVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHinherit}[3][]{\umlHVHrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimpl}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHreal}[3][]{\umlHVHrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlHVHassoc}[3][]{\umlHVHrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniassoc}[3][]{\umlHVHrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlHVHaggreg}[3][]{\umlHVHrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHuniaggreg}[3][]{\umlHVHrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlHVHcompo}[3][]{\umlHVHrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHunicompo}[3][]{\umlHVHrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHimport}[3][]{\umlHVHrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlHVHnest}[3][]{\umlHVHrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlHVHdep}[3][]{\umlHVHrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlHVHfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVinherit}[3][]{\umlVHVrelation[style={tikzuml inherit style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimpl}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVreal}[3][]{\umlVHVrelation[style={tikzuml implements style}, #1]{#2}{#3}}% +\newcommand{\umlVHVassoc}[3][]{\umlVHVrelation[style={tikzuml association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniassoc}[3][]{\umlVHVrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}}% +\newcommand{\umlVHVaggreg}[3][]{\umlVHVrelation[style={tikzuml aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVuniaggreg}[3][]{\umlVHVrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}}% +\newcommand{\umlVHVcompo}[3][]{\umlVHVrelation[style={tikzuml composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVunicompo}[3][]{\umlVHVrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVimport}[3][]{\umlVHVrelation[style={tikzuml import style}, #1]{#2}{#3}}% +\newcommand{\umlVHVnest}[3][]{\umlVHVrelation[style={tikzuml nesting style}, #1]{#2}{#3}}% +\newcommand{\umlVHVdep}[3][]{\umlVHVrelation[style={tikzuml dependency style}, #1]{#2}{#3}}% +\newcommand{\umlVHVfriend}[3][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVfriend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +% define a node +\newcommand{\umlnode}[2]{% + \node (#2) at (#1) {};% +}% +% +% main command to define a relation between two classes through a control node +% args : src class +% control node +% dest class +% optional : arg1, arg2, arg: name of the src/dest/dest side class type attribute defined by the relation +% mult1, mult2, mult: multiplicity of the src/dest/dest side class type attribute defined by the relation +% pos1, pos2, pos: position of the src/dest/dest side class type attribute defined by the relation +% align1, align2, align: text justification of the src/dest/dest side class type attribute defined by the relation +% anchor1, anchor2: src/dest anchors on linked classes +% stereo: stereotype of the relation +% pos stereo: position of the stereotype on the relation +% style: style of the relation (association, aggregation, composition, inherit, ...) +% name: rootname used for naming nodes of the relation +\newcommand{\umlCNrelation}[4][]{% + \pgfkeys{/tikzuml/relation/.cd, arg1/.initial={}, arg2/.initial={}, arg/.initial={},% + mult1/.initial={}, mult2/.initial={}, mult/.initial={},% + pos1/.initial=0.2, pos2/.initial=0.8, pos/.initial=tikzumlEmpty,% + align1/.initial={}, align2/.initial={}, align/.initial={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + stereo/.initial={}, pos stereo/.initial=1,% + style/.initial=->, name/.initial=relation-\thetikzumlRelationNum,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlCNrelation, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/relation/.cd,#1}% + \pgfkeys{/tikzuml/relation/.cd, arg1/.get=\tikzumlCNRelationAttrName, arg2/.get=\tikzumlCNRelationAttrNameTO, arg/.get=\tikzumlCNRelationAttrNameTT,% + mult1/.get=\tikzumlCNRelationMultiplicity, mult2/.get=\tikzumlCNRelationMultiplicityTO, mult/.get=\tikzumlCNRelationMultiplicityTT,% + pos1/.get=\tikzumlCNRelationPosition, pos2/.get=\tikzumlCNRelationPositionTO, pos/.get=\tikzumlCNRelationPositionTT,% + align1/.get=\tikzumlCNRelationAlign, align2/.get=\tikzumlCNRelationAlignTO, align/.get=\tikzumlCNRelationAlignTT,% + anchor1/.get=\tikzumlCNRelationSrcAnchor, anchor2/.get=\tikzumlCNRelationDestAnchor,% + stereo/.get=\tikzumlCNRelationStereoType, pos stereo/.get=\tikzumlCNRelationPositionStereotype,% + style/.get=\tikzumlCNRelationStyle, name/.get=\tikzumlCNRelationName% + }% + % + % managing \_ in class names for node names + \def\tikzumlSrcClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSrcClassNodeName{\tikzumlSrcClassName}}\x% + % + \StrSubstitute{\tikzumlSrcClassNodeName}{:}{@COLON@}[\tikzumlSrcClassNodeName]% + \StrSubstitute{\tikzumlSrcClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlSrcClassNodeName]% + % + \def\tikzumlDestClassName{#4}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlDestClassNodeName{\tikzumlDestClassName}}\x% + % + \StrSubstitute{\tikzumlDestClassNodeName}{:}{@COLON@}[\tikzumlDestClassNodeName]% + \StrSubstitute{\tikzumlDestClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlDestClassNodeName]% + % + % managing alias keys + \def\tikzumlCNRelationAttrNameT{\tikzumlCNRelationAttrNameTO\tikzumlCNRelationAttrNameTT}% + \def\tikzumlCNRelationMultiplicityT{\tikzumlCNRelationMultiplicityTO\tikzumlCNRelationMultiplicityTT}% + \def\tikzumlCNRelationAlignT{\tikzumlCNRelationAlignTO\tikzumlCNRelationAlignTT}% + \def\orientationT{\orientationTO\orientationTT}% + % + \ifthenelse{\equal{\tikzumlCNRelationPositionTT}{tikzumlEmpty}}{% + \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTO}% + }{% + \def\tikzumlCNRelationPositionT{\tikzumlCNRelationPositionTT}% + }% + % + \def\attrAlign{}% + \def\multAlign{}% + \def\attrAlignT{}% + \def\multAlignT{}% + % + \ifthenelse{\equal{\tikzumlCNRelationAlign}{left}}{% + \def\attrAlign{above right}% + \def\multAlign{below right}% + }{% + \ifthenelse{\equal{\tikzumlCNRelationAlign}{right}}{% + \def\attrAlign{above left}% + \def\multAlign{below left}% + }{}% + }% + % + \ifthenelse{\equal{\tikzumlCNRelationAlignT}{left}}{% + \def\attrAlignT{above right}% + \def\multAlignT{below right}% + }{% + \ifthenelse{\equal{\tikzumlCNRelationAlignT}{right}}{% + \def\attrAlignT{above left}% + \def\multAlignT{below left}% + }{}% + }% + % + % def stereotype + \ifthenelse{\equal{\tikzumlCNRelationStereoType}{}}{% + \def\stereotype{}% + }{% + \def\stereotype{$\ll$\tikzumlCNRelationStereoType$\gg$}% + }% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlCNRelationSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlCNRelationSrcAnchor{}% + }{% + \let\tikzumlCNRelationSrcAnchorold\tikzumlCNRelationSrcAnchor% + \def\tikzumlCNRelationSrcAnchor{.\tikzumlCNRelationSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlCNRelationDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlCNRelationDestAnchor{}% + }{% + \let\tikzumlCNRelationDestAnchorold\tikzumlCNRelationDestAnchor% + \def\tikzumlCNRelationDestAnchor{.\tikzumlCNRelationDestAnchorold}% + }% + % + \setcounter{pos}{100*\real{\tikzumlCNRelationPosition}}% + \setcounter{posT}{100*\real{\tikzumlCNRelationPositionT}}% + \setcounter{posStereo}{100*\real{\tikzumlCNRelationPositionStereotype}}% + % + % straight line + %\setcounter{tikzumlControlNodesNum}{1}% + % + \def\tikzumlFirstArc{node[midway, name=\tikzumlCNRelationName-1, anchor=center] {} }% + \def\tikzumlLastArc{node[midway, name=\tikzumlCNRelationName-3, anchor=center]{} }% + \def\posAttrName{}% + \def\posMultiplicity{}% + \def\posAttrNameT{}% + \def\posMultiplicityT{}% + % + \begin{pgfonlayer}{connections}% + \node (\tikzumlCNRelationName-2) at (#3) {};% + \end{pgfonlayer}% + % + \ifnum\theposStereo>100% + \pgfmathsetmacro{\tikzumlCNRelationPositionStereotype}{(\theposStereo-100)/100}% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }% + \else% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionStereotype, anchor=center] {\stereotype} }% + \fi% + % + \ifnum\thepos>100% + \pgfmathsetmacro{\tikzumlCNRelationPosition}{(\thepos-100)/100}% + \def\arcNum{2}% + \else% + \def\arcNum{1}% + \ifnum\thepos=100% + \def\posAttrName{above left}% + \def\posMultiplicity{below right}% + \fi% + \fi% + % + \ifnum\arcNum=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}% + node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }% + \fi% + \ifnum\arcNum=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPosition, \posAttrName, \attrAlign] {\tikzumlCNRelationAttrName}% + node[pos=\tikzumlCNRelationPosition, swap, \posMultiplicity, \multAlign] {\tikzumlCNRelationMultiplicity} }% + \fi% + % + \ifnum\theposT>100% + \pgfmathsetmacro{\tikzumlCNRelationPositionT}{(\theposT-100)/100}% + \def\arcNumT{2}% + \else% + \def\arcNumT{1}% + \ifnum\theposT=100% + \def\posAttrNameT{above left}% + \def\posMultiplicityT{below right}% + \fi% + \fi% + % + \ifnum\arcNumT=1% + \xdef\tikzumlFirstArc{\tikzumlFirstArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}% + node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }% + \fi% + \ifnum\arcNumT=2% + \xdef\tikzumlLastArc{\tikzumlLastArc node[pos=\tikzumlCNRelationPositionT, \posAttrNameT, \attrAlignT] {\tikzumlCNRelationAttrNameT}% + node[pos=\tikzumlCNRelationPositionT, swap, \posMultiplicityT, \multAlignT] {\tikzumlCNRelationMultiplicityT} }% + \fi% + % + \xdef\tikzumlPath{(\tikzumlSrcClassNodeName\tikzumlCNRelationSrcAnchor) -- \tikzumlFirstArc (\tikzumlCNRelationName-2.base) -- \tikzumlLastArc (\tikzumlDestClassNodeName\tikzumlCNRelationDestAnchor) }% + + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlCNRelationStyle}{tikzuml nesting style}}{% + \pgfarrowsdeclare{nested}{nested}{...} + { + \tikzumlNestingSymbolSize=0.2pt% + \advance\tikzumlNestingSymbolSize by .5\pgflinewidth% + \pgfsetdash{}{0pt} % do not dash + \pgfsetroundjoin % fix join + \pgfsetroundcap % fix cap + \pgfpathmoveto{\pgfpoint{-16*\tikzumlNestingSymbolSize}{0pt}}% + \pgfpatharc{180}{90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{90}{0}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{0}{-90}{8*\tikzumlNestingSymbolSize}% + \pgfpatharc{-90}{-180}{8*\tikzumlNestingSymbolSize}% + \pgfpathmoveto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{8*\tikzumlNestingSymbolSize}}% + \pgfpathlineto{\pgfpoint{-8*\tikzumlNestingSymbolSize}{-8*\tikzumlNestingSymbolSize}}% + \pgfusepathqstroke% + }% + \draw[auto, \tikzumlCNRelationStyle, nested-, font=\tikzumlDefaultFont] \tikzumlPath ;% + }{ + \draw[auto, \tikzumlCNRelationStyle, font=\tikzumlDefaultFont] \tikzumlPath ;% + } + \end{pgfonlayer}% + % + \stepcounter{tikzumlRelationNum}% +}% +% +% shortcuts for cnrelations +\newcommand{\umlCNinherit}[4][]{\umlCNrelation[style={tikzuml inherit style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimpl}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNreal}[4][]{\umlCNrelation[style={tikzuml implements style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNassoc}[4][]{\umlCNrelation[style={tikzuml association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniassoc}[4][]{\umlCNrelation[style={tikzuml unidirectional association style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNaggreg}[4][]{\umlCNrelation[style={tikzuml aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNuniaggreg}[4][]{\umlCNrelation[style={tikzuml unidirectional aggregation style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNcompo}[4][]{\umlCNrelation[style={tikzuml composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNunicompo}[4][]{\umlCNrelation[style={tikzuml unidirectional composition style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNimport}[4][]{\umlCNrelation[style={tikzuml import style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNnest}[4][]{\umlCNrelation[style={tikzuml nesting style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNdep}[4][]{\umlCNrelation[style={tikzuml dependency style}, #1]{#2}{#3}{#4}}% +\newcommand{\umlCNfriend}[4][]{% + \pgfkeys{/tikzuml/friendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNfriend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/friendrelation/.cd, #1}% + \umlCNrelation[stereo=friend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +% +% define a note +% arg : attached class +% label of the note +% optional : x,y: coordinates of the note +% width: width of the note +% geometry: geometry of the relation between the note and what it is about +% weight: barycentric weight for a 3-line relation +% arm: length of the first arm +% anchor1, anchor2: anchors of the relation +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the note position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlNoteDefaultWidth,% + geometry/.initial=\tikzumlRelationDefaultGeometry,% + weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto, style/.style={},% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlNoteDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlnoteWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/note/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/note/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlnote, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/note/.cd, #1}% + \pgfkeys{/tikzuml/note/.cd, x/.get=\tikzumlNoteX, y/.get=\tikzumlNoteY, width/.get=\tikzumlNoteTextWidth,% + geometry/.get=\tikzumlNoteGeometry,% + weight/.get=\tikzumlNoteWeight, arm/.get=\tikzumlNoteArm,% + anchor1/.get=\tikzumlNoteSrcAnchor, anchor2/.get=\tikzumlNoteDestAnchor,% + draw/.get=\tikzumlNoteDrawColor, fill/.get=\tikzumlNoteFillColor,% + text/.get=\tikzumlNoteTextColor% + }% + % + \def\tikzumlClassName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlClassNodeName{\tikzumlClassName}}\x% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlNoteSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlNoteSrcAnchor{}% + }{% + \let\tikzumlNoteSrcAnchorold\tikzumlNoteSrcAnchor% + \def\tikzumlNoteSrcAnchor{.\tikzumlNoteSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlNoteDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlNoteDestAnchor{}% + }{% + \let\tikzumlNoteDestAnchorold\tikzumlNoteDestAnchor% + \def\tikzumlNoteDestAnchor{.\tikzumlNoteDestAnchorold}% + }% + % + \iftikzumlnoteWithoutCoords% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) {#3};% + \else% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, font=\tikzumlDefaultFont, outer sep=0, inner xsep=1ex, inner ysep=3ex, /tikzuml/note/style] (note-\thetikzumlNoteNum-coord) at (\tikzumlNoteX, \tikzumlNoteY) {#3};% + \fi% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-right-top, below=2ex, coordinate] {};% + \draw (note-\thetikzumlNoteNum-coord.north east) node[name=note-\thetikzumlNoteNum-top-right, left=2ex, coordinate] {};% + \draw[draw=\tikzumlNoteDrawColor, fill=\tikzumlNoteFillColor] (note-\thetikzumlNoteNum-coord.south west) -- (note-\thetikzumlNoteNum-coord.south east) -- (note-\thetikzumlNoteNum-right-top.base) -- (note-\thetikzumlNoteNum-top-right.base) -- (note-\thetikzumlNoteNum-coord.north west) -- cycle;% + \node[text=\tikzumlNoteTextColor, text width=\tikzumlNoteTextWidth, outer sep=0, inner xsep=1ex, inner ysep=3ex, font=\tikzumlDefaultFont] (note-\thetikzumlNoteNum) at (note-\thetikzumlNoteNum-coord) {#3};% + \draw[draw=\tikzumlNoteDrawColor] (note-\thetikzumlNoteNum-right-top) -| (note-\thetikzumlNoteNum-top-right);% + % + \pgfmathsetmacro{\tikzumlNoteWeightT}{1.0-\tikzumlNoteWeight}% + \node (note-\thetikzumlNoteNum-middle) at (barycentric cs:note-\thetikzumlNoteNum-coord=\tikzumlNoteWeight,\tikzumlClassNodeName=\tikzumlNoteWeightT) {};% + % + \ifthenelse{\equal{\tikzumlNoteGeometry}{--}% + \OR\equal{\tikzumlNoteGeometry}{-|}% + \OR\equal{\tikzumlNoteGeometry}{|-}}{% + \edef\tikzumlnotepath{\tikzumlNoteGeometry} + }{% + \ifthenelse{\equal{\tikzumlNoteGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor -| note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center |- \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(\tikzumlNoteArm,0) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlNoteGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlNoteArm}{auto}}{% + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor |- note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center) -- (note-\thetikzumlNoteNum-middle.center -| \tikzumlClassNodeName\tikzumlNoteDestAnchor) --}% + }{% + \draw (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor)+(0,\tikzumlNoteArm) node[name=note-\thetikzumlNoteNum-tmp] {}; + \edef\tikzumlnotepath{-- (note-\thetikzumlNoteNum-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (note-\thetikzumlNoteNum-coord\tikzumlNoteSrcAnchor) \tikzumlnotepath (\tikzumlClassNodeName\tikzumlNoteDestAnchor);% + \end{pgfonlayer}% + % + \stepcounter{tikzumlNoteNum}% +}% +% +% shortcuts for note with geometry +\newcommand{\umlHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|, #1]{#2}{#3}% +}% +\newcommand{\umlVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-, #1]{#2}{#3}% +}% +\newcommand{\umlVHVnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=|-|, #1]{#2}{#3}% +}% +\newcommand{\umlHVHnote}[3][]{% + \pgfkeys{/tikzuml/note/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHnote, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/note/.cd, #1}% + \umlnote[geometry=-|-, #1]{#2}{#3}% +}% +% +% define a uml association class (command) +% args : name of the class +% attributes of the class +% operations of the class +% optional : x,y: coordinates of the class +% width: width of the class node +% type: type of of class (class, interface, typedef, enum) +% template: template parameters +% name: name of the class node +% geometry: geometry of the line +% weight: barycentric weight of the middle part when geometry is a 3-line +% arm: length of first part when geometry id a 3-line +% anchor1, anchor2: src/dest anchors on linked classes +% style: style of the association class (association, aggregation, composition, inherit, ...) +% draw, fill, fill template, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the class position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlassocclass}[5][]{% + \pgfkeys{/tikzuml/assocclass/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, + width/.initial=\tikzumlClassDefaultWidth, type/.initial=\tikzumlClassDefaultType, style/.style={},% + template/.initial={}, name/.initial=tikzumlEmpty, geometry/.initial=\tikzumlRelationDefaultGeometry,% + weight/.initial=\tikzumlRelationDefaultWeight, arm/.initial=auto,% + anchor1/.initial=tikzumlEmpty, anchor2/.initial=tikzumlEmpty,% + draw/.initial=\tikzumlDefaultDrawColor,% + fill template/.initial=\tikzumlClassTemplateFillColorDefaultFillColor,% + fill/.initial=\tikzumlClassDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no coords/.is if=tikzumlassocclassWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/assocclass/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/assocclass/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlassocclass, invalid option \keyname}% + }% + }% + % + \pgfkeys{/tikzuml/assocclass/.cd,#1}% + \pgfkeys{/tikzuml/assocclass/.cd, x/.get=\tikzumlAssocClassX, y/.get=\tikzumlAssocClassY,% + width/.get=\tikzumlAssocClassMinimumWidth, type/.get=\tikzumlAssocClassTypeTmp,% + template/.get=\tikzumlAssocClassTemplateParam,% + name/.get=\tikzumlAssocClassName, geometry/.get=\tikzumlAssocClassGeometry,% + weight/.get=\tikzumlAssocClassWeight, arm/.get=\tikzumlAssocClassArm,% + anchor1/.get=\tikzumlAssocClassSrcAnchor,% + anchor2/.get=\tikzumlAssocClassDestAnchor,% + draw/.get=\tikzumlAssocClassDrawColor, fill/.get=\tikzumlAssocClassFillColor,% + text/.get=\tikzumlAssocClassTextColor, fill template/.get=\tikzumlAssocClassTemplateFillColor% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{class}\OR\equal{\tikzumlAssocClassTypeTmp}{abstract}}{% + \def\tikzumlAssocClassType{}% + }{% + \def\tikzumlAssocClassType{$\ll$\tikzumlAssocClassTypeTmp$\gg$ \\}% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{% + \def\tikzumlAssocClassVPadding{}% + \def\tikzumlAssocClassHPadding{}% + }{% + \def\tikzumlAssocClassVPadding{\vspace{0.1em} \\}% + \def\tikzumlAssocClassHPadding{\hspace{0.5ex} $ $}% + }% + % + \def\tikzumlAssocClassName{#2}% + \def\tikzumlAssocClassRelationName{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassNodeName{\tikzumlAssocClassName}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssocClassRelationNodeName{\tikzumlAssocClassRelationName}}\x% + % + \ifthenelse{\equal{\tikzumlAssocClassName}{tikzumlEmpty}}{}{% + \def\tikzumlAssocClassNodeName{\tikzumlAssocClassName}% + }% + % + \StrSubstitute{\tikzumlAssocClassNodeName}{:}{@COLON@}[\tikzumlAssocClassNodeName]% + \StrSubstitute{\tikzumlAssocClassNodeName}{\_}{@UNDERSCORE@}[\tikzumlAssocClassNodeName]% + % + \ifthenelse{\equal{\tikzumlAssocClassTypeTmp}{abstract}}{% + \let\tikzumlAssocClassNameOld\tikzumlAssocClassName% + \def\tikzumlAssocClassName{{\it \tikzumlAssocClassNameOld}}% + }{}% + % + \def\tikzumlAssocClassPos{\tikzumlAssocClassX,\tikzumlAssocClassY}% + \def\tikzumlAssocClassAttributes{#4}% + \def\tikzumlAssocClassOperations{#5}% + % + % def anchors macros + \ifthenelse{\equal{\tikzumlAssocClassSrcAnchor}{tikzumlEmpty}}{% + \def\tikzumlAssocClassSrcAnchor{}% + }{% + \let\tikzumlAssocClassSrcAnchorold\tikzumlAssocClassSrcAnchor% + \def\tikzumlAssocClassSrcAnchor{.\tikzumlAssocClassSrcAnchorold}% + }% + % + \ifthenelse{\equal{\tikzumlAssocClassDestAnchor}{tikzumlEmpty}}{% + \def\tikzumlAssocClassDestAnchor{}% + }{% + \let\tikzumlAssocClassDestAnchorold\tikzumlAssocClassDestAnchor% + \def\tikzumlAssocClassDestAnchor{.\tikzumlAssocClassDestAnchorold}% + }% + % + \iftikzumlassocclassWithoutCoords% + \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlAssocClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlAssocClassOperations% + \end{tabular}% + };% + \else% + \node[tikzuml class style, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont, minimum width=\tikzumlAssocClassMinimumWidth, /tikzuml/assocclass/style] (\tikzumlAssocClassNodeName) at (\tikzumlAssocClassPos) {\begin{tabular}{c}\tikzumlAssocClassVPadding \tikzumlAssocClassType \tikzumlAssocClassHPadding \textbf{\tikzumlAssocClassName} \tikzumlAssocClassHPadding \end{tabular}% + \nodepart{second}% + \begin{tabular}{l}% + \tikzumlAssocClassAttributes% + \end{tabular}% + \nodepart{third}% + \begin{tabular}{l}% + \tikzumlAssocClassOperations% + \end{tabular}% + };% + \fi% + % + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{}{% + \draw (\tikzumlAssocClassNodeName.north east) node[tikzuml template style, name=\tikzumlAssocClassNodeName-template, draw=\tikzumlAssocClassDrawColor, fill=\tikzumlAssocClassTemplateFillColor, text=\tikzumlAssocClassTextColor, font=\tikzumlDefaultFont] {\tikzumlAssocClassTemplateParam};% + }% + % + \pgfmathsetmacro{\tikzumlAssocClassWeightT}{1.0-\tikzumlAssocClassWeight} + \node (\tikzumlAssocClassNodeName-middle) at (barycentric cs:\tikzumlAssocClassNodeName=\tikzumlAssocClassWeight,\tikzumlAssocClassRelationNodeName=\tikzumlAssocClassWeightT) {};% + % + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{--}\OR\equal{\tikzumlAssocClassGeometry}{-|}\OR\equal{\tikzumlAssocClassGeometry}{|-}}{% + \edef\tikzumlassocclasspath{\tikzumlAssocClassGeometry} + }{% + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor -| \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center |- \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(\tikzumlAssocClassArm,0) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlnotepath{-- (\tikzumlAssocClassNodeName-tmp.center) |-}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssocClassGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssocClassArm}{auto}}{% + \edef\tikzumlassocclasspath{-- (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor |- \tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center) -- (\tikzumlAssocClassNodeName-middle.center -| \tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor) --}% + }{% + \draw (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor)+(0,\tikzumlAssocClassArm) node[name=\tikzumlAssocClassNodeName-tmp] {}; + \edef\tikzumlassocclasspath{-- (\thetikzumlAssocClassNodeName-tmp.center) -|}% + }% + + }{% + \errmessage{TIKZUML ERROR : Unknown geometry value !!! It should be in the following list : --, |-, -|, |-|, -|-}% + }% + }% + }% + % + \begin{pgfonlayer}{connections}% + \draw[dashed] (\tikzumlAssocClassNodeName\tikzumlAssocClassSrcAnchor) \tikzumlassocclasspath (\tikzumlAssocClassRelationNodeName\tikzumlAssocClassDestAnchor);% + \end{pgfonlayer}% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \ifthenelse{\equal{\tikzumlAssocClassTemplateParam}{}}{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName)(\tikzumlAssocClassNodeName-middle)}% + }{% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlAssocClassNodeName) (\tikzumlAssocClassNodeName-template)(\tikzumlAssocClassNodeName-middle)}% + }% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% use case diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml usecase style}=[ellipse, text centered]% +\tikzstyle{tikzuml actor style}=[ellipse, inner sep=0, outer sep=0]% +% +\newcounter{tikzumlSystemUseCaseNum}% +\newcounter{tikzumlSystemLevel}% +\newcounter{tikzumlUseCaseNum}% +\newcounter{tikzumlActorNum}% +% +\newif\iftikzumlusecaseWithoutCoords% +\newif\iftikzumlactorWithoutCoords% +% +% define a system +% arg : name +% optional : x, y: coordinates of the system +% draw, fill, text: colors +\newenvironment{umlsystem}[2][]{% + \gdef\tikzumlSystemFit{}% + \def\tikzumlSystemName{#2}% + \setcounter{tikzumlSystemUseCaseNum}{0}% + % + \pgfkeys{/tikzuml/system/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlSystemDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlsystem, invalid option \keyname}% + }% + }% + % + \pgfkeys{/tikzuml/system/.cd, #1}% + \pgfkeys{/tikzuml/system/.cd, x/.get=\tikzumlSystemXShift, y/.get=\tikzumlSystemYShift,% + draw/.get=\tikzumlSystemDrawColor, fill/.get=\tikzumlSystemFillColor,% + text/.get=\tikzumlSystemTextColor}% + % + \stepcounter{tikzumlSystemLevel}% + % + \begin{scope}[xshift=\tikzumlSystemXShift cm, yshift=\tikzumlSystemYShift cm]% +}{% + \addtocounter{tikzumlSystemLevel}{-1}% + % if contains no usecase, one define a fictive node to enable the fit option + \ifnum\c@tikzumlSystemUseCaseNum=0% + \node[inner xsep=10ex, inner ysep=1em] (\tikzumlSystemName-root) at (0,0) {};% + \xdef\tikzumlSystemFit{(\tikzumlSystemName-root)}% + \fi% + % + \begin{pgfonlayer}{background}% + \node[inner ysep=1em, inner xsep=2ex, fit = \tikzumlSystemFit] (\tikzumlSystemName-tmp) {};% + \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption-tmp) at (\tikzumlSystemName-tmp.north) {\tikzumlSystemName};% + \node[draw=\tikzumlSystemDrawColor, fill=\tikzumlSystemFillColor, text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont, inner ysep=1em, inner xsep=2ex, fit = (\tikzumlSystemName-tmp) (\tikzumlSystemName-caption-tmp)] (\tikzumlSystemName) {};% + \node[text=\tikzumlSystemTextColor, font=\tikzumlDefaultFont] (\tikzumlSystemName-caption) at (\tikzumlSystemName-caption-tmp.north) {\tikzumlSystemName};% + \end{pgfonlayer}% + \end{scope}% + % +}% +% +% define a use case +% arg : label of the use case +% optional : x, y: coordinates of the use case +% name: name of the node +% width: node width +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the use case position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlusecase}[2][]{% + \stepcounter{tikzumlUseCaseNum}% + \pgfkeys{/tikzuml/usecase/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=auto,% + name/.initial=usecase-\thetikzumlUseCaseNum,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlUseCaseDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlusecaseWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/usecase/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/usecase/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlusecase, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/usecase/.cd, #1}% + \pgfkeys{/tikzuml/usecase/.cd, x/.get=\tikzumlUseCaseX, y/.get=\tikzumlUseCaseY, width/.get=\tikzumlUseCaseTextWidth,% + name/.get=\tikzumlUseCaseName,% + draw/.get=\tikzumlUseCaseDrawColor, fill/.get=\tikzumlUseCaseFillColor,% + text/.get=\tikzumlUseCaseTextColor% + }% + % + \def\tikzumlUseCaseText{#2}% + % + \def\tikzumlUseCasePos{\tikzumlUseCaseX,\tikzumlUseCaseY}% + % + \ifthenelse{\equal{\tikzumlUseCaseTextWidth}{auto}}{% + \iftikzumlusecaseWithoutCoords% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};% + \else% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + \fi% + }{% + \iftikzumlusecaseWithoutCoords% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) {\tikzumlUseCaseText};% + \else% + \node[tikzuml usecase style, draw=\tikzumlUseCaseDrawColor, fill=\tikzumlUseCaseFillColor, text=\tikzumlUseCaseTextColor, font=\tikzumlDefaultFont, text width=\tikzumlUseCaseTextWidth, /tikzuml/usecase/style] (\tikzumlUseCaseName) at (\tikzumlUseCasePos) {\tikzumlUseCaseText};% + \fi% + }% + % + % add to fit + \ifnum\c@tikzumlSystemLevel>0% + \let\tikzumlSystemFitOld\tikzumlSystemFit% + \xdef\tikzumlSystemFit{\tikzumlSystemFitOld (\tikzumlUseCaseName)}% + \stepcounter{tikzumlSystemUseCaseNum}% + \fi% +}% +% +% define the actor symbol +% optional : global tikzpicture styles +\newcommand{\picturedactor}[1]{% + \pgfkeys{/tikzuml/picactor/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/picactor/.cd,#1}% + \pgfkeys{/tikzuml/picactor/.cd, scale/.get=\tikzumlPicturedActorScale}% + % + \begin{tikzpicture}[#1]% + \coordinate (head) at (0,4ex);% + \coordinate (left-hand) at (-2ex,2ex);% + \coordinate (right-hand) at (2ex,2ex);% + \coordinate (left-foot) at (-2ex,-2ex);% + \coordinate (right-foot) at (2ex,-2ex);% + \coordinate (empty) at (0,-3ex);% + \draw (empty) (0,0) -- (head);% + \draw (left-hand) -- (right-hand);% + \draw (0,0) -- (left-foot) (0,0) -- (right-foot);% + \node[fill, draw, circle, inner sep=\tikzumlPicturedActorScale*0.3333ex, minimum size=\tikzumlPicturedActorScale*2ex, anchor=base] at (head) {};% + \end{tikzpicture}% +}% +% +% define an actor +% arg : var name +% optional : x, y: coordinates of the actor +% scale: scale factor of the actor symbol +% below: distance between the actor symbol and its name below +% draw, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the actor position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlactor}[2][]{% + \stepcounter{tikzumlActorNum}% + \pgfkeys{/tikzuml/actor/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, scale/.initial=1, below/.initial=\tikzumlActorDefaultBelow,% + draw/.initial=\tikzumlDefaultDrawColor, text/.initial=\tikzumlDefaultTextColor,% + style/.style={},% + no coords/.is if=tikzumlactorWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/actor/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/actor/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlactor, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/actor/.cd, #1}% + \pgfkeys{/tikzuml/actor/.cd,% + x/.get=\tikzumlActorX, y/.get=\tikzumlActorY, scale/.get=\tikzumlActorScale,% + below/.get=\tikzumlActorBelow,% + draw/.get=\tikzumlActorDrawColor, text/.get=\tikzumlActorTextColor}% + % + \def\tikzumlActorName{#2}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlActorNodeName{\tikzumlActorName}}\x% + % + \def\tikzumlActorPos{\tikzumlActorX,\tikzumlActorY}% + % + \iftikzumlactorWithoutCoords% + \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};% + \else% + \node[tikzuml actor style, text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, /tikzuml/actor/style] (\tikzumlActorNodeName) at (\tikzumlActorPos) {\picturedactor{scale=\tikzumlActorScale, fill=white, draw=\tikzumlActorDrawColor, thick}};% + \fi% + \node[text=\tikzumlActorTextColor, font=\tikzumlDefaultFont, below=\tikzumlActorScale*\tikzumlActorBelow] at (\tikzumlActorNodeName) {\tikzumlActorName};% + % +}% + +% shortcuts for include and extend relation +\newcommand{\umlinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR :in umlVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlHVHextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=-|-, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVinclude}[3][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVinclude, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +\newcommand{\umlVHVextend}[3][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option stereo}% + }{% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVextend, forbidden option geometry}% + }{}% + }% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlrelation[geometry=|-|, stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}% +}% +% +\newcommand{\umlCNinclude}[4][]{% + \pgfkeys{/tikzuml/includerelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNinclude, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/includerelation/.cd, #1}% + \umlCNrelation[stereo=include, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +\newcommand{\umlCNextend}[4][]{% + \pgfkeys{/tikzuml/extendrelation/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlCNextend, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/extendrelation/.cd, #1}% + \umlCNrelation[stereo=extend, style={tikzuml dependency style}, #1]{#2}{#3}{#4}% +}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% state diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml state style}=[rectangle split, rectangle split parts=2, rounded corners, inner xsep=1.5ex]% +\tikzstyle{tikzuml transition style}=[color=\tikzumlDefaultDrawColor, rounded corners, -angle 45]% +% +\newcounter{tikzumlStateJoinNum}% +\newcounter{tikzumlStateDecisionNum}% +\newcounter{tikzumlStateInitialNum}% +\newcounter{tikzumlStateFinalNum}% +\newcounter{tikzumlStateEnterNum}% +\newcounter{tikzumlStateExitNum}% +\newcounter{tikzumlStateEndNum}% +\newcounter{tikzumlStateHistoryNum}% +\newcounter{tikzumlStateDeepHistoryNum}% +\newcounter{tikzumlStateLevel}% +\newcounter{tikzumlStateSubStateNum}% +\newcounter{tikzumlStateText}% +% +\newif\iftikzumlstatejoinWithoutCoords% +\newif\iftikzumlstatedecisionWithoutCoords% +\newif\iftikzumlstateinitialWithoutCoords% +\newif\iftikzumlstatefinalWithoutCoords% +\newif\iftikzumlstateenterWithoutCoords% +\newif\iftikzumlstateexitWithoutCoords% +\newif\iftikzumlstateendWithoutCoords% +\newif\iftikzumlstatehistoryWithoutCoords% +\newif\iftikzumlstatedeephistoryWithoutCoords% +\newif\iftikzumlstateWithoutCoords% +% +% define a uml join state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatejoin}[1][]{% + \pgfkeys{/tikzuml/statejoin/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateJoinDefaultWidth,% + name/.initial=statejoin-\thetikzumlStateJoinNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatejoinWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statejoin/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statejoin/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatejoin, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statejoin/.cd, #1}% + \pgfkeys{/tikzuml/statejoin/.cd, x/.get=\tikzumlStateJoinX, y/.get=\tikzumlStateJoinY, width/.get=\tikzumlStateJoinMinimumWidth,% + name/.get=\tikzumlStateJoinName, color/.get=\tikzumlStateJoinColor% + }% + % + \def\tikzumlStateJoinPos{\tikzumlStateJoinX,\tikzumlStateJoinY}% + % + \iftikzumlstatejoinWithoutCoords% + \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) {};% + \else% + \node[circle, minimum size=\tikzumlStateJoinMinimumWidth, draw=\tikzumlStateJoinColor, fill=\tikzumlStateJoinColor, /tikzuml/statejoin/style] (\tikzumlStateJoinName) at (\tikzumlStateJoinPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateJoinName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateJoinNum}% +}% +% +% define a uml decision state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatedecision}[1][]{% + \pgfkeys{/tikzuml/statedecision/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDecisionDefaultWidth,% + name/.initial=statedecision-\thetikzumlStateDecisionNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatedecisionWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statedecision/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statedecision/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatedecision, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statedecision/.cd, #1}% + \pgfkeys{/tikzuml/statedecision/.cd, x/.get=\tikzumlStateDecisionX, y/.get=\tikzumlStateDecisionY, width/.get=\tikzumlStateDecisionMinimumWidth,% + name/.get=\tikzumlStateDecisionName, color/.get=\tikzumlStateDecisionColor% + }% + % + \def\tikzumlStateDecisionPos{\tikzumlStateDecisionX,\tikzumlStateDecisionY}% + % + \iftikzumlstatedecisionWithoutCoords% + \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) {};% + \else% + \node[rectangle, rotate=45, minimum size=\tikzumlStateDecisionMinimumWidth, draw=\tikzumlStateDecisionColor, /tikzuml/statedecision/style] (\tikzumlStateDecisionName) at (\tikzumlStateDecisionPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDecisionName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDecisionNum}% +}% +% +% define a uml initial state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% entry, do, exit: entry/do/exit action of the state +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateinitial}[1][]{% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateInitialDefaultWidth,% + name/.initial=stateinitial-\thetikzumlStateInitialNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateinitialWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateinitial/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateinitial/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateinitial, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateinitial/.cd, #1}% + \pgfkeys{/tikzuml/stateinitial/.cd, x/.get=\tikzumlStateInitialX, y/.get=\tikzumlStateInitialY, width/.get=\tikzumlStateInitialMinimumWidth,% + name/.get=\tikzumlStateInitialName, color/.get=\tikzumlStateInitialColor% + }% + % + \def\tikzumlStateInitialPos{\tikzumlStateInitialX,\tikzumlStateInitialY}% + % + \iftikzumlstateinitialWithoutCoords% + \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) {};% + \else% + \node[circle, minimum size=\tikzumlStateInitialMinimumWidth, fill=\tikzumlStateInitialColor, /tikzuml/stateinitial/style] (\tikzumlStateInitialName) at (\tikzumlStateInitialPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateInitialName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateInitialNum}% +}% +% +% define a uml final state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatefinal}[1][]{% + \pgfkeys{/tikzuml/statefinal/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateFinalDefaultWidth,% + name/.initial=statefinal-\thetikzumlStateFinalNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatefinalWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statefinal/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statefinal/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatefinal, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statefinal/.cd, #1}% + \pgfkeys{/tikzuml/statefinal/.cd, x/.get=\tikzumlStateFinalX, y/.get=\tikzumlStateFinalY, width/.get=\tikzumlStateFinalMinimumWidth,% + name/.get=\tikzumlStateFinalName, color/.get=\tikzumlStateFinalColor% + }% + % + \def\tikzumlStateFinalPos{\tikzumlStateFinalX,\tikzumlStateFinalY}% + % + \iftikzumlstatefinalWithoutCoords% + \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) {};% + \else% + \node[circle, minimum size=\tikzumlStateFinalMinimumWidth, draw=\tikzumlStateFinalColor, fill=\tikzumlStateFinalColor, double, double distance=0.1cm, /tikzuml/statefinal/style] (\tikzumlStateFinalName) at (\tikzumlStateFinalPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateFinalName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateFinalNum}% +}% +% +% define a uml enter state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateenter}[1][]{% + \pgfkeys{/tikzuml/stateenter/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEnterDefaultWidth,% + name/.initial=stateenter-\thetikzumlStateEnterNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateenterWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateenter/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateenter/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateenter, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateenter/.cd, #1}% + \pgfkeys{/tikzuml/stateenter/.cd, x/.get=\tikzumlStateEnterX, y/.get=\tikzumlStateEnterY, width/.get=\tikzumlStateEnterMinimumWidth,% + name/.get=\tikzumlStateEnterName, color/.get=\tikzumlStateEnterColor% + }% + % + \def\tikzumlStateEnterPos{\tikzumlStateEnterX,\tikzumlStateEnterY}% + % + \iftikzumlstateenterWithoutCoords% + \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) {};% + \else% + \node[circle, minimum size=\tikzumlStateEnterMinimumWidth, draw=\tikzumlStateEnterColor, /tikzuml/stateenter/style] (\tikzumlStateEnterName) at (\tikzumlStateEnterPos) {};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEnterName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEnterNum}% +}% +% +% define a uml exit state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateexit}[1][]{% + \pgfkeys{/tikzuml/stateexit/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateExitDefaultWidth,% + name/.initial=stateexit-\thetikzumlStateExitNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateexitWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateexit/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateexit/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateexit, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateexit/.cd, #1}% + \pgfkeys{/tikzuml/stateexit/.cd, x/.get=\tikzumlStateExitX, y/.get=\tikzumlStateExitY, width/.get=\tikzumlStateExitMinimumWidth,% + name/.get=\tikzumlStateExitName, color/.get=\tikzumlStateExitColor% + }% + % + \def\tikzumlStateExitPos{\tikzumlStateExitX,\tikzumlStateExitY}% + % + \iftikzumlstateexitWithoutCoords% + \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) {};% + \else% + \node[circle, minimum size=\tikzumlStateExitMinimumWidth, draw=\tikzumlStateExitColor, /tikzuml/stateexit/style] (\tikzumlStateExitName) at (\tikzumlStateExitPos) {};% + \fi% + \draw[draw=\tikzumlStateExitColor] (\tikzumlStateExitName.north east) -- (\tikzumlStateExitName.south west) (\tikzumlStateExitName.north west) -- (\tikzumlStateExitName.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateExitName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateExitNum}% +}% +% +% define a uml end state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstateend}[1][]{% + \pgfkeys{/tikzuml/stateend/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateEndDefaultWidth,% + name/.initial=stateend-\thetikzumlStateEndNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstateendWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/stateend/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/stateend/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstateend, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/stateend/.cd, #1}% + \pgfkeys{/tikzuml/stateend/.cd, x/.get=\tikzumlStateEndX, y/.get=\tikzumlStateEndY, width/.get=\tikzumlStateEndMinimumWidth,% + name/.get=\tikzumlStateEndName, color/.get=\tikzumlStateEndColor% + }% + % + \def\tikzumlStateEndPos{\tikzumlStateEndX,\tikzumlStateEndY}% + % + \iftikzumlstateendWithoutCoords% + \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) {};% + \else% + \node[circle, minimum size=\tikzumlStateEndMinimumWidth, /tikzuml/stateend/style] (\tikzumlStateEndName) at (\tikzumlStateEndPos) {};% + \fi% + \draw[draw=\tikzumlStateEndColor] (\tikzumlStateEndName.north east) -- (\tikzumlStateEndName.south west) (\tikzumlStateEndName.north west) -- (\tikzumlStateEndName.south east); + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateEndName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateEndNum}% +}% +% +\newcommand{\picturedhistory}[1]{% + \begin{tikzpicture}[#1]% + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm);% + \end{tikzpicture}% +}% +% +% define a uml history state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatehistory}[1][]{% + \pgfkeys{/tikzuml/statehistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateHistoryDefaultWidth,% + name/.initial=statehistory-\thetikzumlStateHistoryNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatehistoryWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statehistory/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statehistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatehistory, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statehistory/.cd, #1}% + \pgfkeys{/tikzuml/statehistory/.cd, x/.get=\tikzumlStateHistoryX, y/.get=\tikzumlStateHistoryY, width/.get=\tikzumlStateHistoryMinimumWidth,% + name/.get=\tikzumlStateHistoryName, color/.get=\tikzumlStateHistoryColor% + }% + % + \def\tikzumlStateHistoryPos{\tikzumlStateHistoryX,\tikzumlStateHistoryY}% + % + \iftikzumlstatehistoryWithoutCoords% + \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) {\picturedhistory{draw=\tikzumlStateHistoryColor}};% + \else% + \node[circle, minimum size=\tikzumlStateHistoryMinimumWidth, draw=\tikzumlStateHistoryColor, /tikzuml/statehistory/style] (\tikzumlStateHistoryName) at (\tikzumlStateHistoryPos) {\picturedhistory{draw=\tikzumlStateHistoryColor}};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateHistoryName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateHistoryNum}% +}% +% +\newcommand{\pictureddeephistory}[1]{% + \begin{tikzpicture}[#1]% + \draw[thick] (-0.1cm,-0.15cm) -- (-0.1cm,0.15cm) + (-0.1cm,0) -- (0.1cm,0) + (0.1cm,-0.15cm) -- (0.1cm,0.15cm) + (0.23cm,0.19cm) -- (0.23cm,0.11cm) + (0.20cm,0.17cm) -- (0.26cm,0.13cm) + (0.20cm,0.13cm) -- (0.26cm,0.17cm);% + \end{tikzpicture}% +}% +% +% define a uml deep-history state +% args : name of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% color: color of the join symbol +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newcommand{\umlstatedeephistory}[1][]{% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDeepHistoryDefaultWidth,% + name/.initial=statedeephistory-\thetikzumlStateDeepHistoryNum,% + color/.initial=\tikzumlDefaultDrawColor, style/.style={},% + no coords/.is if=tikzumlstatedeephistoryWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/statedeephistory/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/statedeephistory/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlstatedeephistory, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/statedeephistory/.cd, #1}% + \pgfkeys{/tikzuml/statedeephistory/.cd, x/.get=\tikzumlStateDeepHistoryX, y/.get=\tikzumlStateDeepHistoryY, width/.get=\tikzumlStateDeepHistoryMinimumWidth,% + name/.get=\tikzumlStateDeepHistoryName, color/.get=\tikzumlStateDeepHistoryColor% + }% + % + \def\tikzumlStateDeepHistoryPos{\tikzumlStateDeepHistoryX,\tikzumlStateDeepHistoryY}% + % + \iftikzumlstatedeephistoryWithoutCoords% + \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};% + \else% + \node[circle, minimum size=\tikzumlStateDeepHistoryMinimumWidth, draw=\tikzumlStateDeepHistoryColor, /tikzuml/statedeephistory/style] (\tikzumlStateDeepHistoryName) at (\tikzumlStateDeepHistoryPos) {\pictureddeephistory{draw=\tikzumlStateDeepHistoryColor}};% + \fi% + % + % add to fit + \ifnum\c@tikzumlStateLevel>0% + \edef\tikzumlStateFitOld{\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{\tikzumlStateFitOld (\tikzumlStateDeepHistoryName)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + \stepcounter{tikzumlStateDeepHistoryNum}% +}% +% +% define a uml state +% args : name of the state +% content of the state +% optional : x,y: coordinates of the state +% width: width of the state node +% name: name of the state node +% entry, do, exit: entry/do/exit action of the state +% draw, fill, text: colors +% style: to manage every default TikZ option +% no coords: to tell that the state position is defined relatively +% to another node (automatically used with TikZ options above, below, left, right, below left, ...) +\newenvironment{umlstate}[2][]{% + \ifnum\thetikzumlStateLevel>0% + \let\tikzumlState@nameold\tikzumlState@fitname% + \let\tikzumlState@parentold\tikzumlState@parent% + \edef\tikzumlState@parent{\tikzumlState@parentold @@\tikzumlState@nameold}% + \else% + \def\tikzumlState@parent{}% + \fi% + % + \stepcounter{tikzumlStateLevel}% + % + \pgfkeys{/tikzuml/state/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlStateDefaultWidth,% + name/.initial={},% + entry/.initial={}, do/.initial={}, exit/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlStateDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlstateWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/state/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/state/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + % \errmessage{TIKZUML ERROR : in umlstate, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/state/.cd, #1}% + \pgfkeys{/tikzuml/state/.cd, x/.get=\tikzumlStateXShift, y/.get=\tikzumlStateYShift, width/.get=\tikzumlStateMinimumWidth, name/.get=\tikzumlStateName,% + entry/.get=\tikzumlStateEntry, do/.get=\tikzumlStateDo, exit/.get=\tikzumlStateExit,% + draw/.get=\tikzumlStateDrawColor, fill/.get=\tikzumlStateFillColor,% + text/.get=\tikzumlStateTextColor% + }% + % + \ifthenelse{\equal{\tikzumlStateName}{}}{% + \edef\tikzumlState@name{#2}% + }{% + \edef\tikzumlState@name{\tikzumlStateName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlState@fitname{\tikzumlState@name}}\x% + % + \let\tikzumlState@nodeNameold\tikzumlState@nodeName% + \def\tikzumlState@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlState@nodeName{\tikzumlState@name}}\x% + % + \expandafter\gdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{}% + % + \setcounter{tikzumlStateSubStateNum}{0}% + \setcounter{tikzumlStateText}{0}% + % + \def\tikzumlStateText{tikzumlEmpty}% + \begin{scope}[xshift=\tikzumlStateXShift cm, yshift=\tikzumlStateYShift cm]% +}{% + % + \def\tikzumlstaterootlabel{\phantom{\tikzumlState@nodeName}}% + % + \def\tikzumlstaterootinnerysep{0.5ex}% + \def\tikzumlstatebodyinnerysep{2ex}% + % + \ifthenelse{\equal{\tikzumlStateEntry}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{entry/\tikzumlStateEntry}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{entry/\tikzumlStateEntry}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ entry/\tikzumlStateEntry}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\tikzumlStateDo}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{do/\tikzumlStateDo}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{do/\tikzumlStateDo}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ do/\tikzumlStateDo}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + \ifthenelse{\equal{\tikzumlStateExit}{}}{}{% + \ifnum\c@tikzumlStateText=0% + \def\tikzumlStateText{exit/\tikzumlStateExit}% + \else% + \let\tikzumlStateTextOld\tikzumlStateText% + \ifthenelse{\equal{\tikzumlStateText}{tikzumlEmpty}}{% + \def\tikzumlStateText{exit/\tikzumlStateExit}% + }{% + \expandafter\def\expandafter\tikzumlStateText\expandafter{\tikzumlStateTextOld \\ exit/\tikzumlStateExit}% + }% + \fi% + \setcounter{tikzumlStateText}{1}% + \ifnum\c@tikzumlStateSubStateNum=0% + \def\tikzumlstatebodyinnerysep{0}% + \def\tikzumlstaterootinnerysep{0}% + \fi% + }% + % + \addtocounter{tikzumlStateLevel}{-1}% + \begin{pgfonlayer}{state\thetikzumlStateLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlStateSubStateNum=0% + \iftikzumlstateWithoutCoords% + \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) {\tikzumlstaterootlabel};% + \else% + \node[inner ysep=\tikzumlstaterootinnerysep, minimum width=\tikzumlStateMinimumWidth, /tikzuml/state/style] (\tikzumlState@nodeName-root) at (0,0) {\tikzumlstaterootlabel};% + \fi% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname{(\tikzumlState@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlStateLevel>0% + \def\tikzumlStateFitTmp{\csname tikzumlStateFit\tikzumlState@parent\endcsname}% + \expandafter\xdef\csname tikzumlStateFit\tikzumlState@parent\endcsname{\tikzumlStateFitTmp (\tikzumlState@nodeName-body) (\tikzumlState@nodeName-caption)}% + \stepcounter{tikzumlStateSubStateNum}% + \fi% + % + \node[inner xsep=2ex, inner ysep=\tikzumlstatebodyinnerysep, fit = \csname tikzumlStateFit\tikzumlState@parent @@\tikzumlState@fitname\endcsname, /tikzuml/state/style ] (\tikzumlState@nodeName-body) {};% + \def\tikzumlState@orig{body}% + \ifnum\c@tikzumlStateText=1% + \node[above=0] (\tikzumlState@nodeName-texttmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \def\tikzumlState@orig{texttmp}% + \fi% + \node[above] (\tikzumlState@nodeName-captiontmp) at (\tikzumlState@nodeName-\tikzumlState@orig.north) {\tikzumlState@caption};% + \ifnum\c@tikzumlStateText=1% + \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-texttmp) (\tikzumlState@nodeName-captiontmp)] {};% + \else% + \node[rounded corners, draw=\tikzumlStateDrawColor, fill=\tikzumlStateFillColor, name=\tikzumlState@nodeName, fit=(\tikzumlState@nodeName-body) (\tikzumlState@nodeName-captiontmp)] {};% + \fi% + \ifnum\c@tikzumlStateText=1% + \node (\tikzumlState@nodeName-text) at (\tikzumlState@nodeName-texttmp) {\begin{tabular}{l}\tikzumlStateText \end{tabular}};% + \fi% + \node (\tikzumlState@nodeName-caption) at (\tikzumlState@nodeName-captiontmp) {\tikzumlState@caption};% + \draw (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north west) -- (\tikzumlState@nodeName-caption.south -| \tikzumlState@nodeName.north east);% + \end{pgfonlayer}% + \end{scope}% +}% +% +% shortcut for empty state +\newcommand{\umlbasicstate}[2][]{\begin{umlstate}[#1]{#2}\end{umlstate}}% +% +% command to add text in a state, to be used inside umlstate environment +\newcommand{\umlstatetext}[1]{% + \def\tikzumlStateText{#1}% + \setcounter{tikzumlStateText}{1}% +}% +% +% shortcuts for state transitions macros +\newcommand{\umltrans}[3][]{% + \ifthenelse{\equal{#2}{#3}}{% + \umlrelation[style={tikzuml transition style}, recursive mode=transition, #1]{#2}{#3}% + }{% + \umlrelation[style={tikzuml transition style}, #1]{#2}{#3}% + }% +}% +\newcommand{\umlHVtrans}[3][]{\umlHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHtrans}[3][]{\umlVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlVHVtrans}[3][]{\umlVHVrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlHVHtrans}[3][]{\umlHVHrelation[style={tikzuml transition style}, #1]{#2}{#3}}% +\newcommand{\umlCNtrans}[4][]{\umlCNrelation[style={tikzuml transition style}, #1]{#2}{#3}{#4}}% +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% sequence diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml synchron-msg style}=[color=\tikzumlDefaultDrawColor, -triangle 45]% +\tikzstyle{tikzuml asynchron-msg style}=[color=\tikzumlDefaultDrawColor, -angle 45]% +\tikzstyle{tikzuml return-msg style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]% +\tikzstyle{tikzuml call return style}=[color=\tikzumlDefaultDrawColor, dashed, -angle 45]% +\tikzstyle{tikzuml activity style}=[inner xsep=1ex, inner ysep=1ex]% +% +\newcounter{tikzumlObjectNum}% +\newcounter{tikzumlCallLevel}% +\newcounter{tikzumlCallNum}% +\newcounter{tikzumlFragmentLevel}% +\newcounter{tikzumlFragmentLevelNum}% +\newcounter{tikzumlFragmentNum}% +\newcounter{tikzumlFragmentPartNum}% +\newcounter{tikzumlCallStartFragmentNum}% +\newcounter{tikzumlCallEndFragmentNum}% +% +\newif\iftikzumlobjectNoDDots% +\newif\iftikzumlcreatecallNoDDots% +% +% define a sequence diagram +% +\newenvironment{umlseqdiag}{% + \gdef\tikzumlInCreateCall{0}% + \setcounter{tikzumlObjectNum}{0}% + \setcounter{tikzumlCallLevel}{0}% + \setcounter{tikzumlCallNum}{0}% + \setcounter{tikzumlFragmentLevel}{0}% + \setcounter{tikzumlFragmentLevelNum}{0}% + \setcounter{tikzumlFragmentNum}{0}% + \setcounter{tikzumlFragmentPartNum}{0}% + \setcounter{tikzumlCallStartFragmentNum}{0}% + \setcounter{tikzumlCallEndFragmentNum}{0}% + % + \ifx \@umlactor \@empty + \newcommand{\umlactor}[2][]{% + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \else% + \renewcommand{\umlactor}[2][]{% + \pgfkeys{/tikzuml/actorobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlactor, forbidden option stereo}% + }{}% + }% + }% + % + \pgfkeys{/tikzuml/actorobj/.cd, ##1}% + \umlobject[stereo=actor, ##1]{##2}% + }% + \fi% + \begin{scope}[font=\tikzumlDefaultFont]% +}{% + % draw lifelines of each object + \begin{pgfonlayer}{lifelines}% + \foreach \id in \tikzumlIdList {% + \draw (\csname tikzumlLastChild@\id \endcsname)+(0,-2.5ex) node[inner sep=0, name=end-\id] {};% + \draw[dotted] (\id) -- (end-\id);% + }% + \end{pgfonlayer}% + \end{scope}% +}% +% +% define the database symbol +% optional : global tikzpicture styles +\newcommand{\pictureddatabase}[1]{% + \pgfkeys{/tikzuml/database/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/database/.cd,#1}% + \pgfkeys{/tikzuml/database/.cd, scale/.get=\tikzumlDatabaseScale}% + % + \begin{tikzpicture}[#1]% + \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom) at (0,-2ex) {};% + \node[fill, draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top) at (0,4ex) {};% + \fill (bottom.west) rectangle (top.east);% + \begin{scope}% + \clip (-3.5ex,-0.5ex) rectangle (3.5ex,2.5ex);% + \node[draw, dashed, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (bottom2) at (0,-2ex) {};% + \end{scope}% + \node[draw, ellipse, minimum width=\tikzumlDatabaseScale*4ex, minimum height=\tikzumlDatabaseScale*2ex, inner sep=0] (top2) at (0,4ex) {};% + \draw (bottom.west) -- (top.west) (bottom.east) -- (top.east);% + \end{tikzpicture}% +}% +% +% define the entity symbol +% optional : global tikzpicture styles +\newcommand{\picturedentity}[1]{% + \pgfkeys{/tikzuml/entity/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/entity/.cd,#1}% + \pgfkeys{/tikzuml/entity/.cd, scale/.get=\tikzumlEntityScale}% + % + \begin{tikzpicture}[#1]% + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlEntityScale*5ex] (center) at (0,0) {};% + \draw (center.south) node[coordinate, name=bottom] {};% + \draw (bottom)+(-2ex,0) node[coordinate, name=bottom-left] {};% + \draw (bottom)+(2ex,0) node[coordinate, name=bottom-right] {};% + \draw (center) -- (bottom);% + \draw (bottom-left) -- (bottom-right);% + \end{tikzpicture}% +}% +% +% define the boundary symbol +% optional : global tikzpicture styles +\newcommand{\picturedboundary}[1]{% + \pgfkeys{/tikzuml/boundary/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/boundary/.cd,#1}% + \pgfkeys{/tikzuml/boundary/.cd, scale/.get=\tikzumlBoundaryScale}% + % + \begin{tikzpicture}[#1] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlBoundaryScale*5ex] (center) at (0,0) {}; + \draw (center.west)+(-0.8ex,0) node[coordinate, name=left] {}; + \draw (left)+(0,0.2ex) node[coordinate, name=left-top] {}; + \draw (left)+(0,-0.2ex) node[coordinate, name=left-bottom] {}; + \draw (center) -- (left); + \draw (left-top) -- (left-bottom); + \end{tikzpicture} +}% +% +% define the control symbol +% optional : global tikzpicture styles +\newcommand{\picturedcontrol}[1]{% + \pgfkeys{/tikzuml/control/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/control/.cd,#1}% + \pgfkeys{/tikzuml/control/.cd, scale/.get=\tikzumlControlScale}% + % + \begin{tikzpicture}[#1, decoration={markings, mark=at position 0.25 with {\arrow{>}}}] + \node[fill, draw, circle, inner sep=0, minimum size=\tikzumlControlScale*5ex, postaction={decorate}] (center) at (0,0) {}; + \end{tikzpicture} +}% +% +% define a uml object for a sequence diagram +% args : name of the object +% optional : x, y: coordinates of the object +% stereo: stereotype of the object (object, actor, database, boundary, control, entity, multiobject) +% class: class of the object +% scale: scale factor of the object symbol +% draw, fill, text; colors +% no ddots: when used, disable printing of double dots +\newcommand{\umlobject}[2][]{ + \stepcounter{tikzumlObjectNum}% + % + \edef\tikzumlobject@ddot{:}% + \pgfkeys{/tikzuml/obj/.cd, x/.initial=tikzumlEmpty, y/.initial=\tikzumlDefaultX, stereo/.initial=\tikzumlObjectDefaultStereo,% + class/.initial={}, scale/.initial=1,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlObjectDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + no ddots/.is if=tikzumlobjectNoDDots,% + no ddots=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlobject, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/obj/.cd, #1}% + \pgfkeys{/tikzuml/obj/.cd, x/.get=\tikzumlObjectX, y/.get=\tikzumlObjectY,% + stereo/.get=\tikzumlObjectStereo, class/.get=\tikzumlObjectClass,% + scale/.get=\tikzumlObjectScale,% + draw/.get=\tikzumlObjectDrawColor, fill/.get=\tikzumlObjectFillColor,% + text/.get=\tikzumlObjectTextColor% + }% + % + \iftikzumlobjectNoDDots% + \edef\tikzumlobject@ddot{}% + \fi% + % + \ifthenelse{\equal{\tikzumlObjectX}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlObjectX}{4*(\thetikzumlObjectNum-1)}% + }{}% + % + \def\tikzumlObjectName{#2}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlObjectName \endcsname{\tikzumlObjectName}% + % + \ifnum\thetikzumlObjectNum=1% + \xdef\tikzumlIdList{\tikzumlObjectName}% + \else% + \let\tikzumlIdListOld\tikzumlIdList% + \expandafter\xdef\expandafter\tikzumlIdList\expandafter{\tikzumlIdListOld,\tikzumlObjectName}% + \fi% + % + \tikzstyle{tikzuml object box style}=[rectangle, text=\tikzumlObjectTextColor, font=\tikzumlDefaultFont]% + % + \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{% + \tikzstyle{tikzuml object box style}+=[draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor]% + }{% + \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{% + \tikzstyle{tikzuml object box style}+=[fill=\tikzumlObjectFillColor]% + }{}% + }% + % + \ifnum\tikzumlInCreateCall=1% + \draw (\tikzumlCreateCallObjectSrc -| \tikzumlObjectX,0) node[tikzuml object box style] (\tikzumlObjectName) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};% + \else% + \node[tikzuml object box style] (\tikzumlObjectName) at (\tikzumlObjectX,\tikzumlObjectY) {\tikzumlObjectName\tikzumlobject@ddot\tikzumlObjectClass};% + \fi% + % + \ifthenelse{\equal{\tikzumlObjectStereo}{multi}}{% + \draw (\tikzumlObjectName.north east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tr, coordinate] {}; + \draw (\tikzumlObjectName.north west)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tl, coordinate] {}; + \draw (\tikzumlObjectName.south east)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-br, coordinate] {}; + \draw (\tikzumlObjectName-tr)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttr, coordinate] {}; + \draw (\tikzumlObjectName-tl)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-ttl, coordinate] {}; + \draw (\tikzumlObjectName-br)+(0.4ex,0.4ex) node[name=\tikzumlObjectName-tbr, coordinate] {}; + \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-ttl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-ttl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-ttl) -- (\tikzumlObjectName-ttr) -- (\tikzumlObjectName-tbr) -- (\tikzumlObjectName-tbr -| \tikzumlObjectName.east); + \fill[fill=\tikzumlObjectFillColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east) -- (\tikzumlObjectName.north east) -- (\tikzumlObjectName-tl |- \tikzumlObjectName.north); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName-tl |- \tikzumlObjectName.north) -- (\tikzumlObjectName-tl) -- (\tikzumlObjectName-tr) -- (\tikzumlObjectName-br) -- (\tikzumlObjectName-br -| \tikzumlObjectName.east); + \draw[draw=\tikzumlObjectDrawColor] (\tikzumlObjectName.north west) rectangle (\tikzumlObjectName.south east); + }{% + \ifthenelse{\equal{\tikzumlObjectStereo}{object}}{}{% + \node[above=1ex, name=\tikzumlObjectName-picture] at (\tikzumlObjectName) {\csname pictured\tikzumlObjectStereo \endcsname{draw=\tikzumlObjectDrawColor, fill=\tikzumlObjectFillColor, scale=\tikzumlObjectScale}}; + }% + }% +}% +% +% shortcuts for objects +\newcommand{\umlbasicobject}[2][]{% + \pgfkeys{/tikzuml/basicobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{no ddots}}{% + \errmessage{TIKZUML ERROR : in umlbasicobject, forbidden option no ddots}% + }{}% + }% + }% + \pgfkeys{/tikzuml/basicobj/.cd, #1}% + \umlobject[no ddots, #1]{#2}% +}% +% +\newcommand{\umldatabase}[2][]{% + \pgfkeys{/tikzuml/databaseobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldatabase, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/databaseobj/.cd, #1}% + \umlobject[stereo=database, #1]{#2}% +}% +\newcommand{\umlentity}[2][]{% + \pgfkeys{/tikzuml/entityobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlentity, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/entityobj/.cd, #1}% + \umlobject[stereo=entity, #1]{#2}% +}% +\newcommand{\umlcontrol}[2][]{% + \pgfkeys{/tikzuml/controlobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlcontrol, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/controlobj/.cd, #1}% + \umlobject[stereo=control, #1]{#2}% +}% +\newcommand{\umlboundary}[2][]{% + \pgfkeys{/tikzuml/boundaryobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlboundary, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/boundaryobj/.cd, #1}% + \umlobject[stereo=boundary, #1]{#2}% +}% +\newcommand{\umlmulti}[2][]{% + \pgfkeys{/tikzuml/multiobj/.cd, .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlmulti, forbidden option stereo}% + }{}% + }% + }% + \pgfkeys{/tikzuml/multiobj/.cd, #1}% + \umlobject[stereo=multi, #1]{#2}% +}% +% +\newcounter{tikzumlSDNodeNum}% +% +% define a hidden node to lengthen lifeline of a object +% args : object node +% optional : dt: distance between the sdnode and the last call defined on the lifeline of the object +% name: name of the sdnode +\newcommand{\umlsdnode}[2][]{% + \pgfkeys{/tikzuml/sdnode/.cd, dt/.initial=0, name/.initial=tikzumlEmpty}% + \pgfkeys{/tikzuml/sdnode/.cd, #1}% + \pgfkeys{/tikzuml/sdnode/.cd, dt/.get=\tikzumlSDNodeDT, name/.get=\tikzumlSDNodeName}% + % + \ifthenelse{\equal{\tikzumlSDNodeName}{tikzumlEmpty}}{% + \expandafter\def\expandafter\tikzumlSDNode@nodeName{sdnode-\thetikzumlSDNodeNum}% + }{% + \expandafter\def\expandafter\tikzumlSDNode@nodeName{\tikzumlSDNodeName}% + }% + % + \stepcounter{tikzumlSDNodeNum}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlSDNode@objnodeName{#2}}\x% + % + \draw (\expandafter\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname)+(0,-\tikzumlSDNodeDT ex) node[name=\tikzumlSDNode@nodeName,coordinate] {};% + % + % update last node drawn on sender lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlSDNode@objnodeName \endcsname{\tikzumlSDNode@nodeName}% +}% +% +\newlength{\tikzumlCall@xa}% +\newlength{\tikzumlCall@xb}% +% +% define a uml operation call for sequence diagrams +% args : call sender +% call receiver +% optional : dt: time delay from precedent event end +% name: name of the call +% op: operation name and input args +% return: return value +% type: type of the call (synchron, asynchron) +% draw, fill, text: colors +% padding: time padding from call start and to call end +\newenvironment{umlcall}[3][]{% + \stepcounter{tikzumlCallNum}% + \def\tikzumlCallWithReturn{tikzumlFalse}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlCallBottom{0}% + % + \pgfkeys{/tikzuml/call/.cd, dt/.initial=\tikzumlCallDefaultDT, name/.initial={call-\thetikzumlCallNum},% + op/.initial={}, return/.initial={}, type/.initial=\tikzumlCallDefaultType,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + padding/.initial=\tikzumlCallDefaultPadding,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with return}}{% + \def\tikzumlCallWithReturn{tikzumlTrue}% + }{% + \errmessage{TIKZUML ERROR : in umlcall, invalid option \keyname}% + }% + }% + }% + \pgfkeys{/tikzuml/call/.cd, #1}% + \pgfkeys{/tikzuml/call/.cd, dt/.get=\tikzumlCallDT, name/.get=\tikzumlCallName, op/.get=\tikzumlCallOp,% + return/.get=\tikzumlCallReturn, type/.get=\tikzumlCallType,% + padding/.get=\tikzumlCallPadding,% + draw/.get=\tikzumlCallDrawColor, fill/.get=\tikzumlCallFillColor,% + text/.get=\tikzumlCallTextColor% + }% + % + \edef\tikzumlfillcall{\tikzumlCallFillColor}% + \edef\tikzumldrawcall{\tikzumlCallDrawColor}% + \edef\tikzumltextcall{\tikzumlCallTextColor}% + \edef\tikzumltypecall{\tikzumlCallType}% + % + \ifthenelse{\equal{\tikzumlCallDT}{tikzumlEmpty}}{% + \ifnum\thetikzumlCallNum=1% + \def\tikzumlCallDT{2}% + \def\tikzumlcallSrc{2}% + \else% + \def\tikzumlCallDT{2}% + \def\tikzumlcallSrc{1}% + \fi% + }{% + \def\tikzumlcallSrc{0}% + }% + % + \let\tikzumlCallStartNodeNameold\tikzumlCallStartNodeName% + \def\tikzumlCallStartNodeName{#2}% + \let\tikzumlCallEndNodeNameold\tikzumlCallEndNodeName% + \def\tikzumlCallEndNodeName{#3}% + \def\tikzumlcallheight{\tikzumlCallPadding}% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlCallDTold\tikzumlCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCallDTold}% + \edef\tikzumlCallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \edef\tikzumlCall@name{\tikzumlCallName}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlCallName}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCall@nodeName{\tikzumlCall@name}}\x% + % + \let\tikzumlCall@nodeNameold\tikzumlCall@nodeName% + % + \def\tikzumlcallstyle{tikzuml \tikzumlCallType-msg style}% + % + % top node of activity period of call sender + \begin{pgfonlayer}{connections}% + \pgfmathparse{\tikzumlCallDT+\tikzumlcallSrc}% + \draw (\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname)+(0,-\pgfmathresult ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (st-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + % + % update last node drawn on sender lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{st-\tikzumlCall@nodeName}% + % + % top node of activity period of call receiver + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (st-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \node[tikzuml activity style] (et-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- st-\tikzumlCall@nodeName) {};% + }% + % + % update last node drawn on receiver lifeline + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{et-\tikzumlCall@nodeName}% + \xdef\tikzumlCallBottomSrc{et-\tikzumlCall@nodeName}% + \end{pgfonlayer}% + % + \stepcounter{tikzumlCallLevel}% +}{% + \addtocounter{tikzumlCallLevel}{-1}% + % + % bottom nodes of activity periods of call sender and receiver + \begin{pgfonlayer}{connections}% + \ifnum\tikzumlCall@lastchildNum=\thetikzumlCallNum% + % + % this test occurs a bug with latex package preview + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \ifthenelse{\equal{\tikzumlCallReturn}{tikzumlEmpty}}{% + \pgfmathsetmacro{\tikzumlCallPaddingd}{0.5*\tikzumlCallPadding}% + }{% + \pgfmathsetmacro{\tikzumlCallPaddingd}{1.2*\tikzumlCallPadding}% + }% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlCallPaddingd ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \else% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlcallheightold\tikzumlCallPadding% + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}% + \edef\tikzumlcallheight{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1}% + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlcallheightold\tikzumlCallPadding% + \pgfmathparse{\tikzumlcallheightold+0.5*\tikzumlFragment@paddingy}% + \edef\tikzumlcallheight{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1}% + \fi% + % + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \draw (eb-\tikzumlCall@nodeName)+(0,-0.75*\tikzumlCallPadding ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- tikzumlTmpNode) {};% + }{% + \draw (\tikzumlCallBottomSrc)+(0,-\tikzumlcallheight ex) node[coordinate, name=tikzumlTmpNode] {};% + \node[tikzuml activity style] (eb-\tikzumlCall@nodeName) at (\tikzumlCallEndNodeName |- tikzumlTmpNode) {};% + \node[tikzuml activity style] (sb-\tikzumlCall@nodeName) at (\tikzumlCallStartNodeName |- eb-\tikzumlCall@nodeName) {};% + }% + % + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCall@nodeName}% + \fi% + \end{pgfonlayer}% + % + % draw activity periods + \begin{pgfonlayer}{activity}% + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + % draw root activity period only + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + }{% + % draw root activity period + \ifnum\thetikzumlCallLevel=0% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \else% + % draw root activity from inner call + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeNameold}}{}{% + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + \fi% + % draw receiver activity period + \draw[draw=\tikzumldrawcall, fill=\tikzumlfillcall] (et-\tikzumlCall@nodeName.north west) rectangle (eb-\tikzumlCall@nodeName.south east);% + }% + \end{pgfonlayer}% + \ifthenelse{\equal{\tikzumlCallDefaultFillColor}{\tikzumlCallFillColor}}{}{% + \fill[\tikzumlfillcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south east);% + \draw[\tikzumldrawcall] (st-\tikzumlCall@nodeName.north west) rectangle (sb-\tikzumlCall@nodeName.south west) (st-\tikzumlCall@nodeName.north east) rectangle (sb-\tikzumlCall@nodeName.south east);% + }% + % + % update last nodes drawn on sender and receiver lifelines + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallEndNodeName \endcsname{eb-\tikzumlCall@nodeName}% + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCallStartNodeName \endcsname{sb-\tikzumlCall@nodeName}% + % + % draw call arrows + \begin{pgfonlayer}{connections}% + \ifthenelse{\equal{\tikzumlCallStartNodeName}{\tikzumlCallEndNodeName}}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) % + -- ++(0,-0.75*\tikzumlCallPadding ex) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp} % + -- (et-\tikzumlCall@nodeName.east);% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- ++(2.5*\tikzumlCallPadding ex,0) + -- ++(0,-0.75*\tikzumlCallPadding ex) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, right, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn} % + -- (sb-\tikzumlCall@nodeName.east);% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + % draw call arrows + \pgfextractx{\tikzumlCall@xa}{\pgfpointanchor{\tikzumlCallStartNodeName}{center}}% + \pgfextractx{\tikzumlCall@xb}{\pgfpointanchor{\tikzumlCallEndNodeName}{center}}% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.east) -- (et-\tikzumlCall@nodeName.west) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};% + }{% + \draw[\tikzumlcallstyle, \tikzumldrawcall] (st-\tikzumlCall@nodeName.west) -- (et-\tikzumlCall@nodeName.east) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-op] {\tikzumlCallOp};% + }% + % + % draw return arrow and update fit for parent fragment + \ifthenelse{\equal{\tikzumltypecall}{synchron}}{% + \ifthenelse{\NOT\equal{\tikzumlCallReturn}{}\OR\equal{\tikzumlCallWithReturn}{tikzumlTrue}}{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op) (\tikzumlCall@nodeName-return)}% + \fi% + % + \ifthenelse{\tikzumlCall@xb>\tikzumlCall@xa}{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.west) -- (sb-\tikzumlCall@nodeName.east) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};% + }{% + \draw[tikzuml call return style, \tikzumldrawcall] (eb-\tikzumlCall@nodeName.east) -- (sb-\tikzumlCall@nodeName.west) % + node[font=\tikzumlDefaultFont, text=\tikzumltextcall, midway, above=-0.4ex, name=\tikzumlCall@nodeName-return] {\tikzumlCallReturn};% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }{% + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCall@nodeName) (et-\tikzumlCall@nodeName) (eb-\tikzumlCall@nodeName) (sb-\tikzumlCall@nodeName) (\tikzumlCall@nodeName-op)}% + \fi% + }% + }% + \end{pgfonlayer}% +}% +% +% alias for function self call +\newenvironment{umlcallself}[2][]{\begin{umlcall}[#1]{#2}{#2} }{\end{umlcall}}% +% +% define a combined fragment +% optional : name: name of fragment +% type: type of fragment (opt, alt, break, loop, par, critical, ignore, consider, assert, neg, weak, strict, ref) +% label: label of fragment (ex : condition for opt, iterator for loop, ...) +% inner xsep, inner ysep: padding of the fragment box +% draw, fill, text: colors +\newenvironment{umlfragment}[1][]{% + % define a fragment separator + % optional : label of the fragment part (ex : else for alt) + \providecommand{\umlfpart}[1][]{% + \stepcounter{tikzumlFragmentPartNum}% + % + \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-Part-tmp] {};% + \node[anchor=east, name=\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum] at (\tikzumlFragment@name-Part-tmp.north west |- \tikzumlCallBottomSrc) {\phantom{\tikzumlFragmentType}};% + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum.north west |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum] {};% + \draw (\tikzumlFragment@name-Part-tmp.north east |- \tikzumlCallBottomSrc)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum] {};% + \draw[dashed] (\tikzumlFragment@name-PartWest-\thetikzumlFragmentPartNum) -- (\tikzumlFragment@name-PartEast-\thetikzumlFragmentPartNum); + \draw (\tikzumlFragment@name-PartType-\thetikzumlFragmentPartNum)+(0,-0.4*\tikzumlFragment@paddingy ex) node[name=tikzumlTmpNode] {\phantom{\tikzumlFragmentType}};% + \node[anchor=north west] at (tikzumlTmpNode.south west) {[##1]};% + }% + % + \stepcounter{tikzumlFragmentNum}% + % + \pgfkeys{/tikzuml/fragment/.cd, name/.initial=fragment@\alph{tikzumlFragmentNum}, type/.initial=\tikzumlFragmentDefaultType,% + label/.initial=tikzumlEmpty,% + inner xsep/.initial=\tikzumlFragmentDefaultXSep, inner ysep/.initial=\tikzumlFragmentDefaultYSep,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlFragmentDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlfragment, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/fragment/.cd, #1}% + \pgfkeys{/tikzuml/fragment/.cd, name/.get=\tikzumlFragmentName, type/.get=\tikzumlFragmentType,% + label/.get=\tikzumlFragmentLabel,% + inner xsep/.get=\tikzumlFragmentXSep, inner ysep/.get=\tikzumlFragmentYSep,% + draw/.get=\tikzumlFragmentDrawColor, fill/.get=\tikzumlFragmentFillColor,% + text/.get=\tikzumlFragmentTextColor% + }% + % + \ifthenelse{\equal{\tikzumlFragmentLabel}{tikzumlEmpty}}{% + \def\tikzumlFragmentLabel{}% + }{% + \let\tikzumlFragmentLabelold\tikzumlFragmentLabel% + \def\tikzumlFragmentLabel{[\tikzumlFragmentLabelold]}% + }% + % + \ifnum\thetikzumlFragmentLevel>0% + \let\tikzumlFragment@parentold\tikzumlFragment@parent% + \let\tikzumlFragment@nameold\tikzumlFragment@name% + \edef\tikzumlFragment@parent{\tikzumlFragment@nameold}% + \else% + \setcounter{tikzumlFragmentPartNum}{0}% + \edef\tikzumlFragment@parent{}% + \edef\tikzumlFragment@parentold{}% + \edef\tikzumlFragment@nameold{}% + \fi% + % + \edef\tikzumlFragment@name{\tikzumlFragmentName}% + \expandafter\gdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{}% + % + \stepcounter{tikzumlFragmentLevel}% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallStartFragmentNum}% + \fi% + % + \pgfmathparse{6*\tikzumlFragmentYSep}% + \xdef\tikzumlFragment@paddingy{\pgfmathresult}% + \if\c@tikzumlFragmentLevelNum=0% + \setcounter{tikzumlFragmentLevelNum}{\thetikzumlFragmentLevel}% + \fi% + % + % time delay adjustment for two consecutive fragments + \ifnum\thetikzumlCallEndFragmentNum>0% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% +}{% + % + \addtocounter{tikzumlFragmentLevel}{-1}% + % + \ifnum\thetikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@parent \endcsname{\tikzumlFragmentFitOld (\tikzumlFragment@name)}% + \fi% + % + % draw working fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[outer sep=0, inner xsep=\tikzumlFragmentXSep ex, inner ysep=\tikzumlFragmentYSep ex, fit=\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname, name=\tikzumlFragment@name-back] {};% + \end{pgfonlayer}% + % + % draw type and label + \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north east, name=\tikzumlFragment@name-type] % + at (\tikzumlFragment@name-back.north west) {\tikzumlFragmentType};% + \node[text=\tikzumlFragmentTextColor, font=\tikzumlDefaultFont, anchor=north west, name=\tikzumlFragment@name-label] % + at (\tikzumlFragment@name-type.south west) {\tikzumlFragmentLabel};% + % + % draw final fragment box + \begin{pgfonlayer}{fragment\thetikzumlFragmentLevel}% + \node[draw=\tikzumlFragmentDrawColor, fill=\tikzumlFragmentFillColor, outer sep=0, inner sep=0, font=\tikzumlDefaultFont, fit=(\tikzumlFragment@name-back) (\tikzumlFragment@name-type) (\tikzumlFragment@name-label), name=\tikzumlFragment@name] {};% + \end{pgfonlayer}% + % + \draw[draw=\tikzumlFragmentDrawColor] (\tikzumlFragment@name.north west) rectangle (\tikzumlFragment@name.south east);% + \draw (\tikzumlFragment@name-type.south east)+(0,1ex) node[name=\tikzumlFragment@name-typetop, inner sep=0] {};% + \draw (\tikzumlFragment@name-type.south east)+(-1ex,0) node[name=\tikzumlFragment@name-typeleft, inner sep=0] {};% + \draw (\tikzumlFragment@name.north west) -| (\tikzumlFragment@name-typetop.center) -- (\tikzumlFragment@name-typeleft.center) -| (\tikzumlFragment@name.north west);% + % + \ifnum\thetikzumlCallLevel>0% + \stepcounter{tikzumlCallEndFragmentNum}% + \fi% +}% +% +% define a constructor call +% arg : call sender +% name of constructed object +% optional : x: coordinate of the new object +% stereo: stereotype of the new object +% class: class type of the new object +% dt: time delay from last event +% name: name of the call +% draw, fill, text: colors +% no ddots: when used, disable printing of double dots +\newcommand{\umlcreatecall}[3][]{% + \stepcounter{tikzumlCallNum}% + \edef\tikzumlCall@lastchildNum{\thetikzumlCallNum}% for testing presence of sub-calls + \gdef\tikzumlInCreateCall{1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.initial=tikzumlEmpty, stereo/.initial=\tikzumlObjectDefaultStereo, class/.initial={},% + dt/.initial=\tikzumlCreateCallDefaultDT, name/.initial=call-\thetikzumlCallNum,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlCallDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor,% + draw obj/.initial=\tikzumlDefaultDrawColor, fill obj/.initial=\tikzumlObjectDefaultFillColor,% + text obj/.initial=\tikzumlDefaultTextColor,% + no ddots/.is if=tikzumlcreatecallNoDDots,% + no ddots=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlcreatecall, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/createcall/.cd, #1}% + \pgfkeys{/tikzuml/createcall/.cd, x/.get=\tikzumlCreateCallX, stereo/.get=\tikzumlCreateCallStereo,% + class/.get=\tikzumlCreateCallClass,% + dt/.get=\tikzumlCreateCallDT, name/.get=\tikzumlCreateCallName,% + draw/.get=\tikzumlCreateCallDrawColor, fill/.get=\tikzumlCreateCallFillColor,% + text/.get=\tikzumlCreateCallTextColor,% + draw obj/.get=\tikzumlCreateCallObjectDrawColor, fill obj/.get=\tikzumlCreateCallObjectFillColor,% + text obj/.get=\tikzumlCreateCallObjectTextColor% + }% + % + \def\tikzumlCreateCallSrc@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCallSrc@nodeName{\tikzumlCreateCallSrc@name}}\x% + % + % managing time delays from previous/parent fragments + \ifnum\thetikzumlCallStartFragmentNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallStartFragmentNum}{-1} + \fi% + \ifnum\thetikzumlCallEndFragmentNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \addtocounter{tikzumlCallEndFragmentNum}{-1} + \fi% + \ifnum\thetikzumlFragmentPartNum>0% + \let\tikzumlCreateCallDTold\tikzumlCreateCallDT% + \pgfmathparse{0.5*\tikzumlFragment@paddingy+\tikzumlCreateCallDTold}% + \edef\tikzumlCreateCallDT{\pgfmathresult}% + \fi% + % + % managing parent-child structure + \ifnum\thetikzumlCallLevel>0% + \let\tikzumlCall@nameold\tikzumlCall@name% + \def\tikzumlCall@name{\tikzumlCreateCallName}% + \let\tikzumlCall@parentold\tikzumlCall@parent% + \edef\tikzumlCall@parent{\tikzumlCall@parentold @@\tikzumlCall@nameold}% + \else% + \edef\tikzumlCall@parent{}% + \edef\tikzumlCall@parentold{}% + \edef\tikzumlCall@nameold{} + \edef\tikzumlCall@name{\tikzumlCreateCallName}% + \fi% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlCreateCall@nodeName{\tikzumlCall@name}}\x% + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname)+(0,-\tikzumlCreateCallDT ex) node[name=st-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \xdef\tikzumlCreateCallObjectSrc{st-\tikzumlCreateCall@nodeName}% + % + \iftikzumlcreatecallNoDDots% + \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor, no ddots]{#3}% + \else + \umlobject[x=\tikzumlCreateCallX, stereo=\tikzumlCreateCallStereo, class=\tikzumlCreateCallClass, draw=\tikzumlCreateCallObjectDrawColor, fill=\tikzumlCreateCallObjectFillColor, text=\tikzumlCreateCallObjectTextColor]{#3}% + \fi + % + \draw (\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname |- #3)+(0,-0.5*\tikzumlCreateCallDT ex) node[name=sb-\tikzumlCreateCall@nodeName, tikzuml activity style] {};% + % + \expandafter\xdef\csname tikzumlLastChild@\tikzumlCreateCallSrc@nodeName \endcsname{sb-\tikzumlCreateCall@nodeName}% + \xdef\tikzumlCallBottomSrc{sb-\tikzumlCreateCall@nodeName}% + % + \begin{pgfonlayer}{connections}% + \draw[tikzuml synchron-msg style, \tikzumlCreateCallDrawColor] (st-\tikzumlCreateCall@nodeName) -- (#3) node[midway, above, font=\tikzumlDefaultFont, text=\tikzumlCreateCallTextColor, name=\tikzumlCreateCall@nodeName-op] {create};% + \end{pgfonlayer}% + % + \ifnum\thetikzumlCallLevel=0% + \begin{pgfonlayer}{activity}% + \draw[draw=\tikzumlCreateCallDrawColor, fill=\tikzumlCreateCallFillColor] (st-\tikzumlCreateCall@nodeName.north west) rectangle (sb-\tikzumlCreateCall@nodeName.south east);% + \end{pgfonlayer}% + \fi% + % add to fit fragment + \ifnum\c@tikzumlFragmentLevel>0% + \edef\tikzumlFragmentFitOld{\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname}% + \expandafter\xdef\csname tikzumlFragmentFit\tikzumlFragment@name \endcsname{\tikzumlFragmentFitOld (st-\tikzumlCreateCall@nodeName) (sb-\tikzumlCreateCall@nodeName) (\tikzumlCreateCall@nodeName-op) (#3) }% + \fi% +} +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% component diagrams % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +\tikzstyle{tikzuml connector style}=[color=\tikzumlDefaultDrawColor, -]% +% +\newcounter{tikzumlComponentLevel}% +\newcounter{tikzumlComponentSubComponentNum}% +\newcounter{tikzumlConnectorNum}% +\setcounter{tikzumlConnectorNum}{1}% +% +\newif\iftikzumlcomponentWithoutCoords% +% +\newcommand{\picturedcomponent}[1]{% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.initial=1, .unknown/.code={}}% + \pgfkeys{/tikzuml/component/picture/.cd,#1}% + \pgfkeys{/tikzuml/component/picture/.cd, scale/.get=\tikzumlComponentScale}% + \begin{tikzpicture}[#1]% + \filldraw (0,0) rectangle (1ex,1.5ex);% + \filldraw (-0.2ex,0.4ex) rectangle (0.2ex,0.6ex);% + \filldraw (-0.2ex,0.9ex) rectangle (0.2ex,1.1ex);% + \end{tikzpicture}% +}% +% +% define a uml component +% args : name of the component +% content of the component +% optional args : x,y coordinates of the component +% width of the component node +\newenvironment{umlcomponent}[2][]{% + \ifnum\thetikzumlComponentLevel>0% + \let\tikzumlComponent@nameold\tikzumlComponent@fitname% + \let\tikzumlComponent@parentold\tikzumlComponent@parent% + \edef\tikzumlComponent@parent{\tikzumlComponent@parentold @@\tikzumlComponent@nameold}% + \else% + \def\tikzumlComponent@parent{}% + \fi% + % + \stepcounter{tikzumlComponentLevel}% + % + \pgfkeys{/tikzuml/component/.cd, x/.initial=\tikzumlDefaultX, y/.initial=\tikzumlDefaultX, width/.initial=\tikzumlComponentDefaultWidth, name/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + text/.initial=\tikzumlDefaultTextColor, style/.style={},% + no coords/.is if=tikzumlcomponentWithoutCoords,% + no coords=false,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{above}\OR% + \equal{\keyname}{left}\OR% + \equal{\keyname}{below}\OR% + \equal{\keyname}{right}\OR% + \equal{\keyname}{above left}\OR% + \equal{\keyname}{above right}\OR% + \equal{\keyname}{below left}\OR% + \equal{\keyname}{below right}}{% + \IfSubStr{\keyvalue}{ of }{% + \pgfkeys{/tikzuml/component/.cd, no coords}% + }{}% + }{}% + \ifx\keyvalue\pgfkeysnovalue% + \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand once={\keyname}}% + \else% + \pgfkeys{/tikzuml/component/.cd, style/.append style/.expand twice={\expandafter\keyname\expandafter=\keyvalue}}% + \fi% + %\errmessage{TIKZUML ERROR : in umlcomponent, invalid option \keyname}% + }% + }% + \pgfkeys{/tikzuml/component/.cd, #1}% + \pgfkeys{/tikzuml/component/.cd, x/.get=\tikzumlComponentXShift, y/.get=\tikzumlComponentYShift,% + width/.get=\tikzumlComponentMinimumWidth, name/.get=\tikzumlComponentName,% + draw/.get=\tikzumlComponentDrawColor, fill/.get=\tikzumlComponentFillColor,% + text/.get=\tikzumlComponentTextColor% + }% + % + \ifthenelse{\equal{\tikzumlComponentName}{}}{% + \edef\tikzumlComponent@name{#2}% + }{% + \edef\tikzumlComponent@name{\tikzumlComponentName}% + }% + % + \begingroup% + \def\_{@}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@fitname{\tikzumlComponent@name}}\x% + % + \let\tikzumlComponent@nodeNameold\tikzumlComponent@nodeName% + \def\tikzumlComponent@caption{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlComponent@nodeName{\tikzumlComponent@name}}\x% + % + \expandafter\gdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{}% + % + \setcounter{tikzumlComponentSubComponentNum}{0}% + % + \begin{scope}[xshift=\tikzumlComponentXShift cm, yshift=\tikzumlComponentYShift cm]% +}{% + \addtocounter{tikzumlComponentLevel}{-1}% + \begin{pgfonlayer}{component\thetikzumlComponentLevel}% + % + % if contains nothing, one define a fictive node to enable the fit option + \ifnum\c@tikzumlComponentSubComponentNum=0% + \iftikzumlcomponentWithoutCoords% + \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) {\phantom{\tikzumlComponent@nodeName}};% + \else% + \node[inner ysep=0.5ex, minimum width=\tikzumlComponentMinimumWidth, font=\tikzumlDefaultFont, /tikzuml/component/style] (\tikzumlComponent@nodeName-root) at (0,0) {\phantom{\tikzumlComponent@nodeName}};% + \fi% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{(\tikzumlComponent@nodeName-root)}% + \fi% + % + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent\endcsname{\tikzumlComponentFitTmp (\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-caption)}% + \stepcounter{tikzumlComponentSubComponentNum}% + \fi% + % + \node[inner sep=2ex, font=\tikzumlDefaultFont, fit = \csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname] (\tikzumlComponent@nodeName-body) {};% + \node[above, font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-captiontmp) at (\tikzumlComponent@nodeName-body.north) {\tikzumlComponent@caption};% + \node (\tikzumlComponent@nodeName-logotmp) at (\tikzumlComponent@nodeName-captiontmp.north -| \tikzumlComponent@nodeName-body.east) {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };% + \node[draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, name=\tikzumlComponent@nodeName, /tikzuml/component/style, fit=(\tikzumlComponent@nodeName-body) (\tikzumlComponent@nodeName-captiontmp)] {};% + \node[font=\tikzumlDefaultFont] (\tikzumlComponent@nodeName-caption) at (\tikzumlComponent@nodeName-captiontmp) {\tikzumlComponent@caption};% + \draw (\tikzumlComponent@nodeName-caption.north -| \tikzumlComponent@nodeName.east) node[font=\tikzumlDefaultFont, xshift=-1ex, below=-1ex, name=\tikzumlComponent@nodeName-logo] {\picturedcomponent{draw=\tikzumlComponentDrawColor, fill=\tikzumlComponentFillColor, font=\tikzumlDefaultFont} };% + \draw (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north west) -- (\tikzumlComponent@nodeName-caption.south -| \tikzumlComponent@nodeName.north east);% + \coordinate (\tikzumlComponent@nodeName-west-port) at (\tikzumlComponent@nodeName.west); + \coordinate (\tikzumlComponent@nodeName-east-port) at (\tikzumlComponent@nodeName.east); + \coordinate (\tikzumlComponent@nodeName-south-port) at (\tikzumlComponent@nodeName.south); + \coordinate (\tikzumlComponent@nodeName-north-port) at (\tikzumlComponent@nodeName.north); + \end{pgfonlayer}% + \end{scope}% + % + % add to fit + \ifnum\c@tikzumlPackageLevel>0% + \edef\tikzumlPackageFitOld{\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname}% + \expandafter\xdef\csname tikzumlPackageFit\tikzumlPackage@parent @@\tikzumlPackage@fitname\endcsname{\tikzumlPackageFitOld (\tikzumlComponent@nodeName)}% + \stepcounter{tikzumlPackageClassNum}% + \fi% +}% +% +% shortcut for empty component +\newcommand{\umlbasiccomponent}[2][]{\begin{umlcomponent}[#1]{#2} \end{umlcomponent}}% +% +\newcommand{\umlrequiredinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlRequiredInterfaceDefaultDistance,% + name/.initial=tikzumlEmpty, width/.initial=\tikzumlRequiredInterfaceDefaultWidth,% + padding/.initial=\tikzumlRequiredInterfaceDefaultPadding,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/requiredinterfacerelation/.cd, interface/.get=\tikzumlRequiredInterfaceLabel,% + distance/.get=\tikzumlRequiredInterfaceDistance,% + name/.get=\tikzumlRequiredInterfaceName,% + width/.get=\tikzumlRequiredInterfaceWidth,% + padding/.get=\tikzumlRequiredInterfacePadding,% + draw/.get=\tikzumlRequiredInterfaceDrawColor,% + fill/.get=\tikzumlRequiredInterfaceFillColor% + }% + % + \ifthenelse{\equal{\tikzumlRequiredInterfaceName}{tikzumlEmpty}}{% + \edef\tikzumlRequiredInterface@interfacename{#2-east-interface}% + \edef\tikzumlRequiredInterface@portname{#2-east-port}% + \edef\tikzumlRequiredInterface@paddingname{#2-east-padding}% + }{% + \edef\tikzumlRequiredInterface@interfacename{\tikzumlRequiredInterfaceName}% + \edef\tikzumlRequiredInterface@portname{\tikzumlRequiredInterfaceName-port}% + \edef\tikzumlRequiredInterface@paddingname{\tikzumlRequiredInterfaceName-padding}% + }% + % + \edef\tikzumlRequiredInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@nodeName{\tikzumlRequiredInterface@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@interfacenodeName{\tikzumlRequiredInterface@interfacename}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@portnodeName{\tikzumlRequiredInterface@portname}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlRequiredInterface@paddingnodeName{\tikzumlRequiredInterface@paddingname}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlRequiredInterfaceWidth, rectangle, draw=\tikzumlRequiredInterfaceDrawColor, fill=\tikzumlRequiredInterfaceFillColor] (\tikzumlRequiredInterface@portnodeName) at (\tikzumlRequiredInterface@nodeName.east) {};% + }{% + \node[inner sep=0] (\tikzumlRequiredInterface@nodeName-east-port) at (\tikzumlRequiredInterface@nodeName.east) {};% + }% + \begin{scope}% + \draw (\tikzumlRequiredInterface@nodeName)+(\tikzumlRequiredInterfaceDistance,0) node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, name=\tikzumlRequiredInterface@interfacenodeName-tmp] {};% + \clip (\tikzumlRequiredInterface@interfacenodeName-tmp.north) rectangle (\tikzumlRequiredInterface@interfacenodeName-tmp.south -| \tikzumlRequiredInterface@interfacenodeName-tmp.west);% + \node[inner sep=0, text width=\tikzumlRequiredInterfaceWidth, circle, draw=\tikzumlRequiredInterfaceDrawColor] (\tikzumlRequiredInterface@interfacenodeName) at (\tikzumlRequiredInterface@interfacenodeName-tmp) {};% + \end{scope}% + \node[above] at (\tikzumlRequiredInterface@interfacenodeName.north) {\tikzumlRequiredInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlRequiredInterface@portnodeName}{\tikzumlRequiredInterface@interfacenodeName}% + % + \draw (\tikzumlRequiredInterface@interfacenodeName)+(\tikzumlRequiredInterfacePadding,0) node[name=\tikzumlRequiredInterface@paddingnodeName] {};% + % + % add to fit + \ifnum\c@tikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlRequiredInterface@paddingnodeName) (\tikzumlRequiredInterface@portnodeName) }% + \fi% +}% +% +\newcommand{\umlprovidedinterface}[2][]{% + \def\tikzumlInterfaceWithPort{tikzumlFalse}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.initial={}, distance/.initial=\tikzumlProvidedInterfaceDefaultDistance,% + name/.initial=tikzumlEmpty, width/.initial=\tikzumlProvidedInterfaceDefaultWidth,% + padding/.initial=\tikzumlProvidedInterfaceDefaultPadding,% + draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlComponentDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlInterfaceWithPort{tikzumlTrue}% + }{}% + }% + }% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, #1}% + \pgfkeys{/tikzuml/providedinterfacerelation/.cd, interface/.get=\tikzumlProvidedInterfaceLabel,% + distance/.get=\tikzumlProvidedInterfaceDistance,% + name/.get=\tikzumlProvidedInterfaceName,% + width/.get=\tikzumlProvidedInterfaceWidth,% + padding/.get=\tikzumlProvidedInterfacePadding,% + draw/.get=\tikzumlProvidedInterfaceDrawColor,% + fill/.get=\tikzumlProvidedInterfaceFillColor% + }% + % + \ifthenelse{\equal{\tikzumlProvidedInterfaceName}{tikzumlEmpty}}{% + \edef\tikzumlProvidedInterface@interfacename{#2-west-interface}% + \edef\tikzumlProvidedInterface@portname{#2-west-port}% + \edef\tikzumlProvidedInterface@paddingname{#2-west-padding}% + }{% + \edef\tikzumlProvidedInterface@interfacename{\tikzumlProvidedInterfaceName}% + \edef\tikzumlProvidedInterface@portname{\tikzumlProvidedInterfaceName-port}% + \edef\tikzumlProvidedInterface@paddingname{\tikzumlProvidedInterfaceName-padding}% + }% + % + \edef\tikzumlProvidedInterface@name{#2}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@nodeName{\tikzumlProvidedInterface@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@interfacenodeName{\tikzumlProvidedInterface@interfacename}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@portnodeName{\tikzumlProvidedInterface@portname}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlProvidedInterface@paddingnodeName{\tikzumlProvidedInterface@paddingname}}\x% + % + \ifthenelse{\equal{\tikzumlInterfaceWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlProvidedInterfaceWidth, rectangle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};% + }{% + \node[inner sep=0] (\tikzumlProvidedInterface@portnodeName) at (\tikzumlProvidedInterface@nodeName.west) {};% + }% + \draw (\tikzumlProvidedInterface@nodeName)+(-\tikzumlProvidedInterfaceDistance,0) node[inner sep=0, text width=\tikzumlProvidedInterfaceWidth, circle, draw=\tikzumlProvidedInterfaceDrawColor, fill=\tikzumlProvidedInterfaceFillColor, name=\tikzumlProvidedInterface@interfacenodeName] {};% + \node[above] at (\tikzumlProvidedInterface@interfacenodeName.north) + {\tikzumlProvidedInterfaceLabel};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlProvidedInterface@portnodeName}{\tikzumlProvidedInterface@interfacenodeName}% + % + \draw (\tikzumlProvidedInterface@interfacenodeName)+(-\tikzumlProvidedInterfacePadding,0) node[name=\tikzumlProvidedInterface@paddingnodeName] {};% + % + % add to fit + \ifnum\thetikzumlComponentLevel>0% + \def\tikzumlComponentFitTmp{\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname}% + \expandafter\xdef\csname tikzumlComponentFit\tikzumlComponent@parent @@\tikzumlComponent@fitname\endcsname{\tikzumlComponentFitTmp (\tikzumlProvidedInterface@paddingnodeName) (\tikzumlProvidedInterface@portnodeName) }% + \fi% +}% +% +\newlength{\tikzuml@AC@xa}% +\newlength{\tikzuml@AC@ya}% +\newlength{\tikzuml@AC@xb}% +\newlength{\tikzuml@AC@yb}% +\newlength{\tikzuml@AC@xi}% +\newlength{\tikzuml@AC@yi}% +\newlength{\tikzuml@AC@xic}% +\newlength{\tikzuml@AC@yic}% +\newlength{\tikzuml@AC@xio}% +\newlength{\tikzuml@AC@yio}% +\newlength{\tikzuml@AC@AB}% +\newlength{\tikzuml@AC@lambda}% +\newlength{\tikzuml@AC@xtrc}% +\newlength{\tikzuml@AC@ytrc}% +\newlength{\tikzuml@AC@xtlc}% +\newlength{\tikzuml@AC@ytlc}% +\newlength{\tikzuml@AC@xblc}% +\newlength{\tikzuml@AC@yblc}% +\newlength{\tikzuml@AC@xbrc}% +\newlength{\tikzuml@AC@ybrc}% +\newlength{\tikzuml@AC@middleArm}% +% +\newcommand{\umlassemblyconnectorsymbol}[2]{% + \ifthenelse{\NOT\equal{\tikzumlAssemblyConnectorLabel}{}}{% + \edef\tikzuml@ACStart@name{#1}% + \edef\tikzuml@ACEnd@name{#2}% + \edef\tikzuml@AC@width{\tikzumlAssemblyConnectorWidth}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACStart@nodeName{\tikzuml@ACStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACEnd@nodeName{\tikzuml@ACEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzuml@ACInterface@nodeName{\tikzumlAssemblyConnectorSymbolName}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzuml@ACStart@nodeName}{\tikzumlAssemblyConnectorStartAnchor}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzuml@ACEnd@nodeName}{\tikzumlAssemblyConnectorEndAnchor}}% + \pgfmathsetlength{\tikzuml@AC@xi}{0.5*\tikzuml@AC@xa+0.5*\tikzuml@AC@xb}% + \pgfmathsetlength{\tikzuml@AC@yi}{0.5*\tikzuml@AC@ya+0.5*\tikzuml@AC@yb}% + \pgfmathsetlength{\tikzuml@AC@AB}{veclen(\tikzuml@AC@xa-\tikzuml@AC@xb,\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@lambda}{0.25*\tikzuml@AC@width/\tikzuml@AC@AB}% + \pgfmathsetlength{\tikzuml@AC@xic}{\tikzuml@AC@xi-\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yic}{\tikzuml@AC@yi-\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@xio}{\tikzuml@AC@xi+\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@yio}{\tikzuml@AC@yi+\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \node[inner sep=0.5*\tikzuml@AC@width] (\tikzuml@ACInterface@nodeName-interface) at (\tikzuml@AC@xi,\tikzuml@AC@yi) {};% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-io) at (\tikzuml@AC@xio,\tikzuml@AC@yio) {};% + \begin{scope}% + \pgfmathsetlength{\tikzuml@AC@xtrc}{\tikzuml@AC@xic-2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ytrc}{\tikzuml@AC@yic+2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xbrc}{\tikzuml@AC@xic+2*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \pgfmathsetlength{\tikzuml@AC@ybrc}{\tikzuml@AC@yic-2*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@xtlc}{\tikzuml@AC@xic-3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xb-\tikzuml@AC@xa)}% + \pgfmathsetlength{\tikzuml@AC@ytlc}{\tikzuml@AC@yic+3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@ya-\tikzuml@AC@yb)}% + \pgfmathsetlength{\tikzuml@AC@xblc}{\tikzuml@AC@xic+3*\tikzuml@AC@lambda*(\tikzuml@AC@yb-\tikzuml@AC@ya+\tikzuml@AC@xa-\tikzuml@AC@xb)}% + \pgfmathsetlength{\tikzuml@AC@yblc}{\tikzuml@AC@yic-3*\tikzuml@AC@lambda*(\tikzuml@AC@xb-\tikzuml@AC@xa+\tikzuml@AC@yb-\tikzuml@AC@ya)}% + \coordinate (\tikzuml@ACInterface@nodeName-trc) at (\tikzuml@AC@xtrc,\tikzuml@AC@ytrc);% + \coordinate (\tikzuml@ACInterface@nodeName-brc) at (\tikzuml@AC@xbrc,\tikzuml@AC@ybrc);% + \coordinate (\tikzuml@ACInterface@nodeName-tlc) at (\tikzuml@AC@xtlc,\tikzuml@AC@ytlc);% + \coordinate (\tikzuml@ACInterface@nodeName-blc) at (\tikzuml@AC@xblc,\tikzuml@AC@yblc);% + \clip (\tikzuml@ACInterface@nodeName-trc) -- (\tikzuml@ACInterface@nodeName-tlc) -- (\tikzuml@ACInterface@nodeName-blc) -- (\tikzuml@ACInterface@nodeName-brc) -- cycle;% + \node[inner sep=0, text width=\tikzuml@AC@width, circle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorFillColor] (\tikzuml@ACInterface@nodeName-ic) at (\tikzuml@AC@xic,\tikzuml@AC@yic) {};% + \end{scope}% + \node[above, font=\tikzumlDefaultFont] at (\tikzuml@ACInterface@nodeName-interface.north) + {\tikzumlAssemblyConnectorLabel};% + }{}% +}% +% +\newcommand{\umlassemblyconnector}[3][]{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlFalse}% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlFalse}% + \def\tikzumlAssemblyConnectorLastArm{tikzumlFalse}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.initial=--, interface/.initial={},% + arm1/.initial={auto}, arm2/.initial={auto},% + name/.initial=connector-\thetikzumlConnectorNum, width/.initial=1em,% + anchor1/.initial={}, anchor2/.initial={},% + draw/.initial=\tikzumlDefaultDrawColor,% + fill assembly connector/.initial=\tikzumlAssemblyConnectorDefaultFillColor,% + fill port/.initial=\tikzumlPortDefaultFillColor,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{with port}}{% + \def\tikzumlAssemblyConnectorWithPort{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{first arm}}{% + \def\tikzumlAssemblyConnectorFirstArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{second arm}}{% + \def\tikzumlAssemblyConnectorSecondArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{middle arm}}{% + \def\tikzumlAssemblyConnectorMiddleArm{tikzumlTrue}% + }{% + \ifthenelse{\equal{\keyname}{last arm}}{% + \def\tikzumlAssemblyConnectorLastArm{tikzumlTrue}% + }{% + }% + }% + }% + }% + }% + }% + }% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, #1}% + \pgfkeys{/tikzuml/assemblyconnectorrelation/.cd, geometry/.get=\tikzumlAssemblyConnectorGeometry,% + name/.get=\tikzumlAssemblyConnectorName,% + interface/.get=\tikzumlAssemblyConnectorLabel,% + width/.get=\tikzumlAssemblyConnectorWidth,% + arm1/.get=\tikzumlAssemblyConnectorStartArm,% + arm2/.get=\tikzumlAssemblyConnectorEndArm,% + anchor1/.get=\tikzumlAssemblyConnectorStartAnchorTmp,% + anchor2/.get=\tikzumlAssemblyConnectorEndAnchorTmp,% + draw/.get=\tikzumlAssemblyConnectorDrawColor,% + fill assembly connector/.get=\tikzumlAssemblyConnectorFillColor,% + fill port/.get=\tikzumlAssemblyConnectorPortFillColor% + }% + % + \edef\tikzumlAssemblyConnectorStart@name{#2}% + \edef\tikzumlAssemblyConnectorEnd@name{#3}% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorStart@nodeName{\tikzumlAssemblyConnectorStart@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorEnd@nodeName{\tikzumlAssemblyConnectorEnd@name}}\x% + % + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlAssemblyConnectorLabel@nodeName{\tikzumlAssemblyConnectorLabel}}\x% + % + \pgfextractx{\tikzuml@AC@xa}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@ya}{\pgfpointanchor{\tikzumlAssemblyConnectorStart@nodeName}{center}}% + \pgfextractx{\tikzuml@AC@xb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + \pgfextracty{\tikzuml@AC@yb}{\pgfpointanchor{\tikzumlAssemblyConnectorEnd@nodeName}{center}}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\tikzuml@AC@xb>\tikzuml@AC@xa}{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + } + \ifthenelse{\tikzuml@AC@yb>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@xa + 0.5 * \tikzuml@AC@xb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@xa+\tikzumlAssemblyConnectorStartArm}% + }% + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xa} + \pgfmathparse{\tikzuml@AC@middleArm>\tikzuml@AC@xb} + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xa}}{% + \def\tikzumlAssemblyConnectorStartAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{west}% + } + \ifthenelse{\lengthtest{\tikzuml@AC@middleArm>\tikzuml@AC@xb}}{% + \def\tikzumlAssemblyConnectorEndAnchor{east}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{west}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartArm}{auto}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndArm}{auto}}{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{0.5 * \tikzuml@AC@ya + 0.5 * \tikzuml@AC@yb}% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@yb+\tikzumlAssemblyConnectorEndArm}% + }% + }{% + \pgfmathsetlength{\tikzuml@AC@middleArm}{\tikzuml@AC@ya+\tikzumlAssemblyConnectorStartArm}% + }% + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@ya}{% + \def\tikzumlAssemblyConnectorStartAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{south}% + } + \ifthenelse{\tikzuml@AC@middleArm>\tikzuml@AC@yb}{% + \def\tikzumlAssemblyConnectorEndAnchor{north}% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{south}% + } + }{}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorStartAnchorTmp}{}}{% + }{% + \def\tikzumlAssemblyConnectorStartAnchor{\tikzumlAssemblyConnectorStartAnchorTmp}% + }% + \ifthenelse{\equal{\tikzumlAssemblyConnectorEndAnchorTmp}{}}{% + }{% + \def\tikzumlAssemblyConnectorEndAnchor{\tikzumlAssemblyConnectorEndAnchorTmp}% + }% + % + \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + % + \umlrelation[style={tikzuml connector style}, #1]{\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}{\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorWithPort}{tikzumlTrue}}{% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% + \node[inner sep=0.5*\tikzumlAssemblyConnectorWidth, rectangle, draw=\tikzumlAssemblyConnectorDrawColor, fill=\tikzumlAssemblyConnectorPortFillColor] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port-tmp) {};% + }{% + \node[inner sep=0] (\tikzumlAssemblyConnectorStart@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorStart@nodeName.\tikzumlAssemblyConnectorStartAnchor) {};% + \node[inner sep=0] (\tikzumlAssemblyConnectorEnd@nodeName-\tikzumlAssemblyConnectorLabel@nodeName-port) at (\tikzumlAssemblyConnectorEnd@nodeName.\tikzumlAssemblyConnectorEndAnchor) {};% + }% + % + \addtocounter{tikzumlRelationNum}{-1}% + \ifthenelse{\equal{\tikzumlAssemblyConnectorName}{connector-\thetikzumlConnectorNum}}{% + \edef\tikzumlAssemblyConnectorName{relation-\thetikzumlRelationNum}% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorLabel@nodeName}% + }{% + \edef\tikzumlAssemblyConnectorSymbolName{\tikzumlAssemblyConnectorName}% + }% + % + \stepcounter{tikzumlRelationNum}% + % + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{--}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorEnd@nodeName}% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{-|-}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorGeometry}{|-|}}{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorFirstArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorStart@nodeName}{\tikzumlAssemblyConnectorName-2}% + }{% + \ifthenelse{\equal{\tikzumlAssemblyConnectorLastArm}{tikzumlTrue}}{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-4}{\tikzumlAssemblyConnectorEnd@nodeName}% + }{% + \umlassemblyconnectorsymbol{\tikzumlAssemblyConnectorName-2}{\tikzumlAssemblyConnectorName-4}% + }% + }% + }{}% + }% + }% + }% + }% + \stepcounter{tikzumlConnectorNum}% +}% +% +% shortcuts of \umlassemblyconnector +\newcommand{\umlHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHassemblyconnector, forbidden option geometry}% + }{}% + }% + }% + \pgfkeys{/tikzuml/VHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlHVHassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVassemblyconnector}[3][]{% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}}{% + \errmessage{TIKZUML ERROR : in umlVHVassemblyconnector, forbidden option geometry}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVassemblyconnector/.cd, #1}% + \umlassemblyconnector[geometry=|-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlport}[3][]{% + \pgfkeys{/tikzuml/port/.cd, draw/.initial=\tikzumlDefaultDrawColor, fill/.initial=\tikzumlPortDefaultFillColor,% + width/.initial=\tikzumlPortDefaultWidth,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \errmessage{TIKZUML ERROR : in umlport forbidden option \keyname}% + }% + }% + \pgfkeys{/tikzuml/port/.cd, #1}% + \pgfkeys{/tikzuml/port/.cd, width/.get=\tikzumlPortWidth,% + draw/.get=\tikzumlPortDrawColor, fill/.get=\tikzumlPortFillColor}% + \edef\tikzumlPort@name{#2}% + \edef\tikzumlPort@anchor{#3}% + \begingroup% + \def\_{_}\edef\x{\endgroup% + \def\noexpand\tikzumlPort@nodeName{\tikzumlPort@name}}\x% + % + \node[inner sep=0.5*\tikzumlPortWidth, rectangle, draw=\tikzumlPortDrawColor, fill=\tikzumlPortFillColor] (\tikzumlPort@nodeName-\tikzumlPort@anchor-port) at (\tikzumlPort@nodeName.\tikzumlPort@anchor) {};% +}% +% +\newcommand{\umldelegateconnector}[3][]{% + \def\tikzumlDelegateConnectorWithStartPort{tikzumlFalse}% + \def\tikzumlDelegateConnectorWithEndPort{tikzumlFalse}% + \pgfkeys{/tikzuml/delegateconnector/.cd, + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umldelegateconnector, forbidden option stereo}% + }{}% + }}% + \pgfkeys{/tikzuml/delegateconnector/.cd, #1}% + \umlrelation[style={tikzuml connector style}, stereo=delegate, #1]{#2}{#3}% +}% +% +% shortcuts of \umldelegateconnector +\newcommand{\umlHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/HVdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=-|, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/VHdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlHVHdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlHVHdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/HVHdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=-|-, #1]{#2}{#3}% +}% +% +\newcommand{\umlVHVdelegateconnector}[3][]{% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd,% + .unknown/.code={% + \let\keyname=\pgfkeyscurrentname% + \let\keyvalue=\pgfkeyscurrentvalue% + \ifthenelse{\equal{\keyname}{geometry}\OR\equal{\keyname}{stereo}}{% + \errmessage{TIKZUML ERROR : in umlVHVdelegateconnector, forbidden option \keyname}% + }{}% + }}% + \pgfkeys{/tikzuml/VHVdelegateconnector/.cd, #1}% + \umldelegateconnector[geometry=|-|, #1]{#2}{#3}% +}% +%%% End of tikz-uml.sty +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/joss/figures/uml_diagram.pdf b/joss/figures/uml_diagram.pdf new file mode 100644 index 000000000..f825050be Binary files /dev/null and b/joss/figures/uml_diagram.pdf differ diff --git a/joss/figures/uml_diagram.tex b/joss/figures/uml_diagram.tex new file mode 100755 index 000000000..ff1eee36a --- /dev/null +++ b/joss/figures/uml_diagram.tex @@ -0,0 +1,132 @@ +\documentclass[tikz,border=2pt,multi]{standalone} +\usepackage{xcolor} +\usepackage{tikz-uml} +\usetikzlibrary{decorations.text} + +\definecolor{constraint_relaxation_color}{HTML}{cab2d6} +\definecolor{inequality_method_color}{HTML}{92b9e1} +\definecolor{mechanism_color}{HTML}{FFCCAC} +\definecolor{strategy_color}{HTML}{FFEB94} +\definecolor{subproblem_color}{HTML}{C1E1DC} + +\begin{document} + +\begin{tikzpicture}[scale=1.15] +\tikzset{mechanism/.style={fill=mechanism_color}} +\tikzset{constraint_relaxation/.style={fill=constraint_relaxation_color}} +\tikzset{inequality_handling/.style={fill=inequality_method_color}} +\tikzset{strategy/.style={fill=strategy_color}} +\tikzset{subproblem/.style={fill=subproblem_color}} +\tikzset{subclass/.style={opacity=1}} + +\umlclass[x=0, y=2.2]{Uno}{ + globalization\_mechanism +}{ + solve() +} + +% GlobalizationMechanism +\umlabstract[mechanism]{GlobalizationMechanism}{ + constraint\_relaxation\_strategy +}{ + compute\_acceptable\_iterate() +} +\umlsimpleclass[mechanism, subclass, x=-5]{BacktrackingLineSearch} +\umlsimpleclass[mechanism, subclass, x=4.8]{TrustRegionStrategy} + +% Constraint relaxation strategy +\umlabstract[constraint_relaxation, x=0, y=-2.4]{ConstraintRelaxationStrategy}{ + inequality\_handling\_method +}{ + compute\_feasible\_direction() \\ + is\_acceptable() +} +\umlsimpleclass[constraint_relaxation, subclass, x=-4.9, y=-2.4]{FeasibilityRestoration} +%\umlsimpleclass[constraint_relaxation, subclass, x=5.25, y=-2.4]{l1Relaxation} + +% Inequality handling method +\umlabstract[inequality_handling, x=-5, y=-4.9]{InequalityHandlingMethod}{ + subproblem +}{ + reformulate\_problem() +} +\umlsimpleclass[inequality_handling, subclass, x=-5.2, y=-6.5]{InequalityConstrainedMethod} +\umlsimpleclass[inequality_handling, subclass, x=-5.9, y=-7.4]{InteriorPointMethod} + +% Subproblem +\umlabstract[subproblem, x=0, y=-4.9]{Subproblem}{ + hessian\_model \\ + inertia\_correction\_strategy +}{ +} + +% Subproblem solver +\umlabstract[x=4.5, y=-2.8]{SubproblemSolver}{ +}{ + solve() +} + +% Hessian model +\umlabstract[subproblem, x=-2.5, y=-8.2]{HessianModel}{ +}{ + evaluate \\ + compute\_hv +} +\umlsimpleclass[subproblem, subclass, x=-6, y=-9.8]{ExactHessian} +\umlsimpleclass[subproblem, subclass, x=-5, y=-10.6]{QuasiNewtonHessian} +\umlsimpleclass[subproblem, subclass, x=-6.5, y=-11.4]{IdentityHessian} +\umlsimpleclass[subproblem, subclass, x=-5.5, y=-12.2]{ZeroHessian} + +% Inertia correction +\umlabstract[subproblem, x=1.2, y=-8.2]{InertiaCorrectionStrategy}{ +}{ + regularize\_hessian \\ + regularize\_augmented\_matrix +} +\umlsimpleclass[subproblem, subclass, x=2, y=-9.8]{PrimalInertiaCorrection} +\umlsimpleclass[subproblem, subclass, x=3, y=-10.6]{PrimalDualInertiaCorrection} +\umlsimpleclass[subproblem, subclass, x=2, y=-11.4]{NoInertiaCorrection} + +% Globalization strategy +\umlabstract[strategy, x=4.5, y=-4.7]{GlobalizationStrategy}{ +}{ + check\_acceptance() +} +\umlsimpleclass[strategy, subclass, x=5.2, y=-6.3]{MeritFunction} +\umlsimpleclass[strategy, subclass, x=5.5, y=-7.2]{FilterMethod} +\umlsimpleclass[strategy, subclass, x=5, y=-8.1]{FunnelMethod} + +% links +\umlcompo{GlobalizationMechanism}{Uno} +\umlimpl[subclass]{BacktrackingLineSearch}{GlobalizationMechanism} +\umlimpl[subclass]{TrustRegionStrategy}{GlobalizationMechanism} + +\umlcompo{ConstraintRelaxationStrategy}{GlobalizationMechanism} +\umlimpl[subclass]{FeasibilityRestoration}{ConstraintRelaxationStrategy} +%\umlimpl[subclass]{l1Relaxation}{ConstraintRelaxationStrategy} + +\umlcompo{InequalityHandlingMethod}{ConstraintRelaxationStrategy} +\umlimpl[subclass]{InequalityConstrainedMethod}{InequalityHandlingMethod} +\umlimpl[subclass]{InteriorPointMethod}{InequalityHandlingMethod} + +\umlcompo{SubproblemSolver}{ConstraintRelaxationStrategy} + +\umlcompo{GlobalizationStrategy}{ConstraintRelaxationStrategy} +\umlimpl[subclass]{MeritFunction}{GlobalizationStrategy} +\umlimpl[subclass]{FilterMethod}{GlobalizationStrategy} +\umlimpl[subclass]{FunnelMethod}{GlobalizationStrategy} + +\umlcompo{Subproblem}{ConstraintRelaxationStrategy} + +\umlcompo{HessianModel}{Subproblem} +\umlimpl[subclass]{ExactHessian}{HessianModel} +\umlimpl[subclass]{QuasiNewtonHessian}{HessianModel} +\umlimpl[subclass]{IdentityHessian}{HessianModel} +\umlimpl[subclass]{ZeroHessian}{HessianModel} + +\umlcompo{InertiaCorrectionStrategy}{Subproblem} +\umlimpl[subclass]{PrimalInertiaCorrection}{InertiaCorrectionStrategy} +\umlimpl[subclass]{PrimalDualInertiaCorrection}{InertiaCorrectionStrategy} +\umlimpl[subclass]{NoInertiaCorrection}{InertiaCorrectionStrategy} +\end{tikzpicture} +\end{document} \ No newline at end of file diff --git a/joss/figures/wheel.pdf b/joss/figures/wheel.pdf new file mode 100644 index 000000000..047b1b0f0 Binary files /dev/null and b/joss/figures/wheel.pdf differ diff --git a/joss/figures/wheel.tex b/joss/figures/wheel.tex new file mode 100644 index 000000000..1a528dda0 --- /dev/null +++ b/joss/figures/wheel.tex @@ -0,0 +1,127 @@ +\documentclass[tikz,border=2pt,multi]{standalone} +\usepackage{xcolor} +\usetikzlibrary{decorations.text} + +\definecolor{constraint_relaxation_color}{HTML}{cab2d6} +\definecolor{inequality_method_color}{HTML}{92b9e1} +\definecolor{mechanism_color}{HTML}{FFCCAC} +\definecolor{strategy_color}{HTML}{FFEB94} +\definecolor{subproblem_color}{HTML}{C1E1DC} +\definecolor{darkgreen}{rgb}{0, 0.5, 0} + +\begin{document} +\begin{tikzpicture} +\newcommand\smallestradius{ 0.6 cm} +\newcommand\smallradius{ 5.5 cm} +\newcommand\middleradius{ 7 cm} +\newcommand\largeradius{ 8 cm} + +% draw colors of layers +\filldraw[fill=white] (0: \largeradius) arc (0:102.85714285714286:\largeradius) -- (102.85714285714286: \middleradius) arc (102.85714285714286:0:\middleradius) -- cycle; +\filldraw[fill=subproblem_color] (102.85714285714286: \largeradius) arc (102.85714285714286:205.71428571428572:\largeradius) -- (205.71428571428572: \middleradius) arc (205.71428571428572:102.85714285714286:\middleradius) -- cycle; +\filldraw[fill=white] (205.71428571428572: \largeradius) arc (205.71428571428572:257.14285714285717:\largeradius) -- (257.14285714285717: \middleradius) arc (257.14285714285717:205.71428571428572:\middleradius) -- cycle; +\filldraw[fill=white] (257.14285714285717: \largeradius) arc (257.14285714285717:360.0:\largeradius) -- (360.0: \middleradius) arc (360.0:257.14285714285717:\middleradius) -- cycle; + +% draw colors of ingredients +\filldraw[fill=constraint_relaxation_color] (0: \middleradius) arc (0:51.42857142857143:\middleradius) -- (51.42857142857143: \smallradius) arc (51.42857142857143:0:\smallradius) -- cycle; +\filldraw[fill=inequality_method_color] (51.42857142857143: \middleradius) arc (51.42857142857143:102.85714285714286:\middleradius) -- (102.85714285714286: \smallradius) arc (102.85714285714286:51.42857142857143:\smallradius) -- cycle; +\filldraw[fill=white] (102.85714285714286: \middleradius) arc (102.85714285714286:154.28571428571428:\middleradius) -- (154.28571428571428: \smallradius) arc (154.28571428571428:102.85714285714286:\smallradius) -- cycle; +\filldraw[fill=white] (154.28571428571428: \middleradius) arc (154.28571428571428:205.71428571428572:\middleradius) -- (205.71428571428572: \smallradius) arc (205.71428571428572:154.28571428571428:\smallradius) -- cycle; +\filldraw[fill=white] (205.71428571428572: \middleradius) arc (205.71428571428572:257.14285714285717:\middleradius) -- (257.14285714285717: \smallradius) arc (257.14285714285717:205.71428571428572:\smallradius) -- cycle; +\filldraw[fill=strategy_color] (257.14285714285717: \middleradius) arc (257.14285714285717:308.5714285714286:\middleradius) -- (308.5714285714286: \smallradius) arc (308.5714285714286:257.14285714285717:\smallradius) -- cycle; +\filldraw[fill=mechanism_color] (308.5714285714286: \middleradius) arc (308.5714285714286:360.00000000000006:\middleradius) -- (360.00000000000006: \smallradius) arc (360.00000000000006:308.5714285714286:\smallradius) -- cycle; + +% draw layers +\draw [black, thick] (0:0.6) -- (0:8); +\path [decorate, decoration={text along path,, reverse path, text=reformulation, text align=center}] (0: 0.925*8) arc (0:90: 0.925*8); +\draw [black, thick] (102.85714285714286:0.6) -- (102.85714285714286:8); +\path [decorate, decoration={text along path,, reverse path, text=Lagrange-Newton subproblem, text align=center}] (102.85714285714286: 0.925*8) arc (102.85714285714286:192.85714285714286: 0.925*8); +\draw [black, thick] (205.71428571428572:0.6) -- (205.71428571428572:8); +\path [decorate, decoration={text along path, text=subproblem solver, text align=center}] (205.71428571428572: 0.95*8) arc (205.71428571428572:250.71428571428572: 0.95*8); +\draw [black, thick] (257.14285714285717:0.6) -- (257.14285714285717:8); +\path [decorate, decoration={text along path, text=globalization, text align=center}] (257.14285714285717: 0.95*8) arc (257.14285714285717:347.14285714285717: 0.95*8); + +% draw ingredients +% reformulation +\draw [black, thick] (0:0.6) -- (0:7); +\path [decorate, decoration={text along path,, reverse path, text=constraint relaxation, text align=center}] (0: 0.925*7) arc (0:{45}:0.925*7); +\draw [black, thick] (51.42857142857143:0.6) -- (51.42857142857143:7); +\path [decorate, decoration={text along path,, reverse path, text=inequality handling, text align=center}] (51.42857142857143: 0.925*7) arc (51.42857142857143:{96.42857142857143}:0.925*7); +% Lagrange-Newton subproblem +\draw [black, thick] (102.85714285714286:0.6) -- (102.85714285714286:7); +\path [decorate, decoration={text along path,, reverse path, text=Hessian model, text align=center}] (102.85714285714286: 0.925*7) arc (102.85714285714286:{147.85714285714286}:0.925*7); +\draw [black, thick] (154.28571428571428:0.6) -- (154.28571428571428:7); +\path [decorate, decoration={text along path,, reverse path, text=regularization strategy, text align=center}] (154.28571428571428: 0.925*7) arc (154.28571428571428:{199.28571428571428}:0.925*7); +% subproblem solver +\draw [black, thick] (205.71428571428572:0.6) -- (205.71428571428572:7); +\path [decorate, decoration={text along path, text=subproblem solver, text align=center}] (205.71428571428572: 0.95*7) arc (205.71428571428572:{250.71428571428572}:0.95*7); +% globalization +\draw [black, thick] (257.14285714285717:0.6) -- (257.14285714285717:7); +\path [decorate, decoration={text along path, text=globalization strategy, text align=center}] (257.14285714285717: 0.95*7) arc (257.14285714285717:{302.14285714285717}:0.95*7); +\draw [black, thick] (308.5714285714286:0.6) -- (308.5714285714286:7); +\path [decorate, decoration={text along path, text=globalization mechanism, text align=center}] (308.5714285714286: 0.95*7) arc (308.5714285714286:{353.5714285714286}:0.95*7); + +% draw strategy radii +% constraint relaxation +\draw [black] (12.857142857142858:0.6) -- (12.857142857142858:5.5); +\draw [black] (25.714285714285715:0.6) -- (25.714285714285715:5.5); +\draw [black] (38.57142857142857:0.6) -- (38.57142857142857:5.5); +% inequality handling +\draw [black] (68.57142857142857:0.6) -- (68.57142857142857:5.5); +\draw [black] (85.71428571428572:0.6) -- (85.71428571428572:5.5); +% Hessian model +\draw [black] (115.71428571428572:0.6) -- (115.71428571428572:5.5); +\draw [black] (128.57142857142858:0.6) -- (128.57142857142858:5.5); +\draw [black] (141.42857142857144:0.6) -- (141.42857142857144:5.5); +% regularization strategy +\draw [black] (171.42857142857142:0.6) -- (171.42857142857142:5.5); +\draw [black] (188.57142857142856:0.6) -- (188.57142857142856:5.5); +% subproblem solver +\draw [black] (222.85714285714286:0.6) -- (222.85714285714286:5.5); +\draw [black] (240.0:0.6) -- (240.0:5.5); +% globalization strategy +\draw [black] (274.28571428571433:0.6) -- (274.28571428571433:5.5); +\draw [black] (291.42857142857144:0.6) -- (291.42857142857144:5.5); +% globalization mechanism +\draw [black] (325.7142857142858:0.6) -- (325.7142857142858:5.5); +\draw [black] (342.8571428571429:0.6) -- (342.8571428571429:5.5); + +% draw strategies +% constraint relaxation +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={|\color{darkgreen}|feas restoration}}}] (0, 0) -- (6.428571428571429:0.95*5.5); +\path (0, 0) -- (19.285714285714285:0.95*5.5) node[sloped, pos=1, anchor=east, inner sep=0pt] {$\ell_1$ relaxation}; +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={augmented Lag}}}] (0, 0) -- (32.142857142857146:0.95*5.5); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={step decomposition}}}] (0, 0) -- (45.0:0.95*5.5); +% inequality handling +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={|\color{darkgreen}|inequality constrained}}}] (0, 0) -- (60.0:0.95*5.5); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={equality constrained}}}] (0, 0) -- (77.14285714285714:0.95*5.5); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={|\color{darkgreen}|interior point}}}] (0, 0) -- (94.28571428571429:0.95*5.5); +% Hessian model +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|exact}}}] (109.28571428571429:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|quasi-Newton}}}] (122.14285714285714:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|identity}}}] (135.0:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|zero}}}] (147.85714285714286:0.95*5.5) -- (0, 0); +% regularization strategy +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|primal}}}] (162.85714285714286:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|primal-dual}}}] (180.0:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|none}}}] (197.14285714285714:0.95*5.5) -- (0, 0); +% subproblem solver +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|QP solver}}}] (214.2857142857143:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|LP solver}}}] (231.42857142857144:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|linear solver}}}] (248.57142857142858:0.95*5.5) -- (0, 0); +% globalization strategy +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|merit function}}}] (265.7142857142857:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|filter method}}}] (282.8571428571429:0.95*5.5) -- (0, 0); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=left, text={|\color{darkgreen}|funnel method}}}] (300.0:0.95*5.5) -- (0, 0); +% globalization mechanism +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={|\color{darkgreen}|line search}}}] (0, 0) -- (317.14285714285717:0.95*5.5); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={|\color{darkgreen}|trust-region method}}}] (0, 0) -- (334.28571428571433:0.95*5.5); +\draw[white, postaction={decorate, decoration={raise=-3pt, text along path, text align=right, text={proximal term}}}] (0, 0) -- (351.42857142857144:0.95*5.5); + +% draw circles +\draw [thick] (0, 0) circle (\smallestradius); +\draw [thick] (0, 0) circle (\smallradius); +\draw [thick] (0, 0) circle (\middleradius); +\draw [thick] (0, 0) circle (\largeradius); +\end{tikzpicture} +\end{document} diff --git a/joss/paper.bib b/joss/paper.bib new file mode 100644 index 000000000..e99efe329 --- /dev/null +++ b/joss/paper.bib @@ -0,0 +1,357 @@ +@article{wachter2006implementation, + title={On the implementation of an interior-point filter line-search algorithm for large-scale nonlinear programming}, + author={W{\"a}chter, Andreas and Biegler, Lorenz T}, + journal={Mathematical programming}, + volume={106}, + number={1}, + pages={25--57}, + year={2006}, + publisher={Springer}, + doi={10.1007/s10107-004-0559-y} +} + +@article{fletcher1998user, + title={User manual for filterSQP}, + author={Fletcher, Roger and Leyffer, Sven}, + journal={Numerical Analysis Report NA/181, Department of Mathematics, University of Dundee, Dundee, Scotland}, + volume={35}, + year={1998} +} + +@incollection{byrd2006, + title = {{KNITRO: An integrated package for nonlinear optimization}}, + author = {Byrd, Richard H and Nocedal, Jorge and Waltz, Richard A}, + booktitle = {Large-scale nonlinear optimization}, + pages = {35--59}, + year = {2006}, + publisher = {Springer}, + doi = {10.1007/0-387-30065-1_4} +} + +@article{gill2005, + title = {{SNOPT: An SQP algorithm for large-scale constrained optimization}}, + author = {Gill, Philip E and Murray, Walter and Saunders, Michael A}, + journal = {SIAM review}, + volume = {47}, + number = {1}, + pages = {99--131}, + year = {2005}, + publisher = {SIAM}, + doi = {10.1137/S0036144504446096} +} + +@article{VanaretLeyffer2026, + author = {Vanaret, Charlie and Leyffer, Sven}, + title = {Implementing a unified solver for nonlinearly constrained optimization}, + journal = {Mathematical Programming Computation}, + year = {2026}, + doi = {10.1007/s12532-026-00310-9} +} + +@book{nocedal2006, + title = {Numerical optimization}, + author = {Nocedal, Jorge and Wright, Stephen J}, + year = {2006}, + publisher = {Springer}, + doi = {10.1007/978-0-387-40065-5} +} + +@book{lee2011, + title = {Mixed integer nonlinear programming}, + author = {Lee, Jon and Leyffer, Sven}, + year = {2011}, + publisher = {Springer Science \& Business Media}, + doi = {10.1007/978-1-4614-1927-3} +} + +@article{fourer1990, + title = {{AMPL: A mathematical programming language}}, + author = {Fourer, Robert and Gay, David M and Kernighan, Brian W}, + journal = {Management Science}, + volume = {36}, + number = {5}, + pages = {519--554}, + year = {1990}, + doi = {10.1007/978-3-642-83724-1_12} +} + +@techreport{gay1997hooking, + title={Hooking your solver to AMPL}, + author={Gay, David M}, + year={1997}, + institution={Technical Report 93-10, AT\&T Bell Laboratories, Murray Hill, NJ, 1993, revised} +} + +@book{kernighan1988, + title = {{The C programming language}}, + author = {Kernighan, Brian W and Ritchie, Dennis M}, + year = {1988}, + publisher = {Pearson Educaci{\'o}n} +} + +@article{bongartz1995cute, + title={CUTE: Constrained and unconstrained testing environment}, + author={Bongartz, Ingrid and Conn, Andrew R and Gould, Nick and Toint, Ph L}, + journal={ACM Transactions on Mathematical Software (TOMS)}, + volume={21}, + number={1}, + pages={123--160}, + year={1995}, + publisher={ACM New York, NY, USA}, + doi = {10.1145/200979.201043} +} + +@inproceedings{kiessling2024almost, + title={An almost feasible sequential linear programming algorithm}, + author={Kiessling, David and Vanaret, Charlie and Astudillo, Alejandro and Decr{\'e}, Wilm and Swevers, Jan}, + booktitle={2024 European Control Conference (ECC)}, + pages={2328--2335}, + year={2024}, + organization={IEEE}, + doi = {10.23919/ECC64448.2024.10590864} +} + +@article{kiessling2025unified, + title={{A unified funnel restoration SQP algorithm}}, + author={Kiessling, David and Leyffer, Sven and Vanaret, Charlie}, + journal={Mathematical Programming}, + pages={1--45}, + year={2025}, + publisher={Springer}, + doi = {10.1007/s10107-025-02284-3} +} + +@article{shin2024accelerating, + title = {Accelerating optimal power flow with {GPU}s: {SIMD} abstraction of nonlinear programs and condensed-space interior-point methods}, + author = {Shin, Sungho and Anitescu, Mihai and Pacaud, Fran{\c{c}}ois}, + journal = {Electric Power Systems Research}, + volume = {236}, + pages = {110651}, + year = {2024}, + publisher = {Elsevier}, + doi = {10.1016/j.epsr.2024.110651} +} + +@incollection{buskens2012esa, + title={The {ESA} {NLP} solver {WORHP}}, + author={B{\"u}skens, Christof and Wassel, Dennis}, + booktitle={Modeling and optimization in space engineering}, + pages={85--110}, + year={2012}, + publisher={Springer}, + doi={10.1007/978-1-4614-4469-5_4} +} + +@article{fletcher2000stable, + title={Stable reduced {H}essian updates for indefinite quadratic programming}, + author={Fletcher, Roger}, + journal={Mathematical Programming}, + volume={87}, + number={2}, + pages={251--264}, + year={2000}, + publisher={Springer}, + doi={10.1007/s101070050113} +} + +@article{huangfu2018parallelizing, + title={Parallelizing the dual revised simplex method}, + author={Huangfu, QHJAJ and Hall, JA Julian}, + journal={Mathematical Programming Computation}, + volume={10}, + number={1}, + pages={119--142}, + year={2018}, + publisher={Springer}, + doi={10.1007/s12532-017-0130-5} +} + +@inproceedings{amestoy2000mumps, + title={{MUMPS}: a general purpose distributed memory sparse solver}, + author={Amestoy, Patrick R and Duff, Iain S and L’Excellent, Jean-Yves and Koster, Jacko}, + booktitle={International Workshop on Applied Parallel Computing}, + pages={121--130}, + year={2000}, + organization={Springer}, + doi={10.1007/3-540-70734-4_16} +} + +@article{duffma27, +author = {Duff, I. S. and Reid, J. K.}, +title = {The Multifrontal Solution of Indefinite Sparse Symmetric Linear Equations}, +year = {1983}, +volume = {9}, +number = {3}, +journal = {ACM Trans. Math. Softw.}, +pages = {302–325}, +doi = {10.1145/356044.356047} +} + +@article{duff2004ma57, + title={{MA57---a code for the solution of sparse symmetric definite and indefinite systems}}, + author={Duff, Iain S}, + journal={ACM Transactions on Mathematical Software (TOMS)}, + volume={30}, + number={2}, + pages={118--144}, + year={2004}, + doi={10.1145/992200.992202} +} + +@article{bolusani2024scip, + title={{Enabling research through the SCIP optimization suite 8.0}}, + author={Bestuzheva, Ksenia and Besan{\c{c}}on, Mathieu and Chen, Wei-Kun and Chmiela, Antonia and Donkiewicz, Tim and Van Doornmalen, Jasper and Eifler, Leon and Gaul, Oliver and Gamrath, Gerald and Gleixner, Ambros and others}, + journal={ACM Transactions on Mathematical Software}, + volume={49}, + number={2}, + pages={1--21}, + year={2023}, + publisher={ACM New York, NY}, + doi={10.1145/3585516} +} + +@article{hogg2016sparse, + title={{A sparse symmetric indefinite direct solver for GPU architectures}}, + author={Hogg, Jonathan D and Ovtchinnikov, Evgueni and Scott, Jennifer A}, + journal={ACM Transactions on Mathematical Software (TOMS)}, + volume={42}, + number={1}, + pages={1--25}, + year={2016}, + publisher={ACM New York, NY, USA}, + doi={10.1145/2756548} +} + +@article{montoison2023krylov, + title={{Krylov.jl: A Julia basket of hand-picked Krylov methods}}, + author={Montoison, Alexis and Orban, Dominique}, + journal={The Journal of Open Source Software}, + volume={8}, + number={89}, + pages={5187--5187}, + year={2023}, + publisher={Open Journals} +} + +@Article{Andersson2019, + author = {Joel A E Andersson and Joris Gillis and Greg Horn + and James B Rawlings and Moritz Diehl}, + title = {{CasADi} -- {A} software framework for nonlinear optimization + and optimal control}, + journal = {Mathematical Programming Computation}, + volume = {11}, + number = {1}, + pages = {1--36}, + year = {2019}, + publisher = {Springer}, + doi = {10.1007/s12532-018-0139-4} +} + +@article{cesaroni2026derivative, + title={Derivative-Free Bilevel Optimization with Inexact Lower-Level Solutions}, + author={Cesaroni, Edoardo and Liuzzi, Giampaolo and Lucidi, Stefano}, + journal={arXiv preprint arXiv:2603.20759}, + year={2026} +} + +@article{baran2026riemannian, + title={{A Riemannian quasi-Newton algorithm for optimization with Euclidean bounds}}, + author={Baran, Mateusz and Bergmann, Ronny and Przybysz, Patryk}, + journal={arXiv preprint arXiv:2605.10573}, + year={2026} +} + +@article{desef2025optimization, + title={Optimization Techniques in Quantum Information}, + author={Desef, Benjamin}, + journal={arXiv preprint arXiv:2512.15831}, + year={2025} +} + +@phdthesis{gruss2024estimation, + title={Estimation avanc{\'e}e {\`a} horizon glissant, {\'e}tat et param{\`e}tres, pour la conduite du coeur des r{\'e}acteurs PWR}, + author={Gruss, Lucas}, + year={2024}, + school={Ecole nationale sup{\'e}rieure Mines-T{\'e}l{\'e}com Atlantique} +} + +@article{cederberg2026disciplined, + title={Disciplined nonlinear programming}, + author={Cederberg, Daniel and Zhang, William and Nobel, Parth and Boyd, Stephen}, + journal={arXiv preprint arXiv:2606.02896}, + year={2026} +} + +@article{joshy2026modopt, + title={modopt: A modular development environment and library for optimization algorithms}, + author={Joshy, Anugrah Jo and Hwang, John T}, + journal={Advances in Engineering Software}, + volume={213}, + pages={104084}, + year={2026}, + publisher={Elsevier} +} + +@book{lewis2012optimal, + title={Optimal control}, + author={Lewis, Frank L and Vrabie, Draguna and Syrmos, Vassilis L}, + year={2012}, + publisher={John Wiley \& Sons} +} + +@book{sra2011optimization, + title={Optimization for machine learning}, + author={Sra, Suvrit and Nowozin, Sebastian and Wright, Stephen J}, + year={2011}, + publisher={MIT press} +} + +@article{dunning2017jump, + title={JuMP: A modeling language for mathematical optimization}, + author={Dunning, Iain and Huchette, Joey and Lubin, Miles}, + journal={SIAM review}, + volume={59}, + number={2}, + pages={295--320}, + year={2017}, + publisher={SIAM} +} + +@article{Wu2020, + doi = {10.21105/joss.02564}, + year = {2020}, + publisher = {The Open Journal}, + volume = {5}, + number = {54}, + pages = {2564}, + author = {Ella Wu and Gaetan Kenway and Charles A. Mader and John Jasa and Joaquim R. R. A. Martins}, + title = {pyOptSparse: A Python framework for large-scale constrained nonlinear optimization of sparse systems}, + journal = {Journal of Open Source Software} +} + +@article{cederberg2026disciplined, + title={Disciplined nonlinear programming}, + author={Cederberg, Daniel and Zhang, William and Nobel, Parth and Boyd, Stephen}, + journal={arXiv preprint arXiv:2606.02896}, + year={2026} +} + +@article{gould2015cutest, + title={CUTEst: a constrained and unconstrained testing environment with safe threads for mathematical optimization}, + author={Gould, Nicholas IM and Orban, Dominique and Toint, Philippe L}, + journal={Computational optimization and applications}, + volume={60}, + number={3}, + pages={545--557}, + year={2015}, + publisher={Springer} +} + +@software{OptimalControl_jl, +author = {Caillau, Jean-Baptiste and Cots, Olivier and Gergaud, Joseph and Martinon, Pierre and Sed, Sophia}, +doi = {10.5281/zenodo.13336563}, +license = {["MIT"]}, +title = {{OptimalControl.jl: a Julia package to model and solve optimal control problems with ODE's}}, +url = {https://control-toolbox.org/OptimalControl.jl}, +year={2024}, +} \ No newline at end of file diff --git a/joss/paper.md b/joss/paper.md new file mode 100644 index 000000000..c6e55d792 --- /dev/null +++ b/joss/paper.md @@ -0,0 +1,163 @@ +--- +title: 'Uno: a composable framework for nonlinearly constrained optimization' +tags: + - nonlinear programming + - constrained optimization + - sequential quadratic programming + - interior-point methods + - Lagrange-Newton methods + - optimization frameworks + - scientific computing + - Julia + - Python + - C + - Fortran + - AMPL +authors: + - name: Charlie Vanaret^[corresponding author] + orcid: 0000-0002-1131-7631 + affiliation: 1 + - name: Alexis Montoison^[Now at Advanced Micro Devices (AMD).] + orcid: 0000-0002-3403-5450 + affiliation: 2 +affiliations: + - name: Applied Optimization Department, Zuse-Institut Berlin, Germany + index: 1 + - name: Mathematics and Computer Science Division, Argonne National Laboratory, USA + index: 2 +date: 8 June 2026 +bibliography: paper.bib + +--- + +# Summary + +Uno is a composable software framework for nonlinearly constrained optimization written in modern C\texttt{++}. +It unifies the workflows of Lagrange-Newton methods, i.e., gradient-based algorithms that iteratively solve the KKT optimality conditions using Newton's method. +The central idea is to decompose these methods into reusable, interchangeable components (constraint reformulation, step computation, globalization techniques, and acceptance criteria) so that classical and hybrid algorithms can be assembled, compared, and tested within a single framework rather than reimplemented as separate solvers. +As of June 2026, Uno supports sequential (convex and nonconvex) quadratic programming, interior-point (barrier) methods, sequential linear programming, and unconstrained optimization. +For full mathematical details of the algorithms implemented in Uno, see [@VanaretLeyffer2026]. + +Uno has interfaces to Julia, Python, C, Fortran, and AMPL, enabling interoperability across scientific computing environments. +Precompiled artifacts are available on GitHub, and the solver can be accessed directly via `UnoSolver.jl` in Julia or `unopy` in Python. + +# Statement of need + +Nonlinearly constrained optimization is central to engineering, optimal control [@lewis2012optimal], machine learning [@sra2011optimization], scientific modeling [@nocedal2006], and plays a key role in mixed-integer nonlinear optimization [@lee2011]. +The major solution paradigms (sequential quadratic programming, interior-point methods, and augmented Lagrangian methods) are usually developed and implemented as separate solver families. +Yet they share the same building blocks: step computation, constraint handling, Hessian models, and globalization strategies. +Because these building blocks are rigid inside monolithic codes, algorithmic ideas are typically tested at the level of *complete solvers* rather than *building blocks*: evaluating a new globalization strategy or Hessian approximation means reimplementing an entire solver or intrusively modifying an existing one. + +Uno targets two audiences. +For **algorithm developers and optimization researchers**, it makes the building blocks explicit and recombinable across paradigms, so that a single new strategy can be swapped into an otherwise state-of-the-art method and benchmarked in isolation. +For **practitioners and end users**, it exposes those building blocks, pre-assembled into presets that reproduce established solvers, behind multiple language interfaces. Because these presets live in a single framework with a common interface, users can identify the most suitable method for a given class of problems by reconfiguring strategies within Uno, rather than installing and benchmarking several independent solvers. + +The gap Uno fills is the absence of a framework in which *production-grade* algorithmic components can be composed across solver paradigms under a unified abstraction. + +# State of the field + +Popular solvers such as IPOPT [@wachter2006implementation], KNITRO [@byrd2006], SNOPT [@gill2005], and WORHP [@buskens2012esa] are robust and efficient but monolithic: parameter tuning is exposed while internal components remain rigid. +They are designed for end users rather than algorithmic experimentation, and testing a new variant usually requires intrusive modification or reimplementation. +A notable exception among production codes is MadNLP.jl [@shin2024accelerating], an actively developed Julia solver, though it remains focused on interior-point methods. + +Frameworks that do emphasize modularity occupy a different niche. +General-purpose libraries such as `scipy.optimize`, NLopt, pyOpt, and pyOptSparse let users select among complete solvers, but they do not expose the *internal* algorithmic components for recombination. +Closest in spirit is modOpt [@joshy2026modopt], a Python environment that builds optimization algorithms from self-contained modules (line searches, Hessian approximations, merit functions) with an educational focus. + +Uno is distinct on three counts. +First, its components are production-grade algorithmic building blocks compiled in modern C\texttt{++}. +Second, it expresses these paradigms as instances of one generic Lagrange-Newton method, so the same components are reused across all of them rather than confined to a single method. +Third, its presets reproduce state-of-the-art solvers at competitive performance (see below), so a component swapped into Uno is measured against a credible baseline rather than a teaching reference. + +# Software design + +Within Uno, strategies are organized into a coherent hierarchy, illustrated in the wheel of strategies (\autoref{fig:wheel}). +The outer ring lists the high-level *layers* of a Lagrange-Newton method (for example, constraint reformulation and globalization); the middle ring lists the algorithmic *ingredients* that Uno combines automatically to realize each layer; and the inner ring lists the concrete *strategies* available for each ingredient. +Strategies currently implemented in Uno are highlighted in green. + +In Uno's object-oriented architecture, the ingredients of \autoref{fig:wheel} are abstract classes whose interfaces are implemented by subclasses (the strategies). +Uno's simplified UML diagram is shown in \autoref{fig:umldiagram}: inheritance is represented as dashed lines with white arrows, composition as solid lines with black diamonds; abstract classes are written in italic and subclasses in bold. +This architecture separates the mathematical logic of the algorithm (problem reformulation, subproblem definition, globalization) from the computational aspects (evaluating the model's functions, solving the subproblems). + +Uno implements a generic Lagrange-Newton method in which the abstract classes interact and exchange data while remaining agnostic to the underlying strategies. +Strategies are selected by the user at runtime via options. +Uno also provides *presets*: particular combinations of strategies and hyperparameters that correspond to state-of-the-art solvers. +Two presets are currently available: an \texttt{ipopt} preset mimicking the IPOPT solver [@wachter2006implementation] (a *line-search restoration filter interior-point method with exact Hessian and primal-dual inertia correction*), and a \texttt{filtersqp} preset mimicking the filterSQP solver [@fletcher1998user] (a *trust-region restoration filter SQP method with exact Hessian and no inertia correction*). +In principle all combinations of strategies can be generated, although some are not yet supported (e.g., an interior-point method with a trust-region globalization mechanism). + +![Unification framework: wheel of strategies.\label{fig:wheel}](figures/wheel.pdf){ width=70% } + +These two presets perform on a par with the state-of-the-art solvers IPOPT (Uno is slightly less robust) and filterSQP (Uno is slightly more robust) in terms of function evaluations on a set of 429 small CUTE instances with fewer than 100 variables and constraints [@bongartz1995cute] translated to AMPL by Vanderbei. +An up-to-date performance profile is maintained on Uno's documentation page. +This benchmark shows that Uno's composability does not come at the cost of performance: assembling a method from modular components reproduces the behavior of the hand-written solvers it mimics. + +Subproblem solvers are treated as interchangeable components that can be plugged in or swapped out without modifying the algorithmic logic, letting users match the solver to their problem structure, licensing constraints, or performance requirements. +Uno currently interfaces several established LP, QP, and linear solvers: BQPD [@fletcher2000stable], HiGHS [@huangfu2018parallelizing], MUMPS [@amestoy2000mumps], MA27 [@duffma27], MA57 [@duff2004ma57], SSIDS [@hogg2016sparse], and `Krylov.jl` [@montoison2023krylov]. + +# Interfaces + +To make Uno accessible to a wide range of users, we provide multiple language interfaces. + +The AMPL Solver Library [@gay1997hooking] interface gives access to the AMPL [@fourer1990] modeling language for optimization. +It is distributed as a binary that takes a compiled AMPL model (.nl file) as input, allowing users to solve problems without directly interacting with the C\texttt{++} core. + +The C interface provides direct access to Uno's core functionality while maximizing interoperability with other programming languages and tools. +The optimization process is expressed as the interaction between two independent opaque objects: a model describing the optimization problem and a solver holding the algorithmic configuration and execution state. +The interface is therefore centered around two main structures: + +* **Model**: represents an optimization problem and stores information about variables, bounds, constraints, the objective function, and derivative information. Users create a model and set its components (objective, constraints, derivatives, initial primal-dual point). +* **Solver**: represents the algorithm used to solve a given model. Users set solver options, attach callbacks, and access results such as primal and dual solutions, residuals, iteration counts, and performance metrics. + +The Fortran interface provides access to Uno through the C API using `iso_c_binding`. +It is split into two files: `uno_c.f90` for low-level C bindings, and `uno_fortran.f90` for Fortran-friendly wrappers that handle string arguments. +The interface can be included directly in a source file or wrapped in a module for cleaner `use` statements. +It is provided as source rather than a precompiled Fortran module (.mod) to maximize portability and interoperability across compilers and platforms. + +The Julia interface is distributed as the registered package `UnoSolver.jl`. +It integrates Uno into the Julia optimization ecosystem through: + +* a thin wrapper around the full C API, +* an interface to `NLPModels.jl` for solving problems following the NLPModels API, such as `ADNLPModels.jl` or `ExaModels.jl`, +* an interface to `MathOptInterface.jl` for handling JuMP models. + +Precompiled artifacts are downloaded automatically, making the package plug-and-play without requiring user compilation. + +The Python interface is registered on PyPI as `unopy`, providing Uno bindings via precompiled wheels on most platforms. + +MATLAB and Rust interfaces are also under development, further expanding Uno's accessibility. + +Looking ahead, we plan to integrate Uno as a continuous relaxation solver within MINLP frameworks such as SCIP [@bolusani2024scip], which will require efficient reoptimization that reuses internal solver state (active sets, factorizations, preallocated workspace) across structurally similar solves. + +# Research impact statement + +Uno has demonstrated value both as a research tool and as a dependency of established software. +Its original authors used it to prototype a novel globalization strategy, the funnel method [@kiessling2025unified]. +It has since been used as the lower-level solver in derivative-free bilevel optimization [@cesaroni2026derivative], been benchmarked on Euclidean problems with bound constraints [@baran2026riemannian], and been cited in [@gruss2024estimation; @desef2025optimization; @cederberg2026disciplined]. + +Uno is currently available as a nonlinear optimization solver in: + +- Julia: + * the `JuMP.jl` ecosystem [@dunning2017jump], + * `control-toolbox`, a collection of Julia packages for mathematical control and its applications [@OptimalControl_jl], +- C++: + * [CasADi](https://github.com/casadi/casadi), an open-source tool for nonlinear optimization and algorithmic differentiation [@Andersson2019], +- Python: + * [pyOptSparse](https://github.com/mdolab/pyoptsparse), an object-oriented framework for formulating and solving nonlinear constrained optimization problems [@Wu2020], + * [DNLP](https://github.com/cvxgrp/DNLP), an extension of CVXPY to general nonlinear programming [@cederberg2026disciplined], +- Fortran: + * [CUTEst](https://github.com/ralna/cuTEst), the Constrained and Unconstrained Testing Environment with safe threads for optimization software [@gould2015cutest], + * IMPL © /IMPL-DATA © by Industrial Algorithms Limited, a modeling and solving platform used in the process industries. + +![Uno's UML diagram.\label{fig:umldiagram}](figures/uml_diagram.pdf){ width=95% } + +# Acknowledgments + +This work was supported by the Applied Mathematics activity of the U.S. Department of Energy Office of Science, Advanced Scientific Computing Research, under Contract No. DE-AC02-06CH11357. +This work was also supported in part by NSF CSSI Grant No. 2104068. + +# AI usage disclosure + +No generative AI was used in the creation of the software, interfaces, implementation of algorithms, or documentation. +ChatGPT was used to check spelling, grammar, and clarity of the English text in this paper. + +# References diff --git a/joss/paper.pdf b/joss/paper.pdf new file mode 100644 index 000000000..605e949eb Binary files /dev/null and b/joss/paper.pdf differ