3

I'm trying to modify the CircuiTikZ manual's tutorial example (section 2.3) to apply the idea from section 4.24.4, i.e. using a modified dipchip for an opaque black-box block.

\ctikzset{
 logic ports=ieee,
 logic ports/scale=0.7,
 multipoles/dipchip/width=2
 }

\tikzset{block/.style= { dipchip , no topmark , hide numbers , external pins width=0.2 } }

\newcommand{\myblock}[1]{% Add #1- to the node and coord names nodeblock, num pins=6{SR-FF} (#1-FF.pin 1) -- ++(-1,0) nodeand port, anchor=out{} (#1-FF.pin 3) -- (#1-FF.pin 3 -| #1-AND1.out) nodeand port, anchor=out{} (#1-AND1.in 1) to[short, -] ++(-1,0) coordinate(#1-in) to (#1-in |- #1-AND2.in 2) -- (#1-AND2.in 2); }

\begin{circuitikz}[] \draw (0,0) \myblock{A}; \draw (0,-4) \myblock{B};

\draw (A-in) -- ++(-0.5, 0) node[below]{$a_0$}; \draw (B-in) -- ++(-0.5, 0) node[below]{$a_1$}; \draw (A-AND1.in 2) to[short, -*] (A-AND2.in 1) to[short, -*] (B-AND1.in 2) to[short, -*] (B-AND2.in 1) -- ++(0, -2) coordinate(down) node[below]{ENABLE}; \draw (A-FF.pin 2) to[short, -*] (B-FF.pin 2) -- (B-FF.pin 2 |- down) node[below]{CP}; \end{circuitikz}

This works as one would expect, resulting in the following picture:

enter image description here

The problem starts when I want to get rid of the external pin "whiskers" on unconnected pins. If I set external pins width to 0, they go away, but then then CP connection becomes ugly:

enter image description here

What I want to avoid is having to manually draw the external pins for connected pins, and having to offset coordinates by (-0.2,0) or (0.2,0) depending on the side, manually. Basically, I'd like to keep the automatic pins, and the automatic coordinates computed from them, but only for connected pins. For unconnected pins (such as pins 4, 5 and 6 in this example), I'd like to have no external pins at all.

How do I do that?

Cactus
  • 1,107
  • You might consider creating a new component, or simply using a rectangular node instead of a dip chip (which this aint). – John Kormylo Jun 05 '21 at 16:52
  • ...why don't you use a flipflop instead of a dipchip here? – Rmano Jun 05 '21 at 18:15
  • @Rmano because the eventual schematics I will need to draw will use blackbox blocks instead of flipflops or proper DIPs. So I started modifying the tutorial to get a hang of that. – Cactus Jun 06 '21 at 04:14

2 Answers2

4

The following copies the code of dipchip and alters it to be able to pick specific pins only. The new shape is named xdipchip and uses all the parameters of dipchip (so looks just like that), but adds at two spots some checks for a specific list of pins (those code points are marked with %% CHANGES HERE).

The pins used can be controlled with the key xdip pins which takes as its value a comma separated list of pins which should be used. All anchors will be set at the correct spot, meaning the pin \x anchor will be placed at the tip of the pin for \x in the list of shown pins, else at the same spot as bpin \x.

\documentclass[border=3.14]{standalone}

\usepackage{circuitikz}

\makeatletter \ExplSyntaxOn \clist_new:N \l__xdipchip_pins_clist \cs_new_protected:Npn \xdipchip@if@pin #1 {\clist_if_in:NoTF \l__xdipchip_pins_clist { \the \numexpr #1 }} \pgfkeys{/tikz/xdip~ pins/.code=\clist_set:Nn \l__xdipchip_pins_clist {#1}} \ExplSyntaxOff

%% code copied (and then altered) from pgfcircmultipoles.tex \pgfdeclareshape{xdipchip}{ \savedmacro{\ctikzclass}{\edef\ctikzclass{chips}} \saveddimen{\scaledRlen}{\pgfmathsetlength{\pgf@x}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}} \savedmacro\numpins{% \pgf@circ@count@a=\ctikzvalof{multipoles/dipchip/num pins}% \def\numpins{\the\pgf@circ@count@a} } \savedanchor\centerpoint{% \pgf@x=-.5\wd\pgfnodeparttextbox% \pgf@y=-.5\ht\pgfnodeparttextbox% \advance\pgf@y by+.5\dp\pgfnodeparttextbox% }% \savedanchor\origin{\pgfpoint{0pt}{0pt}} \anchor{center}{\origin} \anchor{text}{\centerpoint}% to adjust text \saveddimen\height{% \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen} \pgfmathsetlength\pgf@x{((\numpins) \ctikzvalof{multipoles/dipchip/pin spacing})\pgf@circ@scaled@Rlen/2}% }% \saveddimen{\chipspacing}{ \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen} \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen\ctikzvalof{multipoles/dipchip/pin spacing}}} \saveddimen{\width}{ \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen} \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen\ctikzvalof{multipoles/dipchip/width}}} \saveddimen{\extshift}{ \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen} \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen\ctikzvalof{multipoles/external pins width}}} % standard anchors \savedanchor\northwest{% \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen} \pgfmathsetlength\pgf@y{0.5((\numpins) \ctikzvalof{multipoles/dipchip/pin spacing})\pgf@circ@scaled@Rlen/2}% \pgfmathsetlength\pgf@x{-0.5\pgf@circ@scaled@Rlen\ctikzvalof{multipoles/dipchip/width}} } \anchor{dot}{\northwest \pgfmathsetlength\pgf@x{\pgf@x + 0.3\chipspacing} \pgfmathsetlength\pgf@y{\pgf@y - 0.3\chipspacing} } \anchor{nw}{\northwest} \anchor{ne}{\northwest\pgf@x=-\pgf@x} \anchor{se}{\northwest\pgf@x=-\pgf@x\pgf@y=-\pgf@y} \anchor{sw}{\northwest\pgf@y=-\pgf@y} \anchor{north west}{\northwest} \anchor{north east}{\northwest\pgf@x=-\pgf@x} \anchor{south east}{\northwest\pgf@x=-\pgf@x \pgf@y=-\pgf@y} \anchor{south west}{\northwest\pgf@y=-\pgf@y} \anchor{n}{\northwest\pgf@x=0pt } \anchor{e}{\northwest\pgf@x=-\pgf@x\pgf@y=0pt } \anchor{s}{\northwest\pgf@x=0pt\pgf@y=-\pgf@y} \anchor{w}{\northwest\pgf@y=0pt } \anchor{north}{\northwest\pgf@x=0pt } \anchor{east}{\northwest\pgf@x=-\pgf@x\pgf@y=0pt } \anchor{south}{\northwest\pgf@x=0pt\pgf@y=-\pgf@y} \anchor{west}{\northwest\pgf@y=0pt } % start drawing \backgroundpath{% \northwest \pgf@circ@res@up = \pgf@y \pgf@circ@res@down = -\pgf@y \pgf@circ@res@right = -\pgf@x \pgf@circ@res@left = \pgf@x \pgf@circ@scaled@Rlen=\scaledRlen \pgf@circ@res@step = \ctikzvalof{multipoles/dipchip/pin spacing}\pgf@circ@scaled@Rlen \pgf@circ@res@other = \ctikzvalof{multipoles/external pins width}\pgf@circ@scaled@Rlen \pgfscope% (for the line width) \pgf@circ@setlinewidth{multipoles}{\pgflinewidth} \pgfpathrectanglecorners{\pgfpoint{-\width/2}{-\height/2}}{\pgfpoint{\width/2}{\height/2}}% \pgf@circ@draworfill %% upside mark \ifpgf@circuit@chip@topmark \pgfpathmoveto{\pgfpoint{0.2\pgf@circ@res@left}{\pgf@circ@res@up}} \pgfpatharc{0}{180}{0.2\pgf@circ@res@left} \fi \pgfusepath{stroke}% \pgfsetcolor{\ctikzvalof{color}} % Adding the pin number \ifpgf@circuit@chip@shownumbers \pgf@circ@count@a=\numpins\relax \divide\pgf@circ@count@a by 2 \pgf@circ@count@b=\pgf@circ@count@a % thanks to @marmot: https://tex.stackexchange.com/a/473571/38080 \ifpgf@circuit@chip@straightnumbers \pgfgettransformentries\a\b\temp\temp\temp\temp \pgfmathsetmacro{\rot}{-atan2(\b,\a)} \pgfmathtruncatemacro{\quadrant}{mod(4+int(360+(\rot+45)/90),4)} \else \pgfmathsetmacro{\rot}{0} \pgfmathsetmacro{\quadrant}{0} \fi \def\pgf@circ@strut{\vrule width 0pt height 1em depth 0.4em\relax} \def\mytext{\ctikzvalof{multipoles/font}\space\pgf@circ@strut\the\pgf@circ@count@c\space} \pgfmathloop% \ifnum\pgf@circ@count@a>0 \ifcase\quadrant % rotation 0 % left \pgf@circ@count@c=\pgf@circ@count@a \pgftext[left, at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} % right \pgf@circ@count@c=\numexpr2\pgf@circ@count@b-\pgf@circ@count@a+1\relax \pgftext[right, at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} \or % rotation -90 % left \pgf@circ@count@c=\pgf@circ@count@a \pgftext[top, at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} % right \pgf@circ@count@c=\numexpr2\pgf@circ@count@b-\pgf@circ@count@a+1\relax \pgftext[bottom, at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} \or %rotation 180 % left \pgf@circ@count@c=\pgf@circ@count@a \pgftext[right, at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} % right \pgf@circ@count@c=\numexpr2\pgf@circ@count@b-\pgf@circ@count@a+1\relax \pgftext[left, at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} \or % rotation +90 % left \pgf@circ@count@c=\pgf@circ@count@a \pgftext[bottom, at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} % right \pgf@circ@count@c=\numexpr2\pgf@circ@count@b-\pgf@circ@count@a+1\relax \pgftext[top, at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}, rotate=\rot]{\mytext} \fi \advance\pgf@circ@count@a-1\relax% \repeatpgfmathloop \fi \endpgfscope \ifdim\pgf@circ@res@other>0pt \pgfscope \pgfsetlinewidth{\ctikzvalof{multipoles/external pins thickness}\pgflinewidth} \pgf@circ@count@a=\numpins\relax \divide\pgf@circ@count@a by 2 \pgf@circ@count@b=\pgf@circ@count@a \pgfmathloop% \ifnum\pgf@circ@count@a>0 \edef\padfrac{\ctikzvalof{multipoles/external pad fraction}} \ifnum\padfrac>0 \pgf@circ@res@temp=\pgf@circ@res@step\divide\pgf@circ@res@temp by \padfrac % left side pads \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@left}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} % right side pads \pgfpathmoveto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@right}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \else %% CHANGES HERE % left side pins \xdipchip@if@pin\pgf@circ@count@a {% \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} } {% \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} }% % right side pins \xdipchip@if@pin{\numpins+1-\pgf@circ@count@a} {% \pgfpathmoveto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} } {% \pgfpathmoveto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} \pgfpathlineto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)\pgf@circ@res@step}} }% \fi \advance\pgf@circ@count@a by -1\relax% \repeatpgfmathloop \pgfusepath{stroke} \endpgfscope \fi }% % \pgf@sh@s@<name of the shape here> contains all the code for the shape % and is executed just before a node is drawn. \pgfutil@g@addto@macro\pgf@sh@s@xdipchip{% % Start with the maximum pin number and go backwards. \pgf@circ@count@a=\numpins\relax \pgfmathloop% \ifnum\pgf@circ@count@a>0 % we will create two anchors per pin: the "normal one" like pin 1 for the % electrical contact, and the "border one" like bpin 1 for labels. % they will coincide if external pins width is set to 0. %% CHANGES HERE \xdipchip@if@pin\pgf@circ@count@a {% \expandafter\xdef\csname pgf@anchor@xdipchip@pin\space\the\pgf@circ@count@a\endcsname{% \noexpand\pgf@circ@dippinanchor{\the\pgf@circ@count@a}{1}% } } {% \expandafter\xdef\csname pgf@anchor@xdipchip@pin\space\the\pgf@circ@count@a\endcsname{% \noexpand\pgf@circ@dippinanchor{\the\pgf@circ@count@a}{0}% } }% \expandafter\xdef\csname pgf@anchor@xdipchip@bpin\space\the\pgf@circ@count@a\endcsname{% \noexpand\pgf@circ@dippinanchor{\the\pgf@circ@count@a}{0}% } \advance\pgf@circ@count@a by -1\relax% \repeatpgfmathloop% }% }

\makeatother

\ctikzset{ logic ports=ieee, logic ports/scale=0.7, multipoles/dipchip/width=2 }

\tikzset { block/.style={xdipchip ,no topmark ,hide numbers ,external pins width=0.2 ,xdip pins={#1}} }

\newcommand{\myblock}[1]{% Add #1- to the node and coord names nodeblock={1,2,3}, num pins=6{SR-FF} (#1-FF.pin 1) -- ++(-1,0) nodeand port, anchor=out{} (#1-FF.pin 3) -- (#1-FF.pin 3 -| #1-AND1.out) nodeand port, anchor=out{} (#1-AND1.in 1) to[short, -] ++(-1,0) coordinate(#1-in) to (#1-in |- #1-AND2.in 2) -- (#1-AND2.in 2); }

\begin{document} \begin{circuitikz}[] \draw (0,0) \myblock{A}; \draw (0,-4) \myblock{B};

\draw (A-in) -- ++(-0.5, 0) node[below]{$a_0$}; \draw (B-in) -- ++(-0.5, 0) node[below]{$a_1$}; \draw (A-AND1.in 2) to[short, -*] (A-AND2.in 1) to[short, -*] (B-AND1.in 2) to[short, -*] (B-AND2.in 1) -- ++(0, -2) coordinate(down) node[below]{ENABLE}; \draw (A-FF.pin 2) to[short, -*] (B-FF.pin 2) -- (B-FF.pin 2 |- down) node[below]{CP}; % to show that anchors are placed where they should \draw (5, 0) nodexdipchip, xdip pins={1, 6, 8, 4}{} ; \foreach\x in {1,...,8} \draw[red] (XDIP.pin \x) circle[radius=2pt]; \end{circuitikz} \end{document}

enter image description here


A version that doesn't rely on expl3 (by implementing an own quick list parsing/setting macro and else using pgfutil; this will use Q with category code 3 as the delimiter for our list, the same token is used elsewhere in pgf (namely in the space trimming code) as a delimiter, so this shouldn't be less stable than these parts of pgf).

The code block here only contains the definitions of \xdipchip@if@pin, the xdip pins key, and the necessary utility macros.

\makeatletter
% we'll use Q of category 3 as a delimiter of lists.
\catcode`\Q=3
% check whether something is contained in a list of comma separated values
% list should have a leading and trailing comma around each value
\def\xdipchip@if@pin#1%
  {\expandafter\xdipchip@if@pin@a\expandafter{\the\numexpr#1}}
\def\xdipchip@if@pin@a#1%
  {\expandafter\xdipchip@if@pin@b\expandafter{\xdipchip@pin@list}{#1}}
\def\xdipchip@if@pin@b#1#2%
  {%
    \begingroup
      \pgfutil@in@{Q#2Q}{#1}%
      \expandafter
    \endgroup
    \ifpgfutil@in@
      \expandafter\pgfutil@firstoftwo
    \else
      \expandafter\pgfutil@secondoftwo
    \fi
  }
% setting a list just needs some quick parsing, firs stripping spaces from
% either end, and ignoring blank/empty elements.
\def\xdipchip@set@list#1#2%
  {%
    \edef#1%
      {Q\xdipchip@set@list@sanitize#2,\xdipchip@set@list,\xdipchip@set@list}%
  }
% quick way to check whether list parsing is done by gobbling up to a marker, in
% this case the marker is \xdipchip@set@list
\def\xdipchip@set@list@sanitize@checkend#1\xdipchip@set@list{}
% will only be called after the last element is handled, will gobble the
% remainder of the current sanitizing step
\def\xdipchip@set@list@sanitize@end\xdipchip@set@list#1\xdipchip@set@list{}
% grabs the next list element, checks whether we're done, and if not sanitizes
% it (meaning stripping spaces from either end).
\def\xdipchip@set@list@sanitize#1,%
  {%
    \xdipchip@set@list@sanitize@checkend
      #1\xdipchip@set@list@sanitize@end\xdipchip@set@list
    \expandafter\expandafter\expandafter
    \xdipchip@set@list@sanitize@
    \expandafter\expandafter\expandafter
      {\pgfutil@trimspaces{#1}}%
  }
% we'll protect any argument from further expanding using \unexpanded, and
  % ignore empty/blank elements
\def\xdipchip@set@list@sanitize@#1%
  {%
    \pgfutil@ifempty{#1}%
      {}% ignore empty elements
      {\unexpanded{#1}Q}%
    \xdipchip@set@list@sanitize % get next element
  }
\catcode`\Q=11

\pgfkeys{/tikz/xdip pins/.code=\xdipchip@set@list\xdipchip@pin@list{#1}} \makeatother

Skillmon
  • 60,462
  • Nice, I like it. Would it work also in context or the latex3 thing is LaTeX-only? – Rmano Jun 05 '21 at 18:13
  • @Rmano expl3 is (or was, no idea of the current state) loadable in context and plain, but I can quickly implement a complete independent code variant that only relies on pgfutil. Give me a few minutes (or hours? who knows?). – Skillmon Jun 05 '21 at 18:41
  • I have accepted this one because I like how the actual circuit description remains the same, with no extra drawing code needed. – Cactus Jun 06 '21 at 04:23
  • @Skillmon @Rmano unfortunately I've found a weird bug with this: if I am connecting an xdipchip pin to another xdipchip's pin, then the pin's base coordinate is used instead of its end coordinate: https://gist.github.com/gergoerdi/5c41ba94cb877b5a9efb084a4eb13fc3 – Cactus Jun 06 '21 at 07:24
  • @Cactus is that with the expl3 variant or the other code? – Skillmon Jun 06 '21 at 08:20
  • @Skillmon this is with the first variant. – Cactus Jun 06 '21 at 08:37
  • 1
    The problem is that the anchor is calculated with the current value of xdip pins --- they are not "saved anchors". I will think a solution, but basically the list of pins must be saved as a \savedmacro in the shape. – Rmano Jun 06 '21 at 09:28
  • @Rmano oh, ok (I have no idea about the internals of pgf shapes :) Wouldn't then \savedmacro\xdippins{\let\xdippins\xdipchip@pin@list} suffice? And changing the \xdipchip@if@pin function to check the list \xdippins instead of \xdipchip@pin@list? – Skillmon Jun 06 '21 at 09:34
  • 1
    @Cactus thanks for pointing out this bug. We're currently trying to fix this, if this succeeds this might be added as a feature to the normal dipchip. – Skillmon Jun 06 '21 at 15:47
  • 1
    @Cactus thanks to Skillmon's code there will be a draw only pins=... feature in the next release of circuitikz, for chips and muxdemuxes (as soon as things are tested a bit). You can have a peek by looking at the bleeding edge manual here: https://circuitikz.github.io/circuitikz/ – Rmano Jun 08 '21 at 16:29
2

Although @Skillmon's answer is nice and elegant, what I will do for the next release of circuitikz is making dipchip and qfpchip respect the no input leads option as the multiplexer are already doing. It's a minimal change really, the idea is the following:

\documentclass[border=10pt]{standalone}
\usepackage[siunitx, RPvoltages]{circuitikz}
\makeatletter
\pgfdeclareshape{dipchip}{
    \savedmacro{\ctikzclass}{\edef\ctikzclass{chips}}
    \saveddimen{\scaledRlen}{\pgfmathsetlength{\pgf@x}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}}
    \savedmacro\numpins{%
            \pgf@circ@count@a=\ctikzvalof{multipoles/dipchip/num pins}%
            \def\numpins{\the\pgf@circ@count@a}
    }
    \savedanchor\centerpoint{%
        \pgf@x=-.5\wd\pgfnodeparttextbox%
        \pgf@y=-.5\ht\pgfnodeparttextbox%
        \advance\pgf@y by+.5\dp\pgfnodeparttextbox%
    }%
    \savedanchor\origin{\pgfpoint{0pt}{0pt}}
    \anchor{center}{\origin}
    \anchor{text}{\centerpoint}% to adjust text
    \saveddimen\height{%
        \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}
        \pgfmathsetlength\pgf@x{((\numpins)
        *\ctikzvalof{multipoles/dipchip/pin spacing})*\pgf@circ@scaled@Rlen/2}%
    }%
    \saveddimen{\chipspacing}{
        \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}
        \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen*\ctikzvalof{multipoles/dipchip/pin spacing}}}
    \saveddimen{\width}{
        \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}
        \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen*\ctikzvalof{multipoles/dipchip/width}}}
    \saveddimen{\extshift}{
        \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}
        \pgfmathsetlength\pgf@x{\pgf@circ@scaled@Rlen*\ctikzvalof{multipoles/external pins width}}}
    % standard anchors
    \savedanchor\northwest{%
        \pgfmathsetlength{\pgf@circ@scaled@Rlen}{\ctikzvalof{\ctikzclass/scale}\pgf@circ@Rlen}
        \pgfmathsetlength\pgf@y{0.5*((\numpins)
        *\ctikzvalof{multipoles/dipchip/pin spacing})*\pgf@circ@scaled@Rlen/2}%
        \pgfmathsetlength\pgf@x{-0.5*\pgf@circ@scaled@Rlen*\ctikzvalof{multipoles/dipchip/width}}
    }
    \anchor{dot}{\northwest
        \pgfmathsetlength\pgf@x{\pgf@x + 0.3*\chipspacing}
        \pgfmathsetlength\pgf@y{\pgf@y - 0.3*\chipspacing}
    }
    \anchor{nw}{\northwest}
    \anchor{ne}{\northwest\pgf@x=-\pgf@x}
    \anchor{se}{\northwest\pgf@x=-\pgf@x\pgf@y=-\pgf@y}
    \anchor{sw}{\northwest\pgf@y=-\pgf@y}
    \anchor{north west}{\northwest}
    \anchor{north east}{\northwest\pgf@x=-\pgf@x}
    \anchor{south east}{\northwest\pgf@x=-\pgf@x \pgf@y=-\pgf@y}
    \anchor{south west}{\northwest\pgf@y=-\pgf@y}
    \anchor{n}{\northwest\pgf@x=0pt }
    \anchor{e}{\northwest\pgf@x=-\pgf@x\pgf@y=0pt }
    \anchor{s}{\northwest\pgf@x=0pt\pgf@y=-\pgf@y}
    \anchor{w}{\northwest\pgf@y=0pt }
    \anchor{north}{\northwest\pgf@x=0pt }
    \anchor{east}{\northwest\pgf@x=-\pgf@x\pgf@y=0pt }
    \anchor{south}{\northwest\pgf@x=0pt\pgf@y=-\pgf@y}
    \anchor{west}{\northwest\pgf@y=0pt }
    % start drawing
    \backgroundpath{%
        \northwest
        \pgf@circ@res@up = \pgf@y
        \pgf@circ@res@down = -\pgf@y
        \pgf@circ@res@right = -\pgf@x
        \pgf@circ@res@left = \pgf@x
        \pgf@circ@scaled@Rlen=\scaledRlen
        \pgf@circ@res@step = \ctikzvalof{multipoles/dipchip/pin spacing}\pgf@circ@scaled@Rlen
        \pgf@circ@res@other = \ctikzvalof{multipoles/external pins width}\pgf@circ@scaled@Rlen
        \pgfscope% (for the line width)
        \pgf@circ@setlinewidth{multipoles}{\pgflinewidth}
        \pgfpathrectanglecorners{\pgfpoint{-\width/2}{-\height/2}}{\pgfpoint{\width/2}{\height/2}}%
        \pgf@circ@draworfill
        %% upside mark
        \ifpgf@circuit@chip@topmark
            \pgfpathmoveto{\pgfpoint{0.2*\pgf@circ@res@left}{\pgf@circ@res@up}}
            \pgfpatharc{0}{180}{0.2*\pgf@circ@res@left}
        \fi
        \pgfusepath{stroke}%
        \pgfsetcolor{\ctikzvalof{color}}
        % Adding the pin number
        \ifpgf@circuit@chip@shownumbers
            \pgf@circ@count@a=\numpins\relax
            \divide\pgf@circ@count@a by 2 \pgf@circ@count@b=\pgf@circ@count@a
            % thanks to @marmot: https://tex.stackexchange.com/a/473571/38080
            \ifpgf@circuit@chip@straightnumbers
                \pgfgettransformentries\a\b\temp\temp\temp\temp
                \pgfmathsetmacro{\rot}{-atan2(\b,\a)}
                \pgfmathtruncatemacro{\quadrant}{mod(4+int(360+(\rot+45)/90),4)}
            \else
                \pgfmathsetmacro{\rot}{0}
                \pgfmathsetmacro{\quadrant}{0}
            \fi
            \def\pgf@circ@strut{\vrule width 0pt height 1em depth 0.4em\relax}
            \def\mytext{\ctikzvalof{multipoles/font}\space\pgf@circ@strut\the\pgf@circ@count@c\space}
            \pgfmathloop%
            \ifnum\pgf@circ@count@a>0
                \ifcase\quadrant % rotation 0
                    % left
                    \pgf@circ@count@c=\pgf@circ@count@a
                    \pgftext[left,
                        at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                    % right
                    \pgf@circ@count@c=\numexpr2*\pgf@circ@count@b-\pgf@circ@count@a+1\relax
                    \pgftext[right,
                        at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                \or % rotation -90
                    % left
                    \pgf@circ@count@c=\pgf@circ@count@a
                    \pgftext[top,
                        at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                    % right
                    \pgf@circ@count@c=\numexpr2*\pgf@circ@count@b-\pgf@circ@count@a+1\relax
                    \pgftext[bottom,
                        at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                \or %rotation 180
                    % left
                    \pgf@circ@count@c=\pgf@circ@count@a
                    \pgftext[right,
                        at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                    % right
                    \pgf@circ@count@c=\numexpr2*\pgf@circ@count@b-\pgf@circ@count@a+1\relax
                    \pgftext[left,
                        at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                \or % rotation +90
                    % left
                    \pgf@circ@count@c=\pgf@circ@count@a
                    \pgftext[bottom,
                        at=\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                    % right
                    \pgf@circ@count@c=\numexpr2*\pgf@circ@count@b-\pgf@circ@count@a+1\relax
                    \pgftext[top,
                        at=\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step},
                        rotate=\rot]{\mytext}
                \fi
                \advance\pgf@circ@count@a-1\relax%
                \repeatpgfmathloop
            \fi
            \endpgfscope
            % draw external pins or pads
            \ifdim\pgf@circ@res@other>0pt
            \ifpgfcirc@draw@input@leads
            \pgfscope
                \pgfsetlinewidth{\ctikzvalof{multipoles/external pins thickness}\pgflinewidth}
                \pgf@circ@count@a=\numpins\relax
                \divide\pgf@circ@count@a by 2 \pgf@circ@count@b=\pgf@circ@count@a
                \pgfmathloop%
                \ifnum\pgf@circ@count@a>0
                    \edef\padfrac{\ctikzvalof{multipoles/external pad fraction}}
                    \ifnum\padfrac>0
                        \pgf@circ@res@temp=\pgf@circ@res@step\divide\pgf@circ@res@temp by \padfrac
                        % left side pads
                        \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@left}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        % right side pads
                        \pgfpathmoveto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@right}{-\pgf@circ@res@temp+\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                    \else
                        % left side pins
                        \pgfpathmoveto{\pgfpoint{\pgf@circ@res@left}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@left-\pgf@circ@res@other}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        % right side pins
                        \pgfpathmoveto{\pgfpoint{\pgf@circ@res@right}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                        \pgfpathlineto{\pgfpoint{\pgf@circ@res@right+\pgf@circ@res@other}{\pgf@circ@res@up+(\pgf@circ@dip@pin@shift-\the\pgf@circ@count@a)*\pgf@circ@res@step}}
                    \fi
                    \advance\pgf@circ@count@a by -1\relax%
                \repeatpgfmathloop
                \pgfusepath{stroke}
            \endpgfscope
            \fi
            \fi
        }%
        % \pgf@sh@s@<name of the shape here> contains all the code for the shape
        % and is executed just before a node is drawn.
        \pgfutil@g@addto@macro\pgf@sh@s@dipchip{%
            % Start with the maximum pin number and go backwards.
            \pgf@circ@count@a=\numpins\relax
            \pgfmathloop%
            \ifnum\pgf@circ@count@a>0
                % we will create two anchors per pin: the "normal one" like `pin 1` for the
                % electrical contact, and the "border one" like `bpin 1` for labels.
                % they will coincide if `external pins width` is set to 0.
                \expandafter\xdef\csname pgf@anchor@dipchip@pin\space\the\pgf@circ@count@a\endcsname{%
                    \noexpand\pgf@circ@dippinanchor{\the\pgf@circ@count@a}{1}%
                }
                \expandafter\xdef\csname pgf@anchor@dipchip@bpin\space\the\pgf@circ@count@a\endcsname{%
                    \noexpand\pgf@circ@dippinanchor{\the\pgf@circ@count@a}{0}%
                }
                \advance\pgf@circ@count@a by -1\relax%
                \repeatpgfmathloop%
            }%
        }

\makeatother \begin{document} \ctikzset{ logic ports=ieee, logic ports/scale=0.7, multipoles/dipchip/width=2 }

\tikzset{block/.style= { dipchip , no topmark , hide numbers , external pins width=0.2 , no input leads } }

\newcommand{\myblock}[1]{% Add #1- to the node and coord names nodeblock, num pins=6{SR-FF} (#1-FF.bpin 1) -- ++(-1,0) nodeand port, anchor=out{} %use bpin here (#1-FF.bpin 3) -- (#1-FF.pin 3 -| #1-AND1.out) nodeand port, anchor=out{} (#1-AND1.in 1) to[short, -] ++(-1,0) coordinate(#1-in) to (#1-in |- #1-AND2.in 2) -- (#1-AND2.in 2) (#1-FF.pin 2) -- (#1-FF.bpin 2); %draw the pin explicitly here }

\begin{circuitikz}[] \draw (0,0) \myblock{A}; \draw (0,-4) \myblock{B};

\draw (A-in) -- ++(-0.5, 0) node[below]{$a_0$}; \draw (B-in) -- ++(-0.5, 0) node[below]{$a_1$}; \draw (A-AND1.in 2) to[short, -*] (A-AND2.in 1) to[short, -*] (B-AND1.in 2) to[short, -*] (B-AND2.in 1) -- ++(0, -2) coordinate(down) node[below]{ENABLE}; \draw (A-FF.pin 2) to[short, -*] (B-FF.pin 2) -- (B-FF.pin 2 |- down) node[below]{CP}; \end{circuitikz} \end{document}

So --- when you choose no inputs leads you have all the anchors but no pins in any places; you just choose to use bpin X or pin X for the connection and you can draw a pin just connecting the bpin to the pin anchor.

enter image description here

Rmano
  • 40,848
  • 3
  • 64
  • 125
  • I don't like that this will pollute the code with extra lines just to connect the "point where the lead would end" with the "point where the pin is" to draw the lead. – Cactus Jun 06 '21 at 04:19
  • 1
    Yes, that was the idea when I said that @Skillmon 's code is more elegant. – Rmano Jun 06 '21 at 05:36
  • Anyway, I merged https://github.com/circuitikz/circuitikz/pull/548 for now, it's a nice symmetrical thing anyway. Still thinking about the nice solution. – Rmano Jun 06 '21 at 10:43