pgf/tikz 中的参数化锚点

pgf/tikz 中的参数化锚点

为了绘制印刷电路板布局,我们定义了一个 DIP 形状(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
  }
}

main.tex文件:

\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}

如您所见,可以设置该pcbpins值以便为任意数量的引脚生成 DIP 封装形状。

我们希望根据此参数定义锚点,这样如果指定20引脚,就可以访问节点的锚点DIP.pin0DIP.pin20如何定义?我们知道这是可能的,因为这适用于与门。

答案1

各种形状库中都相当多地实现了这种功能。它不一定简单,有些人可能找到了更简单的方法,但下面说明了使用的一般技术。

\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}

在此处输入图片描述

相关内容