我在玩这个问题,特别是试图修改和扩展链接的例子\foreach
。它工作正常,但当我尝试使用循环来定义不同的锚点组时,会出现错误。如果我直接使用循环变量,我会得到一个“! 未定义的控制序列。“错误。如果我使用计数器的值,则仅使用循环所采用的最后一个值。但是,正如我们所见,所有三个锚点都已定义。所以我的问题是:
- 为什么会发生这种情况?
- 如何解决这个问题?
代码
\documentclass[tikz, border=2mm]{standalone}
\tikzset{%
multipoles/.is family,
multipoles,
pin spacing/.initial=5mm,
top left pins/.initial=3,
bottom left pins/.initial=3,
top right pins/.initial=8,
bottom right pins/.initial=0,
top pins/.initial=0,
bottom pins/.initial=0,
}
\newcommand{\mpp}[1]%
{ \pgfkeysvalueof{/tikz/multipoles/#1}
}
\newcounter{mypincounter}
\pgfdeclareshape{ic8pin}{
\anchor{center}{\pgfpointorigin} % within the node, (0,0) is the center
\anchor{text} % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}
\pgfmathtruncatemacro{\lrd}{max(\mpp{top left pins} +\mpp{bottom left pins} +or(\mpp{top left pins},\mpp{bottom left pins}), \mpp{top right pins} +\mpp{bottom right pins} +or(\mpp{top right pins},\mpp{bottom right pins}) == 0 ? 2 : max(\mpp{top left pins} +\mpp{bottom left pins} +or(\mpp{top left pins},\mpp{bottom left pins}), \mpp{top right pins} +\mpp{bottom right pins} +or(\mpp{top right pins},\mpp{bottom right pins})}
\xdef\LRDivisions{\lrd}
\pgfmathtruncatemacro{\tbd}{max(\mpp{top pins} +and(1,\mpp{top pins}), \mpp{bottom pins} +and(1,\mpp{bottom pins}) == 0 ? 2 : max(\mpp{top pins} +and(1,\mpp{top pins}), \mpp{bottom pins} +and(1,\mpp{bottom pins})}
\xdef\TBDivisions{\tbd}
\foreach \x in {1,...,\mpp{top left pins}}
{ \setcounter{mypincounter}{\x}
\expandafter\savedanchor\csname tlpin\Roman{mypincounter} \endcsname{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}{\LRDivisions*\mpp{pin spacing}/2-\mpp{pin spacing}}}
\anchor{pin\x}{\csname tlpin\Roman{mypincounter} \endcsname}
}
\foregroundpath{ % border and pin numbers are drawn here
\pgfsetlinewidth{0.4pt}
\pgfpathrectanglecorners{\pgfpoint{\TBDivisions*\mpp{pin spacing}/2}{\LRDivisions*\mpp{pin spacing}/2}}{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}{-\LRDivisions*\mpp{pin spacing}/2}}
\pgfusepath{draw} %draw rectangle
\pgftext[left,at={\pgfpoint{-.5cm}{-.55cm}}]{\scriptsize LR : \textcolor{red}{\LRDivisions}}
\pgftext[left,at={\pgfpoint{-.5cm}{.55cm}}]{\scriptsize TB : \textcolor{red}{\TBDivisions}}
}}
\begin{document}
\begin{tikzpicture}
\draw (0,0) node[ic8pin] (IC1) {IC 1};
\draw (-5,5) node[ic8pin,rotate=90] (IC2) {IC 2};
\draw[red] (IC1.pin1) -- ++ (-1,0.5) -- (IC2.pin1);
\draw[blue] (IC1.pin2) -- ++ (-1,0) -- (IC2.pin2);
\draw[green] (IC1.pin3) -- ++ (-1,-0.5) -- (IC2.pin3);
\end{tikzpicture}
\end{document}
这会产生错误(问题出在*\x
):
\foreach \x in {1,...,\mpp{top left pins}}
{ \setcounter{mypincounter}{\x}
\expandafter\savedanchor\csname tlpin\Roman{mypincounter} \endcsname{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}{\LRDivisions*\mpp{pin spacing}/2-\value{mypincounter}*\mpp{pin spacing}*\x}}
\anchor{pin\x}{\csname tlpin\Roman{mypincounter} \endcsname}
}
但这不能正常工作(\value{mypincounter}
始终等于 3):
\foreach \x in {1,...,\mpp{top left pins}}
{ \setcounter{mypincounter}{\x}
\xdef\mydummyx{\x}
\expandafter\savedanchor\csname tlpin\Roman{mypincounter} \endcsname{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}{\LRDivisions*\mpp{pin spacing}/2-\value{mypincounter}*\mpp{pin spacing}}}
\anchor{pin\x}{\csname tlpin\Roman{mypincounter} \endcsname}
}
输出
预期输出
答案1
和savedanchor
都是anchor
内部宏的别名。\anchor
当形状为已声明(因此扩展发生在锚点名称中),但只有当锚点是称为(A.pin 1)
例如,在坐标中,\savedanchor
在声明形状时,不会扩展其任何参数,但在形状为画,例如使用\node
。
对于这种情况,\pgfmathloop
可以使用命令。它是非常轻量级,因为它只是\loop
-\repeat
构造的重新实现,但在宏中保存了当前迭代的次数\pgfmathcounter
。计数从 1 开始。
、star
和形状regular polygon
都cloud
展示了如何将其用于可变数量的锚点,尽管它们使用内部宏来创建锚点并做一些额外的魔法(见下文)。
一个更直接、更简单的例子是:
\documentclass[tikz, border=2mm]{standalone}
\makeatletter
\pgfkeys{%
/pgf/chip pins/.initial=4,
/pgf/chip pin spacing/.initial=0.25cm
}
\def\maxpins{10}
\pgfdeclareshape{chip}{
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by-.5\dp\pgfnodeparttextbox%
}
\anchor{center}{\centerpoint}
\saveddimen\height{%
\pgfmathsetlength\pgf@x{(\pgfkeysvalueof{/pgf/chip pins}+1)*\pgfkeysvalueof{/pgf/chip pin spacing}}%
}
\saveddimen{\chipspacing}{\pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/chip pin spacing}}}
\backgroundpath{%
\pgfpathrectanglecorners{\pgfpointadd{\centerpoint}{\pgfpoint{-.5cm}{-\height/2}}}%
{\pgfpointadd{\centerpoint}{\pgfpoint{.5cm}{\height/2}}}%
}
%
\pgfmathloop%
\ifnum\pgfmathcounter>\maxpins\relax%
\else%
% Need to expand \pgfmathcounter
\edef\marshal{\noexpand\anchor{pin \pgfmathcounter}}%
\expandafter\marshal\expandafter{\expandafter\chippinanchor\expandafter{\pgfmathcounter}}%
\repeatpgfmathloop%
}
\def\chippinanchor#1{%
% When this macro is called,
% \centerpoint, \height and \chipspacing will be defined.
\pgfpointadd{\centerpoint}{\pgfpoint{.5cm}{\height/2-#1*\chipspacing}}%
}
\begin{document}
\begin{tikzpicture}
\node [chip, draw] (A) {A};
\node [chip, draw, rotate=-90, chip pins=5, chip pin spacing=.5cm] (B) at (2,2){B};
\foreach \p in {1,...,4}
\draw (A.pin \p) node [left, font=\tiny] {\p} -| (B.pin \p) node [above, font=\tiny] {\p};
\end{tikzpicture}
\end{document}
请注意,在上面的例子中,形状的最大引脚数是固定的已声明(基于\maxpins
)。允许任意数量的引脚,这些引脚的数量由形状决定画(例如,使用)必须做一些额外的工作。这与、和形状\node
使用的方法相同。star
regular polygon
cloud
\documentclass[tikz, border=2mm]{standalone}
\makeatletter
\pgfkeys{%
/pgf/chip pins/.initial=4,
/pgf/chip pin spacing/.initial=0.25cm
}
\pgfdeclareshape{chip}{
\savedanchor\centerpoint{%
\pgf@x=.5\wd\pgfnodeparttextbox%
\pgf@y=.5\ht\pgfnodeparttextbox%
\advance\pgf@y by-.5\dp\pgfnodeparttextbox%
}%
\anchor{center}{\centerpoint}
\saveddimen\height{%
\pgfmathsetlength\pgf@x{(\pgfkeysvalueof{/pgf/chip pins}+1)*\pgfkeysvalueof{/pgf/chip pin spacing}}%
}%
\saveddimen{\chipspacing}{\pgfmathsetlength\pgf@x{\pgfkeysvalueof{/pgf/chip pin spacing}}}
\backgroundpath{%
\pgfpathrectanglecorners{\pgfpointadd{\centerpoint}{\pgfpoint{-.5cm}{-\height/2}}}%
{\pgfpointadd{\centerpoint}{\pgfpoint{.5cm}{\height/2}}}%
}%
% \pgf@sh@s@chip contains all the code for the chip shape
% and is executed just before a chip node is drawn.
\pgfutil@g@addto@macro\pgf@sh@s@chip{%
% Start with the maximum pin number and go backwards.
% If the anchor is undefined, create it. Otherwise stop.
\c@pgf@counta=\pgfkeysvalueof{/pgf/chip pins}\relax%
\pgfmathloop%
\ifnum\c@pgf@counta>0\relax%
\pgfutil@ifundefined{pgf@anchor@chip@pin\space\the\c@pgf@counta}{%
\expandafter\xdef\csname pgf@anchor@chip@pin\space\the\c@pgf@counta\endcsname{%
\noexpand\chippinanchor{\the\c@pgf@counta}%
}%
}{\c@pgf@counta=0\relax}%
\advance\c@pgf@counta-1\relax%
\repeatpgfmathloop%
}%
}
\def\chippinanchor#1{%
% When this macro is called,
% \centerpoint, \height and \chipspacing will be defined.
\pgfpointadd{\centerpoint}{\pgfpoint{.5cm}{\height/2-#1*\chipspacing}}%
}
\begin{document}
\begin{tikzpicture}
\node [chip, draw] (A) {A};
\node [chip, draw, rotate=-90, chip pins=5, chip pin spacing=.5cm] (B) at (2,2){B};
\foreach \p in {1,...,4}
\draw (A.pin \p) node [left, font=\tiny] {\p} -| (B.pin \p) node [above, font=\tiny] {\p};
\end{tikzpicture}
\end{document}
答案2
(编辑)2017:因为xint 1.1 (2014/10/28)
这里需要\usepackage{xinttools}
。代码已更新以替换\usepackage{xint}
初始答案。
看起来并\anchor
没有立即展开它的第二个参数。
以下代码似乎产生了预期的输出:
\documentclass[tikz, border=2mm]{standalone}
\usepackage{xinttools}
\tikzset{%
multipoles/.is family,
multipoles,
pin spacing/.initial=5mm,
top left pins/.initial=3,
bottom left pins/.initial=3,
top right pins/.initial=8,
bottom right pins/.initial=0,
top pins/.initial=0,
bottom pins/.initial=0,
}
\newcommand{\mpp}[1]%
{ \pgfkeysvalueof{/tikz/multipoles/#1}
}
\newcounter{mypincounter}
\pgfdeclareshape{ic8pin}{
\anchor{center}{\pgfpointorigin} % within the node, (0,0) is the center
\anchor{text} % this is used to center the text in the node
{\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}
\pgfmathtruncatemacro{\lrd}{max(\mpp{top left pins} +\mpp{bottom left pins} +or(\mpp{top left pins},\mpp{bottom left pins}), \mpp{top right pins} +\mpp{bottom right pins} +or(\mpp{top right pins},\mpp{bottom right pins}) == 0 ? 2 : max(\mpp{top left pins} +\mpp{bottom left pins} +or(\mpp{top left pins},\mpp{bottom left pins}), \mpp{top right pins} +\mpp{bottom right pins} +or(\mpp{top right pins},\mpp{bottom right pins})}
\xdef\LRDivisions{\lrd}
\pgfmathtruncatemacro{\tbd}{max(\mpp{top pins} +and(1,\mpp{top pins}), \mpp{bottom pins} +and(1,\mpp{bottom pins}) == 0 ? 2 : max(\mpp{top pins} +and(1,\mpp{top pins}), \mpp{bottom pins} +and(1,\mpp{bottom pins})}
\xdef\TBDivisions{\tbd}
\xintFor* #1 in {\xintSeq {1}{\mpp{top left pins}}}
\do
{%\setcounter{mypincounter}{#1}% not needed
\expandafter\savedanchor\csname tlpin#1\endcsname
{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}%
{(\LRDivisions*\mpp{pin spacing}/2)-(\mpp{pin spacing}*#1)}}
\anchor{pin#1}{\csname tlpin#1\endcsname}
}
\foregroundpath{ % border and pin numbers are drawn here
\pgfsetlinewidth{0.4pt}
\pgfpathrectanglecorners{\pgfpoint{\TBDivisions*\mpp{pin spacing}/2}{\LRDivisions*\mpp{pin spacing}/2}}{\pgfpoint{-\TBDivisions*\mpp{pin spacing}/2}{-\LRDivisions*\mpp{pin spacing}/2}}
\pgfusepath{draw} %draw rectangle
\pgftext[left,at={\pgfpoint{-.5cm}{-.55cm}}]{\scriptsize LR : \textcolor{red}{\LRDivisions}}
\pgftext[left,at={\pgfpoint{-.5cm}{.55cm}}]{\scriptsize TB : \textcolor{red}{\TBDivisions}}
}}
\begin{document}
\begin{tikzpicture}
\draw (0,0) node[ic8pin] (IC1) {IC 1};
\draw (-5,5) node[ic8pin,rotate=90] (IC2) {IC 2};
\draw[red] (IC1.pin1) -- ++ (-1,0.5) -- (IC2.pin1);
\draw[blue] (IC1.pin2) -- ++ (-1,0) -- (IC2.pin2);
\draw[green] (IC1.pin3) -- ++ (-1,-0.5) -- (IC2.pin3);
\end{tikzpicture}
\end{document}