% modiagram-latex-integration, Package for LaTeX with interactive web helper for creating complex MO diagrams. Extends standard orbital support (d, f, etc.) with custom symmetry groups and real-time visual configuration for seamless LaTeX integration. % Copyright (C) 2026 Viktor Altergott % This program is free software: you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation, either version 3 of the License, or % (at your option) any later version. % This program is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % You should have received a copy of the GNU General Public License % along with this program. If not, see . \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{mohelper}[2026/03/31 v1.0 Enhanced MO Diagram Creator] \RequirePackage{tikz, xstring} \RequirePackage{etoolbox} \usetikzlibrary{arrows.meta} \usetikzlibrary{backgrounds} \pgfdeclarelayer{background} \pgfsetlayers{background,main} % DEFINING THE WORKING ENVIRONMENT AND DEALING WITH USER INPUT \newenvironment{mohelper}[1][]{% % Code, der beim START ausgeführt wird (\begin{mohelper}) \begin{tikzpicture}[#1] % Erlaubt zusätzliche TikZ-Optionen \setcounter{c@lumns}{-1} \expandafter\typeout\expandafter{\csname invokeL@ter\endcsname} \csgdef{invokeL@ter}{} \initdi@gram }{% % Code, der am ENDE ausgeführt wird (\end{mohelper}) \finish@job \setcounter{c@lumns}{0} \end{tikzpicture} } % \def\invokeL@ter{} \xdef\@tomside{0} \newcounter{labelID} \newcommand{\labelList}{} % Unsere Liste für die IDs \newcounter{c@lumns} \setcounter{c@lumns}{-1} \newcommand{\fragment}[1]{ \addtocounter{c@lumns}{1} % \def\cs{\csname orbit@list\thec@lumns\endcsname}{} \csgdef{orbit@list\thec@lumns}{} \csgdef{l@bel\thec@lumns}{} \xdef\@tomside{\thec@lumns} #1 % \ifdefined#2 % \addenergyscale{0} % \fi } \newcommand{\addOrbital}[1]{ \pgfkeys{/mohelper/orbitals/.cd, energy/.store in=\tempEnergy, energy=0, sym/.store in=\tempSym, sym=a1, config/.store in=\tempConfig, config={empty}, labels/.store in=\tempLabels, labels={}, label/.store in=\tempLabel, label=, labelposition/.store in=\tempLabelPosition, labelposition=bottom, column/.store in=\tempSide, column=\@tomside, #1 } % handle user input \xdef\merg@dstring{} \foreach \spin [count=\ione] in \tempConfig { \edef\labelorbital{} \foreach \ee [count=\itwo] in \tempLabels { \ifdefequal{\ione}{\itwo}{ \xdef\labelorbital{\ee} }{} } \ifdefempty{\merg@dstring}{ % Erster Eintrag: Kein Komma davor \xdef\merg@dstring{\labelorbital/\spin} }{ % Alle weiteren Einträge: Mit Komma trennen \xdef\merg@dstring{\merg@dstring,\labelorbital/\spin} } } \StrCount{\tempConfig}{,}[\arrcount]% \pgfmathsetmacro{\tempDeg}{int(\arrcount + 1)}% \degener@te{\tempEnergy}{\merg@dstring}{\tempSide} \degener@telabel{\tempEnergy}{\tempDeg}{\tempSide}{\tempLabelPosition}{\tempLabel} \foreach \group in \tempSym { \listcsxadd{orbit@list\tempSide}{\group/\tempEnergy/\tempDeg} } % \expandafter\typeout\expandafter{\csname orbit@listleft\endcsname} } \newcommand{\cslistto@rray}[2]{% \xdef#2{}% Ziel leeren \def\do##1{% \ifdefempty{#2} {\xdef#2{##1}}% Erstes Element {\xdef#2{#2,##1}}% Weitere Elemente mit Komma }% \dolistcsloop{#1}% } \ExplSyntaxOn % Wir erstellen eine "Sequence" (eine moderne Liste) \seq_new:N \g_mo_labels_seq % Ein interner Zeichenbefehl \cs_new:Npn \__mo_draw_label:nnn #1 #2 #3 { % Hier wird \minY erst beim Aufruf ausgewertet! \node[below=0pt, font=\scriptsize] at (#1, \minY - 0.5 - #2) {#3}; } % Connects orbitals of the same symmetry group together \newcommand{\finish@job}{ \ifcase\thec@lumns \relax \fi \pgfmathsetmacro{\range}{int(\thec@lumns - 1)} \foreach \i in {0,..., \range} { \cslistto@rray{orbit@list\i}{\arrayLeft} \pgfmathsetmacro{\ii}{int(\i + 1)} \cslistto@rray{orbit@list\ii}{\arrayMiddle} \foreach \symmetry/\energy/\deg in \arrayLeft{ \foreach \symmetryy/\energyy/\degy in \arrayMiddle{ \ifdefequal{\symmetry}{\symmetryy}{ \begin{pgfonlayer}{background} \connect@further{\energy}{\deg}{\energyy}{\degy}{\i} \end{pgfonlayer} }{} } } } \seq_map_function:NN \g_mo_labels_seq \use:n \seq_gclear:N \g_mo_labels_seq % \cslistto@rray{invokeL@ter}{\dolater} % \foreach \pos/\offset/\text in \dolater{ % \message{show \text} % \node[below=0pt, font=\scriptsize] at (\pos,\minY-0.5-\offset) {\text}; % } \foreach \i in {-1,0,..., \thec@lumns} { \csgdef{orbit@list\i}{} } } % FURTHER DRAWING LOGIC STUFF \newcommand{\orbit@llength}{0.8} \newcommand{\orbit@ldistance}{0.2} \newcommand{\columndistance}{3} \def\diagrammode{normal} \def\electroncolor{black} \newcommand{\initdi@gram}{ \xdef\minX{100} \xdef\maxX{-100} \xdef\minY{100} \xdef\maxY{-100} } \newcommand{\c@lculateColumnX}[2]{ \pgfmathsetmacro{#1}{(\orbit@llength + \columndistance) * #2} } \newcommand{\addEnergyScale}[1]{ \draw[->, -{Stealth[scale=1.2]}, semithick] (\minX-0.5-#1,\minY-0.5) -- (\minX-0.5-#1,\maxY+0.5) node[anchor=east, font=\footnotesize] {E}; } \newcommand{\showEnergyDifference}[3]{ \c@lculateColumnX{\xcolumn}{#2} \StrBefore{#1}{,}[\orbup]% \StrBehind{#1}{,}[\orbdown]% \c@lculateColumnX{\xposs}{\thec@lumns} \pgfmathsetmacro{\xpos}{\orbit@llength/2 + #2 + \xposs} \draw[<->, red, {Stealth[scale=0.7]}-{Stealth[scale=0.7]}, semithick] (\xpos,\orbdown) -- (\xpos,\orbup) node[midway, right, font=\footnotesize] {#3}; } % \newcommand{\addLabel}[2]{ % \c@lculateColumnX{\xpos}{\thec@lumns} % \pgfmathsetmacro{\pos}{\orbit@llength /2 + \xpos} % % \edef\inhalt{#1} % % \listcsxadd{invokeL@ter}{\pos/#2/\inhalt} % \csgdef{l@bel\thec@lumns}{#1} % } \newcommand{\addLabel}[2]{ \c@lculateColumnX{\xpos}{\thec@lumns} \pgfmathsetmacro{\pos}{\orbit@llength / 2 + \xpos} % Wir speichern einen fertigen Funktionsaufruf in der Liste \seq_gput_right:Ne \g_mo_labels_seq { \exp_not:N \__mo_draw_label:nnn {\pos} % Wird zur Zahl expandiert (eingefroren) {#2} % Offset wird eingefroren {\exp_not:n {#1}} % Text wird geschützt (nichts passiert) } } \ExplSyntaxOff % 1: energy % 2: degeneration % 3: column % 4: align % 5: textcontent \newcommand{\degener@telabel}[5]{ \c@lculateColumnX{\xpos}{#3} \ifdefstring{\diagrammode}{compact}{ \pgfmathsetmacro{\lengthkette}{\orbit@llength} }{ \pgfmathsetmacro{\lengthkette}{#2 * \orbit@llength + (#2 - 1) * \orbit@ldistance} } \edef\labelalignment{#4} \ifdefstring{\labelalignment}{left}{ \node[anchor=east, font=\scriptsize] at (\xpos + \orbit@llength /2 - \lengthkette /2,#1) {#5}; }{} \ifdefstring{\labelalignment}{right}{ \node[anchor=west, font=\scriptsize] at (\xpos + \orbit@llength /2 + \lengthkette /2,#1) {#5}; }{} \ifdefstring{\labelalignment}{bottom}{ \ifdefstring{\diagrammode}{compact}{ \edef\labeldistance{3pt} }{ \edef\labeldistance{7pt} } \node[below=\labeldistance, font=\scriptsize] at (\xpos + \orbit@llength /2,#1) {#5}; }{} \ifdefstring{\labelalignment}{top}{ \ifdefstring{\diagrammode}{compact}{ \edef\labeldistance{3pt} }{ \edef\labeldistance{7pt} } \node[above=\labeldistance, font=\scriptsize] at (\xpos + \orbit@llength /2,#1) {#5}; }{} } \newcommand{\orbital}[4]{ \draw[thick] (#1,#2) -- (#1+\orbit@llength,#2);% node[below, font=\scriptsize] {#3}; \ifstrequal{#4}{up}{\electron@up{#1}{#2}}{} \ifstrequal{#4}{down}{\electron@down{#1}{#2}}{} \ifstrequal{#4}{pair}{\electron@up{#1}{#2}\electron@down{#1}{#2}}{} \ifdefstring{\diagrammode}{compact}{ \edef\labeldistance{3pt} }{ \edef\labeldistance{7pt} } \node[below=\labeldistance, font=\scriptsize] at (#1+\orbit@llength/2,#2) {#3}; \pgfmathsetmacro{\tempMinX}{min(\minX, #1)} \pgfmathsetmacro{\tempMaxX}{max(\maxX, #1 + \orbit@llength)} % Hier die volle Breite nehmen! \pgfmathsetmacro{\tempMinY}{min(\minY, #2)} \pgfmathsetmacro{\tempMaxY}{max(\maxY, #2)} \xdef\minX{\tempMinX} \xdef\maxX{\tempMaxX} \xdef\minY{\tempMinY} \xdef\maxY{\tempMaxY} } \tikzset{ electronnormal/.style={\electroncolor, -{Stealth[harpoon]}, thick, semithick}, electroncompact/.style={\electroncolor, very thin, ->, very thin} } \newcommand{\getElec@specs}{ \ifdefstring{\diagrammode}{compact}{ \pgfmathsetmacro{\electronlength}{\orbit@ldistance * 0.5} % \edef\electroncolor{red} \edef\electron@style{electroncompact} }{ \edef\electronlength{0.3} % \edef\eleccolor{black} \edef\electron@style{electronnormal} } } \newcommand{\electron@up}[2]{ \getElec@specs \draw[\electron@style] (#1+0.3,#2-\electronlength) -- (#1+0.3,#2+\electronlength); } \newcommand{\electron@down}[2]{ \getElec@specs \draw[\electron@style] (#1+0.5,#2+\electronlength) -- (#1+0.5,#2-\electronlength); } \DeclareListParser{\@CSVsplitter}{,} % param: % 1: y-level % 2: array {"name"/"spin",...} % 3: column \newcommand{\degener@te}[3]{ \StrCount{#2}{,}[\arrcount]% \pgfmathsetmacro{\arrlength}{int(\arrcount + 1)}% \c@lculateColumnX{\xposs}{#3} \def\currentIdx{0}% \renewcommand*{\do}[1]{% \StrBefore{##1}{/}[\tempName]% \StrBehind{##1}{/}[\tempSpin]% \ifdefstring{\diagrammode}{compact}{ \pgfmathsetmacro{\ypos}{#1 - ((\orbit@ldistance) * (\arrlength - 1)) / 2 + (\currentIdx) * (\orbit@ldistance)}% }{ \pgfmathsetmacro{\xpos}{\xposs - ((\orbit@llength + \orbit@ldistance) * (\arrlength - 1)) / 2 + (\currentIdx) * (\orbit@llength + \orbit@ldistance)}% }% \ifdefstring{\diagrammode}{compact}{ \ifcase\currentIdx \else \def\tempName{} \fi \edef\tempcall{\noexpand\orbital{\xposs}{\ypos}{\tempName}{\tempSpin}} }{ \edef\tempcall{\noexpand\orbital{\xpos}{#1}{\tempName}{\tempSpin}} }% \tempcall \pgfmathsetmacro{\nextIdx}{int(\currentIdx + 1)}% \xdef\currentIdx{\nextIdx}% }% % now finally expanding the text \expandafter\docsvlist\expandafter{#2}% } %connects to the right. the #5 is the column index that will connect to the (#5 +1) column \newcommand{\connect@further}[5]{ \ifdefstring{\diagrammode}{compact}{ \pgfmathsetmacro{\degleft}{1} \pgfmathsetmacro{\degright}{1} }{ \pgfmathsetmacro{\degleft}{#2} \pgfmathsetmacro{\degright}{#4} }% \pgfmathsetmacro{\xposleft}{(\orbit@llength + \columndistance) * #5 +\orbit@llength /2 + (\orbit@llength * \degleft + \orbit@ldistance * (\degleft - 1)) /2} \pgfmathsetmacro{\xposmiddleleft}{(\orbit@llength + \columndistance) * (#5 + 1) +\orbit@llength /2 - (\orbit@llength * \degright + \orbit@ldistance * (\degright - 1)) /2} \draw[on background layer, dashed, thin, gray] (\xposleft,#1) -- (\xposmiddleleft,#3); } % ========================================================================================== % THIS FOLLOWING AREA CONSISTS OF DEPRECATED MACROS, THEY THROW A WARNING WHEN USING THEM, YOU SHOULD NOT USE THEM ANYMORE!! % ========================================================================================== \newcommand{\degenerate}[3]{ \PackageWarningNoLine{mohelper}{% \noexpand\degenerate is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% % \StrCount{#2}{,}[\arrlength] % \foreach \name/\spin [count=\i] in {#2}{ % \ifstrequal{#3}{left}{\def\xposs{0}}{} % \ifstrequal{#3}{middle}{\def\xposs{\orbitallength+\columndistance}}{} % \ifstrequal{#3}{right}{\def\xposs{\orbitallength*2+\columndistance*2}}{} % % \def\xpos{\xposs-\orbitallength-\orbitaldistance} % \pgfmathsetmacro{\xpos}{\xposs - (\orbitallength + \orbitaldistance) * \arrlength /2 + (\i - 1) * (\orbitallength + \orbitaldistance)} % \edef\tempcall{\noexpand\orbital{\xpos}{#1}{\name}{\spin}} % \tempcall % } \ifdefstring{\diagrammode}{compact}{ \def\func{\degeneratecorrectedcompact}% }{\def\func{\degeneratecorrected}}% \func{#1}{#2}{#3}% } % draw orbitals in normal mode \newcommand{\degeneratecorrected}[3]{% % 1. Anzahl für Zentrierung berechnen \StrCount{#2}{,}[\arrcount]% \pgfmathsetmacro{\arrlength}{int(\arrcount + 1)}% % 2. X-Basis bestimmen % \edef\side{#3} % \ifdefstring{\side}{left}{\def\xposs{0}}{}% % \ifdefstring{\side}{middle}{\def\xposs{\orbit@llength+\columndistance}}{}% % \ifdefstring{\side}{right}{\def\xposs{\orbit@llength*2+\columndistance*2}}{}% \c@lculateColumnX{\xposs}{#3} % 3. Der "Text-Splitter" von etoolbox % Wir definieren eine Zählvariable für die Position \def\currentIdx{0}% % Dieser Befehl geht durch JEDES Element einer Komma-Liste, % egal ob sie als Text oder Makro kommt. % \DeclareListParser{\@CSVsplitter}{,}% \renewcommand*{\do}[1]{% % #1 ist jetzt z.B. "v/pair" % Wir spalten den Schrägstrich mit xstring \StrBefore{##1}{/}[\tempName]% \StrBehind{##1}{/}[\tempSpin]% % X-Position berechnen \pgfmathsetmacro{\xpos}{\xposs - ((\orbit@llength + \orbit@ldistance) * (\arrlength - 1)) / 2 + (\currentIdx) * (\orbit@llength + \orbit@ldistance)}% % Orbital zeichnen % \orbital{\xpos}{#1}{\tempName}{\tempSpin}% \edef\tempcall{\noexpand\orbital{\xpos}{#1}{\tempName}{\tempSpin}} \tempcall % Index erhöhen \pgfmathsetmacro{\nextIdx}{int(\currentIdx + 1)}% \xdef\currentIdx{\nextIdx}% }% % now finally expanding the text \expandafter\docsvlist\expandafter{#2}% } % draw orbitals in compact mode \newcommand{\degeneratecorrectedcompact}[3]{% \StrCount{#2}{,}[\arrcount]% \pgfmathsetmacro{\arrlength}{int(\arrcount + 1)}% \c@lculateColumnX{\xposs}{#3} \def\currentIdx{0}% \renewcommand*{\do}[1]{% \StrBefore{##1}{/}[\tempName]% \StrBehind{##1}{/}[\tempSpin]% \pgfmathsetmacro{\ypos}{#1 - ((\orbit@ldistance) * (\arrlength - 1)) / 2 + (\currentIdx) * (\orbit@ldistance)}% \ifcase\currentIdx \else \def\tempName{} \fi \edef\tempcall{\noexpand\orbital{\xposs}{\ypos}{\tempName}{\tempSpin}} \tempcall \pgfmathsetmacro{\nextIdx}{int(\currentIdx + 1)}% \xdef\currentIdx{\nextIdx}% }% % now finally expanding the text \expandafter\docsvlist\expandafter{#2}% } % Deprecated \newcommand{\sliptogether}[6]{ \pgfmathsetmacro{\xposleft}{\orbit@llength /2 + (\orbit@llength * #2 + \orbit@ldistance * (#2 - 1)) /2} \pgfmathsetmacro{\xposmiddleleft}{(\orbit@llength + \columndistance) +\orbit@llength /2 - (\orbit@llength * #4 + \orbit@ldistance * (#4 - 1)) /2} \pgfmathsetmacro{\xposmiddleright}{(\orbit@llength + \columndistance) + + \orbit@llength /2+ (\orbit@llength * #4 + \orbit@ldistance * (#4 - 1)) /2} \pgfmathsetmacro{\xposright}{(\orbit@llength + \columndistance)*2 + \orbit@llength /2 - (\orbit@llength * #6 + \orbit@ldistance * (#6 - 1)) /2} \ifcase#2 \else \draw[dashed, thin, gray] (\xposleft,#1) -- (\xposmiddleleft,#3); \fi \ifcase#6 \else \draw[dashed, thin, gray] (\xposmiddleright,#3) -- (\xposright,#5); \fi } % Deprecated \newcommand{\connectorbital}[5]{ \PackageWarningNoLine{mohelper}{% \noexpand\connectorbital is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% \ifstrequal{#5}{left}{ \ifdefstring{\diagrammode}{compact}{ \sliptogether{#1}{1}{#3}{1}{0}{0}% }{ \sliptogether{#1}{#2}{#3}{#4}{0}{0}% }% }{ \ifdefstring{\diagrammode}{compact}{ \sliptogether{0}{0}{#1}{1}{#3}{1}% }{ \sliptogether{0}{0}{#1}{#2}{#3}{#4}% }% }% } \newcommand{\overlapp}[3]{% \PackageWarningNoLine{mohelper}{% \noexpand\overlapp is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% \ifdefstring{\diagrammode}{compact}{ \def\func{\degeneratecorrectedcompact}% }{\def\func{\degeneratecorrected}}% \foreach \orbs/\elecs in {#1}{% \func{\orbs}{\elecs}{0}% } \foreach \orbs/\elecs in {#2}{% \func{\orbs}{\elecs}{1}% } \foreach \orbs/\elecs in {#3}{% \func{\orbs}{\elecs}{2}% } \foreach \atomorbitalone/\elecsleft in {#1}{% \StrCount{\elecsleft}{,}[\degeneratefirst]% \pgfmathsetmacro{\degeneratefirst}{\degeneratefirst + 1} \ifdefstring{\diagrammode}{compact}{\pgfmathsetmacro{\degeneratefirst}{1}}{}% \foreach \molecorb/\elecsmiddle in {#2}{% \StrCount{\elecsmiddle}{,}[\degeneratesecond]% \pgfmathsetmacro{\degeneratesecond}{\degeneratesecond + 1} \ifdefstring{\diagrammode}{compact}{\pgfmathsetmacro{\degeneratesecond}{1}}{}% \sliptogether{\atomorbitalone}{\degeneratefirst}{\molecorb}{\degeneratesecond}{0}{0} \foreach \atomorbitaltwo/\elecsright in {#3}{ \StrCount{\elecsright}{,}[\degeneratethird]% \pgfmathsetmacro{\degeneratethird}{\degeneratethird + 1}% \ifdefstring{\diagrammode}{compact}{\pgfmathsetmacro{\degeneratethird}{1}}{}% \sliptogether{0}{0}{\molecorb}{\degeneratesecond}{\atomorbitaltwo}{\degeneratethird}% } }% }% }% % hier die ganzes utils für a,e,t % param: % 1: y-level % 2: name des orbitals % 3: zugehörigkeit: left right middle \newcommand{\nondegenerate}[4]{ \PackageWarningNoLine{mohelper}{% \noexpand\nondegenerate is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% % \newcommand{\xposition}{ \ifstrequal{#3}{left}{\def\xpos{0}}{} \ifstrequal{#3}{middle}{\def\xpos{\orbit@llength+\columndistance}}{} \ifstrequal{#3}{right}{\def\xpos{\orbit@llength*2+\columndistance*2}}{} % } \orbital{\xpos}{#1}{#2}{#4} } \newcommand{\twicedegenerate}[6]{ \PackageWarningNoLine{mohelper}{% \noexpand\twicedegenerate is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% % \newcommand{\xposition}{ \ifstrequal{#4}{left}{\def\xposs{0}}{} \ifstrequal{#4}{middle}{\def\xposs{\orbit@llength+\columndistance}}{} \ifstrequal{#4}{right}{\def\xposs{\orbit@llength*2+\columndistance*2}}{} % } \def\xpos{\xposs-\orbit@llength/2-\orbit@ldistance/2} \orbital{\xpos}{#1}{#2}{#5} \orbital{\xpos+\orbit@llength+\orbit@ldistance}{#1}{#3}{#6} } \newcommand{\tripledegenerate}[8]{ \PackageWarningNoLine{mohelper}{% \noexpand\tripledegenerate is obsolete and might get removed in future versions of the package.\MessageBreak Please use \noexpand\fragment{...} instead. See the manual for further information on how to use the new system.% }% % \newcommand{\xposition}{ \ifstrequal{#5}{left}{\def\xposs{0}}{} \ifstrequal{#5}{middle}{\def\xposs{\orbit@llength+\columndistance}}{} \ifstrequal{#5}{right}{\def\xposs{\orbit@llength*2+\columndistance*2}}{} % } \def\xpos{\xposs-\orbit@llength-\orbit@ldistance} \orbital{\xpos}{#1}{#2}{#6} \orbital{\xpos+\orbit@llength+\orbit@ldistance}{#1}{#3}{#7} \orbital{\xpos+2*\orbit@llength+2*\orbit@ldistance}{#1}{#4}{#8} } \newcommand{\addenergyscale}[1]{ \draw[->, -{Stealth[scale=1.2]}, semithick] (\minX-0.5-#1,\minY-0.5) -- (\minX-0.5-#1,\maxY+0.5) node[anchor=east, font=\footnotesize] {E}; } \newcommand{\addlabel}[2]{ \foreach \name [count=\i] in {#1}{ \pgfmathsetmacro{\pos}{\orbit@llength/2 + (\i - 1) * (\orbit@llength + \columndistance)} \node[below=0pt, font=\scriptsize] at (\pos,\minY-0.5-#2) {\name}; } }