3

I'd like do make a picture that consists of few blocks. One of these blocks I called \elementsymbol (in MWE below) - it consists of an arrow surrounded by a circle.

  1. I have the problem with scaling of the picture - connection of the line to the circle center is lost while picture scale is not equal to 1.
  2. I don't know how to pass the label to my block in the form angle:text.

MWE:

\documentclass{standalone}
\usepackage{tikz}

% https://tex.stackexchange.com/questions/33703/extract-x-y-coordinate-of-an-arbitrary-point-in-tikz
\makeatletter
\newcommand{\gettikzxy}[3]{%
  \tikz@scan@one@point\pgfutil@firstofone#1\relax
  \edef#2{\the\pgf@x}%
  \edef#3{\the\pgf@y}%
}
\makeatother

\pgfkeys{
    /element settings/.is family,
    /element settings,
    default/.style={
        name=nonameelement,
        diameter=2ex,
        x pos=0,
        y pos=0,
        label={}
    },
    name/.store in=\elementname,
    diameter/.store in=\elementdiameter,
    x pos/.store in=\elementxpos,
    y pos/.store in=\elementypos,
    label/.store in=\elementlabel
}
\tikzset{
    pics/elementsym/.style args={origin #1:#2 d #3}{
        foreground code={
            \node (-housing) [draw,circle,minimum size=#3] at (#1,#2) {};
            \draw [-stealth] (-housing.center) -- +(45:0.43*#3);    % arrow part
            \draw (-housing.center) -- +(225:0.4*#3);           % arrow part
        }
    }
}
\newcommand\elementsymbol[1][]{
    \pgfkeys{/element settings,default,#1}
    \path pic (\elementname) {elementsym=origin {\elementxpos}:{\elementypos} d {\elementdiameter}};
    % label attachment
    \node [circle,inner sep=0,minimum size=\elementdiameter]
          at (\elementxpos,\elementypos) [label={[label distance=-0.5ex]60:\elementlabel}] {};
}

\begin{document}
\begin{tikzpicture}[
    scale=0.5
] 
    \draw (0,0) -- +(0:5mm) coordinate (con);
    \gettikzxy{(con)}{\xpos}{\ypos}
    \elementsymbol [x pos=\xpos,y pos=\ypos,name=device,label=x] % How to enable argument "label={60:text}"?
\end{tikzpicture}
\end{document}

Output picture

Links listed below were helpful for me (not everything I understand), but I can't find solutions of the above problems by the use of information contained in these links.

  1. Using pgfkeys as an argument to a macro
  2. How to interpret the contents of a macro as key=value assignment for pgfkeys
  3. How to create a command with key values?

After reading pgfkeys documentation in pgf-tikz manual several times I can't understand it in many points.

3

Ignasi's nodes are surely superior, but it might be useful to see a pic version since pics are generally easier to create than nodes and can straightforwardly accommodate more complex constructions. (Perhaps you could create aliens and witches' cauldrons and cats catching trams as nodes, but I'm not sure you should want to!)

First, a few comments about the changes.

  • It seemed to me that having both a command and a pic needlessly complicated things.

  • Moreover, capturing x and y positions for a given coordinate only makes sense if you want to use them separately. If you are just going to say at (\xthingy,\ythingy) you may just as soon use the coordinate.

  • It is not necessary to set the origin. When you say \pic at (<coordinate>), you can use (0,0) in the pic's code for the (<coordinate>) and TikZ should - and generally will - do the right thing.

  • However, there is a bug - a regression - in current PGF/TikZ which prevents the (-...) naming working as advertised. My code, therefore, works around this and does not rely on this feature. If name=<name>, then <name> will refer to the pic as a whole, including the label, whereas <name>-housing will refer to the pic without the label. Anchors can then be used as desired because the second just is a node and the first is a local bounding box.

  • When using a pic on a path, TikZ is not quite so intelligent as when using a node, for example, so you need to give it some help when continuing the path and should not expect the path to be closed (cycle won't work as you expect). The named node and bounding box are designed to make it easy to provide this information.

  • label={<angle>:<text>} is defined as code which sets label angle and label text by storing them in distinct macros. (I don't know whether you need this exactly, but perhaps it will be useful.)

  • pic actions is added in case you want them. If you don't need pic actions, you can ignore or remove it. As shown below, it facilitates simple customisation of the pic.

  • anchor is introduced so that you can specify the anchor for the -housing node, again allowing easy specification of the extra help TikZ needs to place pics sensibly.

The upshot of all this is that we can say

\begin{tikzpicture}[scale=0.5]
  \draw (0,0) -- ++(0:5mm) pic  {element symbol={name=device, anchor=west, label={60:text}}} (device-housing.east) -| ++(-45:15mm) pic [blue, rotate=45] {element symbol={name=another, anchor=north, label={-90:more}}} (another-housing.west) -| ++(175:20mm) pic [green, fill=black, rotate=180] {element symbol={name=next, anchor=south, label={180:this}}} (next-housing.north) |- (0,0);
\end{tikzpicture}

to produce

element symbol in <code>pic</code> form

Code:

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

% addaswyd y côd dilynol o gwestiwn forrest: http://tex.stackexchange.com/q/321358/

\tikzset{%
  pics/element symbol/.style={%
    code={%
      \tikzset{%
        /element settings,
        default,
        #1,
      }
      \begin{scope}[local bounding box/.expanded=\elementname]
        \node (\elementname-housing) [draw, circle, minimum size=\elementdiameter, anchor=\elementanchor, label={[label distance=-0.5ex]\elementlabelangle:\elementlabeltext}, pic actions] at (0,0) {};
        \draw [-Stealth, pic actions] (\elementname-housing.center) +(225:0.4*\elementdiameter) -- +(45:0.43*\elementdiameter);    % arrow part
      \end{scope}
    }
  },
  /element settings/.is family,
  /element settings,
  name/.store in=\elementname,
  anchor/.store in=\elementanchor,
  diameter/.store in=\elementdiameter,
  label angle/.store in=\elementlabelangle,
  label text/.store in=\elementlabeltext,
  label/.code args={#1:#2}{%
    \tikzset{%
      /element settings,
      label angle=#1,
      label text=#2,
    }%
  },
  default/.style={%
    name=nonameelement,
    diameter=2ex,
    label=0:{},
    anchor=center,
  },
}

\begin{document}
\begin{tikzpicture}[scale=0.5]
  \draw (0,0) -- ++(0:5mm) pic  {element symbol={name=device, anchor=west, label={60:text}}} (device-housing.east) -| ++(-45:15mm) pic [blue, rotate=45] {element symbol={name=another, anchor=north, label={-90:more}}} (another-housing.west) -| ++(175:20mm) pic [green, fill=black, rotate=180] {element symbol={name=next, anchor=south, label={180:this}}} (next-housing.north) |- (0,0);
\end{tikzpicture}
\end{document}
  • Great. Thx for all remarks and piece of code - in fact I looked for such kind of advices. – forrest Aug 2 '16 at 9:47
3

Following code shows how to define a new shape for your symbol adapting the original code from forbidden sign shape.

\documentclass[tikz,border=2mm]{standalone} 
\usetikzlibrary{positioning, arrows.meta}

\makeatletter
\pgfdeclareshape{newsign}
{
  \inheritsavedanchors[from=circle] % this is nearly a circle
  \inheritanchorborder[from=circle]
  \inheritanchor[from=circle]{north}
  \inheritanchor[from=circle]{north west}
  \inheritanchor[from=circle]{north east}
  \inheritanchor[from=circle]{center}
  \inheritanchor[from=circle]{west}
  \inheritanchor[from=circle]{east}
  \inheritanchor[from=circle]{mid}
  \inheritanchor[from=circle]{mid west}
  \inheritanchor[from=circle]{mid east}
  \inheritanchor[from=circle]{base}
  \inheritanchor[from=circle]{base west}
  \inheritanchor[from=circle]{base east}
  \inheritanchor[from=circle]{south}
  \inheritanchor[from=circle]{south west}
  \inheritanchor[from=circle]{south east}
  \inheritbackgroundpath[from=circle]
  \foregroundpath{
    \centerpoint%
    \pgf@xc=\pgf@x%
    \pgf@yc=\pgf@y%
    \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%
    \pgfpathmoveto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{-0.6\pgfutil@tempdima}{-0.6\pgfutil@tempdima}}}
    \pgfpathlineto{\pgfpointadd{\pgfqpoint{\pgf@xc}{\pgf@yc}}{\pgfqpoint{0.6\pgfutil@tempdima}{0.6\pgfutil@tempdima}}}
    \pgfsetarrowsstart{}
    \pgfsetarrowsend{Latex}
  }
\makeatother


}

\begin{document}
\begin{tikzpicture}
\node[draw, newsign] (A) {A};

\node[draw, newsign, minimum size=1cm, red, fill=green!30, ultra thick, label=x] at (2,0) (B) {};

\draw (A) -- (B);

\node[draw, newsign] at (0,1) {Text};
\end{tikzpicture}
\end{document}

enter image description here

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.