我有一个比较长而浅的矩形,我需要在它的底部放置一些节点。我不想手动调整坐标,当然也不想多次复制相同的代码。
到目前为止我已经想出了以下代码:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,fit,petri,arrows,backgrounds}
\begin{document}
\begin{tikzpicture}[inner sep=0mm,>=stealth',very thick,color=black!50,
background rectangle/.style={fill=black},show background rectangle,
font=\sffamily,pics/two dots/.style={code={
\node [draw,minimum size=5mm,circle,colored tokens={black!50}]
(#1-left) {};
\node [draw,minimum size=5mm,circle,colored tokens={black!50},
right=0pt of #1-left]
(#1-right) {};
\node [rectangle, fit=(#1-left) (#1-right)] (#1){};
}},
every pin edge/.style={<-,very thick},
box/.style={draw,rectangle,inner sep=#1},box/.default=2mm]
%
\node (W1) {factorial:};
\node (fake1) [right=190mm of W1] {};
%
\node (g env) [box, fit=(W1) (fake1),
pin={[text width=1cm,pin distance=10mm]left:global env}]
{ };
%
\path ([yshift=-20mm]W1.east)pic{two dots=w1fun}
(w1fun) edge [<-, to path={|- (\tikztotarget)}] (W1.east);
%
\node [below=of w1fun-left, align=left] {parameters: n \\ body: \dots}
edge [<-] (w1fun-left.center);
\path (w1fun-right.center) edge[->,to path={-| (\tikztotarget)}]
(node cs:name=g env,angle=183);
\foreach \angl/\idx in {185/6, 195/5, 345/4, 355/3, 357/2, 358/1}
{
\draw (node cs:name=g env,angle=\angl) node [rectangle, draw] (fake2-\idx) {};
\node (E\idx-env) [below=5mm of fake2-\idx,box,
pin={[pin distance=5mm]left:E\idx}] {n:\idx}
edge [->] (fake2-\idx);
\node (E\idx-code) [below=5mm of E\idx-env, align=center]{
(* \idx \hskip5pt (factorial \pgfmathparse{int(\idx - 1)}\pgfmathresult))
};
};
\end{tikzpicture}
\end{document}
这不是一个“最小”的例子,但 \foreach 中的代码才是重要的。
这里发生了什么:
- (g env) 节点就是这个宽浅的矩形。
- 我正在使用 \angle 和 \idx 变量来 -- 查找“锚点”节点的位移。 -- 更改“附加”节点的名称。 -- 计算示例代码中索引的值
我不喜欢这里:
- \pgfmathparse 。我似乎做错了什么。我尝试使用 ($$) 构造,但失败了。有没有比直接使用 \pgfmathparse 更好的方法来查找索引的值?
- 角度。$$sin(x) != x$$,所以我无法为循环设置一个常规范围。有没有办法以惯用的方式等距设置节点?
答案1
等距定位通过语法很容易实现pos
。在
foreach \idx in {1,...,6}
{
node [pos=\idx/7.5-1/7.5,rectangle, draw] (fake2-\idx) {}
node (E\idx-env) [below=5mm of fake2-\idx,box,
pin={[pin distance=5mm]left:E\idx}] {n:\idx}
edge [->] (fake2-\idx)
node (E\idx-code) [below=5mm of E\idx-env, align=center]{
(* \idx \hskip5pt (factorial \the\numexpr\idx-1))
}
};
节点的位置为\idx/7.5-1/7.5
,因此等距。对于整数,可以使用\the\numexpr
,这样就可以去掉\pgfmathparse
。
\documentclass[tikz,border=3mm]{standalone}
\usetikzlibrary{positioning,fit,petri,arrows,backgrounds}
\begin{document}
\begin{tikzpicture}[inner sep=0mm,>=stealth',very thick,color=black!50,
background rectangle/.style={fill=black},show background rectangle,
font=\sffamily,pics/two dots/.style={code={
\node [draw,minimum size=5mm,circle,colored tokens={black!50}]
(#1-left) {};
\node [draw,minimum size=5mm,circle,colored tokens={black!50},
right=0pt of #1-left]
(#1-right) {};
\node [rectangle, fit=(#1-left) (#1-right)] (#1){};
}},
every pin edge/.style={<-,very thick},
box/.style={draw,rectangle,inner sep=#1},box/.default=2mm]
%
\node (W1) {factorial:};
\node (fake1) [right=190mm of W1] {};
%
\node (g env) [box, fit=(W1) (fake1),
pin={[text width=1cm,pin distance=10mm]left:global env}]
{ };
%
\path ([yshift=-20mm]W1.east)pic{two dots=w1fun}
(w1fun) edge [<-, to path={|- (\tikztotarget)}] (W1.east);
%
\node [below=of w1fun-left, align=left] {parameters: n \\ body: \dots}
edge [<-] (w1fun-left.center);
\path (w1fun-right.center) edge[->,to path={-| (\tikztotarget)}]
(node cs:name=g env,angle=183);
\path (g env.south east) -- (g env.south west)
foreach \idx in {1,...,6}
{
node [pos=\idx/7.5-1/7.5,rectangle, draw] (fake2-\idx) {}
node (E\idx-env) [below=5mm of fake2-\idx,box,
pin={[pin distance=5mm]left:E\idx}] {n:\idx}
edge [->] (fake2-\idx)
node (E\idx-code) [below=5mm of E\idx-env, align=center]{
(* \idx \hskip5pt (factorial \the\numexpr\idx-1))
}
};
\end{tikzpicture}
\end{document}
请注意,我必须添加backgrounds
库并移动,\node (W1) {factorial:};
然后从 fit 中\node (fake1) [right=190mm of W1] {};
删除make withdraw
,以使代码编译。我还切换到类,standalone
因为图片对于常规文章来说有点太宽了。
答案2
编写图像的另一种方法:
- 首先使用循环在链中绘制“阶乘”节点
- 比绘制其他节点
\documentclass[tikz, margin=3mm]{standalone}
\usetikzlibrary{arrows.meta,
backgrounds,
chains,
fit,
petri,
positioning}
\begin{document}
\begin{tikzpicture}[
> = Stealth,
font = \small\sffamily,
thick,
color=gray!50,
inner sep = 0pt,
%
background rectangle/.style={fill=black}, show background rectangle,
%
PN/.style = {place, minimum size=5mm, colored tokens={gray!50}},
pics/two dots/.style = {code={
\node [PN] (#1-left) {};
\node [PN, right=0pt of #1-left] (#1-right) {};
\node [fit=(#1-left) (#1-right)] (#1) {};
}},
%
every pin/.style={pin edge={<-, thick, gray!50}, align=left},
box/.style = {draw, inner sep=#1},
box/.default = 2mm,
%
node distance = 4mm and 2mm,
start chain = going left
]
\foreach \x [count=\xx from 0] in {1,...,6}
{
\node (f\x) [on chain] {(*\,\x\,(factorial \xx))};
\node (n\x) [box,
pin=left:E\x,
above=of f\x] {n\x};
\draw[->] (n\x.north) -- ++ (0,4mm) coordinate (p\x);
}
%
\pic at ([shift={(-22mm,2mm)}] f6.north west) {two dots=PN}; % PN: petri net
\node (factorial) [above left=of PN.west |- p6] {factorial:};
\node[draw, inner sep=1mm, shift={(-1mm, 1mm)},
pin=left:global\\ env,
fit=(factorial) (p1)] {};
\draw[->] (factorial) -| (PN);
\draw[->] (PN-right.center) -| ([xshift=3mm] PN.east |- p6);
\draw[->] (PN-left.center) -- ++ (0,-1)
node[below, align=left] {parameters: n\\
body: \dots};
\end{tikzpicture}
\end{document}
答案3
除了上面给出的两个优秀的解决方案之外,还有一个可能有用。
(我只写了负责实际定位的部分。)
\coordinate(g env south west) at (g env.south west);
\coordinate(g env south east) at (g env.south east);
\node (barycentric cs:g env south west=2,g env south east=8) {debug};
可以用 来计算权重的值\mathexpr
。