12

I would like to define a node style, so that the node will look like the LaTeX symbol \oplus, i.e. a circle with lines from north to south, and east to west. (I also have more complicated examples in mind.)

I think that I should draw the lines in the execute at end node, or after mode path arguments, but nothing I have tried seems to work. The code I have in mind is something like this:

\tikzstyle{foo}=[circle,draw,execute at end node={\draw ??????}]

To rephrase the question: How can one do arbitrary drawing within a node, and define this as a style? In particular, how do you get the coordinates of the current node in a style?

Martin Scharrer
  • 262,582

2 Answers2

12

All TikZ node shapes are defined using lower-level PGF code. This is described in the pgfmanual in section 75.5 Declaring New Shapes, on page 625 of the v2.1 manual.

You can use the existing code of the circle shape as a base and add the lines to it. The code can be found in the file ${TEXMF}/tex/generic/pgf/modules/pgfmoduleshapes.code.tex.

Here the way I would do it:

Shape declaration:

\pgfdeclareshape{oplus}
%
% Shaped like '\oplus' math symbol. Based on 'circle' shape
%
{%
  % All anchors are taken from the 'circle' shape:
  \inheritsavedanchors[from={circle}]%
  \inheritanchor[from={circle}]{center}%
  \inheritanchor[from={circle}]{mid}%
  \inheritanchor[from={circle}]{base}%
  \inheritanchor[from={circle}]{north}%
  \inheritanchor[from={circle}]{south}%
  \inheritanchor[from={circle}]{west}%
  \inheritanchor[from={circle}]{east}%
  \inheritanchor[from={circle}]{mid west}%
  \inheritanchor[from={circle}]{mid east}%
  \inheritanchor[from={circle}]{base west}%
  \inheritanchor[from={circle}]{base east}%
  \inheritanchor[from={circle}]{north west}%
  \inheritanchor[from={circle}]{south west}%
  \inheritanchor[from={circle}]{north east}%
  \inheritanchor[from={circle}]{south east}%
  \inheritanchorborder[from={circle}]%
  %
  % Only the background path is different
  %
  \backgroundpath{%
    % First the existing 'circle' code:
    \pgfutil@tempdima=\radius%
    \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/outer xsep}}%
    \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/outer ysep}}%
    \ifdim\pgf@xb<\pgf@yb%
      \advance\pgfutil@tempdima by-\pgf@yb%
    \else%
      \advance\pgfutil@tempdima by-\pgf@xb%
    \fi%
    \pgfpathcircle{\centerpoint}{\pgfutil@tempdima}%
    %
    % Now the | and -- lines:
    \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{0pt}{\pgfutil@tempdima}}}%
    \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{0pt}{-\pgfutil@tempdima}}}%
    \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{\pgfutil@tempdima}{0pt}}}%
    \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{-\pgfutil@tempdima}{0pt}}}%
  }%
}

Usage example:

\documentclass{standalone}

\usepackage{tikz}
\usepackage{pgfshape_oplus}

\begin{document}
\begin{tikzpicture}
  \node [draw=blue,shape=oplus] {Test};
\end{tikzpicture}
\end{document}

Result:

Result

You might also want to draw the additional lines in the \foregroundpath instead. For this see the forbidden sign shape in the file pgflibraryshapes.symbols.code.tex is an good example.

Martin Scharrer
  • 262,582
  • very good answer: the right method, the right code. But note the forbidden sign shape is backwards! – Matthew Leingang Feb 17 '11 at 13:05
  • @Matthew: You mean the line is drawn in the wrong angle, do you? That's something which should be reported to the PGF/TikZ author. Nevertheless the code of it is a good example for having a circle as background path and the other lines in the foreground. – Martin Scharrer Feb 17 '11 at 13:29
  • Yes, that's what I meant. I did report it to the mailing list a while back (google tells me it was Feb 2009). Maybe I should follow up on that since it's just a one-line patch—unless now you want it to be an option to have it backwards! – Matthew Leingang Feb 17 '11 at 13:35
  • @Matthew: Yeah, backwards compatibility (wow what a pun! :-) ) is always an issue even with smaller stuff like this. – Martin Scharrer Feb 17 '11 at 13:48
  • @Martin: Tell me about it. The new pgfmath engine has introduced bugs in lots of the graphs that I use for teaching. :-( – Matthew Leingang Feb 17 '11 at 14:17
  • @Matthew: Yes I heard from that, especially the {\n}^2 vs. \n^2 bug. – Martin Scharrer Feb 17 '11 at 14:20
  • @Martin: c'est ça, exactement. – Matthew Leingang Feb 17 '11 at 14:58
  • @Matthew Thanks because I did not know this problem. I know only the problem with negative values and x^2 but in which case do you put braces around \n? The interesting case is to hide parentheses with braces inside coordinates. – Alain Matthes Feb 17 '11 at 16:14
  • @Matthew: what new pgfmath engine is this? Does pgf have lots of bugs? Alarming... – Faheem Mitha Feb 17 '11 at 17:56
  • @Faheem: Don't be alarmed. It can be worked around by replacing \x^n with (-\x)^n in most cases. They may have actually fixed it in CVS; I haven't checked lately (CVS was recently down for quite a while while sourceforge was under attack). This is the only bug I've found in PGF which I otherwise love! I apologize for hijacking the comment thread as well. – Matthew Leingang Feb 17 '11 at 18:06
  • @Martin: thanks very much for this answer. It is exactly what I needed, and gives the tools to generalise in the ways I wanted to. – Ross Duncan Feb 21 '11 at 09:57
7

A possibility :

 \begin{tikzpicture}
   \tikzset{oplus/.style={path picture={% 
      \draw[black]
       (path picture bounding box.south) -- (path picture bounding box.north) 
       (path picture bounding box.west) -- (path picture bounding box.east);
      }}} 
    \node[oplus,fill=blue!10,draw=blue,thick,circle] {};
    \end{tikzpicture}

oplus

It's possible to send the cross in the background and to change the color

\begin{tikzpicture}
 \tikzset{oplus/.style={path picture={%
 \begin{pgfonlayer}{background} 
 \draw[red,opacity=.5]
  (path picture bounding box.south) -- (path picture bounding box.north) 
  (path picture bounding box.west) -- (path picture bounding box.east);
\end{pgfonlayer}}}
}
\node[oplus,draw=blue,thick,circle](a) {TEST}; 
\end{tikzpicture}

oplus 2

Now your code execute at end node is not good in this case. This code modifies the content of the node. You can try the next code :

 \begin{tikzpicture}
    \tikzset{foo/.style ={circle,draw, execute at end node={\ #1}}} 
    \node[foo=bad](A) at (2,3){good};
 \end{tikzpicture}

Interesting is execute at begin node=$ and execute at end node=$

Now if my answer is not what you want, you can define new shape like shape =oplus like in the other answer from Martin.

Alain Matthes
  • 95,075