7

I would like to use custom logic symbols with the TikZ circuit library. For example some symbols of the 7400 series. What would be the best approach to easily create different symbols, that cant be used with the circuit library?

Here an example of an 74hc238:

74hc238

someonr
  • 8,531

2 Answers2

5

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{circuits.ee.IEC}
\makeatletter
\let\pgfutil@Alph\@Alph % should be the proper definition for use outside of LaTeX
\let\pgfutil@alph\@alph % dito
\pgfmathdeclarefunction{Alph}{1}{%
  \begingroup\edef\pgfmathresult{\pgfutil@Alph{#1}}%
  \pgfmath@smuggleone\pgfmathresult\endgroup}
\pgfmathdeclarefunction{alph}{1}{%
  \begingroup\edef\pgfmathresult{\pgfutil@alph{#1}}%
  \pgfmath@smuggleone\pgfmathresult\endgroup}
\pgfdeclareshape{gLogic}{%
  \savedmacro\gLogicparameters{%
    \pgfmathtruncatemacro\eports{\pgfkeysvalueof{/pgf/gLogic east ports}}%
    \pgfmathtruncatemacro\wports{\pgfkeysvalueof{/pgf/gLogic west ports}}%
    \pgfmathtruncatemacro\nports{\pgfkeysvalueof{/pgf/gLogic north ports}}%
    \pgfmathtruncatemacro\sports{\pgfkeysvalueof{/pgf/gLogic south ports}}%
    \addtosavedmacro\eports \addtosavedmacro\wports
    \addtosavedmacro\nports \addtosavedmacro\sports
    \let\pgf@gLogic@i\relax
    \let\pgf@gLogic@n\relax
    \edef\efunction{\pgfkeysvalueof{/pgf/@gLogic east function/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}\pgfeov}
    \edef\wfunction{\pgfkeysvalueof{/pgf/@gLogic west function/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}\pgfeov}
    \edef\nfunction{\pgfkeysvalueof{/pgf/@gLogic north function/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}\pgfeov}
    \edef\sfunction{\pgfkeysvalueof{/pgf/@gLogic south function/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}\pgfeov}
    \addtosavedmacro\efunction \addtosavedmacro\wfunction
    \addtosavedmacro\nfunction \addtosavedmacro\sfunction
  }
  \saveddimen\pinlength{\pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/gLogic pin length}}}%
  \inheritsavedanchors[from=rectangle ee]
  \inheritanchor[from=rectangle ee]{center}
  \inheritanchor[from=rectangle ee]{north}
  \inheritanchor[from=rectangle ee]{south}
  \inheritanchor[from=rectangle ee]{east}
  \inheritanchor[from=rectangle ee]{west}
  \inheritanchor[from=rectangle ee]{north east}
  \inheritanchor[from=rectangle ee]{north west}
  \inheritanchor[from=rectangle ee]{south east}
  \inheritanchor[from=rectangle ee]{south west}
  \inheritanchor[from=rectangle ee]{input} % eh?
  \inheritanchor[from=rectangle ee]{output}% eh?
  \inheritanchorborder[from=rectangle ee]
  \inheritbackgroundpath[from=rectangle ee]
  \behindbackgroundpath{%
    \pgfmathsetlength\pgfutil@tempdima{\pgfkeysvalueof{/pgf/gLogic pin length}}%
    \pgfmathtruncatemacro\pgf@gLogic@t{\eports+\nports+\wports+\sports}%
    \pgfextract@process\southeast{\csname pgf@anchor@gLogic@south east\endcsname}%
    \pgfextract@process\northwest{\csname pgf@anchor@gLogic@north west\endcsname}%
    \c@pgf@counta\eports
    \let\pgf@gLogic@n\eports
    \pgfmathloop\ifnum\c@pgf@counta>0
      \let\pgf@gLogic@i\pgfmathcounter
      \pgfextract@process\pgf@temp{\pgfpointlineattime{\efunction}{\southeast}{\northeast}}%
      \pgfpathmoveto{\pgf@temp}%
      \pgfpathlineto{\pgfpointadd{\pgf@temp}{\pgfqpoint{\pgfutil@tempdima}{0pt}}}%
      \advance\c@pgf@counta-1
      \pgftext[bottom,left,at=\pgf@temp,y=2\pgflinewidth,x=2\pgflinewidth]{\pgfkeysvalueof{/pgf/@gLogic east label/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}{\pgf@gLogic@t}\pgfeov}
    \repeatpgfmathloop
    \pgf@gLogic@makeanchors{e}{\csname pgf@anchor@gLogic@south east\endcsname}{\csname northeast\endcsname}{\noexpand\pinlength}{0pt}%
    %
    \c@pgf@counta\nports
    \let\pgf@gLogic@n\nports
    \pgfmathloop\ifnum\c@pgf@counta>0
      \let\pgf@gLogic@i\pgfmathcounter
      \pgfextract@process\pgf@temp{\pgfpointlineattime{\nfunction}{\northeast}{\northwest}}%
      \pgfpathmoveto{\pgf@temp}%
      \pgfpathlineto{\pgfpointadd{\pgf@temp}{\pgfqpoint{0pt}{\pgfutil@tempdima}}}%
      \advance\c@pgf@counta-1
      \pgftext[right,bottom,at=\pgf@temp,x=-2\pgflinewidth,y=2\pgflinewidth]{\pgfkeysvalueof{/pgf/@gLogic north label/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}{\pgf@gLogic@t}\pgfeov}
    \repeatpgfmathloop
    \pgf@gLogic@makeanchors{n}{\csname northeast\endcsname}{\csname pgf@anchor@gLogic@north west\endcsname}{0pt}{\noexpand\pinlength}%
    %
    \c@pgf@counta\wports
    \let\pgf@gLogic@n\wports
    \pgfmathloop\ifnum\c@pgf@counta>0
      \let\pgf@gLogic@i\pgfmathcounter
      \pgfextract@process\pgf@temp{\pgfpointlineattime{\wfunction}{\northwest}{\southwest}}%
      \pgfpathmoveto{\pgf@temp}%
      \pgfpathlineto{\pgfpointadd{\pgf@temp}{\pgfqpoint{-\pgfutil@tempdima}{0pt}}}%
      \advance\c@pgf@counta-1
      \pgftext[bottom,right,at=\pgf@temp,y=2\pgflinewidth,x=-2\pgflinewidth]{\pgfkeysvalueof{/pgf/@gLogic west label/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}{\pgf@gLogic@t}\pgfeov}
    \repeatpgfmathloop
    \pgf@gLogic@makeanchors{w}{\csname pgf@anchor@gLogic@north west\endcsname}{\csname southwest\endcsname}{-\noexpand\pinlength}{0pt}%
    %
    \c@pgf@counta\sports
    \let\pgf@gLogic@n\sports
    \pgfmathloop\ifnum\c@pgf@counta>0
      \let\pgf@gLogic@i\pgfmathcounter
      \pgfextract@process\pgf@temp{\pgfpointlineattime{\sfunction}{\southwest}{\southeast}}%
      \pgfpathmoveto{\pgf@temp}%
      \pgfpathlineto{\pgfpointadd{\pgf@temp}{\pgfqpoint{0pt}{-\pgfutil@tempdima}}}%
      \advance\c@pgf@counta-1
      \pgftext[right,top,at=\pgf@temp,x=-2\pgflinewidth,y=-2\pgflinewidth]{\pgfkeysvalueof{/pgf/@gLogic south label/.@cmd}{\pgf@gLogic@i}{\pgf@gLogic@n}{\pgf@gLogic@t}\pgfeov}%
    \repeatpgfmathloop
    \pgf@gLogic@makeanchors{s}{\csname southwest\endcsname}{\csname pgf@anchor@gLogic@south east\endcsname}{0pt}{-\noexpand\pinlength}%
  }
}
\def\pgf@gLogic@makeanchors#1#2#3#4#5{%
  \c@pgf@counta\pgf@gLogic@n
  \let\pgf@gLogic@n\relax
  \pgfmathloop%
    \ifnum\c@pgf@counta>0\relax%
      \pgfutil@ifundefined{pgf@anchor@gLogic@#1Pin\space\the\c@pgf@counta}{%
        \expandafter\xdef\csname pgf@anchor@gLogic@#1Pin\space\the\c@pgf@counta\endcsname{%
          \noexpand\gLogicparameters
          \let\noexpand\pgf@gLogic@n\expandafter\noexpand\csname #1ports\endcsname
          \edef\noexpand\pgf@gLogic@i{\the\c@pgf@counta}%
          \noexpand\pgfpointadd{\noexpand\pgfpointlineattime
            {\expandafter\noexpand\csname #1function\endcsname}{\expandafter\noexpand#2}{\expandafter\noexpand#3}}{\noexpand\pgfqpoint{#4}{#5}}%
        }%
      }{\c@pgf@counta0\relax}% 
    \advance\c@pgf@counta-1\relax%
  \repeatpgfmathloop%  
}
\makeatother
\pgfset{
  gLogic east ports/.initial =2,
  gLogic west ports/.initial =2,
  gLogic north ports/.initial=2,
  gLogic south ports/.initial=2,
  gLogic ports/.style args={#1:#2:#3:#4}{
    /pgf/gLogic east ports ={#1},/pgf/gLogic west ports ={#3},
    /pgf/gLogic north ports={#2},/pgf/gLogic south ports={#4}},
  set gLogic east function/.style ={/pgf/@gLogic east function/.code 2 args={#1}},
  set gLogic west function/.style ={/pgf/@gLogic west function/.code 2 args={#1}},
  set gLogic north function/.style={/pgf/@gLogic north function/.code 2 args={#1}},
  set gLogic south function/.style={/pgf/@gLogic south function/.code 2 args={#1}},
  set gLogic east function ={(#1)/(#2+1)}, set gLogic west function ={(#1)/(#2+1)},
  set gLogic north function={(#1)/(#2+1)}, set gLogic south function={(#1)/(#2+1)},
  gLogic pin length/.initial=+2\tikzcircuitssizeunit,
  set gLogic west label/.style={/pgf/@gLogic west label/.code n args={3}{#1}},
  set gLogic east label/.style={/pgf/@gLogic east label/.code n args={3}{#1}},
  set gLogic north label/.style={/pgf/@gLogic north label/.code n args={3}{#1}},
  set gLogic south label/.style={/pgf/@gLogic south label/.code n args={3}{#1}},
  set gLogic east label ={\scriptsize\pgfmathprint{Alph(#1)}},%
  set gLogic north label={\scriptsize\pgfmathprint{Alph(\eports+#1)}},%
  set gLogic west label ={\scriptsize\pgfmathprint{Alph(\eports+\nports+#1)}},%
  set gLogic south label={\scriptsize\pgfmathprint{Alph(\eports+\nports+\wports+#1)}},%
}
\tikzset{
  circuit declare symbol=gLogic,
  set gLogic graphic={draw, shape=gLogic, circuit symbol size=width 6 height 15, outer sep=+.5\pgflinewidth}
}
\begin{document}
\begin{tikzpicture}
  \node[gLogic,
    gLogic ports=8:0:6:0,
    align=center,
    set gLogic west function={ifthenelse(#1<4,#1,(#1+2))/9},
    set gLogic east label={\scriptsize$Y_{\pgfmathprint{int(\eports-#1+1)}}$},
    set gLogic west label={\scriptsize\ifnum#1<4\pgfmathprint{Alph(#1)}\else$E_{\pgfmathprint{int(#1-3)}}$\fi}] (n) {R2D2-\\Decoder};
  \draw (n.ePin 1) to[bend right] (n.ePin 8);
  \draw (n.wPin 1) to [bend right] (n.wPin 3);

  \node[gLogic, circuit symbol size=width 4 height 8] (m) at (4,0) {};
  \draw (m.ePin 1) to [bend right] (m.ePin 2);
  \draw (m.wPin 1) to [bend right] (m.wPin 2);

  \draw[line cap=rect] (n.ePin 2) --++ (right:.5cm) |- (m.sPin 1);
\end{tikzpicture}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • Thx! Looks like you are a Wizard ;) I really like the syntax. Any more elegant syntax for pin labels in mind? – someonr Nov 26 '13 at 23:44
  • 1
    @someonr See my update. Since I believe that the labels are from a regular nature like in your example I used this approach. The label codes get three arguments, the current pin number, the pin numbers of the current side and the total number of the pins. But as you can see from the initial definition, you can access \eports, \nports, etc from within the label, too. I’ve started my definitions from the east side because everything TikZ does it the same way and then goes counter-clockwise. You will need access to those port numbers for your (serious) IC because that starts at the south. – Qrrbrbirlbel Nov 26 '13 at 23:57
  • this is really awesome and helps me a lot! I really need some TeX/LaTeX/TikZ trainin ;) Would have taken me a lot more time to get something close to this solution. – someonr Nov 27 '13 at 00:01
  • I might have found a bug: This code breaks: \draw (0,0) to[gLogic={set gLogic east label = {#1}}] (0,5); (

    \node[gLogic={set gLogic east label = {#1}}] at (4,0) {}; is ok)

    – someonr Nov 30 '13 at 03:47
2

I just started creating a custom shape. Here the not too bad looking result:

result

Actually I only had little time and little TeX experience. I'll post it anyway, but be warned: There are dragons! Only brave souls may continue. Any tips and help is appreciated ;)

\documentclass{article}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{circuits.ee.IEC}

\usetikzlibrary{positioning}


\makeatletter

%TODO allow easier usage, like:
%\node[glogic={parameter=name,...}] {};
%TODO better input?

%TODO remove max values
\def\maxVPins{20}
\def\maxHPins{20}

\newcounter{pinCounter}
\def\getPinNumber#1{\csname #1Pin\Roman{pinCounter}\endcsname}

\tikzset{%
    gLogic/pin spacing/.initial=3mm,
    gLogic/contact length/.initial=10pt,
    gLogic/horizontal pins/.initial=2,
    gLogic/vertical pins/.initial=2,
    gLogic/pin labels/.initial={},
    gLogic/bottom text/.initial=\empty,
}


\pgfdeclareshape{gLogic}{
    \savedanchor{\upperrightcorner}{
        \pgf@y=.5\ht\pgfnodeparttextbox %
        \pgf@x=.5\wd\pgfnodeparttextbox %
    }

    \anchor{text}{%
        \upperrightcorner%
        \pgf@x=-\pgf@x%
        \pgf@y=-\pgf@y%
    }

    \anchor{center}{\pgfpointorigin}

    \def\pinspacing{\noexpand\pgfkeysvalueof{/tikz/gLogic/pin spacing}}
    \def\myWidth{\pinspacing*\noexpand\pgfkeysvalueof{/tikz/gLogic/horizontal pins}}
    \def\myHight{\pinspacing*\noexpand\pgfkeysvalueof{/tikz/gLogic/vertical pins}}

    %create some anchors to make the positioning library happy ;)
    \edef\defineAnchors{%
        \noexpand\deferredanchor{south west}{\noexpand\pgfpoint{-\myHight/2}{-\myWidth/2}}%
        \noexpand\anchor{south}{\noexpand\pgfpoint{0pt}{-\myWidth/2}}%
        \noexpand\anchor{south east}{\noexpand\pgfpoint{\myHight/2}{-\myWidth/2}}%
        \noexpand\anchor{east}{\noexpand\pgfpoint{\myHight/2}{0pt}}%
        \noexpand\anchor{north east}{\noexpand\pgfpoint{\myHight/2}{\myWidth/2}}%
        \noexpand\anchor{north}{\noexpand\pgfpoint{0pt}{\myWidth/2}}%
        \noexpand\anchor{north west}{\noexpand\pgfpoint{-\myHight/2}{\myWidth/2}}%
        \noexpand\anchor{west}{\noexpand\pgfpoint{-\myHight/2}{0pt}}}
    \defineAnchors

    %TODO make this prettier...
    \def\createAnchorsB{%
        \noexpand\savedanchor\getPinNumber{b}{\noexpand\pgfpoint{\pinspacing * (\n-.5)-\myWidth/2}{-\myHight/2}}%
        \noexpand\anchor{pinB\n}{\getPinNumber{b}}%
    }

    \def\createAnchorsT{%
        \noexpand\savedanchor\getPinNumber{t}{\noexpand\pgfpoint{-\pinspacing * (\n-.5)+\myWidth/2}{\myHight/2}}%
        \noexpand\anchor{pinT\n}{\getPinNumber{t}}%
    }

    \def\createAnchorsL{%
        \noexpand\savedanchor\getPinNumber{l}{\noexpand\pgfpoint{-\myWidth/2}{-\pinspacing * (\n-.5)+\myHight/2}}%
        \noexpand\anchor{pinL\n}{\getPinNumber{l}}%
    }

    \def\createAnchorsR{%
        \noexpand\savedanchor\getPinNumber{r}{\noexpand\pgfpoint{\myWidth/2}{\pinspacing * (\n-.5)-\myHight/2}}%
        \noexpand\anchor{pinR\n}{\getPinNumber{r}}%
    }

    %TODO remove max values and use the real values (some expansion problem)
    \foreach \n  in {1,...,\maxVPins} {
        \pgfmathsetcounter{pinCounter}{\n}
        \edef\expandThis{%
            \createAnchorsL
            \createAnchorsR
        }
        \expandThis
    }
    \foreach \n  in {1,...,\maxHPins} {
        \pgfmathsetcounter{pinCounter}{\n}
        \edef\expandThis{%
            \createAnchorsB%
            \createAnchorsT
        }
        \expandThis
    }


    \foregroundpath{
        \edef\myLabels{\pgfkeysvalueof{/tikz/gLogic/pin labels}}

        %TODO look for a cleaner solution
        \foreach \x [count=\n] in \myLabels {
            \ifx \x\empty\else%don't draw connectors without label
            \ifnumcomp{\n}{<}{\pgfkeysvalueof{/tikz/gLogic/horizontal pins}+1}{
                %bootom row
                \pgfmathsetcounter{pinCounter}{\n}
                \pgfpathmoveto{\getPinNumber{b}}
                \pgftext[top, right,at= \pgfpointadd{\pgfpoint{-1pt}{-1pt}}{\getPinNumber{b}}]{\scriptsize \x}
                \pgfpathlineto{\pgfpointadd{\getPinNumber{b}}{\pgfpoint{0}{-\pgfkeysvalueof{/tikz/gLogic/contact length}}}}
            }{\ifnumcomp{\n}{<}{\pgfkeysvalueof{/tikz/gLogic/horizontal pins}+\pgfkeysvalueof{/tikz/gLogic/vertical pins}+1}{
                %right column
                \pgfmathparse{\n-\pgfkeysvalueof{/tikz/gLogic/horizontal pins}};
                \pgfmathsetcounter{pinCounter}{\pgfmathresult}
                \pgftext[base, left,at= \pgfpointadd{\pgfpoint{2pt}{1pt}}{\getPinNumber{r}}]{\scriptsize \x}
                \pgfpathmoveto{\getPinNumber{r}}
                \pgfpathlineto{\pgfpointadd{\getPinNumber{r}}{\pgfpoint{\pgfkeysvalueof{/tikz/gLogic/contact length}}{0}}}
            }{\ifnumcomp{\n}{<}{2*\pgfkeysvalueof{/tikz/gLogic/horizontal pins}+\pgfkeysvalueof{/tikz/gLogic/vertical pins}+1}{
                %top row
                \pgfmathparse{\n-\pgfkeysvalueof{/tikz/gLogic/horizontal pins}-\pgfkeysvalueof{/tikz/gLogic/vertical pins}};
                \pgfmathsetcounter{pinCounter}{\pgfmathresult}
                \pgftext[bottom, right, at=\pgfpointadd{\pgfpoint{-1pt}{1pt}}{\getPinNumber{t}}]{\scriptsize \x}
                \pgfpathmoveto{\getPinNumber{t}}
                \pgfpathlineto{\pgfpointadd{\getPinNumber{t}}{\pgfpoint{0}{\pgfkeysvalueof{/tikz/gLogic/contact length}}}}
            }{\ifnumcomp{\n}{<}{2*\pgfkeysvalueof{/tikz/gLogic/horizontal pins}+2*\pgfkeysvalueof{/tikz/gLogic/vertical pins}+1}{
                %left column
                \pgfmathparse{\n-2*\pgfkeysvalueof{/tikz/gLogic/horizontal pins}-\pgfkeysvalueof{/tikz/gLogic/vertical pins}};
                \pgfmathsetcounter{pinCounter}{\pgfmathresult}
                \pgftext[base, right, at=\pgfpointadd{\pgfpoint{-2pt}{1pt}}{\getPinNumber{l}}]{\scriptsize \x}
                \pgfpathmoveto{\getPinNumber{l}}
                \pgfpathlineto{\pgfpointadd{\getPinNumber{l}}{\pgfpoint{-\pgfkeysvalueof{/tikz/gLogic/contact length}}{0}}}
            }{}}}}\fi%closing all the ifs ;-/
        }

        %TODO don't define them twice with different expanding behaviours?
        \def\myWidth{\pgfkeysvalueof{/tikz/gLogic/horizontal pins}%
            *\pgfkeysvalueof{/tikz/gLogic/pin spacing}}
        \def\myHight{\pgfkeysvalueof{/tikz/gLogic/vertical pins}%
            *\pgfkeysvalueof{/tikz/gLogic/pin spacing}}

        \pgftext[bottom, at=\pgfpoint{-0pt}{-\myHight/2+2pt}]{\footnotesize \pgfkeysvalueof{/tikz/gLogic/bottom text}}

        % rectangle around the logic gate
        \pgfpathrectanglecorners{\pgfpoint{-\myWidth/2}{-\myHight/2}}%
            {\pgfpoint{\myWidth/2}{\myHight/2}}

        \pgfusepath{draw}% draw all the lines :D
    }
}

\makeatother

\begin{document}

\def\labels{A,B,C,D,E, F, G, H, I, J,K, L, M, N,O, P, Q, R, S, T}

\begin{tikzpicture}[circuit ee IEC]
    \node[gLogic, gLogic/pin spacing=7mm, gLogic/horizontal pins=3, gLogic/pin labels={A,B,~,D,,F}] (IC1) {funny IC};

    \node[gLogic, gLogic/pin spacing=5mm, gLogic/horizontal pins=4, gLogic/vertical pins=6, gLogic/pin labels=\labels, gLogic/bottom text=IC-42-42, above right=3 of IC1] (IC2) {IC};


    \draw (IC1.pinR1)  to [diode={light emitting, name=LED}] ($(IC1.pinR1)+(2,0)$) -| (IC2.pinB4);
\end{tikzpicture}


\end{document}
someonr
  • 8,531
  • looks like my south etc anchors are broken :-/ – someonr Nov 26 '13 at 02:09
  • You need to be aware that the anchors defined by \anchor are only executed when they are accessed, not when the node is created. The values of keys and of the \pgfnodeparttextbox have possibly changed by then. The calculations will be off then. – Qrrbrbirlbel Nov 26 '13 at 21:13
  • @Qrrbrbirlbel I fixed the text anchor witht he help from the tikz manual. What I don't understand ist: Why are the south, north etc anchors wrong? I hoped to use \noexpand so that they wouldn't be expanded on node creation and can reflect the real size. I'll later take a look at your link. – someonr Nov 26 '13 at 23:00
  • Must be still wroong (or wronger) now I get a blank image with `\includestandalone``:(( – someonr Nov 26 '13 at 23:12
  • Well, the problem is still the same (I assume, I haven’t checked your code). If the .south anchor depends on the number of pins, and you change that number (stored in a key) the accessed value is still another. Example? Initial setting: pins=10. Node 1: pins=2. Node 2: pins=4. When drawing: pins=10. You need the save the number of pins (and whatever you can customize for every node separately) to be saved along the node. The macros \savedmacro and \addtosavedmacro will help here. – Qrrbrbirlbel Nov 26 '13 at 23:19
  • @Qrrbrbirlbel thx for the example. I was assuming each node would have some sort of own instance of keys (not sure why). – someonr Nov 26 '13 at 23:43