1

I have built a small CMOS Logic Inverter in Circuitikz

\begin{tikzpicture}[american voltages, european resistors]
    \draw (-0.5,4)
     node[pmos](notAp){}
     (notAp.D) to [short] ++(0,-1) node[nmos, anchor = D](notAn){}
     (notAp.G) to (notAn.G)
     ($(notAp.G)!0.5!(notAn.G)$) to [short,-o] ++(-1,0) node[anchor=east]{$A$}
     ($(notAp.D)!0.5!(notAn.D)$) to [short,-o] ++(1,0) node[anchor=west]{$O$};
 
\end{tikzpicture}

enter image description here

I now want to use this as a gate in more complex drawings, beein able to connect other CMOS Parts to A, O, G and D without having to copy and paste the whole code, define it as cmosinverter and use it like

    \begin{tikzpicture}[american voltages, european resistors]
     \draw (-0.5,4)
        node[cmosinverter](notA){}
        (notA.O) to [short] ++(0,-1) node[cmosinverter, anchor = A](notB){};
    \end{tikzpicture}

How can I define this as a custom shape and also access the anchors, to use it in a normal circuit drawing like other components?

6
  • i have some tutorials on creating componenets for circuitikz on my web site (elfsoft2000.com/projects/index.htm). but you probably shouldn't have to go so far. You can use a scope and treat the local bounding box as a node, more of less. Or use a pic or a savebox. – John Kormylo Feb 17 at 20:58
  • As far as I understand i would have to copy and paste the code everytime again just inside of scope tags, when i use it? And can i define custom anchors on those boxes? So I saw your tutorial under another post, but at first thought its not helping me in my situation. I will try to understand those better, thank you – chenino Feb 17 at 21:09
  • If you want multiple copies with anchors, you will need a shape. which means using basic level pgf commands. But \pgftext can be used with \includeimage or \usebox. – John Kormylo Feb 17 at 21:30
  • As far as i understand i would have to draw every shape myself, if i define it with pgf, but i just want the circuit i have built above copied and connected at other places – chenino Feb 17 at 21:33
  • You can create an image using standalone class, or put an entire tikzpicture into a savebox. The only problem is aligning the anchors with the appropriate points in the image. (oops, \includegraphics) – John Kormylo Feb 17 at 22:26
1

(Look down for the best answer, the third is the charm)

simple approach: no anchors.

The poor-man way would be to use a \newcommand, and start the drawing from the anchor you need. For example, I implemented this that starts from the input:

\documentclass[border=10pt]{standalone}
\usepackage[siunitx, RPvoltages]{circuitikz}
\newcommand{\invcmosA}[1]{%
    {
        coordinate(#1-in) to[short, o-] ++(1,0) coordinate(#1-cross in)
        -- ++(0,1) node[pmos, anchor=G](#1-notAp){}
        (#1-cross in) -- ++(0,-1) node[nmos, anchor=G](#1-notAn){}
        (#1-notAp.D) -- (#1-notAn.D)
        % mark the coordinates
        (#1-notAp.S) coordinate(#1-up)  (#1-notAn.S) coordinate(#1-down)
        coordinate[midway](#1-cross out)
        (#1-cross out) to[short, -o] ++(1,0) coordinate(#1-out)
    }
}

\begin{document}
\begin{circuitikz}
    \draw (0,0) \invcmosA{IA} (4,0) \invcmosA{IB} 
          (IB-up) node[vcc]{} (IB-down) node[vee]{};
    \node [left] at (IA-in) {A};
    \node [right] at (IA-out) {O};
\end{circuitikz}
\end{document}

enter image description here

Now you can do the same starting drawing from the output, or from the up thing, or...

let's use a kind-of anchors here

So the approach here is similar. Now I define the subcircuit with an optional argument, and I will use that optional argument to shift the circuit.

In a first run, I will find the distances between every coordinate I want to use as an anchor --- I used in, out, up, and down here and the starting point of my circuit. Then I will add them, sign-flipped, in a relative move command as shown in the \invcmosAnchor... commands. (In the code below I have left the code to find the distances in, you normally will remove it)

Now I can use that command to shift the subcircuit with the same effect as an anchor.

\documentclass[border=10pt]{standalone}
\usepackage[siunitx, RPvoltages]{circuitikz}
\newcommand{\invcmosWithA}[2]{%
    {
        % move everything to the anchor
        #2
        % normal plotting (everything MUST BE relative!)
        coordinate(#1-in)
        to[short, o-] ++(1,0) coordinate(#1-cross in)
        -- ++(0,1) node[pmos, anchor=G](#1-notAp){}
        (#1-cross in) -- ++(0,-1) node[nmos, anchor=G](#1-notAn){}
        (#1-notAp.D) -- (#1-notAn.D)
        % mark the coordinates
        (#1-notAp.S) coordinate(#1-up)  (#1-notAn.S) coordinate(#1-down)
        coordinate[midway](#1-cross out)
        (#1-cross out) to[short, -o] ++(1,0) coordinate(#1-out)
    }
}
\newcommand{\invcmosAnchorIn}{++(0,0)}
\newcommand{\invcmosAnchorOut}{++(-84.78894pt,0)}
\newcommand{\invcmosAnchorUp}{++(-56.3362pt,-50.36137pt)}
\newcommand{\invcmosAnchorDown}{++(56.3362pt,-50.36137pt)}
\begin{document}
\begin{circuitikz}
    % check the distances, then fill the anchor-commands
    \draw (0,5) \invcmosWithA{T}{};
    \draw (4,6) let \p1 = ($(T-out)-(T-in)$) in node[right]{out: \x1,\y1};
    \draw (4,5) let \p1 = ($(T-up)-(T-in)$) in node[right]{up: \x1,\y1};
    \draw (4,4) let \p1 = ($(T-down)-(T-in)$) in node[right]{down: \x1,\y1};

    \draw (0,0) \invcmosWithA{IA}{} -- 
        ++(2,0) \invcmosWithA{IB}{\invcmosAnchorUp}
        (IB-up)  node[vcc]{} (IB-down) node[vee]{};

    \node [above] at (IA-in) {A};
    \node [above] at (IA-out) {OA};
    \node [above] at (IB-in) {B};
    \node [above] at (IB-out) {OB};
\end{circuitikz}
\end{document}

enter image description here

Automatically set the "pseudo anchors"

This uses a trick to typeset the first time the subcircuit in a box, and define the anchors there. I have changed the name of the anchors so that they form legal TeX macro names.

You have to call the \invcmosSetAnchor macro before using the macros! If you call it after \begin{document}, you can peek at it to check what happens...

\documentclass[]{article}
\usepackage[siunitx, RPvoltages]{circuitikz}
\newbox{\scratchbox}
\newcommand{\invcmosSetAnchors}{
    \sbox{\scratchbox}{%
    \begin{circuitikz}
    \draw (0,0) \invcmosWithA{T}{};
    \foreach [count=\i] \anchor in {in, out, up, down, crossin, crossout, center}
    \draw (0,{2-\i/2}) let \p1 = ($(T-in)-(T-\anchor)$) in
        node[right]{\anchor: \x1,\y1 \expandafter\xdef\csname invcmosAnchor\anchor\endcsname{++(\x1,\y1)}};
    \end{circuitikz}
    }
}

\newcommand{\invcmosWithA}[2]{%
    {
        % move everything to the anchor
        #2
        coordinate(#1-in)
        to[short, o-] ++(1,0) coordinate(#1-crossin)
        -- ++(0,1) node[pmos, anchor=G](#1-notAp){}
        (#1-crossin) -- ++(0,-1) node[nmos, anchor=G](#1-notAn){}
        (#1-notAp.D) -- (#1-notAn.D)
        % mark the coordinates
        (#1-notAp.S) coordinate(#1-up)  (#1-notAn.S) coordinate(#1-down)
        coordinate[midway](#1-crossout)
        ($(#1-crossin)!0.5!(#1-crossout)$) coordinate(#1-center)
        (#1-crossout) to[short, -o] ++(1,0) coordinate(#1-out)
    }
}
\begin{document}

\invcmosSetAnchors
% this works only if you set \invcmosSetAnchors after the \begin{document}
%\usebox{\scratchbox}


\begin{circuitikz}
    \draw (0,0) \invcmosWithA{IA}{} -- 
        ++(2,0) \invcmosWithA{IB}{\invcmosAnchorup}
        (IB-up) node[vcc]{} (IB-down) node[vee]{};
    \node [above] at (IA-in) {A};
    \node [above] at (IA-out) {OA};
    \node [above] at (IB-in) {B};
    \node [above] at (IB-out) {OB};
    \draw [dashed] (IB-out) -- ++(2,0) \invcmosWithA{IC}{\invcmosAnchorcenter};
\end{circuitikz}
\end{document}

enter image description here

The sneak-peek at the '\invcmosSetAnchor` is this:

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.