7

Why does the following tikz code place the arrow tip where it does?

\documentclass[border=5pt, tikz]{standalone}
\usetikzlibrary{arrows.meta, bending}

\begin{document}
\begin{tikzpicture}
  \draw[-Latex, double] (0:0.5) arc (0:180:0.5);
\end{tikzpicture}

\end{document}

badly positioned arrow tip

I get the expected behavior if I remove the double line, remove the bending library, or use the standard latex arrow tip rather than the Latex arrow tip from arrows.meta.

no double lineno bendinglatex arrow tip

Somehow the combination of these three features seems to break, however. Is there any way to get all three to work together?

  • In Tikz manual at each type of arrows.meta is noted: On double lines, the arrow tip will not look correct. So, don't expect to much ... :) – Zarko Nov 16 '16 at 18:49
  • This is do not answer your question but you can try it : \draw[-{[length=9pt,width=7pt,black]Latex},line width=1.4pt,postaction={draw,white,line width=.6pt,}] (0:0.5) arc (0:180:0.5);. In general for double lines we use implies arrow. – Kpym Nov 16 '16 at 19:53
  • @Kpym Is there any way to implement your solution without specifying the arrow size? I think the arrow does need to be drawn on both paths (so that they have the same length and shape), but is it possible to infer the arrow size on one path from the other? – Emma Nov 16 '16 at 22:13
5

tl;dr

Redefine the following macro by adding two new lines:

\documentclass[border=5pt,tikz]{standalone}
\usetikzlibrary{arrows.meta,bending}

\begin{document}

\makeatletter

\def\pgf@draw@curved#1#2{%
  % Prepare:
  {%
    \pgf@xc\pgf@xb          % <--- adding new line
    \pgfarrows@getid{#1}{#2}%
    \pgf@xb\pgf@xc          % <--- adding new line
    % Do shift:
    \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname%
    \expandafter\let\expandafter\pgf@arrow@bending@mode\csname pgf@ar@bending@mode@#1\endcsname%
    \ifx\pgf@arrow@bending@mode\pgfutil@empty\let\pgf@arrow@flex@mode\pgf@arrow@mode@is@flex\fi%
    % do swap:
    {%
      \csname pgf@ar@saves@\pgf@arrow@id\endcsname%
      \ifcase\pgf@arrow@flex@mode\relax%
        \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@visual@\pgf@arrow@id\endcsname% like flex
      \or%
        \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@visual@\pgf@arrow@id\endcsname% 
      \or%
        \expandafter\expandafter\expandafter\pgf@arrow@drawer@rigid\csname pgf@ar@ends@\pgf@arrow@id\endcsname%      
      \or%
        \pgf@arrow@drawer@bend%
      \fi%
      % hull points inside the above
    }%
  \expandafter}%
  % Transform to next tip:
  \expandafter\pgf@xb\the\pgf@xb%
}
\def\pgf@arrow@drawer@rigid@shift#1#2#3{% tip end, back end, line end, sep
  % Let xa be the actual back end of the current arrow plus the back end:
  \advance\pgf@xb by#2%
  \pgf@xa\pgf@xb%
  % Update the xb:
  \pgf@x#1%
  \advance\pgf@x by\pgfarrowsep%
  \advance\pgf@xb by-\pgf@x%
}


\def\pgf@arrow@drawer#1#2{%
  % Prepare:
  {%
    \pgfarrows@getid{#1}{#2}%
    % Do shift:
    \expandafter\expandafter\expandafter\pgf@arrow@drawer@shift\csname pgf@ar@ends@\pgf@arrow@id\endcsname%
    % Do slant:  
    \ifdim\pgfarrows@slant pt=0pt%
    \else%
      \pgftransformxslant{\pgfarrows@slant}%
    \fi%
    % do swap:
    \ifpgfarrowswap%
      \pgftransformyscale{-1}%
    \fi%
    {%
      \csname pgf@ar@saves@\pgf@arrow@id\endcsname%
      \pgfscope%
        \pgf@arrows@color@setup%
        \pgflowlevelsynccm\csname pgf@ar@cache@\pgf@arrow@id\endcsname%
      \endpgfscope%
      \pgf@arrows@rigid@hull%
    }%  
  \expandafter}%
  % Transform to next tip:
  \expandafter\pgftransformxshift\expandafter{\the\pgf@xc}%
}

\def\test#1{\tikz\draw[double,-{#1}](1,0)..controls(1,1)and(0,1)..(0,0);}

\test{Rectangle[length=1,width=5,black]
      Rectangle[length=2,width=4,black!80]
      Rectangle[length=3,width=3,black!60]
      Rectangle[length=4,width=2,black!40]
      Rectangle[length=10,width=1,black!20]}
\test{latex[]}
\test{Straight Barb}
\test{Hooks}
\test{Arc Barb}
\test{Tee Barb}
\test{Classical TikZ Rightarrow}
\test{Computer Modern Rightarrow}
\test{Implies}
\test{Latex}
\test{Stealth}
\test{Kite}
\test{Square}
\test{Circle}
\test{Round Cap}
\test{Butt Cap}
\test{Triangle Cap}
\test{Fast Triangle}
\test{Fast Round}
\test{Rays}

\end{document}

Longer story

The dimension \pgf@xb is used to remember the positions of arrow tips. But for some reason it is overwritten by something in \pgfarrows@getid.

So a workaround is to use \pgf@xc to remember \pgf@xb, and then repair \pgf@xb after \pgfarrows@getid. One can use whatever dimension register one likes. However, it is better to declare a new dimension in the long term.

Even longer story

Why bending library

Without bending library, the xshift is done outside the group where \pgfarrows@getid ruins everything. That is, the overwritten \pgf@xb dies when the group terminates so the correct \pgf@xb is used. (see \pgf@arrow@drawer. This is the original version of \pgf@draw@curved.)

However, Since bending library introduces three modes that require different treatments of xshift, the xshift is done in the \ifcase which lies in the group where \pgfarrows@getid ruins everything.

Why some arrow tips immune?

Some arrow tips are duplicates of that we use in math mode. These arrow are independent of PGF/TikZ's parameters. Long story short: latex an instance.

For arrow tips such as Latex, their \pgfarrows@getid involves some calculations on PGF/TikZ's parameters. To be specific, they need to run \pgfarrowslinewidthdependent.

Why double?

Because when double is used, the calculation of \pgfarrowslinewidthdependent becomes even more complex, and \pgf@xb is overwritten!

3

When you load the bending library, the default method for drawing arrow tips is changed from quick to flex. flex is more computationally expensive than quick, but less expensive than bend, and usually gives better results. But not always. You can restore the quick default by specifying it explicitly:

\documentclass[border=5pt, tikz]{standalone}
\usetikzlibrary{arrows.meta, bending}

\begin{document}
\begin{tikzpicture}
  \draw[-Latex, double] (0:0.5) arc (0:180:0.5);
  \scoped[yshift=10mm]{\draw[-{Latex[quick]}, double] (0:0.5) arc (0:180:0.5);}
\end{tikzpicture}
\end{document}

arrow tips

However, none of the three methods gives great results - quick just happens to the the best of the available evils.

  • This is good to know. Of course the whole point of using the bending library was to use flex on this type of path, where the unflexed arrow looks pretty awkward (not to mention that the arc itself is also deformed). It actually turned out that the latex arrow had enough flexibility (no pun intended) for my desired use, but I'm still interested to see workarounds. – Emma Nov 17 '16 at 3:40
  • @Emma Well you did say the problem disappeared if you didn't load the bending library, so that obviously suggested that output was acceptable. There is no of course here. I assumed you needed the bending library for arrows elsewhere. Anyway, I did say none of them looked any good. – cfr Nov 17 '16 at 4:00
  • I meant that without the bending library the output is as expected, which is not to say that it is as desired :) – Emma Nov 18 '16 at 2:05
  • @Emma You should be clearer, then! But, as I said, it obviously isn't a good solution. Just as well you have a much better one ;). – cfr Nov 18 '16 at 2:18

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.