2

Update 2

The discussion continues on Github where the latest work in progress (and possible future updates) can be found. As I was able to fix all of the problems in the code below, I consider this question to be solved.

Original problem

The tikz/double option which is used by tikz/commuting diagrams/Rightarrow internally creates a wide black line and a slightly less wide white line on top of it to display what looks like a double stroked path (see pgf manual, /tikz/double=). This causes (at least) two types of visual glitches. Notably, several viewers do not display both "strokes" of the path on all zoom levels, as the white part sometimes completely overrides the black path (discussed here, see also the screenshot below). Furthermore, there is a spurious horizontal line at the tail and before the head of the arrow (discussed here). See the pictures below for details.

Work in progress [Update 1]

To remedy these issues, I decided to define a modification of Rightarrow which draws two thin lines instead.

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{calc,cd}

\newlength{\eqoffset}
\makeatletter
% relative coordinates: (0,0) is the arrow's tail, x points towards the head,
% y points perpendicular, unit distance is \eqoffset
\newcommand{\relptstart}[2]{($($(k0)!#1*\eqoffset+\pgf@shorten@start@additional!0:(k1)$)!#2*\eqoffset!90:(k1)$)}
% (0,0) is the arrow's tip, rest is the same
\newcommand{\relptend}[2]{($($(k1)!#1*\eqoffset-\pgf@shorten@end@additional
    -2*\eqoffset-.5*\pgflinewidth!180:(k0)$)!#2*\eqoffset!-90:(k0)$)}
\tikzcdset{
    nRightarrow/.style={line join=round,
    no head,
    /tikz/commutative diagrams/@shiftabletopath,
    execute at begin to = {
        % Do not use tikzcd@noda or tikzcd@x here, it causes interference.
        % Use new names instead
        \path (\tikztostart) -- (\tikztotarget) coordinate[pos=0] (k0) coordinate[pos=1] (k1);
        \pgfpointnormalised{\pgfpointdiff{\pgfpointanchor{k1}{center}}{\pgfpointanchor{k0}{center}}}
        \pgfgetlastxy{\kdx}{\kdy}
        \tikzset{
        to path={
            % arrow body
            % the .06 is from \pgftransformxshift{.06\pgfutil@tempdima}
            \relptstart{0}{1}
            -- \relptend{-.06}{1}
            {
                % correct vertical position, more central horizontal position
                %               [xshift=-\kdy*\eqoffset, yshift=\kdx*\eqoffset]
                % matches original Rightarrow more closely
                [xshift=-\kdy*\eqoffset-\kdx*(\eqoffset+.25*\pgflinewidth),
                yshift=\kdx*\eqoffset-\kdy*(\eqoffset+.25*\pgflinewidth)] 
                \tikztonodes}
            \relptstart{0}{-1}
            -- \relptend{-.06}{-1}
            % arrow tip
            % fake the round cap by using round joins and drawing the path twice with a turnaround at the caps
            \relptend{2}{0}         % tip to top end
            .. controls \relptend{1}{0.05} and \relptend{-0.75}{1.25} ..
            \relptend{-1.4}{2.65}   % top end back to tip
            .. controls \relptend{-0.75}{1.25} and \relptend{1}{0.05} ..
            \relptend{2}{0}         % tip to bottom end
            .. controls \relptend{1}{-0.05} and \relptend{-0.75}{-1.25} ..
            \relptend{-1.4}{-2.65}  % bottom end back to tip
            .. controls \relptend{-0.75}{-1.25} and \relptend{1}{-0.05} ..
            \relptend{2}{0}
            % Add a degenerate path segment at the end so shorten < and shorten > are not applied again
            (k1)
        }}
    }}
}
\makeatother

\begin{document}
\setlength{\eqoffset}{.225ex}
\begin{tikzcd}
    a_1
    \ar[dr, red, Rightarrow, shift={(0pt, 4pt)}, "l", "m"']
    \ar[dr, nRightarrow, shift={(0pt, 4pt)}, green, opacity=.5, "l", "m"']
    & a_2
    \ar[dr, red, Rightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, "l"]
    \ar[dr, blue, shift left=7pt, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l"]
    \ar[dr, green, nRightarrow, shift left=7pt, shorten <=2pt, shorten >=3pt, opacity=.5, "l"]
    & a_3 & a_4 
    \ar[d, red, Rightarrow, shorten <=2pt, shorten >=3pt, "l", "m"']
    \ar[d, green, nRightarrow, shorten <=2pt, shorten >=3pt, opacity=.5, "l", "m"']
    \\
    b_1 & b_2 & b_3 & b_4
\end{tikzcd}

\end{document}

picture of this code

Glitches in Rightarrow:

glitch 1

glitch 2

Known issues

  • This approach will never work with a custom specification of to path.
  • As of now, shift left only works if specified before nRightarrow, seen in the green and blue arrows from a2 to b3.
  • The label position does not exactly match Rightarrow, especially if near start, near end, shorten <, or shorten > is specified. Personally, I think the new label position is just as good or better, as the label position of Rightarrow sometimes is very close to the arrow head.

Other approaches

I also tried the following:

  • Use decorations and meta-decorations: This works to a degree, but sub-pt precision is difficult, and I found no reliable way to have the decoration end at exactly the right point.
  • Define a \newcommand which calls \ar three times, with shift left, shift right, and draw=none plus a custom tip: This works to a degree, but I would very much prefer to have this as a tikz style, and I had some reliability issues.

Thanks in advance for any help!

2
  • I have solved parts of the problem myself and updated the question. Better solutions and improvement suggestions are very welcome.
    – Jonathan
    May 2 at 20:50
  • 1
    Welcome to TeX.SX. When you post a question, please provide a "Minimal Working Example" (MWE) that starts with \documentclass, includes all relevant \usepackage commands, ends with \end{document} and compiles without errors, even if it does not produce your desired output.
    – Sandy G
    May 3 at 12:11

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.