以下示例绘制了三个矩形,每个矩形分为两部分(它们是 Lisp cons 单元)。它工作正常,但似乎有些不对劲:我在宏\begin{scope}
内部使用了\cons
,并且在该宏内部我有两个名为a
和 的节点b
。但是,如果我在宏外部使用名称 和 ,事情就会变得混乱。这两个名称和 不应该a
对文档的其余部分不可见吗?b
a
b
\begin{scope}
该示例运行良好,但更改aa
为a
等则会暴露问题。
有没有更好或更简单的方法来完成我想做的事情?
更新:所以,名称无论如何都是全局定义的……我想\cons
在同一张图片中多次使用宏——如果节点名称是全局的,这似乎行不通。那我该怎么办?我应该只使用相对定位而不给节点任何名称吗?这是唯一的方法吗?
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes,positioning}
\begin{document}
\newcommand{\cons}{%
\begin{tikzpicture}[cell/.style={draw,shape=rectangle,minimum size=0.4cm}]
\begin{scope}
\node[cell](a)[anchor=west]{};
\node[cell](b)[right=0mm of a.east,anchor=west]{};
\end{scope}
\end{tikzpicture}
}
\begin{tikzpicture}
\node(aa){\cons};
\node(bb)[below left=of aa]{\cons};
\node(cc)[below right=of aa]{\cons};
\draw[->,red] (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}
答案1
您可以使用现成的多部分节点形状。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}
\begin{document}
\begin{tikzpicture}[twocell/.style={draw,
rectangle split,
rectangle split horizontal,
rectangle split parts=2
}
]
\node[twocell](aa){};
\node[twocell](bb)[below left=of aa]{};
\node[twocell](cc)[below right=of aa]{};
\draw[->,red] (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}
答案2
杰伊,我不会回答你最初的问题,因为 Percusse 已经回答了,但是你在评论中提出了一个问题:如何让 cons 变圆角。
(我不确定是否应该在那里提出“关注”问题并回答。让我们看看版主怎么看)
正如 Percusse 所建议的,解决方案很棘手。您可以使用未绘制的多部分矩形,并使用append after command
选项在每个部分上绘制圆角矩形。在这里,您将找到使用此选项的几个答案。特别是,我从中获取了代码向简单的 TikZ 图表添加新符号和“命令后附加”和“插入路径”的问题。我不明白为什么命令\pgfextra
是必要的,但它确实有效。
下面是:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}
\begin{document}
\begin{tikzpicture}[%
cons/.style={%
rectangle split,%
rectangle split horizontal,%
rectangle split parts=2,%
outer sep=0pt,%
append after command={%
\pgfextra{%
\draw[rounded corners=3pt] (\tikzlastnode.south west)
rectangle (\tikzlastnode.one split north);%
\draw[rounded corners=3pt] (\tikzlastnode.north east)
rectangle (\tikzlastnode.one split south);}}}]
\node[cons](aa){};
\node[cons](bb)[below left=of aa]{};
\node[cons](cc)[below right=of aa]{};
\draw[->,red] (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}
答案3
append after command
由于使用without ,因此可以简化代码pgfextra
。
您需要使用path
选项创建一个draw
,然后使用选项将节点添加到路径中cons
。使用此方法,您可以避免使用\draw
内部“在命令后附加” 。
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}
\begin{document}
\begin{tikzpicture}[%
cons/.style={%
rectangle split,%
rectangle split horizontal,%
rectangle split parts=2,%
outer sep=0pt,%
append after command={%
[rounded corners=3pt] (\tikzlastnode.south west) rectangle (\tikzlastnode.one split north)
(\tikzlastnode.north east) rectangle (\tikzlastnode.one split south)
}}]
\path [draw] node[cons](aa){};
\path [draw] node[cons](bb)[below left=of aa]{};
\path [draw] node[cons](cc)[below right=of aa]{};
\draw[->,red] (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}
答案4
针对 Ignasi 所说的他不知道\pgfextra
是什么,它会暂停路径解析或跟踪,以便可以执行任意代码。否则,这是有风险的或不可能的。我在下面演示了任意代码的使用。
经过长时间的跟踪,我发现使用时\pgfextra
必须避免使用虚假空格,例如 后面的空格\pgfextra{
。这些空格不会在内部被删除。Ignasi 在他的解决方案中正确地做到了这一点,但很容易被忽视。我希望 PGF 开发人员稍后会在内部处理这个问题。与此同时,当\pgfextra
的参数出现时at end node
,可以使用以下解决方案。
编辑:我在下面提供完整的代码以回应 Altermundus 的评论。
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.multipart,positioning}
\makeatletter
% If we load pgfkeyx.sty, we can normalize the list before parsing.
% Well, let's ignore difficult lists here.
% Using the delimiter \pgfeov for the callback of \pgfkeyscommaloop allows it
% to be multi-parametered.
\def\pgfkeyscommaloop#1#2{\pgfkeys@commaloop{#1}#2,\pgfkeyscommaloop,}
\def\pgfkeys@commaloop#1#2,{%
\expandafter\ifx\@car#2x\@nil\pgfkeyscommaloop
\expandafter\@gobble\else\expandafter\@iden\fi
{#1#2\pgfeov\pgfkeys@commaloop{#1}}%
}
\def\ifpgfkeydef#1{%
\ifcsname pgfk@#1/.@cmd\endcsname
% OK, the command is already in the hash table; no safeguard needed
% against filling the hash.
\expandafter\ifx\csname pgfk@#1/.@cmd\endcsname\relax
\expandafter\expandafter\expandafter\@secondoftwo
\else
\expandafter\expandafter\expandafter\@firstoftwo
\fi
\else
\expandafter\@secondoftwo
\fi
}
\def\pgfkey@def@do#1\pgfeov{\ifpgfkeydef{#1}{-1}{+0}}
\def\pgfkey@undef@do#1\pgfeov{\ifpgfkeydef{#1}{+0}{-1}}
% Given a list of keys, I want to know if at least one of them is defined:
\def\ifonepgfkeydef#1{%
\ifnum\numexpr\z@\pgfkeyscommaloop\pgfkey@def@do{#1}<\z@
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
% Given a list of keys, I want to know if at least one of them is undefined:
\def\ifonepgfkeyundef#1{%
\ifnum\numexpr\z@\pgfkeyscommaloop\pgfkey@undef@do{#1}<\z@
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\ifonepgfkeydef{/tikz/at end of node,/tikz/at end node}{%
\@latexerr{Key(s) '/tikz/at end of node' and/or
'/tikz/at end node' already exist}\@ehd
}{}
% The following acrobatics is just an academic exercise: Altermundus's approach
% is simpler and better:
\tikzset{at end of node/.code=
\begingroup
\def\pgf@@relax{\relax}%
\pgfkeys@spdef\reserveda{#1}%
\def\reservedb##1\pgfextra##2##3\pgf@nil{%
\ifx\pgf@@relax##2\else
\pgfkeys@spdef\reservedb{##2}%
\def\reservedc##1\pgfextra\pgf@@relax{##1}%
\edef\reserveda{\unexpanded{##1}\noexpand\pgfextra{\unexpanded
\expandafter{\reservedb}}\unexpanded\expandafter{\reservedc##3}}%
\fi
}%
\expandafter\reservedb\reserveda\pgfextra\pgf@@relax\pgf@nil
\edef\reserveda{\endgroup
\noexpand\pgfkeysalso{append after command=%
{\unexpanded\expandafter{\reserveda}}}%
}\reserveda
,
at end node/.style={at end of node={#1}}
}
\def\minorrect#1#2#3{%
\draw[rounded corners=#1] (\tikzlastnode.#2)
rectangle (\tikzlastnode.one split #3);
}
\makeatother
\begin{document}
\begin{tikzpicture}[cons/.style={%
rectangle split,
rectangle split horizontal,
rectangle split parts=2,
outer sep=0pt,
at end of node={
\pgfextra{
\minorrect{3pt}{south west}{north}%
\minorrect{10pt}{north east}{south}%
}%
}%
}%
]
\node[cons](aa){};
\node[cons](bb)[below left=of aa]{};
\node[cons](cc)[below right=of aa]{};
\draw[->,red] (aa.west) -| (bb.north);
\draw[->,blue] (aa.east) -| (cc.north);
\end{tikzpicture}
\end{document}