从 GraphViz 过渡到 TikZ 让我很头疼......
我的任务是生成以下各种流程图:
具体来说,我需要一种方法来定位共享边界的节点(最好与它们的宽度和高度无关),同时遵循网格。解释如何绘制表示节点分组的括号,以及如何绘制端点不重合(最好不指定精确坐标或角度)或与特定列对齐的正交箭头(如箭头)可获得额外加分load -> add
。
答案1
主要请求有三点:
一种定位共享边界的节点的方法。这里的一种可能性是使用键
node distance
和positioning
库。例如:\documentclass{standalone} \usepackage{tikz} \usetikzlibrary{positioning} \begin{document} \begin{tikzpicture}[every node/.style={draw}] \node (a) {A}; \node[right=of a] (b) {B}; \node[right=of b] (c) {C}; \begin{scope}[yshift=-1cm,node distance=-\pgflinewidth,every node/.append style={fill=blue!20}] \node (a) {A}; \node[right=of a] (b) {B}; \node[right=of b] (c) {C}; \end{scope} \end{tikzpicture} \end{document}
如何绘制端点不重合(最好不指定精确的坐标或角度)或与特定列对齐的正交箭头。这里的主要工具是垂直坐标系的隐式语法。表达式
( p |- q )
或( q -| p )
。例如,(0,1 |- 2,3)
和(2,3 -| 0,1)
都产生与 相同的结果(0,3)
;以下示例展示了此语法的实际应用:\documentclass{standalone} \usepackage{tikz} \begin{document} \begin{tikzpicture} \node at (0,0) (a) {A}; \node at (2,2) (b) {B}; \node at (4,-1) (c) {C}; \node at (4,-2) (d) {D}; \draw[red] (a) |- (b); \draw[blue] (a) -| (b); \draw[green] (c) -- (a|-c) -- (a|-d) -- (d); \end{tikzpicture} \end{document}
如何绘制表示节点分组的括号。这里的想法是使用装饰;特别是库
brace
提供的装饰decorations.pathreplacing
。一个小例子:\documentclass{standalone} \usepackage{tikz} \usetikzlibrary{decorations.pathreplacing} \begin{document} \begin{tikzpicture} \node (a) {A}; \node at (2,2) (b) {B}; \node at (4,0) (c) {C}; \draw[decorate,decoration=brace] (a) -- (b); \draw[decorate,decoration=brace] (b) -- (c); \draw[decorate,decoration={brace,mirror}] (a) -- (c); \end{tikzpicture} \end{document}
结合这些想法,再定义一些节点的样式,就可以生成原始图表了。完整代码:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{calc,positioning,arrows,decorations.pathreplacing}
\definecolor{myblue}{RGB}{170,223,249}
\begin{document}
\begin{tikzpicture}[
>={stealth'},
every node/.style={node distance=-\pgflinewidth},
exx/.style={rectangle,draw,fill=gray!30,text width=0.9cm,align=center,font=\ttfamily},
sblue/.style={rectangle,rounded corners,draw,fill=myblue,text width=1.25cm,
align=center,text height=9pt,text depth=3pt,font=\sffamily},
mtext/.style={text width=4cm,align=left,text height=9pt,text depth=3pt,font=\ttfamily}
]
% the upper eax,..., edx nodes
\node[exx] (eax) {\%eax};
\node[exx,right= of eax] (ebx) {\%ebx};
\node[exx,right= of ebx] (ecx) {\%ecx};
\node[exx,right= of ecx] (edx) {\%edx};
% the vertical blue nodes
\node[sblue,below right = 10pt of edx] (sadd) {s\_addr};
\node[sblue,below = of sadd] (sdata) {s\_data};
\node[sblue,below = of sdata] (load) {load};
\node[sblue,below = of load] (add) {add};
\node[sblue,below = of add] (sub) {sub};
\node[sblue,below = of sub] (jne) {jne};
% some vertical nodes to place text to the right of the blue nodes
\node[mtext,right = 20pt of sadd] (tsadd) {};
\node[mtext,below = of tsadd] (tsdata) {};
\node[mtext,below = -9pt of tsadd] {movl \%eax,(\%ecx)};
\node[mtext,right = 20pt of load] (tload) {movl (\%ebx),\%eax};
\node[mtext,below = of tload] (tadd) {addl \$1,\%eax};
\node[mtext,below = of tadd] (tsub) {subl \$1,\%edx};
\node[mtext,below = of tsub] (tjne) {jne loop};
% the lower eax,..., edx nodes
\node[exx,below left = 10pt of jne] (edx1) {\%edx};
\node[exx,left= of edx1] (ecx1) {\%ecx};
\node[exx,left= of ecx1] (ebx1) {\%ebx};
\node[exx,left= of ebx1] (eax1) {\%eax};
% the straight lines with arrow tips
\draw[->] (eax) |- (sdata);
\draw[->] (ebx) -- (ebx1);
\draw[->] (ecx) -- (ecx1);
\draw[->] (edx) |- (sub.170);
\draw[->] (sub.190) -| (edx1);
\draw[*->] (ecx|-sadd) |- (sadd);
\draw[*->] (ebx|-load.170) |- (load.170);
\draw[->] (load.190) -- (eax|-load.190) -- (eax|-add.170) -- (add.170);
\draw[->] (add.190) -| (eax1);
% the curved arrows
\draw[->] (sadd.355) to[out=-30,in=30] (sdata.5);
\draw[->] (sadd.0) to[out=-30,in=30] (load.350);
\draw[->,dashed] (sdata.355) to[out=-30,in=30] (load.5);
\draw[->] (sub.0) to[out=-30,in=30] (jne.0);
% the brace
\draw[decorate,decoration=brace] ( $(sadd.north)!.35!(tsadd.north) $ ) -- ( $(sdata.south)!.35!(tsdata.south) $ );
\end{tikzpicture}
\end{document}