这是关于 TikZ 路径上选项、pdfextra 代码和其他元素的执行顺序的第三篇也是最后一篇帖子。其他帖子是这和这。
请考虑以下 LaTeX 手稿
\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\def\x{outside}
\path[draw=blue,font=\Huge]
\pgfextra{ \def\x{inside}
\draw (2,2) circle(5pt)
node[anchor=south west]{xtra};}
(0,0) node[draw] {\x}
;
\end{tikzpicture}
\end{document}
手稿中有一张 TikZ 图片。图片内部执行的第一个操作是将 TeX 宏定义\x
为字符串“outside”。然后定义一个 TikZ 路径,其中包含两个选项:绘制颜色设置为“blue”,字体大小设置为“\Huge”。路径由两个元素组成:(1)一个\pgfextra
块。该块将宏重新定义\x
为字符串“inside”。然后它绘制一个圆圈,旁边是一个显示文本为“xtra”的节点。(2)显示文本为\x
替换文本的节点。绘制节点的轮廓。
本稿排版如下:
请注意,路径的font
选项既适用于\pdfextra
代码也适用于节点,但draw
选项仅适用于节点。为什么?
回答这个问题的一个可能的理论是,无论出于什么原因,代码按以下顺序执行:1.font
选项,2. \pdfextra
,3.draw
选项,4.节点。
\pgfextra
让我们通过将元素移动到节点后面来测试这个理论:
\path[draw=blue,font=\Huge]
(0,0) node[draw] {\x}
\pgfextra{ \def\x{inside}
\draw (2,2) circle(5pt)
node[anchor=south west]{xtra};}
;
我期望节点的显示文本为“外部”,圆的描边颜色为蓝色。然而,我只猜对了一部分:
答案1
如果你查看源代码,你会发现在路径上遇到tikz.code.tex
时执行的代码的定义:\pgfextra
\def\tikz@extra{\pgfutil@ifnextchar\bgroup\tikz@@extra\relax}
\long\def\tikz@@extra#1{#1\tikz@scan@next@command}
\let\endpgfextra=\tikz@scan@next@command
基本上,任何参数都会\pgfextra
立即执行,扫描继续。不会保存或恢复任何图形或字体属性。
当执行如下操作时:
\path [...properties1...] ... \pgfextra { \path [] ...; };
已设置的任何属性properties1
可以不可以影响内部的路径\pgfextra
。这取决于属性、何时设置、是否全局设置,以及可能还有一些我没有想到的其他事情。
考虑基本节点字体(即用于排版节点的字体)。它存储在\tikz@textfont
全局中,并最初(有效地)分配如下:
\let\tikz@textfont=\pgfutil@empty
因此它不包含任何值。这意味着节点中的任何文本都将采用文档字体。当font
使用键时(例如font=\Huge
),将执行以下键:
\tikzoption{font}{\def\tikz@textfont{#1}}
现在,\tikz@textfont
包含\Huge
并且任何没有特定字体的节点都将使用此值在当前范围内。当font
在节点中使用键时,其值将“保留”到节点结束。但是当font
在路径中使用键时,其值将保留到路径结束。任何未指定字体的节点都应采用此值。但是,对于嵌入在路径中的树或图形等内容,这种情况可能会发生,也可能不会发生(如果它们设置了范围并重置了字体,则可能不会)。
这仅适用于字体。线条宽度、颜色等可能有所不同。PGF 已实施多年,参与人员也各不相同。由于以下原因,可能会存在一些一致性,也可能存在一些不一致性:
- 特定功能需要不同的功能
- 对应该发生的事情有强烈的感觉
- 对已经发生的事情的误解
- 我还没有想到的其他一些事情
最重要的是这些都不重要。
首先,\pgfextra
它不是为任意代码设计的。它会立即执行,而不会考虑图形或字体属性可能发生或不会发生什么。特别是,随意地塞入内部\path
而不\pgfextra
使用\pgfinterruptpath
会导致未定义的行为,在这种情况下,一致性的期望有点令人困惑。
其次,即使\pgfinterruptpath
使用了,并且一些属性是继承的而一些属性不是,明确地设置内部任何路径的属性\pgfextra
并不难,特别是因为多个属性可以与样式绑定。
答案2
以下示例说明了为什么您的问题几乎总是无法用简单的参数来回答。此示例具有扩展延迟,因此我们在放置节点后会更改其颜色。这在通常的语法中是不可能的,但在滥用和黑客攻击下却有可能。
\documentclass{article}
\usepackage{tikz}
\def\mymacro{\expandafter\global\expandafter\let\expandafter\pgfsavedstrokecolor\csname\string\color@pgfstrokecolor\endcsname}
\begin{document}
\begin{tikzpicture}
\path[draw=blue,font=\Huge]
\pgfextra{
\def\x{inside}\mymacro\show\pgfsavedstrokecolor% <-- look at the log it's black again
\expandafter\show\csname tikz@strokecolor\endcsname% <-- this one is still blue
\draw (2,2) circle(5pt)%
node[draw,anchor=south west]{xtra}
% we'll change the color of the node above to red with the next line!!
\pgfextra{\csname tikz@addoption\endcsname{\pgfsetstrokecolor{red}}}
node[draw]{xtra2}; %<-- draws red
}
(0,0) node[draw] {\x};
\end{tikzpicture}
\end{document}
除了这个黑魔法之外,如果你注释掉最后一个,\pgfextra
它们都是不是蓝色而是黑色。不是因为一个 bug!但因为我们的 hack 省略了一半正常工作所需的宏。这就是你一直在做的事情,而且让你感到困惑。有太多宏需要设置/重置来模仿 TikZ 行为。
总之,如果不采取极端预防措施(例如适当的 TeX 组和扩展控制),您就不能指望事情在低级别上正常工作。这就是 TikZ 前端的整个想法,这样您就不需要自己做这些了。在路径中间暂停并做一些不平凡的事情需要 TeX 知识,这通常超出了我的能力范围,并且需要正确的 PDF 文字顺序。否则,您会得到如上所述的巫术魔法。
简而言之,事情并不是那么简单的理论,正如评论所说,直到最后事情才完全展开,才有执行顺序。