1

I went to draw my first circuit with circuitikz a few days ago—it's a fairly simple hierarchical logic gate—and I struggled more than I thought I would after looking at some samples. I had to wrestle with a lot of absolute positioning; some things were too wide; but most importantly, I was only either placing one node or drawing one wire. Every example I had seen had just a few semantic groups of draw commands, and mine were, well, clumpy.

Eventually I went from

\begin{circuitikz}
    \draw
    (0,4) node[left](A){$A$}
    (0,3) node[left](B){$B$}
    (0,2) node[left](C){$C$}
    (0,1) node[left](D){$D$}
    (0,0) node[left](E){$E$}
    (2,3.5) node[or port](AoB){}
    (A) -| (AoB.in 1)
    (B) -| (AoB.in 2)
    (2,1.5) node[or port](CoD){}
    (C) -| (CoD.in 1)
    (D) -| (CoD.in 2)
    (5,2.5) node[and port](t1){}
    (AoB.out) -| (t1.in 1)
    (CoD.out) -| (t1.in 2)
    (8, 1.25) node[or port](Y){} ++(1,0) node[right]{$Y$}
    (t1.out) -| (Y.in 1)
    (E) -| (Y.in 2);
\end{circuitikz}

to

\begin{circuitikz}
    \draw

    (0,4) node[left](A){$A$}
    ++(0,-1) node[left](B){$B$}
    ++(2,0.5) node[or port](AoB){}

    (A) -| (AoB.in 1)
    (B) -| (AoB.in 2)

    (0,2) node[left](C){$C$}
    ++(0,-1) node[left](D){$D$}
    ++(2,0.5) node[or port](CoD){}

    (C) -| (CoD.in 1)
    (D) -| (CoD.in 2)

    (5,2.5) node[and port](t1){}
    (AoB.out) -| (t1.in 1)
    (CoD.out) -| (t1.in 2)

    (0,0) node[left](E){$E$}

    (8, 1.25) node[or port](Y){} ++(1,0) node[right]{$Y$}
    (t1.out) -| (Y.in 1)
    (E) -| (Y.in 2);

\end{circuitikz}

but neither feels idiomatic or fluent.

 result of the second code

I do apologize if this is too subjective; it's hard for me to describe what I dislike about the code. It does work. I still feel like I'm missing something fundamental that would make it easier to see more structure in the code.

2
  • 1
    I added an image, I hope you don't mind. I find the code quite ok (especially, for my tastes, the second one which uses far less absolute coords). I would use IEEE ports and avoid "stairs" in the connections, by compacting the list of input labels so that they are at the same distance than input leads, but otherwise I think it's fine.
    – Rmano
    Aug 25 '20 at 6:39
  • @Rmano thanks! I couldn’t figure out how to get rid of the stairs unfortunately :( and it looks like I forgot to make then IEEE 😂 I was so caught up in getting the thing working I forgot to check the style! Aug 25 '20 at 11:39
1

This is a suggestion to obtain:

  • a compact drawing (maybe too much?)
  • the list of inputs at a constant vertical distance
  • an almost automatic positioning (you just have a magic number, the shift to position (A).

The trick is to use a 3-inputs OR for gates 1 and 2 so that when stacked they do not touch (maybe I should think a better way to achieve this? Another parameter for the ports? The problem is that it's complex to think about it for a generic number of inner/outer inputs).

\documentclass[border=10pt]{standalone}
\usepackage[siunitx, RPvoltages]{circuitikz}
\ctikzset{logic ports=ieee}
% we will use 3-inputs ports with just input 1 and 2. We suppress
% input leads to use them.
\tikzset{asymmetric/.style={no input leads, number inputs=3}}

\begin{document}
\begin{circuitikz}
    % first gate to "guide" everything.
    \draw (0,10) node[or port, asymmetric](OR1){};
    % inputs position
    \draw (OR1.bin 1) -- ++(-1,0) node[left](A){$A$};
    \draw (OR1.bin 3) -- (OR1.bin 3-|A.east) node[left](B){$B$};
    % use calc to put the input at the same vertical distance
    \foreach \inode [count=\iy from 2] in {C, D, E}
        \path ($(A.east)!\iy!(B.east)$) node [left](\inode){$\inode$};
    % position second or an connect it
    \draw (C.east) -- (C.east -| OR1.bin 1)
        node [or port, asymmetric, anchor=bin 1](OR2){};
    \draw (D.east) -- (OR2.bin 3);
    % position the and port (this is a normal 2-port)
    \node [and port, anchor=west](AND1) at ($(OR1.out)!0.5!(OR2.out)$) {};
    \draw (OR1.out) -- (AND1.in 1) (AND1.in 2) -- (OR2.out);
    % find the position for the last OR; first move (E) under AND1
    \coordinate (E1) at (E.east -| AND1.out);
    % position the or and connect
    \node [or port, anchor=west](OR3) at ($(AND1.out)!0.5!(E1)$) {};
    \draw (AND1.out) -- (OR3.in 1) (OR3.in 2) |- (E.east);
    % and output
    \node [right](Y) at (OR3.out) {Y};
\end{circuitikz}
\end{document}

enter image description here

Notice that a bad effect here is that using so many different \draw the path unions are far from perfect (using to [short, .-.] will make a better union; for example change

\draw (OR1.out) -- (AND1.in 1) (AND1.in 2) -- (OR2.out);

to

\draw (OR1.out) to[short, .-.] (AND1.in 1) 
      (AND1.in 2) to[short, .-.]  (OR2.out);
2
  • This is pretty over my head, but thanks! Much to learn. Aug 25 '20 at 16:02
  • If you have specific questions, fire! --- I'll try to help. ;-)
    – Rmano
    Aug 25 '20 at 17:38

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.