[Tex/LaTex] Combination of arrows with and without label

arrowsautomationmath-operatorstikz-arrowsxparse

Suppose that an arrow can be

  1. With one head (o), two heads (t), or "squiggly" (g),
  2. Single-lined (s) or double-lined (d),
  3. With (w) or without (o) a label (i.e., text above)

Some of those arrows are defined by "standard" packages, like \xrightarrow{abc}, which corresponds to osw, some of them needs more "exotic" packages, like \xLongrightarrow (tdw), defined by extarrows.

Some needs to be drawn with Tikz, like \xtwoheadrightarrow (tsw), cf. https://tex.stackexchange.com/a/60219/34551

I tried to have a macro allowing me to define all those combinations at once, and to display them with a uniform appearance. I tried to use xparse and l3regex, which seemed to be a good combination to handle it (shout-out to https://tex.stackexchange.com/a/188593/34551).

I think I managed to define a macro that define them all at once, but they look terrible, i.e., really not uniform, and the hack I used for tdw is simply awful.

Should I give up my idea of taking an arrow there and another there, and just draw them all in tiKz? How to make sure, in this case, that they do behave like mathematical operators?

Here's what I managed to get:

enter image description here

Using the following code:

\documentclass{article}
\usepackage{xparse,l3regex}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{extarrows} % For \xLongrightarrow
\usepackage{mathtools}
\usepackage{tikz}
\usetikzlibrary{calc,decorations.pathmorphing,shapes,arrows}

\newcommand\xRightsquigarrow[1]{% https://tex.stackexchange.com/a/83086
  \mathrel{%
    \begin{tikzpicture}[baseline= {( $ (current bounding box.south) + (0,-0.5ex) $ )}]
      \node[inner sep=.5ex] (a) {$\scriptstyle #1$};
      \path[draw,implies-,double distance between line centers=1.5pt,decorate,
      decoration={zigzag,amplitude=0.7pt,segment length=1.2mm,pre=lineto,
    pre   length=4pt}] 
      (a.south east) -- (a.south west);
    \end{tikzpicture}}%
}
\newcommand\Rightsquigarrow{%
  \mathrel{%
    \begin{tikzpicture}[baseline= {( $ (current bounding box.south) + (0,-0.5ex) $ )}]
      \node[inner sep=.5ex] (a) {\hspace*{1em}};
      \path[draw,implies- ,double distance between line centers=1.5pt,decorate,
      decoration={zigzag,amplitude=0.7pt,segment length=1.2mm,pre=lineto,
    pre   length=4pt}] 
      (a.south east) -- (a.south west);
    \end{tikzpicture}}%
}

\makeatletter % https://tex.stackexchange.com/a/114242/34551
\providecommand*{\twoheadrightarrowfill@}{%
  \arrowfill@\relbar\relbar\twoheadrightarrow
}
\providecommand*{\xtwoheadrightarrow}[2][]{%
  \ext@arrow 0579\twoheadrightarrowfill@{#1}{#2}%
}
\makeatother

\ExplSyntaxOn
\NewDocumentCommand{\ar}{ m o }
{
  \IfNoValueTF{#2}
  {% there is no trailing optional argument, set the boolean to false
    \bool_set_false:N \l_label_bool
  }
  {% there is a trailing optional argument, set the boolean to true
    \bool_set_true:N \l_label_bool
    % and store the argument for later usage
    \tl_set:Nn \l_label_tl { #2 }
  }
  \ar_short:n { #1 }
}


% First byte: o, t, g     (one head, two heads, squiggly)
% Second byte: s, d       (single or double)
% Third byte:             (label to write on it)

\bool_new:N \l_label_bool
\tl_new:N \l_label_tl

\cs_new_protected:Npn \ar_short:n #1
{% separate the two characters
  \ar_short_aux:NN #1
}

\cs_new_protected:Npn \ar_short_aux:NN #1 #2{
  \str_case:nn { #1 }
  {
    {o}% One head
    {
      \str_case:nn { #2 }
      {{s}{% Single
      \xtwoheadrightarrow[]{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }{d}{% Double
      \xRightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}\!\!\!\!\Rightarrow}
      }
    }
    {t}% Two heads
    {\str_case:nn { #2 }
      {{s}{% Single
      \xrightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }{d}{% Double
      \xLongrightarrow{  \bool_if:NT \l_label_bool { \l_label_tl }}
    }
      }
    }
    {g}% Squiggly
    {\str_case:nn { #2 }
      {{s}{% Single
      \bool_if:NTF \l_label_bool {\overset{\l_label_tl}{\rightsquigarrow}}{\rightsquigarrow}
    }
    {d}{% Double
      \bool_if:NTF \l_label_bool {\xRightsquigarrow{\l_label_tl}}{\Rightsquigarrow}}
      }
    }
  }
}



\ExplSyntaxOff

\begin{document}

  $a \ar{os} b$

  $a \ar{od} b$

  $a \ar{ts} b$

  $a \ar{td} b$

  $a \ar{gs} b$

  $a \ar{gd} b$

  $a \ar{os}[i_2 : \alpha, 34] b$

  $a \ar{od}[i_2 : \alpha, 34] b$

  $a \ar{ts}[i_2 : \alpha, 34] b$

  $a \ar{td}[i_2 : \alpha, 34] b$

  $a \ar{gs}[i_2 : \alpha, 34] b$

  $a \ar{gd}[i_2 : \alpha, 34] b$

\end{document}

The difference of spacing between them, and the fact that one of them (gsw) is not extensible, are what bug me the most.

Best Answer

Substantially REVISED to achieve what was missing on the earlier post. Namely, all desired arrow types are supported (albeit with wavy, rather than jagged, squiggle), uniform arrow lengths are achieved for a given overset, regardless of arrow type, all math styles are supported.

Some tweaks would be required for a font-size change (currently 10pt) in order to achieve uniformly sized building blocks and arrowheads (see bottom of answer for details).

I have not wrapped it in an overarching macro, but the individual arrow types are called \zigzagarrow (single squiggly line, single arrowhead), \ZigZagarrow (double squiggly line, single arrowhead), \linearrow (single line, single arrowhead), \Linearrow (double line, single arrowhead), \zzigzagarrow (single squiggly line, double arrowhead), \ZZigZagarrow (double squiggly line, double arrowhead), \llinearrow (single line, double arrowhead), and \LLinearrow (double line, double arrowhead),

\documentclass[10pt]{article}
\usepackage{stackengine,scalerel,graphicx,trimclip,amsmath,wasysym}
% UNIFORMLY SIZED BUILDING BLOCKS
\savestack\zigzagtextstyle{\vphantom{()}\scalebox{.86666}[1]{\kern-.5pt\AC\kern-.5pt}}
\savestack\onelinetextstyle{\vphantom{()}\scalebox{1}[1]{\kern-1pt{$-$}\kern-1pt}}
\savestack\twolinetextstyle{\vphantom{()}\scalebox{1}[1]{\kern-1pt{$=$}\kern-1pt}}
\savestack\ZigZagtextstyle{% DERIVATIVE OF \zigzagtextstyle
  $\vphantom{()}\smash{\raisebox{-.002em}{$\vcenter{\hbox{%
   \stackengine{-.805em}{\zigzagtextstyle}{\zigzagtextstyle}{O}{c}{F}{F}{S}}}$}}$}
\newlength\repwidth
\repwidth=\wd\zigzagtextstylecontent\relax
% UNIFORMLY SIZED ARROWHEADS
\newcommand\rightarrowhead{\clipbox{4pt -2pt 0pt -2pt}{$\rightarrow$}}
\newcommand\Rightarrowhead{\clipbox{4pt -2pt 0pt -2pt}{$\Rightarrow$}}
\newcommand\rrightarrowhead{\clipbox{5.5pt -2pt 0pt -2pt}{$\rightarrow\kern-8.5pt\rightarrow$}}
\newcommand\RRightarrowhead{\clipbox{5.5pt -2pt 0pt -2pt}{$\Rightarrow\kern-8.5pt\Rightarrow$}}
% HALF-CYCLE BLOCKS PLUS ARROWHEAD
\newcommand\fXarrowtextstyle[2]{$\vphantom{()}\smash{\vcenter{\hbox{\kern-.03\repwidth%
   \clipbox{-.03\repwidth{} 0pt .527\repwidth{} 0pt}{#1}}}}#2$}
%
\savestack\fzigarrowtextstyle{\fXarrowtextstyle{\zigzagtextstyle}{\rightarrowhead}}
\savestack\fZigarrowtextstyle{\fXarrowtextstyle{\ZigZagtextstyle}{\Rightarrowhead}}
\savestack\flinearrowtextstyle{\fXarrowtextstyle{\onelinetextstyle}{\rightarrowhead}}
\savestack\fLinearrowtextstyle{\fXarrowtextstyle{\twolinetextstyle}{\Rightarrowhead}}
\savestack\fzzigarrowtextstyle{\fXarrowtextstyle{\zigzagtextstyle}{\rrightarrowhead}}
\savestack\fZZigarrowtextstyle{\fXarrowtextstyle{\ZigZagtextstyle}{\RRightarrowhead}}
\savestack\fllinearrowtextstyle{\fXarrowtextstyle{\onelinetextstyle}{\rrightarrowhead}}
\savestack\fLLinearrowtextstyle{\fXarrowtextstyle{\twolinetextstyle}{\RRightarrowhead}}
% SUPPORT FOR ALL MATH STYLES
%  - CYCLE BLOCKS
\newcommand\zigzag{\scalerel*{\zigzagtextstyle}{()}}
\newcommand\ZigZag{\scalerel*{\ZigZagtextstyle}{()}}
\newcommand\oneline{\scalerel*{\onelinetextstyle}{()}}
\newcommand\twoline{\scalerel*{\twolinetextstyle}{()}}
%  - ARROW HEADS
\newcommand\fzigarrow{\scalerel*{\fzigarrowtextstyle}{()}}
\newcommand\fZigarrow{\scalerel*{\fZigarrowtextstyle}{()}}
\newcommand\flinearrow{\scalerel*{\flinearrowtextstyle}{()}}
\newcommand\fLinearrow{\scalerel*{\fLinearrowtextstyle}{()}}
\newcommand\fzzigarrow{\scalerel*{\fzzigarrowtextstyle}{()}}
\newcommand\fZZigarrow{\scalerel*{\fZZigarrowtextstyle}{()}}
\newcommand\fllinearrow{\scalerel*{\fllinearrowtextstyle}{()}}
\newcommand\fLLinearrow{\scalerel*{\fLLinearrowtextstyle}{()}}
% ARROW-EXTENDING USER MACROS
\newcommand\zigzagarrow[1][]{\Xarrow{\zigzag}{\fzigarrow}{#1}{-.65}}
\newcommand\ZigZagarrow[1][]{\Xarrow{\ZigZag}{\fZigarrow}{#1}{-.40}}
\newcommand\linearrow[1][]{\Xarrow{\oneline}{\flinearrow}{#1}{-.65}}
\newcommand\Linearrow[1][]{\Xarrow{\twoline}{\fLinearrow}{#1}{-.40}}
\newcommand\zzigzagarrow[1][]{\Xarrow{\zigzag}{\fzzigarrow}{#1}{-.65}}
\newcommand\ZZigZagarrow[1][]{\Xarrow{\ZigZag}{\fZZigarrow}{#1}{-.40}}
\newcommand\llinearrow[1][]{\Xarrow{\oneline}{\fllinearrow}{#1}{-.65}}
\newcommand\LLinearrow[1][]{\Xarrow{\twoline}{\fLLinearrow}{#1}{-.40}}
% \Xarrow EXTENDING-ARROW MACRO
% #1 - arrow building block
% #2 - arrowhead
% #3 - overtext
% #4 - overset distance multiplier wrt top of paren
\newcommand\Xarrow[4]{\ThisStyle{\mathrel{\Xarrowhelp{#1#2}{#3}{#1}{#4}}}}
\newcommand\Xarrowhelp[4]{%
  \setbox0=\hbox{$\SavedStyle#1$}%
  \setbox2=\hbox{$\SavedStyle_{\,\,#2\,\,}$}%
  \ifdim\wd0<\wd2\relax\Xarrowhelp{#3#1}{#2}{#3}{#4}%
  \else\stackengine{#4\LMex}{\copy0}{\copy2\,}{O}{c}{F}{T}{S}\fi%
}
\begin{document}
\setstackEOL{\\}
\Longunderstack{
3 cycles:
\\
$\zigzagtextstyle\zigzagtextstyle\zigzagtextstyle$
\setbox0=\hbox{\zigzagtextstyle}\the\wd0
\\
$\ZigZagtextstyle\ZigZagtextstyle\ZigZagtextstyle$
\setbox0=\hbox{\zigzagtextstyle}\the\wd0
\\
$\onelinetextstyle\onelinetextstyle\onelinetextstyle$
\setbox0=\hbox{\onelinetextstyle}\the\wd0
\\
$\twolinetextstyle\twolinetextstyle\twolinetextstyle$
\setbox0=\hbox{\twolinetextstyle}\the\wd0
}
\qquad\Longunderstack{
Arrowheads:
\\
\rightarrowhead\setbox0=\hbox{\rightarrowhead}\the\wd0
\\
\Rightarrowhead\setbox0=\hbox{\Rightarrowhead}\the\wd0
\\
\rrightarrowhead\setbox0=\hbox{\rrightarrowhead}\the\wd0
\\
\RRightarrowhead\setbox0=\hbox{\RRightarrowhead}\the\wd0
}
\qquad\Longunderstack{
Half-cycle + arrowheads
\\
\fzigarrowtextstyle \quad \fzzigarrowtextstyle
\\
\fZigarrowtextstyle \quad \fZZigarrowtextstyle
\\
\flinearrowtextstyle \quad \fllinearrowtextstyle
\\
\fLinearrowtextstyle \quad \fLLinearrowtextstyle
}

Examples:

\Shortunderstack{
$A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$A \linearrow B \linearrow[T=298K] C$
\\
$A \Linearrow B \Linearrow[T=298K] C$
\\
$A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$A \llinearrow B \llinearrow[T=298K] C$
\\
$A \LLinearrow B \LLinearrow[T=298K] C$
}
\quad
\Shortunderstack{
$\scriptstyle A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$\scriptstyle A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$\scriptstyle A \linearrow B \linearrow[T=298K] C$
\\
$\scriptstyle A \Linearrow B \Linearrow[T=298K] C$
\\
$\scriptstyle A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$\scriptstyle A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$\scriptstyle A \llinearrow B \llinearrow[T=298K] C$
\\
$\scriptstyle A \LLinearrow B \LLinearrow[T=298K] C$
}
\quad
\Shortunderstack{
$\scriptscriptstyle A \zigzagarrow B \zigzagarrow[T=298K] C$
\\
$\scriptscriptstyle A \ZigZagarrow B \ZigZagarrow[T=298K] C$
\\
$\scriptscriptstyle A \linearrow B \linearrow[T=298K] C$
\\
$\scriptscriptstyle A \Linearrow B \Linearrow[T=298K] C$
\\
$\scriptscriptstyle A \zzigzagarrow B \zzigzagarrow[T=298K] C$
\\
$\scriptscriptstyle A \ZZigZagarrow B \ZZigZagarrow[T=298K] C$
\\
$\scriptscriptstyle A \llinearrow B \llinearrow[T=298K] C$
\\
$\scriptscriptstyle A \LLinearrow B \LLinearrow[T=298K] C$
}
\end{document}

enter image description here

As mentioned earlier, the key is achieving uniformly sized building blocks (cycles and arrowheads, respectively). For 12pt font, here are tweaks required to achieve that:

\savestack\onelinetextstyle{\vphantom{()}\scalebox{.97196}[1]{\kern-1.1pt{$-$}\kern-1.1pt}}
\savestack\twolinetextstyle{\vphantom{()}\scalebox{.97121}[1]{\kern-1pt{$=$}\kern-1pt}}

\newcommand\rrightarrowhead{\clipbox{6.5pt -2pt 0pt -2pt}{$\rightarrow\kern-9.5pt\rightarrow$}}
\newcommand\RRightarrowhead{\clipbox{6.5pt -2pt 0pt -2pt}{$\Rightarrow\kern-9.5pt\Rightarrow$}}

enter image description here