5

I would like to create an antenna shape in TikZ with custom anchors. Since I am struggling with \pgfdeclareshape, I am using path picture instead.

Is it possible to make the coordinates created inside the path picture command accessible as anchors?

Also, is it possible to rotate the entire shape around the center point including the defined anchors?

MWE:

\documentclass[border=1pt]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=newest}
\tikzset{antenna/.style={draw=none,
    path picture={
        \draw coordinate (feed) at (path picture bounding box.west);
        \draw coordinate (center) at (path picture bounding box.center);
        \draw coordinate (phase center) at (path picture bounding box.east);
        \draw (feed)-- (center);
        \draw (center)-- (path picture bounding box.north east);
        \draw (center)-- (path picture bounding box.south east);
}}}

\begin{document}
    \begin{tikzpicture}
        \node[antenna] (antenna1) {};
        %\draw[->] (antenna1.phase center)-- ++(1, 1);  % I want this to work
    \end{tikzpicture}
\end{document}
3
  • You are looking for pic. Dec 30, 2020 at 18:30
  • 2
    I’m voting to close this question because solved in comments. May 14, 2021 at 19:24
  • 3
    I'm voting to leave open because the comment is quite minimal - I wouldn't know how to implement this from the comment alone.
    – Marijn
    May 14, 2021 at 20:44

1 Answer 1

4

We could name a coordinate that it is named antenna1.phase center but since the . is used by TikZ to detect a node-with-anchor specification we would need to use the explicit version, i.e. (node cs: name=antenna.phase center) and then it might be better to define fake anchors (i.e. coordinates as you have used them) but just with - instead of ..

path picture with - instead of .

We could do this as such:

\documentclass[border=1pt,tikz]{standalone}
\makeatletter
\tikzset{name prefix node name/.style={name prefix/.expanded=\tikz@fig@name}}
\makeatother
\tikzset{
  antenna/.style={
    draw=none,
    path picture={
      \tikzset{name prefix node name}
      \coordinate (-feed)   at (path picture bounding box.west)
       coordinate (-center) at (path picture bounding box.center)
       coordinate (-phase center) at (path picture bounding box.east);
      \draw (-feed)   -- (-center)
            (-center) -- (path picture bounding box.north east)
            (-center) -- (path picture bounding box.south east);}}}
\begin{document}
\begin{tikzpicture}
\node[antenna] (antenna1) {};
\draw[->] (antenna1-phase center)-- ++(1, 1);% close enough
\end{tikzpicture}
\end{document}

Here the name prefix is set up with the name of that node in whose path picture we are.

append after command with added anchors for this shape

Note, however, as you defined it antenna1.phase center is just antenna1.east.

That is, unless you rotate the node but then all the path picture bounding box anchors aren't correct anymore either since the path picture bounding box won't rotate with. You'd want an append after command then since it will have the same transformation as the source node.

Let's do it that way and add our special anchors only for that node:

\documentclass[border=1pt,tikz]{standalone}
\makeatletter
\tikzset{
  add anchor to node/.code n args={3}{%
    \edef\tikz@temp##1{%  \tikz@pp@name/\tikzlastnode needs to be expanded
      \noexpand\pgfutil@g@addto@macro\expandafter\noexpand\csname pgf@sh@ma@\tikz@pp@name{#1}\endcsname{%
        \def\expandafter\noexpand\csname pgf@anchor@\csname pgf@sh@ns@\tikz@pp@name{#1}\endcsname @#2\endcsname{##1}%
      }}\tikz@temp{#3}},
  add anchor alias to node/.style n args={3}{
    add anchor to node={#1}{#2}{\pgf@sh@reanchor{\csname pgf@sh@ns@\pgfreferencednodename\endcsname}{#3}}},
  add anchor alias to me/.style args={#1 for #2}{append after command={
      [add anchor alias to node={\tikzlastnode}{#1}{#2}]}}}
\makeatother
\tikzset{
  antenna/.style={
    draw=none, add anchor alias to me/.list={phase center for east,feed for west},
    append after command={(\tikzlastnode.center) edge (\tikzlastnode.feed)
      edge (\tikzlastnode.north east) edge (\tikzlastnode.south east)}}}
\begin{document}
\begin{tikzpicture}
\node[antenna, rotate=10] (antenna1) {};
\draw[->] (antenna1.phase center)-- ++(1, 1);
\end{tikzpicture}
\end{document}

Pic 🐷

That said, before we re-invent the pic, let's use that instead.

- instead of .

Though, we're going to use - instead of . again. A pic sets the appropriate name prefix on its own so every coordinate we define gets the name of the pic prefixed.

\documentclass[border=1pt,tikz]{standalone}
\tikzset{
  pics/antenna/.default=.3333em,
  pics/antenna/.style={code={
      \path[pic actions] (0,0) coordinate (-center) edge (left:#1) coordinate (-feed)
        edge (#1,#1) edge (#1,-#1) coordinate (-phase center) at (right:#1);}}}
\begin{document}
\begin{tikzpicture}
\pic (antenna1) {antenna};
\draw[->] (antenna1-phase center)-- ++(1, 1);
\end{tikzpicture}
\end{document}

That's pretty easy and we even can use a pic along a path and rotate it and change colors and …

Real pic anchors?

With a little hackery again, we can add anchors to a pic that references a coordinate inside the pic.

\documentclass[border=1pt,tikz]{standalone}
\makeatletter
\tikzset{
  add anchor to node/.code n args={3}{%
    \edef\tikz@temp##1{% \tikz@pp@name/\tikzlastnode needs to be expanded
      \noexpand\pgfutil@g@addto@macro\expandafter\noexpand\csname pgf@sh@ma@\tikz@pp@name{#1}\endcsname{%
        \def\expandafter\noexpand\csname pgf@anchor@\csname pgf@sh@ns@\tikz@pp@name{#1}\endcsname @#2\endcsname{##1}%
      }}\tikz@temp{#3}},
  add anchor to pic/.style args={#1 to #2}{
    /utils/exec=\pgfutil@ifundefined{pgf@sh@ns@\tikz@pp@name{}}{\pgfcoordinate{\tikz@pp@name{}}{\pgfpointorigin}}{},
    add anchor to node/.expanded={}{#1}{\noexpand\pgfpointanchor{\tikz@pp@name{#2}}{center}}}}
\makeatother
\tikzset{
  pics/antenna/.default=.3333em,
  pics/antenna/.style={code={
    \path[pic actions] (0,0) coordinate (-center) edge (left:#1) coordinate (-feed)
      edge (#1,#1) edge (#1,-#1) coordinate (-phase center) at (right:#1);
    \tikzset{
      add anchor to pic/.list={phase center to -phase center, feed to -feed}}
}}}
\begin{document}
\begin{tikzpicture}
\pic (antenna1) {antenna};
\draw[->] (antenna1.phase center)-- ++(1, 1);
\end{tikzpicture}
\end{document}
2
  • That answer is awesome… but I wanted to generalize your approach to use the pic inside a node like \node[antennaStyle]{}; where antenna/.style={append after command={pic {antenna}}}… but I get error ERROR: Missing \endcsname inserted. when I try your code this way. The end goal would be to create new anchors with styles antennaStyle to the parent node directly.
    – tobiasBora
    Feb 21, 2023 at 18:30
  • For the robust version, see tex.stackexchange.com/questions/676017/… (thanks again!)
    – tobiasBora
    Feb 22, 2023 at 0:35

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .