2

Tikz has a bunch of useful digital circuit components, basic or complex. Here, I need some of my own, not necessarily even one of the convenient ones. But let's take one, rather convenient example: A magnitude comparator.

I would like to have this magnitude comparator component for my task, with its signal ports defined as anchors. I can make a box with labels on ports and a name on it, but that is not enough!

I need to show what's on the inside, as well. Details shall not go beyond the gates, I don't want the transistors around, but I do need the gates.

Here's what I have on my hands so far, most of which is just copied/mimicked from this (famous?) data flip-flop example:

\makeatletter

% Magnitude Comparator (magn comparator) shape
\pgfdeclareshape{magn comparator}
{
    % The 'minimum width' and 'minimum height' keys, not the content, determine
    % the size
    \savedanchor\northeast
    {%
        \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
        \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
        \pgf@x=0.5\pgf@x
        \pgf@y=0.5\pgf@y
    }
    % This is redundant, but makes some things easier:
    \savedanchor\southwest
    {%
        \pgfmathsetlength\pgf@x{\pgfshapeminwidth}%
        \pgfmathsetlength\pgf@y{\pgfshapeminheight}%
        \pgf@x=-0.5\pgf@x
        \pgf@y=-0.5\pgf@y
    }
    % Inherit from rectangle
    \inheritanchorborder[from=rectangle]

    % Define same anchor a normal rectangle has
    \anchor{center}{\pgfpointorigin}
    \anchor{north}{\northeast \pgf@x=0pt}
    \anchor{east}{\northeast \pgf@y=0pt}
    \anchor{south}{\southwest \pgf@x=0pt}
    \anchor{west}{\southwest \pgf@y=0pt}
    \anchor{north east}{\northeast}
    \anchor{north west}{\northeast \pgf@x=-\pgf@x}
    \anchor{south west}{\southwest}
    \anchor{south east}{\southwest \pgf@x=-\pgf@x}
    \anchor{text}
    {
        \pgfpointorigin
        \advance\pgf@x by -.5\wd\pgfnodeparttextbox%
        \advance\pgf@y by -.5\ht\pgfnodeparttextbox%
        \advance\pgf@y by +.5\dp\pgfnodeparttextbox%
    }

    % Define anchors for input signal ports
    \anchor{input gt}
    {
        \pgf@process{\southwest}%
        \pgf@y=-.5\pgf@y%
    }
    \anchor{input eq}
    {
        \pgf@process{\southwest}%
        \pgf@y=0pt%
    }
    \anchor{input lt}
    {
        \pgf@process{\southwest}%
        \pgf@y=.5\pgf@y%
    }
    \anchor{input a}
    {
        \pgf@process{\northeast}%
        \pgf@x=-.3\pgf@x%
    }
    \anchor{input b}
    {
        \pgf@process{\northeast}%
        \pgf@x=.3\pgf@x%
    }

    % Define anchors for output signal ports
    \anchor{output gt}
    {
        \pgf@process{\northeast}%
        \pgf@y=.5\pgf@y%
    }
    \anchor{output eq}
    {
        \pgf@process{\northeast}%
        \pgf@y=0pt%
    }
    \anchor{output lt}
    {
        \pgf@process{\northeast}%
        \pgf@y=-.5\pgf@y%
    }

    % Draw the rectangle box and the port labels
    \backgroundpath
    {
        % Rectangle box
        \pgfpathrectanglecorners{\southwest}{\northeast}
        % \node [and gate] (kek) at (0, 0) {};
    }
}

% Define default style for this node
\tikzset
{
    every magn comparator node/.style =
    {
        draw,
        minimum width = 2cm,
        minimum height = 2cm,
        thick,
        inner sep = 1mm,
        outer sep = 0pt,
        cap = round
    }
}

\makeatother

This is in a separate file which I include in the preamble of my main LaTeX file.

There are no gates here, it just draws the box. I attempted to simply put down a random AND gate in the usual way I do outside this \pgfdeclareshape thing, which of course did not work. I commented that out, that attempt.

There should be a way for me to define further shapes on top of the existing shapes. What is it?

Edit: I am expecting to have something like this in my hands, which I should be able to place and ports of which I can easily reach as anchors, similar to how it is with an AND/OR/NOR/XOR/NAND gate:

enter image description here

Note that the inside of the box doesn't really function as a magnitude comparator, it's just a dummy example of what I expect.

  • Yes, a \node inside a \backgroundpath won't work in any way. Can you show us how your "magnitude comparator" should look like? For additionl (pseudo-)anchors on a rectangular box there are very easy ways to do this, e.g.: Making FFT Figure using LaTeX Tikz, Tikz surrounding box with automatically drawn border “ports”. There is also the possibility to do this with proper anchors and a well-defined shape if needed. – Qrrbrbirlbel May 03 '15 at 18:20
  • @Qrrbrbirlbel It would take me some time to design and place the insides of my box. I have made a dummy version of it which doesn't really function as a magnitude comparator, but that shouldn't really matter, for sure. – Utkan Gezer May 03 '15 at 19:02
  • In that case, I'd suggest a rectangular node with an path picture and/or a append after command (possibly modified, see [1]/[2]). The anchors are relative easy to place. Are the positions fixed or should they be varied? Also, do you have a lot of shapes with different anchors? Than it might be easier to use pseudo-anchors (see comment above). – Qrrbrbirlbel May 03 '15 at 19:29
  • There is also the not-so-great way of using a pic (see TikZ' manual). – Qrrbrbirlbel May 03 '15 at 19:35
  • @Qrrbrbirlbel I am having hard times to follow. It would actually be alright if the whole picture inside, was really just a picture, a vector-image. I need anchors on the whole thing, the faded inside is just for giving the idea about what's going on inside. I do need this component to be easily created, the way predefined gate components are, and also resized, too. – Utkan Gezer May 03 '15 at 19:41
  • 1
    It might be possible to use the gate shapes inside a \pgfnode inside a \(before)backgroundpath which will need various keys (height, width, etc) re-set to appropriate values. Again, this is all dependent on the variety of your needed shapes. (This will also need the connections to be drawn in PGF, mind you.) Related: Can a shape be composed out of “subshapes” in TikZ? – Qrrbrbirlbel May 03 '15 at 21:08

2 Answers2

5

Dependently on the complexity of your use-cases and how many of these shapes you need … here is a start.

The answer consists the following:

  • A shape declaration that borrows the rectangle ee definition from the circuits.ee (which is just a borrowed rectangle shape with .input and .output anchors).

    I also borrow from the linked TeXample for the text inside a shape’s definition. The anchors are set with \pgfpointlineattime (this is similar to the pos key along a straight line, or the factor inside calc’s ($(<p1>)!<factor>!(<p2>)$) notation).

    If you have a lot more of these shapes that need several different of these anchors along a rectangular’s border, this can be serialized with a fey keys and a loop inside the shape’s declaration. This also applies to the texts.

  • Now that we have a shape with anchors and texts we can use it. For a proper circuit shape we declare a symbol with circuit declare symbol and set it up with set <symbol name> graphic.

    The keys circuit symbol size sets minimum width and minimum height in relation to the circuit symbol unit (a TeX dimen under the hood). This make it scalable in relation to other circuit symbols. The transform shape key is needed to make it rotate along circuitsto paths.

  • A path picture that uses proposed code from another answer of mine. To set up a local coordinate system that rotates and scales with its node: The coordinate (0, 0) is at the node’s center. The x vector points to the east (= output), the y vector to the north anchor. This is important for coordinate specifications like (left:.2) as it uses .2 of half of the horizontal dimension of the node and the applied rotation.

    The circuit symbols inside the path picture get the options gray (as does the lines) and circuit symbol unit=.1cm which does scale down the symbols to an appropriate size. It might be needed to play around with this value to get the size right. It may also be possible to make this dependent on the aforementioned local coordinate system with the dimens \pgf@xx and \pgf@yy.

    Obviously, if you need multiple symbols with the same anchor and connection layout but with different gates it is possible to make the shapes definition malleable according to three value keys which would be set in this case to not gate, nand gate and nor gate.

I have used my paths.ortho library for the connections inside the path picture. You can obviously use any way to connect these lines.

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{circuits.ee,circuits.logic.US,paths.ortho}
\makeatletter
\pgfdeclareshape{my complicated box}{%
  \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}
  \inheritanchor[from=rectangle ee]{output}
  \inheritanchorborder[from=rectangle ee]
  \inheritbackgroundpath[from=rectangle ee]
  \anchor{eq in} {\pgf@sh@reanchor{\pgf@sm@shape@name}{input}}
  \anchor{eq out}{\pgf@sh@reanchor{\pgf@sm@shape@name}{output}}
  \anchor{lt in}{%
    \pgfpointlineattime{.2}{\southwest}
    {\southwest\pgf@xc\pgf@x\northeast\pgf@x\pgf@xc}}
  \anchor{gt in}{%
    \pgfpointlineattime{.8}{\southwest}
    {\southwest\pgf@xc\pgf@x\northeast\pgf@x\pgf@xc}}
  \anchor{gt out}{%
    \pgfpointlineattime{.3}{\northeast}
    {\southwest\pgf@yc\pgf@y\northeast\pgf@y\pgf@yc}}
  \anchor{lt out}{%
    \pgfpointlineattime{.7}{\northeast}
    {\southwest\pgf@yc\pgf@y\northeast\pgf@y\pgf@yc}}
  \anchor{a}{%
    \pgfpointlineattime{.4}
      {\southwest\pgf@xc\pgf@x\northeast\pgf@x\pgf@xc}{\northeast}}
  \anchor{b}{%
    \pgfpointlineattime{.6}
      {\southwest\pgf@xc\pgf@x\northeast\pgf@x\pgf@xc}{\northeast}}
  \beforebackgroundpath{%
    \begingroup
      \tikzset{my complicated box/labels/.try}\tikz@textfont
      \pgf@sh@reanchor{\pgf@sm@shape@name}{eq in}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},left,%
                x=\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{eq}_{\mathrm{in}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{eq out}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},right,%
                x=-\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{eq}_{\mathrm{out}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{gt in}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},left,%
                x=\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{gt}_{\mathrm{in}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{gt out}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},right,%
                x=-\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{gt}_{\mathrm{out}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{lt in}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},left,%
                x=\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{lt}_{\mathrm{in}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{lt out}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},right,%
                x=-\pgfkeysvalueof{/pgf/inner xsep}]{$\mathrm{lt}_{\mathrm{out}}$}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{a}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},top,%
                y=-\pgfkeysvalueof{/pgf/inner ysep}]{a\vphantom{b}}
      \pgf@sh@reanchor{\pgf@sm@shape@name}{b}
      \pgftext[at=\pgfqpoint{\pgf@x}{\pgf@y},top,%
                y=-\pgfkeysvalueof{/pgf/inner ysep}]{b}
    \endgroup}
}
\makeatother
\tikzset{my complicated box/labels/.style={font=\footnotesize, inner sep=.1667em}}
\tikzset{
  circuit declare symbol=my complicated symbol,
  set my complicated symbol graphic={
    draw, shape=my complicated box, circuit symbol size=width 10 height 8,
    transform shape,
    path picture={
      \expandafter\let\expandafter\tfn\csname tikz@fig@name\endcsname
      \pgftransformshift{\pgfpointanchor{\tfn}{center}}%
      \pgfsetxvec{\pgfpointdiff{\pgfpointanchor{\tfn}{center}}
                 {\pgfpointanchor{\tfn}{east}}}%
      \pgfsetyvec{\pgfpointdiff{\pgfpointanchor{\tfn}{center}}
                 {\pgfpointanchor{\tfn}{north}}}
      \tikzset{every circuit symbol/.append style={circuit symbol unit=.1cm, gray}}
      \path[thin, draw=gray]
        (\tfn.eq in) to[not gate=near end] (\tfn.eq out)
        (\tfn.lt out) to ++ (left:.2)
          node[anchor=output, logic gate inputs=nn, nand gate] (\tfn-nand) {}
        (\tfn-nand.input 2) to[-|-=.6] (\tfn.lt in)
        (\tfn-nand.input 1) to[-|] (\tfn.a)
        (\tfn.gt out) to ++ (left:.2)
          node[anchor=output, logic gate inputs=nn, nor gate] (\tfn-nor) {}
        (\tfn-nor.input 2) to[-|-=.6] (\tfn.gt in)
        (\tfn-nor.input 1) to[-|] (\tfn.b);
    }},
}
\begin{document}
\begin{tikzpicture}[circuit logic US]
\draw (0,0) to[my complicated symbol] ++ (30:4);
\end{tikzpicture}
\end{document}

Output

enter image description here

Qrrbrbirlbel
  • 119,821
  • Thanks for everything, but this is kind of too complicated for me, that I think maybe I should just draw a single white-box separately and use several black-boxes all around. I wish I had the time to take a grasp of it, but I'm afraid I don't. – Utkan Gezer May 04 '15 at 05:21
1

A possible solution with pics. It's difficult to use pic-anchors for positioning (Anchoring TiKZ pics) but they serve as reference points for drawing links between them.

\documentclass[tikz,border=2mm]{standalone}

\usetikzlibrary{positioning,circuits.logic.US, fit}

\tikzset{
    mycircuit/.pic={
        \begin{scope}[circuit logic US]
        \node[gray, thick, draw, nor gate] (-gt) at (2,0.75) {};
        \node[gray, thick, draw, not gate] (-eq) at (2,0) {};
        \node[gray, thick, draw, nand gate] (-lt) at (2,-0.75) {};

        \draw[gray] (-gt.output)--++(3mm,0) 
             coordinate[label={[black]left:$\mathrm{gt}_\mathrm{out}$}] (-gtout);

        \draw[gray] (-eq.output)--(-eq.output-|-gtout) 
             coordinate[label={[black]left:$\mathrm{eq}_\mathrm{out}$}] (-eqout);

        \draw[gray] (-lt.output)--(-lt.output-|-gtout) 
             coordinate[label={[black]left:$\mathrm{lt}_\mathrm{out}$}] (-eqout);

        \draw[gray] (-gt.input 1)-|++(-3mm,.5cm) 
             coordinate[label={[black]below:$\mathrm{b}$}] (-b);

        \draw[gray] (-lt.input 1)-|([xshift=-6mm]-b.center) 
             coordinate[label={[black]below:$\mathrm{a}$}] (-a);

        \draw[gray] (-eq.input)--++(-2cm,0) 
             coordinate[label={[black]right:$\mathrm{eq}_\mathrm{in}$}] (-eqin);

        \draw[gray] (-gt.input 2)--++(-1.2cm,0) |- ([yshift=1cm]-eqin.center)  
             coordinate[label={[black]right:$\mathrm{gt}_\mathrm{in}$}] (-gtin);

        \draw[gray] (-lt.input 2)--++(-1.2cm,0) |- ([yshift=-1cm]-eqin.center)  
             coordinate[label={[black]right:$\mathrm{lt}_\mathrm{in}$}] (-ltin);

        \node[draw, fit={(-ltin) (-b) ([yshift=-.5cm]-lt.input 2) (-gtout)}, 
              inner sep=0pt] (-box) {};
        \end{scope}
    }}

\begin{document}
\begin{tikzpicture}

\pic (a) at (0,0) {mycircuit};

\pic (b) at (5,1) {mycircuit};

\draw (a-gtout) -- (b-gtin);
\draw ([yshift=2cm]a-a) coordinate (aux)--(a-a);
\draw ([yshift=-5mm]aux)-|(b-a);
\end{tikzpicture}
\end{document}

enter image description here

Ignasi
  • 136,588