环境扩展和 Tikz 外部库的问题。

环境扩展和 Tikz 外部库的问题。

我创建了自己的环境mytikz,它基本上看起来像这样(完整的 MWE):

\documentclass[a4paper]{article}

\usepackage{tikz}
\usetikzlibrary{external}

\newenvironment{mytikz}{%begin code
    \begin{figure}[htp]
    \centering
    \begin{tikzpicture}%
}%
{%end code
    \end{tikzpicture}
    \caption{}
    \end{figure}%
}

\tikzexternalize

\begin{document}

\begin{mytikz}
    \draw(0,0) circle (1cm);
\end{mytikz}

\end{document}

问题是我想使用 TikZ 的external库,这样我就可以加快文档的构建时间。这是不可能的,因为环境的结束代码不会及时扩展,以便 TikZ 找到它\end{tikzpicture}正在寻找的内容。因此我收到以下错误:

! File ended while scanning use of \tikzexternal@laTeX@collect@until@end@tikzpicture.

有没有办法让我的结束代码更早地展开,这样 TikZ 就可以找到它?我试过使用这个environ包,但这降低了命令的可用性newenvironment(我的实际新环境有点复杂,使用\newenvironmentx这个xargs包)。

答案1

困难在于,外部化库要\end{tikzpicture}确定它正在“外部化”的图片的结尾。它这样做无扩展所以\end{tikzpicture}必须出现同时作为\begin{tikzpicture}。这就是为什么:

\newenvironment{mytikz}{\begin{tikzpicture}}{\end{tikzpicture}}

不起作用。当输入

\begin{mytikz}
\node {hello world};
\end{mytikz}

然后\begin{mytikz}一直扩展到\begin{tikzpicture}(甚至超出),此时 TeX 开始吞噬东西。它遇到\end{mytikz}而不扩展它,因此永远不会意识到它就是\end{tikzpicture}它所寻找的。

环境软件包通过将环境转换为命令来解决这个问题。因此当 TeX\begin{mytikz}看到它会将其展开(完全展开,也就是说,它必须展开到足以知道它是使用包定义的程度environ),然后开始寻找\end{mytikz}。然后它将内容放入内部宏中,并将相应的代码转储到流中。这意味着当 TeX 最终看到时\begin{tikzpicture},正确的内容\end{tikzpicture}也已插入到流中的正确位置。

因此,我们希望保留此功能,但同时添加xargs包的参数处理功能。这里的技巧是意识到参数处理部分并不实际上必须与环境相连 - 它只是对用户来说看起来像它。(这在 TeX/LaTeX 命令中很常见。许多命令似乎带有参数,但实际上不执行任何操作。)如果我们使用 声明一个环境,那么在 之后\NewEnviron出现的任何内容\begin{myenv}都会被放入一个名为 的特殊宏中\BODY。也就是说,如果我们有:

\NewEnviron{myenv}{something first \BODY\ something last}

然后

\begin{myenv}
in the middle
\end{myenv}

在流中被替换something first in the middle something last(几乎……,我并不担心\par这里)。重点是这个效劳于

\begin{myenv}[some][optional]{or}{mandatory}[arguments]
in the middle
\end{myenv}

因为这样会产生something first [some][optional]{or}{mandatory}[arguments] in the middle something last。因此,如果something first恰好是宏,它将“看到”[some][optional]{or}{mandatory}[arguments]并认为它们是用于

这里的“几乎”实际上是放入流中的东西,something first \BODY\ something last所以我们需要\BODY先扩展才能得到参数。

综合以上所有,我们得到:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\usepackage{environ}
\usepackage{xargs}

\newcommandx{\startmytikz}[1][1=]{%
  \begin{figure}[htp]
  \centering
  \begin{tikzpicture}[#1]}

\NewEnviron{mytikz}{\expandafter\startmytikz\BODY
\end{tikzpicture}
\end{figure}}

\begin{document}
\tikzset{external/force remake=true}
\begin{mytikz}[every path/.style={red}]
\draw(0,0) circle (1cm);
\node {hello world};
\end{mytikz}
\end{document}

当然,如果愿意的话,可以将所有这些包含在一个定义中:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{external}
\tikzexternalize
\usepackage{environ}
\usepackage{xargs}

\newcommandx{\NewEnvironx}[5][2,3]{%
  \expandafter\newcommandx\csname start#1\endcsname[#2][#3]{#4}%
  \NewEnviron{#1}{\csname start#1\expandafter\endcsname\BODY #5}}

\NewEnvironx{mytikz}[1][1=]{%
  \begin{figure}[htp]
  \centering
  \begin{tikzpicture}[#1]}
{\end{tikzpicture}
  \end{figure}}

\begin{document}
\tikzset{external/force remake=true}
\begin{mytikz}[every path/.style={red}]
\draw(0,0) circle (1cm);
\node {hello world};
\end{mytikz}


\end{document}

相关内容