为什么 fixltx2e 与 tikzexternalize 不兼容

为什么 fixltx2e 与 tikzexternalize 不兼容

我遇到了一些奇怪的问题,tikzexternalize 有时会工作,有时不工作。我把问题缩小到 fixltx2e。这是一个 MWNE(最小不工作示例)

@ ALtermundus:是的,这是你的照片(不使用它实在是太好了 ;-)

\documentclass{article}

\usepackage{fixltx2e}

\usepackage{pgf}
\usepackage{tikz}
\usepackage{pgfplots}

\usetikzlibrary{calc}
\usetikzlibrary{external}
\tikzexternalize

\newcommand{\fancypicture}{ 
   % from http://altermundus.com/pages/tikz/tikz-examples/index.html
   \path  (0,0)       coordinate (A) 
          (-60:12cm) coordinate (B) 
          (240:12cm) coordinate (C);
    \foreach \density in {10,20,...,160}
        \draw[fill=blue!\density] 
          (A) coordinate  (X) -- (B) coordinate[pos=.15] (A) --
          (C) coordinate[pos=.15] (B) --
          (X) coordinate[pos=.15] (C);
}

\begin{document}

\begin{figure}[ht] %[!b!h!t]
  \centering
  \begin{tikzpicture}
    \fancypicture
  \end{tikzpicture}    
\end{figure}

\begin{figure}[ht] %[!b!h!t]
  \centering
  \begin{tikzpicture}
    \fancypicture
  \end{tikzpicture}    
\end{figure}

\begin{figure}[ht] %[!b!h!t]
  \centering
  \begin{tikzpicture}
    \fancypicture
  \end{tikzpicture}    
\end{figure}

\begin{figure}[ht] %[!b!h!t]
  \centering
  \begin{tikzpicture}
    \fancypicture
  \end{tikzpicture}    
\end{figure}

\end{document}

上述代码的奇怪之处在于:如果只插入两张图片,一切正常。只有绘制更多图片时,我怀疑这会触发 fixltx2e 中的某些修复,导致外部化失败。由于这很难追踪,我只是想知道 tikzexternalize 或 fixltx2e 是否还有更多这样的微妙之处。

答案1

问题似乎在于,fixltx2e重新定义的\@doclearpage方式不符合externalize库的要求:输出例程运行而不生成任何页面,编译停止。我猜,当只有两个图形时不会发生这种情况,因为它们适合放在一页上。

我认为除了不加载之外没有什么其他事情可做fixltx2e

答案2

更新:此问题现已在 PGF CVS 中修复,请参阅下面 Christian Feuersänger 的评论。


当 TikZ/PGF 进入外部化模式时,它仍会处理整个文档。它需要这样做以确保在处理当前正在处理的图片时处于正确的“状态”(即任何宏或样式或其他内容都与普通文档中一样)。这意味着它仍会经历构建页面和对浮动进行排序的过程,只是在最后一刻将其全部丢弃。

它确实做了一些优化。 里面的任何东西\includegraphics都可以安全地丢弃。 任何不是正在处理的 tikz 图片也是如此。

然而,这有一个意想不到的副作用。它会丢弃命令\includegraphicstikzpicture环境,但不会丢弃包含浮动元素(这是合理的,因为浮动元素可以包含图片以外的内容)。但是,如果浮动元素做过仅包含图片,那么它现在是一个高度为零的框。当 LaTeX 尝试构建一个完全由这些丢弃的图形组成的浮动页面时(请记住,这些图形可能是其他 tikz 图片),这会导致问题。正如 TikZ 为每一个除了正在外部化的图形之外,这种情况很容易发生。

由此导致的问题是,生成的浮动页面的高度也很可能为零。这是一个问题,因为 LaTeX 会测试浮动页面的高度是否不为零,以检查其是否正确制作。如果浮动页面的高度为零,则假设它以某种方式失败了,并且必须将所有浮动元素推到下一个浮动页面上。但如果浮动元素本身的高度为零,我们就永远无法摆脱这个循环。

之所以fixltx2e这样做很明显,是因为它添加了一个循环来确保所有浮点数都被正确处理(之前,如果这个失败了,它只会丢失那些浮点数 - 我想,我不是这方面的专家)。

这表明有多种选择:

  1. 禁用循环\@doclearpage。这是线路\ifx\@deferlist\@empty \else\clearpage \fi
  2. 禁用 tikz 外部化库中的优化步骤。这意味着将选项放在\tikzset{external/optimize=false}你的序言中。这可能是最安全可能使外化步骤变得更慢。
  3. 允许零高度浮动页面。这涉及重新定义测试,如下所示:

    \def\@ytryfc #1{%
      \begingroup
        \gdef\@flsucceed{\@elt #1}%
        \global\let\@flfail\@empty
        \@tempdima\ht #1%
        \let\@elt\@ztryfc
        \@trylist
        \ifdim \@tempdima <\@fpmin
          \@cons\@failedlist #1%
        \else
          \global\@fcolmadetrue
        \fi
      \endgroup
      \if@fcolmade
        \let\@elt\@gobble
      \fi}
    
  4. 修复 TikZ/PGF 优化,tikzpicture以便它创建一个非零高度的框。(我试过这个,但想不出能保证有效的方法。)

  5. 在每个外部浮动之后添加\newpage。这意味着它最终不会生成浮动页面。这有点极端,但您可以将其放入\tikzifexternalizing以确保它只在外部化运行中发生。

现在,我仅建议在外部化运行中对 Deep Core 进行更改。幸运的是,TikZ 提供了命令,因此如果您不想丢失优化,\tikzifexternalizing请将重新定义放入其中(用 包围所有内容)。\makeatletter ... \makeatother

相关内容