10

I'm working on a block diagram using TikZ. I'd like to create a symbol like below, which means I have to draw 5 lines inside a node and write a letter in the upper-right corner.

enter image description here

What's the best way to achieve what I need? Any hints appreciated.

mmm
  • 975
  • How often do you need this symbol. Is it a one-off or will you use it a lot? If a lot, will it always be the same or do you want to be able to scale it? – Andrew Stacey Aug 01 '12 at 14:11
  • I'm going to reuse this symbol about 3 times in a document. I'd like to be scalable. But would generally appreciate any hints regarding libraries or techniques to add simple drawings inside nodes, as it's possible I'm going to face this problem more times in the future. – mmm Aug 01 '12 at 14:40

2 Answers2

11

Complementing Claudio's answer: You can also inherit the properties of a rectangle node shape and further add some drawings on top of it and use it as a genuine node shape.

\documentclass{standalone}
\usepackage{tikz}

\makeatletter

\pgfdeclareshape{satnode}{
\inheritsavedanchors[from={rectangle}]
\inheritbackgroundpath[from={rectangle}]
\inheritanchorborder[from={rectangle}]
\foreach \x in {center,north east,north west,north,south,south east,south west}{
\inheritanchor[from={rectangle}]{\x}
}
\foregroundpath{
\pgfpointdiff{\northeast}{\southwest}
\pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast
\pgfpathmoveto{\pgfpoint{0}{0.45\pgf@ya}}
\pgfpathlineto{\pgfpoint{0}{-0.45\pgf@ya}}
\pgfpathmoveto{\pgfpoint{0.45\pgf@xa}{0}}
\pgfpathlineto{\pgfpoint{-0.45\pgf@xa}{0}}
\pgfpathmoveto{\pgfpointadd{\southwest}{\pgfpoint{-0.2\pgf@xa}{-0.3\pgf@ya}}}
\pgfpathlineto{\pgfpointadd{\southwest}{\pgfpoint{-0.5\pgf@xa}{-0.3\pgf@ya}}}
\pgfpathlineto{\pgfpointadd{\northeast}{\pgfpoint{-0.5\pgf@xa}{-0.3\pgf@ya}}}
\pgfpathlineto{\pgfpointadd{\northeast}{\pgfpoint{-0.4\pgf@xa}{-0.3\pgf@ya}}}
{
   \pgftransformshift{\pgfpointadd{\northeast}{\pgfpoint{-0.4\pgf@xa}{-0.3\pgf@ya}}}
   \pgftransformscale{0.5}
   \pgfsetcolor{black}
   \pgftext[left]{$M$}
}
\pgfusepath{stroke}
}
}
\makeatother

\begin{document}
\begin{tikzpicture}

\node[satnode,minimum size=1cm,fill=blue,draw] (a) {};
\node[satnode,draw,fill=red,minimum height=2cm,minimum width=1 cm] (a2) at (-2,0) {};
\node[satnode,thick,draw,minimum height=1cm,minimum width=1.5 cm,fill=yellow] (a1) at (2,0) {};
\draw[-latex] (a2) -- (a) -- (a1);
\end{tikzpicture} 
\end{document}

enter image description here

percusse
  • 157,807
8

Here is a possible implementation (based on Automat within Record). Is this what you had in mind?

\documentclass{article}
\usepackage{xparse}
\usepackage{tikz}
\usetikzlibrary{calc,positioning}

\newcounter{image}
\setcounter{image}{0}

\pgfmathtruncatemacro{\recordwidth}{2}
\pgfmathtruncatemacro{\recordheight}{1}

\newcommand{\setrecordwidth}[1]{\pgfmathtruncatemacro{\recordwidth}{#1}}
\newcommand{\setrecordheight}[1]{\pgfmathtruncatemacro{\recordheight}{#1}}

\newcommand{\mylabel}{M}
\newcommand{\setlabel}[1]{\renewcommand{\mylabel}{#1}}
\newcommand{\labelfont}{\scriptsize}
\newcommand{\setlabelfont}[1]{\renewcommand{\labelfont}{#1}}

\tikzset{drawinside/.code args={#1}{%
            \draw($(#1.west)!0.3!(#1.center)$)--($(#1.east)!0.3!(#1.center)$);
            \draw($(#1.south)!0.3!(#1.center)$)--($(#1.north)!0.3!(#1.center)$);
            \draw($(#1.south west)!0.4!(#1.west)!0.3!(#1.center)$)--($(#1.south west)!0.165!(#1.west)!0.5!(#1.center)$)--(#1.center);
            \draw(#1.center)--($(#1.north east)!0.165!(#1.east)!0.65!(#1.center)$)--($(#1.north east)!0.45!(#1.east)!0.45!(#1.center)$) node[right,font=\labelfont]{$\mylabel$};            
       }
}

\tikzset{record/.style args={#1 and #2}{
        rectangle,draw,minimum width=#1, minimum height=#2
    }
}

\NewDocumentCommand{\drawrecord}{d()}{
\stepcounter{image}
\IfNoValueTF{#1}{%true
\node[record=\recordwidth cm and \recordheight cm,name=a\theimage]{};
}
{%false
\node[record=\recordwidth cm and \recordheight cm,name=a\theimage]at(#1){};
}
\node[drawinside={a\theimage}]{};
}

\begin{document}
\tikz{\drawrecord}
\tikz{\drawrecord}

\vspace*{2cm}
\begin{tikzpicture}
\drawrecord(0,0)
\setlabel{X}
\setlabelfont{\normalfont}
\setrecordwidth{6}
\setrecordheight{3}
\drawrecord(6,0) % that's the 4° picture, so it can be accessed by (a4)
\draw[-stealth]($(a4.west)+(-1,0)$)--(a4.west);
\draw[-stealth](a4.east)--($(a4.east)+(1,0)$);
\end{tikzpicture}
\end{document}

enter image description here

It allows you to customize the dimensions of the block and the labels. Moreover, as did for the last block, you can connect this with the rest of the picture by means of (anumber of the picture).

  • Wow. This achieves much more than just what I wanted - thank you. I feel I'll draw many hints from this example. – mmm Aug 01 '12 at 14:44
  • Glad of having help you :). – Claudio Fiandrino Aug 01 '12 at 14:52
  • I have a follow-up question about this, as the proposed solution is way too flexible/powerful for what I need (also, I would like to avoid xparse) Could you help me here or should I open a new question? – Federico Feb 18 '14 at 12:04
  • @Federico: without xparse it is a bit more tricky to perform the check on the presence of the argument, but it is also doable. I will try to provide a solution later on. – Claudio Fiandrino Feb 18 '14 at 12:51
  • That´s the thing: I do not need the check: I have a fixed size block (1x1 cm), the block is always placed w.r.t. a previously placed node and no label (the "M" in this case). I tried to remove that part, but I get errors I do not know how to solve. – Federico Feb 18 '14 at 12:56
  • @Federico: in that case, it is easier; I think \newcommand{\drawrecord}[1]{\stepcounter{image}}\node[record=\recordwidth cm and \recordheight cm,name=a\theimage]at(#1){};\node[drawinside={a\theimage}]{};} should work. Then you have to use always \drawrecord{0,0}, not \drawrecord(0,0). To remove the label, delete node[right,font=\labelfont]{$\mylabel$} from the drawinside code. – Claudio Fiandrino Feb 18 '14 at 13:02
  • nope :/ I get a Cannot parse this coordinate error at the line where \drawrecord{0,0} is. all the rest is exactly as you wrote. Also tried with \tikzstyle{record} = [draw, rectangle, draw=black, minimum width=1cm, minimum height=1cm] and \node [record, name=a\theimage], but same result. – Federico Feb 18 '14 at 13:11
  • http://tex.stackexchange.com/questions/161075/saturation-block – Federico Feb 18 '14 at 13:54
  • @Federico: wait: in the code of the question, you have a group (open and closed bracket) after stepcounter and before the \node[drawinside={a\theimage}]{};; at that point, there is no node a\theimage thus the parser can not recognize the coordinate. – Claudio Fiandrino Feb 18 '14 at 14:16
  • I am not sure I understand your last comment. If you wish you can give me a full answer to the question I have opened, so that I may also accept it. – Federico Feb 18 '14 at 14:18