Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

In order to draw a printed circuit board layout, we've defined a DIP shape (shapes.tex):

\pgfkeys{/pgf/.cd,
  pcbpins/.initial=14,
  pcbdipdx/.initial=0.3 in,
  pcbdipwidth/.initial=0.4 in,
  pcbdipheight/.initial=0.1 in,
  pcbdipnudge/.initial=0.05 in,
  pcbcircleout/.initial=0.03 in,
  pcbcirclein/.initial=0.015 in,
  pcbcirclediff/.initial=0.1 in
}

\pgfdeclareshape{pcbbase} {
  \savedanchor\centerpoint{
    \pgf@x=.5\wd\pgfnodeparttextbox
    \pgf@y=.5\ht\pgfnodeparttextbox
    \advance\pgf@y by-.5\dp\pgfnodeparttextbox
  }
  \saveddimen\halfwidth{%
    \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}%  
    \pgf@x=0.5\pgf@xb
  }
  \saveddimen\halfheight{
    \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}%  
    \pgf@x=0.5\pgf@yb
  }
  \saveddimen\radius{%
    \pgfmathsetlength{\pgf@xb}{\pgfkeysvalueof{/pgf/minimum width}}%  
    \pgfmathsetlength{\pgf@yb}{\pgfkeysvalueof{/pgf/minimum height}}%  
    \pgf@x=.5\pgf@xb%
    \pgf@x=.5\pgf@yb%
  }
  \anchor{center}{\centerpoint}
  \anchor{mid}{\centerpoint\pgfmathsetlength\pgf@y{.5ex}}
  \anchor{base}{\centerpoint\pgf@y=0pt}
  \anchor{north}{\centerpoint\advance\pgf@y by\halfheight}
  \anchor{south}{\centerpoint\advance\pgf@y by-\halfheight}
  \anchor{west}{\centerpoint\advance\pgf@x by-\halfwidth}
  \anchor{east}{\centerpoint\advance\pgf@x by\halfwidth}
  \anchor{midwest}{\centerpoint\pgfutil@tempdima=\halfwidth\advance\pgf@x by-0.85\pgfutil@tempdima}
}

\pgfdeclareshape{pcbdip} {
  \inheritsavedanchors[from=pcbbase]
  \inheritanchor[from=pcbbase]{center}
  \inheritanchor[from=pcbbase]{mid}
  \inheritanchor[from=pcbbase]{base}
  \inheritanchor[from=pcbbase]{north}
  \inheritanchor[from=pcbbase]{south}
  \inheritanchor[from=pcbbase]{west}
  \inheritanchor[from=pcbbase]{east}
  \inheritanchor[from=pcbbase]{midwest}
  \savedmacro\halfpins{%
    \pgfmathdivide{\pgfkeysvalueof{/pgf/pcbpins}}{2}
    \let\halfpins\pgfmathresult
  }
  \saveddimen\circlein{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbcirclein}}}
  \saveddimen\circleout{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbcircleout}}}
  \saveddimen\circlediff{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbcirclediff}}}
  \saveddimen\dipdx{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbdipdx}}}
  \saveddimen\dipwidth{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbdipwidth}}}
  \saveddimen\dipheight{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbdipheight}}}
  \saveddimen\dipnudge{\pgfmathsetlength{\pgf@x}{\pgfkeysvalueof{/pgf/pcbdipnudge}}}
  \backgroundpath{
    \pgfseteorule
    \pgfutil@tempdima=\circlein
    \pgfutil@tempdimb=\circleout
    \pgfutil@tempdimc=\circlediff
    \pgfutil@tempdimd=\dipdx
    \pgfutil@tempdime=0.5\pgfutil@tempdimc
    \pgfmathloop
    \ifnum\pgfmathcounter>\halfpins
    \else
      \advance\pgfutil@tempdime by -0.5\pgfutil@tempdimc
      \repeatpgfmathloop
    \fi
    \pgfutil@tempdimf=\dipheight
    \pgfutil@tempdimg=\dipwidth
    \pgfutil@tempdimh=\dipnudge
    \pgfmathloop
    \ifnum\pgfmathcounter>\halfpins %pins
    \else
      \centerpoint\advance\pgf@x by-0.5\pgfutil@tempdimd\advance\pgf@y by\pgfutil@tempdime\pgfpathcircle{\pgfpoint{\pgf@x}{\pgf@y}}{\pgfutil@tempdima}
      \centerpoint\advance\pgf@x by-0.5\pgfutil@tempdimd\advance\pgf@y by\pgfutil@tempdime\pgfpathcircle{\pgfpoint{\pgf@x}{\pgf@y}}{\pgfutil@tempdimb}
      \centerpoint\advance\pgf@x by0.5\pgfutil@tempdimd\advance\pgf@y by\pgfutil@tempdime\pgfpathcircle{\pgfpoint{\pgf@x}{\pgf@y}}{\pgfutil@tempdima}
      \centerpoint\advance\pgf@x by0.5\pgfutil@tempdimd\advance\pgf@y by\pgfutil@tempdime\pgfpathcircle{\pgfpoint{\pgf@x}{\pgf@y}}{\pgfutil@tempdimb}
      \advance\pgfutil@tempdime by\pgfutil@tempdimc
      \repeatpgfmathloop
    \fi
    \color{gray}
    \pgfusepath{fill}
    \pgfsetlinewidth{2\pgflinewidth}
    \advance\pgfutil@tempdime by-\pgfutil@tempdimc
    \advance\pgfutil@tempdime by0.5\pgfutil@tempdimf
    \centerpoint\advance\pgf@x by-0.5\pgfutil@tempdimg\advance\pgf@y by\pgfutil@tempdime\pgfpathmoveto{\pgfpoint{\pgf@x}{\pgf@y}}
    \centerpoint\advance\pgf@x by-\pgfutil@tempdimh\advance\pgf@y by\pgfutil@tempdime\pgfpathlineto{\pgfpoint{\pgf@x}{\pgf@y}}\pgfpatharc{-180}{0}{\pgfutil@tempdimh and \pgfutil@tempdimh}
    \centerpoint\advance\pgf@x by0.5\pgfutil@tempdimg\advance\pgf@y by\pgfutil@tempdime\pgfpathlineto{\pgfpoint{\pgf@x}{\pgf@y}}
    \centerpoint\advance\pgf@x by0.5\pgfutil@tempdimg\advance\pgf@y by-\pgfutil@tempdime\pgfpathlineto{\pgfpoint{\pgf@x}{\pgf@y}}
    \centerpoint\advance\pgf@x by-0.5\pgfutil@tempdimg\advance\pgf@y by-\pgfutil@tempdime\pgfpathlineto{\pgfpoint{\pgf@x}{\pgf@y}}\pgfpathclose
    \color{black}
    \pgfusepath{stroke}
    % Draw port labels
    \begingroup
    \tikzset{pcb/part labels} % Use font from this style
    \tikz@textfont
    \centerpoint
    \pgftext[at={\pgfpoint{\pgf@x}{\pgf@y}},rotate=-90]{\raisebox{-0.75ex}{\pgfkeysvalueof{/pgf/pcblabel}}}
\endgroup
  }
}

and with main.tex file:

\documentclass{article}
\usepackage{tikz}
\makeatletter
\input{shapes}
\makeatother
\begin{document}
\begin{tikzpicture}
\node[shape=pcbdip,pcbpins=20] (DIP) at (0,0) {};
\draw (DIP.pin0) -- (DIP.pin18);
\end{tikzpicture}
\end{document}

As you can see, one can set the pcbpins value in order to generate DIP packing shapes for an arbitrary number of pins.

We wish to define anchors based on this parameter as well such that if one specifies 20 pins, one can access the anchors of the node DIP.pin0 to DIP.pin20. How can one define this? We know this is possible since this works for an AND gate.

share|improve this question
1  
I did something similar with circuitikz (see elfsoft2000.com/projects/index.htm) but I used a separate shape for each number of pins (8, 14 and 16 only). –  John Kormylo May 19 at 20:47
    
I'm having trouble with your MWE. Also, cannot find \pgfmathloop in docs. –  John Kormylo May 20 at 14:25
    
What are the generated errors? –  CommuSoft May 29 at 18:22
    
I did this with the original version of the TQFT package (that used nodes, the latest version uses pics). I based it on the code for the polygon shape that comes with TikZ. –  Loop Space May 29 at 18:38
    
(1) Package PGF Math Error: unknown function 'center' (in 'center') (2) Undefined control sequence \pgf@sh@bg@pcbdip ... circleout \pgfutil@tempdc =crclediff \pgfutil@tenp... –  John Kormylo May 29 at 22:05

1 Answer 1

up vote 5 down vote accepted
+150

This kind of thing is done quite a fair bit in the various shapes libraries. It isn't necessarily straightforward, and someone may have found an easier way of doing it, but the following illustrates the general technique used.

\documentclass[tikz,border=5]{standalone}

\pgfkeys{/pgf/.cd,
  box pins/.initial=1,
}
\makeatletter

% A very simple shape
\pgfdeclareshape{box}{
  \nodeparts{}
  \saveddimen\halfwidth{%
    \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/minimum width}/2}%
  }
  \saveddimen\halfheight{%
    \pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/minimum height}/2}%
  }
  \savedmacro\boxpins{%
    \pgfmathparse{int(\pgfkeysvalueof{/pgf/box pins})}%
    \let\boxpins=\pgfmathresult
  }
  \savedanchor\centerpoint{\pgfpointorigin}
  \anchor{center}{\centerpoint}
  \backgroundpath{%
    \pgfpathrectanglecorners{\pgfqpoint{-\halfwidth}{-\halfheight}}%
      {\pgfqpoint{\halfwidth}{\halfheight}}
  }
  %
  % Now add some code which will be executed
  % every time a box node is created.
  \pgfutil@g@addto@macro\pgf@sh@s@box{%
    \pgfmathloop%
    % The macro \boxpins will have been defined when code is executed
    \ifnum\pgfmathcounter>\boxpins\relax% 
    \else%
      % Only add if anchor not defined yet defined.
      \pgfutil@ifundefined{pgf@anchor@box@pin \pgfmathcounter}{%
        % Create anchor pin X for the shape box
        \expandafter\xdef\csname pgf@anchor@box@pin \pgfmathcounter\endcsname{%
          \noexpand\pgf@sh@lib@box@pinanchor{\pgfmathcounter}%
        }%
      }{}%
    \repeatpgfmathloop% 
  }
}
\def\pgf@sh@lib@box@pinanchor#1{%
  % All the saved dimens and macros will be available
  % when this macro is called.
  \ifnum#1>\boxpins\relax%
    % Should issue an error.
    \pgfpointorigin% 
  \else
    \pgfpoint{\halfwidth}{\halfheight*2/(\boxpins+1)*#1-\halfheight}%
  \fi  
}
\begin{document}
\begin{tikzpicture}[minimum size=1cm]
\foreach \b in {1,...,5}{
  \node [box, box pins=\b, draw, label=center:\b] at (0,2*\b) (box-\b) {};
  \foreach \p in {1,...,\b}
    \draw (2,2*\b) -- (box-\b.pin \p);
}
% box-1 does not have a pin 5 anchor
\draw [red] (2,3) -- (box-1.pin 5);
\end{tikzpicture}
\end{document}

enter image description here

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.