我正在使用新的 TikZ/PGF 3.0pic
功能。我大量使用它们,包括在另一张图片中使用一张图片。问题是 Tikz 有时找不到嵌套图片的节点名称。
我期望以下操作能够起作用:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}
\tikzset{complex/.pic={
\node(re) {re};
\node[right=0mm of re](im) {im};
}}
\tikzset{su3v/.pic={
\path pic(c0) {complex};
\path pic[right=1mm of c0im](c1) {complex};
\path pic[right=1mm of c1im](c2) {complex};
}}
\tikzset{spinor/.pic={
\path pic(v0) {su3v};
\path pic[below=2mm of v0c2re](v1) {su3v};
\path pic[below=2mm of v1c2re](v2) {su3v};
\path pic[below=2mm of v2c2re](v3) {su3v};
}}
\path pic {su3v}; % Works
\path pic(name) {su3v}; % ! Package pgf Error: No shape named namec0im is known.
\path pic {spinor}; % ! Package pgf Error: No shape named v0c1im is known.
\end{tikzpicture}
\end{document}
这里有什么问题?
答案1
我要去漏洞在这一点上。
绘制 时pic
,可以使用子节点(和坐标)。如果为 outerpic
指定了名称,则该名称将作为前缀传递给所有子节点(和坐标)。这是一件好事,因为这意味着您不会冒名称冲突的风险。您正在嵌套pic
s,因此名称应该累积。我们可以将嵌套和命名绘制为一棵树,说明應該发生。name
是当前 的名称pic
,prefix
是所有 的指定前缀子图片。
pic {su3v}; <no prefix> <no name>
|
-- pic (c0) {complex} c0 c0
|
-- node (re) {re} c0re
-- node (im) {im} c0im
pic (name) {su3v}; name name
|
-- pic (c0) {complex} namec0 namec0
|
-- node (re) {re} namec0re
-- node (im) {im} namec0im
pic {spinor}; <no prefix> <no name>
|
-- pic (v0) {su3v} v0 v0
|
-- pic (c0) {complex} v0c0 v0c0
|
-- node (re) {re} v0c0re
-- node (im) {im} v0c0im
(对于那些不熟悉这一点的人来说,我们的想法是,要引用节点,我们使用全名减去当前前缀。所以在里面su3v
我们可以像你一样引用c0im
和c1im
,即使su3v
被命名或在里面使用spinor
。)
现在,我说的是應該发生。它没有。实际上发生的是,当 apic
开始时,然后name prefix
有現在全名设置它是前缀。也就是说,本身name prefix
有一个前缀,并且该前缀是满的当前的名称pic
。关键是该名称具有已经附加了自己的前缀。
因此,当嵌套pic
s 时,会发生以下情况。第一个命名的pic
,我们称之为outer
,将 的前缀设置name prefix
为其名称,在本例中为outer
。因此,每当name prefix
被调用时,outer
都会将 添加到其值的前缀中。在 内部outer
,我们假设有另一个pic
,比如inner
。由于这在 内部outer
,因此其真实名称为outerinner
。name prefix
的前缀设置为此,但name prefix
其本身保留其 的值outer
。因此有效name prefix
的是outerinnerouter
。因此实际的树如下:
pic {su3v}; <no prefix> <no name>
|
-- pic (c0) {complex} c0 c0
|
-- node (re) {re} c0re
-- node (im) {im} c0im
pic (name) {su3v}; name name
|
-- pic (c0) {complex} namec0name namec0
|
-- node (re) {re} namec0namere
-- node (im) {im} namec0nameim
pic {spinor}; <no prefix> <no name>
|
-- pic (v0) {su3v} v0 v0
|
-- pic (c0) {complex} v0c0v0 v0c0
|
-- node (re) {re} v0c0v0re
-- node (im) {im} v0c0v0im
此时我应该提到一个有用的诊断。这是将以下内容放入您的序言中:
\makeatletter
\tikzset{show fig name/.code={\tikz@addmode{\message{Fig name is: |\tikz@fig@name|}}}}
\makeatother
然后show fig name
在各种元素上使用该键。
我想这一点是如果你手动然后name prefix
你想保留它并附加所有自动前缀。如果你从不这样做,一个解决方法是将代码复制\def\tikz@subpicture@handle@
到你的序言中(在强制\makeatletter .. \makeatother
配对之间)并更改
\ifx\tikz@fig@name\pgfutil@empty\else%
\tikzset{name prefix/.prefix/.expanded=\tikz@fig@name}%
\fi%
到
\ifx\tikz@fig@name\pgfutil@empty\else%
\tikzset{name prefix/.expanded=\tikz@fig@name}%
\fi%
更好的解决方案是,不使用\tikz@fig@name
,而是使用已声明名称(目前尚未保存 - 前缀和后缀是在节点/图片/坐标首次命名时添加的)并将其添加为后缀到字首至name prefix
。也就是说,关键的一行可能是:
\tikzset{name prefix/.prefix/.suffix/.expanded=\tikz@fig@declaredname}
而name
密钥必须是:
\tikzset{
name/.code={\edef\tikz@fig@name{\tikz@pp@name{#1}}\edef\tikz@fig@declaredname{#1}}%
}
不幸的是,嵌套/.prefix/.suffix
不起作用,因此必须等待 PGF 人员找出一个好的解决方案才能进行适当的修复。与此同时,如果您从不调用name prefix
自身,那么修改\tikz@subpicture@handle@
似乎有效。
但没有保证。
其实,我刚刚想到了一个替代解决方案。那就是放 name prefix/.prefix
到 ,\tikz@fig@name
就像原始代码一样,但随后 会自行清除,name prefix
因为无论当前name prefix
是什么,它都已在 中考虑在内\tikz@fig@name
。进一步调用name prefix
将保持前缀 到 的name prefix
预期。
此外,我将此问题提交到 PGF 错误列表并附有此处的链接。