I have some diagrams I'm drawing using tikz and I'd like to make a macro to draw them for me.
I will describe it fully but here are some examples so you can follow along:
The diagram has a number of nodes which we can be split into two groups, "main nodes" and "detour nodes" main nodes are drawn in a column the left and are drawn with solid borders. Detour nodes are drawn in a column to the right with dashed borders. Main nodes are evenly spaced and each is connected to the node above it with a solid line. detour nodes are not necessarily spaced evenly, they are offset by a half step from the main nodes. Each detour node connects via dashed line to the main node closest above it and closest below it if such exists. Detours do not connect to each other.
Each node has a label (in the picture this is always 3 characters) and main nodes labels are to their left while detour nodes labels are to their right.
Method
I'm using the packages xparse
and tikz
to solve this.
I don't know tex, so when it came to implementing this I had a bit of a tough time. I went with a recursive method since that seemed more natural to me. The main function (\trackdiagram
) is passed two arguments containing the labels separated by ;
. The first contains the labels for the main nodes and the second for the detour nodes.
This main function then passes off each "list" to a recursive method which builds the column. These methods are both recursive and stateful maintaining a counter to indicate the current position.
\makeatletter
\newcommand\providecounter[1]{
\@ifundefined{c@#1}{%
\newcounter{#1}
}{}
}
\makeatother
\NewDocumentCommand\trackdiagram{mm}{
\providecounter{mtHeight}
\providecounter{dtHeight}
\setcounter{mtHeight}{0}
\setcounter{dtHeight}{0}
\begin{tikzpicture}[fill=white,thick,circle,minimum size=2.1em]
\maintrack[#1;]
\detours[#2;]
\end{tikzpicture}
}
\NewDocumentCommand\maintrack{u{[}u{;}u{]}}{
\providecounter{previous}
\setcounter{previous}{\value{mtHeight}}
\addtocounter{mtHeight}{-1}
\def\curcell{maincell\arabic{mtHeight}}
\node[
draw,
fill,
label={left:\textbf{#2}}
](\curcell)at(0,\arabic{mtHeight}){};
\ifnum\value{mtHeight}<-1{%
\draw(\curcell)node[draw,fill]{}--(maincell\arabic{previous});
}\else\fi
\ifx&\else
\maintrack[#3]
\fi
}
\NewDocumentCommand\detours{u{[}u{;}u{]}}{
\providecounter{previous}
\setcounter{previous}{\value{dtHeight}}
\addtocounter{dtHeight}{-1}
\def\curcell{dcell\arabic{dtHeight}}
\ifx&\else
\node[
draw,
dashed,
fill,
label={right:\textbf{#2}}
](\curcell)at(.8,\arabic{dtHeight}+0.5){};
\ifnum\value{dtHeight}<\value{mtHeight}\else
\draw[dashed](\curcell)--(maincell\arabic{dtHeight});
\fi
\ifnum\value{dtHeight}<-1{
\draw[dashed](maincell\arabic{previous})--(\curcell);
}\else\fi
\fi
\ifx&\else
\detours[#3]
\fi
}
Here's how the examples are invoked:
\trackdiagram{UHM;SCR;BAT;INJ;SKD}{AUR;USC;;UNT}
\trackdiagram{SPM;MOV;IFN}{;AKN}
\trackdiagram{TAK;CAM;DOF}{;;BRY;CHU}
\trackdiagram{JMP}{JIF;DAL}
I am not committed to this particular invocation, it is entirely a product of my abilities, not of any particular desire for this particular API. Thus this is perfectly open to review as well.
Review
Because I don't have a background in tex I feel that this probably is pretty autodidactic. There are probably more sensible solutions to a lot of the problems I solved here that someone experienced with latex would use. And this is what I would like to cover with a code-review.
I don't want to use any new packages. So suggestions which involve using fancy new packages are not helpful to me.
\providecounter
instructions and allocate the counters right away with\newcounter
. \$\endgroup\$\SplitArgument
rather than the deprecatedu
argument type. \$\endgroup\$