我尝试使用 foreach 循环来定义新样式。但是,循环内的代码似乎没有效果。以下 MWE 说明了我的问题:
\documentclass[tikz]{standalone}
\tikzset{
mystyle/.code=
{
%\tikzset{very thick}, % This line has an effect (if uncommented)
\foreach \pos in {0.1, 0.2, 0.3, 0.4} % **EDIT**: Should be a list of names in the end.
{
% There will be other statements here that actually use the list members
\tikzset{very thick}, %This line is an exact copy of the comented line but has no effect.
\message{======== Foreach: pos=\pos}
}
}
}
\begin{document}
\begin{tikzpicture}
\draw [help lines] (-10,-10) grid (10,10);
\draw[mystyle] (0,0) --++ (5,0);
\end{tikzpicture}
\end{document}
当我编译此文档时,控制台显示以下消息
... ======== Foreach:pos=0.1 ======== Foreach:pos=0.2 ======== Foreach:pos=0.3 ======== Foreach:pos=0.4 [1] (./mwe.aux)) ...
所以我相信 \tikzset 确实运行了。没有错误消息。
那么,为什么 \tikzset 命令不能使我的线条变粗?我该如何让它工作呢?
编辑:上下文:这(当然)是更大事情的一部分。最后,我想创建如下所示的晶体管棒图:http://www.southampton.ac.uk/~bim/notes/cad/guides/sticks.html (摘要:芯片级晶体管布局仅使用不同颜色的线条来绘制。当“多晶硅”颜色的线与“N 扩散”或“P 扩散”颜色的线相交时,就会出现晶体管栅极。为此,我首先创建了一些线条和节点样式,借用了循环空间和 circuitikz(用于节点样式)。有了它,我可以绘制我的图表,但它仍然是手动的,因为我必须绘制多条线来创建一个晶体管:扩散和多晶硅线。所以,我决定创建一个新的线条样式,这样我就可以自动放置晶体管门。使用从卡西米尔,我能够创建以下内容:
\documentclass[tikz]{standalone}
% Code adapted from: https://tex.stackexchange.com/a/393496/69074
\usetikzlibrary{decorations.markings}
%{{{ Transistor Stick Diagrams
%{{{ Layer Magic
% Source: Adapted from https://tex.stackexchange.com/a/20426/69074
\pgfdeclarelayer{M3L} % Metal 3
\pgfdeclarelayer{M2L} % Metal 1
\pgfdeclarelayer{M1L} % Metal 1
\pgfdeclarelayer{POL} % Poly-Silicon
\pgfdeclarelayer{DDL} % Diffusion
\pgfdeclarelayer{CONTL} % Contacts
\pgfsetlayers{DDL,POL,M1L,M2L,M3L,CONTL,main}
\makeatletter
\pgfkeys{%
/tikz/on layer/.code={
\pgfonlayer{#1}\begingroup
\aftergroup\endpgfonlayer
\aftergroup\endgroup
},
/tikz/node on layer/.code={
\gdef\node@@on@layer{%
\setbox\tikz@tempbox=\hbox\bgroup\pgfonlayer{#1}\unhbox\tikz@tempbox\endpgfonlayer\egroup}
\aftergroup\node@on@layer
},
/tikz/end node on layer/.code={
\endpgfonlayer\endgroup\endgroup
}
}
\def\node@on@layer{\aftergroup\node@@on@layer}
%}}}
%{{{ Declare the Node shapes
% Code stolen (and slightly adapted from Circuitikz:
% Source: /usr/share/texmf-dist/tex/generic/circuitikz/pgfcircshapes.tex
\makeatletter
\newdimen\sticknodewidth
\sticknodewidth=1cm
%% Left out, boring and too long
\makeatother
%}}}
%{{{ Line Styles
\tikzstyle{M3} = [draw=green, line width=0.3, on layer=M3L ] % Metal 3 Path
\tikzstyle{M2} = [draw=yellow, line width=0.3, on layer=M2L ] % Metal 2 Path
\tikzstyle{M1} = [draw=turquoise, line width=0.3, on layer=M1L ] % Metal 1 Path
\tikzstyle{PO} = [draw=blue, line width=0.3, on layer=POL ] % Poly-Silicon Path (Gate)
\tikzstyle{PD} = [draw=red!50, line width=0.3, on layer=DDL ] % P-Diffusion Path (PMOS)
\tikzstyle{ND} = [draw=red, line width=0.3, on layer=DDL ] % N-Diffusion Path (NMOS)
\tikzstyle{air} = [draw=black,dashed,line width=0.1, on layer=CONTL] % N-Diffusion Path (NMOS)
%}}}
%{{{ Port Styles
\tikzstyle{M3P} = [stickport, color=green, node on layer=M3L ] % Metal 3 Terminal
\tikzstyle{M2P} = [stickport, color=yellow, node on layer=M2L ] % Metal 2 Terminal
\tikzstyle{M1P} = [stickport, color=turquoise, node on layer=M1L ] % Metal 1 Terminal
\tikzstyle{POP} = [stickport, color=blue, node on layer=POL ] % Poly-Silicon Terminal
\tikzstyle{PDP} = [stickport, color=red!50, node on layer=DDL ] % P-Diffusion Terminal (PMOS)
\tikzstyle{NDP} = [stickport, color=red, node on layer=DDL ] % N-Diffusion Terminal (NMOS)
\tikzstyle{CON} = [stickcontact, color=black, node on layer=CONTL] % Via (between touching M3,M2,M1,PO,P-Diff,N-Diff)
\tikzstyle{TAP} = [sticktap, color=black, node on layer=CONTL] % Substrate Tap (between touching M1,Diff,N-Diff)
\tikzstyle{TAPCON} = [sticktapcon, color=black, node on layer=CONTL] % Merged Tap and Via
%}}}
%{{{ Automatic Transistors
\tikzset{
gate/.style 2 args=
{
thick,decoration=
{
markings, mark=at position {#1} with
{
\draw[PO] (0,-0.25)coordinate(m#2ga)--(0,0.25)coordinate(m#2gb);
\node[inner xsep=0, inner ysep=0.1mm,above left,font=\tiny,rotate=\pgfdecoratedangle-90](x) {$M_{#2}$};
}
},
postaction={decorate}
},
stick pmos/.style=
{
PD,
gate/.list={#1}
},
pmos/.code=
{
\foreach \name in {#1}
{
% Calculate \pos somehow, I'm not there yet
\tikzset{gate={\pos}{\name}}
}
}
}
%}}}
%}}}
\begin{document}
\begin{tikzpicture}
\draw [help lines] (-10,-10) grid (10,10);
\draw[stick pmos={{0.333}{1},{0.666}{2}}] (0,0)--++(0,2);
\draw[PO] (m1ga)--++(0.5,0.5);
\draw[PO] (m2gb)--++(-0.5,-0.5);
\draw[pmos={a,b,c}] (3,0)--++(0,2); % Gates spaced automatically
\draw[PO] (maga)--++(0.5,0.5);
\draw[PO] (magb)--++(-0.5,-0.5);
\end{tikzpicture}
\end{document}
这个东西非常接近我想要的。然而,最后一部分是这个问题的灵感来源:gate/.list 处理程序不允许我自动放置节点(或者我只是没有找到如何做到这一点),所以我想自己做循环。手册第 82.4.6 节说,/.list 处理程序在内部使用 foreach 循环,所以我尝试了一下,遇到了问题。我创建的 MWE 不是最优的,因为它使用数字列表进行循环,而最终版本应该是名称循环。很抱歉。
答案1
正如我在评论中所说,发生这种情况是因为 的内容\foreach
是在组内执行的,因此当组结束时, 的值line width
(由键修改very thick
)将恢复为先前的值。这就是为什么在循环外执行此操作可以正常工作的原因\foreach
。
第一个代码的解决方案
这是一个通过更改循环命令的简单解决方案。有几个选项,这里我使用expl3
了\fp_step_variable:nnnNn
。
首先我复制一个\fp_step_variable:nnnNn
叫做的副本\fpStepVariable
。它的语法\fp_step_variable:nnnNn
是:
\fp_step_variable:nnnNn {<initial value>} {<step>} {<final value>} <tl var> {<code>}
所以我替换了:
\foreach \pos in {0.1, 0.2, 0.3, 0.4}
经过
\fpStepVariable {0.1} {0.1} {0.4} \pos
我还添加了两个\typeout
s 来显示效果。运行代码后控制台显示:
Line width before: 0.4pt
======== Foreach: pos=0.1 ======== Foreach: pos=0.2 ======== Foreach: pos=0.3 ======== Foreach: pos=0.4
Line width after: 1.2pt
完整代码:
\documentclass[tikz]{standalone}
\usepackage{expl3}
\ExplSyntaxOn
\cs_set_eq:NN \fpStepVariable \fp_step_variable:nnnNn
\ExplSyntaxOff
\tikzset{
mystyle/.code=
{
\typeout{Line width before: \the\pgflinewidth}
\fpStepVariable {0.1} {0.1} {0.4} \pos
{
\tikzset{very thick}, %This line is an exact copy of the comented line but has no effect.
\message{======== Foreach: pos=\pos}
}
\typeout{Line width after: \the\pgflinewidth}
}
}
\begin{document}
\begin{tikzpicture}
\draw [help lines] (-10,-10) grid (10,10);
\draw[mystyle] (0,0) --++ (5,0);
\end{tikzpicture}
\end{document}
第二段代码的解决方法
我在这里使用的解决方案除了一些细节外与上一个非常相似。
以前我使用 ,\fp_step_variable:nnnNn
因为你有一个统一的数字序列。现在你有字母。解决这个问题的一种方法是使用\clist_map_...
函数循环遍历逗号分隔的事物列表。为了保持使用语法相似,我使用了\clist_map_variable:nNn
,其语法是:
\clist_map_variable:nNn {<comma list>} <tl var> {<code>}
我复制\clist_map_variable:nNn
并\ClistMapVariable
使用了:
\ClistMapVariable{#1}\name
您传递给键的#1
列表在哪里。您将面临的一个问题是变量扩展为名称(、或),但它不是名称本身,因此您需要先扩展它。为此我使用了:a,b,c
pmos
\name
a
b
c
\edef\tempa{\noexpand\tikzset{gate={\pos}{\name}}}
\tempa
之后\edef
,\tempa
将会是类似于\tikzset{gate={0.12345}{a}}
我们想要的结果。
最后,我用
\pgfmathparse{rnd}
\edef\pos{\pgfmathresult}
赋予 一定 价值\pos
.
完整代码:
\documentclass[tikz]{standalone}
\usepackage{expl3}
\ExplSyntaxOn
\cs_set_eq:NN \ClistMapVariable \clist_map_variable:nNn
\ExplSyntaxOff
% Code adapted from: https://tex.stackexchange.com/a/393496/69074
\usetikzlibrary{decorations.markings}
%{{{ Transistor Stick Diagrams
%{{{ Layer Magic
% Source: Adapted from https://tex.stackexchange.com/a/20426/69074
\pgfdeclarelayer{M3L} % Metal 3
\pgfdeclarelayer{M2L} % Metal 1
\pgfdeclarelayer{M1L} % Metal 1
\pgfdeclarelayer{POL} % Poly-Silicon
\pgfdeclarelayer{DDL} % Diffusion
\pgfdeclarelayer{CONTL} % Contacts
\pgfsetlayers{DDL,POL,M1L,M2L,M3L,CONTL,main}
\makeatletter
\pgfkeys{%
/tikz/on layer/.code={
\pgfonlayer{#1}\begingroup
\aftergroup\endpgfonlayer
\aftergroup\endgroup
},
/tikz/node on layer/.code={
\gdef\node@@on@layer{%
\setbox\tikz@tempbox=\hbox\bgroup\pgfonlayer{#1}\unhbox\tikz@tempbox\endpgfonlayer\egroup}
\aftergroup\node@on@layer
},
/tikz/end node on layer/.code={
\endpgfonlayer\endgroup\endgroup
}
}
\def\node@on@layer{\aftergroup\node@@on@layer}
%}}}
%{{{ Declare the Node shapes
% Code stolen (and slightly adapted from Circuitikz:
% Source: /usr/share/texmf-dist/tex/generic/circuitikz/pgfcircshapes.tex
\makeatletter
\newdimen\sticknodewidth
\sticknodewidth=1cm
%% Left out, boring and too long
\makeatother
%}}}
%{{{ Line Styles
\tikzset{
M3/.style = { draw=green, line width=0.3, on layer=M3L }, % Metal 3 Path
M2/.style = { draw=yellow, line width=0.3, on layer=M2L }, % Metal 2 Path
M1/.style = { draw=turquoise, line width=0.3, on layer=M1L }, % Metal 1 Path
PO/.style = { draw=blue, line width=0.3, on layer=POL }, % Poly-Silicon Path (Gate)
PD/.style = { draw=red!50, line width=0.3, on layer=DDL }, % P-Diffusion Path (PMOS)
ND/.style = { draw=red, line width=0.3, on layer=DDL }, % N-Diffusion Path (NMOS)
air/.style = { draw=black,dashed,line width=0.1, on layer=CONTL }, % N-Diffusion Path (NMOS)
}
%}}}
%{{{ Port Styles
\tikzset{
M3P/.style = {stickport, color=green, node on layer=M3L }, % Metal 3 Terminal
M2P/.style = {stickport, color=yellow, node on layer=M2L }, % Metal 2 Terminal
M1P/.style = {stickport, color=turquoise, node on layer=M1L }, % Metal 1 Terminal
POP/.style = {stickport, color=blue, node on layer=POL }, % Poly-Silicon Terminal
PDP/.style = {stickport, color=red!50, node on layer=DDL }, % P-Diffusion Terminal (PMOS)
NDP/.style = {stickport, color=red, node on layer=DDL }, % N-Diffusion Terminal (NMOS)
CON/.style = {stickcontact, color=black, node on layer=CONTL}, % Via (between touching M3,M2,M1,PO,P-Diff,N-Diff)
TAP/.style = {sticktap, color=black, node on layer=CONTL}, % Substrate Tap (between touching M1,Diff,N-Diff)
TAPCON/.style = {sticktapcon, color=black, node on layer=CONTL}, % Merged Tap and Via
}
%}}}
%{{{ Automatic Transistors
\tikzset{
gate/.style 2 args=
{
thick,decoration=
{
markings, mark=at position {#1} with
{
\draw[PO] (0,-0.25)coordinate(m#2ga)--(0,0.25)coordinate(m#2gb);
\node[inner xsep=0, inner ysep=0.1mm,above left,font=\tiny,rotate=\pgfdecoratedangle-90](x) {$M_{#2}$};
}
},
postaction={decorate}
},
stick pmos/.style=
{
PD,
gate/.list={#1}
},
pmos/.code=
{
\ClistMapVariable{#1}\name
{
\pgfmathparse{rnd}
\edef\pos{\pgfmathresult}
\edef\tempa{\noexpand\tikzset{gate={\pos}{\name}}}
\tempa
}
}
}
%}}}
%}}}
\begin{document}
\begin{tikzpicture}
\draw [help lines] (-10,-10) grid (10,10);
\draw[stick pmos={{0.333}{1},{0.666}{2}}] (0,0)--++(0,2);
\draw[PO] (m1ga)--++(0.5,0.5);
\draw[PO] (m2gb)--++(-0.5,-0.5);
\draw[pmos={a,b,c}] (3,0)--++(0,2); % Gates spaced automatically
\draw[PO] (maga)--++(0.5,0.5);
\draw[PO] (magb)--++(-0.5,-0.5);
\end{tikzpicture}
\end{document}
评论
这是其中一种方法。还有更多方法。您可以使用 marmot 先生的建议来“偷运”
\tikzset
组外的内容,或者您可以使用其他循环函数,甚至可以使用样式做一些巧妙的事情。我
\clist_map_variable:nNn
习惯于保持与以前类似的语法。您可以使用\clist_map_inline:nn
,这样可以避免进行这种扩展恶作剧。我把这个留给你。该语法
\tikzstyle{a}=[b]
已弃用。您应该使用\tikzset{s/.style={b}}
。我在您的代码中对其进行了更改。