TiKz 3.0 推出了pics
,我很喜欢它们,但它们似乎没有我希望的那么强大。例如,我无法使用这样的嵌套图片:
\tikzset{
one/.pic = {\draw[pic actions] (0,0) -- (1,1);},
two/.pic = {\path pic[pic actions]{one};}
}
\begin{tikzpicture}
\path pic[ultra thick, red]{one};
\path pic[thin]{two};
\end{tikzpicture}
这是一个错误吗,或者这只是图片的工作方式?
没有错误消息。简单地说 (Xe/PDF)LaTeX 没有完成工作。
编辑 :按照 Mark Wibrow 的评论,如果我们删除pic actions
它pic{two}
,则会起作用:
\tikzset{
one/.pic = {\draw[pic actions] (0,0) -- (1,1);},
two/.pic = {\path pic{one};}
}
\begin{tikzpicture}
\path pic[ultra thick, red]{one};
\path pic[thin, blue]{two};
\end{tikzpicture}
因此问题似乎出在内部pic actions
。
答案1
我刚刚遇到这个问题,它似乎仍然是 2023 年 TikZ(PGF 版本 3.1.10)的一个问题。
深入挖掘代码,我们发现:
pic actions
扩展为\tikz@addmode{\tikz@picmode}
附加\tikz@picmode
到宏的\tikz@mode
。- 但是当 TikZ 遇到时,它
pic
会做的是\let\tikz@picmode=\tikz@mode
。\tikz@picmode
内容外部图片的\tikz@mode
。
因此,嵌套 pic
,我们有以下旅程:
在最外层,
\tikz@mode
包含对路径执行什么操作的指令(例如,绘制还是填充)。当 TikZ 遇到第一张图片时,
\tikz@picmode
会被设置为这个,所以现在包含这些指令。 在 内pic
,\tikz@mode
会被清除。现在我们调用
pic actions
附加\tikz@picmode
到的\tikz@mode
,所以\tikz@mode
现在由(至少)组成\tikz@picmode
(可能还有其他内容添加到其中)。我们想要一个嵌套的图片,所以让 TikZ 遇到另一个
pic
。它的别名\tikz@mode
为\tikz@picmode
,这意味着\tikz@picmode
现在由(至少)组成\tikz@picmode
。这就是我们的问题。这是老
\def\a{\a}\a
问题了。\tikz@picmode
包含对自身的引用,因此当它(最终)被调用时,它会进入无限循环。
一个可能的解决方案(可能会引入其他问题,但至少解决了这个问题)是添加一个扩展步骤,这样当\tikz@picmode
附加到\tikz@mode
时,它实际上是内容的\tikz@picmode
附加到\tikz@mode
。这避免了无限递归。
所以pic actions
应该是:
\makeatletter
\tikzset{
pic actions/.code=\expandafter\tikz@addmode\expandafter{\tikz@picmode}
}
\makeatother
在我自己的代码中,我目前正在调用这个,sub pic actions
因为我不喜欢破坏 TikZ 版本的东西,即使我认为我有改进。
\documentclass{article}
%\url{https://tex.stackexchange.com/q/215580/86}
\usepackage{tikz}
\makeatletter
\tikzset{
sub pic actions/.code=\expandafter\tikz@addmode\expandafter{\tikz@picmode}
}
\makeatother
\tikzset{
working demo/.pic={
\pic[sub pic actions] {demo sub};
},
not working demo/.pic={
\pic[pic actions] {demo sub};
},
demo sub/.pic={
\path[pic actions] (0,0) to[out=30,in=180] ++(1.5,.5) -- ++(0,.5) -- ++(.3,0) -- ++(0,-.5) to[out=0,in=150] ++(2.5,-.5) to[out=210,in=-30] (0,0);
}
}
\begin{document}
\begin{tikzpicture}
\pic[draw] {
%not
working demo};
\end{tikzpicture}
\end{document}
答案2
我在这里给出我对这个问题的部分了解。
免责声明
我不是专家,我在这里写的大部分内容都是猜测。
先决条件
有些样式从范围继承到路径,有些则不继承。有些样式从节点和图片的路径继承到路径,有些则不继承。
我不知道确切的规则是什么,但我认为唯一不能被继承的风格是“动作”(正如我们在有关图片动作的文档中所读到的:“动作”是绘图、填充、着色和剪切或它们的任意组合)。
如何为图片添加造型
我不知道图片样式究竟是如何工作的,但我的调查(不是对代码的调查,因为正如我所说,我不是专家)让我找到了以下算法:
\tikzset{picname/.pic={the pic code}}
\pic[some style]{picname};
变成了类似
\begin{scope}[coordinate transform, every pic, some style]
the pic code
\end{scope}
这是过于简化的版本,因为有foreground code
等等background code
......
pic actions
当我们想要继承某些动作时,它很有用,比如说fill
从“某种风格”到内部路径“图片代码”. 并且这在文档中有详细记录。
“图片操作”的问题
问题是pic actions
,当我们用类似的东西来调查它时
\pgfkeysgetvalue{/tikz/pic actions/.@cmd}{\temp};
\wlog{\meaning\temp}
结果是
\long macro:#1\pgfeov ->\tikz@addmode {\tikz@picmode }
这不是我们观察到的某些“普通”风格,例如:
\long macro:#1\pgfeov ->\pgfkeysalso {fill}
pic actions
因此,这可能就是为什么使用嵌套图片失败的关键。
我认为pic actions
只能用于简单继承。但是仍然存在错误pic actions
,因为当您在嵌套图片中使用它时,latex 会冻结而不会引发错误。
当我们需要更复杂的继承时,我们需要使用一些样式,如下所示。
如何克服“图片操作”
下面是一个示例,说明如何创建具有复杂风格和真正复杂嵌套的复杂图片(其工作方式类似于@cfr 答案)。
\tikzset {
every cherry fruit/.style = {fill,red},
cherry fruit/.style={every cherry fruit/.append style={#1}},
every cherry stem/.style = {brown, ultra thick},
cherry stem/.style={every cherry stem/.append style={#1}},
every cherry leaf/.style = {fill, green},
cherry leaf/.style={every cherry leaf/.append style={#1}},
cherry/.pic = {
\draw[every cherry fruit] (0,0) {[rounded corners=1cm] -- (1,1) -- (2,-1) -- (0,-3) -- (-2,-1) -- (-1,1)} -- cycle;
\draw[bend left, every cherry stem] (0,0) to coordinate[pos=.7] (A) (1,2);
\draw[bend left, every cherry leaf] (A) to +(-1.5,1) to cycle;
},
every cherry one/.style={},
cherry one/.style={every cherry one/.append style={#1}},
every cherry two/.style={},
cherry two/.style={every cherry two/.append style={#1}},
two cherries/.pic = {
\pic[every cherry one]{cherry};
\pic[xshift=5cm, every cherry two]{cherry};
}
}
\begin{tikzpicture}
\pic[cherry fruit=yellow]{cherry};
\pic[xshift=5cm]{cherry};
\pic[yshift=-5cm, cherry fruit={fill=none, draw, ultra thick}, cherry one={cherry fruit=yellow}]{two cherries};
\end{tikzpicture}
答案3
您可以将所需的选项作为参数传递给two
:
\documentclass[tikz, border=5pt]{standalone}
\tikzset{
one/.pic = {\path[pic actions] (0,0) -- (1,1);},
two/.pic = {\path pic[#1]{one};}
}
\begin{document}
\begin{tikzpicture}
\path pic[ultra thick, red, draw]{one};
\path pic{two={thin, blue, draw}};
\end{tikzpicture}
\end{document}
由于我不确定您如何使用它,所以我不确定这是您已拒绝的选项、尚未拒绝但现在必须拒绝的选项,还是可能有用的选项。