How to give a name to \pic

This is a work around rather than a solution. I wonder if this is a bug but my understanding of tikz is just not good enough to know for certain.

Apparently, tikz no longer likes something about the to operation here within the pic.

What tikz appears to be doing in the case of the \draw... to.. operation is doubling the prefix so that it looks for EmmaEmma-left wing which obviously does not exist. It doesn't do this if you replace the command with a straight line, apparently.

You can get the example to work by temporarily resetting the pic prefix to the value it has outside the pic and then passing the name of the pic through as an option. Clearly this is extremely clumsy and definitely shouldn't be needed. So either this is a bug or something is staring at me and I'm just not seeing it. (This is, after all, basically verbatim from the manual. So it should work!)

\documentclass[tikz,border=3mm]{standalone}
\tikzset{
  seagull/.pic={
    % Code for a "seagull". Do you see it?...
    \coordinate (-left wing) at (-3mm,0);
    \coordinate (-head) at (0,0);
    \coordinate (-right wing) at (3mm,0);
    \draw [name prefix ..] (#1-left wing) to [bend left] (0,0) (#1-head) to [bend left] (#1-right wing);
  }
}
\begin{document}
  \begin{tikzpicture}%\small\sffamily
    \pic (Emma) at (0,0) {seagull=Emma};
    \pic (Alexandra) at (0,1) {seagull=Alexandra};
    \draw  (Emma-left wing) -- (Alexandra-right wing);
  \end{tikzpicture}
\end{document}

Result


This is indeed a bug, but for a different reason, I think this is happening at the same place when the parsing is done in \tikz@subpicture@handle@ but still I didn't understand perfectly how it goes wrong.

When TikZ starts parsing the last \draw command in the pic code and encounters node names, the name prefix is already set. But the object it is parsing is a node (coordinates are also nodes) so it starts thinking hey, I gotta add a prefix to this reference. Hence another node name prefix is triggered and it looks for that shape. The easiest fix as far as I can see is to refer to explicit coordinates such that node name parsing is avoided, example;

\documentclass[tikz]{standalone}

\tikzset{
seagull/.pic={
% Code for a "seagull". Do you see it?...
\coordinate (-left wing) at (-3mm,0);
\coordinate (-head) at (0,0);
\coordinate (-right wing) at (3mm,0);
\draw (-left wing.center) to [bend left] (0,0) (-head.center) to [bend left] (-right wing.center);
}
}


\begin{document}
\begin{tikzpicture}
  \pic (Emma) {seagull};
  \pic (Alexandra) at (0,1) {seagull};
  \draw (Emma-left wing) -- (Alexandra-right wing);
\end{tikzpicture}
\end{document}

This compiles and gives the same result with cfr's picture. Strange indeed. But I think it's not that straightforward to remedy. It might be the case that node name parsing goes awry too, but I didn't check it.

I tried to read the name prefix and see if it matches the node name and if so skip it but didn't succeed. I think this one is for Till Tantau to fix.


I dig a little bit and this is what I found:

When TikZ encounters \draw(A)to(B), this is what will happen

  • \def\tikztostart{\tikz@pp@name{A}}; usually this is simply A;
  • \def\tikztotarget{\tikz@pp@name{B}}; usually this is simply B;
  • The every to/.code is applied here.

In the simplest case, to is merely --, so TikZ now executes

 \draw(\tikztostart)--(\tikztotarget);

Remember that this is equivalent to

 \draw(A)--(B);

So everything is fine.


However, inside a .pic, node names have prefix and suffix. In this case, provided that the pic is names Emma,

  • \tikztostart is EmmaA;
  • \tikztotarget is EmmaB;
  • TikZ ececutes \draw(\tikztostart)--(\tikztotarget);

That is equivalent to

\draw(EmmaA)--(EmmaB);

When TikZ try to parse this node name, the prefix (and suffix) is added again. At the end you see that it cannot find EmmaEmmaA.

Appendix

In tikz.code.tex line 5157

\def\tikz@shapeborder@name{\tikz@pp@name{#2}}%

The same file, line 2969-2975

\def\tikz@to@use@last@coordinate{%
  \iftikz@shapeborder%
    \edef\tikztostart{\tikz@shapeborder@name}%
  \else%
    \edef\tikztostart{\the\tikz@lastx,\the\tikz@lasty}%
  \fi%
}

In my humble opinion, one should fix the definition of tikztostart.